From 609fe2cae2459d721ac11d23cd27b8a94397ef3c Mon Sep 17 00:00:00 2001 From: "jmc@openbsd.org" Date: Mon, 14 Apr 2025 05:41:42 +0000 Subject: [PATCH 001/244] upstream: rework the text for -3 to make it clearer what default behaviour is, and adjust the text for -R to make them more consistent; issue raised by mikhail mp39590; behaviour explained by naddy ok djm OpenBSD-Commit-ID: 15ff3bd1518d86c84fa8e91d7aa72cfdb41dccc8 --- scp.1 | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/scp.1 b/scp.1 index aa2e2d8b53f8..ff739e8b8304 100644 --- a/scp.1 +++ b/scp.1 @@ -8,9 +8,9 @@ .\" .\" Created: Sun May 7 00:14:37 1995 ylo .\" -.\" $OpenBSD: scp.1,v 1.113 2024/12/06 15:12:56 djm Exp $ +.\" $OpenBSD: scp.1,v 1.114 2025/04/14 05:41:42 jmc Exp $ .\" -.Dd $Mdocdate: December 6 2024 $ +.Dd $Mdocdate: April 14 2025 $ .Dt SCP 1 .Os .Sh NAME @@ -76,15 +76,16 @@ The options are as follows: .Bl -tag -width Ds .It Fl 3 Copies between two remote hosts are transferred through the local host. -Without this option the data is copied directly between the two remote -hosts. -Note that, when using the legacy SCP protocol (via the +This mode is the default, +but see also the +.Fl R +option for copying data directly between two remote hosts. +Note that when using the legacy SCP protocol (via the .Fl O flag), this option selects batch mode for the second host as .Nm cannot ask for passwords or passphrases for both hosts. -This mode is the default. .It Fl 4 Forces .Nm @@ -278,7 +279,9 @@ Quiet mode: disables the progress meter as well as warning and diagnostic messages from .Xr ssh 1 . .It Fl R -Copies between two remote hosts are performed by connecting to the origin +Copies between two remote hosts are transferred through the local host +by default. +This option instead copies between two remote hosts by connecting to the origin host and executing .Nm there. From f3d465530e75cb6c02e2cde1d15e6c4bb51ebfd9 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Tue, 15 Apr 2025 04:00:42 +0000 Subject: [PATCH 002/244] upstream: basic benchmarking support for the unit test framework enable with "make UNITTEST_BENCHMARK=yes" ok dtucker@ OpenBSD-Regress-ID: 7f16a2e247f860897ca46ff87bccbe6002a32564 --- Makefile.in | 7 + regress/Makefile | 31 +-- regress/unittests/Makefile.inc | 25 ++- regress/unittests/authopt/Makefile | 4 +- regress/unittests/authopt/tests.c | 8 +- regress/unittests/bitmap/Makefile | 7 +- regress/unittests/bitmap/tests.c | 30 ++- regress/unittests/conversion/Makefile | 4 +- regress/unittests/conversion/tests.c | 8 +- regress/unittests/hostkeys/Makefile | 4 +- regress/unittests/hostkeys/tests.c | 11 +- regress/unittests/kex/Makefile | 4 +- regress/unittests/kex/test_kex.c | 68 +++++-- regress/unittests/kex/tests.c | 9 +- regress/unittests/match/Makefile | 4 +- regress/unittests/match/tests.c | 8 +- regress/unittests/misc/Makefile | 4 +- regress/unittests/misc/tests.c | 8 +- regress/unittests/sshbuf/tests.c | 10 +- regress/unittests/sshkey/test_sshkey.c | 163 ++++++++++++++- regress/unittests/sshkey/tests.c | 10 +- regress/unittests/sshsig/tests.c | 8 +- regress/unittests/test_helper/test_helper.c | 211 +++++++++++++++++--- regress/unittests/test_helper/test_helper.h | 24 ++- regress/unittests/utf8/Makefile | 7 +- regress/unittests/utf8/tests.c | 8 +- 26 files changed, 580 insertions(+), 105 deletions(-) diff --git a/Makefile.in b/Makefile.in index 4617cebcd5e4..5a7a1bd101e3 100644 --- a/Makefile.in +++ b/Makefile.in @@ -782,6 +782,13 @@ unit: regress-unit-binaries OBJ="$(BUILDDIR)/regress" \ $@ && echo $@ tests passed +unit-bench: regress-unit-binaries + cd $(srcdir)/regress || exit $$?; \ + $(MAKE) \ + .CURDIR="$(abs_top_srcdir)/regress" \ + .OBJDIR="$(BUILDDIR)/regress" \ + OBJ="$(BUILDDIR)/regress" $@ + TEST_SSH_SSHD="$(BUILDDIR)/sshd" interop-tests t-exec file-tests extra-tests: regress-prep regress-binaries $(TARGETS) diff --git a/regress/Makefile b/regress/Makefile index 7e7f95b58a2c..8b69e14e998f 100644 --- a/regress/Makefile +++ b/regress/Makefile @@ -292,26 +292,33 @@ t-extra: ${EXTRA_TESTS:=.sh} interop: ${INTEROP_TARGETS} # Unit tests, built by top-level Makefile -unit: +unit unit-bench: set -e ; if test -z "${SKIP_UNIT}" ; then \ V="" ; \ test "x${USE_VALGRIND}" = "x" || \ V=${.CURDIR}/valgrind-unit.sh ; \ - $$V ${.OBJDIR}/unittests/sshbuf/test_sshbuf ; \ + ARGS=""; \ + test "x$@" = "xunit-bench" && ARGS="-b"; \ + test "x${UNITTEST_FAST}" = "x" || ARGS="$$ARGS -f"; \ + test "x${UNITTEST_SLOW}" = "x" || ARGS="$$ARGS -F"; \ + test "x${UNITTEST_VERBOSE}" = "x" || ARGS="$$ARGS -v"; \ + test "x${UNITTEST_BENCH_DETAIL}" = "x" || ARGS="$$ARGS -B"; \ + test "x${UNITTEST_BENCH_ONLY}" = "x" || ARGS="$$ARGS -O ${UNITTEST_BENCH_ONLY}"; \ + $$V ${.OBJDIR}/unittests/sshbuf/test_sshbuf $${ARGS}; \ $$V ${.OBJDIR}/unittests/sshkey/test_sshkey \ - -d ${.CURDIR}/unittests/sshkey/testdata ; \ + -d ${.CURDIR}/unittests/sshkey/testdata $${ARGS}; \ $$V ${.OBJDIR}/unittests/sshsig/test_sshsig \ - -d ${.CURDIR}/unittests/sshsig/testdata ; \ + -d ${.CURDIR}/unittests/sshsig/testdata $${ARGS}; \ $$V ${.OBJDIR}/unittests/authopt/test_authopt \ - -d ${.CURDIR}/unittests/authopt/testdata ; \ - $$V ${.OBJDIR}/unittests/bitmap/test_bitmap ; \ - $$V ${.OBJDIR}/unittests/conversion/test_conversion ; \ - $$V ${.OBJDIR}/unittests/kex/test_kex ; \ + -d ${.CURDIR}/unittests/authopt/testdata $${ARGS}; \ + $$V ${.OBJDIR}/unittests/bitmap/test_bitmap $${ARGS}; \ + $$V ${.OBJDIR}/unittests/conversion/test_conversion $${ARGS}; \ + $$V ${.OBJDIR}/unittests/kex/test_kex $${ARGS}; \ $$V ${.OBJDIR}/unittests/hostkeys/test_hostkeys \ - -d ${.CURDIR}/unittests/hostkeys/testdata ; \ - $$V ${.OBJDIR}/unittests/match/test_match ; \ - $$V ${.OBJDIR}/unittests/misc/test_misc ; \ + -d ${.CURDIR}/unittests/hostkeys/testdata $${ARGS}; \ + $$V ${.OBJDIR}/unittests/match/test_match $${ARGS}; \ + $$V ${.OBJDIR}/unittests/misc/test_misc $${ARGS}; \ if test "x${TEST_SSH_UTF8}" = "xyes" ; then \ - $$V ${.OBJDIR}/unittests/utf8/test_utf8 ; \ + $$V ${.OBJDIR}/unittests/utf8/test_utf8 $${ARGS}; \ fi \ fi diff --git a/regress/unittests/Makefile.inc b/regress/unittests/Makefile.inc index 98e280486ab1..ad7fdad84a53 100644 --- a/regress/unittests/Makefile.inc +++ b/regress/unittests/Makefile.inc @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile.inc,v 1.16 2024/01/11 01:45:58 djm Exp $ +# $OpenBSD: Makefile.inc,v 1.17 2025/04/15 04:00:42 djm Exp $ .include .include @@ -7,6 +7,9 @@ UNITTEST_FAST?= no # Skip slow tests (e.g. less intensive fuzzing). UNITTEST_SLOW?= no # Include slower tests (e.g. more intensive fuzzing). UNITTEST_VERBOSE?= no # Verbose test output (inc. per-test names). +UNITTEST_BENCHMARK?= no # Run unit tests in benchmarking mode. +UNITTEST_BENCH_DETAIL?=no # Detailed benchmark statistics. +UNITTEST_BENCH_ONLY?= # Run only these benchmarks MALLOC_OPTIONS?= CFGJRSUX TEST_ENV?= MALLOC_OPTIONS=${MALLOC_OPTIONS} @@ -69,8 +72,8 @@ DPADD+=${.CURDIR}/../test_helper/libtest_helper.a .PATH: ${.CURDIR}/${SSHREL} -LDADD+= -lutil -DPADD+= ${LIBUTIL} +LDADD+= -lutil -lm +DPADD+= ${LIBUTIL} ${LIBM} .if (${OPENSSL:L} == "yes") LDADD+= -lcrypto @@ -82,11 +85,21 @@ DPADD+= ${LIBFIDO2} ${LIBCBOR} ${LIBUSBHID} UNITTEST_ARGS?= -.if (${UNITTEST_VERBOSE:L} != "no") +.if (${UNITTEST_VERBOSE:L:R} != "no") UNITTEST_ARGS+= -v .endif -.if (${UNITTEST_FAST:L} != "no") +.if (${UNITTEST_FAST:L:R} != "no") UNITTEST_ARGS+= -f -.elif (${UNITTEST_SLOW:L} != "no") +.elif (${UNITTEST_SLOW:L:R} != "no") UNITTEST_ARGS+= -F .endif + +.if (${UNITTEST_BENCHMARK:L:R} != "no") +UNITTEST_ARGS+= -b +.endif +.if (${UNITTEST_BENCH_DETAIL:L:R} != "no") +UNITTEST_ARGS+= -B +.endif +.if (${UNITTEST_BENCH_ONLY:L} != "") +UNITTEST_ARGS+= -O "${UNITTEST_BENCH_ONLY}" +.endif diff --git a/regress/unittests/authopt/Makefile b/regress/unittests/authopt/Makefile index 3045ec708165..8bed7a915dfa 100644 --- a/regress/unittests/authopt/Makefile +++ b/regress/unittests/authopt/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.7 2023/01/15 23:35:10 djm Exp $ +# $OpenBSD: Makefile,v 1.8 2025/04/15 04:00:42 djm Exp $ PROG=test_authopt SRCS=tests.c @@ -22,6 +22,6 @@ SRCS+=utf8.c REGRESS_TARGETS=run-regress-${PROG} run-regress-${PROG}: ${PROG} - env ${TEST_ENV} ./${PROG} -d ${.CURDIR}/testdata + env ${TEST_ENV} ./${PROG} ${UNITTEST_ARGS} -d ${.CURDIR}/testdata .include diff --git a/regress/unittests/authopt/tests.c b/regress/unittests/authopt/tests.c index d9e190305e76..5285f0db5746 100644 --- a/regress/unittests/authopt/tests.c +++ b/regress/unittests/authopt/tests.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tests.c,v 1.3 2021/12/14 21:25:27 deraadt Exp $ */ +/* $OpenBSD: tests.c,v 1.4 2025/04/15 04:00:42 djm Exp $ */ /* * Regress test for keys options functions. @@ -576,3 +576,9 @@ tests(void) test_cert_parse(); test_merge(); } + +void +benchmarks(void) +{ + printf("no benchmarks\n"); +} diff --git a/regress/unittests/bitmap/Makefile b/regress/unittests/bitmap/Makefile index fe30acc77394..c38cc7918cc1 100644 --- a/regress/unittests/bitmap/Makefile +++ b/regress/unittests/bitmap/Makefile @@ -1,14 +1,15 @@ -# $OpenBSD: Makefile,v 1.4 2017/12/21 00:41:22 djm Exp $ +# $OpenBSD: Makefile,v 1.5 2025/04/15 04:00:42 djm Exp $ PROG=test_bitmap SRCS=tests.c # From usr.sbin/ssh -SRCS+=bitmap.c atomicio.c +SRCS+=bitmap.c atomicio.c misc.c xmalloc.c fatal.c log.c cleanup.c match.c +SRCS+=sshbuf.c sshbuf-getput-basic.c sshbuf-misc.c ssherr.c addr.c addrmatch.c REGRESS_TARGETS=run-regress-${PROG} run-regress-${PROG}: ${PROG} - env ${TEST_ENV} ./${PROG} + env ${TEST_ENV} ./${PROG} ${UNITTEST_ARGS} .include diff --git a/regress/unittests/bitmap/tests.c b/regress/unittests/bitmap/tests.c index 576b863f4066..b8eae2313215 100644 --- a/regress/unittests/bitmap/tests.c +++ b/regress/unittests/bitmap/tests.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tests.c,v 1.2 2021/12/14 21:25:27 deraadt Exp $ */ +/* $OpenBSD: tests.c,v 1.3 2025/04/15 04:00:42 djm Exp $ */ /* * Regress test for bitmap.h bitmap API * @@ -23,7 +23,7 @@ #include "bitmap.h" -#define NTESTS 131 +#define DEFAULT_NTESTS 131 void tests(void) @@ -32,10 +32,15 @@ tests(void) struct bitmap *b; BIGNUM *bn; size_t len; - int i, j, k, n; + int i, j, k, n, ntests = DEFAULT_NTESTS; u_char bbuf[1024], bnbuf[1024]; int r; + if (test_is_fast()) + ntests /= 4; + else if (test_is_slow()) + ntests *= 2; + TEST_START("bitmap_new"); b = bitmap_new(); ASSERT_PTR_NE(b, NULL); @@ -44,9 +49,9 @@ tests(void) TEST_DONE(); TEST_START("bitmap_set_bit / bitmap_test_bit"); - for (i = -1; i < NTESTS; i++) { - for (j = -1; j < NTESTS; j++) { - for (k = -1; k < NTESTS; k++) { + for (i = -1; i < ntests; i++) { + for (j = -1; j < ntests; j++) { + for (k = -1; k < ntests; k++) { bitmap_zero(b); BN_clear(bn); @@ -67,7 +72,7 @@ tests(void) /* Check perfect match between bitmap and bn */ test_subtest_info("match %d/%d/%d", i, j, k); - for (n = 0; n < NTESTS; n++) { + for (n = 0; n < ntests; n++) { ASSERT_INT_EQ(BN_is_bit_set(bn, n), bitmap_test_bit(b, n)); } @@ -99,7 +104,7 @@ tests(void) bitmap_zero(b); ASSERT_INT_EQ(bitmap_from_string(b, bnbuf, len), 0); - for (n = 0; n < NTESTS; n++) { + for (n = 0; n < ntests; n++) { ASSERT_INT_EQ(BN_is_bit_set(bn, n), bitmap_test_bit(b, n)); } @@ -107,7 +112,7 @@ tests(void) /* Test clearing bits */ test_subtest_info("clear %d/%d/%d", i, j, k); - for (n = 0; n < NTESTS; n++) { + for (n = 0; n < ntests; n++) { ASSERT_INT_EQ(bitmap_set_bit(b, n), 0); ASSERT_INT_EQ(BN_set_bit(bn, n), 1); } @@ -123,7 +128,7 @@ tests(void) bitmap_clear_bit(b, k); BN_clear_bit(bn, k); } - for (n = 0; n < NTESTS; n++) { + for (n = 0; n < ntests; n++) { ASSERT_INT_EQ(BN_is_bit_set(bn, n), bitmap_test_bit(b, n)); } @@ -135,4 +140,9 @@ tests(void) TEST_DONE(); #endif } +void +benchmarks(void) +{ + printf("no benchmarks\n"); +} diff --git a/regress/unittests/conversion/Makefile b/regress/unittests/conversion/Makefile index 5793c4934845..f9f5859ac5e8 100644 --- a/regress/unittests/conversion/Makefile +++ b/regress/unittests/conversion/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.4 2021/01/09 12:24:30 dtucker Exp $ +# $OpenBSD: Makefile,v 1.5 2025/04/15 04:00:42 djm Exp $ PROG=test_conversion SRCS=tests.c @@ -11,6 +11,6 @@ SRCS+=match.c addr.c addrmatch.c REGRESS_TARGETS=run-regress-${PROG} run-regress-${PROG}: ${PROG} - env ${TEST_ENV} ./${PROG} + env ${TEST_ENV} ./${PROG} ${UNITTEST_ARGS} .include diff --git a/regress/unittests/conversion/tests.c b/regress/unittests/conversion/tests.c index 5b526f7afa07..d65e6326fd4e 100644 --- a/regress/unittests/conversion/tests.c +++ b/regress/unittests/conversion/tests.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tests.c,v 1.4 2021/12/14 21:25:27 deraadt Exp $ */ +/* $OpenBSD: tests.c,v 1.5 2025/04/15 04:00:42 djm Exp $ */ /* * Regress test for conversions * @@ -50,3 +50,9 @@ tests(void) ASSERT_INT_EQ(convtime("1000000000000000000000w"), -1); TEST_DONE(); } + +void +benchmarks(void) +{ + printf("no benchmarks\n"); +} diff --git a/regress/unittests/hostkeys/Makefile b/regress/unittests/hostkeys/Makefile index 04d93359acaa..79a9d5745419 100644 --- a/regress/unittests/hostkeys/Makefile +++ b/regress/unittests/hostkeys/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.10 2023/01/15 23:35:10 djm Exp $ +# $OpenBSD: Makefile,v 1.11 2025/04/15 04:00:42 djm Exp $ PROG=test_hostkeys SRCS=tests.c test_iterate.c @@ -20,6 +20,6 @@ SRCS+=utf8.c REGRESS_TARGETS=run-regress-${PROG} run-regress-${PROG}: ${PROG} - env ${TEST_ENV} ./${PROG} -d ${.CURDIR}/testdata + env ${TEST_ENV} ./${PROG} ${UNITTEST_ARGS} -d ${.CURDIR}/testdata .include diff --git a/regress/unittests/hostkeys/tests.c b/regress/unittests/hostkeys/tests.c index 92c7646ad164..a14ba19b3abe 100644 --- a/regress/unittests/hostkeys/tests.c +++ b/regress/unittests/hostkeys/tests.c @@ -1,10 +1,14 @@ -/* $OpenBSD: tests.c,v 1.1 2015/02/16 22:18:34 djm Exp $ */ +/* $OpenBSD: tests.c,v 1.2 2025/04/15 04:00:42 djm Exp $ */ /* * Regress test for known_hosts-related API. * * Placed in the public domain */ +#include + +#include "../test_helper/test_helper.h" + void tests(void); void test_iterate(void); /* test_iterate.c */ @@ -14,3 +18,8 @@ tests(void) test_iterate(); } +void +benchmarks(void) +{ + printf("no benchmarks\n"); +} diff --git a/regress/unittests/kex/Makefile b/regress/unittests/kex/Makefile index ca4f0ee38639..b76ee8edc813 100644 --- a/regress/unittests/kex/Makefile +++ b/regress/unittests/kex/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.16 2024/09/09 03:13:39 djm Exp $ +# $OpenBSD: Makefile,v 1.17 2025/04/15 04:00:42 djm Exp $ PROG=test_kex SRCS=tests.c test_kex.c test_proposal.c @@ -35,7 +35,7 @@ SRCS+=digest-openssl.c REGRESS_TARGETS=run-regress-${PROG} run-regress-${PROG}: ${PROG} - env ${TEST_ENV} ./${PROG} + env ${TEST_ENV} ./${PROG} ${UNITTEST_ARGS} .include diff --git a/regress/unittests/kex/test_kex.c b/regress/unittests/kex/test_kex.c index caf8f57f75d6..84dada301b8f 100644 --- a/regress/unittests/kex/test_kex.c +++ b/regress/unittests/kex/test_kex.c @@ -1,4 +1,4 @@ -/* $OpenBSD: test_kex.c,v 1.9 2024/09/09 03:13:39 djm Exp $ */ +/* $OpenBSD: test_kex.c,v 1.10 2025/04/15 04:00:42 djm Exp $ */ /* * Regress test KEX * @@ -8,6 +8,7 @@ #include "includes.h" #include +#include #include #ifdef HAVE_STDINT_H #include @@ -76,7 +77,8 @@ run_kex(struct ssh *client, struct ssh *server) } static void -do_kex_with_key(char *kex, int keytype, int bits) +do_kex_with_key(char *kex, char *cipher, char *mac, + struct sshkey *key, int keytype, int bits) { struct ssh *client = NULL, *server = NULL, *server2 = NULL; struct sshkey *private, *public; @@ -85,9 +87,14 @@ do_kex_with_key(char *kex, int keytype, int bits) char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; char *keyname = NULL; - TEST_START("sshkey_generate"); - ASSERT_INT_EQ(sshkey_generate(keytype, bits, &private), 0); - TEST_DONE(); + if (key != NULL) { + private = key; + keytype = key->type; + } else { + TEST_START("sshkey_generate"); + ASSERT_INT_EQ(sshkey_generate(keytype, bits, &private), 0); + TEST_DONE(); + } TEST_START("sshkey_from_private"); ASSERT_INT_EQ(sshkey_from_private(private, &public), 0); @@ -97,6 +104,14 @@ do_kex_with_key(char *kex, int keytype, int bits) memcpy(kex_params.proposal, myproposal, sizeof(myproposal)); if (kex != NULL) kex_params.proposal[PROPOSAL_KEX_ALGS] = kex; + if (cipher != NULL) { + kex_params.proposal[PROPOSAL_ENC_ALGS_CTOS] = cipher; + kex_params.proposal[PROPOSAL_ENC_ALGS_STOC] = cipher; + } + if (mac != NULL) { + kex_params.proposal[PROPOSAL_MAC_ALGS_CTOS] = mac; + kex_params.proposal[PROPOSAL_MAC_ALGS_STOC] = mac; + } keyname = strdup(sshkey_ssh_name(private)); ASSERT_PTR_NE(keyname, NULL); kex_params.proposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = keyname; @@ -167,7 +182,8 @@ do_kex_with_key(char *kex, int keytype, int bits) TEST_DONE(); TEST_START("cleanup"); - sshkey_free(private); + if (key == NULL) + sshkey_free(private); sshkey_free(public); ssh_free(client); ssh_free(server); @@ -179,19 +195,37 @@ do_kex_with_key(char *kex, int keytype, int bits) static void do_kex(char *kex) { -#if 0 - log_init("test_kex", SYSLOG_LEVEL_DEBUG3, SYSLOG_FACILITY_AUTH, 1); -#endif + struct sshkey *key = NULL; + char name[256]; + + if (test_is_benchmark()) { + snprintf(name, sizeof(name), "generate %s", kex); + TEST_START(name); + ASSERT_INT_EQ(sshkey_generate(KEY_ED25519, 0, &key), 0); + TEST_DONE(); + snprintf(name, sizeof(name), "KEX %s", kex); + BENCH_START(name); + /* + * NB. use a cipher/MAC here that requires minimal bits from + * the KEX to avoid DH-GEX taking forever. + */ + do_kex_with_key(kex, "aes128-ctr", "hmac-sha2-256", key, + KEY_ED25519, 256); + BENCH_FINISH("kex"); + sshkey_free(key); + return; + } + #ifdef WITH_OPENSSL - do_kex_with_key(kex, KEY_RSA, 2048); -#ifdef WITH_DSA - do_kex_with_key(kex, KEY_DSA, 1024); -#endif -#ifdef OPENSSL_HAS_ECC - do_kex_with_key(kex, KEY_ECDSA, 256); -#endif /* OPENSSL_HAS_ECC */ + do_kex_with_key(kex, NULL, NULL, NULL, KEY_RSA, 2048); +# ifdef WITH_DSA + do_kex_with_key(kex, NULL, NULL, NULL, KEY_DSA, 1024); +# endif /* WITH_DSA */ +# ifdef OPENSSL_HAS_ECC + do_kex_with_key(kex, NULL, NULL, NULL, KEY_ECDSA, 256); +# endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ - do_kex_with_key(kex, KEY_ED25519, 256); + do_kex_with_key(kex, NULL, NULL, NULL, KEY_ED25519, 256); } void diff --git a/regress/unittests/kex/tests.c b/regress/unittests/kex/tests.c index d3044f033767..a3ef19ef410a 100644 --- a/regress/unittests/kex/tests.c +++ b/regress/unittests/kex/tests.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tests.c,v 1.3 2023/03/06 12:15:47 dtucker Exp $ */ +/* $OpenBSD: tests.c,v 1.4 2025/04/15 04:00:42 djm Exp $ */ /* * Placed in the public domain */ @@ -16,3 +16,10 @@ tests(void) kex_proposal_tests(); kex_proposal_populate_tests(); } + +void +benchmarks(void) +{ + printf("\n"); + kex_tests(); +} diff --git a/regress/unittests/match/Makefile b/regress/unittests/match/Makefile index 939163d30ef5..7b17e5689344 100644 --- a/regress/unittests/match/Makefile +++ b/regress/unittests/match/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.5 2021/01/09 12:24:31 dtucker Exp $ +# $OpenBSD: Makefile,v 1.6 2025/04/15 04:00:42 djm Exp $ PROG=test_match SRCS=tests.c @@ -11,6 +11,6 @@ SRCS+=cleanup.c atomicio.c addr.c REGRESS_TARGETS=run-regress-${PROG} run-regress-${PROG}: ${PROG} - env ${TEST_ENV} ./${PROG} + env ${TEST_ENV} ./${PROG} ${UNITTEST_ARGS} .include diff --git a/regress/unittests/match/tests.c b/regress/unittests/match/tests.c index f00d1f9348fc..2ca6c769ae3f 100644 --- a/regress/unittests/match/tests.c +++ b/regress/unittests/match/tests.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tests.c,v 1.8 2021/12/14 21:25:27 deraadt Exp $ */ +/* $OpenBSD: tests.c,v 1.9 2025/04/15 04:00:42 djm Exp $ */ /* * Regress test for matching functions * @@ -129,3 +129,9 @@ tests(void) * int addr_match_cidr_list(const char *, const char *); */ } + +void +benchmarks(void) +{ + printf("no benchmarks\n"); +} diff --git a/regress/unittests/misc/Makefile b/regress/unittests/misc/Makefile index d2be393ad703..7282be13a667 100644 --- a/regress/unittests/misc/Makefile +++ b/regress/unittests/misc/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.9 2023/01/06 02:59:50 djm Exp $ +# $OpenBSD: Makefile,v 1.10 2025/04/15 04:00:42 djm Exp $ PROG=test_misc SRCS=tests.c @@ -28,6 +28,6 @@ SRCS+= atomicio.c cleanup.c fatal.c REGRESS_TARGETS=run-regress-${PROG} run-regress-${PROG}: ${PROG} - env ${TEST_ENV} ./${PROG} + env ${TEST_ENV} ./${PROG} ${UNITTEST_ARGS} .include diff --git a/regress/unittests/misc/tests.c b/regress/unittests/misc/tests.c index 32699541413e..7611a0d3b645 100644 --- a/regress/unittests/misc/tests.c +++ b/regress/unittests/misc/tests.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tests.c,v 1.10 2023/01/06 02:59:50 djm Exp $ */ +/* $OpenBSD: tests.c,v 1.11 2025/04/15 04:00:42 djm Exp $ */ /* * Regress test for misc helper functions. * @@ -39,3 +39,9 @@ tests(void) test_hpdelim(); test_ptimeout(); } + +void +benchmarks(void) +{ + printf("no benchmarks\n"); +} diff --git a/regress/unittests/sshbuf/tests.c b/regress/unittests/sshbuf/tests.c index 29916a10bc5b..eb801fb3b302 100644 --- a/regress/unittests/sshbuf/tests.c +++ b/regress/unittests/sshbuf/tests.c @@ -1,10 +1,12 @@ -/* $OpenBSD: tests.c,v 1.1 2014/04/30 05:32:00 djm Exp $ */ +/* $OpenBSD: tests.c,v 1.2 2025/04/15 04:00:42 djm Exp $ */ /* * Regress test for sshbuf.h buffer API * * Placed in the public domain */ +#include + #include "../test_helper/test_helper.h" void sshbuf_tests(void); @@ -28,3 +30,9 @@ tests(void) sshbuf_getput_fuzz_tests(); sshbuf_fixed(); } + +void +benchmarks(void) +{ + printf("no benchmarks\n"); +} diff --git a/regress/unittests/sshkey/test_sshkey.c b/regress/unittests/sshkey/test_sshkey.c index 5bf4b65cc055..fc744eb7430f 100644 --- a/regress/unittests/sshkey/test_sshkey.c +++ b/regress/unittests/sshkey/test_sshkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: test_sshkey.c,v 1.25 2024/08/15 00:52:23 djm Exp $ */ +/* $OpenBSD: test_sshkey.c,v 1.26 2025/04/15 04:00:42 djm Exp $ */ /* * Regress test for sshkey.h key management API * @@ -36,6 +36,7 @@ #include "ssh2.h" void sshkey_tests(void); +void sshkey_benchmarks(void); static void put_opt(struct sshbuf *b, const char *name, const char *value) @@ -133,6 +134,55 @@ signature_test(struct sshkey *k, struct sshkey *bad, const char *sig_alg, free(sig); } +static void +signature_bench(const char *name, int ktype, int bits, const char *sig_alg, + const u_char *d, size_t l) +{ + struct sshkey *k; + size_t len; + u_char *sig; + char testname[256]; + + snprintf(testname, sizeof(testname), "sign %s", name); + TEST_START(testname); + ASSERT_INT_EQ(sshkey_generate(ktype, bits, &k), 0); + ASSERT_PTR_NE(k, NULL); + + BENCH_START(testname); + ASSERT_INT_EQ(sshkey_sign(k, &sig, &len, d, l, sig_alg, + NULL, NULL, 0), 0); + free(sig); + BENCH_FINISH("sign"); + + sshkey_free(k); + TEST_DONE(); +} + +static void +verify_bench(const char *name, int ktype, int bits, const char *sig_alg, + const u_char *d, size_t l) +{ + struct sshkey *k; + size_t len; + u_char *sig; + char testname[256]; + + snprintf(testname, sizeof(testname), "verify %s", name); + TEST_START(testname); + ASSERT_INT_EQ(sshkey_generate(ktype, bits, &k), 0); + ASSERT_PTR_NE(k, NULL); + + ASSERT_INT_EQ(sshkey_sign(k, &sig, &len, d, l, sig_alg, + NULL, NULL, 0), 0); + BENCH_START(testname); + ASSERT_INT_EQ(sshkey_verify(k, sig, len, d, l, NULL, 0, NULL), 0); + BENCH_FINISH("verify"); + + free(sig); + sshkey_free(k); + TEST_DONE(); +} + static void banana(u_char *s, size_t l) { @@ -165,6 +215,19 @@ signature_tests(struct sshkey *k, struct sshkey *bad, const char *sig_alg) } } +static void +signature_benchmark(const char *name, int ktype, int bits, + const char *sig_alg, int bench_verify) +{ + u_char buf[256]; + + banana(buf, sizeof(buf)); + if (bench_verify) + verify_bench(name, ktype, bits, sig_alg, buf, sizeof(buf)); + else + signature_bench(name, ktype, bits, sig_alg, buf, sizeof(buf)); +} + static struct sshkey * get_private(const char *n) { @@ -537,3 +600,101 @@ sshkey_tests(void) TEST_DONE(); #endif /* WITH_OPENSSL */ } + +void +sshkey_benchmarks(void) +{ + struct sshkey *k = NULL; + +#ifdef WITH_OPENSSL + BENCH_START("generate RSA-1024"); + TEST_START("generate KEY_RSA"); + ASSERT_INT_EQ(sshkey_generate(KEY_RSA, 1024, &k), 0); + ASSERT_PTR_NE(k, NULL); + sshkey_free(k); + TEST_DONE(); + BENCH_FINISH("keys"); + + BENCH_START("generate RSA-2048"); + TEST_START("generate KEY_RSA"); + ASSERT_INT_EQ(sshkey_generate(KEY_RSA, 2048, &k), 0); + ASSERT_PTR_NE(k, NULL); + sshkey_free(k); + TEST_DONE(); + BENCH_FINISH("keys"); + +#ifdef WITH_DSA + BENCH_START("generate DSA-1024"); + TEST_START("generate KEY_DSA"); + ASSERT_INT_EQ(sshkey_generate(KEY_DSA, 1024, &k), 0); + ASSERT_PTR_NE(k, NULL); + sshkey_free(k); + TEST_DONE(); + BENCH_FINISH("keys"); +#endif + + BENCH_START("generate ECDSA-256"); + TEST_START("generate KEY_ECDSA"); + ASSERT_INT_EQ(sshkey_generate(KEY_ECDSA, 256, &k), 0); + ASSERT_PTR_NE(k, NULL); + sshkey_free(k); + TEST_DONE(); + BENCH_FINISH("keys"); + + BENCH_START("generate ECDSA-384"); + TEST_START("generate KEY_ECDSA"); + ASSERT_INT_EQ(sshkey_generate(KEY_ECDSA, 384, &k), 0); + ASSERT_PTR_NE(k, NULL); + sshkey_free(k); + TEST_DONE(); + BENCH_FINISH("keys"); + + BENCH_START("generate ECDSA-521"); + TEST_START("generate KEY_ECDSA"); + ASSERT_INT_EQ(sshkey_generate(KEY_ECDSA, 521, &k), 0); + ASSERT_PTR_NE(k, NULL); + sshkey_free(k); + TEST_DONE(); + BENCH_FINISH("keys"); +#endif /* WITH_OPENSSL */ + + BENCH_START("generate ED25519"); + TEST_START("generate KEY_ED25519"); + ASSERT_INT_EQ(sshkey_generate(KEY_ED25519, 256, &k), 0); + ASSERT_PTR_NE(k, NULL); + sshkey_free(k); + TEST_DONE(); + BENCH_FINISH("keys"); + +#ifdef WITH_OPENSSL + /* sign */ + signature_benchmark("RSA-1024/SHA1", KEY_RSA, 1024, "ssh-rsa", 0); + signature_benchmark("RSA-1024/SHA256", KEY_RSA, 1024, "rsa-sha2-256", 0); + signature_benchmark("RSA-1024/SHA512", KEY_RSA, 1024, "rsa-sha2-512", 0); + signature_benchmark("RSA-2048/SHA1", KEY_RSA, 2048, "ssh-rsa", 0); + signature_benchmark("RSA-2048/SHA256", KEY_RSA, 2048, "rsa-sha2-256", 0); + signature_benchmark("RSA-2048/SHA512", KEY_RSA, 2048, "rsa-sha2-512", 0); +#ifdef WITH_DSA + signature_benchmark("DSA-1024", KEY_DSA, 1024, NULL, 0); +#endif + signature_benchmark("ECDSA-256", KEY_ECDSA, 256, NULL, 0); + signature_benchmark("ECDSA-384", KEY_ECDSA, 384, NULL, 0); + signature_benchmark("ECDSA-521", KEY_ECDSA, 521, NULL, 0); + signature_benchmark("ED25519", KEY_ED25519, 0, NULL, 0); + + /* verify */ + signature_benchmark("RSA-1024/SHA1", KEY_RSA, 1024, "ssh-rsa", 1); + signature_benchmark("RSA-1024/SHA256", KEY_RSA, 1024, "rsa-sha2-256", 1); + signature_benchmark("RSA-1024/SHA512", KEY_RSA, 1024, "rsa-sha2-512", 1); + signature_benchmark("RSA-2048/SHA1", KEY_RSA, 2048, "ssh-rsa", 1); + signature_benchmark("RSA-2048/SHA256", KEY_RSA, 2048, "rsa-sha2-256", 1); + signature_benchmark("RSA-2048/SHA512", KEY_RSA, 2048, "rsa-sha2-512", 1); +#ifdef WITH_DSA + signature_benchmark("DSA-1024", KEY_DSA, 1024, NULL, 1); +#endif + signature_benchmark("ECDSA-256", KEY_ECDSA, 256, NULL, 1); + signature_benchmark("ECDSA-384", KEY_ECDSA, 384, NULL, 1); + signature_benchmark("ECDSA-521", KEY_ECDSA, 521, NULL, 1); +#endif /* WITH_OPENSSL */ + signature_benchmark("ED25519", KEY_ED25519, 0, NULL, 1); +} diff --git a/regress/unittests/sshkey/tests.c b/regress/unittests/sshkey/tests.c index 78aa9223d42b..5511e7b8900d 100644 --- a/regress/unittests/sshkey/tests.c +++ b/regress/unittests/sshkey/tests.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tests.c,v 1.1 2014/06/24 01:14:18 djm Exp $ */ +/* $OpenBSD: tests.c,v 1.2 2025/04/15 04:00:42 djm Exp $ */ /* * Regress test for sshbuf.h buffer API * @@ -12,6 +12,7 @@ void sshkey_tests(void); void sshkey_file_tests(void); void sshkey_fuzz_tests(void); +void sshkey_benchmarks(void); void tests(void) @@ -20,3 +21,10 @@ tests(void) sshkey_file_tests(); sshkey_fuzz_tests(); } + +void +benchmarks(void) +{ + printf("\n"); + sshkey_benchmarks(); +} diff --git a/regress/unittests/sshsig/tests.c b/regress/unittests/sshsig/tests.c index 80966bdd2c27..7fcf9488d270 100644 --- a/regress/unittests/sshsig/tests.c +++ b/regress/unittests/sshsig/tests.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tests.c,v 1.4 2024/01/11 01:45:59 djm Exp $ */ +/* $OpenBSD: tests.c,v 1.5 2025/04/15 04:00:42 djm Exp $ */ /* * Regress test for sshbuf.h buffer API * @@ -142,3 +142,9 @@ tests(void) sshbuf_free(msg); free(namespace); } + +void +benchmarks(void) +{ + printf("no benchmarks\n"); +} diff --git a/regress/unittests/test_helper/test_helper.c b/regress/unittests/test_helper/test_helper.c index e23128aa5599..b75f7701401b 100644 --- a/regress/unittests/test_helper/test_helper.c +++ b/regress/unittests/test_helper/test_helper.c @@ -1,4 +1,4 @@ -/* $OpenBSD: test_helper.c,v 1.13 2021/12/14 21:25:27 deraadt Exp $ */ +/* $OpenBSD: test_helper.c,v 1.14 2025/04/15 04:00:42 djm Exp $ */ /* * Copyright (c) 2011 Damien Miller * @@ -21,18 +21,21 @@ #include #include - -#include +#include + +#include #include -#include +#include +#include +#include +#include #ifdef HAVE_STDINT_H # include #endif +#include #include #include -#include #include -#include #ifdef WITH_OPENSSL #include @@ -43,12 +46,21 @@ # include #endif -#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) - #include "entropy.h" #include "test_helper.h" #include "atomicio.h" +#include "match.h" +#include "misc.h" +#include "xmalloc.h" +#define BENCH_FAST_DEADLINE 1 +#define BENCH_NORMAL_DEADLINE 10 +#define BENCH_SLOW_DEADLINE 60 +#define BENCH_SAMPLES_ALLOC 8192 +#define BENCH_COLUMN_WIDTH 40 + +#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) + #define TEST_CHECK_INT(r, pred) do { \ switch (pred) { \ case TEST_EQ: \ @@ -123,6 +135,15 @@ static const char *data_dir = NULL; static char subtest_info[512]; static int fast = 0; static int slow = 0; +static int benchmark_detail_statistics = 0; + +static int benchmark = 0; +static const char *bench_name = NULL; +static char *benchmark_pattern = NULL; +static struct timespec bench_start_time, bench_finish_time; +static struct timespec *bench_samples; +static int bench_skip, bench_nruns, bench_nalloc; +double bench_accum_secs; int main(int argc, char **argv) @@ -147,8 +168,17 @@ main(int argc, char **argv) } } - while ((ch = getopt(argc, argv, "Ffvqd:")) != -1) { + while ((ch = getopt(argc, argv, "O:bBFfvqd:")) != -1) { switch (ch) { + case 'b': + benchmark = 1; + break; + case 'B': + benchmark = benchmark_detail_statistics = 1; + break; + case 'O': + benchmark_pattern = xstrdup(optarg); + break; case 'F': slow = 1; break; @@ -168,7 +198,8 @@ main(int argc, char **argv) break; default: fprintf(stderr, "Unrecognised command line option\n"); - fprintf(stderr, "Usage: %s [-v]\n", __progname); + fprintf(stderr, "Usage: %s [-vqfFbB] [-d data_dir] " + "[-O pattern]\n", __progname); exit(1); } } @@ -178,9 +209,12 @@ main(int argc, char **argv) if (verbose_mode) printf("\n"); - tests(); + if (benchmark) + benchmarks(); + else + tests(); - if (!quiet_mode) + if (!quiet_mode && !benchmark) printf(" %u tests ok\n", test_number); return 0; } @@ -274,7 +308,7 @@ test_done(void) active_test_name = NULL; if (verbose_mode) printf("OK\n"); - else if (!quiet_mode) { + else if (!quiet_mode && !benchmark) { printf("."); fflush(stdout); } @@ -290,6 +324,12 @@ test_subtest_info(const char *fmt, ...) va_end(ap); } +int +test_is_benchmark(void) +{ + return benchmark; +} + void ssl_err_check(const char *file, int line) { @@ -382,23 +422,6 @@ assert_string(const char *file, int line, const char *a1, const char *a2, test_die(); } -static char * -tohex(const void *_s, size_t l) -{ - u_int8_t *s = (u_int8_t *)_s; - size_t i, j; - const char *hex = "0123456789abcdef"; - char *r = malloc((l * 2) + 1); - - assert(r != NULL); - for (i = j = 0; i < l; i++) { - r[j++] = hex[(s[i] >> 4) & 0xf]; - r[j++] = hex[s[i] & 0xf]; - } - r[j] = '\0'; - return r; -} - void assert_mem(const char *file, int line, const char *a1, const char *a2, const void *aa1, const void *aa2, size_t l, enum test_predicate pred) @@ -593,3 +616,131 @@ assert_ptr(const char *file, int line, const char *a1, const char *a2, test_die(); } +static double +tstod(const struct timespec *ts) +{ + return (double)ts->tv_sec + ((double)ts->tv_nsec / 1000000000.0); +} + +void +bench_start(const char *file, int line, const char *name) +{ + char *cp; + + if (bench_name != NULL) { + fprintf(stderr, "\n%s:%d internal error: BENCH_START() called " + "while previous benchmark \"%s\" incomplete", + file, line, bench_name); + abort(); + } + cp = xstrdup(name); + lowercase(cp); + bench_skip = benchmark_pattern != NULL && + match_pattern_list(cp, benchmark_pattern, 1) != 1; + free(cp); + + bench_name = name; + bench_nruns = 0; + if (bench_skip) + return; + free(bench_samples); + bench_nalloc = BENCH_SAMPLES_ALLOC; + bench_samples = xcalloc(sizeof(*bench_samples), bench_nalloc); + bench_accum_secs = 0; +} + +int +bench_done(void) +{ + return bench_skip || bench_accum_secs >= (fast ? BENCH_FAST_DEADLINE : + (slow ? BENCH_SLOW_DEADLINE : BENCH_NORMAL_DEADLINE)); +} + +void +bench_case_start(const char *file, int line) +{ + clock_gettime(CLOCK_REALTIME, &bench_start_time); +} + +void +bench_case_finish(const char *file, int line) +{ + struct timespec ts; + + clock_gettime(CLOCK_REALTIME, &bench_finish_time); + timespecsub(&bench_finish_time, &bench_start_time, &ts); + if (bench_nruns >= bench_nalloc) { + if (bench_nalloc >= INT_MAX / 2) { + fprintf(stderr, "\n%s:%d benchmark %s too many samples", + __FILE__, __LINE__, bench_name); + abort(); + } + bench_samples = xrecallocarray(bench_samples, bench_nalloc, + bench_nalloc * 2, sizeof(*bench_samples)); + bench_nalloc *= 2; + } + bench_samples[bench_nruns++] = ts; + bench_accum_secs += tstod(&ts); +} + +static int +tscmp(const void *aa, const void *bb) +{ + const struct timespec *a = (const struct timespec *)aa; + const struct timespec *b = (const struct timespec *)bb; + + if (timespeccmp(a, b, ==)) + return 0; + return timespeccmp(a, b, <) ? -1 : 1; +} + +void +bench_finish(const char *file, int line, const char *unit) +{ + double std_dev = 0, mean_spr, mean_rps, med_spr, med_rps; + int i; + + if (bench_skip) + goto done; + + if (bench_nruns < 1) { + fprintf(stderr, "\n%s:%d benchmark %s never ran", file, line, + bench_name); + abort(); + } + /* median */ + qsort(bench_samples, bench_nruns, sizeof(*bench_samples), tscmp); + i = bench_nruns / 2; + med_spr = tstod(&bench_samples[i]); + if (bench_nruns > 1 && bench_nruns & 1) + med_spr = (med_spr + tstod(&bench_samples[i - 1])) / 2.0; + med_rps = (med_spr == 0.0) ? INFINITY : 1.0/med_spr; + /* mean */ + mean_spr = bench_accum_secs / (double)bench_nruns; + mean_rps = (mean_spr == 0.0) ? INFINITY : 1.0/mean_spr; + /* std. dev */ + std_dev = 0; + for (i = 0; i < bench_nruns; i++) { + std_dev = tstod(&bench_samples[i]) - mean_spr; + std_dev *= std_dev; + } + std_dev /= (double)bench_nruns; + std_dev = sqrt(std_dev); + if (benchmark_detail_statistics) { + printf("%s: %d runs in %0.3fs, %0.03f/%0.03f ms/%s " + "(mean/median), std.dev %0.03f ms, " + "%0.2f/%0.2f %s/s (mean/median)\n", + bench_name, bench_nruns, bench_accum_secs, + mean_spr * 1000, med_spr * 1000, unit, std_dev * 1000, + mean_rps, med_rps, unit); + } else { + printf("%-*s %0.2f %s/s\n", BENCH_COLUMN_WIDTH, + bench_name, med_rps, unit); + } + done: + bench_name = NULL; + bench_nruns = 0; + free(bench_samples); + bench_samples = NULL; + bench_skip = 0; +} diff --git a/regress/unittests/test_helper/test_helper.h b/regress/unittests/test_helper/test_helper.h index 66302201cec3..23338af38882 100644 --- a/regress/unittests/test_helper/test_helper.h +++ b/regress/unittests/test_helper/test_helper.h @@ -1,4 +1,4 @@ -/* $OpenBSD: test_helper.h,v 1.9 2018/10/17 23:28:05 djm Exp $ */ +/* $OpenBSD: test_helper.h,v 1.10 2025/04/15 04:00:42 djm Exp $ */ /* * Copyright (c) 2011 Damien Miller * @@ -39,6 +39,7 @@ typedef void (test_onerror_func_t)(void *); /* Supplied by test suite */ void tests(void); +void benchmarks(void); const char *test_data_file(const char *name); void test_start(const char *n); @@ -49,6 +50,7 @@ int test_is_verbose(void); int test_is_quiet(void); int test_is_fast(void); int test_is_slow(void); +int test_is_benchmark(void); void test_subtest_info(const char *fmt, ...) __attribute__((format(printf, 1, 2))); void ssl_err_check(const char *file, int line); @@ -285,6 +287,26 @@ void assert_u64(const char *file, int line, #define ASSERT_U64_GE(a1, a2) \ assert_u64(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE) +/* Benchmarking support */ +#define BENCH_START(name) \ + do { \ + bench_start(__FILE__, __LINE__, name); \ + while (!bench_done()) { \ + bench_case_start(__FILE__, __LINE__); \ + do { +#define BENCH_FINISH(unit) \ + } while (0); \ + bench_case_finish(__FILE__, __LINE__); \ + } \ + bench_finish(__FILE__, __LINE__, unit); \ + } while (0) + +void bench_start(const char *file, int line, const char *name); +void bench_case_start(const char *file, int line); +void bench_case_finish(const char *file, int line); +void bench_finish(const char *file, int line, const char *unit); +int bench_done(void); + /* Fuzzing support */ struct fuzz; diff --git a/regress/unittests/utf8/Makefile b/regress/unittests/utf8/Makefile index f8eec0484f8f..e89536500822 100644 --- a/regress/unittests/utf8/Makefile +++ b/regress/unittests/utf8/Makefile @@ -1,14 +1,15 @@ -# $OpenBSD: Makefile,v 1.5 2017/12/21 00:41:22 djm Exp $ +# $OpenBSD: Makefile,v 1.6 2025/04/15 04:00:42 djm Exp $ PROG=test_utf8 SRCS=tests.c # From usr.bin/ssh -SRCS+=utf8.c atomicio.c +SRCS+=utf8.c atomicio.c misc.c xmalloc.c match.c ssherr.c cleanup.c fatal.c +SRCS+=sshbuf.c sshbuf-getput-basic.c sshbuf-misc.c addr.c addrmatch.c log.c REGRESS_TARGETS=run-regress-${PROG} run-regress-${PROG}: ${PROG} - env ${TEST_ENV} ./${PROG} + env ${TEST_ENV} ./${PROG} ${UNITTEST_ARGS} .include diff --git a/regress/unittests/utf8/tests.c b/regress/unittests/utf8/tests.c index 8cf524ddb210..3fb63415e1ad 100644 --- a/regress/unittests/utf8/tests.c +++ b/regress/unittests/utf8/tests.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tests.c,v 1.4 2017/02/19 00:11:29 djm Exp $ */ +/* $OpenBSD: tests.c,v 1.5 2025/04/15 04:00:42 djm Exp $ */ /* * Regress test for the utf8.h *mprintf() API * @@ -102,3 +102,9 @@ tests(void) one(0, "double_fit", "a\343\201\201", 7, 5, -1, "a\\343"); one(0, "double_spc", "a\343\201\201", 13, 13, 13, "a\\343\\201\\201"); } + +void +benchmarks(void) +{ + printf("no benchmarks\n"); +} From 1ec5b39f1f673beac039bb42c98a11aa2b08a0b2 Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Tue, 15 Apr 2025 09:22:25 +0000 Subject: [PATCH 003/244] upstream: Cast signalled_keydrop to int when logging to prevent warning on platforms where sig_atomic_t is not the same as int. bz#3811, patch from jlduran at gmail com. OpenBSD-Commit-ID: b6bc9e9006e7f81ade57d41a48623a4323deca6c --- ssh-agent.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssh-agent.c b/ssh-agent.c index c27c5a956f2c..55b9f44f4d4a 100644 --- a/ssh-agent.c +++ b/ssh-agent.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-agent.c,v 1.310 2025/02/18 08:02:48 djm Exp $ */ +/* $OpenBSD: ssh-agent.c,v 1.311 2025/04/15 09:22:25 dtucker Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -2526,7 +2526,7 @@ main(int ac, char **av) } if (signalled_keydrop) { logit("signal %d received; removing all keys", - signalled_keydrop); + (int)signalled_keydrop); remove_all_identities(); signalled_keydrop = 0; } From 849c2fd894aa87a7e40c71e8d5bda5392b1205be Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Tue, 15 Apr 2025 21:58:49 +1000 Subject: [PATCH 004/244] Look for sqrt(), possibly in libm. The unit tests now use sqrt(), which in some platforms (notably DragonFlyBSD and Solaris) is not in libc but rather libm. Since only the unit tests use this, add TESTLIBS and if necessary put libm in it. --- Makefile.in | 2 +- configure.ac | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Makefile.in b/Makefile.in index 5a7a1bd101e3..f15ac558aea7 100644 --- a/Makefile.in +++ b/Makefile.in @@ -557,7 +557,7 @@ regress-prep: ln -s `cd $(srcdir) && pwd`/regress/Makefile `pwd`/regress/Makefile REGRESSLIBS=libssh.a $(LIBCOMPAT) -TESTLIBS=$(LIBS) $(CHANNELLIBS) +TESTLIBS=$(LIBS) $(CHANNELLIBS) @TESTLIBS@ regress/modpipe$(EXEEXT): $(srcdir)/regress/modpipe.c $(REGRESSLIBS) $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $(srcdir)/regress/modpipe.c \ diff --git a/configure.ac b/configure.ac index ee77a0484b19..bbddca00908b 100644 --- a/configure.ac +++ b/configure.ac @@ -1449,6 +1449,11 @@ AC_CHECK_FUNC([getspnam], , AC_SEARCH_LIBS([basename], [gen], [AC_DEFINE([HAVE_BASENAME], [1], [Define if you have the basename function.])]) +dnl sqrt() only used in unit tests. +AC_CHECK_FUNC([sqrt], , + [AC_CHECK_LIB([m], [sqrt], [TESTLIBS="$TESTLIBS -lm"])]) +AC_SUBST([TESTLIBS]) + dnl zlib defaults to enabled zlib=yes AC_ARG_WITH([zlib], From 46e52fdae08b89264a0b23f94391c2bf637def34 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Wed, 16 Apr 2025 22:29:17 +1000 Subject: [PATCH 005/244] Provide INFINITY if it's not provided. INFINITY is specified in c99, so define if not provided. --- configure.ac | 5 +++++ defines.h | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/configure.ac b/configure.ac index bbddca00908b..69b74add8d00 100644 --- a/configure.ac +++ b/configure.ac @@ -2280,6 +2280,11 @@ AC_CHECK_DECLS([offsetof], , , [ #include ]) +AC_CHECK_DECLS([INFINITY], , + AC_CHECK_DECLS(__builtin_inff), + [#include ] +) + # extra bits for select(2) AC_CHECK_DECLS([howmany, NFDBITS], [], [], [[ #include diff --git a/defines.h b/defines.h index d2baeb9407bd..3721ae16ef92 100644 --- a/defines.h +++ b/defines.h @@ -986,4 +986,11 @@ struct winsize { /* The ML-KEM768 implementation also uses C89 features */ # define USE_MLKEM768X25519 1 #endif + +#if defined(HAVE_DECL_INFINITY) && HAVE_DECL_INFINITY == 0 +# if defined(HAVE_DECL___BUILTIN_INFF) && HAVE_DECL___BUILTIN_INFF == 1 +# define INFINITY __builtin_inff() +# endif +#endif + #endif /* _DEFINES_H */ From 9b50cb171b5c56184ce6fa3994ce62f9882d2daf Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Thu, 17 Apr 2025 16:51:14 +1000 Subject: [PATCH 006/244] Add includes.h for new tests. Fixes builds on older platforms. --- regress/unittests/hostkeys/tests.c | 2 ++ regress/unittests/sshbuf/tests.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/regress/unittests/hostkeys/tests.c b/regress/unittests/hostkeys/tests.c index a14ba19b3abe..c6e17fad09cb 100644 --- a/regress/unittests/hostkeys/tests.c +++ b/regress/unittests/hostkeys/tests.c @@ -5,6 +5,8 @@ * Placed in the public domain */ +#include "includes.h" + #include #include "../test_helper/test_helper.h" diff --git a/regress/unittests/sshbuf/tests.c b/regress/unittests/sshbuf/tests.c index eb801fb3b302..95a34a8c8e97 100644 --- a/regress/unittests/sshbuf/tests.c +++ b/regress/unittests/sshbuf/tests.c @@ -5,6 +5,8 @@ * Placed in the public domain */ +#include "includes.h" + #include #include "../test_helper/test_helper.h" From 52bddbc1a7f53a1e5c871767913648eb639ac6d5 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Fri, 18 Apr 2025 08:10:32 +1000 Subject: [PATCH 007/244] Include time.h for clock_gettime(). --- regress/unittests/test_helper/test_helper.c | 1 + 1 file changed, 1 insertion(+) diff --git a/regress/unittests/test_helper/test_helper.c b/regress/unittests/test_helper/test_helper.c index b75f7701401b..7783d65a4f4a 100644 --- a/regress/unittests/test_helper/test_helper.c +++ b/regress/unittests/test_helper/test_helper.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #ifdef WITH_OPENSSL From c627b468d3b99e487e2b24c90958ae57e633d681 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Fri, 18 Apr 2025 08:14:16 +1000 Subject: [PATCH 008/244] cygwin-install-action now puts setup.exe on D: --- .github/setup_ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/setup_ci.sh b/.github/setup_ci.sh index f6c4a5c84fb5..05ac755a79de 100755 --- a/.github/setup_ci.sh +++ b/.github/setup_ci.sh @@ -184,7 +184,7 @@ while [ ! -z "$PACKAGES" ] && [ "$tries" -gt "0" ]; do fi ;; setup) - if /cygdrive/c/setup.exe -q -P `echo "$PACKAGES" | tr ' ' ,`; then + if /cygdrive/d/setup.exe -q -P `echo "$PACKAGES" | tr ' ' ,`; then PACKAGES="" fi ;; From 76631fdd04824c3e50ea6551d3611b1fe0216a41 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Fri, 18 Apr 2025 08:18:52 +1000 Subject: [PATCH 009/244] Add 10.0 branch to test status page. --- .github/ci-status.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/ci-status.md b/.github/ci-status.md index 68275715dfb1..d47e59e1e5ea 100644 --- a/.github/ci-status.md +++ b/.github/ci-status.md @@ -6,6 +6,10 @@ master : [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/openssh.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:openssh) [![Coverity Status](https://scan.coverity.com/projects/21341/badge.svg)](https://scan.coverity.com/projects/openssh-portable) +10.0 : +[![C/C++ CI](https://github.com/openssh/openssh-portable/actions/workflows/c-cpp.yml/badge.svg?branch=V_10_0)](https://github.com/openssh/openssh-portable/actions/workflows/c-cpp.yml?query=branch:V_10_0) +[![C/C++ CI self-hosted](https://github.com/openssh/openssh-portable-selfhosted/actions/workflows/selfhosted.yml/badge.svg?branch=V_10_0)](https://github.com/openssh/openssh-portable-selfhosted/actions/workflows/selfhosted.yml?query=branch:V_10_0) + 9.9 : [![C/C++ CI](https://github.com/openssh/openssh-portable/actions/workflows/c-cpp.yml/badge.svg?branch=V_9_9)](https://github.com/openssh/openssh-portable/actions/workflows/c-cpp.yml?query=branch:V_9_9) [![C/C++ CI self-hosted](https://github.com/openssh/openssh-portable-selfhosted/actions/workflows/selfhosted.yml/badge.svg?branch=V_9_9)](https://github.com/openssh/openssh-portable-selfhosted/actions/workflows/selfhosted.yml?query=branch:V_9_9) From b5b405fee7f3e79d44e2d2971a4b6b4cc53f112e Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Sun, 20 Apr 2025 09:07:57 +1000 Subject: [PATCH 010/244] Set Windows permssions on regress dir. Prevents "unprotected private key file" error when running tests. --- .github/setup_ci.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/setup_ci.sh b/.github/setup_ci.sh index 05ac755a79de..e3e28da6f1b1 100755 --- a/.github/setup_ci.sh +++ b/.github/setup_ci.sh @@ -12,7 +12,15 @@ case "$host" in echo Setting CYGWIN system environment variable. setx CYGWIN "binmode" echo Removing extended ACLs so umask works as expected. + set -x setfacl -b . regress + icacls regress /c /t /q /Inheritance:d + icacls regress /c /t /q /Grant ${LOGNAME}:F + icacls regress /c /t /q /Remove:g "Authenticated Users" \ + BUILTIN\\Administrators BUILTIN Everyone System Users + takeown /F regress + icacls regress + set +x PACKAGES="$PACKAGES,autoconf,automake,cygwin-devel,gcc-core" PACKAGES="$PACKAGES,make,openssl,libssl-devel,zlib-devel" ;; From c991273c18afc490313a9f282383eaf59d9c13b9 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Wed, 30 Apr 2025 05:23:15 +0000 Subject: [PATCH 011/244] upstream: fix a out-of-bounds read if the known_hosts file is truncated after the hostname. Reported by the OpenAI Security Research Team ok deraadt@ OpenBSD-Commit-ID: c0b516d7c80c4779a403826f73bcd8adbbc54ebd --- hostfile.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/hostfile.c b/hostfile.c index c5669c703735..a4a5a9a5e3a3 100644 --- a/hostfile.c +++ b/hostfile.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hostfile.c,v 1.95 2023/02/21 06:48:18 dtucker Exp $ */ +/* $OpenBSD: hostfile.c,v 1.96 2025/04/30 05:23:15 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -810,6 +810,12 @@ hostkeys_foreach_file(const char *path, FILE *f, hostkeys_foreach_fn *callback, /* Find the end of the host name portion. */ for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++) ; + if (*cp2 == '\0') { + verbose_f("truncated line at %s:%lu", path, linenum); + if ((options & HKF_WANT_MATCH) == 0) + goto bad; + continue; + } lineinfo.hosts = cp; *cp2++ = '\0'; From e048230106fb3f5e7cc07abc311c6feb5f52fd05 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Wed, 30 Apr 2025 05:26:15 +0000 Subject: [PATCH 012/244] upstream: make writing known_hosts lines more atomic, by writing the entire line in one operation and using unbuffered stdio. Usually writes to this file are serialised on the "Are you sure you want to continue connecting?" prompt, but if host key checking is disabled and connections were being made with high concurrency then interleaved writes might have been possible. feedback/ok deraadt@ millert@ OpenBSD-Commit-ID: d11222b49dabe5cfe0937b49cb439ba3d4847b08 --- hostfile.c | 52 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/hostfile.c b/hostfile.c index a4a5a9a5e3a3..e941fc4509ad 100644 --- a/hostfile.c +++ b/hostfile.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hostfile.c,v 1.96 2025/04/30 05:23:15 djm Exp $ */ +/* $OpenBSD: hostfile.c,v 1.97 2025/04/30 05:26:15 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -434,7 +434,7 @@ lookup_marker_in_hostkeys(struct hostkeys *hostkeys, int want_marker) } static int -write_host_entry(FILE *f, const char *host, const char *ip, +format_host_entry(struct sshbuf *entry, const char *host, const char *ip, const struct sshkey *key, int store_hash) { int r, success = 0; @@ -449,22 +449,50 @@ write_host_entry(FILE *f, const char *host, const char *ip, free(lhost); return 0; } - fprintf(f, "%s ", hashed_host); - } else if (ip != NULL) - fprintf(f, "%s,%s ", lhost, ip); - else { - fprintf(f, "%s ", lhost); + if ((r = sshbuf_putf(entry, "%s ", hashed_host)) != 0) + fatal_fr(r, "sshbuf_putf"); + } else if (ip != NULL) { + if ((r = sshbuf_putf(entry, "%s,%s ", lhost, ip)) != 0) + fatal_fr(r, "sshbuf_putf"); + } else { + if ((r = sshbuf_putf(entry, "%s ", lhost)) != 0) + fatal_fr(r, "sshbuf_putf"); } free(hashed_host); free(lhost); - if ((r = sshkey_write(key, f)) == 0) + if ((r = sshkey_format_text(key, entry)) == 0) success = 1; else error_fr(r, "sshkey_write"); - fputc('\n', f); + if ((r = sshbuf_putf(entry, "\n")) != 0) + fatal_fr(r, "sshbuf_putf"); + /* If hashing is enabled, the IP address needs to go on its own line */ if (success && store_hash && ip != NULL) - success = write_host_entry(f, ip, NULL, key, 1); + success = format_host_entry(entry, ip, NULL, key, 1); + return success; +} + +static int +write_host_entry(FILE *f, const char *host, const char *ip, + const struct sshkey *key, int store_hash) +{ + int r, success = 0; + struct sshbuf *entry = NULL; + + if ((entry = sshbuf_new()) == NULL) + fatal_f("allocation failed"); + if ((r = format_host_entry(entry, host, ip, key, store_hash)) != 1) { + debug_f("failed to format host entry"); + goto out; + } + if ((r = fwrite(sshbuf_ptr(entry), sshbuf_len(entry), 1, f)) != 1) { + error_f("fwrite: %s", strerror(errno)); + goto out; + } + success = 1; + out: + sshbuf_free(entry); return success; } @@ -520,9 +548,9 @@ add_host_to_hostfile(const char *filename, const char *host, if (key == NULL) return 1; /* XXX ? */ hostfile_create_user_ssh_dir(filename, 0); - f = fopen(filename, "a+"); - if (!f) + if ((f = fopen(filename, "a+")) == NULL) return 0; + setvbuf(f, NULL, _IONBF, 0); /* Make sure we have a terminating newline. */ if (fseek(f, -1L, SEEK_END) == 0 && fgetc(f) != '\n') addnl = 1; From 566443b5f5d7bc4c5310313b4e46232760850c7a Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Mon, 5 May 2025 02:40:30 +0000 Subject: [PATCH 013/244] upstream: correct log messages; the reap function is used for more than just the preauth process now OpenBSD-Commit-ID: 768c5b674bd77802bb197c31dba78559f1174c02 --- monitor_wrap.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/monitor_wrap.c b/monitor_wrap.c index bd900b2f06ec..c30a7902d386 100644 --- a/monitor_wrap.c +++ b/monitor_wrap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor_wrap.c,v 1.138 2024/10/22 06:13:00 dtucker Exp $ */ +/* $OpenBSD: monitor_wrap.c,v 1.139 2025/05/05 02:40:30 djm Exp $ */ /* * Copyright 2002 Niels Provos * Copyright 2002 Markus Friedl @@ -126,17 +126,17 @@ mm_reap(void) } if (WIFEXITED(status)) { if (WEXITSTATUS(status) != 0) { - debug_f("preauth child exited with status %d", + debug_f("child exited with status %d", WEXITSTATUS(status)); cleanup_exit(255); } } else if (WIFSIGNALED(status)) { - error_f("preauth child terminated by signal %d", + error_f("child terminated by signal %d", WTERMSIG(status)); cleanup_exit(signal_is_crash(WTERMSIG(status)) ? EXIT_CHILD_CRASH : 255); } else { - error_f("preauth child terminated abnormally (status=0x%x)", + error_f("child terminated abnormally (status=0x%x)", status); cleanup_exit(EXIT_CHILD_CRASH); } From 80162f9d7e7eadca4ffd0bd1c015d38cb1821ab6 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Mon, 5 May 2025 02:48:06 +0000 Subject: [PATCH 014/244] upstream: Move agent listener sockets from /tmp to under ~/.ssh/agent for both ssh-agent(1) and forwarded sockets in sshd(8). This ensures processes (such as Firefox) that have restricted filesystem access that includes /tmp (via unveil(3)) do not have the ability to use keys in an agent. Moving the default directory has the consequence that the OS will no longer clean up stale agent sockets, so ssh-agent now gains this ability. To support $HOME on NFS, the socket path includes a truncated hash of the hostname. ssh-agent will by default only clean up sockets from the same hostname. ssh-agent gains some new flags: -U suppresses the automatic cleanup of stale sockets when it starts. -u forces a cleanup without keeping a running agent, -uu forces a cleanup that ignores the hostname. -T makes ssh-agent put the socket back in /tmp. feedback deraadt@ naddy@, doitdoitdoit deraadt@ OpenBSD-Commit-ID: 8383dabd98092fe5498d5f7f15c7d314b03a93e1 --- Makefile.in | 6 ++-- hostfile.c | 2 +- misc.c | 17 ++++++++++- misc.h | 8 ++++- pathnames.h | 9 +++++- session.c | 34 +++------------------ ssh-agent.1 | 32 ++++++++++++++++---- ssh-agent.c | 85 +++++++++++++++++++++++++++++++++++++++++++---------- 8 files changed, 136 insertions(+), 57 deletions(-) diff --git a/Makefile.in b/Makefile.in index f15ac558aea7..4550e17951f4 100644 --- a/Makefile.in +++ b/Makefile.in @@ -140,7 +140,7 @@ SSHD_SESSION_OBJS=sshd-session.o auth-rhosts.o auth-passwd.o \ auth2-gss.o gss-serv.o gss-serv-krb5.o \ loginrec.o auth-pam.o auth-shadow.o auth-sia.o \ sftp-server.o sftp-common.o \ - uidswap.o platform-listen.o $(SKOBJS) + uidswap.o platform-listen.o misc-agent.o $(SKOBJS) SSHD_AUTH_OBJS=sshd-auth.o \ auth2-methods.o \ @@ -155,7 +155,7 @@ SSHD_AUTH_OBJS=sshd-auth.o \ sandbox-null.o sandbox-rlimit.o sandbox-darwin.o \ sandbox-seccomp-filter.o sandbox-capsicum.o sandbox-solaris.o \ sftp-server.o sftp-common.o \ - uidswap.o $(SKOBJS) + uidswap.o misc-agent.o $(SKOBJS) SFTP_CLIENT_OBJS=sftp-common.o sftp-client.o sftp-glob.o @@ -163,7 +163,7 @@ SCP_OBJS= scp.o progressmeter.o $(SFTP_CLIENT_OBJS) SSHADD_OBJS= ssh-add.o $(SKOBJS) -SSHAGENT_OBJS= ssh-agent.o ssh-pkcs11-client.o $(SKOBJS) +SSHAGENT_OBJS= ssh-agent.o ssh-pkcs11-client.o misc-agent.o $(SKOBJS) SSHKEYGEN_OBJS= ssh-keygen.o sshsig.o $(SKOBJS) diff --git a/hostfile.c b/hostfile.c index e941fc4509ad..4b4a0e31ef38 100644 --- a/hostfile.c +++ b/hostfile.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hostfile.c,v 1.97 2025/04/30 05:26:15 djm Exp $ */ +/* $OpenBSD: hostfile.c,v 1.98 2025/05/05 02:48:07 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland diff --git a/misc.c b/misc.c index dd0bd032ae3c..25465dcd2d4f 100644 --- a/misc.c +++ b/misc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: misc.c,v 1.198 2024/10/24 03:14:37 djm Exp $ */ +/* $OpenBSD: misc.c,v 1.199 2025/05/05 02:48:06 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2005-2020 Damien Miller. All rights reserved. @@ -3138,3 +3138,18 @@ signal_is_crash(int sig) } return 0; } + +char * +get_homedir(void) +{ + char *cp; + struct passwd *pw; + + if ((cp = getenv("HOME")) != NULL && *cp != '\0') + return xstrdup(cp); + + if ((pw = getpwuid(getuid())) != NULL && *pw->pw_dir != '\0') + return xstrdup(pw->pw_dir); + + return NULL; +} diff --git a/misc.h b/misc.h index efecdf1ad6f9..a7afa23e8e92 100644 --- a/misc.h +++ b/misc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: misc.h,v 1.110 2024/09/25 01:24:04 djm Exp $ */ +/* $OpenBSD: misc.h,v 1.111 2025/05/05 02:48:06 djm Exp $ */ /* * Author: Tatu Ylonen @@ -108,6 +108,7 @@ int parse_pattern_interval(const char *, char **, int *); int path_absolute(const char *); int stdfd_devnull(int, int, int); int lib_contains_symbol(const char *, const char *); +char *get_homedir(void); void sock_set_v6only(int); @@ -231,6 +232,11 @@ int ptimeout_get_ms(struct timespec *pt); struct timespec *ptimeout_get_tsp(struct timespec *pt); int ptimeout_isset(struct timespec *pt); +/* misc-agent.c */ +char *agent_hostname_hash(void); +int agent_listener(const char *, const char *, int *, char **); +void agent_cleanup_stale(const char *, int); + /* readpass.c */ #define RP_ECHO 0x0001 diff --git a/pathnames.h b/pathnames.h index 1158bec96781..e07395cb6f26 100644 --- a/pathnames.h +++ b/pathnames.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pathnames.h,v 1.32 2024/05/17 00:30:24 djm Exp $ */ +/* $OpenBSD: pathnames.h,v 1.34 2025/05/05 02:48:06 djm Exp $ */ /* * Author: Tatu Ylonen @@ -67,6 +67,13 @@ */ #define _PATH_SSH_USER_DIR ".ssh" + +/* + * The directory in which ssh-agent sockets and agent sockets forwarded by + * sshd reside. This directory should not be world-readable. + */ +#define _PATH_SSH_AGENT_SOCKET_DIR _PATH_SSH_USER_DIR "/agent" + /* * Per-user file containing host keys of known hosts. This file need not be * readable by anyone except the user him/herself, though this does not diff --git a/session.c b/session.c index 6444c77f31c2..630e0e6a353c 100644 --- a/session.c +++ b/session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: session.c,v 1.341 2025/04/09 07:00:03 djm Exp $ */ +/* $OpenBSD: session.c,v 1.342 2025/05/05 02:48:06 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -175,7 +175,6 @@ static char *auth_info_file = NULL; /* Name and directory of socket for authentication agent forwarding. */ static char *auth_sock_name = NULL; -static char *auth_sock_dir = NULL; /* removes the agent forwarding socket */ @@ -185,7 +184,6 @@ auth_sock_cleanup_proc(struct passwd *pw) if (auth_sock_name != NULL) { temporarily_use_uid(pw); unlink(auth_sock_name); - rmdir(auth_sock_dir); auth_sock_name = NULL; restore_uid(); } @@ -205,32 +203,15 @@ auth_input_request_forwarding(struct ssh *ssh, struct passwd * pw) /* Temporarily drop privileged uid for mkdir/bind. */ temporarily_use_uid(pw); - /* Allocate a buffer for the socket name, and format the name. */ - auth_sock_dir = xstrdup("/tmp/ssh-XXXXXXXXXX"); - - /* Create private directory for socket */ - if (mkdtemp(auth_sock_dir) == NULL) { + if (agent_listener(pw->pw_dir, "sshd", &sock, &auth_sock_name) != 0) { + /* a more detailed error is already logged */ ssh_packet_send_debug(ssh, "Agent forwarding disabled: " - "mkdtemp() failed: %.100s", strerror(errno)); + "couldn't create listener socket"); restore_uid(); - free(auth_sock_dir); - auth_sock_dir = NULL; goto authsock_err; } - - xasprintf(&auth_sock_name, "%s/agent.%ld", - auth_sock_dir, (long) getpid()); - - /* Start a Unix listener on auth_sock_name. */ - sock = unix_listener(auth_sock_name, SSH_LISTEN_BACKLOG, 0); - - /* Restore the privileged uid. */ restore_uid(); - /* Check for socket/bind/listen failure. */ - if (sock < 0) - goto authsock_err; - /* Allocate a channel for the authentication agent socket. */ nc = channel_new(ssh, "auth-listener", SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1, @@ -241,16 +222,9 @@ auth_input_request_forwarding(struct ssh *ssh, struct passwd * pw) authsock_err: free(auth_sock_name); - if (auth_sock_dir != NULL) { - temporarily_use_uid(pw); - rmdir(auth_sock_dir); - restore_uid(); - free(auth_sock_dir); - } if (sock != -1) close(sock); auth_sock_name = NULL; - auth_sock_dir = NULL; return 0; } diff --git a/ssh-agent.1 b/ssh-agent.1 index 533ad6d3a6d2..3b515ac42384 100644 --- a/ssh-agent.1 +++ b/ssh-agent.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-agent.1,v 1.82 2025/02/09 18:24:08 schwarze Exp $ +.\" $OpenBSD: ssh-agent.1,v 1.83 2025/05/05 02:48:06 djm Exp $ .\" .\" Author: Tatu Ylonen .\" Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -34,7 +34,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd $Mdocdate: February 9 2025 $ +.Dd $Mdocdate: May 5 2025 $ .Dt SSH-AGENT 1 .Os .Sh NAME @@ -43,13 +43,14 @@ .Sh SYNOPSIS .Nm ssh-agent .Op Fl c | s -.Op Fl \&Dd +.Op Fl \&DdTU .Op Fl a Ar bind_address .Op Fl E Ar fingerprint_hash .Op Fl O Ar option .Op Fl P Ar allowed_providers .Op Fl t Ar life .Nm ssh-agent +.Op Fl TU .Op Fl a Ar bind_address .Op Fl E Ar fingerprint_hash .Op Fl O Ar option @@ -59,6 +60,8 @@ .Nm ssh-agent .Op Fl c | s .Fl k +.Nm ssh-agent +.Fl u .Sh DESCRIPTION .Nm is a program to hold private keys used for public key authentication. @@ -74,8 +77,8 @@ Bind the agent to the .Ux Ns -domain socket .Ar bind_address . -The default is -.Pa $TMPDIR/ssh-XXXXXXXXXX/agent.\*(Ltppid\*(Gt . +The default is to create a socket at a random path matching +.Pa $HOME/.ssh/agent/s.* .It Fl c Generate C-shell commands on standard output. This is the default if @@ -173,6 +176,11 @@ Generate Bourne shell commands on standard output. This is the default if .Ev SHELL does not look like it's a csh style of shell. +.It Fl T +Bind the agent socket in a randomised subdirectory of the form +.Pa $TMPDIR/ssh-XXXXXXXXXX/agent.\*(Ltppid\*(Gt , +instead of the default behaviour of using a randomised name matching +.Pa $HOME/.ssh/agent/s.* . .It Fl t Ar life Set a default value for the maximum lifetime of identities added to the agent. The lifetime may be specified in seconds or in a time format specified in @@ -186,6 +194,20 @@ If a command (and optional arguments) is given, this is executed as a subprocess of the agent. The agent exits automatically when the command given on the command line terminates. +.It Fl U +Instructs +.Nm +not to clean up stale agent sockets under +.Pa $HOME/.ssh/agent/ . +.It Fl u +Instructs +.Nm +to only clean up stale agent sockets under +.Pa $HOME/.ssh/agent/ +and then exit immediately. +If this option is given twice, +.Nm +will delete stale agent sockets regardless of the host name that created them. .El .Pp There are three main ways to get an agent set up. diff --git a/ssh-agent.c b/ssh-agent.c index 55b9f44f4d4a..8a88ef3fd1c0 100644 --- a/ssh-agent.c +++ b/ssh-agent.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-agent.c,v 1.311 2025/04/15 09:22:25 dtucker Exp $ */ +/* $OpenBSD: ssh-agent.c,v 1.312 2025/05/05 02:48:06 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -2208,20 +2208,23 @@ static void usage(void) { fprintf(stderr, - "usage: ssh-agent [-c | -s] [-Dd] [-a bind_address] [-E fingerprint_hash]\n" + "usage: ssh-agent [-c | -s] [-DdTU] [-a bind_address] [-E fingerprint_hash]\n" " [-O option] [-P allowed_providers] [-t life]\n" - " ssh-agent [-a bind_address] [-E fingerprint_hash] [-O option]\n" + " ssh-agent [-TU] [-a bind_address] [-E fingerprint_hash] [-O option]\n" " [-P allowed_providers] [-t life] command [arg ...]\n" - " ssh-agent [-c | -s] -k\n"); + " ssh-agent [-c | -s] -k\n" + " ssh-agent -u\n"); exit(1); } int main(int ac, char **av) { - int c_flag = 0, d_flag = 0, D_flag = 0, k_flag = 0, s_flag = 0; + int c_flag = 0, d_flag = 0, D_flag = 0, k_flag = 0; + int s_flag = 0, T_flag = 0, u_flag = 0, U_flag = 0; int sock = -1, ch, result, saved_errno; - char *shell, *format, *fdstr, *pidstr, *agentsocket = NULL; + char *homedir = NULL, *shell, *format, *pidstr, *agentsocket = NULL; + char *fdstr; const char *errstr = NULL; const char *ccp; #ifdef HAVE_SETRLIMIT @@ -2256,7 +2259,7 @@ main(int ac, char **av) __progname = ssh_get_progname(av[0]); seed_rng(); - while ((ch = getopt(ac, av, "cDdksE:a:O:P:t:")) != -1) { + while ((ch = getopt(ac, av, "cDdksTuUE:a:O:P:t:")) != -1) { switch (ch) { case 'E': fingerprint_hash = ssh_digest_alg_by_name(optarg); @@ -2313,6 +2316,15 @@ main(int ac, char **av) usage(); } break; + case 'T': + T_flag++; + break; + case 'u': + u_flag++; + break; + case 'U': + U_flag++; + break; default: usage(); } @@ -2320,9 +2332,14 @@ main(int ac, char **av) ac -= optind; av += optind; - if (ac > 0 && (c_flag || k_flag || s_flag || d_flag || D_flag)) + if (ac > 0 && + (c_flag || k_flag || s_flag || d_flag || D_flag || u_flag)) usage(); + log_init(__progname, + d_flag ? SYSLOG_LEVEL_DEBUG3 : SYSLOG_LEVEL_INFO, + SYSLOG_FACILITY_AUTH, 1); + if (allowed_providers == NULL) allowed_providers = xstrdup(DEFAULT_ALLOWED_PROVIDERS); if (websafe_allowlist == NULL) @@ -2358,6 +2375,14 @@ main(int ac, char **av) printf("echo Agent pid %ld killed;\n", (long)pid); exit(0); } + if (u_flag) { + if ((homedir = get_homedir()) == NULL) + fatal("Couldn't determine home directory"); + agent_cleanup_stale(homedir, u_flag > 1); + printf("Deleted stale agent sockets in ~/%s\n", + _PATH_SSH_AGENT_SOCKET_DIR); + exit(0); + } /* * Minimum file descriptors: @@ -2391,22 +2416,52 @@ main(int ac, char **av) sock = 3; } - /* Otherwise, create private directory for agent socket */ - if (sock == -1) { - if (agentsocket == NULL) { + if (sock == -1 && agentsocket == NULL && !T_flag) { + /* Default case: ~/.ssh/agent/[socket] */ + if ((homedir = get_homedir()) == NULL) + fatal("Couldn't determine home directory"); + if (!U_flag) + agent_cleanup_stale(homedir, 0); + if (agent_listener(homedir, "agent", &sock, &agentsocket) != 0) + fatal_f("Couldn't prepare agent socket"); + if (strlcpy(socket_name, agentsocket, + sizeof(socket_name)) >= sizeof(socket_name)) { + fatal_f("Socket path \"%s\" too long", + agentsocket); + } + free(homedir); + free(agentsocket); + agentsocket = NULL; + } else if (sock == -1) { + if (T_flag) { + /* + * Create private directory for agent socket + * in $TMPDIR. + */ mktemp_proto(socket_dir, sizeof(socket_dir)); if (mkdtemp(socket_dir) == NULL) { perror("mkdtemp: private socket dir"); exit(1); } - snprintf(socket_name, sizeof socket_name, - "%s/agent.%ld", socket_dir, - (long)parent_pid); + snprintf(socket_name, sizeof(socket_name), + "%s/agent.%ld", socket_dir, (long)parent_pid); } else { /* Try to use specified agent socket */ socket_dir[0] = '\0'; - strlcpy(socket_name, agentsocket, sizeof socket_name); + if (strlcpy(socket_name, agentsocket, + sizeof(socket_name)) >= sizeof(socket_name)) { + fatal_f("Socket path \"%s\" too long", + agentsocket); + } + } + /* Listen on socket */ + prev_mask = umask(0177); + if ((sock = unix_listener(socket_name, + SSH_LISTEN_BACKLOG, 0)) < 0) { + *socket_name = '\0'; /* Don't unlink existing file */ + cleanup_exit(1); } + umask(prev_mask); } closefrom(sock == -1 ? STDERR_FILENO + 1 : sock + 1); From 12912429cf39cfeca97dd18a8f875ad9824d1751 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Mon, 5 May 2025 03:35:06 +0000 Subject: [PATCH 015/244] upstream: missing file in previous commit OpenBSD-Commit-ID: e526c97fcb2fd9f0b7b229720972426ab437d7eb --- misc-agent.c | 329 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 329 insertions(+) create mode 100644 misc-agent.c diff --git a/misc-agent.c b/misc-agent.c new file mode 100644 index 000000000000..d065ab0e5b7a --- /dev/null +++ b/misc-agent.c @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2025 Damien Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "digest.h" +#include "log.h" +#include "misc.h" +#include "pathnames.h" +#include "ssh.h" +#include "xmalloc.h" + +/* stuff shared by agent listeners (ssh-agent and sshd agent forwarding) */ + +#define SOCKET_HOSTNAME_HASHLEN 10 /* length of hostname hash in socket path */ + +/* used for presenting random strings in unix_listener_tmp and hostname_hash */ +static const char presentation_chars[] = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + +/* returns a text-encoded hash of the hostname of specified length (max 64) */ +static char * +hostname_hash(size_t len) +{ + char hostname[NI_MAXHOST], p[65]; + u_char hash[64]; + int r; + size_t l, i; + + l = ssh_digest_bytes(SSH_DIGEST_SHA512); + if (len > 64) { + error_f("bad length %zu > max %zd", len, l - 1); + return NULL; + } + if (gethostname(hostname, sizeof(hostname)) == -1) { + error_f("gethostname: %s", strerror(errno)); + return NULL; + } + if ((r = ssh_digest_memory(SSH_DIGEST_SHA512, + hostname, strlen(hostname), hash, sizeof(hash))) != 0) { + error_fr(r, "ssh_digest_memory"); + return NULL; + } + memset(p, '\0', sizeof(p)); + for (i = 0; i < l; i++) + p[i] = presentation_chars[ + hash[i] % (sizeof(presentation_chars) - 1)]; + /* debug3_f("hostname \"%s\" => hash \"%s\"", hostname, p); */ + p[len] = '\0'; + return xstrdup(p); +} + +char * +agent_hostname_hash(void) +{ + return hostname_hash(SOCKET_HOSTNAME_HASHLEN); +} + +/* + * Creates a unix listener at a mkstemp(3)-style path, e.g. "/dir/sock.XXXXXX" + * Supplied path is modified to the actual one used. + */ +static int +unix_listener_tmp(char *path, int backlog) +{ + struct sockaddr_un sunaddr; + int good, sock = -1; + size_t i, xstart; + mode_t prev_mask; + + /* Find first 'X' template character back from end of string */ + xstart = strlen(path); + while (xstart > 0 && path[xstart - 1] == 'X') + xstart--; + + memset(&sunaddr, 0, sizeof(sunaddr)); + sunaddr.sun_family = AF_UNIX; + prev_mask = umask(0177); + for (good = 0; !good;) { + sock = -1; + /* Randomise path suffix */ + for (i = xstart; path[i] != '\0'; i++) { + path[i] = presentation_chars[ + arc4random_uniform(sizeof(presentation_chars)-1)]; + } + debug_f("trying path \"%s\"", path); + + if (strlcpy(sunaddr.sun_path, path, + sizeof(sunaddr.sun_path)) >= sizeof(sunaddr.sun_path)) { + error_f("path \"%s\" too long for Unix domain socket", + path); + break; + } + + if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) { + error_f("socket: %.100s", strerror(errno)); + break; + } + if (bind(sock, (struct sockaddr *)&sunaddr, + sizeof(sunaddr)) == -1) { + if (errno == EADDRINUSE) { + error_f("bind \"%s\": %.100s", + path, strerror(errno)); + close(sock); + sock = -1; + continue; + } + error_f("bind \"%s\": %.100s", path, strerror(errno)); + break; + } + if (listen(sock, backlog) == -1) { + error_f("listen \"%s\": %s", path, strerror(errno)); + break; + } + good = 1; + } + umask(prev_mask); + if (good) { + debug3_f("listening on unix socket \"%s\" as fd=%d", + path, sock); + } else if (sock != -1) { + close(sock); + sock = -1; + } + return sock; +} + +/* + * Create a subdirectory under the supplied home directory if it + * doesn't already exist + */ +static int +ensure_mkdir(const char *homedir, const char *subdir) +{ + char *path; + + xasprintf(&path, "%s/%s", homedir, subdir); + if (mkdir(path, 0700) == 0) + debug("created directory %s", path); + else if (errno != EEXIST) { + error_f("mkdir %s: %s", path, strerror(errno)); + return -1; + } + free(path); + return 0; +} + +static int +agent_prepare_sockdir(const char *homedir) +{ + if (homedir == NULL || *homedir == '\0' || + ensure_mkdir(homedir, _PATH_SSH_USER_DIR) != 0 || + ensure_mkdir(homedir, _PATH_SSH_AGENT_SOCKET_DIR) != 0) + return -1; + return 0; +} + + +/* Get a path template for an agent socket in the user's homedir */ +static char * +agent_socket_template(const char *homedir, const char *tag) +{ + char *hostnamehash, *ret; + + if ((hostnamehash = hostname_hash(SOCKET_HOSTNAME_HASHLEN)) == NULL) + return NULL; + xasprintf(&ret, "%s/%s/s.%s.%s.XXXXXXXXXX", + homedir, _PATH_SSH_AGENT_SOCKET_DIR, hostnamehash, tag); + free(hostnamehash); + return ret; +} + +int +agent_listener(const char *homedir, const char *tag, int *sockp, char **pathp) +{ + int sock; + char *path; + + *sockp = -1; + *pathp = NULL; + + if (agent_prepare_sockdir(homedir) != 0) + return -1; /* error already logged */ + if ((path = agent_socket_template(homedir, tag)) == NULL) + return -1; /* error already logged */ + if ((sock = unix_listener_tmp(path, SSH_LISTEN_BACKLOG)) == -1) { + free(path); + return -1; /* error already logged */ + } + /* success */ + *sockp = sock; + *pathp = path; + return 0; +} + +static int +socket_is_stale(const char *path) +{ + int fd, r; + struct sockaddr_un sun; + socklen_t l = sizeof(r); + + /* attempt non-blocking connect on socket */ + memset(&sun, '\0', sizeof(sun)); + sun.sun_family = AF_UNIX; + if (strlcpy(sun.sun_path, path, + sizeof(sun.sun_path)) >= sizeof(sun.sun_path)) { + debug_f("path for \"%s\" too long for sockaddr_un", path); + return 0; + } + if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) { + error_f("socket: %s", strerror(errno)); + return 0; + } + set_nonblock(fd); + /* a socket without a listener should yield an error immediately */ + if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { + debug_f("connect \"%s\": %s", path, strerror(errno)); + close(fd); + return 1; + } + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &r, &l) == -1) { + debug_f("getsockopt: %s", strerror(errno)); + close(fd); + return 0; + } + if (r != 0) { + debug_f("socket error on %s: %s", path, strerror(errno)); + close(fd); + return 1; + } + close(fd); + debug_f("socket %s seems still active", path); + return 0; +} + +void +agent_cleanup_stale(const char *homedir, int ignore_hosthash) +{ + DIR *d; + struct dirent *dp; + struct stat sb; + char *prefix = NULL, *dirpath, *path; + struct timespec now, sub; + + /* Only consider sockets last modified > 1 hour ago */ + if (clock_gettime(CLOCK_REALTIME, &now) != 0) { + error_f("clock_gettime: %s", strerror(errno)); + return; + } + sub.tv_sec = 60 * 60; + sub.tv_nsec = 0; + timespecsub(&now, &sub, &now); + + /* Only consider sockets from the same hostname */ + if (!ignore_hosthash) { + if ((path = agent_hostname_hash()) == NULL) { + error_f("couldn't get hostname hash"); + return; + } + xasprintf(&prefix, "s.%s.", path); + free(path); + } + + xasprintf(&dirpath, "%s/%s", homedir, _PATH_SSH_AGENT_SOCKET_DIR); + if ((d = opendir(dirpath)) == NULL) { + if (errno != ENOENT) + error_f("opendir \"%s\": %s", dirpath, strerror(errno)); + free(dirpath); + return; + } + while ((dp = readdir(d)) != NULL) { + if (dp->d_type != DT_SOCK && dp->d_type != DT_UNKNOWN) + continue; + if (fstatat(dirfd(d), dp->d_name, + &sb, AT_SYMLINK_NOFOLLOW) != 0 && errno != ENOENT) { + error_f("stat \"%s/%s\": %s", + dirpath, dp->d_name, strerror(errno)); + continue; + } + if (!S_ISSOCK(sb.st_mode)) + continue; + if (timespeccmp(&sb.st_mtim, &now, >)) { + debug3_f("Ignoring recent socket \"%s/%s\"", + dirpath, dp->d_name); + continue; + } + if (!ignore_hosthash && + strncmp(dp->d_name, prefix, strlen(prefix)) != 0) { + debug3_f("Ignoring socket \"%s/%s\" " + "from different host", dirpath, dp->d_name); + continue; + } + xasprintf(&path, "%s/%s", dirpath, dp->d_name); + if (socket_is_stale(path)) { + debug_f("cleanup stale socket %s", path); + unlinkat(dirfd(d), dp->d_name, 0); + } + free(path); + } + closedir(d); + free(dirpath); + free(prefix); +} + From 6ab8133c067a8e91ba69ce7ca04f95b50f2f2d7b Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Mon, 5 May 2025 14:59:30 +1000 Subject: [PATCH 016/244] depend --- .depend | 1 + 1 file changed, 1 insertion(+) diff --git a/.depend b/.depend index 152905fb7b78..975d4427a2fb 100644 --- a/.depend +++ b/.depend @@ -79,6 +79,7 @@ loginrec.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-comp logintest.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h loginrec.h mac.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h digest.h hmac.h umac.h mac.h misc.h ssherr.h sshbuf.h openbsd-compat/openssl-compat.h match.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h match.h misc.h +misc-agent.o: digest.h log.h ssherr.h misc.h pathnames.h ssh.h xmalloc.h misc.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h misc.h log.h ssherr.h ssh.h sshbuf.h moduli.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h monitor.o: chacha.h poly1305.h cipher-aesctr.h rijndael.h kex.h mac.h crypto_api.h dh.h packet.h dispatch.h auth-options.h sshpty.h channels.h session.h sshlogin.h canohost.h log.h ssherr.h misc.h servconf.h monitor.h monitor_wrap.h monitor_fdpass.h compat.h ssh2.h authfd.h match.h sk-api.h srclimit.h From 7a7cc3cf721fe7fe9f4925d92bb7c694b8550a7f Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Mon, 5 May 2025 18:51:34 +1000 Subject: [PATCH 017/244] Cygwin install in back on D: --- .github/setup_ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/setup_ci.sh b/.github/setup_ci.sh index e3e28da6f1b1..9b2767a8514d 100755 --- a/.github/setup_ci.sh +++ b/.github/setup_ci.sh @@ -192,7 +192,7 @@ while [ ! -z "$PACKAGES" ] && [ "$tries" -gt "0" ]; do fi ;; setup) - if /cygdrive/d/setup.exe -q -P `echo "$PACKAGES" | tr ' ' ,`; then + if /cygdrive/c/setup.exe -q -P `echo "$PACKAGES" | tr ' ' ,`; then PACKAGES="" fi ;; From 7c0e6626e4be53efcfbb92f0c6382a76f1138e38 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Mon, 5 May 2025 19:08:48 +1000 Subject: [PATCH 018/244] includes.h for compat, time.h for clock_gettime. --- misc-agent.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/misc-agent.c b/misc-agent.c index d065ab0e5b7a..a8605302ef8c 100644 --- a/misc-agent.c +++ b/misc-agent.c @@ -14,6 +14,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include #include #include @@ -25,6 +27,9 @@ #include #include #include +#ifdef HAVE_TIME_H +# include +#endif #include #include "digest.h" From 27861e9b15151898841097c14ee974c026093131 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Mon, 5 May 2025 19:09:25 +1000 Subject: [PATCH 019/244] Supply timespecsub if needed. --- defines.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/defines.h b/defines.h index 3721ae16ef92..a1bd6fad345e 100644 --- a/defines.h +++ b/defines.h @@ -515,6 +515,13 @@ struct winsize { } while (0) #endif +#ifndef timespeccmp +#define timespeccmp(tsp, usp, cmp) \ + (((tsp)->tv_sec == (usp)->tv_sec) ? \ + ((tsp)->tv_nsec cmp (usp)->tv_nsec) : \ + ((tsp)->tv_sec cmp (usp)->tv_sec)) +#endif + #ifndef TIMEVAL_TO_TIMESPEC #define TIMEVAL_TO_TIMESPEC(tv, ts) { \ (ts)->tv_sec = (tv)->tv_sec; \ From 61525ba967ac1bb7394ea0792aa6030bcbbad049 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Mon, 5 May 2025 20:45:42 +1000 Subject: [PATCH 020/244] Handle systems that don't have st_mtim. Ignores nanoseconds, but it's checking for >1h old so a few nanoseconds shouldn't matter much. Fixes build on Mac OS X. --- misc-agent.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/misc-agent.c b/misc-agent.c index a8605302ef8c..f13ccdf26b5d 100644 --- a/misc-agent.c +++ b/misc-agent.c @@ -270,7 +270,7 @@ agent_cleanup_stale(const char *homedir, int ignore_hosthash) struct dirent *dp; struct stat sb; char *prefix = NULL, *dirpath, *path; - struct timespec now, sub; + struct timespec now, sub, *mtimp = NULL; /* Only consider sockets last modified > 1 hour ago */ if (clock_gettime(CLOCK_REALTIME, &now) != 0) { @@ -309,7 +309,14 @@ agent_cleanup_stale(const char *homedir, int ignore_hosthash) } if (!S_ISSOCK(sb.st_mode)) continue; - if (timespeccmp(&sb.st_mtim, &now, >)) { +#ifdef HAVE_STRUCT_STAT_ST_MTIM + mtimp = &sb.st_mtim; +#else + sub.tv_sec = sb.st_mtime; + sub.tv_nsec = 0; + mtimp = ⊂ +#endif + if (timespeccmp(mtimp, &now, >)) { debug3_f("Ignoring recent socket \"%s/%s\"", dirpath, dp->d_name); continue; From 57eb87b15bd0343372f99d661ce95efb25a16f1e Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Tue, 6 May 2025 08:07:23 +1000 Subject: [PATCH 021/244] Boringssl now puts libcrypto in a different place. --- .github/setup_ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/setup_ci.sh b/.github/setup_ci.sh index 9b2767a8514d..df70c96ecb8a 100755 --- a/.github/setup_ci.sh +++ b/.github/setup_ci.sh @@ -248,7 +248,7 @@ if [ ! -z "${INSTALL_BORINGSSL}" ]; then cd ${HOME}/boringssl && mkdir build && cd build && cmake -GNinja -DCMAKE_POSITION_INDEPENDENT_CODE=ON .. && ninja && mkdir -p /opt/boringssl/lib && - cp ${HOME}/boringssl/build/crypto/libcrypto.a /opt/boringssl/lib && + cp ${HOME}/boringssl/build/libcrypto.a /opt/boringssl/lib && cp -r ${HOME}/boringssl/include /opt/boringssl) fi From d2480827b3ef6ec119965822afdff35d734b2dee Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Tue, 6 May 2025 08:15:34 +1000 Subject: [PATCH 022/244] New location of cygwin setup. --- .github/setup_ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/setup_ci.sh b/.github/setup_ci.sh index df70c96ecb8a..e4c7b041aa50 100755 --- a/.github/setup_ci.sh +++ b/.github/setup_ci.sh @@ -192,7 +192,7 @@ while [ ! -z "$PACKAGES" ] && [ "$tries" -gt "0" ]; do fi ;; setup) - if /cygdrive/c/setup.exe -q -P `echo "$PACKAGES" | tr ' ' ,`; then + if /cygdrive/d/cygwin/setup.exe -q -P `echo "$PACKAGES" | tr ' ' ,`; then PACKAGES="" fi ;; From 5fd6ef297dec23e3574646b6334087131230d0a6 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Tue, 6 May 2025 19:01:00 +1000 Subject: [PATCH 023/244] Add minimal implementations of fstatat and unlinkat. Fixes build on some pre-POSIX.1-2008 platforms. --- configure.ac | 2 ++ openbsd-compat/bsd-misc.c | 40 +++++++++++++++++++++++++++++++++++++++ openbsd-compat/bsd-misc.h | 8 ++++++++ 3 files changed, 50 insertions(+) diff --git a/configure.ac b/configure.ac index 69b74add8d00..b19f790cdd54 100644 --- a/configure.ac +++ b/configure.ac @@ -2004,6 +2004,7 @@ AC_CHECK_FUNCS([ \ fnmatch \ freeaddrinfo \ freezero \ + fstatat \ fstatfs \ fstatvfs \ futimes \ @@ -2099,6 +2100,7 @@ AC_CHECK_FUNCS([ \ timegm \ timingsafe_bcmp \ truncate \ + unlinkat \ unsetenv \ updwtmpx \ utimensat \ diff --git a/openbsd-compat/bsd-misc.c b/openbsd-compat/bsd-misc.c index 226a5915bd1d..b26b4ba4670e 100644 --- a/openbsd-compat/bsd-misc.c +++ b/openbsd-compat/bsd-misc.c @@ -220,6 +220,46 @@ fchmodat(int fd, const char *path, mode_t mode, int flag) } #endif +#ifndef HAVE_FSTATAT +/* + * A limited implementation of fstatat that just has what OpenSSH uses: + * cwd-relative and absolute paths, with or without following symlinks. + */ +int +fstatat(int dirfd, const char *path, struct stat *sb, int flag) +{ + if (dirfd != AT_FDCWD && path && path[0] != '/') { + errno = ENOSYS; + return -1; + } + if (flag == 0) + return stat(path, sb); + else if (flag == AT_SYMLINK_NOFOLLOW) + return lstat(path, sb); + errno = ENOSYS; + return -1; +} +#endif + +#ifndef HAVE_UNLINKAT +/* + * A limited implementation of unlinkat that just has what OpenSSH uses: + * cwd-relative and absolute paths. + */ +int +unlinkat(int dirfd, const char *path, int flag) +{ + if (dirfd != AT_FDCWD && path && path[0] != '/') { + errno = ENOSYS; + return -1; + } + if (flag == 0) + return unlink(path); + errno = ENOSYS; + return -1; +} +#endif + #ifndef HAVE_TRUNCATE int truncate(const char *path, off_t length) { diff --git a/openbsd-compat/bsd-misc.h b/openbsd-compat/bsd-misc.h index 61ead1b7fad0..edb0fcc8ca2b 100644 --- a/openbsd-compat/bsd-misc.h +++ b/openbsd-compat/bsd-misc.h @@ -77,6 +77,14 @@ int fchmodat(int, const char *, mode_t, int); int fchownat(int, const char *, uid_t, gid_t, int); #endif +#ifdef HAVE_FSTATAT +int fstatat(int, const char *, struct stat *, int); +#endif + +#ifdef HAVE_UNLINKAT +int unlinkat(int, const char *, int); +#endif + #ifndef HAVE_TRUNCATE int truncate (const char *, off_t); #endif /* HAVE_TRUNCATE */ From fe883543bece18c975fa53aa02104f0433645d99 Mon Sep 17 00:00:00 2001 From: "jmc@openbsd.org" Date: Mon, 5 May 2025 05:47:28 +0000 Subject: [PATCH 024/244] upstream: - add full stop to the text in -a - move the -U and -u text to the correct place OpenBSD-Commit-ID: 2fb484337a0978c703f61983bb14bc5cbaf898c2 --- ssh-agent.1 | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ssh-agent.1 b/ssh-agent.1 index 3b515ac42384..9f56e3efdc08 100644 --- a/ssh-agent.1 +++ b/ssh-agent.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-agent.1,v 1.83 2025/05/05 02:48:06 djm Exp $ +.\" $OpenBSD: ssh-agent.1,v 1.84 2025/05/05 05:47:28 jmc Exp $ .\" .\" Author: Tatu Ylonen .\" Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -78,7 +78,7 @@ Bind the agent to the socket .Ar bind_address . The default is to create a socket at a random path matching -.Pa $HOME/.ssh/agent/s.* +.Pa $HOME/.ssh/agent/s.* . .It Fl c Generate C-shell commands on standard output. This is the default if @@ -189,11 +189,6 @@ A lifetime specified for an identity with .Xr ssh-add 1 overrides this value. Without this option the default maximum lifetime is forever. -.It Ar command Op Ar arg ... -If a command (and optional arguments) is given, -this is executed as a subprocess of the agent. -The agent exits automatically when the command given on the command -line terminates. .It Fl U Instructs .Nm @@ -208,6 +203,11 @@ and then exit immediately. If this option is given twice, .Nm will delete stale agent sockets regardless of the host name that created them. +.It Ar command Op Ar arg ... +If a command (and optional arguments) is given, +this is executed as a subprocess of the agent. +The agent exits automatically when the command given on the command +line terminates. .El .Pp There are three main ways to get an agent set up. From 928f8dcc1bb622c25be409c34374b655d0149373 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Mon, 5 May 2025 05:51:11 +0000 Subject: [PATCH 025/244] upstream: Now that there's an I-D for certificate keys, refer to that instead of the much more basic format description we had previously. OpenBSD-Commit-ID: cf01e0727a813fee8626ad7b3aa240621cc92014 --- PROTOCOL | 4 +- PROTOCOL.certkeys | 326 ---------------------------------------------- 2 files changed, 2 insertions(+), 328 deletions(-) delete mode 100644 PROTOCOL.certkeys diff --git a/PROTOCOL b/PROTOCOL index 26387793febc..a0a9837efe3e 100644 --- a/PROTOCOL +++ b/PROTOCOL @@ -41,7 +41,7 @@ https://www.openssh.com/txt/draft-miller-secsh-compression-delayed-00.txt OpenSSH introduces new public key algorithms to support certificate authentication for users and host keys. These methods are documented -in the file PROTOCOL.certkeys +in at https://datatracker.ietf.org/doc/draft-miller-ssh-cert/ 1.4. transport: Elliptic Curve cryptography @@ -792,4 +792,4 @@ master instance and later clients. OpenSSH extends the usual agent protocol. These changes are documented in the PROTOCOL.agent file. -$OpenBSD: PROTOCOL,v 1.55 2024/01/08 05:05:15 djm Exp $ +$OpenBSD: PROTOCOL,v 1.56 2025/05/05 05:51:11 djm Exp $ diff --git a/PROTOCOL.certkeys b/PROTOCOL.certkeys deleted file mode 100644 index 0a212c635c5d..000000000000 --- a/PROTOCOL.certkeys +++ /dev/null @@ -1,326 +0,0 @@ -This document describes a simple public-key certificate authentication -system for use by SSH. - -Background ----------- - -The SSH protocol currently supports a simple public key authentication -mechanism. Unlike other public key implementations, SSH eschews the use -of X.509 certificates and uses raw keys. This approach has some benefits -relating to simplicity of configuration and minimisation of attack -surface, but it does not support the important use-cases of centrally -managed, passwordless authentication and centrally certified host keys. - -These protocol extensions build on the simple public key authentication -system already in SSH to allow certificate-based authentication. The -certificates used are not traditional X.509 certificates, with numerous -options and complex encoding rules, but something rather more minimal: a -key, some identity information and usage options that have been signed -with some other trusted key. - -A sshd server may be configured to allow authentication via certified -keys, by extending the existing ~/.ssh/authorized_keys mechanism to -allow specification of certification authority keys in addition to -raw user keys. The ssh client will support automatic verification of -acceptance of certified host keys, by adding a similar ability to -specify CA keys in ~/.ssh/known_hosts. - -All certificate types include certification information along with the -public key that is used to sign challenges. In OpenSSH, ssh-keygen -performs the CA signing operation. - -Certified keys are represented using new key types: - - ssh-rsa-cert-v01@openssh.com - ssh-dss-cert-v01@openssh.com - ecdsa-sha2-nistp256-cert-v01@openssh.com - ecdsa-sha2-nistp384-cert-v01@openssh.com - ecdsa-sha2-nistp521-cert-v01@openssh.com - ssh-ed25519-cert-v01@openssh.com - -Two additional types exist for RSA certificates to force use of -SHA-2 signatures (SHA-256 and SHA-512 respectively): - - rsa-sha2-256-cert-v01@openssh.com - rsa-sha2-512-cert-v01@openssh.com - -These RSA/SHA-2 types should not appear in keys at rest or transmitted -on the wire, but do appear in a SSH_MSG_KEXINIT's host-key algorithms -field or in the "public key algorithm name" field of a "publickey" -SSH_USERAUTH_REQUEST to indicate that the signature will use the -specified algorithm. - -Protocol extensions -------------------- - -The SSH wire protocol includes several extensibility mechanisms. -These modifications shall take advantage of namespaced public key -algorithm names to add support for certificate authentication without -breaking the protocol - implementations that do not support the -extensions will simply ignore them. - -Authentication using the new key formats described below proceeds -using the existing SSH "publickey" authentication method described -in RFC4252 section 7. - -New public key formats ----------------------- - -The certificate key types take a similar high-level format (note: data -types and encoding are as per RFC4251 section 5). The serialised wire -encoding of these certificates is also used for storing them on disk. - -#define SSH_CERT_TYPE_USER 1 -#define SSH_CERT_TYPE_HOST 2 - -RSA certificate - - string "ssh-rsa-cert-v01@openssh.com" - string nonce - mpint e - mpint n - uint64 serial - uint32 type - string key id - string valid principals - uint64 valid after - uint64 valid before - string critical options - string extensions - string reserved - string signature key - string signature - -DSA certificate - - string "ssh-dss-cert-v01@openssh.com" - string nonce - mpint p - mpint q - mpint g - mpint y - uint64 serial - uint32 type - string key id - string valid principals - uint64 valid after - uint64 valid before - string critical options - string extensions - string reserved - string signature key - string signature - -ECDSA certificate - - string "ecdsa-sha2-nistp256-cert-v01@openssh.com" | - "ecdsa-sha2-nistp384-cert-v01@openssh.com" | - "ecdsa-sha2-nistp521-cert-v01@openssh.com" - string nonce - string curve - string public_key - uint64 serial - uint32 type - string key id - string valid principals - uint64 valid after - uint64 valid before - string critical options - string extensions - string reserved - string signature key - string signature - -ED25519 certificate - - string "ssh-ed25519-cert-v01@openssh.com" - string nonce - string pk - uint64 serial - uint32 type - string key id - string valid principals - uint64 valid after - uint64 valid before - string critical options - string extensions - string reserved - string signature key - string signature - -The nonce field is a CA-provided random bitstring of arbitrary length -(but typically 16 or 32 bytes) included to make attacks that depend on -inducing collisions in the signature hash infeasible. - -e and n are the RSA exponent and public modulus respectively. - -p, q, g, y are the DSA parameters as described in FIPS-186-2. - -curve and public key are respectively the ECDSA "[identifier]" and "Q" -defined in section 3.1 of RFC5656. - -pk is the encoded Ed25519 public key as defined by RFC8032. - -serial is an optional certificate serial number set by the CA to -provide an abbreviated way to refer to certificates from that CA. -If a CA does not wish to number its certificates, it must set this -field to zero. - -type specifies whether this certificate is for identification of a user -or a host using a SSH_CERT_TYPE_... value. - -key id is a free-form text field that is filled in by the CA at the time -of signing; the intention is that the contents of this field are used to -identify the identity principal in log messages. - -"valid principals" is a string containing zero or more principals as -strings packed inside it. These principals list the names for which this -certificate is valid; hostnames for SSH_CERT_TYPE_HOST certificates and -usernames for SSH_CERT_TYPE_USER certificates. As a special case, a -zero-length "valid principals" field means the certificate is valid for -any principal of the specified type. - -"valid after" and "valid before" specify a validity period for the -certificate. Each represents a time in seconds since 1970-01-01 -00:00:00. A certificate is considered valid if: - - valid after <= current time < valid before - -critical options is a set of zero or more key options encoded as -below. All such options are "critical" in the sense that an implementation -must refuse to authorise a key that has an unrecognised option. - -extensions is a set of zero or more optional extensions. These extensions -are not critical, and an implementation that encounters one that it does -not recognise may safely ignore it. - -Generally, critical options are used to control features that restrict -access where extensions are used to enable features that grant access. -This ensures that certificates containing unknown restrictions do not -inadvertently grant access while allowing new protocol features to be -enabled via extensions without breaking certificates' backwards -compatibility. - -The reserved field is currently unused and is ignored in this version of -the protocol. - -The signature key field contains the CA key used to sign the -certificate. The valid key types for CA keys are ssh-rsa, -ssh-dss, ssh-ed25519 and the ECDSA types ecdsa-sha2-nistp256, -ecdsa-sha2-nistp384, ecdsa-sha2-nistp521. "Chained" certificates, where -the signature key type is a certificate type itself are NOT supported. -Note that it is possible for a RSA certificate key to be signed by a -Ed25519 or ECDSA CA key and vice-versa. - -signature is computed over all preceding fields from the initial string -up to, and including the signature key. Signatures are computed and -encoded according to the rules defined for the CA's public key algorithm -(RFC4253 section 6.6 for ssh-rsa and ssh-dss, RFC5656 for the ECDSA -types, and RFC8032 for Ed25519). - -Critical options ----------------- - -The critical options section of the certificate specifies zero or more -options on the certificate's validity. The format of this field -is a sequence of zero or more tuples: - - string name - string data - -Options must be lexically ordered by "name" if they appear in the -sequence. Each named option may only appear once in a certificate. - -The name field identifies the option. The data field contains -option-specific information encoded as zero or more values inside -the string. I.e. an empty data field would be encoded as a zero- -length string (00 00 00 00), and data field that holds a single -string value "a" would be encoded as (00 00 00 05 00 00 00 01 65). - -All options are "critical"; if an implementation does not recognise -a option, then the validating party should refuse to accept the -certificate. - -Custom options should append the originating author or organisation's -domain name to the option name, e.g. "my-option@example.com". - -No critical options are defined for host certificates at present. The -supported user certificate options and the contents and structure of -their data fields are: - -Name Format Description ------------------------------------------------------------------------------ -force-command string Specifies a command that is executed - (replacing any the user specified on the - ssh command-line) whenever this key is - used for authentication. - -source-address string Comma-separated list of source addresses - from which this certificate is accepted - for authentication. Addresses are - specified in CIDR format (nn.nn.nn.nn/nn - or hhhh::hhhh/nn). - If this option is not present, then - certificates may be presented from any - source address. - -verify-required empty Flag indicating that signatures made - with this certificate must assert FIDO - user verification (e.g. PIN or - biometric). This option only makes sense - for the U2F/FIDO security key types that - support this feature in their signature - formats. - -Extensions ----------- - -The extensions section of the certificate specifies zero or more -non-critical certificate extensions. The encoding and ordering of -extensions in this field is identical to that of the critical options, -as is the requirement that each name appear only once. - -If an implementation does not recognise an extension, then it should -ignore it. - -Custom options should append the originating author or organisation's -domain name to the option name, e.g. "my-option@example.com". - -No extensions are defined for host certificates at present. The -supported user certificate extensions and the contents and structure of -their data fields are: - -Name Format Description ------------------------------------------------------------------------------ -no-touch-required empty Flag indicating that signatures made - with this certificate need not assert - FIDO user presence. This option only - makes sense for the U2F/FIDO security - key types that support this feature in - their signature formats. - -permit-X11-forwarding empty Flag indicating that X11 forwarding - should be permitted. X11 forwarding will - be refused if this option is absent. - -permit-agent-forwarding empty Flag indicating that agent forwarding - should be allowed. Agent forwarding - must not be permitted unless this - option is present. - -permit-port-forwarding empty Flag indicating that port-forwarding - should be allowed. If this option is - not present, then no port forwarding will - be allowed. - -permit-pty empty Flag indicating that PTY allocation - should be permitted. In the absence of - this option PTY allocation will be - disabled. - -permit-user-rc empty Flag indicating that execution of - ~/.ssh/rc should be permitted. Execution - of this script will not be permitted if - this option is not present. - -$OpenBSD: PROTOCOL.certkeys,v 1.20 2024/12/06 16:02:12 djm Exp $ From a32d28d792567253bb601362f36391f155f8f772 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Tue, 6 May 2025 05:40:56 +0000 Subject: [PATCH 026/244] upstream: finally remove DSA signature support from OpenSSH. feedback/ok tb@, ok deraadt@ OpenBSD-Commit-ID: bfe6ee73c1b676c81a2901030c791f8ec888228f --- .depend | 3 +- Makefile.in | 2 +- PROTOCOL | 11 +- TODO | 2 +- authfd.c | 4 +- authfile.c | 3 +- configure.ac | 1 - contrib/cygwin/ssh-user-config | 3 +- dns.c | 5 +- hostfile.c | 6 +- openbsd-compat/openssl-compat.h | 3 - pathnames.h | 4 +- readconf.c | 5 +- ssh-add.c | 5 +- ssh-dss.c | 457 -------------------------------- ssh-keygen.c | 89 +------ ssh-keyscan.c | 26 +- ssh-keysign.c | 5 +- ssh.c | 8 +- ssh_config | 3 +- sshconnect.c | 5 +- sshd-auth.c | 5 +- sshd-session.c | 3 +- sshd.c | 3 +- sshkey.c | 42 +-- sshkey.h | 11 +- 26 files changed, 41 insertions(+), 673 deletions(-) delete mode 100644 ssh-dss.c diff --git a/.depend b/.depend index 975d4427a2fb..3e64eb84a6a5 100644 --- a/.depend +++ b/.depend @@ -79,7 +79,7 @@ loginrec.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-comp logintest.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h loginrec.h mac.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h digest.h hmac.h umac.h mac.h misc.h ssherr.h sshbuf.h openbsd-compat/openssl-compat.h match.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h match.h misc.h -misc-agent.o: digest.h log.h ssherr.h misc.h pathnames.h ssh.h xmalloc.h +misc-agent.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h digest.h log.h ssherr.h misc.h pathnames.h ssh.h xmalloc.h misc.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h misc.h log.h ssherr.h ssh.h sshbuf.h moduli.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h monitor.o: chacha.h poly1305.h cipher-aesctr.h rijndael.h kex.h mac.h crypto_api.h dh.h packet.h dispatch.h auth-options.h sshpty.h channels.h session.h sshlogin.h canohost.h log.h ssherr.h misc.h servconf.h monitor.h monitor_wrap.h monitor_fdpass.h compat.h ssh2.h authfd.h match.h sk-api.h srclimit.h @@ -129,7 +129,6 @@ sntrup761.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-com srclimit.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ./openbsd-compat/sys-tree.h addr.h canohost.h log.h ssherr.h misc.h srclimit.h xmalloc.h servconf.h openbsd-compat/sys-queue.h match.h ssh-add.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h ssh.h log.h ssherr.h sshkey.h sshbuf.h authfd.h authfile.h pathnames.h misc.h digest.h ssh-sk.h sk-api.h hostfile.h ssh-agent.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/sys-queue.h xmalloc.h ssh.h ssh2.h sshbuf.h sshkey.h authfd.h log.h ssherr.h misc.h digest.h match.h msg.h pathnames.h ssh-pkcs11.h sk-api.h myproposal.h -ssh-dss.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ssh-ecdsa-sk.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/openssl-compat.h sshbuf.h ssherr.h digest.h sshkey.h ssh-ecdsa.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ssh-ed25519-sk.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h crypto_api.h log.h ssherr.h sshbuf.h sshkey.h ssh.h digest.h diff --git a/Makefile.in b/Makefile.in index 4550e17951f4..ae86a712b17b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -105,7 +105,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ log.o match.o moduli.o nchan.o packet.o \ readpass.o ttymodes.o xmalloc.o addr.o addrmatch.o \ atomicio.o dispatch.o mac.o misc.o utf8.o \ - monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-ecdsa-sk.o \ + monitor_fdpass.o rijndael.o ssh-ecdsa.o ssh-ecdsa-sk.o \ ssh-ed25519-sk.o ssh-rsa.o dh.o \ msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \ ssh-pkcs11.o smult_curve25519_ref.o \ diff --git a/PROTOCOL b/PROTOCOL index a0a9837efe3e..f99173c527b7 100644 --- a/PROTOCOL +++ b/PROTOCOL @@ -34,7 +34,6 @@ The method is documented in: https://www.openssh.com/txt/draft-miller-secsh-compression-delayed-00.txt 1.3. transport: New public key algorithms "ssh-rsa-cert-v01@openssh.com", - "ssh-dsa-cert-v01@openssh.com", "ecdsa-sha2-nistp256-cert-v01@openssh.com", "ecdsa-sha2-nistp384-cert-v01@openssh.com" and "ecdsa-sha2-nistp521-cert-v01@openssh.com" @@ -765,15 +764,15 @@ authorized_keys files, are formatted as a single line of text consisting of the public key algorithm name followed by a base64-encoded key blob. The public key blob (before base64 encoding) is the same format used for the encoding of public keys sent on the wire: as described in RFC4253 -section 6.6 for RSA and DSA keys, RFC5656 section 3.1 for ECDSA keys -and the "New public key formats" section of PROTOCOL.certkeys for the -OpenSSH certificate formats. +section 6.6 for RSA keys, RFC5656 section 3.1 for ECDSA keys and +https://datatracker.ietf.org/doc/draft-miller-ssh-cert/ +for the OpenSSH certificate formats. 5.2 Private key format OpenSSH private keys, as generated by ssh-keygen(1) use the format described in PROTOCOL.key by default. As a legacy option, PEM format -(RFC7468) private keys are also supported for RSA, DSA and ECDSA keys +(RFC7468) private keys are also supported for RSA and ECDSA keys and were the default format before OpenSSH 7.8. 5.3 KRL format @@ -792,4 +791,4 @@ master instance and later clients. OpenSSH extends the usual agent protocol. These changes are documented in the PROTOCOL.agent file. -$OpenBSD: PROTOCOL,v 1.56 2025/05/05 05:51:11 djm Exp $ +$OpenBSD: PROTOCOL,v 1.57 2025/05/06 05:40:56 djm Exp $ diff --git a/TODO b/TODO index b76529c960a0..e9e2d96e6e1d 100644 --- a/TODO +++ b/TODO @@ -7,7 +7,7 @@ Documentation: - Install FAQ? -- General FAQ on S/Key, TIS, RSA, RSA2, DSA, etc and suggestions on when it +- General FAQ on S/Key, TIS, RSA, RSA2, etc and suggestions on when it would be best to use them. - Create a Documentation/ directory? diff --git a/authfd.c b/authfd.c index e04ad0cf2d02..66797880af84 100644 --- a/authfd.c +++ b/authfd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: authfd.c,v 1.134 2023/12/18 14:46:56 djm Exp $ */ +/* $OpenBSD: authfd.c,v 1.135 2025/05/06 05:40:56 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -601,8 +601,6 @@ ssh_add_identity_constrained(int sock, struct sshkey *key, #ifdef WITH_OPENSSL case KEY_RSA: case KEY_RSA_CERT: - case KEY_DSA: - case KEY_DSA_CERT: case KEY_ECDSA: case KEY_ECDSA_CERT: case KEY_ECDSA_SK: diff --git a/authfile.c b/authfile.c index 4a2f21eb7f6d..bf485baf237a 100644 --- a/authfile.c +++ b/authfile.c @@ -1,4 +1,4 @@ -/* $OpenBSD: authfile.c,v 1.145 2024/09/22 12:56:21 jsg Exp $ */ +/* $OpenBSD: authfile.c,v 1.146 2025/05/06 05:40:56 djm Exp $ */ /* * Copyright (c) 2000, 2013 Markus Friedl. All rights reserved. * @@ -328,7 +328,6 @@ sshkey_load_private_cert(int type, const char *filename, const char *passphrase, switch (type) { #ifdef WITH_OPENSSL case KEY_RSA: - case KEY_DSA: case KEY_ECDSA: #endif /* WITH_OPENSSL */ case KEY_ED25519: diff --git a/configure.ac b/configure.ac index b19f790cdd54..221d5f5618bf 100644 --- a/configure.ac +++ b/configure.ac @@ -3078,7 +3078,6 @@ if test "x$openssl" = "xyes" ; then AC_CHECK_FUNCS([ \ BN_is_prime_ex \ DES_crypt \ - DSA_generate_parameters_ex \ EVP_DigestSign \ EVP_DigestVerify \ EVP_DigestFinal_ex \ diff --git a/contrib/cygwin/ssh-user-config b/contrib/cygwin/ssh-user-config index 3858722f646d..35802d06ecba 100644 --- a/contrib/cygwin/ssh-user-config +++ b/contrib/cygwin/ssh-user-config @@ -246,9 +246,8 @@ done check_user_homedir check_user_dot_ssh_dir create_identity id_rsa rsa "SSH2 RSA" -create_identity id_dsa dsa "SSH2 DSA" +create_identity id_ed25519 ed25519 "SSH2 Ed25519" create_identity id_ecdsa ecdsa "SSH2 ECDSA" -create_identity identity rsa1 "(deprecated) SSH1 RSA" fix_authorized_keys_perms echo diff --git a/dns.c b/dns.c index 939241440777..c01c7bebee18 100644 --- a/dns.c +++ b/dns.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dns.c,v 1.44 2023/03/10 04:06:21 dtucker Exp $ */ +/* $OpenBSD: dns.c,v 1.45 2025/05/06 05:40:56 djm Exp $ */ /* * Copyright (c) 2003 Wesley Griffin. All rights reserved. @@ -88,9 +88,6 @@ dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type, case KEY_RSA: *algorithm = SSHFP_KEY_RSA; break; - case KEY_DSA: - *algorithm = SSHFP_KEY_DSA; - break; case KEY_ECDSA: *algorithm = SSHFP_KEY_ECDSA; break; diff --git a/hostfile.c b/hostfile.c index 4b4a0e31ef38..4cec57da50c6 100644 --- a/hostfile.c +++ b/hostfile.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hostfile.c,v 1.98 2025/05/05 02:48:07 djm Exp $ */ +/* $OpenBSD: hostfile.c,v 1.99 2025/05/06 05:40:56 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -150,8 +150,8 @@ host_hash(const char *host, const char *name_from_hostfile, u_int src_len) } /* - * Parses an RSA (number of bits, e, n) or DSA key from a string. Moves the - * pointer over the key. Skips any whitespace at the beginning and at end. + * Parses an RSA key from a string. Moves the pointer over the key. + * Skips any whitespace at the beginning and at end. */ int diff --git a/openbsd-compat/openssl-compat.h b/openbsd-compat/openssl-compat.h index 6b8fff412951..a7c41c235b5c 100644 --- a/openbsd-compat/openssl-compat.h +++ b/openbsd-compat/openssl-compat.h @@ -45,9 +45,6 @@ void ssh_libcrypto_init(void); #ifndef OPENSSL_RSA_MAX_MODULUS_BITS # define OPENSSL_RSA_MAX_MODULUS_BITS 16384 #endif -#ifndef OPENSSL_DSA_MAX_MODULUS_BITS -# define OPENSSL_DSA_MAX_MODULUS_BITS 10000 -#endif #ifdef LIBRESSL_VERSION_NUMBER # if LIBRESSL_VERSION_NUMBER < 0x3010000fL diff --git a/pathnames.h b/pathnames.h index e07395cb6f26..9e76dbba841f 100644 --- a/pathnames.h +++ b/pathnames.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pathnames.h,v 1.34 2025/05/05 02:48:06 djm Exp $ */ +/* $OpenBSD: pathnames.h,v 1.35 2025/05/06 05:40:56 djm Exp $ */ /* * Author: Tatu Ylonen @@ -36,7 +36,6 @@ */ #define _PATH_SERVER_CONFIG_FILE SSHDIR "/sshd_config" #define _PATH_HOST_CONFIG_FILE SSHDIR "/ssh_config" -#define _PATH_HOST_DSA_KEY_FILE SSHDIR "/ssh_host_dsa_key" #define _PATH_HOST_ECDSA_KEY_FILE SSHDIR "/ssh_host_ecdsa_key" #define _PATH_HOST_ED25519_KEY_FILE SSHDIR "/ssh_host_ed25519_key" #define _PATH_HOST_XMSS_KEY_FILE SSHDIR "/ssh_host_xmss_key" @@ -87,7 +86,6 @@ * Name of the default file containing client-side authentication key. This * file should only be readable by the user him/herself. */ -#define _PATH_SSH_CLIENT_ID_DSA _PATH_SSH_USER_DIR "/id_dsa" #define _PATH_SSH_CLIENT_ID_ECDSA _PATH_SSH_USER_DIR "/id_ecdsa" #define _PATH_SSH_CLIENT_ID_RSA _PATH_SSH_USER_DIR "/id_rsa" #define _PATH_SSH_CLIENT_ID_ED25519 _PATH_SSH_USER_DIR "/id_ed25519" diff --git a/readconf.c b/readconf.c index 7cbe7d2c2dc5..a56cbe0da7d0 100644 --- a/readconf.c +++ b/readconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.c,v 1.398 2025/03/18 04:53:14 djm Exp $ */ +/* $OpenBSD: readconf.c,v 1.399 2025/05/06 05:40:56 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -2869,9 +2869,6 @@ fill_default_options(Options * options) add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_ED25519_SK, 0); add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_XMSS, 0); -#ifdef WITH_DSA - add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_DSA, 0); -#endif } if (options->escape_char == -1) options->escape_char = '~'; diff --git a/ssh-add.c b/ssh-add.c index 0035cb84a0c1..18897a0a834d 100644 --- a/ssh-add.c +++ b/ssh-add.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-add.c,v 1.173 2024/09/06 02:30:44 djm Exp $ */ +/* $OpenBSD: ssh-add.c,v 1.174 2025/05/06 05:40:56 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -85,9 +85,6 @@ static char *default_files[] = { _PATH_SSH_CLIENT_ID_ED25519, _PATH_SSH_CLIENT_ID_ED25519_SK, _PATH_SSH_CLIENT_ID_XMSS, -#ifdef WITH_DSA - _PATH_SSH_CLIENT_ID_DSA, -#endif NULL }; diff --git a/ssh-dss.c b/ssh-dss.c deleted file mode 100644 index aea661377f5c..000000000000 --- a/ssh-dss.c +++ /dev/null @@ -1,457 +0,0 @@ -/* $OpenBSD: ssh-dss.c,v 1.50 2024/01/11 01:45:36 djm Exp $ */ -/* - * Copyright (c) 2000 Markus Friedl. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "includes.h" - -#if defined(WITH_OPENSSL) && defined(WITH_DSA) - -#include - -#include -#include -#include - -#include -#include - -#include "sshbuf.h" -#include "ssherr.h" -#include "digest.h" -#define SSHKEY_INTERNAL -#include "sshkey.h" - -#include "openbsd-compat/openssl-compat.h" - -#define INTBLOB_LEN 20 -#define SIGBLOB_LEN (2*INTBLOB_LEN) - -static u_int -ssh_dss_size(const struct sshkey *key) -{ - const BIGNUM *dsa_p; - - if (key->dsa == NULL) - return 0; - DSA_get0_pqg(key->dsa, &dsa_p, NULL, NULL); - return BN_num_bits(dsa_p); -} - -static int -ssh_dss_alloc(struct sshkey *k) -{ - if ((k->dsa = DSA_new()) == NULL) - return SSH_ERR_ALLOC_FAIL; - return 0; -} - -static void -ssh_dss_cleanup(struct sshkey *k) -{ - DSA_free(k->dsa); - k->dsa = NULL; -} - -static int -ssh_dss_equal(const struct sshkey *a, const struct sshkey *b) -{ - const BIGNUM *dsa_p_a, *dsa_q_a, *dsa_g_a, *dsa_pub_key_a; - const BIGNUM *dsa_p_b, *dsa_q_b, *dsa_g_b, *dsa_pub_key_b; - - if (a->dsa == NULL || b->dsa == NULL) - return 0; - DSA_get0_pqg(a->dsa, &dsa_p_a, &dsa_q_a, &dsa_g_a); - DSA_get0_pqg(b->dsa, &dsa_p_b, &dsa_q_b, &dsa_g_b); - DSA_get0_key(a->dsa, &dsa_pub_key_a, NULL); - DSA_get0_key(b->dsa, &dsa_pub_key_b, NULL); - if (dsa_p_a == NULL || dsa_p_b == NULL || - dsa_q_a == NULL || dsa_q_b == NULL || - dsa_g_a == NULL || dsa_g_b == NULL || - dsa_pub_key_a == NULL || dsa_pub_key_b == NULL) - return 0; - if (BN_cmp(dsa_p_a, dsa_p_b) != 0) - return 0; - if (BN_cmp(dsa_q_a, dsa_q_b) != 0) - return 0; - if (BN_cmp(dsa_g_a, dsa_g_b) != 0) - return 0; - if (BN_cmp(dsa_pub_key_a, dsa_pub_key_b) != 0) - return 0; - return 1; -} - -static int -ssh_dss_serialize_public(const struct sshkey *key, struct sshbuf *b, - enum sshkey_serialize_rep opts) -{ - int r; - const BIGNUM *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key; - - if (key->dsa == NULL) - return SSH_ERR_INVALID_ARGUMENT; - DSA_get0_pqg(key->dsa, &dsa_p, &dsa_q, &dsa_g); - DSA_get0_key(key->dsa, &dsa_pub_key, NULL); - if (dsa_p == NULL || dsa_q == NULL || - dsa_g == NULL || dsa_pub_key == NULL) - return SSH_ERR_INTERNAL_ERROR; - if ((r = sshbuf_put_bignum2(b, dsa_p)) != 0 || - (r = sshbuf_put_bignum2(b, dsa_q)) != 0 || - (r = sshbuf_put_bignum2(b, dsa_g)) != 0 || - (r = sshbuf_put_bignum2(b, dsa_pub_key)) != 0) - return r; - - return 0; -} - -static int -ssh_dss_serialize_private(const struct sshkey *key, struct sshbuf *b, - enum sshkey_serialize_rep opts) -{ - int r; - const BIGNUM *dsa_priv_key; - - DSA_get0_key(key->dsa, NULL, &dsa_priv_key); - if (!sshkey_is_cert(key)) { - if ((r = ssh_dss_serialize_public(key, b, opts)) != 0) - return r; - } - if ((r = sshbuf_put_bignum2(b, dsa_priv_key)) != 0) - return r; - - return 0; -} - -static int -ssh_dss_generate(struct sshkey *k, int bits) -{ - DSA *private; - - if (bits != 1024) - return SSH_ERR_KEY_LENGTH; - if ((private = DSA_new()) == NULL) - return SSH_ERR_ALLOC_FAIL; - if (!DSA_generate_parameters_ex(private, bits, NULL, 0, NULL, - NULL, NULL) || !DSA_generate_key(private)) { - DSA_free(private); - return SSH_ERR_LIBCRYPTO_ERROR; - } - k->dsa = private; - return 0; -} - -static int -ssh_dss_copy_public(const struct sshkey *from, struct sshkey *to) -{ - const BIGNUM *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key; - BIGNUM *dsa_p_dup = NULL, *dsa_q_dup = NULL, *dsa_g_dup = NULL; - BIGNUM *dsa_pub_key_dup = NULL; - int r = SSH_ERR_INTERNAL_ERROR; - - DSA_get0_pqg(from->dsa, &dsa_p, &dsa_q, &dsa_g); - DSA_get0_key(from->dsa, &dsa_pub_key, NULL); - if ((dsa_p_dup = BN_dup(dsa_p)) == NULL || - (dsa_q_dup = BN_dup(dsa_q)) == NULL || - (dsa_g_dup = BN_dup(dsa_g)) == NULL || - (dsa_pub_key_dup = BN_dup(dsa_pub_key)) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto out; - } - if (!DSA_set0_pqg(to->dsa, dsa_p_dup, dsa_q_dup, dsa_g_dup)) { - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - dsa_p_dup = dsa_q_dup = dsa_g_dup = NULL; /* transferred */ - if (!DSA_set0_key(to->dsa, dsa_pub_key_dup, NULL)) { - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - dsa_pub_key_dup = NULL; /* transferred */ - /* success */ - r = 0; - out: - BN_clear_free(dsa_p_dup); - BN_clear_free(dsa_q_dup); - BN_clear_free(dsa_g_dup); - BN_clear_free(dsa_pub_key_dup); - return r; -} - -static int -ssh_dss_deserialize_public(const char *ktype, struct sshbuf *b, - struct sshkey *key) -{ - int ret = SSH_ERR_INTERNAL_ERROR; - BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL, *dsa_pub_key = NULL; - - if (sshbuf_get_bignum2(b, &dsa_p) != 0 || - sshbuf_get_bignum2(b, &dsa_q) != 0 || - sshbuf_get_bignum2(b, &dsa_g) != 0 || - sshbuf_get_bignum2(b, &dsa_pub_key) != 0) { - ret = SSH_ERR_INVALID_FORMAT; - goto out; - } - if (!DSA_set0_pqg(key->dsa, dsa_p, dsa_q, dsa_g)) { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - dsa_p = dsa_q = dsa_g = NULL; /* transferred */ - if (!DSA_set0_key(key->dsa, dsa_pub_key, NULL)) { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - dsa_pub_key = NULL; /* transferred */ -#ifdef DEBUG_PK - DSA_print_fp(stderr, key->dsa, 8); -#endif - /* success */ - ret = 0; - out: - BN_clear_free(dsa_p); - BN_clear_free(dsa_q); - BN_clear_free(dsa_g); - BN_clear_free(dsa_pub_key); - return ret; -} - -static int -ssh_dss_deserialize_private(const char *ktype, struct sshbuf *b, - struct sshkey *key) -{ - int r; - BIGNUM *dsa_priv_key = NULL; - - if (!sshkey_is_cert(key)) { - if ((r = ssh_dss_deserialize_public(ktype, b, key)) != 0) - return r; - } - - if ((r = sshbuf_get_bignum2(b, &dsa_priv_key)) != 0) - return r; - if (!DSA_set0_key(key->dsa, NULL, dsa_priv_key)) { - BN_clear_free(dsa_priv_key); - return SSH_ERR_LIBCRYPTO_ERROR; - } - return 0; -} - -static int -ssh_dss_sign(struct sshkey *key, - u_char **sigp, size_t *lenp, - const u_char *data, size_t datalen, - const char *alg, const char *sk_provider, const char *sk_pin, u_int compat) -{ - DSA_SIG *sig = NULL; - const BIGNUM *sig_r, *sig_s; - u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN]; - size_t rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); - struct sshbuf *b = NULL; - int ret = SSH_ERR_INVALID_ARGUMENT; - - if (lenp != NULL) - *lenp = 0; - if (sigp != NULL) - *sigp = NULL; - - if (key == NULL || key->dsa == NULL || - sshkey_type_plain(key->type) != KEY_DSA) - return SSH_ERR_INVALID_ARGUMENT; - if (dlen == 0) - return SSH_ERR_INTERNAL_ERROR; - - if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, - digest, sizeof(digest))) != 0) - goto out; - - if ((sig = DSA_do_sign(digest, dlen, key->dsa)) == NULL) { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - - DSA_SIG_get0(sig, &sig_r, &sig_s); - rlen = BN_num_bytes(sig_r); - slen = BN_num_bytes(sig_s); - if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) { - ret = SSH_ERR_INTERNAL_ERROR; - goto out; - } - explicit_bzero(sigblob, SIGBLOB_LEN); - BN_bn2bin(sig_r, sigblob + SIGBLOB_LEN - INTBLOB_LEN - rlen); - BN_bn2bin(sig_s, sigblob + SIGBLOB_LEN - slen); - - if ((b = sshbuf_new()) == NULL) { - ret = SSH_ERR_ALLOC_FAIL; - goto out; - } - if ((ret = sshbuf_put_cstring(b, "ssh-dss")) != 0 || - (ret = sshbuf_put_string(b, sigblob, SIGBLOB_LEN)) != 0) - goto out; - - len = sshbuf_len(b); - if (sigp != NULL) { - if ((*sigp = malloc(len)) == NULL) { - ret = SSH_ERR_ALLOC_FAIL; - goto out; - } - memcpy(*sigp, sshbuf_ptr(b), len); - } - if (lenp != NULL) - *lenp = len; - ret = 0; - out: - explicit_bzero(digest, sizeof(digest)); - DSA_SIG_free(sig); - sshbuf_free(b); - return ret; -} - -static int -ssh_dss_verify(const struct sshkey *key, - const u_char *sig, size_t siglen, - const u_char *data, size_t dlen, const char *alg, u_int compat, - struct sshkey_sig_details **detailsp) -{ - DSA_SIG *dsig = NULL; - BIGNUM *sig_r = NULL, *sig_s = NULL; - u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob = NULL; - size_t len, hlen = ssh_digest_bytes(SSH_DIGEST_SHA1); - int ret = SSH_ERR_INTERNAL_ERROR; - struct sshbuf *b = NULL; - char *ktype = NULL; - - if (key == NULL || key->dsa == NULL || - sshkey_type_plain(key->type) != KEY_DSA || - sig == NULL || siglen == 0) - return SSH_ERR_INVALID_ARGUMENT; - if (hlen == 0) - return SSH_ERR_INTERNAL_ERROR; - - /* fetch signature */ - if ((b = sshbuf_from(sig, siglen)) == NULL) - return SSH_ERR_ALLOC_FAIL; - if (sshbuf_get_cstring(b, &ktype, NULL) != 0 || - sshbuf_get_string(b, &sigblob, &len) != 0) { - ret = SSH_ERR_INVALID_FORMAT; - goto out; - } - if (strcmp("ssh-dss", ktype) != 0) { - ret = SSH_ERR_KEY_TYPE_MISMATCH; - goto out; - } - if (sshbuf_len(b) != 0) { - ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; - goto out; - } - - if (len != SIGBLOB_LEN) { - ret = SSH_ERR_INVALID_FORMAT; - goto out; - } - - /* parse signature */ - if ((dsig = DSA_SIG_new()) == NULL || - (sig_r = BN_new()) == NULL || - (sig_s = BN_new()) == NULL) { - ret = SSH_ERR_ALLOC_FAIL; - goto out; - } - if ((BN_bin2bn(sigblob, INTBLOB_LEN, sig_r) == NULL) || - (BN_bin2bn(sigblob + INTBLOB_LEN, INTBLOB_LEN, sig_s) == NULL)) { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - if (!DSA_SIG_set0(dsig, sig_r, sig_s)) { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - sig_r = sig_s = NULL; /* transferred */ - - /* sha1 the data */ - if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, dlen, - digest, sizeof(digest))) != 0) - goto out; - - switch (DSA_do_verify(digest, hlen, dsig, key->dsa)) { - case 1: - ret = 0; - break; - case 0: - ret = SSH_ERR_SIGNATURE_INVALID; - goto out; - default: - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - - out: - explicit_bzero(digest, sizeof(digest)); - DSA_SIG_free(dsig); - BN_clear_free(sig_r); - BN_clear_free(sig_s); - sshbuf_free(b); - free(ktype); - if (sigblob != NULL) - freezero(sigblob, len); - return ret; -} - -static const struct sshkey_impl_funcs sshkey_dss_funcs = { - /* .size = */ ssh_dss_size, - /* .alloc = */ ssh_dss_alloc, - /* .cleanup = */ ssh_dss_cleanup, - /* .equal = */ ssh_dss_equal, - /* .ssh_serialize_public = */ ssh_dss_serialize_public, - /* .ssh_deserialize_public = */ ssh_dss_deserialize_public, - /* .ssh_serialize_private = */ ssh_dss_serialize_private, - /* .ssh_deserialize_private = */ ssh_dss_deserialize_private, - /* .generate = */ ssh_dss_generate, - /* .copy_public = */ ssh_dss_copy_public, - /* .sign = */ ssh_dss_sign, - /* .verify = */ ssh_dss_verify, -}; - -const struct sshkey_impl sshkey_dss_impl = { - /* .name = */ "ssh-dss", - /* .shortname = */ "DSA", - /* .sigalg = */ NULL, - /* .type = */ KEY_DSA, - /* .nid = */ 0, - /* .cert = */ 0, - /* .sigonly = */ 0, - /* .keybits = */ 0, - /* .funcs = */ &sshkey_dss_funcs, -}; - -const struct sshkey_impl sshkey_dsa_cert_impl = { - /* .name = */ "ssh-dss-cert-v01@openssh.com", - /* .shortname = */ "DSA-CERT", - /* .sigalg = */ NULL, - /* .type = */ KEY_DSA_CERT, - /* .nid = */ 0, - /* .cert = */ 1, - /* .sigonly = */ 0, - /* .keybits = */ 0, - /* .funcs = */ &sshkey_dss_funcs, -}; - -#endif /* WITH_OPENSSL && WITH_DSA */ diff --git a/ssh-keygen.c b/ssh-keygen.c index 89c3ed287628..3217f084d384 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keygen.c,v 1.477 2024/12/04 14:24:20 djm Exp $ */ +/* $OpenBSD: ssh-keygen.c,v 1.478 2025/05/06 05:40:56 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1994 Tatu Ylonen , Espoo, Finland @@ -70,18 +70,14 @@ #define DEFAULT_KEY_TYPE_NAME "ed25519" /* - * Default number of bits in the RSA, DSA and ECDSA keys. These value can be + * Default number of bits in the RSA and ECDSA keys. These value can be * overridden on the command line. * - * These values, with the exception of DSA, provide security equivalent to at - * least 128 bits of security according to NIST Special Publication 800-57: - * Recommendation for Key Management Part 1 rev 4 section 5.6.1. - * For DSA it (and FIPS-186-4 section 4.2) specifies that the only size for - * which a 160bit hash is acceptable is 1kbit, and since ssh-dss specifies only - * SHA1 we limit the DSA key size 1k bits. + * These values provide security equivalent to at least 128 bits of security + * according to NIST Special Publication 800-57: Recommendation for Key + * Management Part 1 rev 4 section 5.6.1. */ #define DEFAULT_BITS 3072 -#define DEFAULT_BITS_DSA 1024 #define DEFAULT_BITS_ECDSA 256 static int quiet = 0; @@ -185,9 +181,6 @@ type_bits_valid(int type, const char *name, u_int32_t *bitsp) int nid; switch(type) { - case KEY_DSA: - *bitsp = DEFAULT_BITS_DSA; - break; case KEY_ECDSA: if (name != NULL && (nid = sshkey_ecdsa_nid_from_name(name)) > 0) @@ -203,10 +196,6 @@ type_bits_valid(int type, const char *name, u_int32_t *bitsp) } #ifdef WITH_OPENSSL switch (type) { - case KEY_DSA: - if (*bitsp != 1024) - fatal("Invalid DSA key length: must be 1024 bits"); - break; case KEY_RSA: if (*bitsp < SSH_RSA_MINIMUM_MODULUS_SIZE) fatal("Invalid RSA key length: minimum is %d bits", @@ -262,12 +251,6 @@ ask_filename(struct passwd *pw, const char *prompt) name = _PATH_SSH_CLIENT_ID_ED25519; else { switch (sshkey_type_from_shortname(key_type_name)) { -#ifdef WITH_DSA - case KEY_DSA_CERT: - case KEY_DSA: - name = _PATH_SSH_CLIENT_ID_DSA; - break; -#endif #ifdef OPENSSL_HAS_ECC case KEY_ECDSA_CERT: case KEY_ECDSA: @@ -382,12 +365,6 @@ do_convert_to_pkcs8(struct sshkey *k) EVP_PKEY_get0_RSA(k->pkey))) fatal("PEM_write_RSA_PUBKEY failed"); break; -#ifdef WITH_DSA - case KEY_DSA: - if (!PEM_write_DSA_PUBKEY(stdout, k->dsa)) - fatal("PEM_write_DSA_PUBKEY failed"); - break; -#endif #ifdef OPENSSL_HAS_ECC case KEY_ECDSA: if (!PEM_write_EC_PUBKEY(stdout, @@ -410,12 +387,6 @@ do_convert_to_pem(struct sshkey *k) EVP_PKEY_get0_RSA(k->pkey))) fatal("PEM_write_RSAPublicKey failed"); break; -#ifdef WITH_DSA - case KEY_DSA: - if (!PEM_write_DSA_PUBKEY(stdout, k->dsa)) - fatal("PEM_write_DSA_PUBKEY failed"); - break; -#endif #ifdef OPENSSL_HAS_ECC case KEY_ECDSA: if (!PEM_write_EC_PUBKEY(stdout, @@ -491,10 +462,6 @@ do_convert_private_ssh2(struct sshbuf *b) u_int magic, i1, i2, i3, i4; size_t slen; u_long e; -#ifdef WITH_DSA - BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL; - BIGNUM *dsa_pub_key = NULL, *dsa_priv_key = NULL; -#endif BIGNUM *rsa_n = NULL, *rsa_e = NULL, *rsa_d = NULL; BIGNUM *rsa_p = NULL, *rsa_q = NULL, *rsa_iqmp = NULL; BIGNUM *rsa_dmp1 = NULL, *rsa_dmq1 = NULL; @@ -526,10 +493,6 @@ do_convert_private_ssh2(struct sshbuf *b) if (strstr(type, "rsa")) { ktype = KEY_RSA; -#ifdef WITH_DSA - } else if (strstr(type, "dsa")) { - ktype = KEY_DSA; -#endif } else { free(type); return NULL; @@ -539,27 +502,6 @@ do_convert_private_ssh2(struct sshbuf *b) free(type); switch (key->type) { -#ifdef WITH_DSA - case KEY_DSA: - if ((dsa_p = BN_new()) == NULL || - (dsa_q = BN_new()) == NULL || - (dsa_g = BN_new()) == NULL || - (dsa_pub_key = BN_new()) == NULL || - (dsa_priv_key = BN_new()) == NULL) - fatal_f("BN_new"); - buffer_get_bignum_bits(b, dsa_p); - buffer_get_bignum_bits(b, dsa_g); - buffer_get_bignum_bits(b, dsa_q); - buffer_get_bignum_bits(b, dsa_pub_key); - buffer_get_bignum_bits(b, dsa_priv_key); - if (!DSA_set0_pqg(key->dsa, dsa_p, dsa_q, dsa_g)) - fatal_f("DSA_set0_pqg failed"); - dsa_p = dsa_q = dsa_g = NULL; /* transferred */ - if (!DSA_set0_key(key->dsa, dsa_pub_key, dsa_priv_key)) - fatal_f("DSA_set0_key failed"); - dsa_pub_key = dsa_priv_key = NULL; /* transferred */ - break; -#endif case KEY_RSA: if ((r = sshbuf_get_u8(b, &e1)) != 0 || (e1 < 30 && (r = sshbuf_get_u8(b, &e2)) != 0) || @@ -734,14 +676,6 @@ do_convert_from_pkcs8(struct sshkey **k, int *private) (*k)->pkey = pubkey; pubkey = NULL; break; -#ifdef WITH_DSA - case EVP_PKEY_DSA: - if ((*k = sshkey_new(KEY_UNSPEC)) == NULL) - fatal("sshkey_new failed"); - (*k)->type = KEY_DSA; - (*k)->dsa = EVP_PKEY_get1_DSA(pubkey); - break; -#endif #ifdef OPENSSL_HAS_ECC case EVP_PKEY_EC: if ((*k = sshkey_new(KEY_UNSPEC)) == NULL) @@ -817,12 +751,6 @@ do_convert_from(struct passwd *pw) fprintf(stdout, "\n"); } else { switch (k->type) { -#ifdef WITH_DSA - case KEY_DSA: - ok = PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, - NULL, 0, NULL, NULL); - break; -#endif #ifdef OPENSSL_HAS_ECC case KEY_ECDSA: ok = PEM_write_ECPrivateKey(stdout, @@ -3329,7 +3257,7 @@ usage(void) fprintf(stderr, "usage: ssh-keygen [-q] [-a rounds] [-b bits] [-C comment] [-f output_keyfile]\n" " [-m format] [-N new_passphrase] [-O option]\n" - " [-t dsa | ecdsa | ecdsa-sk | ed25519 | ed25519-sk | rsa]\n" + " [-t ecdsa | ecdsa-sk | ed25519 | ed25519-sk | rsa]\n" " [-w provider] [-Z cipher]\n" " ssh-keygen -p [-a rounds] [-f keyfile] [-m format] [-N new_passphrase]\n" " [-P old_passphrase] [-Z cipher]\n" @@ -3805,11 +3733,6 @@ main(int argc, char **argv) n += do_print_resource_record(pw, _PATH_HOST_RSA_KEY_FILE, rr_hostname, print_generic, opts, nopts); -#ifdef WITH_DSA - n += do_print_resource_record(pw, - _PATH_HOST_DSA_KEY_FILE, rr_hostname, - print_generic, opts, nopts); -#endif n += do_print_resource_record(pw, _PATH_HOST_ECDSA_KEY_FILE, rr_hostname, print_generic, opts, nopts); diff --git a/ssh-keyscan.c b/ssh-keyscan.c index 3436c0b5c7c6..7b1e0ca86500 100644 --- a/ssh-keyscan.c +++ b/ssh-keyscan.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keyscan.c,v 1.165 2024/12/06 15:17:15 djm Exp $ */ +/* $OpenBSD: ssh-keyscan.c,v 1.166 2025/05/06 05:40:56 djm Exp $ */ /* * Copyright 1995, 1996 by David Mazieres . * @@ -62,15 +62,14 @@ int IPv4or6 = AF_UNSPEC; int ssh_port = SSH_DEFAULT_PORT; -#define KT_DSA (1) -#define KT_RSA (1<<1) -#define KT_ECDSA (1<<2) -#define KT_ED25519 (1<<3) -#define KT_XMSS (1<<4) -#define KT_ECDSA_SK (1<<5) -#define KT_ED25519_SK (1<<6) +#define KT_RSA (1) +#define KT_ECDSA (1<<1) +#define KT_ED25519 (1<<2) +#define KT_XMSS (1<<3) +#define KT_ECDSA_SK (1<<4) +#define KT_ED25519_SK (1<<5) -#define KT_MIN KT_DSA +#define KT_MIN KT_RSA #define KT_MAX KT_ED25519_SK int get_cert = 0; @@ -240,10 +239,6 @@ keygrab_ssh2(con *c) int r; switch (c->c_keytype) { - case KT_DSA: - myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ? - "ssh-dss-cert-v01@openssh.com" : "ssh-dss"; - break; case KT_RSA: myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ? "rsa-sha2-512-cert-v01@openssh.com," @@ -743,11 +738,6 @@ main(int argc, char **argv) int type = sshkey_type_from_shortname(tname); switch (type) { -#ifdef WITH_DSA - case KEY_DSA: - get_keytypes |= KT_DSA; - break; -#endif case KEY_ECDSA: get_keytypes |= KT_ECDSA; break; diff --git a/ssh-keysign.c b/ssh-keysign.c index 955f7b0abad9..4d65dd1d33a0 100644 --- a/ssh-keysign.c +++ b/ssh-keysign.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keysign.c,v 1.75 2025/02/15 01:48:30 djm Exp $ */ +/* $OpenBSD: ssh-keysign.c,v 1.76 2025/05/06 05:40:56 djm Exp $ */ /* * Copyright (c) 2002 Markus Friedl. All rights reserved. * @@ -200,9 +200,6 @@ main(int argc, char **argv) i = 0; /* XXX This really needs to read sshd_config for the paths */ -#ifdef WITH_DSA - key_fd[i++] = open(_PATH_HOST_DSA_KEY_FILE, O_RDONLY); -#endif key_fd[i++] = open(_PATH_HOST_ECDSA_KEY_FILE, O_RDONLY); key_fd[i++] = open(_PATH_HOST_ED25519_KEY_FILE, O_RDONLY); key_fd[i++] = open(_PATH_HOST_XMSS_KEY_FILE, O_RDONLY); diff --git a/ssh.c b/ssh.c index dc4886d0ecdf..b2172b810a61 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.612 2025/04/09 01:24:40 djm Exp $ */ +/* $OpenBSD: ssh.c,v 1.613 2025/05/06 05:40:56 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1746,15 +1746,9 @@ main(int ac, char **av) L_CERT(_PATH_HOST_ECDSA_KEY_FILE, 0); L_CERT(_PATH_HOST_ED25519_KEY_FILE, 1); L_CERT(_PATH_HOST_RSA_KEY_FILE, 2); -#ifdef WITH_DSA - L_CERT(_PATH_HOST_DSA_KEY_FILE, 3); -#endif L_PUBKEY(_PATH_HOST_ECDSA_KEY_FILE, 4); L_PUBKEY(_PATH_HOST_ED25519_KEY_FILE, 5); L_PUBKEY(_PATH_HOST_RSA_KEY_FILE, 6); -#ifdef WITH_DSA - L_PUBKEY(_PATH_HOST_DSA_KEY_FILE, 7); -#endif L_CERT(_PATH_HOST_XMSS_KEY_FILE, 8); L_PUBKEY(_PATH_HOST_XMSS_KEY_FILE, 9); if (loaded == 0) diff --git a/ssh_config b/ssh_config index cc5663562e95..238a0c5e371b 100644 --- a/ssh_config +++ b/ssh_config @@ -1,4 +1,4 @@ -# $OpenBSD: ssh_config,v 1.36 2023/08/02 23:04:38 djm Exp $ +# $OpenBSD: ssh_config,v 1.37 2025/05/06 05:40:56 djm Exp $ # This is the ssh client system-wide configuration file. See # ssh_config(5) for more information. This file provides defaults for @@ -30,7 +30,6 @@ # ConnectTimeout 0 # StrictHostKeyChecking ask # IdentityFile ~/.ssh/id_rsa -# IdentityFile ~/.ssh/id_dsa # IdentityFile ~/.ssh/id_ecdsa # IdentityFile ~/.ssh/id_ed25519 # Port 22 diff --git a/sshconnect.c b/sshconnect.c index c86182d13673..b306fa3cc24f 100644 --- a/sshconnect.c +++ b/sshconnect.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshconnect.c,v 1.369 2024/12/06 16:21:48 djm Exp $ */ +/* $OpenBSD: sshconnect.c,v 1.370 2025/05/06 05:40:56 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1626,9 +1626,6 @@ show_other_keys(struct hostkeys *hostkeys, struct sshkey *key) { int type[] = { KEY_RSA, -#ifdef WITH_DSA - KEY_DSA, -#endif KEY_ECDSA, KEY_ED25519, KEY_XMSS, diff --git a/sshd-auth.c b/sshd-auth.c index 30eecd8a4723..5de06a5baa49 100644 --- a/sshd-auth.c +++ b/sshd-auth.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd-auth.c,v 1.3 2025/01/16 06:37:10 dtucker Exp $ */ +/* $OpenBSD: sshd-auth.c,v 1.4 2025/05/06 05:40:56 djm Exp $ */ /* * SSH2 implementation: * Privilege Separation: @@ -250,7 +250,6 @@ list_hostkey_types(void) append_hostkey_type(b, "rsa-sha2-512"); append_hostkey_type(b, "rsa-sha2-256"); /* FALLTHROUGH */ - case KEY_DSA: case KEY_ECDSA: case KEY_ED25519: case KEY_ECDSA_SK: @@ -271,7 +270,6 @@ list_hostkey_types(void) append_hostkey_type(b, "rsa-sha2-256-cert-v01@openssh.com"); /* FALLTHROUGH */ - case KEY_DSA_CERT: case KEY_ECDSA_CERT: case KEY_ED25519_CERT: case KEY_ECDSA_SK_CERT: @@ -297,7 +295,6 @@ get_hostkey_public_by_type(int type, int nid, struct ssh *ssh) for (i = 0; i < options.num_host_key_files; i++) { switch (type) { case KEY_RSA_CERT: - case KEY_DSA_CERT: case KEY_ECDSA_CERT: case KEY_ED25519_CERT: case KEY_ECDSA_SK_CERT: diff --git a/sshd-session.c b/sshd-session.c index c64eb29fcefd..60f887e92d7b 100644 --- a/sshd-session.c +++ b/sshd-session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd-session.c,v 1.12 2025/03/12 22:43:44 djm Exp $ */ +/* $OpenBSD: sshd-session.c,v 1.13 2025/05/06 05:40:56 djm Exp $ */ /* * SSH2 implementation: * Privilege Separation: @@ -485,7 +485,6 @@ get_hostkey_by_type(int type, int nid, int need_private, struct ssh *ssh) for (i = 0; i < options.num_host_key_files; i++) { switch (type) { case KEY_RSA_CERT: - case KEY_DSA_CERT: case KEY_ECDSA_CERT: case KEY_ED25519_CERT: case KEY_ECDSA_SK_CERT: diff --git a/sshd.c b/sshd.c index 4a93e29e4c04..03732bb09c50 100644 --- a/sshd.c +++ b/sshd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd.c,v 1.617 2025/04/07 08:12:22 dtucker Exp $ */ +/* $OpenBSD: sshd.c,v 1.618 2025/05/06 05:40:56 djm Exp $ */ /* * Copyright (c) 2000, 2001, 2002 Markus Friedl. All rights reserved. * Copyright (c) 2002 Niels Provos. All rights reserved. @@ -1658,7 +1658,6 @@ main(int ac, char **av) switch (keytype) { case KEY_RSA: - case KEY_DSA: case KEY_ECDSA: case KEY_ED25519: case KEY_ECDSA_SK: diff --git a/sshkey.c b/sshkey.c index ab80752b8d0b..55a156818962 100644 --- a/sshkey.c +++ b/sshkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshkey.c,v 1.148 2024/12/03 15:53:51 tb Exp $ */ +/* $OpenBSD: sshkey.c,v 1.149 2025/05/06 05:40:56 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * Copyright (c) 2008 Alexander von Gernler. All rights reserved. @@ -119,10 +119,6 @@ extern const struct sshkey_impl sshkey_rsa_sha256_impl; extern const struct sshkey_impl sshkey_rsa_sha256_cert_impl; extern const struct sshkey_impl sshkey_rsa_sha512_impl; extern const struct sshkey_impl sshkey_rsa_sha512_cert_impl; -# ifdef WITH_DSA -extern const struct sshkey_impl sshkey_dss_impl; -extern const struct sshkey_impl sshkey_dsa_cert_impl; -# endif #endif /* WITH_OPENSSL */ #ifdef WITH_XMSS extern const struct sshkey_impl sshkey_xmss_impl; @@ -152,10 +148,6 @@ const struct sshkey_impl * const keyimpls[] = { &sshkey_ecdsa_sk_webauthn_impl, # endif /* ENABLE_SK */ # endif /* OPENSSL_HAS_ECC */ -# ifdef WITH_DSA - &sshkey_dss_impl, - &sshkey_dsa_cert_impl, -# endif &sshkey_rsa_impl, &sshkey_rsa_cert_impl, &sshkey_rsa_sha256_impl, @@ -451,8 +443,6 @@ sshkey_type_plain(int type) switch (type) { case KEY_RSA_CERT: return KEY_RSA; - case KEY_DSA_CERT: - return KEY_DSA; case KEY_ECDSA_CERT: return KEY_ECDSA; case KEY_ECDSA_SK_CERT: @@ -475,8 +465,6 @@ sshkey_type_certified(int type) switch (type) { case KEY_RSA: return KEY_RSA_CERT; - case KEY_DSA: - return KEY_DSA_CERT; case KEY_ECDSA: return KEY_ECDSA_CERT; case KEY_ECDSA_SK: @@ -3322,20 +3310,6 @@ sshkey_private_to_blob_pem_pkcs8(struct sshkey *key, struct sshbuf *buf, goto out; switch (key->type) { -#ifdef WITH_DSA - case KEY_DSA: - if (format == SSHKEY_PRIVATE_PEM) { - success = PEM_write_bio_DSAPrivateKey(bio, key->dsa, - cipher, passphrase, len, NULL, NULL); - } else { - if ((pkey = EVP_PKEY_new()) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto out; - } - success = EVP_PKEY_set1_DSA(pkey, key->dsa); - } - break; -#endif #ifdef OPENSSL_HAS_ECC case KEY_ECDSA: if (format == SSHKEY_PRIVATE_PEM) { @@ -3403,7 +3377,6 @@ sshkey_private_to_fileblob(struct sshkey *key, struct sshbuf *blob, { switch (key->type) { #ifdef WITH_OPENSSL - case KEY_DSA: case KEY_ECDSA: case KEY_RSA: break; /* see below */ @@ -3578,19 +3551,6 @@ sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type, prv->pkey = pk; if ((r = sshkey_check_rsa_length(prv, 0)) != 0) goto out; -#ifdef WITH_DSA - } else if (EVP_PKEY_base_id(pk) == EVP_PKEY_DSA && - (type == KEY_UNSPEC || type == KEY_DSA)) { - if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto out; - } - prv->dsa = EVP_PKEY_get1_DSA(pk); - prv->type = KEY_DSA; -#ifdef DEBUG_PK - DSA_print_fp(stderr, prv->dsa, 8); -#endif -#endif #ifdef OPENSSL_HAS_ECC } else if (EVP_PKEY_base_id(pk) == EVP_PKEY_EC && (type == KEY_UNSPEC || type == KEY_ECDSA)) { diff --git a/sshkey.h b/sshkey.h index 19bbbac7dc0f..5fa410b9431d 100644 --- a/sshkey.h +++ b/sshkey.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sshkey.h,v 1.66 2025/04/02 04:28:03 tb Exp $ */ +/* $OpenBSD: sshkey.h,v 1.67 2025/05/06 05:40:56 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. @@ -30,9 +30,6 @@ #ifdef WITH_OPENSSL #include -#ifdef WITH_DSA -#include -#endif #include # ifdef OPENSSL_HAS_ECC # include @@ -46,7 +43,6 @@ #else /* WITH_OPENSSL */ # define BIGNUM void # define RSA void -# define DSA void # define EC_KEY void # define EC_GROUP void # define EC_POINT void @@ -62,11 +58,9 @@ struct sshbuf; /* Key types */ enum sshkey_types { KEY_RSA, - KEY_DSA, KEY_ECDSA, KEY_ED25519, KEY_RSA_CERT, - KEY_DSA_CERT, KEY_ECDSA_CERT, KEY_ED25519_CERT, KEY_XMSS, @@ -129,8 +123,6 @@ struct sshkey_cert { struct sshkey { int type; int flags; - /* KEY_DSA */ - DSA *dsa; /* KEY_ECDSA and KEY_ECDSA_SK */ int ecdsa_nid; /* NID of curve */ /* libcrypto-backed keys */ @@ -353,7 +345,6 @@ int check_rsa_length(const RSA *rsa); /* XXX remove */ #if !defined(WITH_OPENSSL) # undef RSA -# undef DSA # undef EC_KEY # undef EC_GROUP # undef EC_POINT From 55b38ff4d7286c8fac2a472da664462e0f2d75e0 Mon Sep 17 00:00:00 2001 From: "deraadt@openbsd.org" Date: Tue, 6 May 2025 15:15:05 +0000 Subject: [PATCH 027/244] upstream: test ssh-agent with the -T flag to force the old /tmp location rather than inside the homedir. During relink operation, /.ssh/agent was created which is surprising. This test sequence could use some improvement so this is a temporary fix. observed by florian, change ok semarie OpenBSD-Commit-ID: c7246a6b519ac390ca550719f91acfdaef1fa0f0 --- .skipped-commit-ids | 1 + 1 file changed, 1 insertion(+) diff --git a/.skipped-commit-ids b/.skipped-commit-ids index 7988e25006f4..319beea0dee6 100644 --- a/.skipped-commit-ids +++ b/.skipped-commit-ids @@ -39,6 +39,7 @@ fb39324748824cb0387e9d67c41d1bef945c54ea Makefile change 112aacedd3b61cc5c34b1fa6d9fb759214179172 Makefile change a959fc45ea3431b36f52eda04faefc58bcde00db groupaccess.c changes 6d07e4606997e36b860621a14dd41975f2902f8f Makefile.inc +c7246a6b519ac390ca550719f91acfdaef1fa0f0 Makefile relink change Old upstream tree: From 93e904a673a632604525fdc98b940b7996f1ce54 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Wed, 7 May 2025 04:10:21 +0000 Subject: [PATCH 028/244] upstream: memory leak on error path; bz3821 OpenBSD-Commit-ID: 65577596a15ad6dd9a1ab3fc24c1c31303ee6e2b --- misc-agent.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/misc-agent.c b/misc-agent.c index f13ccdf26b5d..9d96880e9090 100644 --- a/misc-agent.c +++ b/misc-agent.c @@ -266,10 +266,10 @@ socket_is_stale(const char *path) void agent_cleanup_stale(const char *homedir, int ignore_hosthash) { - DIR *d; + DIR *d = NULL; struct dirent *dp; struct stat sb; - char *prefix = NULL, *dirpath, *path; + char *prefix = NULL, *dirpath = NULL, *path; struct timespec now, sub, *mtimp = NULL; /* Only consider sockets last modified > 1 hour ago */ @@ -295,8 +295,7 @@ agent_cleanup_stale(const char *homedir, int ignore_hosthash) if ((d = opendir(dirpath)) == NULL) { if (errno != ENOENT) error_f("opendir \"%s\": %s", dirpath, strerror(errno)); - free(dirpath); - return; + goto out; } while ((dp = readdir(d)) != NULL) { if (dp->d_type != DT_SOCK && dp->d_type != DT_UNKNOWN) @@ -334,8 +333,9 @@ agent_cleanup_stale(const char *homedir, int ignore_hosthash) } free(path); } - closedir(d); + out: + if (d != NULL) + closedir(d); free(dirpath); free(prefix); } - From c5dbbe8805caaee132545ab4cffd3b2221e80975 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Tue, 15 Apr 2025 05:00:13 +0000 Subject: [PATCH 029/244] upstream: missing ifdef OpenBSD-Regress-ID: 7260fb672de5738c17dec06c71a5be0186bb2b09 --- regress/unittests/sshkey/test_sshkey.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/regress/unittests/sshkey/test_sshkey.c b/regress/unittests/sshkey/test_sshkey.c index fc744eb7430f..aca1f2406d50 100644 --- a/regress/unittests/sshkey/test_sshkey.c +++ b/regress/unittests/sshkey/test_sshkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: test_sshkey.c,v 1.26 2025/04/15 04:00:42 djm Exp $ */ +/* $OpenBSD: test_sshkey.c,v 1.27 2025/04/15 05:00:13 djm Exp $ */ /* * Regress test for sshkey.h key management API * From 0404fa799746c283325a463c363436eb152daefc Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Tue, 15 Apr 2025 05:31:24 +0000 Subject: [PATCH 030/244] upstream: another missing ifdef OpenBSD-Regress-ID: 4f71f8f122eac4cbf7f1d2088a9be45317dd3e4a --- regress/unittests/sshkey/test_sshkey.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/regress/unittests/sshkey/test_sshkey.c b/regress/unittests/sshkey/test_sshkey.c index aca1f2406d50..53bdc0ca62d8 100644 --- a/regress/unittests/sshkey/test_sshkey.c +++ b/regress/unittests/sshkey/test_sshkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: test_sshkey.c,v 1.27 2025/04/15 05:00:13 djm Exp $ */ +/* $OpenBSD: test_sshkey.c,v 1.28 2025/04/15 05:31:24 djm Exp $ */ /* * Regress test for sshkey.h key management API * From 7cc8e150d51a4545b86d996692b541419b35d1a3 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Tue, 6 May 2025 06:05:48 +0000 Subject: [PATCH 031/244] upstream: remove DSA from the regression/unit test suite too. OpenBSD-Regress-ID: 4424d2eaf0bce3887318ef6d18de6c06f3617d6e --- INSTALL | 2 +- Makefile.in | 2 - contrib/redhat/openssh.spec | 14 -- contrib/redhat/sshd.init | 2 +- openbsd-compat/openssl-compat.h | 1 - regress/Makefile | 30 +-- regress/agent.sh | 8 +- regress/cert-hostkey.sh | 4 +- regress/cert-userkey.sh | 6 +- regress/dsa_ssh2.prv | 14 -- regress/dsa_ssh2.pub | 13 -- regress/hostbased.sh | 3 +- regress/keytype.sh | 4 +- regress/knownhosts-command.sh | 3 +- regress/krl.sh | 3 +- regress/limit-keytype.sh | 6 +- regress/misc/fuzz-harness/fixed-keys.h | 35 --- .../testdata/create-agent-corpus.sh | 2 +- .../fuzz-harness/testdata/id_dsa-cert.pub | 1 - regress/misc/ssh-verify-attestation/Makefile | 4 +- regress/ssh-com-client.sh | 14 +- regress/ssh-com.sh | 26 +-- regress/ssh2putty.sh | 3 +- regress/sshcfgparse.sh | 27 +-- regress/unittests/Makefile.inc | 6 +- regress/unittests/authopt/Makefile | 4 +- regress/unittests/hostkeys/Makefile | 4 +- regress/unittests/hostkeys/mktestdata.sh | 13 +- regress/unittests/hostkeys/test_iterate.c | 212 ++++-------------- regress/unittests/hostkeys/testdata/dsa_1.pub | 1 - regress/unittests/hostkeys/testdata/dsa_2.pub | 1 - regress/unittests/hostkeys/testdata/dsa_3.pub | 1 - regress/unittests/hostkeys/testdata/dsa_4.pub | 1 - regress/unittests/hostkeys/testdata/dsa_5.pub | 1 - regress/unittests/hostkeys/testdata/dsa_6.pub | 1 - .../unittests/hostkeys/testdata/known_hosts | 12 +- regress/unittests/kex/Makefile | 4 +- regress/unittests/kex/test_kex.c | 5 +- regress/unittests/sshkey/Makefile | 4 +- regress/unittests/sshkey/common.c | 37 +-- regress/unittests/sshkey/common.h | 5 +- regress/unittests/sshkey/mktestdata.sh | 53 +---- regress/unittests/sshkey/test_file.c | 96 +------- regress/unittests/sshkey/test_fuzz.c | 75 +------ regress/unittests/sshkey/test_sshkey.c | 69 +----- regress/unittests/sshkey/testdata/dsa_1 | 12 - .../unittests/sshkey/testdata/dsa_1-cert.fp | 1 - .../unittests/sshkey/testdata/dsa_1-cert.pub | 1 - regress/unittests/sshkey/testdata/dsa_1.fp | 1 - regress/unittests/sshkey/testdata/dsa_1.fp.bb | 1 - .../unittests/sshkey/testdata/dsa_1.param.g | 1 - .../sshkey/testdata/dsa_1.param.priv | 1 - .../unittests/sshkey/testdata/dsa_1.param.pub | 1 - regress/unittests/sshkey/testdata/dsa_1.pub | 1 - regress/unittests/sshkey/testdata/dsa_1_pw | 15 -- regress/unittests/sshkey/testdata/dsa_2 | 12 - regress/unittests/sshkey/testdata/dsa_2.fp | 1 - regress/unittests/sshkey/testdata/dsa_2.fp.bb | 1 - regress/unittests/sshkey/testdata/dsa_2.pub | 1 - regress/unittests/sshkey/testdata/dsa_n | 21 -- regress/unittests/sshkey/testdata/dsa_n_pw | 21 -- regress/unittests/sshsig/Makefile | 4 +- regress/unittests/sshsig/mktestdata.sh | 8 +- regress/unittests/sshsig/testdata/dsa | 12 - regress/unittests/sshsig/testdata/dsa.pub | 1 - regress/unittests/sshsig/testdata/dsa.sig | 13 -- regress/unittests/sshsig/tests.c | 7 +- 67 files changed, 126 insertions(+), 843 deletions(-) delete mode 100644 regress/dsa_ssh2.prv delete mode 100644 regress/dsa_ssh2.pub delete mode 100644 regress/misc/fuzz-harness/testdata/id_dsa-cert.pub delete mode 100644 regress/unittests/hostkeys/testdata/dsa_1.pub delete mode 100644 regress/unittests/hostkeys/testdata/dsa_2.pub delete mode 100644 regress/unittests/hostkeys/testdata/dsa_3.pub delete mode 100644 regress/unittests/hostkeys/testdata/dsa_4.pub delete mode 100644 regress/unittests/hostkeys/testdata/dsa_5.pub delete mode 100644 regress/unittests/hostkeys/testdata/dsa_6.pub delete mode 100644 regress/unittests/sshkey/testdata/dsa_1 delete mode 100644 regress/unittests/sshkey/testdata/dsa_1-cert.fp delete mode 100644 regress/unittests/sshkey/testdata/dsa_1-cert.pub delete mode 100644 regress/unittests/sshkey/testdata/dsa_1.fp delete mode 100644 regress/unittests/sshkey/testdata/dsa_1.fp.bb delete mode 100644 regress/unittests/sshkey/testdata/dsa_1.param.g delete mode 100644 regress/unittests/sshkey/testdata/dsa_1.param.priv delete mode 100644 regress/unittests/sshkey/testdata/dsa_1.param.pub delete mode 100644 regress/unittests/sshkey/testdata/dsa_1.pub delete mode 100644 regress/unittests/sshkey/testdata/dsa_1_pw delete mode 100644 regress/unittests/sshkey/testdata/dsa_2 delete mode 100644 regress/unittests/sshkey/testdata/dsa_2.fp delete mode 100644 regress/unittests/sshkey/testdata/dsa_2.fp.bb delete mode 100644 regress/unittests/sshkey/testdata/dsa_2.pub delete mode 100644 regress/unittests/sshkey/testdata/dsa_n delete mode 100644 regress/unittests/sshkey/testdata/dsa_n_pw delete mode 100644 regress/unittests/sshsig/testdata/dsa delete mode 100644 regress/unittests/sshsig/testdata/dsa.pub delete mode 100644 regress/unittests/sshsig/testdata/dsa.sig diff --git a/INSTALL b/INSTALL index 3ad1659f36f6..56e351af60e1 100644 --- a/INSTALL +++ b/INSTALL @@ -245,7 +245,7 @@ manually using the following commands: ssh-keygen -t [type] -f /etc/ssh/ssh_host_key -N "" -for each of the types you wish to generate (rsa, dsa or ecdsa) or +for each of the types you wish to generate (rsa, ed25519 or ecdsa) or ssh-keygen -A diff --git a/Makefile.in b/Makefile.in index ae86a712b17b..672bf4493cf8 100644 --- a/Makefile.in +++ b/Makefile.in @@ -194,7 +194,6 @@ PATHSUBS = \ -e 's|/etc/shosts.equiv|$(sysconfdir)/shosts.equiv|g' \ -e 's|/etc/ssh/ssh_host_key|$(sysconfdir)/ssh_host_key|g' \ -e 's|/etc/ssh/ssh_host_ecdsa_key|$(sysconfdir)/ssh_host_ecdsa_key|g' \ - -e 's|/etc/ssh/ssh_host_dsa_key|$(sysconfdir)/ssh_host_dsa_key|g' \ -e 's|/etc/ssh/ssh_host_rsa_key|$(sysconfdir)/ssh_host_rsa_key|g' \ -e 's|/etc/ssh/ssh_host_ed25519_key|$(sysconfdir)/ssh_host_ed25519_key|g' \ -e 's|/var/run/sshd.pid|$(piddir)/sshd.pid|g' \ @@ -494,7 +493,6 @@ host-key: ssh-keygen$(EXEEXT) fi host-key-force: ssh-keygen$(EXEEXT) ssh$(EXEEXT) - ./ssh-keygen -t dsa -f $(DESTDIR)$(sysconfdir)/ssh_host_dsa_key -N "" ./ssh-keygen -t rsa -f $(DESTDIR)$(sysconfdir)/ssh_host_rsa_key -N "" ./ssh-keygen -t ed25519 -f $(DESTDIR)$(sysconfdir)/ssh_host_ed25519_key -N "" if ./ssh -Q key | grep ecdsa >/dev/null ; then \ diff --git a/contrib/redhat/openssh.spec b/contrib/redhat/openssh.spec index 74116b485135..b60695f09f95 100644 --- a/contrib/redhat/openssh.spec +++ b/contrib/redhat/openssh.spec @@ -281,20 +281,6 @@ if [ "$1" != 0 -a -r /var/run/sshd.pid ] ; then touch /var/run/sshd.restart fi -%triggerun server -- openssh-server < 2.5.0p1 -# Count the number of HostKey and HostDsaKey statements we have. -gawk 'BEGIN {IGNORECASE=1} - /^hostkey/ || /^hostdsakey/ {sawhostkey = sawhostkey + 1} - END {exit sawhostkey}' /etc/ssh/sshd_config -# And if we only found one, we know the client was relying on the old default -# behavior, which loaded the the SSH2 DSA host key when HostDsaKey wasn't -# specified. Now that HostKey is used for both SSH1 and SSH2 keys, specifying -# one nullifies the default, which would have loaded both. -if [ $? -eq 1 ] ; then - echo HostKey /etc/ssh/ssh_host_rsa_key >> /etc/ssh/sshd_config - echo HostKey /etc/ssh/ssh_host_dsa_key >> /etc/ssh/sshd_config -fi - %triggerpostun server -- ssh-server if [ "$1" != 0 ] ; then /sbin/chkconfig --add sshd diff --git a/contrib/redhat/sshd.init b/contrib/redhat/sshd.init index 8ee5fcd3bb4f..b82545956ac8 100755 --- a/contrib/redhat/sshd.init +++ b/contrib/redhat/sshd.init @@ -41,7 +41,7 @@ start() /usr/bin/ssh-keygen -A if [ -x /sbin/restorecon ]; then /sbin/restorecon /etc/ssh/ssh_host_rsa_key.pub - /sbin/restorecon /etc/ssh/ssh_host_dsa_key.pub + /sbin/restorecon /etc/ssh/ssh_host_ed25519_key.pub /sbin/restorecon /etc/ssh/ssh_host_ecdsa_key.pub fi diff --git a/openbsd-compat/openssl-compat.h b/openbsd-compat/openssl-compat.h index a7c41c235b5c..936f4068d843 100644 --- a/openbsd-compat/openssl-compat.h +++ b/openbsd-compat/openssl-compat.h @@ -24,7 +24,6 @@ #include #include #include -#include #ifdef OPENSSL_HAS_ECC #include #endif diff --git a/regress/Makefile b/regress/Makefile index 8b69e14e998f..d97ea34a2050 100644 --- a/regress/Makefile +++ b/regress/Makefile @@ -2,7 +2,7 @@ tests: prep file-tests t-exec unit -REGRESS_TARGETS= t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 +REGRESS_TARGETS= t1 t2 t3 t4 t5 t7 t9 t10 t11 t12 # File based tests file-tests: $(REGRESS_TARGETS) @@ -130,9 +130,9 @@ CLEANFILES= *.core actual agent-key.* authorized_keys_${USERNAME} \ ed25519-agent.pub ed25519 ed25519.pub empty.in \ expect failed-regress.log failed-ssh.log failed-sshd.log \ hkr.* host.ecdsa-sha2-nistp256 host.ecdsa-sha2-nistp384 \ - host.ecdsa-sha2-nistp521 host.ssh-dss host.ssh-ed25519 \ + host.ecdsa-sha2-nistp521 host.ssh-ed25519 \ host.ssh-rsa host_ca_key* host_krl_* host_revoked_* key.* \ - key.dsa-* key.ecdsa-* key.ed25519-512 \ + key.ecdsa-* key.ed25519-512 \ key.ed25519-512.pub key.rsa-* keys-command-args kh.* askpass \ known_hosts known_hosts-cert known_hosts.* krl-* ls.copy \ modpipe netcat no_identity_config \ @@ -191,36 +191,18 @@ t5: ${TEST_SSH_SSHKEYGEN} -Bf ${.CURDIR}/rsa_openssh.pub |\ awk '{print $$2}' | diff - ${.CURDIR}/t5.ok ; \ fi -t6: - set -xe ; if ${TEST_SSH_SSH} -Q key | grep -q "^ssh-dss" ; then \ - ${TEST_SSH_SSHKEYGEN} -if ${.CURDIR}/dsa_ssh2.prv > $(OBJ)/t6.out1 ; \ - ${TEST_SSH_SSHKEYGEN} -if ${.CURDIR}/dsa_ssh2.pub > $(OBJ)/t6.out2 ; \ - chmod 600 $(OBJ)/t6.out1 ; \ - ${TEST_SSH_SSHKEYGEN} -yf $(OBJ)/t6.out1 | diff - $(OBJ)/t6.out2 ; \ - fi $(OBJ)/t7.out: - set -xe ; if ${TEST_SSH_SSH} -Q key | grep -q "^ssh-dss" ; then \ + set -xe ; if ${TEST_SSH_SSH} -Q key | grep -q "^ssh-rsa" ; then \ ${TEST_SSH_SSHKEYGEN} -q -t rsa -N '' -f $@ ; \ fi t7: $(OBJ)/t7.out - set -xe ; if ${TEST_SSH_SSH} -Q key | grep -q "^ssh-dss" ; then \ + set -xe ; if ${TEST_SSH_SSH} -Q key | grep -q "^ssh-rsa" ; then \ ${TEST_SSH_SSHKEYGEN} -lf $(OBJ)/t7.out > /dev/null ; \ ${TEST_SSH_SSHKEYGEN} -Bf $(OBJ)/t7.out > /dev/null ; \ fi -$(OBJ)/t8.out: - set -xe ; if ssh -Q key | grep -q "^ssh-dss" ; then \ - ${TEST_SSH_SSHKEYGEN} -q -t dsa -N '' -f $@ ; \ - fi - -t8: $(OBJ)/t8.out - set -xe ; if ssh -Q key | grep -q "^ssh-dss" ; then \ - ${TEST_SSH_SSHKEYGEN} -lf $(OBJ)/t8.out > /dev/null ; \ - ${TEST_SSH_SSHKEYGEN} -Bf $(OBJ)/t8.out > /dev/null ; \ - fi - $(OBJ)/t9.out: ! ${TEST_SSH_SSH} -Q key-plain | grep ecdsa >/dev/null || \ ${TEST_SSH_SSHKEYGEN} -q -t ecdsa -N '' -f $@ @@ -240,7 +222,7 @@ t10: $(OBJ)/t10.out ${TEST_SSH_SSHKEYGEN} -Bf $(OBJ)/t10.out > /dev/null t11: - set -xe ; if ${TEST_SSH_SSH} -Q key | grep -q "^ssh-dss" ; then \ + set -xe ; if ${TEST_SSH_SSH} -Q key | grep -q "^ssh-rsa" ; then \ ${TEST_SSH_SSHKEYGEN} -E sha256 -lf ${.CURDIR}/rsa_openssh.pub |\ awk '{print $$2}' | diff - ${.CURDIR}/t11.ok ; \ fi diff --git a/regress/agent.sh b/regress/agent.sh index f0022aca5528..26d4c9ed44b2 100644 --- a/regress/agent.sh +++ b/regress/agent.sh @@ -1,4 +1,4 @@ -# $OpenBSD: agent.sh,v 1.22 2024/10/24 03:28:34 djm Exp $ +# $OpenBSD: agent.sh,v 1.23 2025/05/06 06:05:48 djm Exp $ # Placed in the Public Domain. tid="simple agent test" @@ -86,10 +86,6 @@ fi for t in ${SSH_KEYTYPES}; do trace "connect via agent using $t key" - if [ "$t" = "ssh-dss" ]; then - echo "PubkeyAcceptedAlgorithms +ssh-dss" >> $OBJ/ssh_proxy - echo "PubkeyAcceptedAlgorithms +ssh-dss" >> $OBJ/sshd_proxy - fi ${SSH} -F $OBJ/ssh_proxy -i $OBJ/$t-agent.pub -oIdentitiesOnly=yes \ somehost exit 52 r=$? @@ -143,7 +139,6 @@ fi (printf 'cert-authority,principals="estragon" '; cat $OBJ/user_ca_key.pub) \ > $OBJ/authorized_keys_$USER for t in ${SSH_KEYTYPES}; do - if [ "$t" != "ssh-dss" ]; then trace "connect via agent using $t key" ${SSH} -F $OBJ/ssh_proxy -i $OBJ/$t-agent.pub \ -oCertificateFile=$OBJ/$t-agent-cert.pub \ @@ -152,7 +147,6 @@ for t in ${SSH_KEYTYPES}; do if [ $r -ne 52 ]; then fail "ssh connect with failed (exit code $r)" fi - fi done ## Deletion tests. diff --git a/regress/cert-hostkey.sh b/regress/cert-hostkey.sh index a3414e1a5c50..bfdd3588d98f 100644 --- a/regress/cert-hostkey.sh +++ b/regress/cert-hostkey.sh @@ -1,4 +1,4 @@ -# $OpenBSD: cert-hostkey.sh,v 1.27 2021/09/30 05:26:26 dtucker Exp $ +# $OpenBSD: cert-hostkey.sh,v 1.28 2025/05/06 06:05:48 djm Exp $ # Placed in the Public Domain. tid="certified host keys" @@ -70,7 +70,7 @@ touch $OBJ/host_revoked_plain touch $OBJ/host_revoked_cert cat $OBJ/host_ca_key.pub $OBJ/host_ca_key2.pub > $OBJ/host_revoked_ca -PLAIN_TYPES=`echo "$SSH_KEYTYPES" | sed 's/^ssh-dss/ssh-dsa/g;s/^ssh-//'` +PLAIN_TYPES=`echo "$SSH_KEYTYPES" | sed 's/^ssh-//'` if echo "$PLAIN_TYPES" | grep '^rsa$' >/dev/null 2>&1 ; then PLAIN_TYPES="$PLAIN_TYPES rsa-sha2-256 rsa-sha2-512" diff --git a/regress/cert-userkey.sh b/regress/cert-userkey.sh index 2ab0a1e9e65c..fde2caefbd4f 100644 --- a/regress/cert-userkey.sh +++ b/regress/cert-userkey.sh @@ -1,4 +1,4 @@ -# $OpenBSD: cert-userkey.sh,v 1.29 2024/12/06 16:25:58 djm Exp $ +# $OpenBSD: cert-userkey.sh,v 1.30 2025/05/06 06:05:48 djm Exp $ # Placed in the Public Domain. tid="certified user keys" @@ -10,7 +10,7 @@ cp $OBJ/ssh_proxy $OBJ/ssh_proxy_bak grep -v AuthorizedKeysFile $OBJ/sshd_proxy > $OBJ/sshd_proxy_bak echo "AuthorizedKeysFile $OBJ/authorized_keys_%u_*" >> $OBJ/sshd_proxy_bak -PLAIN_TYPES=`$SSH -Q key-plain | maybe_filter_sk | sed 's/^ssh-dss/ssh-dsa/;s/^ssh-//'` +PLAIN_TYPES=`$SSH -Q key-plain | maybe_filter_sk | sed 's/^ssh-//'` EXTRA_TYPES="" rsa="" @@ -25,7 +25,7 @@ kname() { sk-ecdsa-*) n="sk-ecdsa" ;; sk-ssh-ed25519*) n="sk-ssh-ed25519" ;; # subshell because some seds will add a newline - *) n=$(echo $1 | sed 's/^dsa/ssh-dss/;s/^rsa/ssh-rsa/;s/^ed/ssh-ed/') ;; + *) n=$(echo $1 | sed 's/^rsa/ssh-rsa/;s/^ed/ssh-ed/') ;; esac if [ -z "$rsa" ]; then echo "$n*,ssh-ed25519*" diff --git a/regress/dsa_ssh2.prv b/regress/dsa_ssh2.prv deleted file mode 100644 index c93b4037194c..000000000000 --- a/regress/dsa_ssh2.prv +++ /dev/null @@ -1,14 +0,0 @@ ----- BEGIN SSH2 ENCRYPTED PRIVATE KEY ---- -Subject: ssh-keygen test -Comment: "1024-bit dsa, Tue Jan 08 2002 22:00:23 +0100" -P2/56wAAAgIAAAAmZGwtbW9kcHtzaWdue2RzYS1uaXN0LXNoYTF9LGRoe3BsYWlufX0AAA -AEbm9uZQAAAcQAAAHAAAAAAAAABACwUfm3AxZTut3icBmwCcD48nY64HzuELlQ+vEqjIcR -Lo49es/DQTeLNQ+kdKRCfouosGNv0WqxRtF0tUsWdXxS37oHGa4QPugBdHRd7YlZGZv8kg -x7FsoepY7v7E683/97dv2zxL3AGagTEzWr7fl0yPexAaZoDvtQrrjX44BLmwAABACWQkvv -MxnD8eFkS1konFfMJ1CkuRfTN34CBZ6dY7VTSGemy4QwtFdMKmoufD0eKgy3p5WOeWCYKt -F4FhjHKZk/aaxFjjIbtkrnlvXg64QI11dSZyBN6/ViQkHPSkUDF+A6AAEhrNbQbAFSvao1 -kTvNtPCtL0AkUIduEMzGQfLCTAAAAKDeC043YVo9Zo0zAEeIA4uZh4LBCQAAA/9aj7Y5ik -ehygJ4qTDSlVypsPuV+n59tMS0e2pfrSG87yf5r94AKBmJeho5OO6wYaXCxsVB7AFbSUD6 -75AK8mHF4v1/+7SWKk5f8xlMCMSPZ9K0+j/W1d/q2qkhnnDZolOHDomLA+U00i5ya/jnTV -zyDPWLFpWK8u3xGBPAYX324gAAAKDHFvooRnaXdZbeWGTTqmgHB1GU9A== ----- END SSH2 ENCRYPTED PRIVATE KEY ---- diff --git a/regress/dsa_ssh2.pub b/regress/dsa_ssh2.pub deleted file mode 100644 index 215d73baef31..000000000000 --- a/regress/dsa_ssh2.pub +++ /dev/null @@ -1,13 +0,0 @@ ----- BEGIN SSH2 PUBLIC KEY ---- -Subject: ssh-keygen test -Comment: "1024-bit dsa, Tue Jan 08 2002 22:00:23 +0100" -AAAAB3NzaC1kc3MAAACBALBR+bcDFlO63eJwGbAJwPjydjrgfO4QuVD68SqMhxEujj16z8 -NBN4s1D6R0pEJ+i6iwY2/RarFG0XS1SxZ1fFLfugcZrhA+6AF0dF3tiVkZm/ySDHsWyh6l -ju/sTrzf/3t2/bPEvcAZqBMTNavt+XTI97EBpmgO+1CuuNfjgEubAAAAFQDeC043YVo9Zo -0zAEeIA4uZh4LBCQAAAIEAlkJL7zMZw/HhZEtZKJxXzCdQpLkX0zd+AgWenWO1U0hnpsuE -MLRXTCpqLnw9HioMt6eVjnlgmCrReBYYxymZP2msRY4yG7ZK55b14OuECNdXUmcgTev1Yk -JBz0pFAxfgOgABIazW0GwBUr2qNZE7zbTwrS9AJFCHbhDMxkHywkwAAACAWo+2OYpHocoC -eKkw0pVcqbD7lfp+fbTEtHtqX60hvO8n+a/eACgZiXoaOTjusGGlwsbFQewBW0lA+u+QCv -JhxeL9f/u0lipOX/MZTAjEj2fStPo/1tXf6tqpIZ5w2aJThw6JiwPlNNIucmv4501c8gz1 -ixaVivLt8RgTwGF99uI= ----- END SSH2 PUBLIC KEY ---- diff --git a/regress/hostbased.sh b/regress/hostbased.sh index eb9cf2727d33..5de176b18bf7 100644 --- a/regress/hostbased.sh +++ b/regress/hostbased.sh @@ -1,4 +1,4 @@ -# $OpenBSD: hostbased.sh,v 1.4 2022/12/07 11:45:43 dtucker Exp $ +# $OpenBSD: hostbased.sh,v 1.5 2025/05/06 06:05:48 djm Exp $ # Placed in the Public Domain. # This test requires external setup and thus is skipped unless @@ -43,7 +43,6 @@ for key in `${SUDO} ${SSHD} -T | awk '$1=="hostkey"{print $2}'`; do 521*ECDSA*) algos="$algos ecdsa-sha2-nistp521" ;; *RSA*) algos="$algos ssh-rsa rsa-sha2-256 rsa-sha2-512" ;; *ED25519*) algos="$algos ssh-ed25519" ;; - *DSA*) algos="$algos ssh-dss" ;; *) verbose "unknown host key type $key" ;; esac done diff --git a/regress/keytype.sh b/regress/keytype.sh index f1c045183bd3..11ef7d0cb270 100644 --- a/regress/keytype.sh +++ b/regress/keytype.sh @@ -1,4 +1,4 @@ -# $OpenBSD: keytype.sh,v 1.11 2021/02/25 03:27:34 djm Exp $ +# $OpenBSD: keytype.sh,v 1.12 2025/05/06 06:05:48 djm Exp $ # Placed in the Public Domain. tid="login with different key types" @@ -10,7 +10,6 @@ cp $OBJ/ssh_proxy $OBJ/ssh_proxy_bak ktypes="" for i in ${SSH_KEYTYPES}; do case "$i" in - ssh-dss) ktypes="$ktypes dsa-1024" ;; ssh-rsa) ktypes="$ktypes rsa-2048 rsa-3072" ;; ssh-ed25519) ktypes="$ktypes ed25519-512" ;; ecdsa-sha2-nistp256) ktypes="$ktypes ecdsa-256" ;; @@ -36,7 +35,6 @@ done kname_to_ktype() { case $1 in - dsa-1024) echo ssh-dss;; ecdsa-256) echo ecdsa-sha2-nistp256;; ecdsa-384) echo ecdsa-sha2-nistp384;; ecdsa-521) echo ecdsa-sha2-nistp521;; diff --git a/regress/knownhosts-command.sh b/regress/knownhosts-command.sh index 8472ec8121c5..2ed6fa05e06a 100644 --- a/regress/knownhosts-command.sh +++ b/regress/knownhosts-command.sh @@ -1,4 +1,4 @@ -# $OpenBSD: knownhosts-command.sh,v 1.3 2021/08/30 01:15:45 djm Exp $ +# $OpenBSD: knownhosts-command.sh,v 1.4 2025/05/06 06:05:48 djm Exp $ # Placed in the Public Domain. tid="known hosts command " @@ -40,7 +40,6 @@ ${SSH} -F $OBJ/ssh_proxy x true && fail "ssh connect succeeded with bad exit" for keytype in ${SSH_HOSTKEY_TYPES} ; do algs=$keytype - test "x$keytype" = "xssh-dss" && continue test "x$keytype" = "xssh-rsa" && algs=ssh-rsa,rsa-sha2-256,rsa-sha2-512 verbose "keytype $keytype" cat > $OBJ/knownhosts_command << _EOF diff --git a/regress/krl.sh b/regress/krl.sh index d560d61e8ce1..37d9f171a2c0 100644 --- a/regress/krl.sh +++ b/regress/krl.sh @@ -1,4 +1,4 @@ -# $OpenBSD: krl.sh,v 1.12 2023/01/16 04:11:29 djm Exp $ +# $OpenBSD: krl.sh,v 1.13 2025/05/06 06:05:48 djm Exp $ # Placed in the Public Domain. tid="key revocation lists" @@ -11,7 +11,6 @@ for t in $SSH_KEYTYPES; do case "$t" in ecdsa*) ktype2=ecdsa ;; ssh-rsa) ktype3=rsa ;; - ssh-dss) ktype4=dsa ;; sk-ssh-ed25519@openssh.com) ktype5=ed25519-sk ;; sk-ecdsa-sha2-nistp256@openssh.com) ktype6=ecdsa-sk ;; esac diff --git a/regress/limit-keytype.sh b/regress/limit-keytype.sh index 7127de007cc6..2f5b63a4831c 100644 --- a/regress/limit-keytype.sh +++ b/regress/limit-keytype.sh @@ -1,4 +1,4 @@ -# $OpenBSD: limit-keytype.sh,v 1.10 2021/02/25 03:27:34 djm Exp $ +# $OpenBSD: limit-keytype.sh,v 1.11 2025/05/06 06:05:48 djm Exp $ # Placed in the Public Domain. tid="restrict pubkey type" @@ -17,7 +17,6 @@ for t in $SSH_KEYTYPES ; do case "$t" in ssh-rsa) ktype2=rsa ;; ecdsa*) ktype3=ecdsa ;; # unused - ssh-dss) ktype4=dsa ;; sk-ssh-ed25519@openssh.com) ktype5=ed25519-sk ;; sk-ecdsa-sha2-nistp256@openssh.com) ktype6=ecdsa-sk ;; esac @@ -75,7 +74,6 @@ keytype() { case "$1" in ecdsa) printf "ecdsa-sha2-*" ;; ed25519) printf "ssh-ed25519" ;; - dsa) printf "ssh-dss" ;; rsa) printf "rsa-sha2-256,rsa-sha2-512,ssh-rsa" ;; sk-ecdsa) printf "sk-ecdsa-*" ;; sk-ssh-ed25519) printf "sk-ssh-ed25519-*" ;; @@ -123,7 +121,7 @@ if [ "$ktype1" != "$ktype2" ]; then fi ${SSH} $opts -i $OBJ/user_key2 proxy true || fatal "key2 failed" -# Allow only DSA in main config, Ed25519 for user. +# Allow only Ed25519 in main config, Ed25519 for user. verbose "match w/ matching" prepare_config "PubkeyAcceptedAlgorithms `keytype $ktype4`" \ "Match user $USER" "PubkeyAcceptedAlgorithms +`keytype $ktype1`" diff --git a/regress/misc/fuzz-harness/fixed-keys.h b/regress/misc/fuzz-harness/fixed-keys.h index c6e7c6cc1828..7dae9ac0034d 100644 --- a/regress/misc/fuzz-harness/fixed-keys.h +++ b/regress/misc/fuzz-harness/fixed-keys.h @@ -34,41 +34,6 @@ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDf56l/5UYqgY9oBlet/pLRzK6ZCd12QYGdUVfQDl6HftG0u6DSpjm2HGwFRsYZWv2ZN3ZBfAu6MHBiDmXUw/8WaD7nfXZmDH2keZL6opQttqvSGU2Cm00Rv5o1R3ej2qDdpepebv5meMBXTl5/+bE1E3Zm+4STDtxGmlMlxsEj68XeVe4JedfaSUMj3kaXYBbdYdG1qeosdle4GSONEEMpzsxSr8Y/WGYuIB33l29Tt9mNGUgSw/zjMYQjUVvQv+SY8dw62JV8d+3wK2YL2/r73gms6I8EE1JxX53KuAAY+x0p2v/W8ilCYI2Ijyzc8KIPwntmIFpibQjx+rkb+qdT" #define CERT_RSA \ "ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAg89JX6OBMYDSxER8fnU5y8xxeMCHR/hI0uVqdEhNyCpcAAAADAQABAAABAQDf56l/5UYqgY9oBlet/pLRzK6ZCd12QYGdUVfQDl6HftG0u6DSpjm2HGwFRsYZWv2ZN3ZBfAu6MHBiDmXUw/8WaD7nfXZmDH2keZL6opQttqvSGU2Cm00Rv5o1R3ej2qDdpepebv5meMBXTl5/+bE1E3Zm+4STDtxGmlMlxsEj68XeVe4JedfaSUMj3kaXYBbdYdG1qeosdle4GSONEEMpzsxSr8Y/WGYuIB33l29Tt9mNGUgSw/zjMYQjUVvQv+SY8dw62JV8d+3wK2YL2/r73gms6I8EE1JxX53KuAAY+x0p2v/W8ilCYI2Ijyzc8KIPwntmIFpibQjx+rkb+qdTAAAAAAAAA+0AAAABAAAAB3VseXNzZXMAAAAXAAAAB3VseXNzZXMAAAAIb2R5c3NldXMAAAAAAAAAAP//////////AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAADMAAAALc3NoLWVkMjU1MTkAAAAgM9BeYRUxUuZ4VHJp8oxVaA8OS/z+5EFPCZwQNq1nMwMAAABTAAAAC3NzaC1lZDI1NTE5AAAAQGCDA6PWw4x9bHQl0w7NqifHepumqD3dmyMx+hZGuPRon+TsyCjfytu7hWmV7l9XUF0fPQNFQ7FGat5e+7YUNgE= id_rsa.pub" -#define PRIV_DSA \ -"-----BEGIN OPENSSH PRIVATE KEY-----\n"\ -"b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABsgAAAAdzc2gtZH\n"\ -"NzAAAAgQCsGTfjpQ465EOkfQXJM9BOvfRQE0fqlykAls+ncz+T7hrbeScRu8xpwzsznJNm\n"\ -"xlW8o6cUDiHmBJ5OHgamUC9N7YJeU/6fnOAZifgN8mqK6k8pKHuje8ANOiYgHLl0yiASQA\n"\ -"3//qMyzZ+W/hemoLSmLAbEqlfWVeyYx+wta1Vm+QAAABUAvWyehvUvdHvQxavYgS5p0t5Q\n"\ -"d7UAAACBAIRA9Yy+f4Kzqpv/qICPO3zk42UuP7WAhSW2nCbQdLlCiSTxcjKgcvXNRckwJP\n"\ -"44JjSHOtJy/AMtJrPIbLYG6KuWTdBlEHFiG6DafvLG+qPMSL2bPjXTOhuOMbCHIZ+5WBkW\n"\ -"THeG/Nv11iI01Of9V6tXkig23K370flkRkXFi9MdAAAAgCt6YUcQkNwG7B/e5M1FZsLP9O\n"\ -"kVB3BwLAOjmWdHpyhu3HpwSJa3XLEvhXN0i6IVI2KgPo/2GtYA6rHt14L+6u1pmhh8sAvQ\n"\ -"ksp3qZB+xh/NP+hBqf0sbHX0yYbzKOvI5SCc/kKK6yagcBZOsubM/KC8TxyVgmD5c6WzYs\n"\ -"h5TEpvAAAB2PHjRbbx40W2AAAAB3NzaC1kc3MAAACBAKwZN+OlDjrkQ6R9Bckz0E699FAT\n"\ -"R+qXKQCWz6dzP5PuGtt5JxG7zGnDOzOck2bGVbyjpxQOIeYEnk4eBqZQL03tgl5T/p+c4B\n"\ -"mJ+A3yaorqTykoe6N7wA06JiAcuXTKIBJADf/+ozLNn5b+F6agtKYsBsSqV9ZV7JjH7C1r\n"\ -"VWb5AAAAFQC9bJ6G9S90e9DFq9iBLmnS3lB3tQAAAIEAhED1jL5/grOqm/+ogI87fOTjZS\n"\ -"4/tYCFJbacJtB0uUKJJPFyMqBy9c1FyTAk/jgmNIc60nL8Ay0ms8hstgboq5ZN0GUQcWIb\n"\ -"oNp+8sb6o8xIvZs+NdM6G44xsIchn7lYGRZMd4b82/XWIjTU5/1Xq1eSKDbcrfvR+WRGRc\n"\ -"WL0x0AAACAK3phRxCQ3AbsH97kzUVmws/06RUHcHAsA6OZZ0enKG7cenBIlrdcsS+Fc3SL\n"\ -"ohUjYqA+j/Ya1gDqse3Xgv7q7WmaGHywC9CSynepkH7GH80/6EGp/SxsdfTJhvMo68jlIJ\n"\ -"z+QorrJqBwFk6y5sz8oLxPHJWCYPlzpbNiyHlMSm8AAAAUUA+OGldMi76ClO/sstpdbBUE\n"\ -"lq8AAAAAAQI=\n"\ -"-----END OPENSSH PRIVATE KEY-----\n" -#define PUB_DSA \ -"ssh-dss AAAAB3NzaC1kc3MAAACBAKwZN+OlDjrkQ6R9Bckz0E699FATR+qXKQCWz6dzP5PuGtt5JxG7zGnDOzOck2bGVbyjpxQOIeYEnk4eBqZQL03tgl5T/p+c4BmJ+A3yaorqTykoe6N7wA06JiAcuXTKIBJADf/+ozLNn5b+F6agtKYsBsSqV9ZV7JjH7C1rVWb5AAAAFQC9bJ6G9S90e9DFq9iBLmnS3lB3tQAAAIEAhED1jL5/grOqm/+ogI87fOTjZS4/tYCFJbacJtB0uUKJJPFyMqBy9c1FyTAk/jgmNIc60nL8Ay0ms8hstgboq5ZN0GUQcWIboNp+8sb6o8xIvZs+NdM6G44xsIchn7lYGRZMd4b82/XWIjTU5/1Xq1eSKDbcrfvR+WRGRcWL0x0AAACAK3phRxCQ3AbsH97kzUVmws/06RUHcHAsA6OZZ0enKG7cenBIlrdcsS+Fc3SLohUjYqA+j/Ya1gDqse3Xgv7q7WmaGHywC9CSynepkH7GH80/6EGp/SxsdfTJhvMo68jlIJz+QorrJqBwFk6y5sz8oLxPHJWCYPlzpbNiyHlMSm8=" -#define CERT_DSA \ -"ssh-dss-cert-v01@openssh.com AAAAHHNzaC1kc3MtY2VydC12MDFAb3BlbnNzaC5jb20AAAAguF716Yub+vVKNlONKLsfxGYWkRe/PyjfYdGRTsFaDvAAAACBAKwZN+OlDjrkQ6R9Bckz0E699FATR+qXKQCWz6dzP5PuGtt5JxG7zGnDOzOck2bGVbyjpxQOIeYEnk4eBqZQL03tgl5T/p+c4BmJ+A3yaorqTykoe6N7wA06JiAcuXTKIBJADf/+ozLNn5b+F6agtKYsBsSqV9ZV7JjH7C1rVWb5AAAAFQC9bJ6G9S90e9DFq9iBLmnS3lB3tQAAAIEAhED1jL5/grOqm/+ogI87fOTjZS4/tYCFJbacJtB0uUKJJPFyMqBy9c1FyTAk/jgmNIc60nL8Ay0ms8hstgboq5ZN0GUQcWIboNp+8sb6o8xIvZs+NdM6G44xsIchn7lYGRZMd4b82/XWIjTU5/1Xq1eSKDbcrfvR+WRGRcWL0x0AAACAK3phRxCQ3AbsH97kzUVmws/06RUHcHAsA6OZZ0enKG7cenBIlrdcsS+Fc3SLohUjYqA+j/Ya1gDqse3Xgv7q7WmaGHywC9CSynepkH7GH80/6EGp/SxsdfTJhvMo68jlIJz+QorrJqBwFk6y5sz8oLxPHJWCYPlzpbNiyHlMSm8AAAAAAAAD6AAAAAEAAAAHdWx5c3NlcwAAABcAAAAHdWx5c3NlcwAAAAhvZHlzc2V1cwAAAAAAAAAA//////////8AAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAwAAAFMAAAALc3NoLWVkMjU1MTkAAABAjMQEZcbdUYJBjIC4GxByFDOb8tv71vDZdx7irHwaqIjx5rzpJUuOV1r8ZO4kY+Yaiun1yrWj2QYkfJrHBvD1DA== id_dsa.pub" -#define PRIV_ECDSA \ -"-----BEGIN OPENSSH PRIVATE KEY-----\n"\ -"b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS\n"\ -"1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQTDJ0VlMv+0rguNzaJ1DF2KueHaxRSQ\n"\ -"6LpIxGbulrg1a8RPbnMXwag5GcDiDllD2lDUJUuBEWyjXA0rZoZX35ELAAAAoE/Bbr5PwW\n"\ -"6+AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMMnRWUy/7SuC43N\n"\ -"onUMXYq54drFFJDoukjEZu6WuDVrxE9ucxfBqDkZwOIOWUPaUNQlS4ERbKNcDStmhlffkQ\n"\ -"sAAAAhAIhE6hCID5oOm1TDktc++KFKyScjLifcZ6Cgv5xSSyLOAAAAAAECAwQFBgc=\n"\ -"-----END OPENSSH PRIVATE KEY-----\n" #define PUB_ECDSA \ "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMMnRWUy/7SuC43NonUMXYq54drFFJDoukjEZu6WuDVrxE9ucxfBqDkZwOIOWUPaUNQlS4ERbKNcDStmhlffkQs=" #define CERT_ECDSA \ diff --git a/regress/misc/fuzz-harness/testdata/create-agent-corpus.sh b/regress/misc/fuzz-harness/testdata/create-agent-corpus.sh index 1043b9ff47d7..842b8c48d9dd 100755 --- a/regress/misc/fuzz-harness/testdata/create-agent-corpus.sh +++ b/regress/misc/fuzz-harness/testdata/create-agent-corpus.sh @@ -14,7 +14,7 @@ sleep 1 AGENT_PID=$! trap "kill $AGENT_PID" EXIT -PRIV="id_dsa id_ecdsa id_ecdsa_sk id_ed25519 id_ed25519_sk id_rsa" +PRIV="id_ecdsa id_ecdsa_sk id_ed25519 id_ed25519_sk id_rsa" # add keys ssh-add $PRIV diff --git a/regress/misc/fuzz-harness/testdata/id_dsa-cert.pub b/regress/misc/fuzz-harness/testdata/id_dsa-cert.pub deleted file mode 100644 index 3afb87fe62f7..000000000000 --- a/regress/misc/fuzz-harness/testdata/id_dsa-cert.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-dss-cert-v01@openssh.com AAAAHHNzaC1kc3MtY2VydC12MDFAb3BlbnNzaC5jb20AAAAguF716Yub+vVKNlONKLsfxGYWkRe/PyjfYdGRTsFaDvAAAACBAKwZN+OlDjrkQ6R9Bckz0E699FATR+qXKQCWz6dzP5PuGtt5JxG7zGnDOzOck2bGVbyjpxQOIeYEnk4eBqZQL03tgl5T/p+c4BmJ+A3yaorqTykoe6N7wA06JiAcuXTKIBJADf/+ozLNn5b+F6agtKYsBsSqV9ZV7JjH7C1rVWb5AAAAFQC9bJ6G9S90e9DFq9iBLmnS3lB3tQAAAIEAhED1jL5/grOqm/+ogI87fOTjZS4/tYCFJbacJtB0uUKJJPFyMqBy9c1FyTAk/jgmNIc60nL8Ay0ms8hstgboq5ZN0GUQcWIboNp+8sb6o8xIvZs+NdM6G44xsIchn7lYGRZMd4b82/XWIjTU5/1Xq1eSKDbcrfvR+WRGRcWL0x0AAACAK3phRxCQ3AbsH97kzUVmws/06RUHcHAsA6OZZ0enKG7cenBIlrdcsS+Fc3SLohUjYqA+j/Ya1gDqse3Xgv7q7WmaGHywC9CSynepkH7GH80/6EGp/SxsdfTJhvMo68jlIJz+QorrJqBwFk6y5sz8oLxPHJWCYPlzpbNiyHlMSm8AAAAAAAAD6AAAAAEAAAAHdWx5c3NlcwAAABcAAAAHdWx5c3NlcwAAAAhvZHlzc2V1cwAAAAAAAAAA//////////8AAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACAz0F5hFTFS5nhUcmnyjFVoDw5L/P7kQU8JnBA2rWczAwAAAFMAAAALc3NoLWVkMjU1MTkAAABAjMQEZcbdUYJBjIC4GxByFDOb8tv71vDZdx7irHwaqIjx5rzpJUuOV1r8ZO4kY+Yaiun1yrWj2QYkfJrHBvD1DA== id_dsa.pub diff --git a/regress/misc/ssh-verify-attestation/Makefile b/regress/misc/ssh-verify-attestation/Makefile index 2a797aecae46..06fb8aac4e98 100644 --- a/regress/misc/ssh-verify-attestation/Makefile +++ b/regress/misc/ssh-verify-attestation/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.1 2024/12/04 16:42:49 djm Exp $ +# $OpenBSD: Makefile,v 1.2 2025/05/06 06:05:48 djm Exp $ .include .include @@ -13,7 +13,7 @@ SRCS=ssh-verify-attestation.c # From usr.bin/ssh SRCS+=sshbuf-getput-basic.c sshbuf-getput-crypto.c sshbuf-misc.c sshbuf.c SRCS+=sshbuf-io.c atomicio.c sshkey.c authfile.c cipher.c log.c ssh-rsa.c -SRCS+=ssh-dss.c ssh-ecdsa.c ssh-ed25519.c mac.c umac.c umac128.c hmac.c misc.c +SRCS+=ssh-ecdsa.c ssh-ed25519.c mac.c umac.c umac128.c hmac.c misc.c SRCS+=ssherr.c uidswap.c cleanup.c xmalloc.c match.c krl.c fatal.c SRCS+=addr.c addrmatch.c bitmap.c SRCS+=ed25519.c hash.c diff --git a/regress/ssh-com-client.sh b/regress/ssh-com-client.sh index e4f80cf0aadf..97b36b564f4a 100644 --- a/regress/ssh-com-client.sh +++ b/regress/ssh-com-client.sh @@ -1,4 +1,4 @@ -# $OpenBSD: ssh-com-client.sh,v 1.7 2013/05/17 04:29:14 dtucker Exp $ +# $OpenBSD: ssh-com-client.sh,v 1.8 2025/05/06 06:05:48 djm Exp $ # Placed in the Public Domain. tid="connect with ssh.com client" @@ -28,7 +28,7 @@ VERSIONS=" # setup authorized keys SRC=`dirname ${SCRIPT}` -cp ${SRC}/dsa_ssh2.prv ${OBJ}/id.com +cp ${SRC}/rsa_ssh2.prv ${OBJ}/id.com chmod 600 ${OBJ}/id.com ${SSHKEYGEN} -i -f ${OBJ}/id.com > $OBJ/id.openssh chmod 600 ${OBJ}/id.openssh @@ -36,8 +36,8 @@ ${SSHKEYGEN} -y -f ${OBJ}/id.openssh > $OBJ/authorized_keys_$USER ${SSHKEYGEN} -e -f ${OBJ}/id.openssh > $OBJ/id.com.pub echo IdKey ${OBJ}/id.com > ${OBJ}/id.list -# we need a DSA host key -t=dsa +# we need a RSA host key +t=rsa rm -f ${OBJ}/$t ${OBJ}/$t.pub ${SSHKEYGEN} -q -N '' -t $t -f ${OBJ}/$t $SUDO cp $OBJ/$t $OBJ/host.$t @@ -47,7 +47,6 @@ echo HostKey $OBJ/host.$t >> $OBJ/sshd_config mkdir -p ${OBJ}/${USER}/hostkeys HK=${OBJ}/${USER}/hostkeys/key_${PORT}_127.0.0.1 ${SSHKEYGEN} -e -f ${OBJ}/rsa.pub > ${HK}.ssh-rsa.pub -${SSHKEYGEN} -e -f ${OBJ}/dsa.pub > ${HK}.ssh-dss.pub cat > ${OBJ}/ssh2_config << EOF *: @@ -74,7 +73,7 @@ for v in ${VERSIONS}; do continue fi verbose "ssh2 ${v}" - key=ssh-dss + key=ssh-rsa skipcat=0 case $v in 2.1.*|2.3.0) @@ -124,7 +123,6 @@ for v in ${VERSIONS}; do done rm -rf ${OBJ}/${USER} -for i in ssh2_config random_seed dsa.pub dsa host.dsa \ - id.list id.com id.com.pub id.openssh; do +for i in ssh2_config random_seed id.list id.com id.com.pub id.openssh; do rm -f ${OBJ}/$i done diff --git a/regress/ssh-com.sh b/regress/ssh-com.sh index b1a2505d1135..bb833380eb57 100644 --- a/regress/ssh-com.sh +++ b/regress/ssh-com.sh @@ -1,4 +1,4 @@ -# $OpenBSD: ssh-com.sh,v 1.10 2017/05/08 01:52:49 djm Exp $ +# $OpenBSD: ssh-com.sh,v 1.11 2025/05/06 06:05:48 djm Exp $ # Placed in the Public Domain. tid="connect to ssh.com server" @@ -41,8 +41,8 @@ cat << EOF > $OBJ/sshd2_config PubKeyAuthentication yes #AllowedAuthentications publickey AuthorizationFile authorization - HostKeyFile ${SRC}/dsa_ssh2.prv - PublicHostKeyFile ${SRC}/dsa_ssh2.pub + HostKeyFile ${SRC}/rsa_ssh2.prv + PublicHostKeyFile ${SRC}/rsa_ssh2.pub RandomSeedFile ${OBJ}/random_seed MaxConnections 0 PermitRootLogin yes @@ -55,23 +55,21 @@ EOF sed "s/HostKeyAlias.*/HostKeyAlias ssh2-localhost-with-alias/" \ < $OBJ/ssh_config > $OBJ/ssh_config_com -# we need a DSA key for -rm -f ${OBJ}/dsa ${OBJ}/dsa.pub -${SSHKEYGEN} -q -N '' -t dsa -f ${OBJ}/dsa +# we need a RSA key for +rm -f ${OBJ}/rsa ${OBJ}/rsa.pub +${SSHKEYGEN} -q -N '' -t rsa -f ${OBJ}/rsa # setup userdir, try rsa first mkdir -p ${OBJ}/${USER} cp /dev/null ${OBJ}/${USER}/authorization -for t in rsa dsa; do - ${SSHKEYGEN} -e -f ${OBJ}/$t.pub > ${OBJ}/${USER}/$t.com - echo Key $t.com >> ${OBJ}/${USER}/authorization - echo IdentityFile ${OBJ}/$t >> ${OBJ}/ssh_config_com -done +${SSHKEYGEN} -e -f ${OBJ}/rsa.pub > ${OBJ}/${USER}/rsa.com +echo Key rsa.com >> ${OBJ}/${USER}/authorization +echo IdentityFile ${OBJ}/rsa >> ${OBJ}/ssh_config_com -# convert and append DSA hostkey +# convert and append RSA hostkey ( printf 'ssh2-localhost-with-alias,127.0.0.1,::1 ' - ${SSHKEYGEN} -if ${SRC}/dsa_ssh2.pub + ${SSHKEYGEN} -if ${SRC}/rsa_ssh2.pub ) >> $OBJ/known_hosts # go for it @@ -114,6 +112,6 @@ done rm -rf ${OBJ}/${USER} for i in sshd_config_proxy ssh_config_proxy random_seed \ - sshd2_config dsa.pub dsa ssh_config_com; do + sshd2_config rsa.pub rsa ssh_config_com; do rm -f ${OBJ}/$i done diff --git a/regress/ssh2putty.sh b/regress/ssh2putty.sh index 9b08310391ca..bd291313f6c3 100755 --- a/regress/ssh2putty.sh +++ b/regress/ssh2putty.sh @@ -1,5 +1,5 @@ #!/bin/sh -# $OpenBSD: ssh2putty.sh,v 1.9 2021/07/25 12:13:03 dtucker Exp $ +# $OpenBSD: ssh2putty.sh,v 1.10 2025/05/06 06:05:48 djm Exp $ if test "x$1" = "x" -o "x$2" = "x" -o "x$3" = "x" ; then echo "Usage: ssh2putty hostname port ssh-private-key" @@ -12,7 +12,6 @@ KEYFILE=$3 OPENSSL_BIN="${OPENSSL_BIN:-openssl}" -# XXX - support DSA keys too if grep "BEGIN RSA PRIVATE KEY" $KEYFILE >/dev/null 2>&1 ; then : else diff --git a/regress/sshcfgparse.sh b/regress/sshcfgparse.sh index 504853d32db5..29fa1d839be2 100644 --- a/regress/sshcfgparse.sh +++ b/regress/sshcfgparse.sh @@ -1,15 +1,8 @@ -# $OpenBSD: sshcfgparse.sh,v 1.9 2021/06/08 07:05:27 dtucker Exp $ +# $OpenBSD: sshcfgparse.sh,v 1.10 2025/05/06 06:05:48 djm Exp $ # Placed in the Public Domain. tid="ssh config parse" -dsa=0 -for t in $SSH_KEYTYPES; do - case "$t" in - ssh-dss) dsa=1 ;; - esac -done - expect_result_present() { _str="$1" ; shift for _expect in "$@" ; do @@ -66,33 +59,23 @@ verbose "pubkeyacceptedalgorithms" # Default set f=`${SSH} -GF none host | awk '/^pubkeyacceptedalgorithms /{print $2}'` expect_result_present "$f" "ssh-ed25519" "ssh-ed25519-cert-v01.*" -expect_result_absent "$f" "ssh-dss" # Explicit override f=`${SSH} -GF none -opubkeyacceptedalgorithms=ssh-ed25519 host | \ awk '/^pubkeyacceptedalgorithms /{print $2}'` expect_result_present "$f" "ssh-ed25519" -expect_result_absent "$f" "ssh-ed25519-cert-v01.*" "ssh-dss" +expect_result_absent "$f" "ssh-ed25519-cert-v01.*" # Removal from default set f=`${SSH} -GF none -opubkeyacceptedalgorithms=-ssh-ed25519-cert* host | \ awk '/^pubkeyacceptedalgorithms /{print $2}'` expect_result_present "$f" "ssh-ed25519" -expect_result_absent "$f" "ssh-ed25519-cert-v01.*" "ssh-dss" +expect_result_absent "$f" "ssh-ed25519-cert-v01.*" f=`${SSH} -GF none -opubkeyacceptedalgorithms=-ssh-ed25519 host | \ awk '/^pubkeyacceptedalgorithms /{print $2}'` expect_result_present "$f" "ssh-ed25519-cert-v01.*" -expect_result_absent "$f" "ssh-ed25519" "ssh-dss" +expect_result_absent "$f" "ssh-ed25519" # Append to default set. # This is not tested when built !WITH_OPENSSL -if [ "$dsa" = "1" ]; then - f=`${SSH} -GF none -opubkeyacceptedalgorithms=+ssh-dss-cert* host | \ - awk '/^pubkeyacceptedalgorithms /{print $2}'` - expect_result_present "$f" "ssh-ed25519" "ssh-dss-cert-v01.*" - expect_result_absent "$f" "ssh-dss" - f=`${SSH} -GF none -opubkeyacceptedalgorithms=+ssh-dss host | \ - awk '/^pubkeyacceptedalgorithms /{print $2}'` - expect_result_present "$f" "ssh-ed25519" "ssh-ed25519-cert-v01.*" "ssh-dss" - expect_result_absent "$f" "ssh-dss-cert-v01.*" -fi +# XXX need a test for this verbose "agentforwarding" f=`${SSH} -GF none host | awk '/^forwardagent /{print$2}'` diff --git a/regress/unittests/Makefile.inc b/regress/unittests/Makefile.inc index ad7fdad84a53..5fcf7a950a39 100644 --- a/regress/unittests/Makefile.inc +++ b/regress/unittests/Makefile.inc @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile.inc,v 1.17 2025/04/15 04:00:42 djm Exp $ +# $OpenBSD: Makefile.inc,v 1.18 2025/05/06 06:05:48 djm Exp $ .include .include @@ -18,10 +18,6 @@ TEST_ENV?= MALLOC_OPTIONS=${MALLOC_OPTIONS} OPENSSL?= yes DSAKEY?= yes -.if (${DSAKEY:L} == "yes") -CFLAGS+= -DWITH_DSA -.endif - .if (${OPENSSL:L} == "yes") CFLAGS+= -DWITH_OPENSSL .endif diff --git a/regress/unittests/authopt/Makefile b/regress/unittests/authopt/Makefile index 8bed7a915dfa..d5ea2c796be1 100644 --- a/regress/unittests/authopt/Makefile +++ b/regress/unittests/authopt/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.8 2025/04/15 04:00:42 djm Exp $ +# $OpenBSD: Makefile,v 1.9 2025/05/06 06:05:48 djm Exp $ PROG=test_authopt SRCS=tests.c @@ -8,7 +8,7 @@ SRCS+=auth-options.c # From usr.bin/ssh SRCS+=sshbuf-getput-basic.c sshbuf-getput-crypto.c sshbuf-misc.c sshbuf.c SRCS+=sshbuf-io.c atomicio.c sshkey.c authfile.c cipher.c log.c ssh-rsa.c -SRCS+=ssh-dss.c ssh-ecdsa.c ssh-ed25519.c mac.c umac.c umac128.c hmac.c misc.c +SRCS+=ssh-ecdsa.c ssh-ed25519.c mac.c umac.c umac128.c hmac.c misc.c SRCS+=ssherr.c uidswap.c cleanup.c xmalloc.c match.c krl.c fatal.c SRCS+=addr.c addrmatch.c bitmap.c SRCS+=ed25519.c hash.c diff --git a/regress/unittests/hostkeys/Makefile b/regress/unittests/hostkeys/Makefile index 79a9d5745419..142ffa632aad 100644 --- a/regress/unittests/hostkeys/Makefile +++ b/regress/unittests/hostkeys/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.11 2025/04/15 04:00:42 djm Exp $ +# $OpenBSD: Makefile,v 1.12 2025/05/06 06:05:48 djm Exp $ PROG=test_hostkeys SRCS=tests.c test_iterate.c @@ -6,7 +6,7 @@ SRCS=tests.c test_iterate.c # From usr.bin/ssh SRCS+=sshbuf-getput-basic.c sshbuf-getput-crypto.c sshbuf-misc.c sshbuf.c SRCS+=sshbuf-io.c atomicio.c sshkey.c authfile.c cipher.c log.c ssh-rsa.c -SRCS+=ssh-dss.c ssh-ecdsa.c ssh-ed25519.c mac.c umac.c umac128.c hmac.c misc.c +SRCS+=ssh-ecdsa.c ssh-ed25519.c mac.c umac.c umac128.c hmac.c misc.c SRCS+=ssherr.c uidswap.c cleanup.c xmalloc.c match.c krl.c fatal.c SRCS+=addr.c addrmatch.c bitmap.c hostfile.c SRCS+=ed25519.c hash.c diff --git a/regress/unittests/hostkeys/mktestdata.sh b/regress/unittests/hostkeys/mktestdata.sh index 5a46de990dca..5fec5829853a 100644 --- a/regress/unittests/hostkeys/mktestdata.sh +++ b/regress/unittests/hostkeys/mktestdata.sh @@ -1,11 +1,11 @@ #!/bin/sh -# $OpenBSD: mktestdata.sh,v 1.2 2017/04/30 23:33:48 djm Exp $ +# $OpenBSD: mktestdata.sh,v 1.3 2025/05/06 06:05:48 djm Exp $ set -ex cd testdata -rm -f rsa* dsa* ecdsa* ed25519* +rm -f rsa* ecdsa* ed25519* rm -f known_hosts* gen_all() { @@ -14,11 +14,10 @@ gen_all() { test "x$_n" = "x1" && _ecdsa_bits=384 test "x$_n" = "x2" && _ecdsa_bits=521 ssh-keygen -qt rsa -b 1024 -C "RSA #$_n" -N "" -f rsa_$_n - ssh-keygen -qt dsa -b 1024 -C "DSA #$_n" -N "" -f dsa_$_n ssh-keygen -qt ecdsa -b $_ecdsa_bits -C "ECDSA #$_n" -N "" -f ecdsa_$_n ssh-keygen -qt ed25519 -C "ED25519 #$_n" -N "" -f ed25519_$_n # Don't need private keys - rm -f rsa_$_n dsa_$_n ecdsa_$_n ed25519_$_n + rm -f rsa_$_n ecdsa_$_n ed25519_$_n } hentries() { @@ -65,18 +64,18 @@ rm -f known_hosts_hash_frag.old echo "# Revoked and CA keys" printf "@revoked sisyphus.example.com " ; cat ed25519_4.pub printf "@cert-authority prometheus.example.com " ; cat ecdsa_4.pub - printf "@cert-authority *.example.com " ; cat dsa_4.pub + printf "@cert-authority *.example.com " ; cat rsa_4.pub printf "\n" echo "# Some invalid lines" # Invalid marker - printf "@what sisyphus.example.com " ; cat dsa_1.pub + printf "@what sisyphus.example.com " ; cat rsa_1.pub # Key missing echo "sisyphus.example.com " # Key blob missing echo "prometheus.example.com ssh-ed25519 " # Key blob truncated - echo "sisyphus.example.com ssh-dsa AAAATgAAAAdz" + echo "sisyphus.example.com ssh-rsa AAAATgAAAAdz" # Invalid type echo "sisyphus.example.com ssh-XXX AAAATgAAAAdzc2gtWFhYAAAAP0ZVQ0tPRkZGVUNLT0ZGRlVDS09GRkZVQ0tPRkZGVUNLT0ZGRlVDS09GRkZVQ0tPRkZGVUNLT0ZGRlVDS09GRg==" # Type mismatch with blob diff --git a/regress/unittests/hostkeys/test_iterate.c b/regress/unittests/hostkeys/test_iterate.c index 7efb8e1b9cc6..0139376f4a78 100644 --- a/regress/unittests/hostkeys/test_iterate.c +++ b/regress/unittests/hostkeys/test_iterate.c @@ -1,4 +1,4 @@ -/* $OpenBSD: test_iterate.c,v 1.9 2024/01/11 01:45:58 djm Exp $ */ +/* $OpenBSD: test_iterate.c,v 1.10 2025/05/06 06:05:48 djm Exp $ */ /* * Regress test for hostfile.h hostkeys_foreach() * @@ -94,15 +94,8 @@ check(struct hostkey_foreach_line *l, void *_ctx) expected->no_parse_keytype == KEY_ECDSA) skip = 1; #endif /* OPENSSL_HAS_ECC */ -#ifndef WITH_DSA - if (expected->l.keytype == KEY_DSA || - expected->no_parse_keytype == KEY_DSA) - skip = 1; -#endif #ifndef WITH_OPENSSL - if (expected->l.keytype == KEY_DSA || - expected->no_parse_keytype == KEY_DSA || - expected->l.keytype == KEY_RSA || + if (expected->l.keytype == KEY_RSA || expected->no_parse_keytype == KEY_RSA || expected->l.keytype == KEY_ECDSA || expected->no_parse_keytype == KEY_ECDSA) @@ -160,14 +153,9 @@ prepare_expected(struct expected *expected, size_t n) if (expected[i].l.keytype == KEY_ECDSA) continue; #endif /* OPENSSL_HAS_ECC */ -#ifndef WITH_DSA - if (expected[i].l.keytype == KEY_DSA) - continue; -#endif #ifndef WITH_OPENSSL switch (expected[i].l.keytype) { case KEY_RSA: - case KEY_DSA: case KEY_ECDSA: continue; } @@ -204,23 +192,9 @@ struct expected expected_full[] = { NULL, /* comment */ 0, /* note */ } }, - { "dsa_1.pub" , -1, -1, 0, HKF_MATCH_HOST, 0, 0, -1, { - NULL, - 2, - HKF_STATUS_OK, - 0, - NULL, - MRK_NONE, - "sisyphus.example.com", - NULL, - KEY_DSA, - NULL, /* filled at runtime */ - "DSA #1", - 0, - } }, { "ecdsa_1.pub" , -1, -1, 0, HKF_MATCH_HOST, 0, 0, -1, { NULL, - 3, + 2, HKF_STATUS_OK, 0, NULL, @@ -234,7 +208,7 @@ struct expected expected_full[] = { } }, { "ed25519_1.pub" , -1, -1, 0, HKF_MATCH_HOST, 0, 0, -1, { NULL, - 4, + 3, HKF_STATUS_OK, 0, NULL, @@ -248,7 +222,7 @@ struct expected expected_full[] = { } }, { "rsa_1.pub" , -1, -1, 0, HKF_MATCH_HOST, 0, 0, -1, { NULL, - 5, + 4, HKF_STATUS_OK, 0, NULL, @@ -262,7 +236,7 @@ struct expected expected_full[] = { } }, { NULL, -1, -1, 0, 0, 0, 0, -1, { NULL, - 6, + 5, HKF_STATUS_COMMENT, 0, "", @@ -276,7 +250,7 @@ struct expected expected_full[] = { } }, { NULL, -1, -1, 0, 0, 0, 0, -1, { NULL, - 7, + 6, HKF_STATUS_COMMENT, 0, "# Plain host keys, hostnames + addresses", @@ -288,23 +262,9 @@ struct expected expected_full[] = { NULL, 0, } }, - { "dsa_2.pub" , -1, -1, HKF_MATCH_HOST, 0, HKF_MATCH_IP, HKF_MATCH_IP, -1, { - NULL, - 8, - HKF_STATUS_OK, - 0, - NULL, - MRK_NONE, - "prometheus.example.com,192.0.2.1,2001:db8::1", - NULL, - KEY_DSA, - NULL, /* filled at runtime */ - "DSA #2", - 0, - } }, { "ecdsa_2.pub" , -1, -1, HKF_MATCH_HOST, 0, HKF_MATCH_IP, HKF_MATCH_IP, -1, { NULL, - 9, + 7, HKF_STATUS_OK, 0, NULL, @@ -318,7 +278,7 @@ struct expected expected_full[] = { } }, { "ed25519_2.pub" , -1, -1, HKF_MATCH_HOST, 0, HKF_MATCH_IP, HKF_MATCH_IP, -1, { NULL, - 10, + 8, HKF_STATUS_OK, 0, NULL, @@ -332,7 +292,7 @@ struct expected expected_full[] = { } }, { "rsa_2.pub" , -1, -1, HKF_MATCH_HOST, 0, HKF_MATCH_IP, HKF_MATCH_IP, -1, { NULL, - 11, + 9, HKF_STATUS_OK, 0, NULL, @@ -346,7 +306,7 @@ struct expected expected_full[] = { } }, { NULL, -1, -1, 0, 0, 0, 0, -1, { NULL, - 12, + 10, HKF_STATUS_COMMENT, 0, "", @@ -360,7 +320,7 @@ struct expected expected_full[] = { } }, { NULL, -1, -1, 0, 0, 0, 0, -1, { NULL, - 13, + 11, HKF_STATUS_COMMENT, 0, "# Some hosts with wildcard names / IPs", @@ -372,23 +332,9 @@ struct expected expected_full[] = { NULL, 0, } }, - { "dsa_3.pub" , -1, -1, HKF_MATCH_HOST, HKF_MATCH_HOST, HKF_MATCH_IP, HKF_MATCH_IP, -1, { - NULL, - 14, - HKF_STATUS_OK, - 0, - NULL, - MRK_NONE, - "*.example.com,192.0.2.*,2001:*", - NULL, - KEY_DSA, - NULL, /* filled at runtime */ - "DSA #3", - 0, - } }, { "ecdsa_3.pub" , -1, -1, HKF_MATCH_HOST, HKF_MATCH_HOST, HKF_MATCH_IP, HKF_MATCH_IP, -1, { NULL, - 15, + 12, HKF_STATUS_OK, 0, NULL, @@ -402,7 +348,7 @@ struct expected expected_full[] = { } }, { "ed25519_3.pub" , -1, -1, HKF_MATCH_HOST, HKF_MATCH_HOST, HKF_MATCH_IP, HKF_MATCH_IP, -1, { NULL, - 16, + 13, HKF_STATUS_OK, 0, NULL, @@ -416,7 +362,7 @@ struct expected expected_full[] = { } }, { "rsa_3.pub" , -1, -1, HKF_MATCH_HOST, HKF_MATCH_HOST, HKF_MATCH_IP, HKF_MATCH_IP, -1, { NULL, - 17, + 14, HKF_STATUS_OK, 0, NULL, @@ -430,7 +376,7 @@ struct expected expected_full[] = { } }, { NULL, -1, -1, 0, 0, 0, 0, -1, { NULL, - 18, + 15, HKF_STATUS_COMMENT, 0, "", @@ -444,7 +390,7 @@ struct expected expected_full[] = { } }, { NULL, -1, -1, 0, 0, 0, 0, -1, { NULL, - 19, + 16, HKF_STATUS_COMMENT, 0, "# Hashed hostname and address entries", @@ -456,23 +402,9 @@ struct expected expected_full[] = { NULL, 0, } }, - { "dsa_5.pub" , -1, -1, 0, HKF_MATCH_HOST|HKF_MATCH_HOST_HASHED, 0, 0, -1, { - NULL, - 20, - HKF_STATUS_OK, - 0, - NULL, - MRK_NONE, - NULL, - NULL, - KEY_DSA, - NULL, /* filled at runtime */ - "DSA #5", - 0, - } }, { "ecdsa_5.pub" , -1, -1, 0, HKF_MATCH_HOST|HKF_MATCH_HOST_HASHED, 0, 0, -1, { NULL, - 21, + 17, HKF_STATUS_OK, 0, NULL, @@ -486,7 +418,7 @@ struct expected expected_full[] = { } }, { "ed25519_5.pub" , -1, -1, 0, HKF_MATCH_HOST|HKF_MATCH_HOST_HASHED, 0, 0, -1, { NULL, - 22, + 18, HKF_STATUS_OK, 0, NULL, @@ -500,7 +432,7 @@ struct expected expected_full[] = { } }, { "rsa_5.pub" , -1, -1, 0, HKF_MATCH_HOST|HKF_MATCH_HOST_HASHED, 0, 0, -1, { NULL, - 23, + 19, HKF_STATUS_OK, 0, NULL, @@ -514,7 +446,7 @@ struct expected expected_full[] = { } }, { NULL, -1, -1, 0, 0, 0, 0, -1, { NULL, - 24, + 20, HKF_STATUS_COMMENT, 0, "", @@ -531,51 +463,9 @@ struct expected expected_full[] = { * hostname and addresses in the pre-hashed known_hosts are split * to separate lines. */ - { "dsa_6.pub" , -1, -1, HKF_MATCH_HOST|HKF_MATCH_HOST_HASHED, 0, 0, 0, -1, { - NULL, - 25, - HKF_STATUS_OK, - 0, - NULL, - MRK_NONE, - NULL, - NULL, - KEY_DSA, - NULL, /* filled at runtime */ - "DSA #6", - 0, - } }, - { "dsa_6.pub" , -1, -1, 0, 0, HKF_MATCH_IP|HKF_MATCH_IP_HASHED, 0, -1, { - NULL, - 26, - HKF_STATUS_OK, - 0, - NULL, - MRK_NONE, - NULL, - NULL, - KEY_DSA, - NULL, /* filled at runtime */ - "DSA #6", - 0, - } }, - { "dsa_6.pub" , -1, -1, 0, 0, 0, HKF_MATCH_IP|HKF_MATCH_IP_HASHED, -1, { - NULL, - 27, - HKF_STATUS_OK, - 0, - NULL, - MRK_NONE, - NULL, - NULL, - KEY_DSA, - NULL, /* filled at runtime */ - "DSA #6", - 0, - } }, { "ecdsa_6.pub" , -1, -1, HKF_MATCH_HOST|HKF_MATCH_HOST_HASHED, 0, 0, 0, -1, { NULL, - 28, + 21, HKF_STATUS_OK, 0, NULL, @@ -589,7 +479,7 @@ struct expected expected_full[] = { } }, { "ecdsa_6.pub" , -1, -1, 0, 0, HKF_MATCH_IP|HKF_MATCH_IP_HASHED, 0, -1, { NULL, - 29, + 22, HKF_STATUS_OK, 0, NULL, @@ -603,7 +493,7 @@ struct expected expected_full[] = { } }, { "ecdsa_6.pub" , -1, -1, 0, 0, 0, HKF_MATCH_IP|HKF_MATCH_IP_HASHED, -1, { NULL, - 30, + 23, HKF_STATUS_OK, 0, NULL, @@ -617,7 +507,7 @@ struct expected expected_full[] = { } }, { "ed25519_6.pub" , -1, -1, HKF_MATCH_HOST|HKF_MATCH_HOST_HASHED, 0, 0, 0, -1, { NULL, - 31, + 24, HKF_STATUS_OK, 0, NULL, @@ -631,7 +521,7 @@ struct expected expected_full[] = { } }, { "ed25519_6.pub" , -1, -1, 0, 0, HKF_MATCH_IP|HKF_MATCH_IP_HASHED, 0, -1, { NULL, - 32, + 25, HKF_STATUS_OK, 0, NULL, @@ -645,7 +535,7 @@ struct expected expected_full[] = { } }, { "ed25519_6.pub" , -1, -1, 0, 0, 0, HKF_MATCH_IP|HKF_MATCH_IP_HASHED, -1, { NULL, - 33, + 26, HKF_STATUS_OK, 0, NULL, @@ -659,7 +549,7 @@ struct expected expected_full[] = { } }, { "rsa_6.pub" , -1, -1, HKF_MATCH_HOST|HKF_MATCH_HOST_HASHED, 0, 0, 0, -1, { NULL, - 34, + 27, HKF_STATUS_OK, 0, NULL, @@ -673,7 +563,7 @@ struct expected expected_full[] = { } }, { "rsa_6.pub" , -1, -1, 0, 0, HKF_MATCH_IP|HKF_MATCH_IP_HASHED, 0, -1, { NULL, - 35, + 28, HKF_STATUS_OK, 0, NULL, @@ -687,7 +577,7 @@ struct expected expected_full[] = { } }, { "rsa_6.pub" , -1, -1, 0, 0, 0, HKF_MATCH_IP|HKF_MATCH_IP_HASHED, -1, { NULL, - 36, + 29, HKF_STATUS_OK, 0, NULL, @@ -701,7 +591,7 @@ struct expected expected_full[] = { } }, { NULL, -1, -1, 0, 0, 0, 0, -1, { NULL, - 37, + 30, HKF_STATUS_COMMENT, 0, "", @@ -715,7 +605,7 @@ struct expected expected_full[] = { } }, { NULL, -1, -1, 0, 0, 0, 0, -1, { NULL, - 38, + 31, HKF_STATUS_COMMENT, 0, "", @@ -729,7 +619,7 @@ struct expected expected_full[] = { } }, { NULL, -1, -1, 0, 0, 0, 0, -1, { NULL, - 39, + 32, HKF_STATUS_COMMENT, 0, "# Revoked and CA keys", @@ -743,7 +633,7 @@ struct expected expected_full[] = { } }, { "ed25519_4.pub" , -1, -1, 0, HKF_MATCH_HOST, 0, 0, -1, { NULL, - 40, + 33, HKF_STATUS_OK, 0, NULL, @@ -757,7 +647,7 @@ struct expected expected_full[] = { } }, { "ecdsa_4.pub" , -1, -1, HKF_MATCH_HOST, 0, 0, 0, -1, { NULL, - 41, + 34, HKF_STATUS_OK, 0, NULL, @@ -769,23 +659,9 @@ struct expected expected_full[] = { "ECDSA #4", 0, } }, - { "dsa_4.pub" , -1, -1, HKF_MATCH_HOST, HKF_MATCH_HOST, 0, 0, -1, { - NULL, - 42, - HKF_STATUS_OK, - 0, - NULL, - MRK_CA, - "*.example.com", - NULL, - KEY_DSA, - NULL, /* filled at runtime */ - "DSA #4", - 0, - } }, { NULL, -1, -1, 0, 0, 0, 0, -1, { NULL, - 43, + 35, HKF_STATUS_COMMENT, 0, "", @@ -799,7 +675,7 @@ struct expected expected_full[] = { } }, { NULL, -1, -1, 0, 0, 0, 0, -1, { NULL, - 44, + 36, HKF_STATUS_COMMENT, 0, "# Some invalid lines", @@ -813,7 +689,7 @@ struct expected expected_full[] = { } }, { NULL, -1, -1, 0, 0, 0, 0, -1, { NULL, - 45, + 37, HKF_STATUS_INVALID, 0, NULL, @@ -827,7 +703,7 @@ struct expected expected_full[] = { } }, { NULL, -1, -1, 0, HKF_MATCH_HOST, 0, 0, -1, { NULL, - 46, + 38, HKF_STATUS_INVALID, 0, NULL, @@ -841,7 +717,7 @@ struct expected expected_full[] = { } }, { NULL, -1, -1, HKF_MATCH_HOST, 0, 0, 0, -1, { NULL, - 47, + 39, HKF_STATUS_INVALID, 0, NULL, @@ -853,9 +729,9 @@ struct expected expected_full[] = { NULL, 0, } }, - { NULL, -1, -1, 0, HKF_MATCH_HOST, 0, 0, -1, { + { NULL, HKF_STATUS_OK, KEY_ED25519, 0, HKF_MATCH_HOST, 0, 0, -1, { NULL, - 48, + 40, HKF_STATUS_INVALID, /* Would be ok if key not parsed */ 0, NULL, @@ -869,7 +745,7 @@ struct expected expected_full[] = { } }, { NULL, -1, -1, 0, HKF_MATCH_HOST, 0, 0, -1, { NULL, - 49, + 41, HKF_STATUS_INVALID, 0, NULL, @@ -883,7 +759,7 @@ struct expected expected_full[] = { } }, { NULL, HKF_STATUS_OK, KEY_RSA, HKF_MATCH_HOST, 0, 0, 0, -1, { NULL, - 50, + 42, HKF_STATUS_INVALID, /* Would be ok if key not parsed */ 0, NULL, diff --git a/regress/unittests/hostkeys/testdata/dsa_1.pub b/regress/unittests/hostkeys/testdata/dsa_1.pub deleted file mode 100644 index 56e1e3714625..000000000000 --- a/regress/unittests/hostkeys/testdata/dsa_1.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-dss AAAAB3NzaC1kc3MAAACBAOqffHxEW4c+Z9q/r3l4sYK8F7qrBsU8XF9upGsW62T9InROFFq9IO0x3pQ6mDA0Wtw0sqcDmkPCHPyP4Ok/fU3/drLaZusHoVYu8pBBrWsIDrKgkeX9TEodBsSrYdl4Sqtqq9EZv9+DttV6LStZrgYyUTOKwOF95wGantpLynX5AAAAFQDdt+zjRNlETDsgmxcSYFgREirJrQAAAIBQlrPaiPhR24FhnMLcHH4016vL7AqDDID6Qw7PhbXGa4/XlxWMIigjBKrIPKvnZ6p712LSnCKtcbfdx0MtmJlNa01CYqPaRhgRaf+uGdvTkTUcdaq8R5lLJL+JMNwUhcC8ijm3NqEjXjffuebGe1EzIeiITbA7Nndcd+GytwRDegAAAIEAkRYPjSVcUxfUHhHdpP6V8CuY1+CYSs9EPJ7iiWTDuXWVIBTU32oJLAnrmAcOwtIzEfPvm+rff5FI/Yhon2pB3VTXhPPEBjYzE5qANanAT4e6tzAVc5f3DUhHaDknwRYfDz86GFvuLtDjeE/UZ9t6OofYoEsCBpYozLAprBvNIQY= DSA #1 diff --git a/regress/unittests/hostkeys/testdata/dsa_2.pub b/regress/unittests/hostkeys/testdata/dsa_2.pub deleted file mode 100644 index 394e0bf00255..000000000000 --- a/regress/unittests/hostkeys/testdata/dsa_2.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-dss AAAAB3NzaC1kc3MAAACBAI38Hy/61/O5Bp6yUG8J5XQCeNjRS0xvjlCdzKLyXCueMa+L+X2L/u9PWUsy5SVbTjGgpB8sF6UkCNsV+va7S8zCCHas2MZ7GPlxP6GZBkRPTIFR0N/Pu7wfBzDQz0t0iL4VmxBfTBQv/SxkGWZg+yHihIQP9fwdSAwD/7aVh6ItAAAAFQDSyihIUlINlswM0PJ8wXSti3yIMwAAAIB+oqzaB6ozqs8YxpN5oQOBa/9HEBQEsp8RSIlQmVubXRNgktp42n+Ii1waU9UUk8DX5ahhIeR6B7ojWkqmDAji4SKpoHf4kmr6HvYo85ZSTSx0W4YK/gJHSpDJwhlT52tAfb1JCbWSObjl09B4STv7KedCHcR5oXQvvrV+XoKOSAAAAIAue/EXrs2INw1RfaKNHC0oqOMxmRitv0BFMuNVPo1VDj39CE5kA7AHjwvS1TNeaHtK5Hhgeb6vsmLmNPTOc8xCob0ilyQbt9O0GbONeF2Ge7D2UJyULA/hxql+tCYFIC6yUrmo35fF9XiNisXLoaflk9fjp7ROWWVwnki/jstaQw== DSA #2 diff --git a/regress/unittests/hostkeys/testdata/dsa_3.pub b/regress/unittests/hostkeys/testdata/dsa_3.pub deleted file mode 100644 index e506ea42253a..000000000000 --- a/regress/unittests/hostkeys/testdata/dsa_3.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-dss AAAAB3NzaC1kc3MAAACBAI6lz2Ip9bzE7TGuDD4SjO9S4Ac90gq0h6ai1O06eI8t/Ot2uJ5Jk2QyVr2jvIZHDl/5bwBx7+5oyjlwRoUrAPPD814wf5tU2tSnmdu1Wbf0cBswif5q0r4tevzmopp/AtgH11QHo3u0/pfyJd10qBDLV2FaYSKMmZvyPfZJ0s9pAAAAFQD5Eqjl6Rx2qVePodD9OwAPT0bU6wAAAIAfnDm6csZF0sFaJR3NIJvaYgSGr8s7cqlsk2gLltB/1wOOO2yX+NeEC+B0H93hlMfaUsPa08bwgmYxnavSMqEBpmtPceefJiEd68zwYqXd38f88wyWZ9Z5iwaI/6OVZPHzCbDxOa4ewVTevRNYUKP1xUTZNT8/gSMfZLYPk4T2AQAAAIAUKroozRMyV+3V/rxt0gFnNxRXBKk+9cl3vgsQ7ktkI9cYg7V1T2K0XF21AVMK9gODszy6PBJjV6ruXBV6TRiqIbQauivp3bHHKYsG6wiJNqwdbVwIjfvv8nn1qFoZQLXG3sdONr9NwN8KzrX89OV0BlR2dVM5qqp+YxOXymP9yg== DSA #3 diff --git a/regress/unittests/hostkeys/testdata/dsa_4.pub b/regress/unittests/hostkeys/testdata/dsa_4.pub deleted file mode 100644 index 8552c3819287..000000000000 --- a/regress/unittests/hostkeys/testdata/dsa_4.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-dss AAAAB3NzaC1kc3MAAACBAKvjnFHm0VvMr5h2Zu3nURsxQKGoxm+DCzYDxRYcilK07Cm5c4XTrFbA2X86+9sGs++W7QRMcTJUYIg0a+UtIMtAjwORd6ZPXM2K5dBW+gh1oHyvKi767tWX7I2c+1ZPJDY95mUUfZQUEfdy9eGDSBmw/pSsveQ1ur6XNUh/MtP/AAAAFQDHnXk/9jBJAdce1pHtLWnbdPSGdQAAAIEAm2OLy8tZBfiEO3c3X1yyB/GTcDwrQCqRMDkhnsmrliec3dWkOfNTzu+MrdvF8ymTWLEqPpbMheYtvNyZ3TF0HO5W7aVBpdGZbOdOAIfB+6skqGbI8A5Up1d7dak/bSsqL2r5NjwbDOdq+1hBzzvbl/qjh+sQarV2zHrpKoQaV28AAACANtkBVedBbqIAdphCrN/LbUi9WlyuF9UZz+tlpVLYrj8GJVwnplV2tvOmUw6yP5/pzCimTsao8dpL5PWxm7fKxLWVxA+lEsA4WeC885CiZn8xhdaJOCN+NyJ2bqkz+4VPI7oDGBm0aFwUqJn+M1PiSgvI50XdF2dBsFRTRNY0wzA= DSA #4 diff --git a/regress/unittests/hostkeys/testdata/dsa_5.pub b/regress/unittests/hostkeys/testdata/dsa_5.pub deleted file mode 100644 index 149e1efd166b..000000000000 --- a/regress/unittests/hostkeys/testdata/dsa_5.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-dss AAAAB3NzaC1kc3MAAACBALrFy7w5ihlaOG+qR+6fj+vm5EQaO3qwxgACLcgH+VfShuOG4mkx8qFJmf+OZ3fh5iKngjNZfKtfcqI7zHWdk6378TQfQC52/kbZukjNXOLCpyNkogahcjA00onIoTK1RUDuMW28edAHwPFbpttXDTaqis+8JPMY8hZwsZGENCzTAAAAFQD6+It5vozwGgaN9ROYPMlByhi6jwAAAIBz2mcAC694vNzz9b6614gkX9d9E99PzJYfU1MPkXDziKg7MrjBw7Opd5y1jL09S3iL6lSTlHkKwVKvQ3pOwWRwXXRrKVus4I0STveoApm526jmp6mY0YEtqR98vMJ0v97h1ydt8FikKlihefCsnXVicb8887PXs2Y8C6GuFT3tfQAAAIBbmHtV5tPcrMRDkULhaQ/Whap2VKvT2DUhIHA7lx6oy/KpkltOpxDZOIGUHKqffGbiR7Jh01/y090AY5L2eCf0S2Ytx93+eADwVVpJbFJo6zSwfeey2Gm6L2oA+rCz9zTdmtZoekpD3/RAOQjnJIAPwbs7mXwabZTw4xRtiYIRrw== DSA #5 diff --git a/regress/unittests/hostkeys/testdata/dsa_6.pub b/regress/unittests/hostkeys/testdata/dsa_6.pub deleted file mode 100644 index edbb97643d26..000000000000 --- a/regress/unittests/hostkeys/testdata/dsa_6.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-dss AAAAB3NzaC1kc3MAAACBAIutigAse65TCW6hHDOEGXenE9L4L0talHbs65hj3UUNtWflKdQeXLofqXgW8AwaDKmnuRPrxRoxVNXj84n45wtBEdt4ztmdAZteAbXSnHqpcxME3jDxh3EtxzGPXLs+RUmKPVguraSgo7W2oN7KFx6VM+AcAtxANSTlvDid3s47AAAAFQCd9Q3kkHSLWe77sW0eRaayI45ovwAAAIAw6srGF6xvFasI44Y3r9JJ2K+3ezozl3ldL3p2+p2HG3iWafC4SdV8pB6ZIxKlYAywiiFb3LzH/JweGFq1jtoFDRM3MlYORBevydU4zPz7b5QLDVB0sY4evYtWmg2BFJvoWRfhLnlZVW7h5N8v4fNIwdVmVsw4Ljes7iF2HRGhHgAAAIBDFT3fww2Oby1xUA6G9pDAcVikrQFqp1sJRylNTUyeyQ37SNAGzYxwHJFgQr8gZLdRQ1UW+idYpqVbVNcYFMOiw/zSqK2OfVwPZ9U+TTKdc992ChSup6vJEKM/ZVIyDWDbJr7igQ4ahy7jo9mFvm8ljN926EnspQzCvs0Dxk6tHA== DSA #6 diff --git a/regress/unittests/hostkeys/testdata/known_hosts b/regress/unittests/hostkeys/testdata/known_hosts index 4446f45dffe8..5298e3eebb3d 100644 --- a/regress/unittests/hostkeys/testdata/known_hosts +++ b/regress/unittests/hostkeys/testdata/known_hosts @@ -1,30 +1,23 @@ # Plain host keys, plain host names -sisyphus.example.com ssh-dss AAAAB3NzaC1kc3MAAACBAOqffHxEW4c+Z9q/r3l4sYK8F7qrBsU8XF9upGsW62T9InROFFq9IO0x3pQ6mDA0Wtw0sqcDmkPCHPyP4Ok/fU3/drLaZusHoVYu8pBBrWsIDrKgkeX9TEodBsSrYdl4Sqtqq9EZv9+DttV6LStZrgYyUTOKwOF95wGantpLynX5AAAAFQDdt+zjRNlETDsgmxcSYFgREirJrQAAAIBQlrPaiPhR24FhnMLcHH4016vL7AqDDID6Qw7PhbXGa4/XlxWMIigjBKrIPKvnZ6p712LSnCKtcbfdx0MtmJlNa01CYqPaRhgRaf+uGdvTkTUcdaq8R5lLJL+JMNwUhcC8ijm3NqEjXjffuebGe1EzIeiITbA7Nndcd+GytwRDegAAAIEAkRYPjSVcUxfUHhHdpP6V8CuY1+CYSs9EPJ7iiWTDuXWVIBTU32oJLAnrmAcOwtIzEfPvm+rff5FI/Yhon2pB3VTXhPPEBjYzE5qANanAT4e6tzAVc5f3DUhHaDknwRYfDz86GFvuLtDjeE/UZ9t6OofYoEsCBpYozLAprBvNIQY= DSA #1 sisyphus.example.com ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBF6yQEtD9yBw9gmDRf477WBBzvWhAa0ioBI3nbA4emKykj0RbuQd5C4XdQAEOZGzE7v//FcCjwB2wi+JH5eKkxCtN6CjohDASZ1huoIV2UVyYIicZJEEOg1IWjjphvaxtw== ECDSA #1 sisyphus.example.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK9ks7jkua5YWIwByRnnnc6UPJQWI75O0e/UJdPYU1JI ED25519 #1 sisyphus.example.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDg4hB4vAZHJ0PVRiJajOv/GlytFWNpv5/9xgB9+5BIbvp8LOrFZ5D9K0Gsmwpd4G4rfaAz8j896DhMArg0vtkilIPPGt/6VzWMERgvaIQPJ/IE99X3+fjcAG56oAWwy29JX10lQMzBPU6XJIaN/zqpkb6qUBiAHBdLpxrFBBU0/w== RSA #1 # Plain host keys, hostnames + addresses -prometheus.example.com,192.0.2.1,2001:db8::1 ssh-dss AAAAB3NzaC1kc3MAAACBAI38Hy/61/O5Bp6yUG8J5XQCeNjRS0xvjlCdzKLyXCueMa+L+X2L/u9PWUsy5SVbTjGgpB8sF6UkCNsV+va7S8zCCHas2MZ7GPlxP6GZBkRPTIFR0N/Pu7wfBzDQz0t0iL4VmxBfTBQv/SxkGWZg+yHihIQP9fwdSAwD/7aVh6ItAAAAFQDSyihIUlINlswM0PJ8wXSti3yIMwAAAIB+oqzaB6ozqs8YxpN5oQOBa/9HEBQEsp8RSIlQmVubXRNgktp42n+Ii1waU9UUk8DX5ahhIeR6B7ojWkqmDAji4SKpoHf4kmr6HvYo85ZSTSx0W4YK/gJHSpDJwhlT52tAfb1JCbWSObjl09B4STv7KedCHcR5oXQvvrV+XoKOSAAAAIAue/EXrs2INw1RfaKNHC0oqOMxmRitv0BFMuNVPo1VDj39CE5kA7AHjwvS1TNeaHtK5Hhgeb6vsmLmNPTOc8xCob0ilyQbt9O0GbONeF2Ge7D2UJyULA/hxql+tCYFIC6yUrmo35fF9XiNisXLoaflk9fjp7ROWWVwnki/jstaQw== DSA #2 prometheus.example.com,192.0.2.1,2001:db8::1 ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAB8qVcXwgBM92NCmReQlPrZAoui4Bz/mW0VUBFOpHXXW1n+15b/Y7Pc6UBd/ITTZmaBciXY+PWaSBGdwc5GdqGdLgFyJ/QAGrFMPNpVutm/82gNQzlxpNwjbMcKyiZEXzSgnjS6DzMQ0WuSMdzIBXq8OW/Kafxg4ZkU6YqALUXxlQMZuQ== ECDSA #2 prometheus.example.com,192.0.2.1,2001:db8::1 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIBp6PVW0z2o9C4Ukv/JOgmK7QMFe1pD1s3ADFF7IQob ED25519 #2 prometheus.example.com,192.0.2.1,2001:db8::1 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDmbUhNabB5AmBDX6GNHZ3lbn7pRxqfpW+f53QqNGlK0sLV+0gkMIrOfUp1kdE2ZLE6tfzdicatj/RlH6/wuo4yyYb+Pyx3G0vxdmAIiA4aANq38XweDucBC0TZkRWVHK+Gs5V/uV0z7N0axJvkkJujMLvST3CRiiWwlficBc6yVQ== RSA #2 # Some hosts with wildcard names / IPs -*.example.com,192.0.2.*,2001:* ssh-dss AAAAB3NzaC1kc3MAAACBAI6lz2Ip9bzE7TGuDD4SjO9S4Ac90gq0h6ai1O06eI8t/Ot2uJ5Jk2QyVr2jvIZHDl/5bwBx7+5oyjlwRoUrAPPD814wf5tU2tSnmdu1Wbf0cBswif5q0r4tevzmopp/AtgH11QHo3u0/pfyJd10qBDLV2FaYSKMmZvyPfZJ0s9pAAAAFQD5Eqjl6Rx2qVePodD9OwAPT0bU6wAAAIAfnDm6csZF0sFaJR3NIJvaYgSGr8s7cqlsk2gLltB/1wOOO2yX+NeEC+B0H93hlMfaUsPa08bwgmYxnavSMqEBpmtPceefJiEd68zwYqXd38f88wyWZ9Z5iwaI/6OVZPHzCbDxOa4ewVTevRNYUKP1xUTZNT8/gSMfZLYPk4T2AQAAAIAUKroozRMyV+3V/rxt0gFnNxRXBKk+9cl3vgsQ7ktkI9cYg7V1T2K0XF21AVMK9gODszy6PBJjV6ruXBV6TRiqIbQauivp3bHHKYsG6wiJNqwdbVwIjfvv8nn1qFoZQLXG3sdONr9NwN8KzrX89OV0BlR2dVM5qqp+YxOXymP9yg== DSA #3 *.example.com,192.0.2.*,2001:* ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBIb3BhJZk+vUQPg5TQc1koIzuGqloCq7wjr9LjlhG24IBeiFHLsdWw74HDlH4DrOmlxToVYk2lTdnjARleRByjk= ECDSA #3 *.example.com,192.0.2.*,2001:* ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBlYfExtYZAPqYvYdrlpGlSWhh/XNHcH3v3c2JzsVNbB ED25519 #3 *.example.com,192.0.2.*,2001:* ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDX8F93W3SH4ZSus4XUQ2cw9dqcuyUETTlKEeGv3zlknV3YCoe2Mp04naDhiuwj8sOsytrZSESzLY1ZEyzrjxE6ZFVv8NKgck/AbRjcwlRFOcx9oKUxOrXRa0IoXlTq0kyjKCJfaHBKnGitZThknCPTbVmpATkm5xx6J0WEDozfoQ== RSA #3 # Hashed hostname and address entries -|1|z3xOIdT5ue3Vuf3MzT67kaioqjw=|GZhhe5uwDOBQrC9N4cCjpbLpSn4= ssh-dss AAAAB3NzaC1kc3MAAACBALrFy7w5ihlaOG+qR+6fj+vm5EQaO3qwxgACLcgH+VfShuOG4mkx8qFJmf+OZ3fh5iKngjNZfKtfcqI7zHWdk6378TQfQC52/kbZukjNXOLCpyNkogahcjA00onIoTK1RUDuMW28edAHwPFbpttXDTaqis+8JPMY8hZwsZGENCzTAAAAFQD6+It5vozwGgaN9ROYPMlByhi6jwAAAIBz2mcAC694vNzz9b6614gkX9d9E99PzJYfU1MPkXDziKg7MrjBw7Opd5y1jL09S3iL6lSTlHkKwVKvQ3pOwWRwXXRrKVus4I0STveoApm526jmp6mY0YEtqR98vMJ0v97h1ydt8FikKlihefCsnXVicb8887PXs2Y8C6GuFT3tfQAAAIBbmHtV5tPcrMRDkULhaQ/Whap2VKvT2DUhIHA7lx6oy/KpkltOpxDZOIGUHKqffGbiR7Jh01/y090AY5L2eCf0S2Ytx93+eADwVVpJbFJo6zSwfeey2Gm6L2oA+rCz9zTdmtZoekpD3/RAOQjnJIAPwbs7mXwabZTw4xRtiYIRrw== DSA #5 |1|B7t/AYabn8zgwU47Cb4A/Nqt3eI=|arQPZyRphkzisr7w6wwikvhaOyE= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPIudcagzq4QPtP1jkpje34+0POLB0jwT64hqrbCqhTH2T800KDZ0h2vwlJYa3OP3Oqru9AB5pnuHsKw7mAhUGY= ECDSA #5 |1|JR81WxEocTP5d7goIRkl8fHBbno=|l6sj6FOsoXxgEZMzn/BnOfPKN68= ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINf63qSV8rD57N+digID8t28WVhd3Yf2K2UhaoG8TsWQ ED25519 #5 |1|W7x4zY6KtTZJgsopyOusJqvVPag=|QauLt7hKezBZFZi2i4Xopho7Nsk= ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC/C15Q4sfnk7BZff1er8bscay+5s51oD4eWArlHWMK/ZfYeeTAccTy+7B7Jv+MS4nKCpflrvJI2RQz4kS8vF0ATdBbi4jeWefStlHNg0HLhnCY7NAfDIlRdaN9lm3Pqm2vmr+CkqwcJaSpycDg8nPN9yNAuD6pv7NDuUnECezojQ== RSA #5 -|1|mxnU8luzqWLvfVi5qBm5xVIyCRM=|9Epopft7LBd80Bf6RmWPIpwa8yU= ssh-dss AAAAB3NzaC1kc3MAAACBAIutigAse65TCW6hHDOEGXenE9L4L0talHbs65hj3UUNtWflKdQeXLofqXgW8AwaDKmnuRPrxRoxVNXj84n45wtBEdt4ztmdAZteAbXSnHqpcxME3jDxh3EtxzGPXLs+RUmKPVguraSgo7W2oN7KFx6VM+AcAtxANSTlvDid3s47AAAAFQCd9Q3kkHSLWe77sW0eRaayI45ovwAAAIAw6srGF6xvFasI44Y3r9JJ2K+3ezozl3ldL3p2+p2HG3iWafC4SdV8pB6ZIxKlYAywiiFb3LzH/JweGFq1jtoFDRM3MlYORBevydU4zPz7b5QLDVB0sY4evYtWmg2BFJvoWRfhLnlZVW7h5N8v4fNIwdVmVsw4Ljes7iF2HRGhHgAAAIBDFT3fww2Oby1xUA6G9pDAcVikrQFqp1sJRylNTUyeyQ37SNAGzYxwHJFgQr8gZLdRQ1UW+idYpqVbVNcYFMOiw/zSqK2OfVwPZ9U+TTKdc992ChSup6vJEKM/ZVIyDWDbJr7igQ4ahy7jo9mFvm8ljN926EnspQzCvs0Dxk6tHA== DSA #6 -|1|klvLmvh2vCpkNMDEjVvrE8SJWTg=|e/dqEEBLnbgqmwEesl4cDRu/7TM= ssh-dss AAAAB3NzaC1kc3MAAACBAIutigAse65TCW6hHDOEGXenE9L4L0talHbs65hj3UUNtWflKdQeXLofqXgW8AwaDKmnuRPrxRoxVNXj84n45wtBEdt4ztmdAZteAbXSnHqpcxME3jDxh3EtxzGPXLs+RUmKPVguraSgo7W2oN7KFx6VM+AcAtxANSTlvDid3s47AAAAFQCd9Q3kkHSLWe77sW0eRaayI45ovwAAAIAw6srGF6xvFasI44Y3r9JJ2K+3ezozl3ldL3p2+p2HG3iWafC4SdV8pB6ZIxKlYAywiiFb3LzH/JweGFq1jtoFDRM3MlYORBevydU4zPz7b5QLDVB0sY4evYtWmg2BFJvoWRfhLnlZVW7h5N8v4fNIwdVmVsw4Ljes7iF2HRGhHgAAAIBDFT3fww2Oby1xUA6G9pDAcVikrQFqp1sJRylNTUyeyQ37SNAGzYxwHJFgQr8gZLdRQ1UW+idYpqVbVNcYFMOiw/zSqK2OfVwPZ9U+TTKdc992ChSup6vJEKM/ZVIyDWDbJr7igQ4ahy7jo9mFvm8ljN926EnspQzCvs0Dxk6tHA== DSA #6 -|1|wsk3ddB3UjuxEsoeNCeZjZ6NvZs=|O3O/q2Z/u7DrxoTiIq6kzCevQT0= ssh-dss AAAAB3NzaC1kc3MAAACBAIutigAse65TCW6hHDOEGXenE9L4L0talHbs65hj3UUNtWflKdQeXLofqXgW8AwaDKmnuRPrxRoxVNXj84n45wtBEdt4ztmdAZteAbXSnHqpcxME3jDxh3EtxzGPXLs+RUmKPVguraSgo7W2oN7KFx6VM+AcAtxANSTlvDid3s47AAAAFQCd9Q3kkHSLWe77sW0eRaayI45ovwAAAIAw6srGF6xvFasI44Y3r9JJ2K+3ezozl3ldL3p2+p2HG3iWafC4SdV8pB6ZIxKlYAywiiFb3LzH/JweGFq1jtoFDRM3MlYORBevydU4zPz7b5QLDVB0sY4evYtWmg2BFJvoWRfhLnlZVW7h5N8v4fNIwdVmVsw4Ljes7iF2HRGhHgAAAIBDFT3fww2Oby1xUA6G9pDAcVikrQFqp1sJRylNTUyeyQ37SNAGzYxwHJFgQr8gZLdRQ1UW+idYpqVbVNcYFMOiw/zSqK2OfVwPZ9U+TTKdc992ChSup6vJEKM/ZVIyDWDbJr7igQ4ahy7jo9mFvm8ljN926EnspQzCvs0Dxk6tHA== DSA #6 |1|B8epmkLSni+vGZDijr/EwxeR2k4=|7ct8yzNOVJhKm3ZD2w0XIT7df8E= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBK1wRLyKtvK3Mmhd0XPkKwW4ev1KBVf8J4aG8lESq1TsaqqfOXYGyxMq5pN8fCGiD5UPOqyTYz/ZNzClRhJRHao= ECDSA #6 |1|JojD885UhYhbCu571rgyM/5PpYU=|BJaU2aE1FebQZy3B5tzTDRWFRG0= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBK1wRLyKtvK3Mmhd0XPkKwW4ev1KBVf8J4aG8lESq1TsaqqfOXYGyxMq5pN8fCGiD5UPOqyTYz/ZNzClRhJRHao= ECDSA #6 |1|5t7UDHDybVrDZVQPCpwdnr6nk4k=|EqJ73W/veIL3H2x+YWHcJxI5ETA= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBK1wRLyKtvK3Mmhd0XPkKwW4ev1KBVf8J4aG8lESq1TsaqqfOXYGyxMq5pN8fCGiD5UPOqyTYz/ZNzClRhJRHao= ECDSA #6 @@ -39,12 +32,11 @@ prometheus.example.com,192.0.2.1,2001:db8::1 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAA # Revoked and CA keys @revoked sisyphus.example.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDFP8L9REfN/iYy1KIRtFqSCn3V2+vOCpoZYENFGLdOF ED25519 #4 @cert-authority prometheus.example.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHZd0OXHIWwK3xnjAdMZ1tojxWycdu38pORO/UX5cqsKMgGCKQVBWWO3TFk1ePkGIE9VMWT1hCGqWRRwYlH+dSE= ECDSA #4 -@cert-authority *.example.com ssh-dss AAAAB3NzaC1kc3MAAACBAKvjnFHm0VvMr5h2Zu3nURsxQKGoxm+DCzYDxRYcilK07Cm5c4XTrFbA2X86+9sGs++W7QRMcTJUYIg0a+UtIMtAjwORd6ZPXM2K5dBW+gh1oHyvKi767tWX7I2c+1ZPJDY95mUUfZQUEfdy9eGDSBmw/pSsveQ1ur6XNUh/MtP/AAAAFQDHnXk/9jBJAdce1pHtLWnbdPSGdQAAAIEAm2OLy8tZBfiEO3c3X1yyB/GTcDwrQCqRMDkhnsmrliec3dWkOfNTzu+MrdvF8ymTWLEqPpbMheYtvNyZ3TF0HO5W7aVBpdGZbOdOAIfB+6skqGbI8A5Up1d7dak/bSsqL2r5NjwbDOdq+1hBzzvbl/qjh+sQarV2zHrpKoQaV28AAACANtkBVedBbqIAdphCrN/LbUi9WlyuF9UZz+tlpVLYrj8GJVwnplV2tvOmUw6yP5/pzCimTsao8dpL5PWxm7fKxLWVxA+lEsA4WeC885CiZn8xhdaJOCN+NyJ2bqkz+4VPI7oDGBm0aFwUqJn+M1PiSgvI50XdF2dBsFRTRNY0wzA= DSA #4 # Some invalid lines -@what sisyphus.example.com ssh-dss AAAAB3NzaC1kc3MAAACBAOqffHxEW4c+Z9q/r3l4sYK8F7qrBsU8XF9upGsW62T9InROFFq9IO0x3pQ6mDA0Wtw0sqcDmkPCHPyP4Ok/fU3/drLaZusHoVYu8pBBrWsIDrKgkeX9TEodBsSrYdl4Sqtqq9EZv9+DttV6LStZrgYyUTOKwOF95wGantpLynX5AAAAFQDdt+zjRNlETDsgmxcSYFgREirJrQAAAIBQlrPaiPhR24FhnMLcHH4016vL7AqDDID6Qw7PhbXGa4/XlxWMIigjBKrIPKvnZ6p712LSnCKtcbfdx0MtmJlNa01CYqPaRhgRaf+uGdvTkTUcdaq8R5lLJL+JMNwUhcC8ijm3NqEjXjffuebGe1EzIeiITbA7Nndcd+GytwRDegAAAIEAkRYPjSVcUxfUHhHdpP6V8CuY1+CYSs9EPJ7iiWTDuXWVIBTU32oJLAnrmAcOwtIzEfPvm+rff5FI/Yhon2pB3VTXhPPEBjYzE5qANanAT4e6tzAVc5f3DUhHaDknwRYfDz86GFvuLtDjeE/UZ9t6OofYoEsCBpYozLAprBvNIQY= DSA #1 +@what ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDg4hB4vAZHJ0PVRiJajOv/GlytFWNpv5/9xgB9+5BIbvp8LOrFZ5D9K0Gsmwpd4G4rfaAz8j896DhMArg0vtkilIPPGt/6VzWMERgvaIQPJ/IE99X3+fjcAG56oAWwy29JX10lQMzBPU6XJIaN/zqpkb6qUBiAHBdLpxrFBBU0/w== RSA #1 sisyphus.example.com prometheus.example.com ssh-ed25519 -sisyphus.example.com ssh-dsa AAAATgAAAAdz +sisyphus.example.com ssh-ed25519 AAAATgAAAAdz sisyphus.example.com ssh-XXX AAAATgAAAAdzc2gtWFhYAAAAP0ZVQ0tPRkZGVUNLT0ZGRlVDS09GRkZVQ0tPRkZGVUNLT0ZGRlVDS09GRkZVQ0tPRkZGVUNLT0ZGRlVDS09GRg== prometheus.example.com ssh-rsa AAAATgAAAAdzc2gtWFhYAAAAP0ZVQ0tPRkZGVUNLT0ZGRlVDS09GRkZVQ0tPRkZGVUNLT0ZGRlVDS09GRkZVQ0tPRkZGVUNLT0ZGRlVDS09GRg== diff --git a/regress/unittests/kex/Makefile b/regress/unittests/kex/Makefile index b76ee8edc813..645fb0609733 100644 --- a/regress/unittests/kex/Makefile +++ b/regress/unittests/kex/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.17 2025/04/15 04:00:42 djm Exp $ +# $OpenBSD: Makefile,v 1.18 2025/05/06 06:05:48 djm Exp $ PROG=test_kex SRCS=tests.c test_kex.c test_proposal.c @@ -6,7 +6,7 @@ SRCS=tests.c test_kex.c test_proposal.c # From usr.bin/ssh SRCS+=sshbuf-getput-basic.c sshbuf-getput-crypto.c sshbuf-misc.c sshbuf.c SRCS+=sshbuf-io.c atomicio.c sshkey.c authfile.c cipher.c log.c ssh-rsa.c -SRCS+=ssh-dss.c ssh-ecdsa.c ssh-ed25519.c mac.c umac.c umac128.c hmac.c misc.c +SRCS+=ssh-ecdsa.c ssh-ed25519.c mac.c umac.c umac128.c hmac.c misc.c SRCS+=ssherr.c uidswap.c cleanup.c xmalloc.c match.c krl.c fatal.c SRCS+=addr.c addrmatch.c bitmap.c packet.c dispatch.c canohost.c ssh_api.c SRCS+=compat.c ed25519.c hash.c diff --git a/regress/unittests/kex/test_kex.c b/regress/unittests/kex/test_kex.c index 84dada301b8f..54b826239ae8 100644 --- a/regress/unittests/kex/test_kex.c +++ b/regress/unittests/kex/test_kex.c @@ -1,4 +1,4 @@ -/* $OpenBSD: test_kex.c,v 1.10 2025/04/15 04:00:42 djm Exp $ */ +/* $OpenBSD: test_kex.c,v 1.11 2025/05/06 06:05:48 djm Exp $ */ /* * Regress test KEX * @@ -218,9 +218,6 @@ do_kex(char *kex) #ifdef WITH_OPENSSL do_kex_with_key(kex, NULL, NULL, NULL, KEY_RSA, 2048); -# ifdef WITH_DSA - do_kex_with_key(kex, NULL, NULL, NULL, KEY_DSA, 1024); -# endif /* WITH_DSA */ # ifdef OPENSSL_HAS_ECC do_kex_with_key(kex, NULL, NULL, NULL, KEY_ECDSA, 256); # endif /* OPENSSL_HAS_ECC */ diff --git a/regress/unittests/sshkey/Makefile b/regress/unittests/sshkey/Makefile index cd0f44d13d24..b237ff55c8d3 100644 --- a/regress/unittests/sshkey/Makefile +++ b/regress/unittests/sshkey/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.12 2023/01/15 23:35:10 djm Exp $ +# $OpenBSD: Makefile,v 1.13 2025/05/06 06:05:48 djm Exp $ PROG=test_sshkey SRCS=tests.c test_sshkey.c test_file.c test_fuzz.c common.c @@ -6,7 +6,7 @@ SRCS=tests.c test_sshkey.c test_file.c test_fuzz.c common.c # From usr.bin/ssh SRCS+=sshbuf-getput-basic.c sshbuf-getput-crypto.c sshbuf-misc.c sshbuf.c SRCS+=sshbuf-io.c atomicio.c sshkey.c authfile.c cipher.c log.c ssh-rsa.c -SRCS+=ssh-dss.c ssh-ecdsa.c ssh-ed25519.c mac.c umac.c umac128.c hmac.c misc.c +SRCS+=ssh-ecdsa.c ssh-ed25519.c mac.c umac.c umac128.c hmac.c misc.c SRCS+=ssherr.c uidswap.c cleanup.c xmalloc.c match.c krl.c fatal.c SRCS+=addr.c addrmatch.c bitmap.c SRCS+=ed25519.c hash.c diff --git a/regress/unittests/sshkey/common.c b/regress/unittests/sshkey/common.c index f325c2ac2025..a579eccb29d5 100644 --- a/regress/unittests/sshkey/common.c +++ b/regress/unittests/sshkey/common.c @@ -1,4 +1,4 @@ -/* $OpenBSD: common.c,v 1.6 2024/08/15 00:52:23 djm Exp $ */ +/* $OpenBSD: common.c,v 1.7 2025/05/06 06:05:48 djm Exp $ */ /* * Helpers for key API tests * @@ -21,7 +21,6 @@ #ifdef WITH_OPENSSL #include #include -#include #include #ifdef OPENSSL_HAS_NISTP256 # include @@ -126,38 +125,4 @@ rsa_q(struct sshkey *k) RSA_get0_factors(EVP_PKEY_get0_RSA(k->pkey), NULL, &q); return q; } - -const BIGNUM * -dsa_g(struct sshkey *k) -{ - const BIGNUM *g = NULL; - - ASSERT_PTR_NE(k, NULL); - ASSERT_PTR_NE(k->dsa, NULL); - DSA_get0_pqg(k->dsa, NULL, NULL, &g); - return g; -} - -const BIGNUM * -dsa_pub_key(struct sshkey *k) -{ - const BIGNUM *pub_key = NULL; - - ASSERT_PTR_NE(k, NULL); - ASSERT_PTR_NE(k->dsa, NULL); - DSA_get0_key(k->dsa, &pub_key, NULL); - return pub_key; -} - -const BIGNUM * -dsa_priv_key(struct sshkey *k) -{ - const BIGNUM *priv_key = NULL; - - ASSERT_PTR_NE(k, NULL); - ASSERT_PTR_NE(k->dsa, NULL); - DSA_get0_key(k->dsa, NULL, &priv_key); - return priv_key; -} #endif /* WITH_OPENSSL */ - diff --git a/regress/unittests/sshkey/common.h b/regress/unittests/sshkey/common.h index 7a514fdc8fe6..6127116da3d4 100644 --- a/regress/unittests/sshkey/common.h +++ b/regress/unittests/sshkey/common.h @@ -1,4 +1,4 @@ -/* $OpenBSD: common.h,v 1.2 2018/09/13 09:03:20 djm Exp $ */ +/* $OpenBSD: common.h,v 1.3 2025/05/06 06:05:48 djm Exp $ */ /* * Helpers for key API tests * @@ -19,7 +19,4 @@ const BIGNUM *rsa_n(struct sshkey *k); const BIGNUM *rsa_e(struct sshkey *k); const BIGNUM *rsa_p(struct sshkey *k); const BIGNUM *rsa_q(struct sshkey *k); -const BIGNUM *dsa_g(struct sshkey *k); -const BIGNUM *dsa_pub_key(struct sshkey *k); -const BIGNUM *dsa_priv_key(struct sshkey *k); diff --git a/regress/unittests/sshkey/mktestdata.sh b/regress/unittests/sshkey/mktestdata.sh index fcd78e990e8b..97e5d79fd734 100755 --- a/regress/unittests/sshkey/mktestdata.sh +++ b/regress/unittests/sshkey/mktestdata.sh @@ -1,5 +1,5 @@ #!/bin/sh -# $OpenBSD: mktestdata.sh,v 1.11 2020/06/19 03:48:49 djm Exp $ +# $OpenBSD: mktestdata.sh,v 1.12 2025/05/06 06:05:48 djm Exp $ PW=mekmitasdigoat @@ -24,27 +24,6 @@ rsa_params() { done } -dsa_params() { - _in="$1" - _outbase="$2" - set -e - openssl dsa -noout -text -in $_in | \ - awk '/^priv:$/,/^pub:/' | \ - grep -v '^[a-zA-Z]' | tr -d ' \n:' > ${_outbase}.priv - openssl dsa -noout -text -in $_in | \ - awk '/^pub:/,/^P:/' | #\ - grep -v '^[a-zA-Z]' | tr -d ' \n:' > ${_outbase}.pub - openssl dsa -noout -text -in $_in | \ - awk '/^G:/,0' | \ - grep -v '^[a-zA-Z]' | tr -d ' \n:' > ${_outbase}.g - for x in priv pub g ; do - echo "" >> ${_outbase}.$x - echo ============ ${_outbase}.$x - cat ${_outbase}.$x - echo ============ - done -} - ecdsa_params() { _in="$1" _outbase="$2" @@ -79,15 +58,14 @@ else exit 1 fi -rm -f rsa_1 dsa_1 ecdsa_1 ed25519_1 -rm -f rsa_2 dsa_2 ecdsa_2 ed25519_2 -rm -f rsa_n dsa_n ecdsa_n # new-format keys -rm -f rsa_1_pw dsa_1_pw ecdsa_1_pw ed25519_1_pw -rm -f rsa_n_pw dsa_n_pw ecdsa_n_pw +rm -f rsa_1 ecdsa_1 ed25519_1 +rm -f rsa_2 ecdsa_2 ed25519_2 +rm -f rsa_n ecdsa_n # new-format keys +rm -f rsa_1_pw ecdsa_1_pw ed25519_1_pw +rm -f rsa_n_pw ecdsa_n_pw rm -f pw *.pub *.bn.* *.param.* *.fp *.fp.bb ssh-keygen -t rsa -b 1024 -C "RSA test key #1" -N "" -f rsa_1 -m PEM -ssh-keygen -t dsa -b 1024 -C "DSA test key #1" -N "" -f dsa_1 -m PEM ssh-keygen -t ecdsa -b 256 -C "ECDSA test key #1" -N "" -f ecdsa_1 -m PEM ssh-keygen -t ed25519 -C "ED25519 test key #1" -N "" -f ed25519_1 ssh-keygen -w "$SK_DUMMY" -t ecdsa-sk -C "ECDSA-SK test key #1" \ @@ -97,7 +75,6 @@ ssh-keygen -w "$SK_DUMMY" -t ed25519-sk -C "ED25519-SK test key #1" \ ssh-keygen -t rsa -b 2048 -C "RSA test key #2" -N "" -f rsa_2 -m PEM -ssh-keygen -t dsa -b 1024 -C "DSA test key #2" -N "" -f dsa_2 -m PEM ssh-keygen -t ecdsa -b 521 -C "ECDSA test key #2" -N "" -f ecdsa_2 -m PEM ssh-keygen -t ed25519 -C "ED25519 test key #2" -N "" -f ed25519_2 ssh-keygen -w "$SK_DUMMY" -t ecdsa-sk -C "ECDSA-SK test key #2" \ @@ -106,37 +83,29 @@ ssh-keygen -w "$SK_DUMMY" -t ed25519-sk -C "ED25519-SK test key #2" \ -N "" -f ed25519_sk2 cp rsa_1 rsa_n -cp dsa_1 dsa_n cp ecdsa_1 ecdsa_n ssh-keygen -pf rsa_n -N "" -ssh-keygen -pf dsa_n -N "" ssh-keygen -pf ecdsa_n -N "" cp rsa_1 rsa_1_pw -cp dsa_1 dsa_1_pw cp ecdsa_1 ecdsa_1_pw cp ed25519_1 ed25519_1_pw cp ecdsa_sk1 ecdsa_sk1_pw cp ed25519_sk1 ed25519_sk1_pw cp rsa_1 rsa_n_pw -cp dsa_1 dsa_n_pw cp ecdsa_1 ecdsa_n_pw ssh-keygen -pf rsa_1_pw -m PEM -N "$PW" -ssh-keygen -pf dsa_1_pw -m PEM -N "$PW" ssh-keygen -pf ecdsa_1_pw -m PEM -N "$PW" ssh-keygen -pf ed25519_1_pw -N "$PW" ssh-keygen -pf ecdsa_sk1_pw -m PEM -N "$PW" ssh-keygen -pf ed25519_sk1_pw -N "$PW" ssh-keygen -pf rsa_n_pw -N "$PW" -ssh-keygen -pf dsa_n_pw -N "$PW" ssh-keygen -pf ecdsa_n_pw -N "$PW" rsa_params rsa_1 rsa_1.param rsa_params rsa_2 rsa_2.param -dsa_params dsa_1 dsa_1.param -dsa_params dsa_1 dsa_1.param ecdsa_params ecdsa_1 ecdsa_1.param ecdsa_params ecdsa_2 ecdsa_2.param # XXX ed25519, *sk params @@ -144,9 +113,6 @@ ecdsa_params ecdsa_2 ecdsa_2.param ssh-keygen -s rsa_2 -I hugo -n user1,user2 \ -Oforce-command=/bin/ls -Ono-port-forwarding -Osource-address=10.0.0.0/8 \ -V 19990101:20110101 -z 1 rsa_1.pub -ssh-keygen -s rsa_2 -I hugo -n user1,user2 \ - -Oforce-command=/bin/ls -Ono-port-forwarding -Osource-address=10.0.0.0/8 \ - -V 19990101:20110101 -z 2 dsa_1.pub ssh-keygen -s rsa_2 -I hugo -n user1,user2 \ -Oforce-command=/bin/ls -Ono-port-forwarding -Osource-address=10.0.0.0/8 \ -V 19990101:20110101 -z 3 ecdsa_1.pub @@ -175,8 +141,6 @@ ssh-keygen -s rsa_2 -I hugo -n user1,user2 -t rsa-sha2-512 \ ssh-keygen -s ed25519_1 -I julius -n host1,host2 -h \ -V 19990101:20110101 -z 5 rsa_1.pub -ssh-keygen -s ed25519_1 -I julius -n host1,host2 -h \ - -V 19990101:20110101 -z 6 dsa_1.pub ssh-keygen -s ecdsa_1 -I julius -n host1,host2 -h \ -V 19990101:20110101 -z 7 ecdsa_1.pub ssh-keygen -s ed25519_1 -I julius -n host1,host2 -h \ @@ -187,33 +151,28 @@ ssh-keygen -s ed25519_1 -I julius -n host1,host2 -h \ -V 19990101:20110101 -z 8 ed25519_sk1.pub ssh-keygen -lf rsa_1 | awk '{print $2}' > rsa_1.fp -ssh-keygen -lf dsa_1 | awk '{print $2}' > dsa_1.fp ssh-keygen -lf ecdsa_1 | awk '{print $2}' > ecdsa_1.fp ssh-keygen -lf ed25519_1 | awk '{print $2}' > ed25519_1.fp ssh-keygen -lf ecdsa_sk1 | awk '{print $2}' > ecdsa_sk1.fp ssh-keygen -lf ed25519_sk1 | awk '{print $2}' > ed25519_sk1.fp ssh-keygen -lf rsa_2 | awk '{print $2}' > rsa_2.fp -ssh-keygen -lf dsa_2 | awk '{print $2}' > dsa_2.fp ssh-keygen -lf ecdsa_2 | awk '{print $2}' > ecdsa_2.fp ssh-keygen -lf ed25519_2 | awk '{print $2}' > ed25519_2.fp ssh-keygen -lf ecdsa_sk2 | awk '{print $2}' > ecdsa_sk2.fp ssh-keygen -lf ed25519_sk2 | awk '{print $2}' > ed25519_sk2.fp ssh-keygen -lf rsa_1-cert.pub | awk '{print $2}' > rsa_1-cert.fp -ssh-keygen -lf dsa_1-cert.pub | awk '{print $2}' > dsa_1-cert.fp ssh-keygen -lf ecdsa_1-cert.pub | awk '{print $2}' > ecdsa_1-cert.fp ssh-keygen -lf ed25519_1-cert.pub | awk '{print $2}' > ed25519_1-cert.fp ssh-keygen -lf ecdsa_sk1-cert.pub | awk '{print $2}' > ecdsa_sk1-cert.fp ssh-keygen -lf ed25519_sk1-cert.pub | awk '{print $2}' > ed25519_sk1-cert.fp ssh-keygen -Bf rsa_1 | awk '{print $2}' > rsa_1.fp.bb -ssh-keygen -Bf dsa_1 | awk '{print $2}' > dsa_1.fp.bb ssh-keygen -Bf ecdsa_1 | awk '{print $2}' > ecdsa_1.fp.bb ssh-keygen -Bf ed25519_1 | awk '{print $2}' > ed25519_1.fp.bb ssh-keygen -Bf ecdsa_sk1 | awk '{print $2}' > ecdsa_sk1.fp.bb ssh-keygen -Bf ed25519_sk1 | awk '{print $2}' > ed25519_sk1.fp.bb ssh-keygen -Bf rsa_2 | awk '{print $2}' > rsa_2.fp.bb -ssh-keygen -Bf dsa_2 | awk '{print $2}' > dsa_2.fp.bb ssh-keygen -Bf ecdsa_2 | awk '{print $2}' > ecdsa_2.fp.bb ssh-keygen -Bf ed25519_2 | awk '{print $2}' > ed25519_2.fp.bb ssh-keygen -Bf ecdsa_sk2 | awk '{print $2}' > ecdsa_sk2.fp.bb diff --git a/regress/unittests/sshkey/test_file.c b/regress/unittests/sshkey/test_file.c index 3babe604dcca..49148aca07b2 100644 --- a/regress/unittests/sshkey/test_file.c +++ b/regress/unittests/sshkey/test_file.c @@ -1,4 +1,4 @@ -/* $OpenBSD: test_file.c,v 1.12 2024/08/15 00:52:23 djm Exp $ */ +/* $OpenBSD: test_file.c,v 1.13 2025/05/06 06:05:48 djm Exp $ */ /* * Regress test for sshkey.h key management API * @@ -21,7 +21,6 @@ #ifdef WITH_OPENSSL #include #include -#include #include #ifdef OPENSSL_HAS_NISTP256 # include @@ -165,99 +164,6 @@ sshkey_file_tests(void) sshkey_free(k1); -#ifdef WITH_DSA - TEST_START("parse DSA from private"); - buf = load_file("dsa_1"); - ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); - sshbuf_free(buf); - ASSERT_PTR_NE(k1, NULL); - a = load_bignum("dsa_1.param.g"); - b = load_bignum("dsa_1.param.priv"); - c = load_bignum("dsa_1.param.pub"); - ASSERT_BIGNUM_EQ(dsa_g(k1), a); - ASSERT_BIGNUM_EQ(dsa_priv_key(k1), b); - ASSERT_BIGNUM_EQ(dsa_pub_key(k1), c); - BN_free(a); - BN_free(b); - BN_free(c); - TEST_DONE(); - - TEST_START("parse DSA from private w/ passphrase"); - buf = load_file("dsa_1_pw"); - ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, - (const char *)sshbuf_ptr(pw), &k2, NULL), 0); - sshbuf_free(buf); - ASSERT_PTR_NE(k2, NULL); - ASSERT_INT_EQ(sshkey_equal(k1, k2), 1); - sshkey_free(k2); - TEST_DONE(); - - TEST_START("parse DSA from new-format"); - buf = load_file("dsa_n"); - ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k2, NULL), 0); - sshbuf_free(buf); - ASSERT_PTR_NE(k2, NULL); - ASSERT_INT_EQ(sshkey_equal(k1, k2), 1); - sshkey_free(k2); - TEST_DONE(); - - TEST_START("parse DSA from new-format w/ passphrase"); - buf = load_file("dsa_n_pw"); - ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, - (const char *)sshbuf_ptr(pw), &k2, NULL), 0); - sshbuf_free(buf); - ASSERT_PTR_NE(k2, NULL); - ASSERT_INT_EQ(sshkey_equal(k1, k2), 1); - sshkey_free(k2); - TEST_DONE(); - - TEST_START("load DSA from public"); - ASSERT_INT_EQ(sshkey_load_public(test_data_file("dsa_1.pub"), &k2, - NULL), 0); - ASSERT_PTR_NE(k2, NULL); - ASSERT_INT_EQ(sshkey_equal(k1, k2), 1); - sshkey_free(k2); - TEST_DONE(); - - TEST_START("load DSA cert"); - ASSERT_INT_EQ(sshkey_load_cert(test_data_file("dsa_1"), &k2), 0); - ASSERT_PTR_NE(k2, NULL); - ASSERT_INT_EQ(k2->type, KEY_DSA_CERT); - ASSERT_INT_EQ(sshkey_equal(k1, k2), 0); - ASSERT_INT_EQ(sshkey_equal_public(k1, k2), 1); - TEST_DONE(); - - TEST_START("DSA key hex fingerprint"); - buf = load_text_file("dsa_1.fp"); - cp = sshkey_fingerprint(k1, SSH_DIGEST_SHA256, SSH_FP_BASE64); - ASSERT_PTR_NE(cp, NULL); - ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf)); - sshbuf_free(buf); - free(cp); - TEST_DONE(); - - TEST_START("DSA cert hex fingerprint"); - buf = load_text_file("dsa_1-cert.fp"); - cp = sshkey_fingerprint(k2, SSH_DIGEST_SHA256, SSH_FP_BASE64); - ASSERT_PTR_NE(cp, NULL); - ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf)); - sshbuf_free(buf); - free(cp); - sshkey_free(k2); - TEST_DONE(); - - TEST_START("DSA key bubblebabble fingerprint"); - buf = load_text_file("dsa_1.fp.bb"); - cp = sshkey_fingerprint(k1, SSH_DIGEST_SHA1, SSH_FP_BUBBLEBABBLE); - ASSERT_PTR_NE(cp, NULL); - ASSERT_STRING_EQ(cp, (const char *)sshbuf_ptr(buf)); - sshbuf_free(buf); - free(cp); - TEST_DONE(); - - sshkey_free(k1); -#endif - #ifdef OPENSSL_HAS_ECC TEST_START("parse ECDSA from private"); buf = load_file("ecdsa_1"); diff --git a/regress/unittests/sshkey/test_fuzz.c b/regress/unittests/sshkey/test_fuzz.c index 0aff7c9bf4e4..12d0e12eacef 100644 --- a/regress/unittests/sshkey/test_fuzz.c +++ b/regress/unittests/sshkey/test_fuzz.c @@ -1,4 +1,4 @@ -/* $OpenBSD: test_fuzz.c,v 1.14 2024/01/11 01:45:58 djm Exp $ */ +/* $OpenBSD: test_fuzz.c,v 1.15 2025/05/06 06:05:48 djm Exp $ */ /* * Fuzz tests for key parsing * @@ -21,7 +21,6 @@ #ifdef WITH_OPENSSL #include #include -#include #include #ifdef OPENSSL_HAS_NISTP256 # include @@ -160,52 +159,6 @@ sshkey_fuzz_tests(void) fuzz_cleanup(fuzz); TEST_DONE(); -#ifdef WITH_DSA - TEST_START("fuzz DSA private"); - buf = load_file("dsa_1"); - fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf), - sshbuf_len(buf)); - ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); - sshkey_free(k1); - sshbuf_free(buf); - ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL); - TEST_ONERROR(onerror, fuzz); - for(i = 0; !fuzz_done(fuzz); i++, fuzz_next(fuzz)) { - r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz)); - ASSERT_INT_EQ(r, 0); - if (sshkey_parse_private_fileblob(fuzzed, "", &k1, NULL) == 0) - sshkey_free(k1); - sshbuf_reset(fuzzed); - if (test_is_fast() && i >= NUM_FAST_BASE64_TESTS) - break; - } - sshbuf_free(fuzzed); - fuzz_cleanup(fuzz); - TEST_DONE(); - - TEST_START("fuzz DSA new-format private"); - buf = load_file("dsa_n"); - fuzz = fuzz_begin(FUZZ_BASE64, sshbuf_mutable_ptr(buf), - sshbuf_len(buf)); - ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); - sshkey_free(k1); - sshbuf_free(buf); - ASSERT_PTR_NE(fuzzed = sshbuf_new(), NULL); - TEST_ONERROR(onerror, fuzz); - for(i = 0; !fuzz_done(fuzz); i++, fuzz_next(fuzz)) { - r = sshbuf_put(fuzzed, fuzz_ptr(fuzz), fuzz_len(fuzz)); - ASSERT_INT_EQ(r, 0); - if (sshkey_parse_private_fileblob(fuzzed, "", &k1, NULL) == 0) - sshkey_free(k1); - sshbuf_reset(fuzzed); - if (test_is_fast() && i >= NUM_FAST_BASE64_TESTS) - break; - } - sshbuf_free(fuzzed); - fuzz_cleanup(fuzz); - TEST_DONE(); -#endif - #ifdef OPENSSL_HAS_ECC TEST_START("fuzz ECDSA private"); buf = load_file("ecdsa_1"); @@ -290,22 +243,6 @@ sshkey_fuzz_tests(void) sshkey_free(k1); TEST_DONE(); -#ifdef WITH_DSA - TEST_START("fuzz DSA public"); - buf = load_file("dsa_1"); - ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); - sshbuf_free(buf); - public_fuzz(k1); - sshkey_free(k1); - TEST_DONE(); - - TEST_START("fuzz DSA cert"); - ASSERT_INT_EQ(sshkey_load_cert(test_data_file("dsa_1"), &k1), 0); - public_fuzz(k1); - sshkey_free(k1); - TEST_DONE(); -#endif - #ifdef OPENSSL_HAS_ECC TEST_START("fuzz ECDSA public"); buf = load_file("ecdsa_1"); @@ -362,16 +299,6 @@ sshkey_fuzz_tests(void) sshkey_free(k1); TEST_DONE(); -#ifdef WITH_DSA - TEST_START("fuzz DSA sig"); - buf = load_file("dsa_1"); - ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); - sshbuf_free(buf); - sig_fuzz(k1, NULL); - sshkey_free(k1); - TEST_DONE(); -#endif - #ifdef OPENSSL_HAS_ECC TEST_START("fuzz ECDSA sig"); buf = load_file("ecdsa_1"); diff --git a/regress/unittests/sshkey/test_sshkey.c b/regress/unittests/sshkey/test_sshkey.c index 53bdc0ca62d8..832ef9b202cc 100644 --- a/regress/unittests/sshkey/test_sshkey.c +++ b/regress/unittests/sshkey/test_sshkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: test_sshkey.c,v 1.28 2025/04/15 05:31:24 djm Exp $ */ +/* $OpenBSD: test_sshkey.c,v 1.29 2025/05/06 06:05:48 djm Exp $ */ /* * Regress test for sshkey.h key management API * @@ -18,7 +18,6 @@ #ifdef WITH_OPENSSL #include #include -#include #if defined(OPENSSL_HAS_ECC) && defined(OPENSSL_HAS_NISTP256) # include #endif @@ -271,14 +270,6 @@ sshkey_tests(void) sshkey_free(k1); TEST_DONE(); -#ifdef WITH_DSA - TEST_START("new/free KEY_DSA"); - k1 = sshkey_new(KEY_DSA); - ASSERT_PTR_NE(k1, NULL); - ASSERT_PTR_NE(k1->dsa, NULL); - sshkey_free(k1); - TEST_DONE(); -#endif #ifdef OPENSSL_HAS_ECC TEST_START("new/free KEY_ECDSA"); @@ -310,14 +301,6 @@ sshkey_tests(void) ASSERT_PTR_EQ(k1, NULL); TEST_DONE(); -#ifdef WITH_DSA - TEST_START("generate KEY_DSA wrong bits"); - ASSERT_INT_EQ(sshkey_generate(KEY_DSA, 2048, &k1), - SSH_ERR_KEY_LENGTH); - ASSERT_PTR_EQ(k1, NULL); - sshkey_free(k1); - TEST_DONE(); -#endif #ifdef OPENSSL_HAS_ECC TEST_START("generate KEY_ECDSA wrong bits"); @@ -340,15 +323,6 @@ sshkey_tests(void) ASSERT_INT_EQ(BN_num_bits(rsa_n(kr)), 1024); TEST_DONE(); -#ifdef WITH_DSA - TEST_START("generate KEY_DSA"); - ASSERT_INT_EQ(sshkey_generate(KEY_DSA, 1024, &kd), 0); - ASSERT_PTR_NE(kd, NULL); - ASSERT_PTR_NE(kd->dsa, NULL); - ASSERT_PTR_NE(dsa_g(kd), NULL); - ASSERT_PTR_NE(dsa_priv_key(kd), NULL); - TEST_DONE(); -#endif #ifdef OPENSSL_HAS_ECC TEST_START("generate KEY_ECDSA"); @@ -388,22 +362,6 @@ sshkey_tests(void) sshkey_free(k1); TEST_DONE(); -#ifdef WITH_DSA - TEST_START("demote KEY_DSA"); - ASSERT_INT_EQ(sshkey_from_private(kd, &k1), 0); - ASSERT_PTR_NE(k1, NULL); - ASSERT_PTR_NE(kd, k1); - ASSERT_INT_EQ(k1->type, KEY_DSA); - ASSERT_PTR_NE(k1->dsa, NULL); - ASSERT_PTR_NE(dsa_g(k1), NULL); - ASSERT_PTR_EQ(dsa_priv_key(k1), NULL); - TEST_DONE(); - - TEST_START("equal KEY_DSA/demoted KEY_DSA"); - ASSERT_INT_EQ(sshkey_equal(kd, k1), 1); - sshkey_free(k1); - TEST_DONE(); -#endif #ifdef OPENSSL_HAS_ECC TEST_START("demote KEY_ECDSA"); @@ -551,16 +509,6 @@ sshkey_tests(void) sshkey_free(k2); TEST_DONE(); -#ifdef WITH_DSA - TEST_START("sign and verify DSA"); - k1 = get_private("dsa_1"); - ASSERT_INT_EQ(sshkey_load_public(test_data_file("dsa_2.pub"), &k2, - NULL), 0); - signature_tests(k1, k2, NULL); - sshkey_free(k1); - sshkey_free(k2); - TEST_DONE(); -#endif #ifdef OPENSSL_HAS_ECC TEST_START("sign and verify ECDSA"); @@ -623,15 +571,6 @@ sshkey_benchmarks(void) TEST_DONE(); BENCH_FINISH("keys"); -#ifdef WITH_DSA - BENCH_START("generate DSA-1024"); - TEST_START("generate KEY_DSA"); - ASSERT_INT_EQ(sshkey_generate(KEY_DSA, 1024, &k), 0); - ASSERT_PTR_NE(k, NULL); - sshkey_free(k); - TEST_DONE(); - BENCH_FINISH("keys"); -#endif BENCH_START("generate ECDSA-256"); TEST_START("generate KEY_ECDSA"); @@ -674,9 +613,6 @@ sshkey_benchmarks(void) signature_benchmark("RSA-2048/SHA1", KEY_RSA, 2048, "ssh-rsa", 0); signature_benchmark("RSA-2048/SHA256", KEY_RSA, 2048, "rsa-sha2-256", 0); signature_benchmark("RSA-2048/SHA512", KEY_RSA, 2048, "rsa-sha2-512", 0); -#ifdef WITH_DSA - signature_benchmark("DSA-1024", KEY_DSA, 1024, NULL, 0); -#endif signature_benchmark("ECDSA-256", KEY_ECDSA, 256, NULL, 0); signature_benchmark("ECDSA-384", KEY_ECDSA, 384, NULL, 0); signature_benchmark("ECDSA-521", KEY_ECDSA, 521, NULL, 0); @@ -689,9 +625,6 @@ sshkey_benchmarks(void) signature_benchmark("RSA-2048/SHA1", KEY_RSA, 2048, "ssh-rsa", 1); signature_benchmark("RSA-2048/SHA256", KEY_RSA, 2048, "rsa-sha2-256", 1); signature_benchmark("RSA-2048/SHA512", KEY_RSA, 2048, "rsa-sha2-512", 1); -#ifdef WITH_DSA - signature_benchmark("DSA-1024", KEY_DSA, 1024, NULL, 1); -#endif signature_benchmark("ECDSA-256", KEY_ECDSA, 256, NULL, 1); signature_benchmark("ECDSA-384", KEY_ECDSA, 384, NULL, 1); signature_benchmark("ECDSA-521", KEY_ECDSA, 521, NULL, 1); diff --git a/regress/unittests/sshkey/testdata/dsa_1 b/regress/unittests/sshkey/testdata/dsa_1 deleted file mode 100644 index d3f24824f8d5..000000000000 --- a/regress/unittests/sshkey/testdata/dsa_1 +++ /dev/null @@ -1,12 +0,0 @@ ------BEGIN DSA PRIVATE KEY----- -MIIBvAIBAAKBgQD6kutNFRsHTwEAv6d39Lhsqy1apdHBZ9c2HfyRr7WmypyGIy2m -Ka43vzXI8CNwmRSYs+A6d0vJC7Pl+f9QzJ/04NWOA+MiwfurwrR3CRe61QRYb8Py -mcHOxueHs95IcjrbIPNn86cjnPP5qvv/guUzCjuww4zBdJOXpligrGt2XwIVAKMD -/50qQy7j8JaMk+1+Xtg1pK01AoGBAO7l9QVVbSSoy5lq6cOtvpf8UlwOa6+zBwbl -o4gmFd1RwX1yWkA8kQ7RrhCSg8Hc6mIGnKRgKRli/3LgbSfZ0obFJehkRtEWtN4P -h8fVUeS74iQbIwFQeKlYHIlNTRoGtAbdi3nHdV+BBkEQc1V3rjqYqhjOoz/yNsgz -LND26HrdAoGBAOdXpyfmobEBaOqZAuvgj1P0uhjG2P31Ufurv22FWPBU3A9qrkxb -OXwE0LwvjCvrsQV/lrYhJz/tiys40VeahulWZE5SAHMXGIf95LiLSgaXMjko7joo -t+LK84ltLymwZ4QMnYjnZSSclf1UuyQMcUtb34+I0u9Ycnyhp2mSFsQtAhRYIbQ5 -KfXsZuBPuWe5FJz3ldaEgw== ------END DSA PRIVATE KEY----- diff --git a/regress/unittests/sshkey/testdata/dsa_1-cert.fp b/regress/unittests/sshkey/testdata/dsa_1-cert.fp deleted file mode 100644 index 75ff0e9cd9f7..000000000000 --- a/regress/unittests/sshkey/testdata/dsa_1-cert.fp +++ /dev/null @@ -1 +0,0 @@ -SHA256:kOLgXSoAT8O5T6r36n5NJUYigbux1d7gdH/rmWiJm6s diff --git a/regress/unittests/sshkey/testdata/dsa_1-cert.pub b/regress/unittests/sshkey/testdata/dsa_1-cert.pub deleted file mode 100644 index e768db1e7bad..000000000000 --- a/regress/unittests/sshkey/testdata/dsa_1-cert.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-dss-cert-v01@openssh.com AAAAHHNzaC1kc3MtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgdTlbNU9Hn9Qng3FHxwH971bxCIoq1ern/QWFFDWXgmYAAACBAPqS600VGwdPAQC/p3f0uGyrLVql0cFn1zYd/JGvtabKnIYjLaYprje/NcjwI3CZFJiz4Dp3S8kLs+X5/1DMn/Tg1Y4D4yLB+6vCtHcJF7rVBFhvw/KZwc7G54ez3khyOtsg82fzpyOc8/mq+/+C5TMKO7DDjMF0k5emWKCsa3ZfAAAAFQCjA/+dKkMu4/CWjJPtfl7YNaStNQAAAIEA7uX1BVVtJKjLmWrpw62+l/xSXA5rr7MHBuWjiCYV3VHBfXJaQDyRDtGuEJKDwdzqYgacpGApGWL/cuBtJ9nShsUl6GRG0Ra03g+Hx9VR5LviJBsjAVB4qVgciU1NGga0Bt2Lecd1X4EGQRBzVXeuOpiqGM6jP/I2yDMs0Pboet0AAACBAOdXpyfmobEBaOqZAuvgj1P0uhjG2P31Ufurv22FWPBU3A9qrkxbOXwE0LwvjCvrsQV/lrYhJz/tiys40VeahulWZE5SAHMXGIf95LiLSgaXMjko7joot+LK84ltLymwZ4QMnYjnZSSclf1UuyQMcUtb34+I0u9Ycnyhp2mSFsQtAAAAAAAAAAYAAAACAAAABmp1bGl1cwAAABIAAAAFaG9zdDEAAAAFaG9zdDIAAAAANowB8AAAAABNHmBwAAAAAAAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACBThupGO0X+FLQhbz8CoKPwc7V3JNsQuGtlsgN+F7SMGQAAAFMAAAALc3NoLWVkMjU1MTkAAABAh/z1LIdNL1b66tQ8t9DY9BTB3BQKpTKmc7ezyFKLwl96yaIniZwD9Ticdbe/8i/Li3uCFE3EAt8NAIv9zff8Bg== DSA test key #1 diff --git a/regress/unittests/sshkey/testdata/dsa_1.fp b/regress/unittests/sshkey/testdata/dsa_1.fp deleted file mode 100644 index 75ff0e9cd9f7..000000000000 --- a/regress/unittests/sshkey/testdata/dsa_1.fp +++ /dev/null @@ -1 +0,0 @@ -SHA256:kOLgXSoAT8O5T6r36n5NJUYigbux1d7gdH/rmWiJm6s diff --git a/regress/unittests/sshkey/testdata/dsa_1.fp.bb b/regress/unittests/sshkey/testdata/dsa_1.fp.bb deleted file mode 100644 index ba37776ee30a..000000000000 --- a/regress/unittests/sshkey/testdata/dsa_1.fp.bb +++ /dev/null @@ -1 +0,0 @@ -xetag-todiz-mifah-torec-mynyv-cyvit-gopon-pygag-rupic-cenav-bexax diff --git a/regress/unittests/sshkey/testdata/dsa_1.param.g b/regress/unittests/sshkey/testdata/dsa_1.param.g deleted file mode 100644 index e51c3f9fd1b4..000000000000 --- a/regress/unittests/sshkey/testdata/dsa_1.param.g +++ /dev/null @@ -1 +0,0 @@ -00eee5f505556d24a8cb996ae9c3adbe97fc525c0e6bafb30706e5a3882615dd51c17d725a403c910ed1ae109283c1dcea62069ca460291962ff72e06d27d9d286c525e86446d116b4de0f87c7d551e4bbe2241b23015078a9581c894d4d1a06b406dd8b79c7755f81064110735577ae3a98aa18cea33ff236c8332cd0f6e87add diff --git a/regress/unittests/sshkey/testdata/dsa_1.param.priv b/regress/unittests/sshkey/testdata/dsa_1.param.priv deleted file mode 100644 index 4f743314c76e..000000000000 --- a/regress/unittests/sshkey/testdata/dsa_1.param.priv +++ /dev/null @@ -1 +0,0 @@ -5821b43929f5ec66e04fb967b9149cf795d68483 diff --git a/regress/unittests/sshkey/testdata/dsa_1.param.pub b/regress/unittests/sshkey/testdata/dsa_1.param.pub deleted file mode 100644 index ba0313beec48..000000000000 --- a/regress/unittests/sshkey/testdata/dsa_1.param.pub +++ /dev/null @@ -1 +0,0 @@ -00e757a727e6a1b10168ea9902ebe08f53f4ba18c6d8fdf551fbabbf6d8558f054dc0f6aae4c5b397c04d0bc2f8c2bebb1057f96b621273fed8b2b38d1579a86e956644e520073171887fde4b88b4a0697323928ee3a28b7e2caf3896d2f29b067840c9d88e765249c95fd54bb240c714b5bdf8f88d2ef58727ca1a7699216c42d diff --git a/regress/unittests/sshkey/testdata/dsa_1.pub b/regress/unittests/sshkey/testdata/dsa_1.pub deleted file mode 100644 index 41cae2f69f52..000000000000 --- a/regress/unittests/sshkey/testdata/dsa_1.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-dss AAAAB3NzaC1kc3MAAACBAPqS600VGwdPAQC/p3f0uGyrLVql0cFn1zYd/JGvtabKnIYjLaYprje/NcjwI3CZFJiz4Dp3S8kLs+X5/1DMn/Tg1Y4D4yLB+6vCtHcJF7rVBFhvw/KZwc7G54ez3khyOtsg82fzpyOc8/mq+/+C5TMKO7DDjMF0k5emWKCsa3ZfAAAAFQCjA/+dKkMu4/CWjJPtfl7YNaStNQAAAIEA7uX1BVVtJKjLmWrpw62+l/xSXA5rr7MHBuWjiCYV3VHBfXJaQDyRDtGuEJKDwdzqYgacpGApGWL/cuBtJ9nShsUl6GRG0Ra03g+Hx9VR5LviJBsjAVB4qVgciU1NGga0Bt2Lecd1X4EGQRBzVXeuOpiqGM6jP/I2yDMs0Pboet0AAACBAOdXpyfmobEBaOqZAuvgj1P0uhjG2P31Ufurv22FWPBU3A9qrkxbOXwE0LwvjCvrsQV/lrYhJz/tiys40VeahulWZE5SAHMXGIf95LiLSgaXMjko7joot+LK84ltLymwZ4QMnYjnZSSclf1UuyQMcUtb34+I0u9Ycnyhp2mSFsQt DSA test key #1 diff --git a/regress/unittests/sshkey/testdata/dsa_1_pw b/regress/unittests/sshkey/testdata/dsa_1_pw deleted file mode 100644 index 24c73039fe1a..000000000000 --- a/regress/unittests/sshkey/testdata/dsa_1_pw +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN DSA PRIVATE KEY----- -Proc-Type: 4,ENCRYPTED -DEK-Info: AES-128-CBC,BC8386C373B22EB7F00ADC821D5D8BE9 - -+HDV2DQ09sxrIAeXTz9r3YFuPRa2hk1+NGcr3ETkXbC6KiZ14wpTnGTloKwaQjIW -eXTa9mpCOWAoohgvsVb+hOuOlP7AfeHu1IXV4EAS+GDpkiV5UxlCXXwqlD75Buu4 -wwDd/p4SWzILH3WGjDk5JIXoxWNY13LHwC7Q6gtGJx4AicUG7YBRTXMIBDa/Kh77 -6o2rFETKmp4VHBvHbakmiETfptdM8bbWxKWeY2vakThyESgeofsLoTOQCIwlEfJC -s2D/KYL65C8VbHYgIoSLTQnooO45DDyxIuhCqP+H23mhv9vB1Od3nc2atgHj/XFs -dcOPFkF/msDRYqxY3V0AS6+jpKwFodZ7g/hyGcyPxOkzlJVuKoKuH6P5PyQ69Gx0 -iqri0xEPyABr7kGlXNrjjctojX+B4WwSnjg/2euXXWFXCRalIdA7ErATTiQbGOx7 -Vd6Gn8PZbSy1MkqEDrZRip0pfAFJYI/8GXPC75BpnRsrVlfhtrngbW+kBP35LzaN -l2K+RQ3gSB3iFoqNb1Kuu6T5MZlyVl5H2dVlJSeb1euQ2OycXdDoFTyJ4AiyWS7w -Vlh8zeJnso5QRDjMwx99pZilbbuFGSLsahiGEveFc6o= ------END DSA PRIVATE KEY----- diff --git a/regress/unittests/sshkey/testdata/dsa_2 b/regress/unittests/sshkey/testdata/dsa_2 deleted file mode 100644 index 3cc9631afa0f..000000000000 --- a/regress/unittests/sshkey/testdata/dsa_2 +++ /dev/null @@ -1,12 +0,0 @@ ------BEGIN DSA PRIVATE KEY----- -MIIBvQIBAAKBgQCbyPXNdHeLsjpobPVCMkfagBkt15Zsltqf/PGNP1y1cuz7rsTX -ZekQwUkSTNm5coqXe+ZOw2O4tjobJDd60I1/VPgaB0NYlQR9Hn87M284WD4f6VY+ -aunHmP134a8ybG5G4NqVNF3ihvxAR2pVITqb7kE46r2uYZNcNlHI8voRCwIVAMcP -bwqFNsQbH5pJyZW30wj4KVZ3AoGBAIK98BVeKQVf8qDFqx9ovMuNgVSxpd+N0Yta -5ZEy1OI2ziu5RhjueIM2K7Gq2Mnp38ob1AM53BUxqlcBJaHEDa6rj6yvuMgW9oCJ -dImBM8sIFxfBbXNbpJiMaDwa6WyT84OkpDE6uuAepTMnWOUWkUVkAiyokHDUGXkG -GyoQblbXAoGBAIsf7TaZ804sUWwRV0wI8DYx+hxD5QdrfYPYMtL2fHn3lICimGt0 -FTtUZ25jKg0E0DMBPdET6ZEHB3ZZkR8hFoUzZhdnyJMu3UjVtgaV88Ue3PrXxchk -0W2jHPaAgQU3JIWzo8HFIFqvC/HEL+EyW3rBTY2uXM3XGI+YcWSA4ZrZAhUAsY2f -bDFNzgZ4DaZ9wLRzTgOswPU= ------END DSA PRIVATE KEY----- diff --git a/regress/unittests/sshkey/testdata/dsa_2.fp b/regress/unittests/sshkey/testdata/dsa_2.fp deleted file mode 100644 index 51fbeb4d8ce1..000000000000 --- a/regress/unittests/sshkey/testdata/dsa_2.fp +++ /dev/null @@ -1 +0,0 @@ -SHA256:ecwhWcXgpdBxZ2e+OjpRRY7dqXHHCD62BGtoVQQBwCk diff --git a/regress/unittests/sshkey/testdata/dsa_2.fp.bb b/regress/unittests/sshkey/testdata/dsa_2.fp.bb deleted file mode 100644 index 4d908ee30977..000000000000 --- a/regress/unittests/sshkey/testdata/dsa_2.fp.bb +++ /dev/null @@ -1 +0,0 @@ -xeser-megad-pocan-rozit-belup-tapoh-fapif-kyvit-vonav-cehab-naxax diff --git a/regress/unittests/sshkey/testdata/dsa_2.pub b/regress/unittests/sshkey/testdata/dsa_2.pub deleted file mode 100644 index 77bb555d595f..000000000000 --- a/regress/unittests/sshkey/testdata/dsa_2.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-dss AAAAB3NzaC1kc3MAAACBAJvI9c10d4uyOmhs9UIyR9qAGS3XlmyW2p/88Y0/XLVy7PuuxNdl6RDBSRJM2blyipd75k7DY7i2OhskN3rQjX9U+BoHQ1iVBH0efzszbzhYPh/pVj5q6ceY/XfhrzJsbkbg2pU0XeKG/EBHalUhOpvuQTjqva5hk1w2Ucjy+hELAAAAFQDHD28KhTbEGx+aScmVt9MI+ClWdwAAAIEAgr3wFV4pBV/yoMWrH2i8y42BVLGl343Ri1rlkTLU4jbOK7lGGO54gzYrsarYyenfyhvUAzncFTGqVwElocQNrquPrK+4yBb2gIl0iYEzywgXF8Ftc1ukmIxoPBrpbJPzg6SkMTq64B6lMydY5RaRRWQCLKiQcNQZeQYbKhBuVtcAAACBAIsf7TaZ804sUWwRV0wI8DYx+hxD5QdrfYPYMtL2fHn3lICimGt0FTtUZ25jKg0E0DMBPdET6ZEHB3ZZkR8hFoUzZhdnyJMu3UjVtgaV88Ue3PrXxchk0W2jHPaAgQU3JIWzo8HFIFqvC/HEL+EyW3rBTY2uXM3XGI+YcWSA4ZrZ DSA test key #2 diff --git a/regress/unittests/sshkey/testdata/dsa_n b/regress/unittests/sshkey/testdata/dsa_n deleted file mode 100644 index 657624e0e72f..000000000000 --- a/regress/unittests/sshkey/testdata/dsa_n +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABswAAAAdzc2gtZH -NzAAAAgQD6kutNFRsHTwEAv6d39Lhsqy1apdHBZ9c2HfyRr7WmypyGIy2mKa43vzXI8CNw -mRSYs+A6d0vJC7Pl+f9QzJ/04NWOA+MiwfurwrR3CRe61QRYb8PymcHOxueHs95IcjrbIP -Nn86cjnPP5qvv/guUzCjuww4zBdJOXpligrGt2XwAAABUAowP/nSpDLuPwloyT7X5e2DWk -rTUAAACBAO7l9QVVbSSoy5lq6cOtvpf8UlwOa6+zBwblo4gmFd1RwX1yWkA8kQ7RrhCSg8 -Hc6mIGnKRgKRli/3LgbSfZ0obFJehkRtEWtN4Ph8fVUeS74iQbIwFQeKlYHIlNTRoGtAbd -i3nHdV+BBkEQc1V3rjqYqhjOoz/yNsgzLND26HrdAAAAgQDnV6cn5qGxAWjqmQLr4I9T9L -oYxtj99VH7q79thVjwVNwPaq5MWzl8BNC8L4wr67EFf5a2ISc/7YsrONFXmobpVmROUgBz -FxiH/eS4i0oGlzI5KO46KLfiyvOJbS8psGeEDJ2I52UknJX9VLskDHFLW9+PiNLvWHJ8oa -dpkhbELQAAAdhWTOFbVkzhWwAAAAdzc2gtZHNzAAAAgQD6kutNFRsHTwEAv6d39Lhsqy1a -pdHBZ9c2HfyRr7WmypyGIy2mKa43vzXI8CNwmRSYs+A6d0vJC7Pl+f9QzJ/04NWOA+Miwf -urwrR3CRe61QRYb8PymcHOxueHs95IcjrbIPNn86cjnPP5qvv/guUzCjuww4zBdJOXplig -rGt2XwAAABUAowP/nSpDLuPwloyT7X5e2DWkrTUAAACBAO7l9QVVbSSoy5lq6cOtvpf8Ul -wOa6+zBwblo4gmFd1RwX1yWkA8kQ7RrhCSg8Hc6mIGnKRgKRli/3LgbSfZ0obFJehkRtEW -tN4Ph8fVUeS74iQbIwFQeKlYHIlNTRoGtAbdi3nHdV+BBkEQc1V3rjqYqhjOoz/yNsgzLN -D26HrdAAAAgQDnV6cn5qGxAWjqmQLr4I9T9LoYxtj99VH7q79thVjwVNwPaq5MWzl8BNC8 -L4wr67EFf5a2ISc/7YsrONFXmobpVmROUgBzFxiH/eS4i0oGlzI5KO46KLfiyvOJbS8psG -eEDJ2I52UknJX9VLskDHFLW9+PiNLvWHJ8oadpkhbELQAAABRYIbQ5KfXsZuBPuWe5FJz3 -ldaEgwAAAAAB ------END OPENSSH PRIVATE KEY----- diff --git a/regress/unittests/sshkey/testdata/dsa_n_pw b/regress/unittests/sshkey/testdata/dsa_n_pw deleted file mode 100644 index 24ac299a482d..000000000000 --- a/regress/unittests/sshkey/testdata/dsa_n_pw +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jYmMAAAAGYmNyeXB0AAAAGAAAABCVs+LsMJ -wnB5zM9U9pTXrGAAAAEAAAAAEAAAGzAAAAB3NzaC1kc3MAAACBAPqS600VGwdPAQC/p3f0 -uGyrLVql0cFn1zYd/JGvtabKnIYjLaYprje/NcjwI3CZFJiz4Dp3S8kLs+X5/1DMn/Tg1Y -4D4yLB+6vCtHcJF7rVBFhvw/KZwc7G54ez3khyOtsg82fzpyOc8/mq+/+C5TMKO7DDjMF0 -k5emWKCsa3ZfAAAAFQCjA/+dKkMu4/CWjJPtfl7YNaStNQAAAIEA7uX1BVVtJKjLmWrpw6 -2+l/xSXA5rr7MHBuWjiCYV3VHBfXJaQDyRDtGuEJKDwdzqYgacpGApGWL/cuBtJ9nShsUl -6GRG0Ra03g+Hx9VR5LviJBsjAVB4qVgciU1NGga0Bt2Lecd1X4EGQRBzVXeuOpiqGM6jP/ -I2yDMs0Pboet0AAACBAOdXpyfmobEBaOqZAuvgj1P0uhjG2P31Ufurv22FWPBU3A9qrkxb -OXwE0LwvjCvrsQV/lrYhJz/tiys40VeahulWZE5SAHMXGIf95LiLSgaXMjko7joot+LK84 -ltLymwZ4QMnYjnZSSclf1UuyQMcUtb34+I0u9Ycnyhp2mSFsQtAAAB4HiOcRW4w+sIqBL0 -TPVbf0glN1hUi0rcE63Pqxmvxb8LkldC4IxAUagPrjhNAEW2AY42+CvPrtGB1z7gDADAIW -xZX6wKwIcXP0Qh+xHE12F4u6mwfasssnAp4t1Ki8uCjMjnimgb3KdWpp0kiUV0oR062TXV -PAdfrWjaq4fw0KOqbHIAG/v36AqzuqjSTfDbqvLZM3y0gp2Q1RxaQVJA5ZIKKyqRyFX7sr -BaEIyCgeE3hM0EB7BycY1oIcS/eNxrACBWVJCENl5N7LtEYXNX7TANFniztfXzwaqGTT6A -fCfbW4gz1UKldLUBzbIrPwMWlirAstbHvOf/2Iay2pNAs/SHhI0aF2jsGfvv5/D6N+r9dG -B2SgDKBg7pywMH1DTvg6YT3P4GjCx0GUHqRCFLvD1rDdk4KSjvaRMpVq1PJ0/Wv6UGtsMS -TR0PaEHDRNZqAX4YxqujnWrGKuRJhuz0eUvp7fZvbWHtiAMKV7368kkeUmkOHanb+TS+zs -KINX8ev8zJZ6WVr8Vl+IQavpv0i2bXwS6QqbEuifpv/+uBb7pqRiU4u8en0eMdX1bZoTPM -R6xHCnGD/Jpb3zS91Ya57T6CiXZ12KCaL6nWGnCkZVpzkfJ2HjFklWSWBQ6uyaosDQ== ------END OPENSSH PRIVATE KEY----- diff --git a/regress/unittests/sshsig/Makefile b/regress/unittests/sshsig/Makefile index bc3c6c739d48..f8b6560eba18 100644 --- a/regress/unittests/sshsig/Makefile +++ b/regress/unittests/sshsig/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.3 2023/01/15 23:35:10 djm Exp $ +# $OpenBSD: Makefile,v 1.4 2025/05/06 06:05:48 djm Exp $ PROG=test_sshsig SRCS=tests.c @@ -6,7 +6,7 @@ SRCS=tests.c # From usr.bin/ssh SRCS+=sshbuf-getput-basic.c sshbuf-getput-crypto.c sshbuf-misc.c sshbuf.c SRCS+=sshbuf-io.c atomicio.c sshkey.c authfile.c cipher.c log.c ssh-rsa.c -SRCS+=ssh-dss.c ssh-ecdsa.c ssh-ed25519.c mac.c umac.c umac128.c hmac.c misc.c +SRCS+=ssh-ecdsa.c ssh-ed25519.c mac.c umac.c umac128.c hmac.c misc.c SRCS+=ssherr.c uidswap.c cleanup.c xmalloc.c match.c krl.c fatal.c SRCS+=addr.c addrmatch.c bitmap.c sshsig.c SRCS+=ed25519.c hash.c diff --git a/regress/unittests/sshsig/mktestdata.sh b/regress/unittests/sshsig/mktestdata.sh index d2300f9c6ee1..b7c60cc27767 100755 --- a/regress/unittests/sshsig/mktestdata.sh +++ b/regress/unittests/sshsig/mktestdata.sh @@ -1,5 +1,5 @@ #!/bin/sh -# $OpenBSD: mktestdata.sh,v 1.1 2020/06/19 04:32:09 djm Exp $ +# $OpenBSD: mktestdata.sh,v 1.2 2025/05/06 06:05:48 djm Exp $ NAMESPACE=unittest @@ -17,14 +17,13 @@ else fi rm -f signed-data namespace -rm -f rsa dsa ecdsa ed25519 ecdsa_sk ed25519_sk -rm -f rsa.sig dsa.sig ecdsa.sig ed25519.sig ecdsa_sk.sig ed25519_sk.sig +rm -f rsa ecdsa ed25519 ecdsa_sk ed25519_sk +rm -f rsa.sig ecdsa.sig ed25519.sig ecdsa_sk.sig ed25519_sk.sig printf "This is a test, this is only a test" > signed-data printf "$NAMESPACE" > namespace ssh-keygen -t rsa -C "RSA test" -N "" -f rsa -m PEM -ssh-keygen -t dsa -C "DSA test" -N "" -f dsa -m PEM ssh-keygen -t ecdsa -C "ECDSA test" -N "" -f ecdsa -m PEM ssh-keygen -t ed25519 -C "ED25519 test key" -N "" -f ed25519 ssh-keygen -w "$SK_DUMMY" -t ecdsa-sk -C "ECDSA-SK test key" \ @@ -33,7 +32,6 @@ ssh-keygen -w "$SK_DUMMY" -t ed25519-sk -C "ED25519-SK test key" \ -N "" -f ed25519_sk ssh-keygen -Y sign -f rsa -n $NAMESPACE - < signed-data > rsa.sig -ssh-keygen -Y sign -f dsa -n $NAMESPACE - < signed-data > dsa.sig ssh-keygen -Y sign -f ecdsa -n $NAMESPACE - < signed-data > ecdsa.sig ssh-keygen -Y sign -f ed25519 -n $NAMESPACE - < signed-data > ed25519.sig ssh-keygen -w "$SK_DUMMY" \ diff --git a/regress/unittests/sshsig/testdata/dsa b/regress/unittests/sshsig/testdata/dsa deleted file mode 100644 index 7c0063efcdf5..000000000000 --- a/regress/unittests/sshsig/testdata/dsa +++ /dev/null @@ -1,12 +0,0 @@ ------BEGIN DSA PRIVATE KEY----- -MIIBuwIBAAKBgQCXpndQdz2mQVnk+lYOF3nxDT+h6SiJmUvBFhnFWBv8tG4pTOkb -EwGufLEzGpzjTj+3bjVau7LFt37AFrqs4Num272BWNsYNIjOlGPgq7Xjv32FN00x -JYh1DoRs1cGGnvohlsWEamGGhTHD1a9ipctPEBV+NrxtZMrl+pO/ZZg8vQIVAKJB -P3iNYSpSuW74+q4WxLCuK8O3AoGAQldE+BIuxlvoG1IFiWesx0CU+H2KO0SEZc9A -SX/qjOabh0Fb78ofTlEf9gWHFfat8SvSJQIOPMVlb76Lio8AAMT8Eaa/qQKKYmQL -dNq4MLhhjxx5KLGt6J2JyFPExCv+qnHYHD59ngtLwKyqGjpSC8LPLktdXn8W/Aad -Ly1K7+MCgYBsMHBczhSeUh8w7i20CVg4OlNTmfJRVU2tO6OpMxZ/quitRm3hLKSN -u4xRkvHJwi4LhQtv1SXvLI5gs5P3gCG8tsIAiyCqLinHha63iBdJpqhnV/x/j7dB -yJr3xJbnmLdWLkkCtNk1Ir1/CuEz+ufAyLGdKWksEAu1UUlb501BkwIVAILIa3Rg -0h7J9lQpHJphvF3K0M1T ------END DSA PRIVATE KEY----- diff --git a/regress/unittests/sshsig/testdata/dsa.pub b/regress/unittests/sshsig/testdata/dsa.pub deleted file mode 100644 index e77aa7ef41a0..000000000000 --- a/regress/unittests/sshsig/testdata/dsa.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-dss AAAAB3NzaC1kc3MAAACBAJemd1B3PaZBWeT6Vg4XefENP6HpKImZS8EWGcVYG/y0bilM6RsTAa58sTManONOP7duNVq7ssW3fsAWuqzg26bbvYFY2xg0iM6UY+CrteO/fYU3TTEliHUOhGzVwYae+iGWxYRqYYaFMcPVr2Kly08QFX42vG1kyuX6k79lmDy9AAAAFQCiQT94jWEqUrlu+PquFsSwrivDtwAAAIBCV0T4Ei7GW+gbUgWJZ6zHQJT4fYo7RIRlz0BJf+qM5puHQVvvyh9OUR/2BYcV9q3xK9IlAg48xWVvvouKjwAAxPwRpr+pAopiZAt02rgwuGGPHHkosa3onYnIU8TEK/6qcdgcPn2eC0vArKoaOlILws8uS11efxb8Bp0vLUrv4wAAAIBsMHBczhSeUh8w7i20CVg4OlNTmfJRVU2tO6OpMxZ/quitRm3hLKSNu4xRkvHJwi4LhQtv1SXvLI5gs5P3gCG8tsIAiyCqLinHha63iBdJpqhnV/x/j7dByJr3xJbnmLdWLkkCtNk1Ir1/CuEz+ufAyLGdKWksEAu1UUlb501Bkw== DSA test diff --git a/regress/unittests/sshsig/testdata/dsa.sig b/regress/unittests/sshsig/testdata/dsa.sig deleted file mode 100644 index 0b14ad6b8a7b..000000000000 --- a/regress/unittests/sshsig/testdata/dsa.sig +++ /dev/null @@ -1,13 +0,0 @@ ------BEGIN SSH SIGNATURE----- -U1NIU0lHAAAAAQAAAbEAAAAHc3NoLWRzcwAAAIEAl6Z3UHc9pkFZ5PpWDhd58Q0/oekoiZ -lLwRYZxVgb/LRuKUzpGxMBrnyxMxqc404/t241Wruyxbd+wBa6rODbptu9gVjbGDSIzpRj -4Ku14799hTdNMSWIdQ6EbNXBhp76IZbFhGphhoUxw9WvYqXLTxAVfja8bWTK5fqTv2WYPL -0AAAAVAKJBP3iNYSpSuW74+q4WxLCuK8O3AAAAgEJXRPgSLsZb6BtSBYlnrMdAlPh9ijtE -hGXPQEl/6ozmm4dBW+/KH05RH/YFhxX2rfEr0iUCDjzFZW++i4qPAADE/BGmv6kCimJkC3 -TauDC4YY8ceSixreidichTxMQr/qpx2Bw+fZ4LS8Csqho6UgvCzy5LXV5/FvwGnS8tSu/j -AAAAgGwwcFzOFJ5SHzDuLbQJWDg6U1OZ8lFVTa07o6kzFn+q6K1GbeEspI27jFGS8cnCLg -uFC2/VJe8sjmCzk/eAIby2wgCLIKouKceFrreIF0mmqGdX/H+Pt0HImvfElueYt1YuSQK0 -2TUivX8K4TP658DIsZ0paSwQC7VRSVvnTUGTAAAACHVuaXR0ZXN0AAAAAAAAAAZzaGE1MT -IAAAA3AAAAB3NzaC1kc3MAAAAodi5lr0pqBpO76OY4N1CtfR85BCgZ95qfVjP/e9lToj0q -lwjSJJXUjw== ------END SSH SIGNATURE----- diff --git a/regress/unittests/sshsig/tests.c b/regress/unittests/sshsig/tests.c index 7fcf9488d270..ef1a46edcbb2 100644 --- a/regress/unittests/sshsig/tests.c +++ b/regress/unittests/sshsig/tests.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tests.c,v 1.5 2025/04/15 04:00:42 djm Exp $ */ +/* $OpenBSD: tests.c,v 1.6 2025/05/06 06:05:48 djm Exp $ */ /* * Regress test for sshbuf.h buffer API * @@ -103,11 +103,6 @@ tests(void) check_sig("rsa.pub", "rsa.sig", msg, namespace); TEST_DONE(); -#ifdef WITH_DSA - TEST_START("check DSA signature"); - check_sig("dsa.pub", "dsa.sig", msg, namespace); - TEST_DONE(); -#endif #ifdef OPENSSL_HAS_ECC TEST_START("check ECDSA signature"); From 207289a5663bdf49903e1aeb938dcc0924e2ac63 Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Wed, 7 May 2025 10:44:26 +0000 Subject: [PATCH 032/244] upstream: Rename sockaddr_un sun -> sunaddr. This makes things easier in -portable, where on Solaris an derivatives "sun" is defined to "1", causing compilation errors. ok deraadt@. OpenBSD-Commit-ID: 0669043afb49856b57b382f0489221bd98305d3b --- misc-agent.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/misc-agent.c b/misc-agent.c index 9d96880e9090..34ce2a5244ef 100644 --- a/misc-agent.c +++ b/misc-agent.c @@ -226,14 +226,14 @@ static int socket_is_stale(const char *path) { int fd, r; - struct sockaddr_un sun; + struct sockaddr_un sunaddr; socklen_t l = sizeof(r); /* attempt non-blocking connect on socket */ - memset(&sun, '\0', sizeof(sun)); - sun.sun_family = AF_UNIX; - if (strlcpy(sun.sun_path, path, - sizeof(sun.sun_path)) >= sizeof(sun.sun_path)) { + memset(&sunaddr, '\0', sizeof(sunaddr)); + sunaddr.sun_family = AF_UNIX; + if (strlcpy(sunaddr.sun_path, path, + sizeof(sunaddr.sun_path)) >= sizeof(sunaddr.sun_path)) { debug_f("path for \"%s\" too long for sockaddr_un", path); return 0; } @@ -243,7 +243,7 @@ socket_is_stale(const char *path) } set_nonblock(fd); /* a socket without a listener should yield an error immediately */ - if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { + if (connect(fd, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1) { debug_f("connect \"%s\": %s", path, strerror(errno)); close(fd); return 1; From 755c3d082e59e6884f28d30e6333a1444e9173d1 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Wed, 7 May 2025 21:05:06 +1000 Subject: [PATCH 033/244] Skip d_type check on platforms that don't have it. On those, the subsequent stat() should catch the sockets. --- configure.ac | 6 ++++++ misc-agent.c | 2 ++ 2 files changed, 8 insertions(+) diff --git a/configure.ac b/configure.ac index 221d5f5618bf..98d98594b5c8 100644 --- a/configure.ac +++ b/configure.ac @@ -1700,6 +1700,12 @@ AC_RUN_IFELSE( ] ) +AC_CHECK_MEMBERS([struct dirent.d_type], [], [], [[ +#ifdef HAVE_DIRENT_H +#include +#endif +]]) + AC_MSG_CHECKING([for /proc/pid/fd directory]) if test -d "/proc/$$/fd" ; then AC_DEFINE([HAVE_PROC_PID], [1], [Define if you have /proc/$pid/fd]) diff --git a/misc-agent.c b/misc-agent.c index 34ce2a5244ef..db8f93bc873b 100644 --- a/misc-agent.c +++ b/misc-agent.c @@ -298,8 +298,10 @@ agent_cleanup_stale(const char *homedir, int ignore_hosthash) goto out; } while ((dp = readdir(d)) != NULL) { +#ifdef HAVE_DIRENT_D_TYPE if (dp->d_type != DT_SOCK && dp->d_type != DT_UNKNOWN) continue; +#endif if (fstatat(dirfd(d), dp->d_name, &sb, AT_SYMLINK_NOFOLLOW) != 0 && errno != ENOENT) { error_f("stat \"%s/%s\": %s", From 086369736a9496b39af0d9f09443fa81b59b7f05 Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Wed, 16 Apr 2025 10:18:34 +1000 Subject: [PATCH 034/244] ssh-agent: exit 0 from SIGTERM under systemd socket-activation When the ssh-agent service is configured to be launched under systemd socket-activation, the user can inspect the status of the agent with something like: systemctl --user status ssh-agent.service If the user does: systemctl --user stop ssh-agent.service it causes the `systemd --user` supervisor to send a SIGTERM to the agent, which terminates while leaving the systemd-managed socket in place. That's good, and as expected. (If the user wants to close the socket, they can do "systemctl --user stop ssh-agent.socket" instead) But because ssh-agent exits with code 2 in response to a SIGTERM, the supervisor marks the service as "failed", even though the state of the supervised service is exactly the same as during session startup (not running, ready to launch when a client connects to the socket). This change makes ssh-agent exit cleanly (code 0) in response to a SIGTERM when launched under socket activation. This aligns the systemd supervisor's understanding of the state of supervised ssh-agent with reality. Signed-off-by: Daniel Kahn Gillmor --- ssh-agent.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ssh-agent.c b/ssh-agent.c index 8a88ef3fd1c0..d82b351d04b6 100644 --- a/ssh-agent.c +++ b/ssh-agent.c @@ -2241,6 +2241,7 @@ main(int ac, char **av) size_t npfd = 0; u_int maxfds; sigset_t nsigset, osigset; + int socket_activated = 0; /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ sanitise_stdfd(); @@ -2414,6 +2415,7 @@ main(int ac, char **av) fatal("bad LISTEN_PID: %d vs pid %d", pid, getpid()); debug("using socket activation on fd=3"); sock = 3; + socket_activated = 1; } if (sock == -1 && agentsocket == NULL && !T_flag) { @@ -2577,7 +2579,8 @@ main(int ac, char **av) sigprocmask(SIG_BLOCK, &nsigset, &osigset); if (signalled_exit != 0) { logit("exiting on signal %d", (int)signalled_exit); - cleanup_exit(2); + cleanup_exit((signalled_exit == SIGTERM && + socket_activated) ? 0 : 2); } if (signalled_keydrop) { logit("signal %d received; removing all keys", From 1511f113a27d8aafe080aa6493cb3c0cf2b5abe0 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Thu, 8 May 2025 11:38:24 +1000 Subject: [PATCH 035/244] Add no-op implmentation of dirfd(). Fixes build on pre-POSIX.1 2008 systems. --- openbsd-compat/bsd-misc.c | 9 +++++++++ openbsd-compat/bsd-misc.h | 6 ++++++ 2 files changed, 15 insertions(+) diff --git a/openbsd-compat/bsd-misc.c b/openbsd-compat/bsd-misc.c index b26b4ba4670e..09bbb6049cac 100644 --- a/openbsd-compat/bsd-misc.c +++ b/openbsd-compat/bsd-misc.c @@ -158,6 +158,15 @@ utimensat(int fd, const char *path, const struct timespec times[2], } #endif +#ifndef HAVE_DIRFD +int +dirfd(DIR *dir) +{ + errno = ENOSYS; + return -1; +} +#endif + #ifndef HAVE_FCHOWNAT /* * A limited implementation of fchownat() that only implements the diff --git a/openbsd-compat/bsd-misc.h b/openbsd-compat/bsd-misc.h index edb0fcc8ca2b..4ac73c73ee27 100644 --- a/openbsd-compat/bsd-misc.h +++ b/openbsd-compat/bsd-misc.h @@ -65,6 +65,12 @@ struct timeval { int utimes(const char *, struct timeval *); #endif /* HAVE_UTIMES */ +#ifndef HAVE_DIRFD +#include +#include +int dirfd(DIR *); +#endif + #ifndef AT_FDCWD # define AT_FDCWD (-2) #endif From f5726215957bb34e18bb872d527845c2f64e2389 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Thu, 8 May 2025 18:56:39 +1000 Subject: [PATCH 036/244] Since it's unused, make dirfd() take void *. Some platforms (eg Old BSDs) in some configurations define DIR to "void *", which causes compile errors in the no-op implementation. --- openbsd-compat/bsd-misc.c | 2 +- openbsd-compat/bsd-misc.h | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/openbsd-compat/bsd-misc.c b/openbsd-compat/bsd-misc.c index 09bbb6049cac..669d2bb7e273 100644 --- a/openbsd-compat/bsd-misc.c +++ b/openbsd-compat/bsd-misc.c @@ -160,7 +160,7 @@ utimensat(int fd, const char *path, const struct timespec times[2], #ifndef HAVE_DIRFD int -dirfd(DIR *dir) +dirfd(void *dir) { errno = ENOSYS; return -1; diff --git a/openbsd-compat/bsd-misc.h b/openbsd-compat/bsd-misc.h index 4ac73c73ee27..d237256d45fc 100644 --- a/openbsd-compat/bsd-misc.h +++ b/openbsd-compat/bsd-misc.h @@ -66,9 +66,7 @@ int utimes(const char *, struct timeval *); #endif /* HAVE_UTIMES */ #ifndef HAVE_DIRFD -#include -#include -int dirfd(DIR *); +int dirfd(void *); #endif #ifndef AT_FDCWD From 3357bf2fe2d11b6ed4465c1ed2871bd1099cbbc5 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Fri, 9 May 2025 19:08:36 +1000 Subject: [PATCH 037/244] Put PRIV_ECDSA back, it's still used. Should fix oss-fuzz test. --- cipher.c | 2 +- regress/misc/fuzz-harness/fixed-keys.h | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/cipher.c b/cipher.c index 8a18da2df8d1..692aafe96cff 100644 --- a/cipher.c +++ b/cipher.c @@ -75,7 +75,7 @@ struct sshcipher { #define CFLAG_CHACHAPOLY (1<<1) #define CFLAG_AESCTR (1<<2) #define CFLAG_NONE (1<<3) -#define CFLAG_INTERNAL CFLAG_NONE /* Don't use "none" for packets */ +#define CFLAG_INTERNAL 0 #ifdef WITH_OPENSSL const EVP_CIPHER *(*evptype)(void); #else diff --git a/regress/misc/fuzz-harness/fixed-keys.h b/regress/misc/fuzz-harness/fixed-keys.h index 7dae9ac0034d..61afa876a0fa 100644 --- a/regress/misc/fuzz-harness/fixed-keys.h +++ b/regress/misc/fuzz-harness/fixed-keys.h @@ -34,6 +34,15 @@ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDf56l/5UYqgY9oBlet/pLRzK6ZCd12QYGdUVfQDl6HftG0u6DSpjm2HGwFRsYZWv2ZN3ZBfAu6MHBiDmXUw/8WaD7nfXZmDH2keZL6opQttqvSGU2Cm00Rv5o1R3ej2qDdpepebv5meMBXTl5/+bE1E3Zm+4STDtxGmlMlxsEj68XeVe4JedfaSUMj3kaXYBbdYdG1qeosdle4GSONEEMpzsxSr8Y/WGYuIB33l29Tt9mNGUgSw/zjMYQjUVvQv+SY8dw62JV8d+3wK2YL2/r73gms6I8EE1JxX53KuAAY+x0p2v/W8ilCYI2Ijyzc8KIPwntmIFpibQjx+rkb+qdT" #define CERT_RSA \ "ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAg89JX6OBMYDSxER8fnU5y8xxeMCHR/hI0uVqdEhNyCpcAAAADAQABAAABAQDf56l/5UYqgY9oBlet/pLRzK6ZCd12QYGdUVfQDl6HftG0u6DSpjm2HGwFRsYZWv2ZN3ZBfAu6MHBiDmXUw/8WaD7nfXZmDH2keZL6opQttqvSGU2Cm00Rv5o1R3ej2qDdpepebv5meMBXTl5/+bE1E3Zm+4STDtxGmlMlxsEj68XeVe4JedfaSUMj3kaXYBbdYdG1qeosdle4GSONEEMpzsxSr8Y/WGYuIB33l29Tt9mNGUgSw/zjMYQjUVvQv+SY8dw62JV8d+3wK2YL2/r73gms6I8EE1JxX53KuAAY+x0p2v/W8ilCYI2Ijyzc8KIPwntmIFpibQjx+rkb+qdTAAAAAAAAA+0AAAABAAAAB3VseXNzZXMAAAAXAAAAB3VseXNzZXMAAAAIb2R5c3NldXMAAAAAAAAAAP//////////AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAADMAAAALc3NoLWVkMjU1MTkAAAAgM9BeYRUxUuZ4VHJp8oxVaA8OS/z+5EFPCZwQNq1nMwMAAABTAAAAC3NzaC1lZDI1NTE5AAAAQGCDA6PWw4x9bHQl0w7NqifHepumqD3dmyMx+hZGuPRon+TsyCjfytu7hWmV7l9XUF0fPQNFQ7FGat5e+7YUNgE= id_rsa.pub" +#define PRIV_ECDSA \ +"-----BEGIN OPENSSH PRIVATE KEY-----\n"\ +"b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS\n"\ +"1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQTDJ0VlMv+0rguNzaJ1DF2KueHaxRSQ\n"\ +"6LpIxGbulrg1a8RPbnMXwag5GcDiDllD2lDUJUuBEWyjXA0rZoZX35ELAAAAoE/Bbr5PwW\n"\ +"6+AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMMnRWUy/7SuC43N\n"\ +"onUMXYq54drFFJDoukjEZu6WuDVrxE9ucxfBqDkZwOIOWUPaUNQlS4ERbKNcDStmhlffkQ\n"\ +"sAAAAhAIhE6hCID5oOm1TDktc++KFKyScjLifcZ6Cgv5xSSyLOAAAAAAECAwQFBgc=\n"\ +"-----END OPENSSH PRIVATE KEY-----\n" #define PUB_ECDSA \ "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMMnRWUy/7SuC43NonUMXYq54drFFJDoukjEZu6WuDVrxE9ucxfBqDkZwOIOWUPaUNQlS4ERbKNcDStmhlffkQs=" #define CERT_ECDSA \ From 140ba45895de8ebfb3e2517b0ddee58729979c29 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Fri, 9 May 2025 19:32:06 +1000 Subject: [PATCH 038/244] Move misc-agent.o to LIBSSH_OBJS. It's needed by the fuzzer. --- Makefile.in | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile.in b/Makefile.in index 672bf4493cf8..410a29a123ab 100644 --- a/Makefile.in +++ b/Makefile.in @@ -116,7 +116,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ kexgexc.o kexgexs.o \ kexsntrup761x25519.o kexmlkem768x25519.o sntrup761.o kexgen.o \ sftp-realpath.o platform-pledge.o platform-tracing.o platform-misc.o \ - sshbuf-io.o + sshbuf-io.o misc-agent.o SKOBJS= ssh-sk-client.o @@ -140,7 +140,7 @@ SSHD_SESSION_OBJS=sshd-session.o auth-rhosts.o auth-passwd.o \ auth2-gss.o gss-serv.o gss-serv-krb5.o \ loginrec.o auth-pam.o auth-shadow.o auth-sia.o \ sftp-server.o sftp-common.o \ - uidswap.o platform-listen.o misc-agent.o $(SKOBJS) + uidswap.o platform-listen.o $(SKOBJS) SSHD_AUTH_OBJS=sshd-auth.o \ auth2-methods.o \ @@ -155,7 +155,7 @@ SSHD_AUTH_OBJS=sshd-auth.o \ sandbox-null.o sandbox-rlimit.o sandbox-darwin.o \ sandbox-seccomp-filter.o sandbox-capsicum.o sandbox-solaris.o \ sftp-server.o sftp-common.o \ - uidswap.o misc-agent.o $(SKOBJS) + uidswap.o $(SKOBJS) SFTP_CLIENT_OBJS=sftp-common.o sftp-client.o sftp-glob.o @@ -163,7 +163,7 @@ SCP_OBJS= scp.o progressmeter.o $(SFTP_CLIENT_OBJS) SSHADD_OBJS= ssh-add.o $(SKOBJS) -SSHAGENT_OBJS= ssh-agent.o ssh-pkcs11-client.o misc-agent.o $(SKOBJS) +SSHAGENT_OBJS= ssh-agent.o ssh-pkcs11-client.o $(SKOBJS) SSHKEYGEN_OBJS= ssh-keygen.o sshsig.o $(SKOBJS) From 82f1f52c5582f005761e4e200c279ddd9c6781e4 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Sat, 10 May 2025 06:37:24 +1000 Subject: [PATCH 039/244] Add RUN_ONLY_TEST to limit which tests are run. For testing, you can set the repo variable RUN_ONLY_TEST in your repo (Repo -> Settings -> Security -> Actions -> Variables) to run only that test. --- .github/workflows/c-cpp.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 424c193fb207..b5b6de7fa3fb 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -111,6 +111,12 @@ jobs: - { target: macos-15, config: pam } runs-on: ${{ matrix.target }} steps: + - name: check RUN_ONLY_TEST + # For testing, you can set the repo variable RUN_ONLY_TEST in your repo + # (Repo -> Settings -> Security -> Actions -> Variables) to run only + # that test config. + if: vars.RUN_ONLY_TEST != '' + run: sh -c 'if [ "${{ vars.RUN_ONLY_TEST }}" != "${{ matrix.target }} ${{matrix.config }}" ]; then exit 1; else exit 0; fi' - name: set cygwin git params if: ${{ startsWith(matrix.target, 'windows') }} run: git config --global core.autocrlf input From d5cbac2364b03e55b733a2422a07e78e16d2a118 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Sat, 10 May 2025 07:59:44 +1000 Subject: [PATCH 040/244] Pass Cygwin setup location to CI setup. (instead of hard coding it, wrongly). --- .github/setup_ci.sh | 3 ++- .github/workflows/c-cpp.yml | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/setup_ci.sh b/.github/setup_ci.sh index e4c7b041aa50..81cdc1368fdd 100755 --- a/.github/setup_ci.sh +++ b/.github/setup_ci.sh @@ -192,7 +192,8 @@ while [ ! -z "$PACKAGES" ] && [ "$tries" -gt "0" ]; do fi ;; setup) - if /cygdrive/d/cygwin/setup.exe -q -P `echo "$PACKAGES" | tr ' ' ,`; then + setup="/cygdrive/$(echo "${CYGWIN_SETUP}" | tr -d : | tr '\' '/')" + if "${setup}" -q -P `echo "$PACKAGES" | tr ' ' ,`; then PACKAGES="" fi ;; diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index b5b6de7fa3fb..0807ae8516fc 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -121,11 +121,14 @@ jobs: if: ${{ startsWith(matrix.target, 'windows') }} run: git config --global core.autocrlf input - name: install cygwin + id: cygwin_install if: ${{ startsWith(matrix.target, 'windows') }} uses: cygwin/cygwin-install-action@master - uses: actions/checkout@main - name: setup CI system run: sh ./.github/setup_ci.sh ${{ matrix.config }} + env: + CYGWIN_SETUP: ${{ steps.cygwin_install.outputs.setup }} - name: autoreconf run: sh -c autoreconf - name: configure From 56782dad7d7f96b4943951227515bd7904ac3cf7 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Sat, 10 May 2025 08:26:37 +1000 Subject: [PATCH 041/244] Skip keygen-knownhost test on Cygwin. It fails but at this time it's not clear why. --- .github/configs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/configs b/.github/configs index 2526e3ef4812..50a661dc2cec 100755 --- a/.github/configs +++ b/.github/configs @@ -345,6 +345,8 @@ case "$host" in SUDO="" # Don't run compat tests on cygwin as they don't currently compile. TEST_TARGET="tests" + # Not sure why this tests fails. + SKIP_LTESTS="keygen-knownhosts" ;; *-darwin*) # Unless specified otherwise, build without OpenSSL on Mac OS since From d1b28639c1cb382943bd92c68992ea74af9b5773 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Sat, 10 May 2025 08:52:11 +1000 Subject: [PATCH 042/244] Tell Cygwin to use native symlinks. --- .github/setup_ci.sh | 2 +- .github/workflows/c-cpp.yml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/setup_ci.sh b/.github/setup_ci.sh index 81cdc1368fdd..356823bc6669 100755 --- a/.github/setup_ci.sh +++ b/.github/setup_ci.sh @@ -10,7 +10,7 @@ case "$host" in *cygwin) PACKAGER=setup echo Setting CYGWIN system environment variable. - setx CYGWIN "binmode" + setx CYGWIN "binmode winsymlinks:native" echo Removing extended ACLs so umask works as expected. set -x setfacl -b . regress diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 0807ae8516fc..8c0e0a91b1ee 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -124,6 +124,8 @@ jobs: id: cygwin_install if: ${{ startsWith(matrix.target, 'windows') }} uses: cygwin/cygwin-install-action@master + env: + CYGWIN: "binmode winsymlinks:native" - uses: actions/checkout@main - name: setup CI system run: sh ./.github/setup_ci.sh ${{ matrix.config }} From cf795d55437e6c1ffe85e90e0fae00e885e50036 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Sat, 10 May 2025 09:25:18 +1000 Subject: [PATCH 043/244] Also skip sftp-cmds test on Cygwin. Fails at the hardlink step. --- .github/configs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/configs b/.github/configs index 50a661dc2cec..8e11af25c134 100755 --- a/.github/configs +++ b/.github/configs @@ -144,6 +144,8 @@ case "$config" in TCMALLOC_STACKTRACE_METHOD=generic_fp TEST_SSH_SSHD_ENV="TCMALLOC_STACKTRACE_METHOD=generic_fp" export TCMALLOC_STACKTRACE_METHOD TEST_SSH_SSHD_ENV + + SKIP_LTESTS="agent-restrict" ;; krb5|heimdal) CONFIGFLAGS="--with-kerberos5" @@ -345,8 +347,8 @@ case "$host" in SUDO="" # Don't run compat tests on cygwin as they don't currently compile. TEST_TARGET="tests" - # Not sure why this tests fails. - SKIP_LTESTS="keygen-knownhosts" + # Not sure why these tests fail on github. + SKIP_LTESTS="keygen-knownhosts sftp-cmds" ;; *-darwin*) # Unless specified otherwise, build without OpenSSL on Mac OS since From 8846caccb86b3f5a4f1c10bfffcc9cf1adc17925 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Sat, 10 May 2025 10:23:30 +1000 Subject: [PATCH 044/244] Remove CYGWIN binmode as it's now obsolete. --- .github/setup_ci.sh | 2 +- .github/workflows/c-cpp.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/setup_ci.sh b/.github/setup_ci.sh index 356823bc6669..d7ec2ed11f41 100755 --- a/.github/setup_ci.sh +++ b/.github/setup_ci.sh @@ -10,7 +10,7 @@ case "$host" in *cygwin) PACKAGER=setup echo Setting CYGWIN system environment variable. - setx CYGWIN "binmode winsymlinks:native" + setx CYGWIN "winsymlinks:native" echo Removing extended ACLs so umask works as expected. set -x setfacl -b . regress diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 8c0e0a91b1ee..d83ecd9c331a 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -125,7 +125,7 @@ jobs: if: ${{ startsWith(matrix.target, 'windows') }} uses: cygwin/cygwin-install-action@master env: - CYGWIN: "binmode winsymlinks:native" + CYGWIN: "winsymlinks:native" - uses: actions/checkout@main - name: setup CI system run: sh ./.github/setup_ci.sh ${{ matrix.config }} From ddfb78a15f57a33427d462b9c401de5c8e6799da Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Sat, 10 May 2025 21:48:06 +1000 Subject: [PATCH 045/244] Skip sftp-perm on Cygwin too. --- .github/configs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/configs b/.github/configs index 8e11af25c134..f3235c5a7cad 100755 --- a/.github/configs +++ b/.github/configs @@ -348,7 +348,7 @@ case "$host" in # Don't run compat tests on cygwin as they don't currently compile. TEST_TARGET="tests" # Not sure why these tests fail on github. - SKIP_LTESTS="keygen-knownhosts sftp-cmds" + SKIP_LTESTS="keygen-knownhosts sftp-cmds sftp-perm" ;; *-darwin*) # Unless specified otherwise, build without OpenSSL on Mac OS since From ee1d31781cf0d292a50b4df4cb8cb6ffcbfbe9af Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Sun, 11 May 2025 16:35:31 +1000 Subject: [PATCH 046/244] Move debug log output into separate workflow step. Should reduce the need to scroll back to find out which test actually failed. --- .github/run_test.sh | 12 ------------ .github/workflows/c-cpp.yml | 3 +++ .github/workflows/selfhosted.yml | 3 +++ 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/.github/run_test.sh b/.github/run_test.sh index 74ab2423c0d8..bd6fb7b7b3e1 100755 --- a/.github/run_test.sh +++ b/.github/run_test.sh @@ -21,18 +21,6 @@ if [ ! -z "$SUDO" ] && [ ! -z "$TEST_SSH_HOSTBASED_AUTH" ]; then done fi -output_failed_logs() { - for i in regress/failed*.log; do - if [ -f "$i" ]; then - echo ------------------------------------------------------------------------- - echo LOGFILE $i - cat $i - echo ------------------------------------------------------------------------- - fi - done -} -trap output_failed_logs 0 - env="" if [ ! -z "${SUDO}" ]; then env="${env} SUDO=${SUDO}" diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index d83ecd9c331a..91b07ed97614 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -149,6 +149,9 @@ jobs: env: TEST_SSH_UNSAFE_PERMISSIONS: 1 TEST_SSH_HOSTBASED_AUTH: yes + - name: show logs + if: failure() + run: for i in regress/failed*.log; do echo ====; echo logfile $i; echo =====; cat $i; done - name: save logs if: failure() uses: actions/upload-artifact@main diff --git a/.github/workflows/selfhosted.yml b/.github/workflows/selfhosted.yml index d892a28c3eb6..9f2bd99eb131 100644 --- a/.github/workflows/selfhosted.yml +++ b/.github/workflows/selfhosted.yml @@ -129,6 +129,9 @@ jobs: - name: make tests run: vmrun ./.github/run_test.sh ${{ matrix.config }} timeout-minutes: 600 + - name: show logs + if: failure() + run: vmrun 'for i in regress/failed*.log; do echo ====; echo logfile $i; echo =====; cat $i; done' - name: save logs if: failure() uses: actions/upload-artifact@main From c404686c17daeda7e95ca6fc14c8a4a570cf975d Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Sun, 11 May 2025 22:54:13 +1000 Subject: [PATCH 047/244] Debug log for why an account is considered locked. --- platform.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/platform.c b/platform.c index 4c4fe57ea09a..fd1a7a7c205c 100644 --- a/platform.c +++ b/platform.c @@ -183,17 +183,26 @@ platform_locked_account(struct passwd *pw) /* check for locked account */ if (passwd && *passwd) { #ifdef LOCKED_PASSWD_STRING - if (strcmp(passwd, LOCKED_PASSWD_STRING) == 0) + if (strcmp(passwd, LOCKED_PASSWD_STRING) == 0) { + debug3_f("password matches locked string '%s'", + LOCKED_PASSWD_STRING); locked = 1; + } #endif #ifdef LOCKED_PASSWD_PREFIX if (strncmp(passwd, LOCKED_PASSWD_PREFIX, - strlen(LOCKED_PASSWD_PREFIX)) == 0) + strlen(LOCKED_PASSWD_PREFIX)) == 0) { + debug3_f("password matches locked prefix '%s'", + LOCKED_PASSWD_PREFIX); locked = 1; + } #endif #ifdef LOCKED_PASSWD_SUBSTR - if (strstr(passwd, LOCKED_PASSWD_SUBSTR)) + if (strstr(passwd, LOCKED_PASSWD_SUBSTR)) { + debug3_f("password matches locked substring '%s'", + LOCKED_PASSWD_SUBSTR); locked = 1; + } #endif } #ifdef USE_LIBIAF From fc8c56ade809f66f7df4b5153a4d92593631c12a Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Tue, 20 May 2025 15:01:29 +1000 Subject: [PATCH 048/244] Set runner pasword to random string. The most recent version of the Github ubuntu-latest image sets the password field to "!" which sshd considers to be a locked account, breaking most of the tests. --- .github/setup_ci.sh | 17 +++++++++++++++-- .github/workflows/c-cpp.yml | 2 +- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.github/setup_ci.sh b/.github/setup_ci.sh index d7ec2ed11f41..e4b266a18c21 100755 --- a/.github/setup_ci.sh +++ b/.github/setup_ci.sh @@ -1,8 +1,11 @@ #!/bin/sh +config="$1" +target="$2" + PACKAGES="" - . .github/configs $@ + . .github/configs ${config} host=`./config.guess` echo "config.guess: $host" @@ -32,7 +35,7 @@ case "$host" in PACKAGER=apt esac -TARGETS=$@ +TARGETS=${config} INSTALL_FIDO_PPA="no" export DEBIAN_FRONTEND=noninteractive @@ -289,3 +292,13 @@ if [ ! -z "${INSTALL_PUTTY}" ]; then ) /usr/local/bin/plink -V fi + +# This is the github "target" as specificed in the yml file. +case "${target}" in +ubuntu-latest) + echo ubuntu-latest target: setting random password string. + pw=$(openssl rand -base64 9) + sudo usermod --password "${pw}" runner + sudo usermod --unlock runner + ;; +esac diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 91b07ed97614..7c37c9ce2cb1 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -128,7 +128,7 @@ jobs: CYGWIN: "winsymlinks:native" - uses: actions/checkout@main - name: setup CI system - run: sh ./.github/setup_ci.sh ${{ matrix.config }} + run: sh ./.github/setup_ci.sh ${{ matrix.config }} ${{ matrix.target }} env: CYGWIN_SETUP: ${{ steps.cygwin_install.outputs.setup }} - name: autoreconf From 2d023e7a95d673e93ccc1978bf8931f7335b2b53 Mon Sep 17 00:00:00 2001 From: "tedu@openbsd.org" Date: Thu, 8 May 2025 17:32:53 +0000 Subject: [PATCH 049/244] upstream: convert a last quad_t to int64_t. ok deraadt djm OpenBSD-Commit-ID: 1c9e01ba1a9ccf442a9cdf10f222077f66885f1f --- auth-passwd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/auth-passwd.c b/auth-passwd.c index 347d91e25192..a9d768891575 100644 --- a/auth-passwd.c +++ b/auth-passwd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth-passwd.c,v 1.48 2020/10/18 11:32:01 djm Exp $ */ +/* $OpenBSD: auth-passwd.c,v 1.49 2025/05/08 17:32:53 tedu Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -133,7 +133,7 @@ static void warn_expiry(Authctxt *authctxt, auth_session_t *as) { int r; - quad_t pwtimeleft, actimeleft, daysleft, pwwarntime, acwarntime; + int64_t pwtimeleft, actimeleft, daysleft, pwwarntime, acwarntime; pwwarntime = acwarntime = TWO_WEEKS; From 17003b9f1cd7b7bf1f52493cc4a1ab95727c3ed7 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Fri, 9 May 2025 02:42:03 +0000 Subject: [PATCH 050/244] upstream: make the progress-meter code safe against being called when not initialised; spotted by tb@ feedback/ok tb@ deraadt@ OpenBSD-Commit-ID: a9fda1ee08a24c62e0981ff6d15ca93b63467038 --- progressmeter.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/progressmeter.c b/progressmeter.c index f1712da30df4..0d1faba398c1 100644 --- a/progressmeter.c +++ b/progressmeter.c @@ -1,4 +1,4 @@ -/* $OpenBSD: progressmeter.c,v 1.54 2024/09/22 12:56:21 jsg Exp $ */ +/* $OpenBSD: progressmeter.c,v 1.55 2025/05/09 02:42:03 djm Exp $ */ /* * Copyright (c) 2003 Nils Nordman. All rights reserved. * @@ -132,7 +132,8 @@ refresh_progress_meter(int force_update) int hours, minutes, seconds; int file_len, cols; - if ((!force_update && !alarm_fired && !win_resized) || !can_output()) + if (file == NULL || (!force_update && !alarm_fired && !win_resized) || + !can_output()) return; alarm_fired = 0; @@ -276,6 +277,7 @@ stop_progress_meter(void) refresh_progress_meter(1); atomicio(vwrite, STDOUT_FILENO, "\n", 1); + file = NULL; } static void From 2d35e24739b515394017b74465a0996c384cf28f Mon Sep 17 00:00:00 2001 From: "tb@openbsd.org" Date: Mon, 12 May 2025 05:41:20 +0000 Subject: [PATCH 051/244] upstream: Use EC_POINT_[sg]et_affine_coordinates() It is available in all supported OpenSSL flavors/versions and the _GFp variants will be removed from LibreSSL. ok hshoexer jsing OpenBSD-Commit-ID: ecedca0e1ffa80e0c9ef7c787bc6a972882c596b --- sk-usbhid.c | 6 +++--- sshkey.c | 10 ++++------ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/sk-usbhid.c b/sk-usbhid.c index 427431b9a457..e2fa0b499af6 100644 --- a/sk-usbhid.c +++ b/sk-usbhid.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sk-usbhid.c,v 1.47 2024/12/03 08:31:49 djm Exp $ */ +/* $OpenBSD: sk-usbhid.c,v 1.48 2025/05/12 05:41:20 tb Exp $ */ /* * Copyright (c) 2019 Markus Friedl * Copyright (c) 2020 Pedro Martelletto @@ -636,8 +636,8 @@ pack_public_key_ecdsa(const fido_cred_t *cred, skdebug(__func__, "BN_bin2bn failed"); goto out; } - if (EC_POINT_set_affine_coordinates_GFp(g, q, x, y, NULL) != 1) { - skdebug(__func__, "EC_POINT_set_affine_coordinates_GFp failed"); + if (EC_POINT_set_affine_coordinates(g, q, x, y, NULL) != 1) { + skdebug(__func__, "EC_POINT_set_affine_coordinates failed"); goto out; } response->public_key_len = EC_POINT_point2oct(g, q, diff --git a/sshkey.c b/sshkey.c index 55a156818962..9e31411e21d6 100644 --- a/sshkey.c +++ b/sshkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshkey.c,v 1.149 2025/05/06 05:40:56 djm Exp $ */ +/* $OpenBSD: sshkey.c,v 1.150 2025/05/12 05:41:20 tb Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * Copyright (c) 2008 Alexander von Gernler. All rights reserved. @@ -2707,8 +2707,7 @@ sshkey_ec_validate_public(const EC_GROUP *group, const EC_POINT *public) /* log2(x) > log2(order)/2, log2(y) > log2(order)/2 */ if (EC_GROUP_get_order(group, order, NULL) != 1 || - EC_POINT_get_affine_coordinates_GFp(group, public, - x, y, NULL) != 1) { + EC_POINT_get_affine_coordinates(group, public, x, y, NULL) != 1) { ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } @@ -2792,9 +2791,8 @@ sshkey_dump_ec_point(const EC_GROUP *group, const EC_POINT *point) fprintf(stderr, "%s: BN_new failed\n", __func__); goto out; } - if (EC_POINT_get_affine_coordinates_GFp(group, point, - x, y, NULL) != 1) { - fprintf(stderr, "%s: EC_POINT_get_affine_coordinates_GFp\n", + if (EC_POINT_get_affine_coordinates(group, point, x, y, NULL) != 1) { + fprintf(stderr, "%s: EC_POINT_get_affine_coordinates\n", __func__); goto out; } From cff2175200b412a9207a4fe5c1bdcc54e8a73d07 Mon Sep 17 00:00:00 2001 From: "tb@openbsd.org" Date: Mon, 12 May 2025 05:42:02 +0000 Subject: [PATCH 052/244] upstream: Use EC_POINT_[sg]et_affine_coordinates() It is available in all supported OpenSSL flavors/versions and the _GFp variants will be removed from LibreSSL. ok hshoexer jsing OpenBSD-Regress-ID: 66cf1561e7b6c49002978f2d6720956f33a882f0 --- .../misc/ssh-verify-attestation/ssh-verify-attestation.c | 6 +++--- regress/unittests/sshbuf/test_sshbuf_getput_crypto.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/regress/misc/ssh-verify-attestation/ssh-verify-attestation.c b/regress/misc/ssh-verify-attestation/ssh-verify-attestation.c index 4d82a0390587..9316805e0cc5 100644 --- a/regress/misc/ssh-verify-attestation/ssh-verify-attestation.c +++ b/regress/misc/ssh-verify-attestation/ssh-verify-attestation.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-verify-attestation.c,v 1.2 2024/12/06 10:37:42 djm Exp $ */ +/* $OpenBSD: ssh-verify-attestation.c,v 1.3 2025/05/12 05:42:02 tb Exp $ */ /* * Copyright (c) 2022-2024 Damien Miller * @@ -164,8 +164,8 @@ get_pubkey_from_cred_ecdsa(const fido_cred_t *cred, size_t *pubkey_len) error_f("BN_bin2bn failed"); goto out; } - if (EC_POINT_set_affine_coordinates_GFp(g, q, x, y, NULL) != 1) { - error_f("EC_POINT_set_affine_coordinates_GFp failed"); + if (EC_POINT_set_affine_coordinates(g, q, x, y, NULL) != 1) { + error_f("EC_POINT_set_affine_coordinates failed"); goto out; } *pubkey_len = EC_POINT_point2oct(g, q, diff --git a/regress/unittests/sshbuf/test_sshbuf_getput_crypto.c b/regress/unittests/sshbuf/test_sshbuf_getput_crypto.c index e3620e97fe99..48573ae82967 100644 --- a/regress/unittests/sshbuf/test_sshbuf_getput_crypto.c +++ b/regress/unittests/sshbuf/test_sshbuf_getput_crypto.c @@ -1,4 +1,4 @@ -/* $OpenBSD: test_sshbuf_getput_crypto.c,v 1.3 2021/12/14 21:25:27 deraadt Exp $ */ +/* $OpenBSD: test_sshbuf_getput_crypto.c,v 1.4 2025/05/12 05:42:02 tb Exp $ */ /* * Regress test for sshbuf.h buffer API * @@ -230,7 +230,7 @@ sshbuf_getput_crypto_tests(void) ASSERT_PTR_NE(ecp, NULL); MKBN(ec256_x, bn_x); MKBN(ec256_y, bn_y); - ASSERT_INT_EQ(EC_POINT_set_affine_coordinates_GFp( + ASSERT_INT_EQ(EC_POINT_set_affine_coordinates( EC_KEY_get0_group(eck), ecp, bn_x, bn_y, NULL), 1); ASSERT_INT_EQ(EC_KEY_set_public_key(eck, ecp), 1); BN_free(bn_x); @@ -259,7 +259,7 @@ sshbuf_getput_crypto_tests(void) bn_y = BN_new(); ASSERT_PTR_NE(bn_x, NULL); ASSERT_PTR_NE(bn_y, NULL); - ASSERT_INT_EQ(EC_POINT_get_affine_coordinates_GFp( + ASSERT_INT_EQ(EC_POINT_get_affine_coordinates( EC_KEY_get0_group(eck), EC_KEY_get0_public_key(eck), bn_x, bn_y, NULL), 1); MKBN(ec256_x, bn); From 1a9b1cfa4e8b807c7f82fdba8f730c2abdbba071 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Tue, 20 May 2025 18:14:06 +1000 Subject: [PATCH 053/244] Add compat shims for EC_POINT affine_coordinates LibreSSL <3.4 does not have EC_POINT_[gs]et_affine_coordinates but does have the now-deprecated _GFp variantes. We still support LibreSSL back as far as 3.2.x so add a compat shim. --- configure.ac | 4 ++++ openbsd-compat/openssl-compat.h | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/configure.ac b/configure.ac index 98d98594b5c8..94e782e1563b 100644 --- a/configure.ac +++ b/configure.ac @@ -3107,6 +3107,10 @@ if test "x$openssl" = "xyes" ; then # LibreSSL/OpenSSL API differences AC_CHECK_FUNCS([ \ + EC_POINT_get_affine_coordinates \ + EC_POINT_get_affine_coordinates_GFp \ + EC_POINT_set_affine_coordinates \ + EC_POINT_set_affine_coordinates_GFp \ EVP_CIPHER_CTX_iv \ EVP_CIPHER_CTX_iv_noconst \ EVP_CIPHER_CTX_get_iv \ diff --git a/openbsd-compat/openssl-compat.h b/openbsd-compat/openssl-compat.h index 936f4068d843..4539d8d50002 100644 --- a/openbsd-compat/openssl-compat.h +++ b/openbsd-compat/openssl-compat.h @@ -60,6 +60,20 @@ void ssh_libcrypto_init(void); # define BN_set_flags(a, b) #endif +/* LibreSSL <3.4 has the _GFp variants but not the equivalent modern ones. */ +#ifndef HAVE_EC_POINT_GET_AFFINE_COORDINATES +# ifdef HAVE_EC_POINT_GET_AFFINE_COORDINATES_GFP +# define EC_POINT_get_affine_coordinates(a, b, c, d, e) \ + (EC_POINT_get_affine_coordinates_GFp(a, b, c, d, e)) +# endif +#endif +#ifndef HAVE_EC_POINT_SET_AFFINE_COORDINATES +# ifdef HAVE_EC_POINT_SET_AFFINE_COORDINATES_GFP +# define EC_POINT_set_affine_coordinates(a, b, c, d, e) \ + (EC_POINT_set_affine_coordinates_GFp(a, b, c, d, e)) +# endif +#endif + #ifndef HAVE_EVP_CIPHER_CTX_GET_IV # ifdef HAVE_EVP_CIPHER_CTX_GET_UPDATED_IV # define EVP_CIPHER_CTX_get_iv EVP_CIPHER_CTX_get_updated_iv From 9d9a2c0369419f3b4952e597db7b8696f54e7f3a Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Tue, 20 May 2025 19:16:38 +1000 Subject: [PATCH 054/244] Include openssl compat shims in test. Fixes tests on platforms using older LibreSSL releases prior to 3.4. --- regress/unittests/sshbuf/test_sshbuf_getput_crypto.c | 1 + 1 file changed, 1 insertion(+) diff --git a/regress/unittests/sshbuf/test_sshbuf_getput_crypto.c b/regress/unittests/sshbuf/test_sshbuf_getput_crypto.c index 48573ae82967..46a96fdadb38 100644 --- a/regress/unittests/sshbuf/test_sshbuf_getput_crypto.c +++ b/regress/unittests/sshbuf/test_sshbuf_getput_crypto.c @@ -22,6 +22,7 @@ #ifdef OPENSSL_HAS_NISTP256 # include #endif +#include "openbsd-compat/openssl-compat.h" #include "../test_helper/test_helper.h" #include "ssherr.h" From 0214e53124c09528b6ee29b9a551442b5611a454 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Tue, 20 May 2025 18:28:52 +1000 Subject: [PATCH 055/244] Add debug output when setting up CI environment. --- .github/setup_ci.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/setup_ci.sh b/.github/setup_ci.sh index e4b266a18c21..c4473f2f71b4 100755 --- a/.github/setup_ci.sh +++ b/.github/setup_ci.sh @@ -5,6 +5,12 @@ target="$2" PACKAGES="" +echo Running as: +id + +echo Environment: +set + . .github/configs ${config} host=`./config.guess` From 648a3a008cf1cfa54631d2f0457b5313c455f484 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Tue, 20 May 2025 18:48:23 +1000 Subject: [PATCH 056/244] Use USERNAME rather than LOGNAME on Cygwin. LOGNAME is specified by POSIX, but Windows (or at least, github's Windows images) don't set it. --- .github/setup_ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/setup_ci.sh b/.github/setup_ci.sh index c4473f2f71b4..5e778d377136 100755 --- a/.github/setup_ci.sh +++ b/.github/setup_ci.sh @@ -24,7 +24,7 @@ case "$host" in set -x setfacl -b . regress icacls regress /c /t /q /Inheritance:d - icacls regress /c /t /q /Grant ${LOGNAME}:F + icacls regress /c /t /q /Grant ${USERNAME}:F icacls regress /c /t /q /Remove:g "Authenticated Users" \ BUILTIN\\Administrators BUILTIN Everyone System Users takeown /F regress From 6fb728df50c1afd338cb0223a84ce24579577eff Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Tue, 20 May 2025 19:28:55 +1000 Subject: [PATCH 057/244] Run all tests on Cygwin again. ... now that we've fixed ci-setup on Cygwin. --- .github/configs | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/configs b/.github/configs index f3235c5a7cad..a1059f935943 100755 --- a/.github/configs +++ b/.github/configs @@ -347,8 +347,6 @@ case "$host" in SUDO="" # Don't run compat tests on cygwin as they don't currently compile. TEST_TARGET="tests" - # Not sure why these tests fail on github. - SKIP_LTESTS="keygen-knownhosts sftp-cmds sftp-perm" ;; *-darwin*) # Unless specified otherwise, build without OpenSSL on Mac OS since From 750f1867476bda36879f69e25e8f52cb45c58807 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Tue, 20 May 2025 22:17:02 +1000 Subject: [PATCH 058/244] Include OpenSSL compat shim where needed. --- regress/misc/ssh-verify-attestation/ssh-verify-attestation.c | 1 + sk-usbhid.c | 1 + 2 files changed, 2 insertions(+) diff --git a/regress/misc/ssh-verify-attestation/ssh-verify-attestation.c b/regress/misc/ssh-verify-attestation/ssh-verify-attestation.c index 9316805e0cc5..da7f5a23366c 100644 --- a/regress/misc/ssh-verify-attestation/ssh-verify-attestation.c +++ b/regress/misc/ssh-verify-attestation/ssh-verify-attestation.c @@ -70,6 +70,7 @@ #include #include #include +#include "openbsd-compat/openssl-compat.h" extern char *__progname; diff --git a/sk-usbhid.c b/sk-usbhid.c index e2fa0b499af6..c18c40df2db6 100644 --- a/sk-usbhid.c +++ b/sk-usbhid.c @@ -49,6 +49,7 @@ #include #include #include +#include "openbsd-compat/openssl-compat.h" #endif /* WITH_OPENSSL */ #include From 83729cf503289104d7e64a69be14579523988cb6 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Wed, 21 May 2025 18:47:46 +1000 Subject: [PATCH 059/244] merge netcat SOCKS4A support from OpenBSD Not a full sync of this file as we have diverged substantially from upstream (it has libtls support, etc.) --- regress/netcat.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/regress/netcat.c b/regress/netcat.c index 20ec3f5954fa..51e999df6d68 100644 --- a/regress/netcat.c +++ b/regress/netcat.c @@ -185,6 +185,8 @@ main(int argc, char *argv[]) socksv = -1; /* HTTP proxy CONNECT */ else if (strcmp(optarg, "4") == 0) socksv = 4; /* SOCKS v.4 */ + else if (strcasecmp(optarg, "4A") == 0) + socksv = 44; /* SOCKS v.4A */ else if (strcmp(optarg, "5") == 0) socksv = 5; /* SOCKS v.5 */ else @@ -1586,7 +1588,7 @@ socks_connect(const char *host, const char *port, default: errx(1, "connection failed, unsupported address type"); } - } else if (socksv == 4) { + } else if (socksv == 4 || socksv == 44) { /* This will exit on lookup failure */ decode_addrport(host, port, (struct sockaddr *)&addr, sizeof(addr), 1, 0); @@ -1595,10 +1597,22 @@ socks_connect(const char *host, const char *port, buf[0] = SOCKS_V4; buf[1] = SOCKS_CONNECT; /* connect */ memcpy(buf + 2, &in4->sin_port, sizeof in4->sin_port); - memcpy(buf + 4, &in4->sin_addr, sizeof in4->sin_addr); + if (socksv == 4) { + memcpy(buf + 4, &in4->sin_addr, sizeof in4->sin_addr); + } else { + /* SOCKS4A uses addr of 0.0.0.x, and hostname later */ + buf[4] = buf[5] = buf[6] = 0; + buf[7] = 1; + } buf[8] = 0; /* empty username */ wlen = 9; - + if (socksv == 44) { + /* SOCKS4A has nul-terminated hostname after user */ + if (strlcpy(buf + 9, host, + sizeof(buf) - 9) >= sizeof(buf) - 9) + errx(1, "hostname too big"); + wlen = 9 + strlen(host) + 1; + } cnt = atomicio(vwrite, proxyfd, buf, wlen); if (cnt != wlen) err(1, "write failed (%zu/%zu)", cnt, wlen); From 1743589d038476f28dc4dfb1f69317649ae22ac5 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Wed, 21 May 2025 06:43:48 +0000 Subject: [PATCH 060/244] upstream: function to make a sshbuf from a hex string; useful in tests also constify some arguments OpenBSD-Commit-ID: 00f9c25b256be0efd73f2d8268ff041bc45ffb2c --- sshbuf-misc.c | 40 ++++++++++++++++++++++++++++++++++++++-- sshbuf.h | 6 ++++-- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/sshbuf-misc.c b/sshbuf-misc.c index 9c5c42bba70a..adbf9903b4d8 100644 --- a/sshbuf-misc.c +++ b/sshbuf-misc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshbuf-misc.c,v 1.18 2022/01/22 00:43:43 djm Exp $ */ +/* $OpenBSD: sshbuf-misc.c,v 1.19 2025/05/21 06:43:48 djm Exp $ */ /* * Copyright (c) 2011 Damien Miller * @@ -71,7 +71,7 @@ sshbuf_dump(const struct sshbuf *buf, FILE *f) } char * -sshbuf_dtob16(struct sshbuf *buf) +sshbuf_dtob16(const struct sshbuf *buf) { size_t i, j, len = sshbuf_len(buf); const u_char *p = sshbuf_ptr(buf); @@ -90,6 +90,42 @@ sshbuf_dtob16(struct sshbuf *buf) return ret; } +static int +b16tod(const char v) +{ + if (v >= '0' && v <= '9') + return v - '0'; + if (v >= 'a' && v <= 'f') + return 10 + v - 'a'; + if (v >= 'A' && v <= 'A') + return 10 + v - 'A'; + return -1; +} + +struct sshbuf * +sshbuf_b16tod(const char *b16) +{ + struct sshbuf *ret; + size_t o; + int r, v1, v2; + + if ((ret = sshbuf_new()) == NULL) + return NULL; + for (o = 0; b16[o] != '\0'; o += 2) { + if ((v1 = b16tod(b16[o])) == -1 || + (v2 = b16tod(b16[o + 1])) == -1) { + sshbuf_free(ret); + return NULL; + } + if ((r = sshbuf_put_u8(ret, (u_char)((v1 << 4) | v2))) != 0) { + sshbuf_free(ret); + return NULL; + } + } + /* success */ + return ret; +} + int sshbuf_dtob64(const struct sshbuf *d, struct sshbuf *b64, int wrap) { diff --git a/sshbuf.h b/sshbuf.h index 49c32af8fbb7..681abb9eec03 100644 --- a/sshbuf.h +++ b/sshbuf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sshbuf.h,v 1.29 2024/08/15 00:51:51 djm Exp $ */ +/* $OpenBSD: sshbuf.h,v 1.30 2025/05/21 06:43:48 djm Exp $ */ /* * Copyright (c) 2011 Damien Miller * @@ -235,7 +235,9 @@ void sshbuf_dump(const struct sshbuf *buf, FILE *f); void sshbuf_dump_data(const void *s, size_t len, FILE *f); /* Return the hexadecimal representation of the contents of the buffer */ -char *sshbuf_dtob16(struct sshbuf *buf); +char *sshbuf_dtob16(const struct sshbuf *buf); +/* Make a sshbuf from a hex string */ +struct sshbuf *sshbuf_b16tod(const char *b16); /* Encode the contents of the buffer as base64 */ char *sshbuf_dtob64_string(const struct sshbuf *buf, int wrap); From 0c14e6b69a20f20d602e0e72559ca3f4dbc797fb Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Wed, 21 May 2025 06:44:24 +0000 Subject: [PATCH 061/244] upstream: use logit_f("...") instead of logit("func: ...") OpenBSD-Commit-ID: c8d49eb39a9abff3cbcaeaf7df9d48468a5a0695 --- dispatch.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dispatch.c b/dispatch.c index 6118147bf140..430b6afda1d3 100644 --- a/dispatch.c +++ b/dispatch.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dispatch.c,v 1.33 2023/03/05 05:34:09 dtucker Exp $ */ +/* $OpenBSD: dispatch.c,v 1.34 2025/05/21 06:44:24 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -41,7 +41,7 @@ dispatch_protocol_error(int type, u_int32_t seq, struct ssh *ssh) { int r; - logit("dispatch_protocol_error: type %d seq %u", type, seq); + logit_f("type %d seq %u", type, seq); if ((r = sshpkt_start(ssh, SSH2_MSG_UNIMPLEMENTED)) != 0 || (r = sshpkt_put_u32(ssh, seq)) != 0 || (r = sshpkt_send(ssh)) != 0 || @@ -53,7 +53,7 @@ dispatch_protocol_error(int type, u_int32_t seq, struct ssh *ssh) int dispatch_protocol_ignore(int type, u_int32_t seq, struct ssh *ssh) { - logit("dispatch_protocol_ignore: type %d seq %u", type, seq); + logit_f("type %d seq %u", type, seq); return 0; } From 5699f4e9553c6a228fd9dc578d99e3aa6451c014 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Wed, 21 May 2025 08:36:39 +0000 Subject: [PATCH 062/244] upstream: remove log tarballing "it seemed like a good idea at the time" - dtucker@ ensure that log files have correct perms when running under sudo/doas ok dtucker@ OpenBSD-Regress-ID: 20588c14b05de9519f85d638b374b66ae0678c89 --- regress/test-exec.sh | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/regress/test-exec.sh b/regress/test-exec.sh index 8a00c729cf67..714636f6ebfc 100644 --- a/regress/test-exec.sh +++ b/regress/test-exec.sh @@ -1,4 +1,4 @@ -# $OpenBSD: test-exec.sh,v 1.127 2025/03/28 05:41:15 dtucker Exp $ +# $OpenBSD: test-exec.sh,v 1.128 2025/05/21 08:36:39 djm Exp $ # Placed in the Public Domain. #SUDO=sudo @@ -535,6 +535,7 @@ save_debug_log () $SUDO chown -R $USER $logfile fi done + test -z "$SUDO" || $SUDO chmod ug+rw $TEST_SSHD_LOGFILE echo $@ >>$TEST_REGRESS_LOGFILE echo $@ >>$TEST_SSH_LOGFILE echo $@ >>$TEST_SSHD_LOGFILE @@ -542,19 +543,6 @@ save_debug_log () (cat $TEST_REGRESS_LOGFILE; echo) >>$OBJ/failed-regress.log (cat $TEST_SSH_LOGFILE; echo) >>$OBJ/failed-ssh.log (cat $TEST_SSHD_LOGFILE; echo) >>$OBJ/failed-sshd.log - - # Save all logfiles in a tarball. - (cd $OBJ && - logfiles="" - for i in $TEST_REGRESS_LOGFILE $TEST_SSH_LOGFILE $TEST_SSHD_LOGFILE \ - $TEST_SSH_LOGDIR; do - if [ -e "`basename $i`" ]; then - logfiles="$logfiles `basename $i`" - else - logfiles="$logfiles $i" - fi - done - tar cf "$tarname" $logfiles) } trace () From 0adb2db25eff3fe1c90c55654387ae1e4e18a396 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Wed, 21 May 2025 08:41:52 +0000 Subject: [PATCH 063/244] upstream: test SOCKS4A; ok tb OpenBSD-Regress-ID: d880b75280295cd581a86e39bb0996d347f122d2 --- regress/dynamic-forward.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/regress/dynamic-forward.sh b/regress/dynamic-forward.sh index 85901eaa6340..6cc47e7605e1 100644 --- a/regress/dynamic-forward.sh +++ b/regress/dynamic-forward.sh @@ -1,4 +1,4 @@ -# $OpenBSD: dynamic-forward.sh,v 1.17 2024/03/08 11:34:10 dtucker Exp $ +# $OpenBSD: dynamic-forward.sh,v 1.18 2025/05/21 08:41:52 djm Exp $ # Placed in the Public Domain. tid="dynamic forwarding" @@ -54,7 +54,7 @@ stop_ssh() { check_socks() { direction=$1 expect_success=$2 - for s in 4 5; do + for s in 4A 4 5; do for h in 127.0.0.1 localhost; do trace "testing ssh socks version $s host $h (-$direction)" ${REAL_SSH} -q -F $OBJ/ssh_config -o \ From b71773c20d566fa5dcaf9edf3139bdcb3f2c4bc2 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Wed, 21 May 2025 19:14:47 +1000 Subject: [PATCH 064/244] pull a small netcat SOCKS4A fix from upstream --- regress/netcat.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/regress/netcat.c b/regress/netcat.c index 51e999df6d68..1eac0218aaf1 100644 --- a/regress/netcat.c +++ b/regress/netcat.c @@ -1589,9 +1589,11 @@ socks_connect(const char *host, const char *port, errx(1, "connection failed, unsupported address type"); } } else if (socksv == 4 || socksv == 44) { - /* This will exit on lookup failure */ - decode_addrport(host, port, (struct sockaddr *)&addr, - sizeof(addr), 1, 0); + if (socksv == 4) { + /* This will exit on lookup failure */ + decode_addrport(host, port, (struct sockaddr *)&addr, + sizeof(addr), 1, 0); + } /* Version 4 */ buf[0] = SOCKS_V4; From e391c5289c2b687ff886cf780dc8fcb426e4d5d2 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Thu, 22 May 2025 10:52:31 +1000 Subject: [PATCH 065/244] Remove 9.7 branch from CI status page. It's been obsolete long enough that github no longer reports its status. --- .github/ci-status.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/ci-status.md b/.github/ci-status.md index d47e59e1e5ea..971011db96fa 100644 --- a/.github/ci-status.md +++ b/.github/ci-status.md @@ -17,7 +17,3 @@ master : 9.8 : [![C/C++ CI](https://github.com/openssh/openssh-portable/actions/workflows/c-cpp.yml/badge.svg?branch=V_9_8)](https://github.com/openssh/openssh-portable/actions/workflows/c-cpp.yml?query=branch:V_9_8) [![C/C++ CI self-hosted](https://github.com/openssh/openssh-portable-selfhosted/actions/workflows/selfhosted.yml/badge.svg?branch=V_9_8)](https://github.com/openssh/openssh-portable-selfhosted/actions/workflows/selfhosted.yml?query=branch:V_9_8) - -9.7 : -[![C/C++ CI](https://github.com/openssh/openssh-portable/actions/workflows/c-cpp.yml/badge.svg?branch=V_9_7)](https://github.com/openssh/openssh-portable/actions/workflows/c-cpp.yml?query=branch:V_9_7) -[![C/C++ CI self-hosted](https://github.com/openssh/openssh-portable-selfhosted/actions/workflows/selfhosted.yml/badge.svg?branch=V_9_7)](https://github.com/openssh/openssh-portable-selfhosted/actions/workflows/selfhosted.yml?query=branch:V_9_7) From df22801b3f0ae245f825cf9c9dbb4543e41a7c5c Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Thu, 22 May 2025 11:34:04 +1000 Subject: [PATCH 066/244] Install nc during upstream test. This ensures that the installed nc matches the expectations of the regress tests. --- .github/workflows/upstream.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/upstream.yml b/.github/workflows/upstream.yml index 615a7763fb9b..b603d410b025 100644 --- a/.github/workflows/upstream.yml +++ b/.github/workflows/upstream.yml @@ -43,7 +43,9 @@ jobs: run: sshfs_mount working-directory: ${{ runner.temp }} - name: update source - run: vmrun "cd /usr/src && cvs up -dPA usr.bin/ssh regress/usr.bin/ssh" + run: vmrun "cd /usr/src && cvs up -dPA {regress/,}usr.bin/{ssh,nc}" + - name: install netcat + run: vmrun "cd /usr/src/usr.bin/nc && make obj clean nc && sudo make install" - name: make clean run: vmrun "cd /usr/src/usr.bin/ssh && make obj && make clean && cd /usr/src/regress/usr.bin/ssh && make obj && make clean && sudo chmod -R g-w /usr/src /usr/obj" - name: make From 49a2412ad23162e44be9e0b2cb12f6daf6b666d7 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Thu, 22 May 2025 12:21:11 +1000 Subject: [PATCH 067/244] Fix cvs up of nc. --- .github/workflows/upstream.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/upstream.yml b/.github/workflows/upstream.yml index b603d410b025..9bf66ceb4aa3 100644 --- a/.github/workflows/upstream.yml +++ b/.github/workflows/upstream.yml @@ -43,8 +43,8 @@ jobs: run: sshfs_mount working-directory: ${{ runner.temp }} - name: update source - run: vmrun "cd /usr/src && cvs up -dPA {regress/,}usr.bin/{ssh,nc}" - - name: install netcat + run: vmrun "cd /usr/src && cvs up -dPA usr.bin/ssh regress/usr.bin/ssh usr.bin/nc" + - name: update netcat run: vmrun "cd /usr/src/usr.bin/nc && make obj clean nc && sudo make install" - name: make clean run: vmrun "cd /usr/src/usr.bin/ssh && make obj && make clean && cd /usr/src/regress/usr.bin/ssh && make obj && make clean && sudo chmod -R g-w /usr/src /usr/obj" From d1d5c8b9b8de8283618c18d0dafdec6a209911cc Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Thu, 22 May 2025 12:25:35 +1000 Subject: [PATCH 068/244] Fix nc install some more. --- .github/workflows/upstream.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/upstream.yml b/.github/workflows/upstream.yml index 9bf66ceb4aa3..9e74f94a74d1 100644 --- a/.github/workflows/upstream.yml +++ b/.github/workflows/upstream.yml @@ -43,9 +43,9 @@ jobs: run: sshfs_mount working-directory: ${{ runner.temp }} - name: update source - run: vmrun "cd /usr/src && cvs up -dPA usr.bin/ssh regress/usr.bin/ssh usr.bin/nc" + run: vmrun "cd /usr/src && cvs -q up -dPA usr.bin/ssh regress/usr.bin/ssh usr.bin/nc" - name: update netcat - run: vmrun "cd /usr/src/usr.bin/nc && make obj clean nc && sudo make install" + run: vmrun "cd /usr/src/usr.bin/nc && make clean all && sudo make install" - name: make clean run: vmrun "cd /usr/src/usr.bin/ssh && make obj && make clean && cd /usr/src/regress/usr.bin/ssh && make obj && make clean && sudo chmod -R g-w /usr/src /usr/obj" - name: make From 58d094c7cb974d7bd3ba6eb1059b186a2ac3dd55 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Wed, 21 May 2025 12:12:20 +0000 Subject: [PATCH 069/244] upstream: Correct FILES section to mention new default path to agent sockets. Spotted by / ok jmc@ OpenBSD-Commit-ID: 91d736d78d71a4276c9cbb075b1462bbc3df55a6 --- ssh-agent.1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ssh-agent.1 b/ssh-agent.1 index 9f56e3efdc08..58258be49b4e 100644 --- a/ssh-agent.1 +++ b/ssh-agent.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-agent.1,v 1.84 2025/05/05 05:47:28 jmc Exp $ +.\" $OpenBSD: ssh-agent.1,v 1.85 2025/05/21 12:12:20 djm Exp $ .\" .\" Author: Tatu Ylonen .\" Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -34,7 +34,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd $Mdocdate: May 5 2025 $ +.Dd $Mdocdate: May 21 2025 $ .Dt SSH-AGENT 1 .Os .Sh NAME @@ -308,7 +308,7 @@ but is easily abused by root or another instance of the same user. .El .Sh FILES .Bl -tag -width Ds -.It Pa $TMPDIR/ssh-XXXXXXXXXX/agent. +.It Pa $HOME/.ssh/agent/s.* .Ux Ns -domain sockets used to contain the connection to the authentication agent. These sockets should only be readable by the owner. From b5877b7b3e597f47578ade9dbe7e4332f112dfc4 Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Thu, 22 May 2025 03:41:10 +0000 Subject: [PATCH 070/244] upstream: Add $OpenBSD$ marker for easier syncing. OpenBSD-Commit-ID: 27ff3e1e2e6610d9981ebe43ae9b783236800035 --- misc-agent.c | 1 + 1 file changed, 1 insertion(+) diff --git a/misc-agent.c b/misc-agent.c index db8f93bc873b..312cff60db8d 100644 --- a/misc-agent.c +++ b/misc-agent.c @@ -1,3 +1,4 @@ +/* $OpenBSD: misc-agent.c,v 1.4 2025/05/22 03:41:10 dtucker Exp $ */ /* * Copyright (c) 2025 Damien Miller * From 1ccf42378df202472e7254f37f7dabb2f5723955 Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Thu, 22 May 2025 03:53:46 +0000 Subject: [PATCH 071/244] upstream: Copy arg to be passed to dirname(). POSIX allows dirname() to modify its args and return a pointer into it, so this prevents an overlapping strlcpy. bz#3819, patch from cjwatson at debian.org OpenBSD-Commit-ID: c32e496e6a1618aba31c8b7a9d4e1376c5ea6aa1 --- misc.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/misc.c b/misc.c index 25465dcd2d4f..f4e02bd04a78 100644 --- a/misc.c +++ b/misc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: misc.c,v 1.199 2025/05/05 02:48:06 djm Exp $ */ +/* $OpenBSD: misc.c,v 1.200 2025/05/22 03:53:46 dtucker Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2005-2020 Damien Miller. All rights reserved. @@ -2254,7 +2254,7 @@ int safe_path(const char *name, struct stat *stp, const char *pw_dir, uid_t uid, char *err, size_t errlen) { - char buf[PATH_MAX], homedir[PATH_MAX]; + char buf[PATH_MAX], buf2[PATH_MAX], homedir[PATH_MAX]; char *cp; int comparehome = 0; struct stat st; @@ -2280,7 +2280,12 @@ safe_path(const char *name, struct stat *stp, const char *pw_dir, /* for each component of the canonical path, walking upwards */ for (;;) { - if ((cp = dirname(buf)) == NULL) { + /* + * POSIX allows dirname to modify its argument and return a + * pointer into it, so make a copy to avoid overlapping strlcpy. + */ + strlcpy(buf2, buf, sizeof(buf2)); + if ((cp = dirname(buf2)) == NULL) { snprintf(err, errlen, "dirname() failed"); return -1; } From 6d192645a613aa814d51050b0458f37265b90d6c Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Thu, 22 May 2025 04:22:03 +0000 Subject: [PATCH 072/244] upstream: Output the current name for PermitRootLogin's "prohibit-password" in sshd -T instead of its deprecated alias "without-password". bz#3788, patch from cjwatson at debian.org. OpenBSD-Commit-ID: 2d5df18d5ad33a9b6c7547ec78a8e6ea13813df9 --- servconf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/servconf.c b/servconf.c index f7bc92377db3..f2a540dad54e 100644 --- a/servconf.c +++ b/servconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.c,v 1.425 2025/02/25 06:25:30 djm Exp $ */ +/* $OpenBSD: servconf.c,v 1.426 2025/05/22 04:22:03 dtucker Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -1282,8 +1282,8 @@ static const struct multistate multistate_addressfamily[] = { { NULL, -1 } }; static const struct multistate multistate_permitrootlogin[] = { - { "without-password", PERMIT_NO_PASSWD }, { "prohibit-password", PERMIT_NO_PASSWD }, + { "without-password", PERMIT_NO_PASSWD }, { "forced-commands-only", PERMIT_FORCED_ONLY }, { "yes", PERMIT_YES }, { "no", PERMIT_NO }, From de25e739781c4c09d20abd410f50f0a6f192dc72 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Thu, 22 May 2025 18:42:44 +1000 Subject: [PATCH 073/244] minimal shims for fstatat(2)/unlinkat(2) in agent Add some very minimal and task-specific replacements for fstatat(2) and unlinkat(2) in the ssh-agent socket cleanup loop, for platforms that lack these functions. ok dtucker@ --- misc-agent.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/misc-agent.c b/misc-agent.c index 312cff60db8d..712c42b82876 100644 --- a/misc-agent.c +++ b/misc-agent.c @@ -264,13 +264,20 @@ socket_is_stale(const char *path) return 0; } +#ifndef HAVE_FSTATAT +# define fstatat(x, y, buf, z) lstat(path, buf) +#endif +#ifndef HAVE_UNLINKAT +# define unlinkat(x, y, z) unlink(path) +#endif + void agent_cleanup_stale(const char *homedir, int ignore_hosthash) { DIR *d = NULL; struct dirent *dp; struct stat sb; - char *prefix = NULL, *dirpath = NULL, *path; + char *prefix = NULL, *dirpath = NULL, *path = NULL; struct timespec now, sub, *mtimp = NULL; /* Only consider sockets last modified > 1 hour ago */ @@ -290,6 +297,7 @@ agent_cleanup_stale(const char *homedir, int ignore_hosthash) } xasprintf(&prefix, "s.%s.", path); free(path); + path = NULL; } xasprintf(&dirpath, "%s/%s", homedir, _PATH_SSH_AGENT_SOCKET_DIR); @@ -298,7 +306,11 @@ agent_cleanup_stale(const char *homedir, int ignore_hosthash) error_f("opendir \"%s\": %s", dirpath, strerror(errno)); goto out; } + + path = NULL; while ((dp = readdir(d)) != NULL) { + free(path); + xasprintf(&path, "%s/%s", dirpath, dp->d_name); #ifdef HAVE_DIRENT_D_TYPE if (dp->d_type != DT_SOCK && dp->d_type != DT_UNKNOWN) continue; @@ -329,16 +341,18 @@ agent_cleanup_stale(const char *homedir, int ignore_hosthash) "from different host", dirpath, dp->d_name); continue; } - xasprintf(&path, "%s/%s", dirpath, dp->d_name); if (socket_is_stale(path)) { debug_f("cleanup stale socket %s", path); unlinkat(dirfd(d), dp->d_name, 0); } - free(path); } out: if (d != NULL) closedir(d); + free(path); free(dirpath); free(prefix); } + +#undef unlinkat +#undef fstatat From 450a8a1df1577ddbe68fe8da1fb8514d3781ef32 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Thu, 22 May 2025 21:16:37 +1000 Subject: [PATCH 074/244] Collect all of regress dir on failure. This may allow us to sort through its entrails and determine the cause of some types of failures. --- .github/workflows/c-cpp.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 7c37c9ce2cb1..8c3d64b8cc7f 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -160,8 +160,4 @@ jobs: path: | config.h config.log - regress/*.log - regress/valgrind-out/ - regress/asan.log.* - regress/msan.log.* - regress/log/* + regress/ From 2b2a7a2a0d70023b439080bb2770ff36522dbea8 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Thu, 22 May 2025 22:09:48 +1000 Subject: [PATCH 075/244] Remove debug change accidentally commited. Fixes Coverity CID 481160. --- cipher.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cipher.c b/cipher.c index 692aafe96cff..8a18da2df8d1 100644 --- a/cipher.c +++ b/cipher.c @@ -75,7 +75,7 @@ struct sshcipher { #define CFLAG_CHACHAPOLY (1<<1) #define CFLAG_AESCTR (1<<2) #define CFLAG_NONE (1<<3) -#define CFLAG_INTERNAL 0 +#define CFLAG_INTERNAL CFLAG_NONE /* Don't use "none" for packets */ #ifdef WITH_OPENSSL const EVP_CIPHER *(*evptype)(void); #else From 7acb70e05e9977ceca7b33df84ceaea337b1efef Mon Sep 17 00:00:00 2001 From: "bluhm@openbsd.org" Date: Thu, 22 May 2025 04:34:18 +0000 Subject: [PATCH 076/244] upstream: Fix OpenBSD RCS ID typos. from Andrius V OpenBSD-Regress-ID: 5c03a2ef5323969fc4978f2eec4f1a25c48c572a --- regress/penalty-expire.sh | 2 +- regress/penalty.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/regress/penalty-expire.sh b/regress/penalty-expire.sh index 4f0bbe638f63..27e36e3eefbf 100644 --- a/regress/penalty-expire.sh +++ b/regress/penalty-expire.sh @@ -1,4 +1,4 @@ -# $OpenBSD +# $OpenBSD: penalty-expire.sh,v 1.3 2025/05/22 04:34:18 bluhm Exp $ # Placed in the Public Domain. tid="penalties" diff --git a/regress/penalty.sh b/regress/penalty.sh index 8b8353238111..bf719dc0aab2 100644 --- a/regress/penalty.sh +++ b/regress/penalty.sh @@ -1,4 +1,4 @@ -# $OpenBSD +# $OpenBSD: penalty.sh,v 1.7 2025/05/22 04:34:18 bluhm Exp $ # Placed in the Public Domain. tid="penalties" From 6629eee21ca9d0a597a04dcac744a1ad882f912e Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Thu, 22 May 2025 12:14:19 +0000 Subject: [PATCH 077/244] upstream: Adjust debug message to prevent (unsigned) integer overflow. Fixes Coverity CID 481110, ok djm@ OpenBSD-Commit-ID: 26178bf3b812707fb498ea85d076cadd1f2eb686 --- misc-agent.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/misc-agent.c b/misc-agent.c index 712c42b82876..cf9b0fa0cb77 100644 --- a/misc-agent.c +++ b/misc-agent.c @@ -1,4 +1,4 @@ -/* $OpenBSD: misc-agent.c,v 1.4 2025/05/22 03:41:10 dtucker Exp $ */ +/* $OpenBSD: misc-agent.c,v 1.5 2025/05/22 12:14:19 dtucker Exp $ */ /* * Copyright (c) 2025 Damien Miller * @@ -59,7 +59,7 @@ hostname_hash(size_t len) l = ssh_digest_bytes(SSH_DIGEST_SHA512); if (len > 64) { - error_f("bad length %zu > max %zd", len, l - 1); + error_f("bad length %zu >= max %zd", len, l); return NULL; } if (gethostname(hostname, sizeof(hostname)) == -1) { From 4b8bee62d72ffb3c419c9ead6c9fb1a586283868 Mon Sep 17 00:00:00 2001 From: "deraadt@openbsd.org" Date: Fri, 23 May 2025 00:40:45 +0000 Subject: [PATCH 078/244] upstream: use "const char * const" for malloc_options here also OpenBSD-Commit-ID: 869715b9c7e1dd5b85efd07814e7e53f0286eea2 --- xmalloc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xmalloc.c b/xmalloc.c index 67191e3f214d..bf1da4b89456 100644 --- a/xmalloc.c +++ b/xmalloc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: xmalloc.c,v 1.37 2022/03/13 23:27:54 cheloha Exp $ */ +/* $OpenBSD: xmalloc.c,v 1.38 2025/05/23 00:40:45 deraadt Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -27,7 +27,7 @@ #include "log.h" #if defined(__OpenBSD__) -char *malloc_options = "S"; +const char * const malloc_options = "S"; #endif /* __OpenBSD__ */ void * From 24889a33071086b6f1f62568b0c2bd0a4955ac49 Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Fri, 23 May 2025 01:14:35 +0000 Subject: [PATCH 079/244] upstream: Import regenerated moduli. OpenBSD-Commit-ID: 07e29dc891e29b31e03e2e5493658b4a9ac19431 --- moduli | 859 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 426 insertions(+), 433 deletions(-) diff --git a/moduli b/moduli index ab7fd2bb0c27..2fe04ab76032 100644 --- a/moduli +++ b/moduli @@ -1,434 +1,427 @@ -# $OpenBSD: moduli,v 1.39 2024/11/29 00:13:36 dtucker Exp $ +# $OpenBSD: moduli,v 1.40 2025/05/23 01:14:35 dtucker Exp $ # Time Type Tests Tries Size Generator Modulus -20240828044144 2 6 100 2047 5 C2CE9B70B9DD5860C0846274F1FF29B2E3D5EFFA5A8568C6B9829BD8C42422F0BEE2D6D74503BCD91A002B09EB75174B87734CFFAC12682D49D50AF5B9837E3B30675E93087C5279A431B40D8219B2292A0EBB23ED0856BACF21F7A8C801FC3B0A1D2C76C4372109A24587D8E09F91CA0018EB2FB7D75BDD8FE230D49CC593E2152A7EFB4B7FCAA9228D061120DED56DDF6019817221B4D9A0F5DECF928148EB22AC583AC3BF37541CC285C6BB4E0C028E7140C133B12EB80354C01C053F5B435EA2798404749664674966DFB7113F86BC74FD37333330A664FA86AE1B40006717AC6091961C45164F3714777CC776DB2C7C72FA6A89EF3DEB98EF63216235F7 -20240828044149 2 6 100 2047 2 C2CE9B70B9DD5860C0846274F1FF29B2E3D5EFFA5A8568C6B9829BD8C42422F0BEE2D6D74503BCD91A002B09EB75174B87734CFFAC12682D49D50AF5B9837E3B30675E93087C5279A431B40D8219B2292A0EBB23ED0856BACF21F7A8C801FC3B0A1D2C76C4372109A24587D8E09F91CA0018EB2FB7D75BDD8FE230D49CC593E2152A7EFB4B7FCAA9228D061120DED56DDF6019817221B4D9A0F5DECF928148EB22AC583AC3BF37541CC285C6BB4E0C028E7140C133B12EB80354C01C053F5B435EA2798404749664674966DFB7113F86BC74FD37333330A664FA86AE1B40006717AC6091961C45164F3714777CC776DB2C7C72FA6A89EF3DEB98EF63217EB4CB -20240828044153 2 6 100 2047 5 C2CE9B70B9DD5860C0846274F1FF29B2E3D5EFFA5A8568C6B9829BD8C42422F0BEE2D6D74503BCD91A002B09EB75174B87734CFFAC12682D49D50AF5B9837E3B30675E93087C5279A431B40D8219B2292A0EBB23ED0856BACF21F7A8C801FC3B0A1D2C76C4372109A24587D8E09F91CA0018EB2FB7D75BDD8FE230D49CC593E2152A7EFB4B7FCAA9228D061120DED56DDF6019817221B4D9A0F5DECF928148EB22AC583AC3BF37541CC285C6BB4E0C028E7140C133B12EB80354C01C053F5B435EA2798404749664674966DFB7113F86BC74FD37333330A664FA86AE1B40006717AC6091961C45164F3714777CC776DB2C7C72FA6A89EF3DEB98EF632197445F -20240828044203 2 6 100 2047 5 C2CE9B70B9DD5860C0846274F1FF29B2E3D5EFFA5A8568C6B9829BD8C42422F0BEE2D6D74503BCD91A002B09EB75174B87734CFFAC12682D49D50AF5B9837E3B30675E93087C5279A431B40D8219B2292A0EBB23ED0856BACF21F7A8C801FC3B0A1D2C76C4372109A24587D8E09F91CA0018EB2FB7D75BDD8FE230D49CC593E2152A7EFB4B7FCAA9228D061120DED56DDF6019817221B4D9A0F5DECF928148EB22AC583AC3BF37541CC285C6BB4E0C028E7140C133B12EB80354C01C053F5B435EA2798404749664674966DFB7113F86BC74FD37333330A664FA86AE1B40006717AC6091961C45164F3714777CC776DB2C7C72FA6A89EF3DEB98EF6321E28D7F -20240828044206 2 6 100 2047 5 C2CE9B70B9DD5860C0846274F1FF29B2E3D5EFFA5A8568C6B9829BD8C42422F0BEE2D6D74503BCD91A002B09EB75174B87734CFFAC12682D49D50AF5B9837E3B30675E93087C5279A431B40D8219B2292A0EBB23ED0856BACF21F7A8C801FC3B0A1D2C76C4372109A24587D8E09F91CA0018EB2FB7D75BDD8FE230D49CC593E2152A7EFB4B7FCAA9228D061120DED56DDF6019817221B4D9A0F5DECF928148EB22AC583AC3BF37541CC285C6BB4E0C028E7140C133B12EB80354C01C053F5B435EA2798404749664674966DFB7113F86BC74FD37333330A664FA86AE1B40006717AC6091961C45164F3714777CC776DB2C7C72FA6A89EF3DEB98EF6321F5D65F -20240828044207 2 6 100 2047 2 C2CE9B70B9DD5860C0846274F1FF29B2E3D5EFFA5A8568C6B9829BD8C42422F0BEE2D6D74503BCD91A002B09EB75174B87734CFFAC12682D49D50AF5B9837E3B30675E93087C5279A431B40D8219B2292A0EBB23ED0856BACF21F7A8C801FC3B0A1D2C76C4372109A24587D8E09F91CA0018EB2FB7D75BDD8FE230D49CC593E2152A7EFB4B7FCAA9228D061120DED56DDF6019817221B4D9A0F5DECF928148EB22AC583AC3BF37541CC285C6BB4E0C028E7140C133B12EB80354C01C053F5B435EA2798404749664674966DFB7113F86BC74FD37333330A664FA86AE1B40006717AC6091961C45164F3714777CC776DB2C7C72FA6A89EF3DEB98EF6321F5F783 -20240828044210 2 6 100 2047 2 C2CE9B70B9DD5860C0846274F1FF29B2E3D5EFFA5A8568C6B9829BD8C42422F0BEE2D6D74503BCD91A002B09EB75174B87734CFFAC12682D49D50AF5B9837E3B30675E93087C5279A431B40D8219B2292A0EBB23ED0856BACF21F7A8C801FC3B0A1D2C76C4372109A24587D8E09F91CA0018EB2FB7D75BDD8FE230D49CC593E2152A7EFB4B7FCAA9228D061120DED56DDF6019817221B4D9A0F5DECF928148EB22AC583AC3BF37541CC285C6BB4E0C028E7140C133B12EB80354C01C053F5B435EA2798404749664674966DFB7113F86BC74FD37333330A664FA86AE1B40006717AC6091961C45164F3714777CC776DB2C7C72FA6A89EF3DEB98EF63220959FB -20240828044217 2 6 100 2047 2 C2CE9B70B9DD5860C0846274F1FF29B2E3D5EFFA5A8568C6B9829BD8C42422F0BEE2D6D74503BCD91A002B09EB75174B87734CFFAC12682D49D50AF5B9837E3B30675E93087C5279A431B40D8219B2292A0EBB23ED0856BACF21F7A8C801FC3B0A1D2C76C4372109A24587D8E09F91CA0018EB2FB7D75BDD8FE230D49CC593E2152A7EFB4B7FCAA9228D061120DED56DDF6019817221B4D9A0F5DECF928148EB22AC583AC3BF37541CC285C6BB4E0C028E7140C133B12EB80354C01C053F5B435EA2798404749664674966DFB7113F86BC74FD37333330A664FA86AE1B40006717AC6091961C45164F3714777CC776DB2C7C72FA6A89EF3DEB98EF63223CB053 -20240828044224 2 6 100 2047 2 C2CE9B70B9DD5860C0846274F1FF29B2E3D5EFFA5A8568C6B9829BD8C42422F0BEE2D6D74503BCD91A002B09EB75174B87734CFFAC12682D49D50AF5B9837E3B30675E93087C5279A431B40D8219B2292A0EBB23ED0856BACF21F7A8C801FC3B0A1D2C76C4372109A24587D8E09F91CA0018EB2FB7D75BDD8FE230D49CC593E2152A7EFB4B7FCAA9228D061120DED56DDF6019817221B4D9A0F5DECF928148EB22AC583AC3BF37541CC285C6BB4E0C028E7140C133B12EB80354C01C053F5B435EA2798404749664674966DFB7113F86BC74FD37333330A664FA86AE1B40006717AC6091961C45164F3714777CC776DB2C7C72FA6A89EF3DEB98EF63226F7A83 -20240828044233 2 6 100 2047 5 C2CE9B70B9DD5860C0846274F1FF29B2E3D5EFFA5A8568C6B9829BD8C42422F0BEE2D6D74503BCD91A002B09EB75174B87734CFFAC12682D49D50AF5B9837E3B30675E93087C5279A431B40D8219B2292A0EBB23ED0856BACF21F7A8C801FC3B0A1D2C76C4372109A24587D8E09F91CA0018EB2FB7D75BDD8FE230D49CC593E2152A7EFB4B7FCAA9228D061120DED56DDF6019817221B4D9A0F5DECF928148EB22AC583AC3BF37541CC285C6BB4E0C028E7140C133B12EB80354C01C053F5B435EA2798404749664674966DFB7113F86BC74FD37333330A664FA86AE1B40006717AC6091961C45164F3714777CC776DB2C7C72FA6A89EF3DEB98EF6322B452E7 -20240828044240 2 6 100 2047 2 C2CE9B70B9DD5860C0846274F1FF29B2E3D5EFFA5A8568C6B9829BD8C42422F0BEE2D6D74503BCD91A002B09EB75174B87734CFFAC12682D49D50AF5B9837E3B30675E93087C5279A431B40D8219B2292A0EBB23ED0856BACF21F7A8C801FC3B0A1D2C76C4372109A24587D8E09F91CA0018EB2FB7D75BDD8FE230D49CC593E2152A7EFB4B7FCAA9228D061120DED56DDF6019817221B4D9A0F5DECF928148EB22AC583AC3BF37541CC285C6BB4E0C028E7140C133B12EB80354C01C053F5B435EA2798404749664674966DFB7113F86BC74FD37333330A664FA86AE1B40006717AC6091961C45164F3714777CC776DB2C7C72FA6A89EF3DEB98EF6322E58253 -20240828044251 2 6 100 2047 5 C2CE9B70B9DD5860C0846274F1FF29B2E3D5EFFA5A8568C6B9829BD8C42422F0BEE2D6D74503BCD91A002B09EB75174B87734CFFAC12682D49D50AF5B9837E3B30675E93087C5279A431B40D8219B2292A0EBB23ED0856BACF21F7A8C801FC3B0A1D2C76C4372109A24587D8E09F91CA0018EB2FB7D75BDD8FE230D49CC593E2152A7EFB4B7FCAA9228D061120DED56DDF6019817221B4D9A0F5DECF928148EB22AC583AC3BF37541CC285C6BB4E0C028E7140C133B12EB80354C01C053F5B435EA2798404749664674966DFB7113F86BC74FD37333330A664FA86AE1B40006717AC6091961C45164F3714777CC776DB2C7C72FA6A89EF3DEB98EF632334AB77 -20240828044259 2 6 100 2047 2 C2CE9B70B9DD5860C0846274F1FF29B2E3D5EFFA5A8568C6B9829BD8C42422F0BEE2D6D74503BCD91A002B09EB75174B87734CFFAC12682D49D50AF5B9837E3B30675E93087C5279A431B40D8219B2292A0EBB23ED0856BACF21F7A8C801FC3B0A1D2C76C4372109A24587D8E09F91CA0018EB2FB7D75BDD8FE230D49CC593E2152A7EFB4B7FCAA9228D061120DED56DDF6019817221B4D9A0F5DECF928148EB22AC583AC3BF37541CC285C6BB4E0C028E7140C133B12EB80354C01C053F5B435EA2798404749664674966DFB7113F86BC74FD37333330A664FA86AE1B40006717AC6091961C45164F3714777CC776DB2C7C72FA6A89EF3DEB98EF632379357B -20240828044311 2 6 100 2047 5 C2CE9B70B9DD5860C0846274F1FF29B2E3D5EFFA5A8568C6B9829BD8C42422F0BEE2D6D74503BCD91A002B09EB75174B87734CFFAC12682D49D50AF5B9837E3B30675E93087C5279A431B40D8219B2292A0EBB23ED0856BACF21F7A8C801FC3B0A1D2C76C4372109A24587D8E09F91CA0018EB2FB7D75BDD8FE230D49CC593E2152A7EFB4B7FCAA9228D061120DED56DDF6019817221B4D9A0F5DECF928148EB22AC583AC3BF37541CC285C6BB4E0C028E7140C133B12EB80354C01C053F5B435EA2798404749664674966DFB7113F86BC74FD37333330A664FA86AE1B40006717AC6091961C45164F3714777CC776DB2C7C72FA6A89EF3DEB98EF6323D336A7 -20240828044323 2 6 100 2047 2 C2CE9B70B9DD5860C0846274F1FF29B2E3D5EFFA5A8568C6B9829BD8C42422F0BEE2D6D74503BCD91A002B09EB75174B87734CFFAC12682D49D50AF5B9837E3B30675E93087C5279A431B40D8219B2292A0EBB23ED0856BACF21F7A8C801FC3B0A1D2C76C4372109A24587D8E09F91CA0018EB2FB7D75BDD8FE230D49CC593E2152A7EFB4B7FCAA9228D061120DED56DDF6019817221B4D9A0F5DECF928148EB22AC583AC3BF37541CC285C6BB4E0C028E7140C133B12EB80354C01C053F5B435EA2798404749664674966DFB7113F86BC74FD37333330A664FA86AE1B40006717AC6091961C45164F3714777CC776DB2C7C72FA6A89EF3DEB98EF63242A969B -20240828044326 2 6 100 2047 2 C2CE9B70B9DD5860C0846274F1FF29B2E3D5EFFA5A8568C6B9829BD8C42422F0BEE2D6D74503BCD91A002B09EB75174B87734CFFAC12682D49D50AF5B9837E3B30675E93087C5279A431B40D8219B2292A0EBB23ED0856BACF21F7A8C801FC3B0A1D2C76C4372109A24587D8E09F91CA0018EB2FB7D75BDD8FE230D49CC593E2152A7EFB4B7FCAA9228D061120DED56DDF6019817221B4D9A0F5DECF928148EB22AC583AC3BF37541CC285C6BB4E0C028E7140C133B12EB80354C01C053F5B435EA2798404749664674966DFB7113F86BC74FD37333330A664FA86AE1B40006717AC6091961C45164F3714777CC776DB2C7C72FA6A89EF3DEB98EF63243E12C3 -20240828044349 2 6 100 2047 5 C2CE9B70B9DD5860C0846274F1FF29B2E3D5EFFA5A8568C6B9829BD8C42422F0BEE2D6D74503BCD91A002B09EB75174B87734CFFAC12682D49D50AF5B9837E3B30675E93087C5279A431B40D8219B2292A0EBB23ED0856BACF21F7A8C801FC3B0A1D2C76C4372109A24587D8E09F91CA0018EB2FB7D75BDD8FE230D49CC593E2152A7EFB4B7FCAA9228D061120DED56DDF6019817221B4D9A0F5DECF928148EB22AC583AC3BF37541CC285C6BB4E0C028E7140C133B12EB80354C01C053F5B435EA2798404749664674966DFB7113F86BC74FD37333330A664FA86AE1B40006717AC6091961C45164F3714777CC776DB2C7C72FA6A89EF3DEB98EF6324EA98FF -20240828044351 2 6 100 2047 5 C2CE9B70B9DD5860C0846274F1FF29B2E3D5EFFA5A8568C6B9829BD8C42422F0BEE2D6D74503BCD91A002B09EB75174B87734CFFAC12682D49D50AF5B9837E3B30675E93087C5279A431B40D8219B2292A0EBB23ED0856BACF21F7A8C801FC3B0A1D2C76C4372109A24587D8E09F91CA0018EB2FB7D75BDD8FE230D49CC593E2152A7EFB4B7FCAA9228D061120DED56DDF6019817221B4D9A0F5DECF928148EB22AC583AC3BF37541CC285C6BB4E0C028E7140C133B12EB80354C01C053F5B435EA2798404749664674966DFB7113F86BC74FD37333330A664FA86AE1B40006717AC6091961C45164F3714777CC776DB2C7C72FA6A89EF3DEB98EF6324F33C17 -20240828044406 2 6 100 2047 5 C2CE9B70B9DD5860C0846274F1FF29B2E3D5EFFA5A8568C6B9829BD8C42422F0BEE2D6D74503BCD91A002B09EB75174B87734CFFAC12682D49D50AF5B9837E3B30675E93087C5279A431B40D8219B2292A0EBB23ED0856BACF21F7A8C801FC3B0A1D2C76C4372109A24587D8E09F91CA0018EB2FB7D75BDD8FE230D49CC593E2152A7EFB4B7FCAA9228D061120DED56DDF6019817221B4D9A0F5DECF928148EB22AC583AC3BF37541CC285C6BB4E0C028E7140C133B12EB80354C01C053F5B435EA2798404749664674966DFB7113F86BC74FD37333330A664FA86AE1B40006717AC6091961C45164F3714777CC776DB2C7C72FA6A89EF3DEB98EF632569D1BF -20240828044412 2 6 100 2047 2 C2CE9B70B9DD5860C0846274F1FF29B2E3D5EFFA5A8568C6B9829BD8C42422F0BEE2D6D74503BCD91A002B09EB75174B87734CFFAC12682D49D50AF5B9837E3B30675E93087C5279A431B40D8219B2292A0EBB23ED0856BACF21F7A8C801FC3B0A1D2C76C4372109A24587D8E09F91CA0018EB2FB7D75BDD8FE230D49CC593E2152A7EFB4B7FCAA9228D061120DED56DDF6019817221B4D9A0F5DECF928148EB22AC583AC3BF37541CC285C6BB4E0C028E7140C133B12EB80354C01C053F5B435EA2798404749664674966DFB7113F86BC74FD37333330A664FA86AE1B40006717AC6091961C45164F3714777CC776DB2C7C72FA6A89EF3DEB98EF632591055B -20240828044416 2 6 100 2047 2 C2CE9B70B9DD5860C0846274F1FF29B2E3D5EFFA5A8568C6B9829BD8C42422F0BEE2D6D74503BCD91A002B09EB75174B87734CFFAC12682D49D50AF5B9837E3B30675E93087C5279A431B40D8219B2292A0EBB23ED0856BACF21F7A8C801FC3B0A1D2C76C4372109A24587D8E09F91CA0018EB2FB7D75BDD8FE230D49CC593E2152A7EFB4B7FCAA9228D061120DED56DDF6019817221B4D9A0F5DECF928148EB22AC583AC3BF37541CC285C6BB4E0C028E7140C133B12EB80354C01C053F5B435EA2798404749664674966DFB7113F86BC74FD37333330A664FA86AE1B40006717AC6091961C45164F3714777CC776DB2C7C72FA6A89EF3DEB98EF6325A64983 -20240828044426 2 6 100 2047 2 C2CE9B70B9DD5860C0846274F1FF29B2E3D5EFFA5A8568C6B9829BD8C42422F0BEE2D6D74503BCD91A002B09EB75174B87734CFFAC12682D49D50AF5B9837E3B30675E93087C5279A431B40D8219B2292A0EBB23ED0856BACF21F7A8C801FC3B0A1D2C76C4372109A24587D8E09F91CA0018EB2FB7D75BDD8FE230D49CC593E2152A7EFB4B7FCAA9228D061120DED56DDF6019817221B4D9A0F5DECF928148EB22AC583AC3BF37541CC285C6BB4E0C028E7140C133B12EB80354C01C053F5B435EA2798404749664674966DFB7113F86BC74FD37333330A664FA86AE1B40006717AC6091961C45164F3714777CC776DB2C7C72FA6A89EF3DEB98EF6325F39C73 -20240828044435 2 6 100 2047 5 C2CE9B70B9DD5860C0846274F1FF29B2E3D5EFFA5A8568C6B9829BD8C42422F0BEE2D6D74503BCD91A002B09EB75174B87734CFFAC12682D49D50AF5B9837E3B30675E93087C5279A431B40D8219B2292A0EBB23ED0856BACF21F7A8C801FC3B0A1D2C76C4372109A24587D8E09F91CA0018EB2FB7D75BDD8FE230D49CC593E2152A7EFB4B7FCAA9228D061120DED56DDF6019817221B4D9A0F5DECF928148EB22AC583AC3BF37541CC285C6BB4E0C028E7140C133B12EB80354C01C053F5B435EA2798404749664674966DFB7113F86BC74FD37333330A664FA86AE1B40006717AC6091961C45164F3714777CC776DB2C7C72FA6A89EF3DEB98EF63263987CF -20240828044440 2 6 100 2047 5 C2CE9B70B9DD5860C0846274F1FF29B2E3D5EFFA5A8568C6B9829BD8C42422F0BEE2D6D74503BCD91A002B09EB75174B87734CFFAC12682D49D50AF5B9837E3B30675E93087C5279A431B40D8219B2292A0EBB23ED0856BACF21F7A8C801FC3B0A1D2C76C4372109A24587D8E09F91CA0018EB2FB7D75BDD8FE230D49CC593E2152A7EFB4B7FCAA9228D061120DED56DDF6019817221B4D9A0F5DECF928148EB22AC583AC3BF37541CC285C6BB4E0C028E7140C133B12EB80354C01C053F5B435EA2798404749664674966DFB7113F86BC74FD37333330A664FA86AE1B40006717AC6091961C45164F3714777CC776DB2C7C72FA6A89EF3DEB98EF63265B2A5F -20240828044445 2 6 100 2047 2 C2CE9B70B9DD5860C0846274F1FF29B2E3D5EFFA5A8568C6B9829BD8C42422F0BEE2D6D74503BCD91A002B09EB75174B87734CFFAC12682D49D50AF5B9837E3B30675E93087C5279A431B40D8219B2292A0EBB23ED0856BACF21F7A8C801FC3B0A1D2C76C4372109A24587D8E09F91CA0018EB2FB7D75BDD8FE230D49CC593E2152A7EFB4B7FCAA9228D061120DED56DDF6019817221B4D9A0F5DECF928148EB22AC583AC3BF37541CC285C6BB4E0C028E7140C133B12EB80354C01C053F5B435EA2798404749664674966DFB7113F86BC74FD37333330A664FA86AE1B40006717AC6091961C45164F3714777CC776DB2C7C72FA6A89EF3DEB98EF63267C888B -20240828044453 2 6 100 2047 2 C2CE9B70B9DD5860C0846274F1FF29B2E3D5EFFA5A8568C6B9829BD8C42422F0BEE2D6D74503BCD91A002B09EB75174B87734CFFAC12682D49D50AF5B9837E3B30675E93087C5279A431B40D8219B2292A0EBB23ED0856BACF21F7A8C801FC3B0A1D2C76C4372109A24587D8E09F91CA0018EB2FB7D75BDD8FE230D49CC593E2152A7EFB4B7FCAA9228D061120DED56DDF6019817221B4D9A0F5DECF928148EB22AC583AC3BF37541CC285C6BB4E0C028E7140C133B12EB80354C01C053F5B435EA2798404749664674966DFB7113F86BC74FD37333330A664FA86AE1B40006717AC6091961C45164F3714777CC776DB2C7C72FA6A89EF3DEB98EF6326B9D6C3 -20240828044505 2 6 100 2047 5 C2CE9B70B9DD5860C0846274F1FF29B2E3D5EFFA5A8568C6B9829BD8C42422F0BEE2D6D74503BCD91A002B09EB75174B87734CFFAC12682D49D50AF5B9837E3B30675E93087C5279A431B40D8219B2292A0EBB23ED0856BACF21F7A8C801FC3B0A1D2C76C4372109A24587D8E09F91CA0018EB2FB7D75BDD8FE230D49CC593E2152A7EFB4B7FCAA9228D061120DED56DDF6019817221B4D9A0F5DECF928148EB22AC583AC3BF37541CC285C6BB4E0C028E7140C133B12EB80354C01C053F5B435EA2798404749664674966DFB7113F86BC74FD37333330A664FA86AE1B40006717AC6091961C45164F3714777CC776DB2C7C72FA6A89EF3DEB98EF63270DF46F -20240828044509 2 6 100 2047 2 C2CE9B70B9DD5860C0846274F1FF29B2E3D5EFFA5A8568C6B9829BD8C42422F0BEE2D6D74503BCD91A002B09EB75174B87734CFFAC12682D49D50AF5B9837E3B30675E93087C5279A431B40D8219B2292A0EBB23ED0856BACF21F7A8C801FC3B0A1D2C76C4372109A24587D8E09F91CA0018EB2FB7D75BDD8FE230D49CC593E2152A7EFB4B7FCAA9228D061120DED56DDF6019817221B4D9A0F5DECF928148EB22AC583AC3BF37541CC285C6BB4E0C028E7140C133B12EB80354C01C053F5B435EA2798404749664674966DFB7113F86BC74FD37333330A664FA86AE1B40006717AC6091961C45164F3714777CC776DB2C7C72FA6A89EF3DEB98EF632725FB3B -20240828044510 2 6 100 2047 2 C2CE9B70B9DD5860C0846274F1FF29B2E3D5EFFA5A8568C6B9829BD8C42422F0BEE2D6D74503BCD91A002B09EB75174B87734CFFAC12682D49D50AF5B9837E3B30675E93087C5279A431B40D8219B2292A0EBB23ED0856BACF21F7A8C801FC3B0A1D2C76C4372109A24587D8E09F91CA0018EB2FB7D75BDD8FE230D49CC593E2152A7EFB4B7FCAA9228D061120DED56DDF6019817221B4D9A0F5DECF928148EB22AC583AC3BF37541CC285C6BB4E0C028E7140C133B12EB80354C01C053F5B435EA2798404749664674966DFB7113F86BC74FD37333330A664FA86AE1B40006717AC6091961C45164F3714777CC776DB2C7C72FA6A89EF3DEB98EF632728D6F3 -20240828044525 2 6 100 2047 2 C2CE9B70B9DD5860C0846274F1FF29B2E3D5EFFA5A8568C6B9829BD8C42422F0BEE2D6D74503BCD91A002B09EB75174B87734CFFAC12682D49D50AF5B9837E3B30675E93087C5279A431B40D8219B2292A0EBB23ED0856BACF21F7A8C801FC3B0A1D2C76C4372109A24587D8E09F91CA0018EB2FB7D75BDD8FE230D49CC593E2152A7EFB4B7FCAA9228D061120DED56DDF6019817221B4D9A0F5DECF928148EB22AC583AC3BF37541CC285C6BB4E0C028E7140C133B12EB80354C01C053F5B435EA2798404749664674966DFB7113F86BC74FD37333330A664FA86AE1B40006717AC6091961C45164F3714777CC776DB2C7C72FA6A89EF3DEB98EF6327A20713 -20240828044536 2 6 100 2047 5 C2CE9B70B9DD5860C0846274F1FF29B2E3D5EFFA5A8568C6B9829BD8C42422F0BEE2D6D74503BCD91A002B09EB75174B87734CFFAC12682D49D50AF5B9837E3B30675E93087C5279A431B40D8219B2292A0EBB23ED0856BACF21F7A8C801FC3B0A1D2C76C4372109A24587D8E09F91CA0018EB2FB7D75BDD8FE230D49CC593E2152A7EFB4B7FCAA9228D061120DED56DDF6019817221B4D9A0F5DECF928148EB22AC583AC3BF37541CC285C6BB4E0C028E7140C133B12EB80354C01C053F5B435EA2798404749664674966DFB7113F86BC74FD37333330A664FA86AE1B40006717AC6091961C45164F3714777CC776DB2C7C72FA6A89EF3DEB98EF6327FA0007 -20240828044603 2 6 100 2047 2 C2CE9B70B9DD5860C0846274F1FF29B2E3D5EFFA5A8568C6B9829BD8C42422F0BEE2D6D74503BCD91A002B09EB75174B87734CFFAC12682D49D50AF5B9837E3B30675E93087C5279A431B40D8219B2292A0EBB23ED0856BACF21F7A8C801FC3B0A1D2C76C4372109A24587D8E09F91CA0018EB2FB7D75BDD8FE230D49CC593E2152A7EFB4B7FCAA9228D061120DED56DDF6019817221B4D9A0F5DECF928148EB22AC583AC3BF37541CC285C6BB4E0C028E7140C133B12EB80354C01C053F5B435EA2798404749664674966DFB7113F86BC74FD37333330A664FA86AE1B40006717AC6091961C45164F3714777CC776DB2C7C72FA6A89EF3DEB98EF6328C7601B -20240828044621 2 6 100 2047 2 E8198A1A9FF997DF62B131D5C187C3160A61128E5DC14FED2EC25E38EE627FC070B240AFA70179A5981739E7F1CC1EFD94BECAA338C8BEFCA1C036EF1F7804AD1BBE8B86C3BDDDA7868F9302E45F47BABB6A8D54E1871678AB37855761AAD6408EA4CEE8B4DE9A5972981B07EAC9CD496331C4E1104ED49ACB5F4F37DC9B98098C04053775DB2994B23CA4561C739DB5A19638C0D1D97C07EF26ADC912A5C6A3506B5E935E4C11E18769334B4D02CDB4802ACE68B55D2D3CD354B0DE2D4DB4727FAD43694110D90A4A18206A731466E83FCE2A6F8E042E1D244F7EA4DD2FF3B9E3910C2B7672E4605A2025BDAA0D67455F8FD50FD241B5074FD2602100B138DB -20240828044622 2 6 100 2047 2 E8198A1A9FF997DF62B131D5C187C3160A61128E5DC14FED2EC25E38EE627FC070B240AFA70179A5981739E7F1CC1EFD94BECAA338C8BEFCA1C036EF1F7804AD1BBE8B86C3BDDDA7868F9302E45F47BABB6A8D54E1871678AB37855761AAD6408EA4CEE8B4DE9A5972981B07EAC9CD496331C4E1104ED49ACB5F4F37DC9B98098C04053775DB2994B23CA4561C739DB5A19638C0D1D97C07EF26ADC912A5C6A3506B5E935E4C11E18769334B4D02CDB4802ACE68B55D2D3CD354B0DE2D4DB4727FAD43694110D90A4A18206A731466E83FCE2A6F8E042E1D244F7EA4DD2FF3B9E3910C2B7672E4605A2025BDAA0D67455F8FD50FD241B5074FD2602100BA7D33 -20240828044630 2 6 100 2047 5 E8198A1A9FF997DF62B131D5C187C3160A61128E5DC14FED2EC25E38EE627FC070B240AFA70179A5981739E7F1CC1EFD94BECAA338C8BEFCA1C036EF1F7804AD1BBE8B86C3BDDDA7868F9302E45F47BABB6A8D54E1871678AB37855761AAD6408EA4CEE8B4DE9A5972981B07EAC9CD496331C4E1104ED49ACB5F4F37DC9B98098C04053775DB2994B23CA4561C739DB5A19638C0D1D97C07EF26ADC912A5C6A3506B5E935E4C11E18769334B4D02CDB4802ACE68B55D2D3CD354B0DE2D4DB4727FAD43694110D90A4A18206A731466E83FCE2A6F8E042E1D244F7EA4DD2FF3B9E3910C2B7672E4605A2025BDAA0D67455F8FD50FD241B5074FD2602100F35A77 -20240828044634 2 6 100 2047 2 E8198A1A9FF997DF62B131D5C187C3160A61128E5DC14FED2EC25E38EE627FC070B240AFA70179A5981739E7F1CC1EFD94BECAA338C8BEFCA1C036EF1F7804AD1BBE8B86C3BDDDA7868F9302E45F47BABB6A8D54E1871678AB37855761AAD6408EA4CEE8B4DE9A5972981B07EAC9CD496331C4E1104ED49ACB5F4F37DC9B98098C04053775DB2994B23CA4561C739DB5A19638C0D1D97C07EF26ADC912A5C6A3506B5E935E4C11E18769334B4D02CDB4802ACE68B55D2D3CD354B0DE2D4DB4727FAD43694110D90A4A18206A731466E83FCE2A6F8E042E1D244F7EA4DD2FF3B9E3910C2B7672E4605A2025BDAA0D67455F8FD50FD241B5074FD26021010E6E03 -20240828044637 2 6 100 2047 2 E8198A1A9FF997DF62B131D5C187C3160A61128E5DC14FED2EC25E38EE627FC070B240AFA70179A5981739E7F1CC1EFD94BECAA338C8BEFCA1C036EF1F7804AD1BBE8B86C3BDDDA7868F9302E45F47BABB6A8D54E1871678AB37855761AAD6408EA4CEE8B4DE9A5972981B07EAC9CD496331C4E1104ED49ACB5F4F37DC9B98098C04053775DB2994B23CA4561C739DB5A19638C0D1D97C07EF26ADC912A5C6A3506B5E935E4C11E18769334B4D02CDB4802ACE68B55D2D3CD354B0DE2D4DB4727FAD43694110D90A4A18206A731466E83FCE2A6F8E042E1D244F7EA4DD2FF3B9E3910C2B7672E4605A2025BDAA0D67455F8FD50FD241B5074FD26021011F7EAB -20240828044646 2 6 100 2047 2 E8198A1A9FF997DF62B131D5C187C3160A61128E5DC14FED2EC25E38EE627FC070B240AFA70179A5981739E7F1CC1EFD94BECAA338C8BEFCA1C036EF1F7804AD1BBE8B86C3BDDDA7868F9302E45F47BABB6A8D54E1871678AB37855761AAD6408EA4CEE8B4DE9A5972981B07EAC9CD496331C4E1104ED49ACB5F4F37DC9B98098C04053775DB2994B23CA4561C739DB5A19638C0D1D97C07EF26ADC912A5C6A3506B5E935E4C11E18769334B4D02CDB4802ACE68B55D2D3CD354B0DE2D4DB4727FAD43694110D90A4A18206A731466E83FCE2A6F8E042E1D244F7EA4DD2FF3B9E3910C2B7672E4605A2025BDAA0D67455F8FD50FD241B5074FD26021016091AB -20240828044657 2 6 100 2047 5 E8198A1A9FF997DF62B131D5C187C3160A61128E5DC14FED2EC25E38EE627FC070B240AFA70179A5981739E7F1CC1EFD94BECAA338C8BEFCA1C036EF1F7804AD1BBE8B86C3BDDDA7868F9302E45F47BABB6A8D54E1871678AB37855761AAD6408EA4CEE8B4DE9A5972981B07EAC9CD496331C4E1104ED49ACB5F4F37DC9B98098C04053775DB2994B23CA4561C739DB5A19638C0D1D97C07EF26ADC912A5C6A3506B5E935E4C11E18769334B4D02CDB4802ACE68B55D2D3CD354B0DE2D4DB4727FAD43694110D90A4A18206A731466E83FCE2A6F8E042E1D244F7EA4DD2FF3B9E3910C2B7672E4605A2025BDAA0D67455F8FD50FD241B5074FD2602101B2C867 -20240828044658 2 6 100 2047 5 E8198A1A9FF997DF62B131D5C187C3160A61128E5DC14FED2EC25E38EE627FC070B240AFA70179A5981739E7F1CC1EFD94BECAA338C8BEFCA1C036EF1F7804AD1BBE8B86C3BDDDA7868F9302E45F47BABB6A8D54E1871678AB37855761AAD6408EA4CEE8B4DE9A5972981B07EAC9CD496331C4E1104ED49ACB5F4F37DC9B98098C04053775DB2994B23CA4561C739DB5A19638C0D1D97C07EF26ADC912A5C6A3506B5E935E4C11E18769334B4D02CDB4802ACE68B55D2D3CD354B0DE2D4DB4727FAD43694110D90A4A18206A731466E83FCE2A6F8E042E1D244F7EA4DD2FF3B9E3910C2B7672E4605A2025BDAA0D67455F8FD50FD241B5074FD2602101B60E87 -20240828044721 2 6 100 2047 5 E8198A1A9FF997DF62B131D5C187C3160A61128E5DC14FED2EC25E38EE627FC070B240AFA70179A5981739E7F1CC1EFD94BECAA338C8BEFCA1C036EF1F7804AD1BBE8B86C3BDDDA7868F9302E45F47BABB6A8D54E1871678AB37855761AAD6408EA4CEE8B4DE9A5972981B07EAC9CD496331C4E1104ED49ACB5F4F37DC9B98098C04053775DB2994B23CA4561C739DB5A19638C0D1D97C07EF26ADC912A5C6A3506B5E935E4C11E18769334B4D02CDB4802ACE68B55D2D3CD354B0DE2D4DB4727FAD43694110D90A4A18206A731466E83FCE2A6F8E042E1D244F7EA4DD2FF3B9E3910C2B7672E4605A2025BDAA0D67455F8FD50FD241B5074FD2602102652CD7 -20240828044731 2 6 100 2047 5 E8198A1A9FF997DF62B131D5C187C3160A61128E5DC14FED2EC25E38EE627FC070B240AFA70179A5981739E7F1CC1EFD94BECAA338C8BEFCA1C036EF1F7804AD1BBE8B86C3BDDDA7868F9302E45F47BABB6A8D54E1871678AB37855761AAD6408EA4CEE8B4DE9A5972981B07EAC9CD496331C4E1104ED49ACB5F4F37DC9B98098C04053775DB2994B23CA4561C739DB5A19638C0D1D97C07EF26ADC912A5C6A3506B5E935E4C11E18769334B4D02CDB4802ACE68B55D2D3CD354B0DE2D4DB4727FAD43694110D90A4A18206A731466E83FCE2A6F8E042E1D244F7EA4DD2FF3B9E3910C2B7672E4605A2025BDAA0D67455F8FD50FD241B5074FD2602102B160B7 -20240828044737 2 6 100 2047 5 E8198A1A9FF997DF62B131D5C187C3160A61128E5DC14FED2EC25E38EE627FC070B240AFA70179A5981739E7F1CC1EFD94BECAA338C8BEFCA1C036EF1F7804AD1BBE8B86C3BDDDA7868F9302E45F47BABB6A8D54E1871678AB37855761AAD6408EA4CEE8B4DE9A5972981B07EAC9CD496331C4E1104ED49ACB5F4F37DC9B98098C04053775DB2994B23CA4561C739DB5A19638C0D1D97C07EF26ADC912A5C6A3506B5E935E4C11E18769334B4D02CDB4802ACE68B55D2D3CD354B0DE2D4DB4727FAD43694110D90A4A18206A731466E83FCE2A6F8E042E1D244F7EA4DD2FF3B9E3910C2B7672E4605A2025BDAA0D67455F8FD50FD241B5074FD2602102DA0A57 -20240828044755 2 6 100 2047 2 E8198A1A9FF997DF62B131D5C187C3160A61128E5DC14FED2EC25E38EE627FC070B240AFA70179A5981739E7F1CC1EFD94BECAA338C8BEFCA1C036EF1F7804AD1BBE8B86C3BDDDA7868F9302E45F47BABB6A8D54E1871678AB37855761AAD6408EA4CEE8B4DE9A5972981B07EAC9CD496331C4E1104ED49ACB5F4F37DC9B98098C04053775DB2994B23CA4561C739DB5A19638C0D1D97C07EF26ADC912A5C6A3506B5E935E4C11E18769334B4D02CDB4802ACE68B55D2D3CD354B0DE2D4DB4727FAD43694110D90A4A18206A731466E83FCE2A6F8E042E1D244F7EA4DD2FF3B9E3910C2B7672E4605A2025BDAA0D67455F8FD50FD241B5074FD260210367434B -20240828044803 2 6 100 2047 5 E8198A1A9FF997DF62B131D5C187C3160A61128E5DC14FED2EC25E38EE627FC070B240AFA70179A5981739E7F1CC1EFD94BECAA338C8BEFCA1C036EF1F7804AD1BBE8B86C3BDDDA7868F9302E45F47BABB6A8D54E1871678AB37855761AAD6408EA4CEE8B4DE9A5972981B07EAC9CD496331C4E1104ED49ACB5F4F37DC9B98098C04053775DB2994B23CA4561C739DB5A19638C0D1D97C07EF26ADC912A5C6A3506B5E935E4C11E18769334B4D02CDB4802ACE68B55D2D3CD354B0DE2D4DB4727FAD43694110D90A4A18206A731466E83FCE2A6F8E042E1D244F7EA4DD2FF3B9E3910C2B7672E4605A2025BDAA0D67455F8FD50FD241B5074FD2602103A3B7DF -20240828044807 2 6 100 2047 2 E8198A1A9FF997DF62B131D5C187C3160A61128E5DC14FED2EC25E38EE627FC070B240AFA70179A5981739E7F1CC1EFD94BECAA338C8BEFCA1C036EF1F7804AD1BBE8B86C3BDDDA7868F9302E45F47BABB6A8D54E1871678AB37855761AAD6408EA4CEE8B4DE9A5972981B07EAC9CD496331C4E1104ED49ACB5F4F37DC9B98098C04053775DB2994B23CA4561C739DB5A19638C0D1D97C07EF26ADC912A5C6A3506B5E935E4C11E18769334B4D02CDB4802ACE68B55D2D3CD354B0DE2D4DB4727FAD43694110D90A4A18206A731466E83FCE2A6F8E042E1D244F7EA4DD2FF3B9E3910C2B7672E4605A2025BDAA0D67455F8FD50FD241B5074FD2602103C2D9CB -20240828044812 2 6 100 2047 2 E8198A1A9FF997DF62B131D5C187C3160A61128E5DC14FED2EC25E38EE627FC070B240AFA70179A5981739E7F1CC1EFD94BECAA338C8BEFCA1C036EF1F7804AD1BBE8B86C3BDDDA7868F9302E45F47BABB6A8D54E1871678AB37855761AAD6408EA4CEE8B4DE9A5972981B07EAC9CD496331C4E1104ED49ACB5F4F37DC9B98098C04053775DB2994B23CA4561C739DB5A19638C0D1D97C07EF26ADC912A5C6A3506B5E935E4C11E18769334B4D02CDB4802ACE68B55D2D3CD354B0DE2D4DB4727FAD43694110D90A4A18206A731466E83FCE2A6F8E042E1D244F7EA4DD2FF3B9E3910C2B7672E4605A2025BDAA0D67455F8FD50FD241B5074FD2602103DE1313 -20240828044821 2 6 100 2047 2 E8198A1A9FF997DF62B131D5C187C3160A61128E5DC14FED2EC25E38EE627FC070B240AFA70179A5981739E7F1CC1EFD94BECAA338C8BEFCA1C036EF1F7804AD1BBE8B86C3BDDDA7868F9302E45F47BABB6A8D54E1871678AB37855761AAD6408EA4CEE8B4DE9A5972981B07EAC9CD496331C4E1104ED49ACB5F4F37DC9B98098C04053775DB2994B23CA4561C739DB5A19638C0D1D97C07EF26ADC912A5C6A3506B5E935E4C11E18769334B4D02CDB4802ACE68B55D2D3CD354B0DE2D4DB4727FAD43694110D90A4A18206A731466E83FCE2A6F8E042E1D244F7EA4DD2FF3B9E3910C2B7672E4605A2025BDAA0D67455F8FD50FD241B5074FD2602104264E53 -20240828044835 2 6 100 2047 5 E8198A1A9FF997DF62B131D5C187C3160A61128E5DC14FED2EC25E38EE627FC070B240AFA70179A5981739E7F1CC1EFD94BECAA338C8BEFCA1C036EF1F7804AD1BBE8B86C3BDDDA7868F9302E45F47BABB6A8D54E1871678AB37855761AAD6408EA4CEE8B4DE9A5972981B07EAC9CD496331C4E1104ED49ACB5F4F37DC9B98098C04053775DB2994B23CA4561C739DB5A19638C0D1D97C07EF26ADC912A5C6A3506B5E935E4C11E18769334B4D02CDB4802ACE68B55D2D3CD354B0DE2D4DB4727FAD43694110D90A4A18206A731466E83FCE2A6F8E042E1D244F7EA4DD2FF3B9E3910C2B7672E4605A2025BDAA0D67455F8FD50FD241B5074FD2602104909817 -20240828044855 2 6 100 2047 2 E8198A1A9FF997DF62B131D5C187C3160A61128E5DC14FED2EC25E38EE627FC070B240AFA70179A5981739E7F1CC1EFD94BECAA338C8BEFCA1C036EF1F7804AD1BBE8B86C3BDDDA7868F9302E45F47BABB6A8D54E1871678AB37855761AAD6408EA4CEE8B4DE9A5972981B07EAC9CD496331C4E1104ED49ACB5F4F37DC9B98098C04053775DB2994B23CA4561C739DB5A19638C0D1D97C07EF26ADC912A5C6A3506B5E935E4C11E18769334B4D02CDB4802ACE68B55D2D3CD354B0DE2D4DB4727FAD43694110D90A4A18206A731466E83FCE2A6F8E042E1D244F7EA4DD2FF3B9E3910C2B7672E4605A2025BDAA0D67455F8FD50FD241B5074FD2602105309B8B -20240828044903 2 6 100 2047 5 E8198A1A9FF997DF62B131D5C187C3160A61128E5DC14FED2EC25E38EE627FC070B240AFA70179A5981739E7F1CC1EFD94BECAA338C8BEFCA1C036EF1F7804AD1BBE8B86C3BDDDA7868F9302E45F47BABB6A8D54E1871678AB37855761AAD6408EA4CEE8B4DE9A5972981B07EAC9CD496331C4E1104ED49ACB5F4F37DC9B98098C04053775DB2994B23CA4561C739DB5A19638C0D1D97C07EF26ADC912A5C6A3506B5E935E4C11E18769334B4D02CDB4802ACE68B55D2D3CD354B0DE2D4DB4727FAD43694110D90A4A18206A731466E83FCE2A6F8E042E1D244F7EA4DD2FF3B9E3910C2B7672E4605A2025BDAA0D67455F8FD50FD241B5074FD26021056A2A5F -20240828044903 2 6 100 2047 2 E8198A1A9FF997DF62B131D5C187C3160A61128E5DC14FED2EC25E38EE627FC070B240AFA70179A5981739E7F1CC1EFD94BECAA338C8BEFCA1C036EF1F7804AD1BBE8B86C3BDDDA7868F9302E45F47BABB6A8D54E1871678AB37855761AAD6408EA4CEE8B4DE9A5972981B07EAC9CD496331C4E1104ED49ACB5F4F37DC9B98098C04053775DB2994B23CA4561C739DB5A19638C0D1D97C07EF26ADC912A5C6A3506B5E935E4C11E18769334B4D02CDB4802ACE68B55D2D3CD354B0DE2D4DB4727FAD43694110D90A4A18206A731466E83FCE2A6F8E042E1D244F7EA4DD2FF3B9E3910C2B7672E4605A2025BDAA0D67455F8FD50FD241B5074FD26021056A52EB -20240828044921 2 6 100 2047 2 E8198A1A9FF997DF62B131D5C187C3160A61128E5DC14FED2EC25E38EE627FC070B240AFA70179A5981739E7F1CC1EFD94BECAA338C8BEFCA1C036EF1F7804AD1BBE8B86C3BDDDA7868F9302E45F47BABB6A8D54E1871678AB37855761AAD6408EA4CEE8B4DE9A5972981B07EAC9CD496331C4E1104ED49ACB5F4F37DC9B98098C04053775DB2994B23CA4561C739DB5A19638C0D1D97C07EF26ADC912A5C6A3506B5E935E4C11E18769334B4D02CDB4802ACE68B55D2D3CD354B0DE2D4DB4727FAD43694110D90A4A18206A731466E83FCE2A6F8E042E1D244F7EA4DD2FF3B9E3910C2B7672E4605A2025BDAA0D67455F8FD50FD241B5074FD2602105F6DDD3 -20240828044930 2 6 100 2047 2 E8198A1A9FF997DF62B131D5C187C3160A61128E5DC14FED2EC25E38EE627FC070B240AFA70179A5981739E7F1CC1EFD94BECAA338C8BEFCA1C036EF1F7804AD1BBE8B86C3BDDDA7868F9302E45F47BABB6A8D54E1871678AB37855761AAD6408EA4CEE8B4DE9A5972981B07EAC9CD496331C4E1104ED49ACB5F4F37DC9B98098C04053775DB2994B23CA4561C739DB5A19638C0D1D97C07EF26ADC912A5C6A3506B5E935E4C11E18769334B4D02CDB4802ACE68B55D2D3CD354B0DE2D4DB4727FAD43694110D90A4A18206A731466E83FCE2A6F8E042E1D244F7EA4DD2FF3B9E3910C2B7672E4605A2025BDAA0D67455F8FD50FD241B5074FD26021063AE353 -20240828044934 2 6 100 2047 5 E8198A1A9FF997DF62B131D5C187C3160A61128E5DC14FED2EC25E38EE627FC070B240AFA70179A5981739E7F1CC1EFD94BECAA338C8BEFCA1C036EF1F7804AD1BBE8B86C3BDDDA7868F9302E45F47BABB6A8D54E1871678AB37855761AAD6408EA4CEE8B4DE9A5972981B07EAC9CD496331C4E1104ED49ACB5F4F37DC9B98098C04053775DB2994B23CA4561C739DB5A19638C0D1D97C07EF26ADC912A5C6A3506B5E935E4C11E18769334B4D02CDB4802ACE68B55D2D3CD354B0DE2D4DB4727FAD43694110D90A4A18206A731466E83FCE2A6F8E042E1D244F7EA4DD2FF3B9E3910C2B7672E4605A2025BDAA0D67455F8FD50FD241B5074FD260210651B5C7 -20240828044937 2 6 100 2047 2 E8198A1A9FF997DF62B131D5C187C3160A61128E5DC14FED2EC25E38EE627FC070B240AFA70179A5981739E7F1CC1EFD94BECAA338C8BEFCA1C036EF1F7804AD1BBE8B86C3BDDDA7868F9302E45F47BABB6A8D54E1871678AB37855761AAD6408EA4CEE8B4DE9A5972981B07EAC9CD496331C4E1104ED49ACB5F4F37DC9B98098C04053775DB2994B23CA4561C739DB5A19638C0D1D97C07EF26ADC912A5C6A3506B5E935E4C11E18769334B4D02CDB4802ACE68B55D2D3CD354B0DE2D4DB4727FAD43694110D90A4A18206A731466E83FCE2A6F8E042E1D244F7EA4DD2FF3B9E3910C2B7672E4605A2025BDAA0D67455F8FD50FD241B5074FD2602106651B4B -20240828044944 2 6 100 2047 2 E8198A1A9FF997DF62B131D5C187C3160A61128E5DC14FED2EC25E38EE627FC070B240AFA70179A5981739E7F1CC1EFD94BECAA338C8BEFCA1C036EF1F7804AD1BBE8B86C3BDDDA7868F9302E45F47BABB6A8D54E1871678AB37855761AAD6408EA4CEE8B4DE9A5972981B07EAC9CD496331C4E1104ED49ACB5F4F37DC9B98098C04053775DB2994B23CA4561C739DB5A19638C0D1D97C07EF26ADC912A5C6A3506B5E935E4C11E18769334B4D02CDB4802ACE68B55D2D3CD354B0DE2D4DB4727FAD43694110D90A4A18206A731466E83FCE2A6F8E042E1D244F7EA4DD2FF3B9E3910C2B7672E4605A2025BDAA0D67455F8FD50FD241B5074FD26021069D4573 -20240828045003 2 6 100 2047 2 E8198A1A9FF997DF62B131D5C187C3160A61128E5DC14FED2EC25E38EE627FC070B240AFA70179A5981739E7F1CC1EFD94BECAA338C8BEFCA1C036EF1F7804AD1BBE8B86C3BDDDA7868F9302E45F47BABB6A8D54E1871678AB37855761AAD6408EA4CEE8B4DE9A5972981B07EAC9CD496331C4E1104ED49ACB5F4F37DC9B98098C04053775DB2994B23CA4561C739DB5A19638C0D1D97C07EF26ADC912A5C6A3506B5E935E4C11E18769334B4D02CDB4802ACE68B55D2D3CD354B0DE2D4DB4727FAD43694110D90A4A18206A731466E83FCE2A6F8E042E1D244F7EA4DD2FF3B9E3910C2B7672E4605A2025BDAA0D67455F8FD50FD241B5074FD26021072D06EB -20240828045023 2 6 100 2047 2 E8198A1A9FF997DF62B131D5C187C3160A61128E5DC14FED2EC25E38EE627FC070B240AFA70179A5981739E7F1CC1EFD94BECAA338C8BEFCA1C036EF1F7804AD1BBE8B86C3BDDDA7868F9302E45F47BABB6A8D54E1871678AB37855761AAD6408EA4CEE8B4DE9A5972981B07EAC9CD496331C4E1104ED49ACB5F4F37DC9B98098C04053775DB2994B23CA4561C739DB5A19638C0D1D97C07EF26ADC912A5C6A3506B5E935E4C11E18769334B4D02CDB4802ACE68B55D2D3CD354B0DE2D4DB4727FAD43694110D90A4A18206A731466E83FCE2A6F8E042E1D244F7EA4DD2FF3B9E3910C2B7672E4605A2025BDAA0D67455F8FD50FD241B5074FD2602107C5C8DB -20240828045043 2 6 100 2047 2 E8198A1A9FF997DF62B131D5C187C3160A61128E5DC14FED2EC25E38EE627FC070B240AFA70179A5981739E7F1CC1EFD94BECAA338C8BEFCA1C036EF1F7804AD1BBE8B86C3BDDDA7868F9302E45F47BABB6A8D54E1871678AB37855761AAD6408EA4CEE8B4DE9A5972981B07EAC9CD496331C4E1104ED49ACB5F4F37DC9B98098C04053775DB2994B23CA4561C739DB5A19638C0D1D97C07EF26ADC912A5C6A3506B5E935E4C11E18769334B4D02CDB4802ACE68B55D2D3CD354B0DE2D4DB4727FAD43694110D90A4A18206A731466E83FCE2A6F8E042E1D244F7EA4DD2FF3B9E3910C2B7672E4605A2025BDAA0D67455F8FD50FD241B5074FD26021085D358B -20240828045540 2 6 100 3071 5 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DB83F1177 -20240828045614 2 6 100 3071 5 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DB8AA8ABF -20240828045644 2 6 100 3071 2 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DB90E7B73 -20240828045720 2 6 100 3071 5 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DB984B19F -20240828045813 2 6 100 3071 5 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DBA2CAEB7 -20240828045858 2 6 100 3071 2 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DBABFBAAB -20240828045903 2 6 100 3071 5 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DBACAA69F -20240828045912 2 6 100 3071 2 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DBAE15E2B -20240828045932 2 6 100 3071 5 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DBB1CB097 -20240828050005 2 6 100 3071 5 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DBB86CA4F -20240828050036 2 6 100 3071 5 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DBBEDB4C7 -20240828050043 2 6 100 3071 5 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DBBFC577F -20240828050107 2 6 100 3071 2 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DBC490C0B -20240828050136 2 6 100 3071 5 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DBCA8444F -20240828050201 2 6 100 3071 2 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DBCFC24F3 -20240828050209 2 6 100 3071 2 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DBD0E9213 -20240828050303 2 6 100 3071 2 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DBDBBE653 -20240828050329 2 6 100 3071 2 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DBE0AE17B -20240828050406 2 6 100 3071 2 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DBE8344F3 -20240828050430 2 6 100 3071 2 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DBEC9D58B -20240828050438 2 6 100 3071 2 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DBEDF58FB -20240828050528 2 6 100 3071 2 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DBF858DCB -20240828050633 2 6 100 3071 5 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DC0619997 -20240828050638 2 6 100 3071 2 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DC06A2A8B -20240828050712 2 6 100 3071 5 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DC0D40C6F -20240828050715 2 6 100 3071 5 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DC0D78F7F -20240828050743 2 6 100 3071 5 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DC12FBEF7 -20240828050851 2 6 100 3071 2 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DC216E8EB -20240828050903 2 6 100 3071 5 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DC235154F -20240828050905 2 6 100 3071 2 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DC235B9E3 -20240828050941 2 6 100 3071 5 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DC2AA4F87 -20240828051038 2 6 100 3071 2 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DC36951FB -20240828051046 2 6 100 3071 2 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DC37DE073 -20240828051104 2 6 100 3071 2 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DC3B311A3 -20240828051215 2 6 100 3071 2 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DC4A3904B -20240828051246 2 6 100 3071 2 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DC502215B -20240828051312 2 6 100 3071 2 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DC5506613 -20240828051329 2 6 100 3071 2 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DC57E32D3 -20240828051336 2 6 100 3071 2 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DC58E630B -20240828051520 2 6 100 3071 2 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DC6DF9DDB -20240828051549 2 6 100 3071 2 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DC736A7B3 -20240828051622 2 6 100 3071 2 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DC7A11C13 -20240828051823 2 6 100 3071 2 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DC933AB0B -20240828051906 2 6 100 3071 5 F0E30849E47025007BE82AED18F1B234816DC958D27A2133A1FEA5C9D5B00C107D4C3563B295FB10AA1BEFB5C160159F85A69C3990D6A5078FEE7D5462F14890168BF2AA6B06729778AF1CDA95F5EB5FD024D9A4B904FB6501213268D69167449CCEF555129648DA0C6C1500DB898ABAEBE716B468AFDADB8E499D0043B7D4070A957EF41EF2ED3D9DB4EB8607B620C714084F6909D0B980FC54E7BA3A4F7C6716BC8430C5D73475A95F64B8AA9BB6F9CD524EFEC35E322F10DA32826E005EBA1C81EA662FB1517EED4D778DB6658C7D6150F144BBA60DAE6B75499E70CD7D70842131C00E04319DB1B53867E6BF820B1D74692227A574F937B668F25017F6DB3D6FEB2A61F8E377FA73E8652089A0ECBE15AD1CB8C44D738AB114BBE7AB9985545DE182011208113A56C5D84D8E7640517C5EFA28670168906BA869583EFEE72F89C1B3CA019C4D544B711A9A0297911CBEEB124EA9D7076696F62AC9E8814CDA985B35800D4DB253497725F131169F56AF543DD51EED43501A249DC9BF25EF -20240828052009 2 6 100 3071 2 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79BBF34E3B -20240828052030 2 6 100 3071 2 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79BC38F533 -20240828052045 2 6 100 3071 5 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79BC632227 -20240828052153 2 6 100 3071 5 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79BD42ABFF -20240828052207 2 6 100 3071 5 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79BD6986DF -20240828052211 2 6 100 3071 5 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79BD7241F7 -20240828052259 2 6 100 3071 2 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79BE0ECA0B -20240828052336 2 6 100 3071 2 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79BE863B2B -20240828052339 2 6 100 3071 5 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79BE899267 -20240828052415 2 6 100 3071 2 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79BF03197B -20240828052431 2 6 100 3071 2 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79BF33F3BB -20240828052513 2 6 100 3071 5 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79BFBAA987 -20240828052522 2 6 100 3071 2 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79BFD18B5B -20240828052527 2 6 100 3071 2 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79BFDA82D3 -20240828052609 2 6 100 3071 5 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79C0656637 -20240828052616 2 6 100 3071 2 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79C07626F3 -20240828052621 2 6 100 3071 2 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79C07E39AB -20240828052816 2 6 100 3071 2 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79C2033C13 -20240828052903 2 6 100 3071 2 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79C29B2063 -20240828052932 2 6 100 3071 2 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79C2FB438B -20240828052959 2 6 100 3071 2 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79C35070C3 -20240828053054 2 6 100 3071 2 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79C4050DE3 -20240828053223 2 6 100 3071 5 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79C52F78A7 -20240828053319 2 6 100 3071 2 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79C5E6180B -20240828053339 2 6 100 3071 2 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79C61E1503 -20240828053345 2 6 100 3071 2 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79C62B8123 -20240828053430 2 6 100 3071 2 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79C6B80C6B -20240828053549 2 6 100 3071 5 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79C7B7959F -20240828053758 2 6 100 3071 2 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79C95C0E23 -20240828053817 2 6 100 3071 2 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79C9938013 -20240828053837 2 6 100 3071 5 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79C9D0494F -20240828053914 2 6 100 3071 5 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79CA42683F -20240828054013 2 6 100 3071 2 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79CB06EC0B -20240828054258 2 6 100 3071 2 F92C6D0F2F9D19FE24813B351098A85FABD54907EA3F2B1DDC129631277DD947357AAEA3FBDAF717CF7FB244ED5EA7475AA7AB9F8CC8E92BFEBA6B9F4394EFEFDAB17F42338B58FEB6B09CD728221C9261C1FB59A2EEBDD7A974CD3D56031DA903E422D77061725705DC1366F17C530CFB45A704C00018D78004241F3CF6AD1C934F576F8D4C542FD83BBE0C8C3B122063A7457D3A47D1EC0A2266A36ABB664E96959D60C46344757771F7DBD79B25F033CA5E7674DDD2AC03F79C7C8E2B637CF3C9DD55D3FD5BDDB1CEE1B5F57B72B01F91BCD385AF7AD03C183EA95D95D07838BE129BDF7B724A27FC2ED5AF6AE17C995ACDB42C783845342A07BB2318A392B21912B8E4165B1A4688C35FFBB23B733DCD0136373E308F9320A5C2BAF95492F6E4F5964B18917846376B2ADB2E2892B1D51DDC63578DFA361EA5190E39B6E93772B2A3F66CD6B0B183F41A68A31AA7E9A23DDBE383AC2E262C368DC859989BA361A683A9B7F3B158A1BC9ECF4F8669F363DAF10ECE0EB29581CB79CD234BAB -20240828060009 2 6 100 4095 2 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A70951B13 -20240828060511 2 6 100 4095 5 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A726F0C37 -20240828060714 2 6 100 4095 2 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A7335AED3 -20240828061156 2 6 100 4095 2 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A7501901B -20240828061217 2 6 100 4095 2 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A751A9A43 -20240828061522 2 6 100 4095 5 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A763D53FF -20240828061600 2 6 100 4095 5 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A7675A20F -20240828061619 2 6 100 4095 2 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A768B4D03 -20240828061636 2 6 100 4095 2 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A769E17B3 -20240828062452 2 6 100 4095 2 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A79B996BB -20240828062521 2 6 100 4095 2 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A79E2492B -20240828062623 2 6 100 4095 2 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A7A419E13 -20240828062831 2 6 100 4095 2 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A7B0C50CB -20240828062854 2 6 100 4095 2 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A7B27FC2B -20240828063249 2 6 100 4095 2 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A7CA08843 -20240828063334 2 6 100 4095 5 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A7CE52E4F -20240828063443 2 6 100 4095 2 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A7D4D4863 -20240828063548 2 6 100 4095 2 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A7DAC7243 -20240828063629 2 6 100 4095 2 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A7DE88D73 -20240828064128 2 6 100 4095 2 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A7FCA819B -20240828064626 2 6 100 4095 2 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A819B3083 -20240828064816 2 6 100 4095 2 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A8247AB73 -20240828065323 2 6 100 4095 5 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A84385B67 -20240828065513 2 6 100 4095 2 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A84DF9C03 -20240828070128 2 6 100 4095 2 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A872AEE03 -20240828070200 2 6 100 4095 5 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A87566497 -20240828070537 2 6 100 4095 5 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A88AEB07F -20240828070904 2 6 100 4095 5 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A8A00154F -20240828071020 2 6 100 4095 2 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A8A740023 -20240828071247 2 6 100 4095 2 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A8B633D9B -20240828071353 2 6 100 4095 2 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A8BC1DD33 -20240828071426 2 6 100 4095 2 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A8BF0634B -20240828071455 2 6 100 4095 2 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A8C19F3D3 -20240828071541 2 6 100 4095 2 C1FD462836A96C337420C7007228E616EC573732284C62893AB8CC4E3F3E182E3A2FC77E35BC37FC6A207BB3B56EEAD789DFE450ECA8A88518B4EBACEF11D667EA651A91285ED252C792EB32026784FE21B43F3E4B61DBB0E26D3DC6EE8B9090CCDFA2876C4CABA186BA994026CF4AE3D17DC5A0D1B4D70F58EA021ACA38F9D1EC7CFF066D1F0C1DEEAED46C531E9719664DC3AD0E61FE171E558BD54FB13004B7E19B3AD908A5FDA716B1AFF98F48527F12F755CB53E0ACE01192CD0CFAA0B7623D1E035DED85CD39B69922E719FFD315DEADD6AEA9064B7DBB7F1079FB06C0442AB9E364E2E756D6EA8C07A92E9BB03EA11678BD0AE1ECC81748068B0658EC1E0C54886933C5BC69BED9334255F55748403F957CE5F314D8F154E213068BAC299C0D323623D4FECF1C17601E347500A00F8AFB1FD63C936842FE87831519613BD966C1653F623A42F236CCB0AEE2E81F702C8CC6E560999B686E3C5B4DE07ABD8DE477D0475F5CE1C61D3D8B1919C378D9AC041F21AC522530F7A4D62125D8DB8F8217BDB3E330A04758448AF7093A65591A0E7E82BA13F6F92CCC68AFD64A965D13A7C36ED85916B3EF9C3AB022E6F66A4317AA01B201BED766AFF938563E93784662AF2F72AE5BA52CF2B0C4ADAF6C20689296CF729D5A643A64A20E4380DE5E3C932CD162C12D55650AECDAAA74FEA3C85B534EF588D2693B7A8C5E63D3 -20240828071923 2 6 100 4095 2 E36F035A457FE7C42A6DFEA5F5F192B2FB147FA8B29FD9BE0FB4DB472F5668038712145FFD9C047435AAA518C55B975D814D566AA3233887D5C2C886B754D50B133FE132D81A0851637D6085F2289D8584BF5130452AD24DD87D7158CDAC16832D42476486F0EC2DBBCD38CEE963C5E367ADE50C9502735AD3583445AABEE10E63480E3791FFC7BCF4BD5C1F6E9768E1B1D9B6B75E177F95914B6D5F06CA7CB001B15CAD26B9C20565F8351E69B5E6CA74D30E770523BA7E05475050DCF81A3F9B7C38EF1C31447E35543AE5B00E0BB13C63F8F1DCE0397BF523882AB79E2DF4BDF7E18ED799142089E79CE6AC0E562A587B055D9F963260DAA84A1C520A0D46A01138F20B0EAF73300DD4196A403892EC30B2C84860C4EC4A1FE5778512F546F5B813380393D3BABC535668515BEEFA350207C3BFA1502B52A775146FA97E4CBF701C2DC7845FF604EC73052F217185E74813FD18D3EBA6489E0BD00852B156193735F5A34952DCFD4BD493ECD2C9948E9D4436A79B1F5B6BB7991F1253B8B68BA7511EF94B87D4D9843A5A510837C7AFCD7F42A9657C78BA516606F94BC27F1579BBC0776216AC8B96C2D6D485B6C6EE489C504E32A6B4979287D53E42D120D411F849C748B31FCB2CEB1663C813A0E327DCC18242B484CBF5F9191063933EFEC4C6A600C415B0F29365F6DBBD2DE794D7E14D62CFD7F1E570D1A9B3CF4313 -20240828072226 2 6 100 4095 5 E36F035A457FE7C42A6DFEA5F5F192B2FB147FA8B29FD9BE0FB4DB472F5668038712145FFD9C047435AAA518C55B975D814D566AA3233887D5C2C886B754D50B133FE132D81A0851637D6085F2289D8584BF5130452AD24DD87D7158CDAC16832D42476486F0EC2DBBCD38CEE963C5E367ADE50C9502735AD3583445AABEE10E63480E3791FFC7BCF4BD5C1F6E9768E1B1D9B6B75E177F95914B6D5F06CA7CB001B15CAD26B9C20565F8351E69B5E6CA74D30E770523BA7E05475050DCF81A3F9B7C38EF1C31447E35543AE5B00E0BB13C63F8F1DCE0397BF523882AB79E2DF4BDF7E18ED799142089E79CE6AC0E562A587B055D9F963260DAA84A1C520A0D46A01138F20B0EAF73300DD4196A403892EC30B2C84860C4EC4A1FE5778512F546F5B813380393D3BABC535668515BEEFA350207C3BFA1502B52A775146FA97E4CBF701C2DC7845FF604EC73052F217185E74813FD18D3EBA6489E0BD00852B156193735F5A34952DCFD4BD493ECD2C9948E9D4436A79B1F5B6BB7991F1253B8B68BA7511EF94B87D4D9843A5A510837C7AFCD7F42A9657C78BA516606F94BC27F1579BBC0776216AC8B96C2D6D485B6C6EE489C504E32A6B4979287D53E42D120D411F849C748B31FCB2CEB1663C813A0E327DCC18242B484CBF5F9191063933EFEC4C6A600C415B0F29365F6DBBD2DE794D7E14D62CFD7F1E570D1A9B4F5B7EF -20240828072458 2 6 100 4095 2 E36F035A457FE7C42A6DFEA5F5F192B2FB147FA8B29FD9BE0FB4DB472F5668038712145FFD9C047435AAA518C55B975D814D566AA3233887D5C2C886B754D50B133FE132D81A0851637D6085F2289D8584BF5130452AD24DD87D7158CDAC16832D42476486F0EC2DBBCD38CEE963C5E367ADE50C9502735AD3583445AABEE10E63480E3791FFC7BCF4BD5C1F6E9768E1B1D9B6B75E177F95914B6D5F06CA7CB001B15CAD26B9C20565F8351E69B5E6CA74D30E770523BA7E05475050DCF81A3F9B7C38EF1C31447E35543AE5B00E0BB13C63F8F1DCE0397BF523882AB79E2DF4BDF7E18ED799142089E79CE6AC0E562A587B055D9F963260DAA84A1C520A0D46A01138F20B0EAF73300DD4196A403892EC30B2C84860C4EC4A1FE5778512F546F5B813380393D3BABC535668515BEEFA350207C3BFA1502B52A775146FA97E4CBF701C2DC7845FF604EC73052F217185E74813FD18D3EBA6489E0BD00852B156193735F5A34952DCFD4BD493ECD2C9948E9D4436A79B1F5B6BB7991F1253B8B68BA7511EF94B87D4D9843A5A510837C7AFCD7F42A9657C78BA516606F94BC27F1579BBC0776216AC8B96C2D6D485B6C6EE489C504E32A6B4979287D53E42D120D411F849C748B31FCB2CEB1663C813A0E327DCC18242B484CBF5F9191063933EFEC4C6A600C415B0F29365F6DBBD2DE794D7E14D62CFD7F1E570D1A9B5EF31DB -20240828073047 2 6 100 4095 5 E36F035A457FE7C42A6DFEA5F5F192B2FB147FA8B29FD9BE0FB4DB472F5668038712145FFD9C047435AAA518C55B975D814D566AA3233887D5C2C886B754D50B133FE132D81A0851637D6085F2289D8584BF5130452AD24DD87D7158CDAC16832D42476486F0EC2DBBCD38CEE963C5E367ADE50C9502735AD3583445AABEE10E63480E3791FFC7BCF4BD5C1F6E9768E1B1D9B6B75E177F95914B6D5F06CA7CB001B15CAD26B9C20565F8351E69B5E6CA74D30E770523BA7E05475050DCF81A3F9B7C38EF1C31447E35543AE5B00E0BB13C63F8F1DCE0397BF523882AB79E2DF4BDF7E18ED799142089E79CE6AC0E562A587B055D9F963260DAA84A1C520A0D46A01138F20B0EAF73300DD4196A403892EC30B2C84860C4EC4A1FE5778512F546F5B813380393D3BABC535668515BEEFA350207C3BFA1502B52A775146FA97E4CBF701C2DC7845FF604EC73052F217185E74813FD18D3EBA6489E0BD00852B156193735F5A34952DCFD4BD493ECD2C9948E9D4436A79B1F5B6BB7991F1253B8B68BA7511EF94B87D4D9843A5A510837C7AFCD7F42A9657C78BA516606F94BC27F1579BBC0776216AC8B96C2D6D485B6C6EE489C504E32A6B4979287D53E42D120D411F849C748B31FCB2CEB1663C813A0E327DCC18242B484CBF5F9191063933EFEC4C6A600C415B0F29365F6DBBD2DE794D7E14D62CFD7F1E570D1A9B82262CF -20240828073253 2 6 100 4095 2 E36F035A457FE7C42A6DFEA5F5F192B2FB147FA8B29FD9BE0FB4DB472F5668038712145FFD9C047435AAA518C55B975D814D566AA3233887D5C2C886B754D50B133FE132D81A0851637D6085F2289D8584BF5130452AD24DD87D7158CDAC16832D42476486F0EC2DBBCD38CEE963C5E367ADE50C9502735AD3583445AABEE10E63480E3791FFC7BCF4BD5C1F6E9768E1B1D9B6B75E177F95914B6D5F06CA7CB001B15CAD26B9C20565F8351E69B5E6CA74D30E770523BA7E05475050DCF81A3F9B7C38EF1C31447E35543AE5B00E0BB13C63F8F1DCE0397BF523882AB79E2DF4BDF7E18ED799142089E79CE6AC0E562A587B055D9F963260DAA84A1C520A0D46A01138F20B0EAF73300DD4196A403892EC30B2C84860C4EC4A1FE5778512F546F5B813380393D3BABC535668515BEEFA350207C3BFA1502B52A775146FA97E4CBF701C2DC7845FF604EC73052F217185E74813FD18D3EBA6489E0BD00852B156193735F5A34952DCFD4BD493ECD2C9948E9D4436A79B1F5B6BB7991F1253B8B68BA7511EF94B87D4D9843A5A510837C7AFCD7F42A9657C78BA516606F94BC27F1579BBC0776216AC8B96C2D6D485B6C6EE489C504E32A6B4979287D53E42D120D411F849C748B31FCB2CEB1663C813A0E327DCC18242B484CBF5F9191063933EFEC4C6A600C415B0F29365F6DBBD2DE794D7E14D62CFD7F1E570D1A9B8EDB05B -20240828074035 2 6 100 4095 5 E36F035A457FE7C42A6DFEA5F5F192B2FB147FA8B29FD9BE0FB4DB472F5668038712145FFD9C047435AAA518C55B975D814D566AA3233887D5C2C886B754D50B133FE132D81A0851637D6085F2289D8584BF5130452AD24DD87D7158CDAC16832D42476486F0EC2DBBCD38CEE963C5E367ADE50C9502735AD3583445AABEE10E63480E3791FFC7BCF4BD5C1F6E9768E1B1D9B6B75E177F95914B6D5F06CA7CB001B15CAD26B9C20565F8351E69B5E6CA74D30E770523BA7E05475050DCF81A3F9B7C38EF1C31447E35543AE5B00E0BB13C63F8F1DCE0397BF523882AB79E2DF4BDF7E18ED799142089E79CE6AC0E562A587B055D9F963260DAA84A1C520A0D46A01138F20B0EAF73300DD4196A403892EC30B2C84860C4EC4A1FE5778512F546F5B813380393D3BABC535668515BEEFA350207C3BFA1502B52A775146FA97E4CBF701C2DC7845FF604EC73052F217185E74813FD18D3EBA6489E0BD00852B156193735F5A34952DCFD4BD493ECD2C9948E9D4436A79B1F5B6BB7991F1253B8B68BA7511EF94B87D4D9843A5A510837C7AFCD7F42A9657C78BA516606F94BC27F1579BBC0776216AC8B96C2D6D485B6C6EE489C504E32A6B4979287D53E42D120D411F849C748B31FCB2CEB1663C813A0E327DCC18242B484CBF5F9191063933EFEC4C6A600C415B0F29365F6DBBD2DE794D7E14D62CFD7F1E570D1A9BBE344BF -20240828074440 2 6 100 4095 2 E36F035A457FE7C42A6DFEA5F5F192B2FB147FA8B29FD9BE0FB4DB472F5668038712145FFD9C047435AAA518C55B975D814D566AA3233887D5C2C886B754D50B133FE132D81A0851637D6085F2289D8584BF5130452AD24DD87D7158CDAC16832D42476486F0EC2DBBCD38CEE963C5E367ADE50C9502735AD3583445AABEE10E63480E3791FFC7BCF4BD5C1F6E9768E1B1D9B6B75E177F95914B6D5F06CA7CB001B15CAD26B9C20565F8351E69B5E6CA74D30E770523BA7E05475050DCF81A3F9B7C38EF1C31447E35543AE5B00E0BB13C63F8F1DCE0397BF523882AB79E2DF4BDF7E18ED799142089E79CE6AC0E562A587B055D9F963260DAA84A1C520A0D46A01138F20B0EAF73300DD4196A403892EC30B2C84860C4EC4A1FE5778512F546F5B813380393D3BABC535668515BEEFA350207C3BFA1502B52A775146FA97E4CBF701C2DC7845FF604EC73052F217185E74813FD18D3EBA6489E0BD00852B156193735F5A34952DCFD4BD493ECD2C9948E9D4436A79B1F5B6BB7991F1253B8B68BA7511EF94B87D4D9843A5A510837C7AFCD7F42A9657C78BA516606F94BC27F1579BBC0776216AC8B96C2D6D485B6C6EE489C504E32A6B4979287D53E42D120D411F849C748B31FCB2CEB1663C813A0E327DCC18242B484CBF5F9191063933EFEC4C6A600C415B0F29365F6DBBD2DE794D7E14D62CFD7F1E570D1A9BD60A58B -20240828074721 2 6 100 4095 5 E36F035A457FE7C42A6DFEA5F5F192B2FB147FA8B29FD9BE0FB4DB472F5668038712145FFD9C047435AAA518C55B975D814D566AA3233887D5C2C886B754D50B133FE132D81A0851637D6085F2289D8584BF5130452AD24DD87D7158CDAC16832D42476486F0EC2DBBCD38CEE963C5E367ADE50C9502735AD3583445AABEE10E63480E3791FFC7BCF4BD5C1F6E9768E1B1D9B6B75E177F95914B6D5F06CA7CB001B15CAD26B9C20565F8351E69B5E6CA74D30E770523BA7E05475050DCF81A3F9B7C38EF1C31447E35543AE5B00E0BB13C63F8F1DCE0397BF523882AB79E2DF4BDF7E18ED799142089E79CE6AC0E562A587B055D9F963260DAA84A1C520A0D46A01138F20B0EAF73300DD4196A403892EC30B2C84860C4EC4A1FE5778512F546F5B813380393D3BABC535668515BEEFA350207C3BFA1502B52A775146FA97E4CBF701C2DC7845FF604EC73052F217185E74813FD18D3EBA6489E0BD00852B156193735F5A34952DCFD4BD493ECD2C9948E9D4436A79B1F5B6BB7991F1253B8B68BA7511EF94B87D4D9843A5A510837C7AFCD7F42A9657C78BA516606F94BC27F1579BBC0776216AC8B96C2D6D485B6C6EE489C504E32A6B4979287D53E42D120D411F849C748B31FCB2CEB1663C813A0E327DCC18242B484CBF5F9191063933EFEC4C6A600C415B0F29365F6DBBD2DE794D7E14D62CFD7F1E570D1A9BE6938F7 -20240828075138 2 6 100 4095 2 E36F035A457FE7C42A6DFEA5F5F192B2FB147FA8B29FD9BE0FB4DB472F5668038712145FFD9C047435AAA518C55B975D814D566AA3233887D5C2C886B754D50B133FE132D81A0851637D6085F2289D8584BF5130452AD24DD87D7158CDAC16832D42476486F0EC2DBBCD38CEE963C5E367ADE50C9502735AD3583445AABEE10E63480E3791FFC7BCF4BD5C1F6E9768E1B1D9B6B75E177F95914B6D5F06CA7CB001B15CAD26B9C20565F8351E69B5E6CA74D30E770523BA7E05475050DCF81A3F9B7C38EF1C31447E35543AE5B00E0BB13C63F8F1DCE0397BF523882AB79E2DF4BDF7E18ED799142089E79CE6AC0E562A587B055D9F963260DAA84A1C520A0D46A01138F20B0EAF73300DD4196A403892EC30B2C84860C4EC4A1FE5778512F546F5B813380393D3BABC535668515BEEFA350207C3BFA1502B52A775146FA97E4CBF701C2DC7845FF604EC73052F217185E74813FD18D3EBA6489E0BD00852B156193735F5A34952DCFD4BD493ECD2C9948E9D4436A79B1F5B6BB7991F1253B8B68BA7511EF94B87D4D9843A5A510837C7AFCD7F42A9657C78BA516606F94BC27F1579BBC0776216AC8B96C2D6D485B6C6EE489C504E32A6B4979287D53E42D120D411F849C748B31FCB2CEB1663C813A0E327DCC18242B484CBF5F9191063933EFEC4C6A600C415B0F29365F6DBBD2DE794D7E14D62CFD7F1E570D1A9C00C2AD3 -20240828075304 2 6 100 4095 2 E36F035A457FE7C42A6DFEA5F5F192B2FB147FA8B29FD9BE0FB4DB472F5668038712145FFD9C047435AAA518C55B975D814D566AA3233887D5C2C886B754D50B133FE132D81A0851637D6085F2289D8584BF5130452AD24DD87D7158CDAC16832D42476486F0EC2DBBCD38CEE963C5E367ADE50C9502735AD3583445AABEE10E63480E3791FFC7BCF4BD5C1F6E9768E1B1D9B6B75E177F95914B6D5F06CA7CB001B15CAD26B9C20565F8351E69B5E6CA74D30E770523BA7E05475050DCF81A3F9B7C38EF1C31447E35543AE5B00E0BB13C63F8F1DCE0397BF523882AB79E2DF4BDF7E18ED799142089E79CE6AC0E562A587B055D9F963260DAA84A1C520A0D46A01138F20B0EAF73300DD4196A403892EC30B2C84860C4EC4A1FE5778512F546F5B813380393D3BABC535668515BEEFA350207C3BFA1502B52A775146FA97E4CBF701C2DC7845FF604EC73052F217185E74813FD18D3EBA6489E0BD00852B156193735F5A34952DCFD4BD493ECD2C9948E9D4436A79B1F5B6BB7991F1253B8B68BA7511EF94B87D4D9843A5A510837C7AFCD7F42A9657C78BA516606F94BC27F1579BBC0776216AC8B96C2D6D485B6C6EE489C504E32A6B4979287D53E42D120D411F849C748B31FCB2CEB1663C813A0E327DCC18242B484CBF5F9191063933EFEC4C6A600C415B0F29365F6DBBD2DE794D7E14D62CFD7F1E570D1A9C0911F9B -20240828075632 2 6 100 4095 2 E36F035A457FE7C42A6DFEA5F5F192B2FB147FA8B29FD9BE0FB4DB472F5668038712145FFD9C047435AAA518C55B975D814D566AA3233887D5C2C886B754D50B133FE132D81A0851637D6085F2289D8584BF5130452AD24DD87D7158CDAC16832D42476486F0EC2DBBCD38CEE963C5E367ADE50C9502735AD3583445AABEE10E63480E3791FFC7BCF4BD5C1F6E9768E1B1D9B6B75E177F95914B6D5F06CA7CB001B15CAD26B9C20565F8351E69B5E6CA74D30E770523BA7E05475050DCF81A3F9B7C38EF1C31447E35543AE5B00E0BB13C63F8F1DCE0397BF523882AB79E2DF4BDF7E18ED799142089E79CE6AC0E562A587B055D9F963260DAA84A1C520A0D46A01138F20B0EAF73300DD4196A403892EC30B2C84860C4EC4A1FE5778512F546F5B813380393D3BABC535668515BEEFA350207C3BFA1502B52A775146FA97E4CBF701C2DC7845FF604EC73052F217185E74813FD18D3EBA6489E0BD00852B156193735F5A34952DCFD4BD493ECD2C9948E9D4436A79B1F5B6BB7991F1253B8B68BA7511EF94B87D4D9843A5A510837C7AFCD7F42A9657C78BA516606F94BC27F1579BBC0776216AC8B96C2D6D485B6C6EE489C504E32A6B4979287D53E42D120D411F849C748B31FCB2CEB1663C813A0E327DCC18242B484CBF5F9191063933EFEC4C6A600C415B0F29365F6DBBD2DE794D7E14D62CFD7F1E570D1A9C1E1F5EB -20240828080239 2 6 100 4095 2 E36F035A457FE7C42A6DFEA5F5F192B2FB147FA8B29FD9BE0FB4DB472F5668038712145FFD9C047435AAA518C55B975D814D566AA3233887D5C2C886B754D50B133FE132D81A0851637D6085F2289D8584BF5130452AD24DD87D7158CDAC16832D42476486F0EC2DBBCD38CEE963C5E367ADE50C9502735AD3583445AABEE10E63480E3791FFC7BCF4BD5C1F6E9768E1B1D9B6B75E177F95914B6D5F06CA7CB001B15CAD26B9C20565F8351E69B5E6CA74D30E770523BA7E05475050DCF81A3F9B7C38EF1C31447E35543AE5B00E0BB13C63F8F1DCE0397BF523882AB79E2DF4BDF7E18ED799142089E79CE6AC0E562A587B055D9F963260DAA84A1C520A0D46A01138F20B0EAF73300DD4196A403892EC30B2C84860C4EC4A1FE5778512F546F5B813380393D3BABC535668515BEEFA350207C3BFA1502B52A775146FA97E4CBF701C2DC7845FF604EC73052F217185E74813FD18D3EBA6489E0BD00852B156193735F5A34952DCFD4BD493ECD2C9948E9D4436A79B1F5B6BB7991F1253B8B68BA7511EF94B87D4D9843A5A510837C7AFCD7F42A9657C78BA516606F94BC27F1579BBC0776216AC8B96C2D6D485B6C6EE489C504E32A6B4979287D53E42D120D411F849C748B31FCB2CEB1663C813A0E327DCC18242B484CBF5F9191063933EFEC4C6A600C415B0F29365F6DBBD2DE794D7E14D62CFD7F1E570D1A9C432FEB3 -20240828080841 2 6 100 4095 2 E36F035A457FE7C42A6DFEA5F5F192B2FB147FA8B29FD9BE0FB4DB472F5668038712145FFD9C047435AAA518C55B975D814D566AA3233887D5C2C886B754D50B133FE132D81A0851637D6085F2289D8584BF5130452AD24DD87D7158CDAC16832D42476486F0EC2DBBCD38CEE963C5E367ADE50C9502735AD3583445AABEE10E63480E3791FFC7BCF4BD5C1F6E9768E1B1D9B6B75E177F95914B6D5F06CA7CB001B15CAD26B9C20565F8351E69B5E6CA74D30E770523BA7E05475050DCF81A3F9B7C38EF1C31447E35543AE5B00E0BB13C63F8F1DCE0397BF523882AB79E2DF4BDF7E18ED799142089E79CE6AC0E562A587B055D9F963260DAA84A1C520A0D46A01138F20B0EAF73300DD4196A403892EC30B2C84860C4EC4A1FE5778512F546F5B813380393D3BABC535668515BEEFA350207C3BFA1502B52A775146FA97E4CBF701C2DC7845FF604EC73052F217185E74813FD18D3EBA6489E0BD00852B156193735F5A34952DCFD4BD493ECD2C9948E9D4436A79B1F5B6BB7991F1253B8B68BA7511EF94B87D4D9843A5A510837C7AFCD7F42A9657C78BA516606F94BC27F1579BBC0776216AC8B96C2D6D485B6C6EE489C504E32A6B4979287D53E42D120D411F849C748B31FCB2CEB1663C813A0E327DCC18242B484CBF5F9191063933EFEC4C6A600C415B0F29365F6DBBD2DE794D7E14D62CFD7F1E570D1A9C68352A3 -20240828081126 2 6 100 4095 2 E36F035A457FE7C42A6DFEA5F5F192B2FB147FA8B29FD9BE0FB4DB472F5668038712145FFD9C047435AAA518C55B975D814D566AA3233887D5C2C886B754D50B133FE132D81A0851637D6085F2289D8584BF5130452AD24DD87D7158CDAC16832D42476486F0EC2DBBCD38CEE963C5E367ADE50C9502735AD3583445AABEE10E63480E3791FFC7BCF4BD5C1F6E9768E1B1D9B6B75E177F95914B6D5F06CA7CB001B15CAD26B9C20565F8351E69B5E6CA74D30E770523BA7E05475050DCF81A3F9B7C38EF1C31447E35543AE5B00E0BB13C63F8F1DCE0397BF523882AB79E2DF4BDF7E18ED799142089E79CE6AC0E562A587B055D9F963260DAA84A1C520A0D46A01138F20B0EAF73300DD4196A403892EC30B2C84860C4EC4A1FE5778512F546F5B813380393D3BABC535668515BEEFA350207C3BFA1502B52A775146FA97E4CBF701C2DC7845FF604EC73052F217185E74813FD18D3EBA6489E0BD00852B156193735F5A34952DCFD4BD493ECD2C9948E9D4436A79B1F5B6BB7991F1253B8B68BA7511EF94B87D4D9843A5A510837C7AFCD7F42A9657C78BA516606F94BC27F1579BBC0776216AC8B96C2D6D485B6C6EE489C504E32A6B4979287D53E42D120D411F849C748B31FCB2CEB1663C813A0E327DCC18242B484CBF5F9191063933EFEC4C6A600C415B0F29365F6DBBD2DE794D7E14D62CFD7F1E570D1A9C78B996B -20240828081614 2 6 100 4095 2 E36F035A457FE7C42A6DFEA5F5F192B2FB147FA8B29FD9BE0FB4DB472F5668038712145FFD9C047435AAA518C55B975D814D566AA3233887D5C2C886B754D50B133FE132D81A0851637D6085F2289D8584BF5130452AD24DD87D7158CDAC16832D42476486F0EC2DBBCD38CEE963C5E367ADE50C9502735AD3583445AABEE10E63480E3791FFC7BCF4BD5C1F6E9768E1B1D9B6B75E177F95914B6D5F06CA7CB001B15CAD26B9C20565F8351E69B5E6CA74D30E770523BA7E05475050DCF81A3F9B7C38EF1C31447E35543AE5B00E0BB13C63F8F1DCE0397BF523882AB79E2DF4BDF7E18ED799142089E79CE6AC0E562A587B055D9F963260DAA84A1C520A0D46A01138F20B0EAF73300DD4196A403892EC30B2C84860C4EC4A1FE5778512F546F5B813380393D3BABC535668515BEEFA350207C3BFA1502B52A775146FA97E4CBF701C2DC7845FF604EC73052F217185E74813FD18D3EBA6489E0BD00852B156193735F5A34952DCFD4BD493ECD2C9948E9D4436A79B1F5B6BB7991F1253B8B68BA7511EF94B87D4D9843A5A510837C7AFCD7F42A9657C78BA516606F94BC27F1579BBC0776216AC8B96C2D6D485B6C6EE489C504E32A6B4979287D53E42D120D411F849C748B31FCB2CEB1663C813A0E327DCC18242B484CBF5F9191063933EFEC4C6A600C415B0F29365F6DBBD2DE794D7E14D62CFD7F1E570D1A9C9536B03 -20240828082258 2 6 100 4095 2 E36F035A457FE7C42A6DFEA5F5F192B2FB147FA8B29FD9BE0FB4DB472F5668038712145FFD9C047435AAA518C55B975D814D566AA3233887D5C2C886B754D50B133FE132D81A0851637D6085F2289D8584BF5130452AD24DD87D7158CDAC16832D42476486F0EC2DBBCD38CEE963C5E367ADE50C9502735AD3583445AABEE10E63480E3791FFC7BCF4BD5C1F6E9768E1B1D9B6B75E177F95914B6D5F06CA7CB001B15CAD26B9C20565F8351E69B5E6CA74D30E770523BA7E05475050DCF81A3F9B7C38EF1C31447E35543AE5B00E0BB13C63F8F1DCE0397BF523882AB79E2DF4BDF7E18ED799142089E79CE6AC0E562A587B055D9F963260DAA84A1C520A0D46A01138F20B0EAF73300DD4196A403892EC30B2C84860C4EC4A1FE5778512F546F5B813380393D3BABC535668515BEEFA350207C3BFA1502B52A775146FA97E4CBF701C2DC7845FF604EC73052F217185E74813FD18D3EBA6489E0BD00852B156193735F5A34952DCFD4BD493ECD2C9948E9D4436A79B1F5B6BB7991F1253B8B68BA7511EF94B87D4D9843A5A510837C7AFCD7F42A9657C78BA516606F94BC27F1579BBC0776216AC8B96C2D6D485B6C6EE489C504E32A6B4979287D53E42D120D411F849C748B31FCB2CEB1663C813A0E327DCC18242B484CBF5F9191063933EFEC4C6A600C415B0F29365F6DBBD2DE794D7E14D62CFD7F1E570D1A9CBE55E03 -20240828082637 2 6 100 4095 2 E36F035A457FE7C42A6DFEA5F5F192B2FB147FA8B29FD9BE0FB4DB472F5668038712145FFD9C047435AAA518C55B975D814D566AA3233887D5C2C886B754D50B133FE132D81A0851637D6085F2289D8584BF5130452AD24DD87D7158CDAC16832D42476486F0EC2DBBCD38CEE963C5E367ADE50C9502735AD3583445AABEE10E63480E3791FFC7BCF4BD5C1F6E9768E1B1D9B6B75E177F95914B6D5F06CA7CB001B15CAD26B9C20565F8351E69B5E6CA74D30E770523BA7E05475050DCF81A3F9B7C38EF1C31447E35543AE5B00E0BB13C63F8F1DCE0397BF523882AB79E2DF4BDF7E18ED799142089E79CE6AC0E562A587B055D9F963260DAA84A1C520A0D46A01138F20B0EAF73300DD4196A403892EC30B2C84860C4EC4A1FE5778512F546F5B813380393D3BABC535668515BEEFA350207C3BFA1502B52A775146FA97E4CBF701C2DC7845FF604EC73052F217185E74813FD18D3EBA6489E0BD00852B156193735F5A34952DCFD4BD493ECD2C9948E9D4436A79B1F5B6BB7991F1253B8B68BA7511EF94B87D4D9843A5A510837C7AFCD7F42A9657C78BA516606F94BC27F1579BBC0776216AC8B96C2D6D485B6C6EE489C504E32A6B4979287D53E42D120D411F849C748B31FCB2CEB1663C813A0E327DCC18242B484CBF5F9191063933EFEC4C6A600C415B0F29365F6DBBD2DE794D7E14D62CFD7F1E570D1A9CD49EF1B -20240828082710 2 6 100 4095 5 E36F035A457FE7C42A6DFEA5F5F192B2FB147FA8B29FD9BE0FB4DB472F5668038712145FFD9C047435AAA518C55B975D814D566AA3233887D5C2C886B754D50B133FE132D81A0851637D6085F2289D8584BF5130452AD24DD87D7158CDAC16832D42476486F0EC2DBBCD38CEE963C5E367ADE50C9502735AD3583445AABEE10E63480E3791FFC7BCF4BD5C1F6E9768E1B1D9B6B75E177F95914B6D5F06CA7CB001B15CAD26B9C20565F8351E69B5E6CA74D30E770523BA7E05475050DCF81A3F9B7C38EF1C31447E35543AE5B00E0BB13C63F8F1DCE0397BF523882AB79E2DF4BDF7E18ED799142089E79CE6AC0E562A587B055D9F963260DAA84A1C520A0D46A01138F20B0EAF73300DD4196A403892EC30B2C84860C4EC4A1FE5778512F546F5B813380393D3BABC535668515BEEFA350207C3BFA1502B52A775146FA97E4CBF701C2DC7845FF604EC73052F217185E74813FD18D3EBA6489E0BD00852B156193735F5A34952DCFD4BD493ECD2C9948E9D4436A79B1F5B6BB7991F1253B8B68BA7511EF94B87D4D9843A5A510837C7AFCD7F42A9657C78BA516606F94BC27F1579BBC0776216AC8B96C2D6D485B6C6EE489C504E32A6B4979287D53E42D120D411F849C748B31FCB2CEB1663C813A0E327DCC18242B484CBF5F9191063933EFEC4C6A600C415B0F29365F6DBBD2DE794D7E14D62CFD7F1E570D1A9CD7A6C07 -20240828082726 2 6 100 4095 2 E36F035A457FE7C42A6DFEA5F5F192B2FB147FA8B29FD9BE0FB4DB472F5668038712145FFD9C047435AAA518C55B975D814D566AA3233887D5C2C886B754D50B133FE132D81A0851637D6085F2289D8584BF5130452AD24DD87D7158CDAC16832D42476486F0EC2DBBCD38CEE963C5E367ADE50C9502735AD3583445AABEE10E63480E3791FFC7BCF4BD5C1F6E9768E1B1D9B6B75E177F95914B6D5F06CA7CB001B15CAD26B9C20565F8351E69B5E6CA74D30E770523BA7E05475050DCF81A3F9B7C38EF1C31447E35543AE5B00E0BB13C63F8F1DCE0397BF523882AB79E2DF4BDF7E18ED799142089E79CE6AC0E562A587B055D9F963260DAA84A1C520A0D46A01138F20B0EAF73300DD4196A403892EC30B2C84860C4EC4A1FE5778512F546F5B813380393D3BABC535668515BEEFA350207C3BFA1502B52A775146FA97E4CBF701C2DC7845FF604EC73052F217185E74813FD18D3EBA6489E0BD00852B156193735F5A34952DCFD4BD493ECD2C9948E9D4436A79B1F5B6BB7991F1253B8B68BA7511EF94B87D4D9843A5A510837C7AFCD7F42A9657C78BA516606F94BC27F1579BBC0776216AC8B96C2D6D485B6C6EE489C504E32A6B4979287D53E42D120D411F849C748B31FCB2CEB1663C813A0E327DCC18242B484CBF5F9191063933EFEC4C6A600C415B0F29365F6DBBD2DE794D7E14D62CFD7F1E570D1A9CD8C1A83 -20240828082826 2 6 100 4095 2 E36F035A457FE7C42A6DFEA5F5F192B2FB147FA8B29FD9BE0FB4DB472F5668038712145FFD9C047435AAA518C55B975D814D566AA3233887D5C2C886B754D50B133FE132D81A0851637D6085F2289D8584BF5130452AD24DD87D7158CDAC16832D42476486F0EC2DBBCD38CEE963C5E367ADE50C9502735AD3583445AABEE10E63480E3791FFC7BCF4BD5C1F6E9768E1B1D9B6B75E177F95914B6D5F06CA7CB001B15CAD26B9C20565F8351E69B5E6CA74D30E770523BA7E05475050DCF81A3F9B7C38EF1C31447E35543AE5B00E0BB13C63F8F1DCE0397BF523882AB79E2DF4BDF7E18ED799142089E79CE6AC0E562A587B055D9F963260DAA84A1C520A0D46A01138F20B0EAF73300DD4196A403892EC30B2C84860C4EC4A1FE5778512F546F5B813380393D3BABC535668515BEEFA350207C3BFA1502B52A775146FA97E4CBF701C2DC7845FF604EC73052F217185E74813FD18D3EBA6489E0BD00852B156193735F5A34952DCFD4BD493ECD2C9948E9D4436A79B1F5B6BB7991F1253B8B68BA7511EF94B87D4D9843A5A510837C7AFCD7F42A9657C78BA516606F94BC27F1579BBC0776216AC8B96C2D6D485B6C6EE489C504E32A6B4979287D53E42D120D411F849C748B31FCB2CEB1663C813A0E327DCC18242B484CBF5F9191063933EFEC4C6A600C415B0F29365F6DBBD2DE794D7E14D62CFD7F1E570D1A9CDEC8AA3 -20240828082907 2 6 100 4095 5 E36F035A457FE7C42A6DFEA5F5F192B2FB147FA8B29FD9BE0FB4DB472F5668038712145FFD9C047435AAA518C55B975D814D566AA3233887D5C2C886B754D50B133FE132D81A0851637D6085F2289D8584BF5130452AD24DD87D7158CDAC16832D42476486F0EC2DBBCD38CEE963C5E367ADE50C9502735AD3583445AABEE10E63480E3791FFC7BCF4BD5C1F6E9768E1B1D9B6B75E177F95914B6D5F06CA7CB001B15CAD26B9C20565F8351E69B5E6CA74D30E770523BA7E05475050DCF81A3F9B7C38EF1C31447E35543AE5B00E0BB13C63F8F1DCE0397BF523882AB79E2DF4BDF7E18ED799142089E79CE6AC0E562A587B055D9F963260DAA84A1C520A0D46A01138F20B0EAF73300DD4196A403892EC30B2C84860C4EC4A1FE5778512F546F5B813380393D3BABC535668515BEEFA350207C3BFA1502B52A775146FA97E4CBF701C2DC7845FF604EC73052F217185E74813FD18D3EBA6489E0BD00852B156193735F5A34952DCFD4BD493ECD2C9948E9D4436A79B1F5B6BB7991F1253B8B68BA7511EF94B87D4D9843A5A510837C7AFCD7F42A9657C78BA516606F94BC27F1579BBC0776216AC8B96C2D6D485B6C6EE489C504E32A6B4979287D53E42D120D411F849C748B31FCB2CEB1663C813A0E327DCC18242B484CBF5F9191063933EFEC4C6A600C415B0F29365F6DBBD2DE794D7E14D62CFD7F1E570D1A9CE27CDDF -20240828083210 2 6 100 4095 2 E36F035A457FE7C42A6DFEA5F5F192B2FB147FA8B29FD9BE0FB4DB472F5668038712145FFD9C047435AAA518C55B975D814D566AA3233887D5C2C886B754D50B133FE132D81A0851637D6085F2289D8584BF5130452AD24DD87D7158CDAC16832D42476486F0EC2DBBCD38CEE963C5E367ADE50C9502735AD3583445AABEE10E63480E3791FFC7BCF4BD5C1F6E9768E1B1D9B6B75E177F95914B6D5F06CA7CB001B15CAD26B9C20565F8351E69B5E6CA74D30E770523BA7E05475050DCF81A3F9B7C38EF1C31447E35543AE5B00E0BB13C63F8F1DCE0397BF523882AB79E2DF4BDF7E18ED799142089E79CE6AC0E562A587B055D9F963260DAA84A1C520A0D46A01138F20B0EAF73300DD4196A403892EC30B2C84860C4EC4A1FE5778512F546F5B813380393D3BABC535668515BEEFA350207C3BFA1502B52A775146FA97E4CBF701C2DC7845FF604EC73052F217185E74813FD18D3EBA6489E0BD00852B156193735F5A34952DCFD4BD493ECD2C9948E9D4436A79B1F5B6BB7991F1253B8B68BA7511EF94B87D4D9843A5A510837C7AFCD7F42A9657C78BA516606F94BC27F1579BBC0776216AC8B96C2D6D485B6C6EE489C504E32A6B4979287D53E42D120D411F849C748B31FCB2CEB1663C813A0E327DCC18242B484CBF5F9191063933EFEC4C6A600C415B0F29365F6DBBD2DE794D7E14D62CFD7F1E570D1A9CF4E290B -20240828083415 2 6 100 4095 2 E36F035A457FE7C42A6DFEA5F5F192B2FB147FA8B29FD9BE0FB4DB472F5668038712145FFD9C047435AAA518C55B975D814D566AA3233887D5C2C886B754D50B133FE132D81A0851637D6085F2289D8584BF5130452AD24DD87D7158CDAC16832D42476486F0EC2DBBCD38CEE963C5E367ADE50C9502735AD3583445AABEE10E63480E3791FFC7BCF4BD5C1F6E9768E1B1D9B6B75E177F95914B6D5F06CA7CB001B15CAD26B9C20565F8351E69B5E6CA74D30E770523BA7E05475050DCF81A3F9B7C38EF1C31447E35543AE5B00E0BB13C63F8F1DCE0397BF523882AB79E2DF4BDF7E18ED799142089E79CE6AC0E562A587B055D9F963260DAA84A1C520A0D46A01138F20B0EAF73300DD4196A403892EC30B2C84860C4EC4A1FE5778512F546F5B813380393D3BABC535668515BEEFA350207C3BFA1502B52A775146FA97E4CBF701C2DC7845FF604EC73052F217185E74813FD18D3EBA6489E0BD00852B156193735F5A34952DCFD4BD493ECD2C9948E9D4436A79B1F5B6BB7991F1253B8B68BA7511EF94B87D4D9843A5A510837C7AFCD7F42A9657C78BA516606F94BC27F1579BBC0776216AC8B96C2D6D485B6C6EE489C504E32A6B4979287D53E42D120D411F849C748B31FCB2CEB1663C813A0E327DCC18242B484CBF5F9191063933EFEC4C6A600C415B0F29365F6DBBD2DE794D7E14D62CFD7F1E570D1A9D01153B3 -20240828083603 2 6 100 4095 2 E36F035A457FE7C42A6DFEA5F5F192B2FB147FA8B29FD9BE0FB4DB472F5668038712145FFD9C047435AAA518C55B975D814D566AA3233887D5C2C886B754D50B133FE132D81A0851637D6085F2289D8584BF5130452AD24DD87D7158CDAC16832D42476486F0EC2DBBCD38CEE963C5E367ADE50C9502735AD3583445AABEE10E63480E3791FFC7BCF4BD5C1F6E9768E1B1D9B6B75E177F95914B6D5F06CA7CB001B15CAD26B9C20565F8351E69B5E6CA74D30E770523BA7E05475050DCF81A3F9B7C38EF1C31447E35543AE5B00E0BB13C63F8F1DCE0397BF523882AB79E2DF4BDF7E18ED799142089E79CE6AC0E562A587B055D9F963260DAA84A1C520A0D46A01138F20B0EAF73300DD4196A403892EC30B2C84860C4EC4A1FE5778512F546F5B813380393D3BABC535668515BEEFA350207C3BFA1502B52A775146FA97E4CBF701C2DC7845FF604EC73052F217185E74813FD18D3EBA6489E0BD00852B156193735F5A34952DCFD4BD493ECD2C9948E9D4436A79B1F5B6BB7991F1253B8B68BA7511EF94B87D4D9843A5A510837C7AFCD7F42A9657C78BA516606F94BC27F1579BBC0776216AC8B96C2D6D485B6C6EE489C504E32A6B4979287D53E42D120D411F849C748B31FCB2CEB1663C813A0E327DCC18242B484CBF5F9191063933EFEC4C6A600C415B0F29365F6DBBD2DE794D7E14D62CFD7F1E570D1A9D0BAF663 -20240828083703 2 6 100 4095 2 E36F035A457FE7C42A6DFEA5F5F192B2FB147FA8B29FD9BE0FB4DB472F5668038712145FFD9C047435AAA518C55B975D814D566AA3233887D5C2C886B754D50B133FE132D81A0851637D6085F2289D8584BF5130452AD24DD87D7158CDAC16832D42476486F0EC2DBBCD38CEE963C5E367ADE50C9502735AD3583445AABEE10E63480E3791FFC7BCF4BD5C1F6E9768E1B1D9B6B75E177F95914B6D5F06CA7CB001B15CAD26B9C20565F8351E69B5E6CA74D30E770523BA7E05475050DCF81A3F9B7C38EF1C31447E35543AE5B00E0BB13C63F8F1DCE0397BF523882AB79E2DF4BDF7E18ED799142089E79CE6AC0E562A587B055D9F963260DAA84A1C520A0D46A01138F20B0EAF73300DD4196A403892EC30B2C84860C4EC4A1FE5778512F546F5B813380393D3BABC535668515BEEFA350207C3BFA1502B52A775146FA97E4CBF701C2DC7845FF604EC73052F217185E74813FD18D3EBA6489E0BD00852B156193735F5A34952DCFD4BD493ECD2C9948E9D4436A79B1F5B6BB7991F1253B8B68BA7511EF94B87D4D9843A5A510837C7AFCD7F42A9657C78BA516606F94BC27F1579BBC0776216AC8B96C2D6D485B6C6EE489C504E32A6B4979287D53E42D120D411F849C748B31FCB2CEB1663C813A0E327DCC18242B484CBF5F9191063933EFEC4C6A600C415B0F29365F6DBBD2DE794D7E14D62CFD7F1E570D1A9D11A10CB -20240828083816 2 6 100 4095 5 E36F035A457FE7C42A6DFEA5F5F192B2FB147FA8B29FD9BE0FB4DB472F5668038712145FFD9C047435AAA518C55B975D814D566AA3233887D5C2C886B754D50B133FE132D81A0851637D6085F2289D8584BF5130452AD24DD87D7158CDAC16832D42476486F0EC2DBBCD38CEE963C5E367ADE50C9502735AD3583445AABEE10E63480E3791FFC7BCF4BD5C1F6E9768E1B1D9B6B75E177F95914B6D5F06CA7CB001B15CAD26B9C20565F8351E69B5E6CA74D30E770523BA7E05475050DCF81A3F9B7C38EF1C31447E35543AE5B00E0BB13C63F8F1DCE0397BF523882AB79E2DF4BDF7E18ED799142089E79CE6AC0E562A587B055D9F963260DAA84A1C520A0D46A01138F20B0EAF73300DD4196A403892EC30B2C84860C4EC4A1FE5778512F546F5B813380393D3BABC535668515BEEFA350207C3BFA1502B52A775146FA97E4CBF701C2DC7845FF604EC73052F217185E74813FD18D3EBA6489E0BD00852B156193735F5A34952DCFD4BD493ECD2C9948E9D4436A79B1F5B6BB7991F1253B8B68BA7511EF94B87D4D9843A5A510837C7AFCD7F42A9657C78BA516606F94BC27F1579BBC0776216AC8B96C2D6D485B6C6EE489C504E32A6B4979287D53E42D120D411F849C748B31FCB2CEB1663C813A0E327DCC18242B484CBF5F9191063933EFEC4C6A600C415B0F29365F6DBBD2DE794D7E14D62CFD7F1E570D1A9D18C60B7 -20240828084040 2 6 100 4095 2 E36F035A457FE7C42A6DFEA5F5F192B2FB147FA8B29FD9BE0FB4DB472F5668038712145FFD9C047435AAA518C55B975D814D566AA3233887D5C2C886B754D50B133FE132D81A0851637D6085F2289D8584BF5130452AD24DD87D7158CDAC16832D42476486F0EC2DBBCD38CEE963C5E367ADE50C9502735AD3583445AABEE10E63480E3791FFC7BCF4BD5C1F6E9768E1B1D9B6B75E177F95914B6D5F06CA7CB001B15CAD26B9C20565F8351E69B5E6CA74D30E770523BA7E05475050DCF81A3F9B7C38EF1C31447E35543AE5B00E0BB13C63F8F1DCE0397BF523882AB79E2DF4BDF7E18ED799142089E79CE6AC0E562A587B055D9F963260DAA84A1C520A0D46A01138F20B0EAF73300DD4196A403892EC30B2C84860C4EC4A1FE5778512F546F5B813380393D3BABC535668515BEEFA350207C3BFA1502B52A775146FA97E4CBF701C2DC7845FF604EC73052F217185E74813FD18D3EBA6489E0BD00852B156193735F5A34952DCFD4BD493ECD2C9948E9D4436A79B1F5B6BB7991F1253B8B68BA7511EF94B87D4D9843A5A510837C7AFCD7F42A9657C78BA516606F94BC27F1579BBC0776216AC8B96C2D6D485B6C6EE489C504E32A6B4979287D53E42D120D411F849C748B31FCB2CEB1663C813A0E327DCC18242B484CBF5F9191063933EFEC4C6A600C415B0F29365F6DBBD2DE794D7E14D62CFD7F1E570D1A9D26C42A3 -20240828090009 2 6 100 6143 2 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F2258E4DB -20240828090718 2 6 100 6143 2 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F233F2A7B -20240828091256 2 6 100 6143 5 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F23ED9417 -20240828091549 2 6 100 6143 2 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F243D1C03 -20240828092905 2 6 100 6143 5 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F25E8D11F -20240828093653 2 6 100 6143 2 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F26E25303 -20240828100014 2 6 100 6143 2 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F29D9C7A3 -20240828100324 2 6 100 6143 5 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F2A3C434F -20240828105814 2 6 100 6143 5 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F3151094F -20240828111427 2 6 100 6143 2 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F33641C63 -20240828113247 2 6 100 6143 2 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F35BB7B0B -20240828113333 2 6 100 6143 5 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F35CD9A97 -20240828113540 2 6 100 6143 2 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F360A482B -20240828115349 2 6 100 6143 2 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F3862A7B3 -20240828115426 2 6 100 6143 5 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F386EC997 -20240828120438 2 6 100 6143 2 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F39B5CC43 -20240828121629 2 6 100 6143 2 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F3B334FB3 -20240828121657 2 6 100 6143 2 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F3B3B734B -20240828122545 2 6 100 6143 2 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F3C524DB3 -20240828123158 2 6 100 6143 5 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F3D1B196F -20240828130157 2 6 100 6143 5 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F40EB0D47 -20240828130238 2 6 100 6143 2 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F40F7E253 -20240828134737 2 6 100 6143 2 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F46C46D3B -20240828135646 2 6 100 6143 2 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F47E7985B -20240828144149 2 6 100 6143 2 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F4DB24103 -20240828145157 2 6 100 6143 2 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F4EF2EE0B -20240828145816 2 6 100 6143 5 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F4FB0AC7F -20240828151150 2 6 100 6143 5 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F515FD9BF -20240828151822 2 6 100 6143 5 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F5229B63F -20240828153933 2 6 100 6143 2 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F54CF3923 -20240828154759 2 6 100 6143 2 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F55E07A93 -20240828161625 2 6 100 6143 2 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F598D643B -20240828162500 2 6 100 6143 5 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F5A998FB7 -20240828162916 2 6 100 6143 2 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F5B1CC43B -20240828163955 2 6 100 6143 2 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F5C71914B -20240828164552 2 6 100 6143 5 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F5D2E5D1F -20240828170129 2 6 100 6143 5 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F5F34D397 -20240828172001 2 6 100 6143 5 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F6192353F -20240828172046 2 6 100 6143 5 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F61A3C147 -20240828172320 2 6 100 6143 5 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F61EF7817 -20240828173414 2 6 100 6143 2 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F6352E0CB -20240828173441 2 6 100 6143 5 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F6359E007 -20240828180730 2 6 100 6143 2 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F679AD6CB -20240828180915 2 6 100 6143 2 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F67CD41EB -20240828180941 2 6 100 6143 2 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F67D23A63 -20240828181257 2 6 100 6143 5 FC9BE67A111C24C58B9D8DFF78C575F1AC8199BA90C7C86923636AEFB38B41C1282E5A8232B7B9AECD439830D372F7B8D22004BD6BD64F326ABA86F1FEA022C374CDDD3CA3F161873B1D51326B69BC26112479F45CDBBB0DF942D942333DEBECD3E705804408C841D2EA09535C2B5779315396B517A6C628C9E23DE15EEE013BB18D7B40EDEA8655765566F3923B6EEA21853E436480D25D1D7172F02B16814BE600FBE715963C7576E022AAA046EA7D25B4642F7626582BE4ADF0E251A6677DFC67C49260C444D7825A03685A5BD789A13E1AAF1970ED54C71B234682E3AAF67EEFC3875C8868086EE6068A48E6C4E7A7BBEE17505D4AB7E8ACA56E336490553B41E1ED5D023D2D2DBAFC3362D8CDEC1809F4A37845A1DB87AE4D7AE6F6D941B0AF97921C9E659331B524F47EF80EAF574D5961DB05724C17F45686389361D29A234BE063DA02D889905B8B1B5BA87355B60F5FB44CFF859415F439DAC677F1D5A1563B22236386D0CED95BE925C51D22F2173B579B1EBAE7E8B8EDB26A8532FD6DE7E1F33D6BF984BAF3AF00A2C382A7B354C77F029D041FB132BF27C430320DFAD34530246D6CB04D7A78F5364186A9A86B359A9F5FD28D4B9ABCF51BE2C955CF8102D64B322A50FEF96DD5C4D21268D7E044CC52AB57AD26BEFED1634C24BA947F1DBD024BA9A3CD94EEE0DA0CA9FD481BEB41BF6DB6ACF409E732C482643D5D5A5B720B26E618C7AA244B8F7506CB8FC8299195D03E30B03C6263A75AACBC3A32C9A7DD5D7653537125BC0FE7241A410DBF8E04ECCD1486DA3A321EAF36C5A5DC40A0FB262A64727CF7AE645BAF538E8784ECA49E1A277B29C56B8D1AFF2BE2E1665906C48A58230497091B47EF239C5D34FB19C25D89BB0B8573E8417AE90FEEB6FAC06F9F60A6C57F1D4E3325FB0AB1A3A088B4133A319158CBDDCF0CCC2938F64E0029F0389FAC55BFC1F0D0F15B2E70799562C53FC3D1D97CCFA25ED83FF115503D44A7A91FF295AD2F1BC598FE86B8AE7DA77773179A4A0EB0ED618102D880D9963798BF91EB6E16870A4AB9E8137E1D6503ADD39D8E8F683B05BF -20240828182555 2 6 100 6143 2 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE3180CE228BB -20240828184406 2 6 100 6143 2 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE3180F2F287B -20240828185315 2 6 100 6143 2 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE3181059FDFB -20240828191106 2 6 100 6143 2 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE31812A21FB3 -20240828191122 2 6 100 6143 5 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE31812A28277 -20240828195243 2 6 100 6143 2 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE318180489DB -20240828195610 2 6 100 6143 5 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE31818728F67 -20240828201325 2 6 100 6143 2 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE3181AAF829B -20240828202233 2 6 100 6143 2 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE3181BD9FE33 -20240828202820 2 6 100 6143 2 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE3181C96132B -20240828204913 2 6 100 6143 2 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE3181F3FE8A3 -20240828205946 2 6 100 6143 5 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE318209CB6D7 -20240828211537 2 6 100 6143 5 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE31822AC1387 -20240828220459 2 6 100 6143 5 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE318290F4E1F -20240828224012 2 6 100 6143 2 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE3182D9E3A03 -20240828232844 2 6 100 6143 2 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE31833F1DD7B -20240828233400 2 6 100 6143 2 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE3183494A423 -20240828235802 2 6 100 6143 5 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE31837ADEA57 -20240829001115 2 6 100 6143 2 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE318395E7B83 -20240829004718 2 6 100 6143 2 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE3183E0E5603 -20240829004844 2 6 100 6143 5 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE3183E34D98F -20240829005431 2 6 100 6143 5 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE3183EECD0DF -20240829010933 2 6 100 6143 2 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE31840CEA00B -20240829014049 2 6 100 6143 2 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE31844D61FFB -20240829014355 2 6 100 6143 5 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE3184533474F -20240829014829 2 6 100 6143 5 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE31845BEB5C7 -20240829015142 2 6 100 6143 2 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE31846235FD3 -20240829015517 2 6 100 6143 2 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE3184695C7FB -20240829020608 2 6 100 6143 2 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE31847F7E373 -20240829023600 2 6 100 6143 5 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE3184BC56B47 -20240829025737 2 6 100 6143 2 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE3184E74875B -20240829031846 2 6 100 6143 5 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE318511B9B7F -20240829033452 2 6 100 6143 5 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE318531C0F27 -20240829034004 2 6 100 6143 5 C272750D88E88AEF9E0F2188FF6C61DE6B22B20E1C1D5A5E5B13A9C97ACB497B050868137519E1EC9CAEC9ABE3D69DC4C96ADA353B3809627C938691FCC17E260254A0ABF1FB7629416CF61DE72AC7B91EAC39F9A9CC38B729272D78976679C9F93E0E67BAC79B88598FA5B160A9403FB851D2046A6A319C55E028AF6AEDCE7588403635FDFEABCF52C2EB9D7CB86F1CEB17DF39D951744D332D51302626F56AF310A3E20B3BED391B713FF8589D35E44DE1DA41D70EE06762C2789444107C50101D55738975C05B61243016DBEFAF2521C724FCFF279D34EE418052A2AE927474EC5C055ECAB0B2E1F5E6EF378EEB15A7ECAB59638A0A7163577121789E3301236F63178910C6AEDEC6664DED0F0762D6F6854B44BC811A03E8627DB90D7A2E9FC85D32B498E8E5A92BC771A6D9C8E9A967F3EC3C0927926021B97FA8A201C22422BD61E330920F35AE966B43CDD8B6EC853AA8F1CE0C1061C152826F9769746EA7E06325B50A9C3D9B7A88C5D22B68556E24ADD0664F0230DF4896F53319223F39D68B6507E213ACD50EEDE83AAB51E3C4B020B6F0B0AB06CB071460D139DC597ADB530E51FEC7EEF6D5111BA3A7EE874B4708ADC8186D2D5326DBDF692E60C6170AE64590151BB6ECA0AA51E6233148C7D78034812FA93C6A7F7864182D576BB83714C3A4E17228B0D4569F70C451632477265A2A40B9419A13408BD7C3B33979589A112D6156484AD84560272D7717F763507AF92C86F4475669962B63A2BAB2EE0CAA835B90A7DB43CF8A2879674B60B1B1EC25933019968455AC054BCA392EF57C3C76D79AE684894BD009B97AAC3754537E85C93C9F96D59B8359C055B1B7109086E4DC7F55CEB628BFAB792B931B955AADA57FA6A8CB019B1ACE092199C0E5F94855DFBB08E3DCA886337842F363B8117751C5DD48DD431E903C2B1C7677FE2AD42A0CCCD2677B9A4774E9168A2C4C1B8EA5267971D0DD6BB91320A677928D2087069C7D460BB4E72698AED4F7127975D49F87D52724DE830C66F422547D0B934F32F4E9FC0617A6D2BB022987EE13330BDBA970A8FAE31853C097B7 -20240829043625 2 6 100 7679 2 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD187E5F08523 -20240829053823 2 6 100 7679 2 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD187EA33BB33 -20240829061611 2 6 100 7679 2 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD187ECC3E213 -20240829064111 2 6 100 7679 5 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD187EE73FD37 -20240829065111 2 6 100 7679 5 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD187EF1CB167 -20240829082003 2 6 100 7679 2 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD187F52294C3 -20240829091934 2 6 100 7679 5 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD187F92CC467 -20240829093659 2 6 100 7679 2 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD187FA58CCB3 -20240829103319 2 6 100 7679 2 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD187FE2DC683 -20240829123824 2 6 100 7679 2 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD18806C1B393 -20240829130958 2 6 100 7679 2 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD18808EFDAAB -20240829135456 2 6 100 7679 2 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD1880C119733 -20240829150211 2 6 100 7679 2 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD18810B3AE03 -20240829152452 2 6 100 7679 5 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD18812362547 -20240829171859 2 6 100 7679 2 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD1881A26609B -20240829181704 2 6 100 7679 2 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD1881E2C3E3B -20240829182818 2 6 100 7679 2 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD1881EED38A3 -20240829184006 2 6 100 7679 2 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD1881FB9391B -20240829190814 2 6 100 7679 5 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD18821A70EA7 -20240829195154 2 6 100 7679 5 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD18824BB04C7 -20240829200011 2 6 100 7679 5 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD1882546EC8F -20240829203003 2 6 100 7679 2 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD188274D620B -20240829220907 2 6 100 7679 2 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD1882E2608EB -20240829221444 2 6 100 7679 2 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD1882E810C9B -20240829222440 2 6 100 7679 2 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD1882F2EBA7B -20240829230449 2 6 100 7679 2 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD18831F68C1B -20240829231044 2 6 100 7679 5 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD18832552757 -20240829233827 2 6 100 7679 2 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD188343C3EAB -20240829235120 2 6 100 7679 2 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD188351A81B3 -20240830003221 2 6 100 7679 2 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD18837F06443 -20240830011832 2 6 100 7679 2 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD1883B1C9E73 -20240830013013 2 6 100 7679 2 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD1883BE3681B -20240830014610 2 6 100 7679 2 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD1883CF597DB -20240830032931 2 6 100 7679 2 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD188443580AB -20240830042102 2 6 100 7679 5 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD18847CB52C7 -20240830042255 2 6 100 7679 5 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD18847E4A687 -20240830052035 2 6 100 7679 5 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD1884BDB09B7 -20240830053449 2 6 100 7679 2 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD1884CD217AB -20240830054036 2 6 100 7679 5 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD1884D30808F -20240830060721 2 6 100 7679 2 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD1884F02040B -20240830071657 2 6 100 7679 5 EF541828E23A6BB90EFE9D9BEEDD3F9DE2E08069B8FD3ED88F27CD7E4F00AA272010368A26104FDBE69743D020951E909C76D9EF11E8050208720244763E9D59526B99F462FAC17E3A1ABD3B328C80753B1777D032397E4E3BDC90FB275DE027A21362A8FF88456ED3A9F397C045745B0C4D090D10304B86631AE9561AE9FD3C9FEB4490FD074E78702F4187A8E5CE8E7AE1E66593C34B9F08153994E70FE56B9CA823FCF1C176E875F6654CCECDF52463CDA61BE848C5B0E9CFF4E908CD0AA9BD4F4A58DF5996AAC3D411270CAD4BAC154467F91184713B4EFCFEE7922C8F58F9259937935A94A7791E99F4838EE1981A3EC9E6A2C44CBC10ACE390882CA40592D13E91AF49C78C4D518D9EFA98142A9102970E721D6ED83981164C488AD25BBC424C235C7AF62C4B4170EFFC11FA6EBEA4661D320013FFA6A4DA1EAE2F0545B95FD4E13B182BFEC226A01C3B46229FCE86A9E11B3E026326C1BA745510DDE4FCEB777BE42D1057DAD45ACEAB111C907760669A0C1F15DA4F5B8180E844DD5D602F7FAE7D16A5E8A2929E804A1BD17D38866A5EE3B1F50C3054C5E397969BCA2008DC96503513217BE8D2F15FB9DA26A8A5FE981111EC64CBEE1420D2DF7853B17E40766873E712977C1043237B39E2DE3868D079D96D76ACB24123AFDB5C6A6A9BCD40ED4C696EDAC4FE015CA982535A2A84B1A42767E1FBFB936B9FBD72CF98993C6B1EBDA16BF03FE325FA62511128CB669EE148067ED9A10338F87E4D3D39FE695A2F99B5D645A7653C3EBEA517FAFDD9CFF12B54E947A64BE8564A3851EA0F7A09C8C2E3D78FE0D3739ECA465A81194B8760F4F7213737C3FBE0E2F13704E7FDE2EDC91E22F1B76327CAA49BEBCDB1A33F178DA6F38666D09942532843CD95E61891A54EE7745D731FC2AD6B434D42F300D19176DBDD94594E3EB018EDC8666E89FB4C205A3D70F07F96AFA887F6D4A2FE573E77FDDD28D76F5C15C34CADDA8B9652FBEBEAA4CF56260833B160E8122141D17DE72CAF4859EB84CCACC341B7790A2D9B297538549451FBA5C47A37C7A99E31AED087BDF7F9E79D99CB6FADDBA30ACD5CF06FAC18DE33A94A8FC08ED8D93A24CDD7DAE09CD8CFF1C918173B32C10CE0F5EE9ED40D2BB3173370E941158C448617E4251E522CCE793B1A4399E8A39B923BC594AB453CE0145ADD622DCDF98D7D9A1E3C3C4BF128194857AC3959468BA2C2540EB5438D165F04D0A0D15BD19A5EBA1F7D6F82848877E480A20859C002F448716156AAD2008E4A7694E4F4C346C4EF359B21BB984C2073FE3E95DF3B183EFAC45BC426E3A569703F6C48DB20F7A32CB7E7C2ADD18853C7A8E7 -20240830084720 2 6 100 7679 2 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FEF75703DB -20240830094656 2 6 100 7679 5 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FEFB626A2F -20240830095006 2 6 100 7679 5 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FEFB909467 -20240830110930 2 6 100 7679 5 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF0108EC1F -20240830112637 2 6 100 7679 2 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF02315BCB -20240830113545 2 6 100 7679 5 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF02D19C77 -20240830134211 2 6 100 7679 5 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF0BA3E697 -20240830134427 2 6 100 7679 5 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF0BC3CC37 -20240830134817 2 6 100 7679 2 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF0C009ED3 -20240830145923 2 6 100 7679 5 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF10E44067 -20240830161320 2 6 100 7679 2 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF15FCEA4B -20240830170319 2 6 100 7679 5 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF197243AF -20240830171339 2 6 100 7679 5 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF1A211BAF -20240830173745 2 6 100 7679 5 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF1BC7E24F -20240830181908 2 6 100 7679 5 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF1E96C5DF -20240830181940 2 6 100 7679 2 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF1E9711DB -20240830183135 2 6 100 7679 2 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF1F5C367B -20240830190740 2 6 100 7679 2 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF21D6FFCB -20240830192133 2 6 100 7679 2 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF22C8073B -20240830213430 2 6 100 7679 2 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF2BE900AB -20240830213722 2 6 100 7679 5 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF2C10C36F -20240830221923 2 6 100 7679 2 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF2EF2814B -20240830225347 2 6 100 7679 2 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF314EE303 -20240830231356 2 6 100 7679 2 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF32AF8B0B -20240830234723 2 6 100 7679 2 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF34FE61CB -20240831004647 2 6 100 7679 5 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF3918C417 -20240831020149 2 6 100 7679 5 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF3E4B559F -20240831022637 2 6 100 7679 2 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF4002F243 -20240831030552 2 6 100 7679 5 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF42BB548F -20240831033741 2 6 100 7679 5 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF44F1D9D7 -20240831034841 2 6 100 7679 5 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF45ACBE37 -20240831035452 2 6 100 7679 2 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF460E12C3 -20240831053706 2 6 100 7679 5 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF4D2CFB27 -20240831055400 2 6 100 7679 2 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF4E512613 -20240831073419 2 6 100 7679 2 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF5532694B -20240831074414 2 6 100 7679 5 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF55DB1637 -20240831081807 2 6 100 7679 5 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF583421DF -20240831090302 2 6 100 7679 2 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF5B405DA3 -20240831093205 2 6 100 7679 2 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF5D338B6B -20240831103110 2 6 100 7679 2 D5949FC6991BCA2FAE324A3249CCAE8A99AEB0E6E81054670B5BCEA51FAB2D6C0A271648412828FAE2E356A85355BD9DF43DDD71F82F93494A6E4F0F78E998A4B13481478A814CE13A471D3BC48EF5A2BFDF48E920696BA74DFE2672ED7FC456B46C6CE48C129701E0D0DE344FED8581E2F1D010735EBDC6E9683D892CB2C2A164B500A5D2A9A41D8FCE24CDFD4A8DBAB66671B3FD8B6275C3482A10A73D2C1FD50627B4AAB5F81C67FDAA3D3AD28E916D9DF4F6E9035BACC614A3FC352650DCB94BBB4C3E40CDF33B242FC97C9D5BF655DF4672F496FA8B619B515DCB37932CDF25313659B982542675BA0300768C7BEB3EEC64BA9E0EB247B0B9D000E0BB07C3E054B5DAA9CE521C54EF0A1DC00203A4F723FC2361DAD5AC276C723044DD3B56A3B4C38C46CD3E9510AD9264BCB2AE52EA59F4B3CD500B7134135784D994C42CF8DCA5E90937C53A19D8DD356BB868CCE05A982F7204F1D3C19CCD16873CBC7CA44BA2D34B57E63F092B93C075530ED66177BE42F1677E4EB1A18EA0ED62C654F04B68DE9DD4A9C1AC509CE5DF1CF266C6A16696F858C024C16A95AF16105D9E778BD3A9FFE09CCBE4454EFFE6A309F629434FCB894B42BA2FAD7C4BA7091301422C347ACCB39FF801F97F36B3464A7B84C4C4A85503DD7BCFD97462AFCFDE1CF4C8FDA6FC5019B262C3E58C77E28BED5A2583B28DBA0E59D5665E7A5339A02C976FD31B4797DB945851DE5164A9AA3359F1A35E31357314DB6C82B5DB62D70BB7C22B3C110A0495E2B7200104FBD230C9C11824601EF4FA78ABDA0D5BF866B2CA6087E20AB2C8FBE1FFCEA5D19F11EB801002A801D9A72678009269FEFE57A4B8D389047D05F03C5472F5FB731C5BB3C5E2A9BA907D496E10FB953D953F650602639F37EED2F65424056F92CDCAA33DD65E714EF3D5419E7B4C1CE77A40D441962F2D42135ADD4951E90CC0FC85C2946C82F74C9B1398D6A086BC7EAA1763173AEF572969FA738EE079BF5C5EFAF8E4D99DB8618E646876342CC8BF3B1A62F969265FB633700F4CC598AB407F84BD2B1AD496AF8E785063078688A86AD6B4E4ED2CA31AF2F7899D0AD613A57BFA5746F743A62F66105DEEEBF637D9ADCBF941E4728DDD5D03AFE58EAD827B154BD22C00A94822A240DFE575479E9C00E38064BBBD1A5B511957045BFE40951312B2F5F5CC45CD94823AFC0CD2BE902C2E9DF92D87C8E24308E788EC48187B2EB69516AC9D7CA97C0E1C610320AFDC5767FFAFBBE16EA80B8E2CF1AA030FD86E803A19CC2BEF8CDCF8A7A1BCF82A1ADE289ED2733AEFAFA82296C331088447B110D8AC831708F631EB967936B2FF61456293 -20240831121754 2 6 100 8191 2 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB1349E143 -20240831124443 2 6 100 8191 5 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB14CB7AFF -20240831135558 2 6 100 8191 2 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB18CC80A3 -20240831145738 2 6 100 8191 2 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB1C36864B -20240831165313 2 6 100 8191 5 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB22B0FAD7 -20240831185249 2 6 100 8191 2 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB29880B2B -20240831185952 2 6 100 8191 2 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB29E5889B -20240831194619 2 6 100 8191 5 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB2C7FC84F -20240831230544 2 6 100 8191 5 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB37F47B7F -20240901001522 2 6 100 8191 2 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB3BE4A76B -20240901013228 2 6 100 8191 5 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB404463B7 -20240901015829 2 6 100 8191 5 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB41B1142F -20240901025646 2 6 100 8191 5 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB44FDAE87 -20240901031615 2 6 100 8191 2 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB461000EB -20240901042008 2 6 100 8191 5 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB49A1BE47 -20240901044227 2 6 100 8191 2 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB4AE1A82B -20240901064528 2 6 100 8191 5 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB51D37F37 -20240901073955 2 6 100 8191 5 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB54DB30B7 -20240901080825 2 6 100 8191 2 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB56740653 -20240901083546 2 6 100 8191 5 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB57EF4EAF -20240901093005 2 6 100 8191 2 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB5AF60F7B -20240901122015 2 6 100 8191 2 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB64814643 -20240901124800 2 6 100 8191 5 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB661018A7 -20240901134700 2 6 100 8191 5 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB695D723F -20240901135853 2 6 100 8191 2 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB6A06CAEB -20240901140005 2 6 100 8191 5 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB6A0E0D2F -20240901141551 2 6 100 8191 5 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB6AEB6337 -20240901141841 2 6 100 8191 2 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB6B0A7C53 -20240901144342 2 6 100 8191 2 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB6C6CC963 -20240901151624 2 6 100 8191 5 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB6E3F7CCF -20240901173158 2 6 100 8191 5 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB75F13437 -20240901180438 2 6 100 8191 2 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB77CD90AB -20240901182042 2 6 100 8191 2 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB78AD2B63 -20240901193908 2 6 100 8191 2 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB7D18983B -20240901195652 2 6 100 8191 5 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB7E1244DF -20240901202100 2 6 100 8191 5 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB7F6CD3C7 -20240901210156 2 6 100 8191 2 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB81BA121B -20240901220732 2 6 100 8191 2 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB8571A7D3 -20240901233244 2 6 100 8191 2 FE0FE5928DE815B6A6B360EA50D7859C014FC47CB277FE8AA545E89E2D34791ADC80654D6B276978CAD4E12481459D6E40E32CD8500BBE14ABFBD4E72A14280C66F25A30CB81F885761B07BABB863C9DA0ABEA9EAC4ABB8BB272AD3ABA2B808CB6B12A4A5D68AF9B47FBF91C1AA08C7738B911583E29F339BFB9C46B193071A3BD7297521767A34B002F0EB1470246325AD1D48E7C7EBCFEED0866747ACC8FB2C731FC1D73C52F3868C1071D92BDF96037BBAE974A789968F22ECB1CBA7129FD2D524F0D4109DCA2E056483DDBC90FA159982AEB86F929E0D05188B4434C0AC1F071B6F431D08201E683F95CE6D2B4FA354E74F346144E52DB92A0F468ACCC0F8AE53C8BD1818CC577F65DE4188A6E2E10EB84FF9A31B04506E2E8ABD48FCA067B44348667922B7479EBFB9E6E5B8583C4AED84CEC8CCF3A3C3082A3519D2EE53917A09BBE4A52D1F8EA458F493D9D272B49529E6FD509A4EBC7E0927ADACF86C5C8BE31DE98EE65F3FA6CCDB9C308971118C68AF076C64A42745E9485C79AD78880C9DDD03D9529A71C4AE4D8A976C6461119E8CB44536420EDF4AC2499748F3078A1749E6FB4F8F8DCBE64962610695F1DB0BE4FE879A34D7A9BC94DAF492A9259C521F690EC1B00966F855C4B42C2D189B8AFDC34CFE3D49D974820287EE978495D640D80766C4CCA16D92117610A7DF97F444FC5B9B72C10BB8D632255C465F4128092C57B99426E4B0FD336BFC2455538E48FFCDC8CFFFC2064FFBC5FC0FA3CFC6A37140EBADEBF6C1F60C32F650C42988212D00CFFE0DB9D975F991A950D2D8C6B47676672EDB553FD8AA505E69BCCB9C89096FF1F5F5369F285EB8CE629FA7B56923824C3FFD7A2050471A4D90EC9DF24C22D9427267ACC6A13AABA1710B9469EE96E106468410866076B98D19B3E36F4CD052B89A35786D318FFE6EC0805E73A23E41C79B5287E0FC7618C2B4AA89CA27C8DEB5D016109ABEF7651589F4CBC413D3219945E35D243E8A6D3908735B01333F527C9CD10E5F0B2467C9F3623BCBC0008106B6732BD0CCABEBC331A463726BA783A8C036339D60B6B9AF8671D2AD57E07B6C445F23DD6B6FCF82F7B856FFCCC57A5C0B1D53F2E7930107B24009AB14883B20371E427A4FDBB0EFABB9B182071FF7BD4675D7CF47CFE9C17D9B9EFF98210EAF8D87638848AF6A6E1A5DE6AB975C96DE99352B534F639697EB6463F5F66A8613E24E462C92518A663725C023F18975A943FE89E9EF2C075F0FCA2AED88C2D61D0BCBE05629A88CA424A70B7EBEF17ADFC9005531FC01E2132C6AC685B36CCAF52DA039D0139E7E52E435374F4FF898005B84E75CACF730D262E66977FA18D5653538E9D7DF66B5684D7E3107E9F4A7A5EA5949A292D2CE9EB0B2AA76D737623614130364318DF1EBDE95676B507EF5CC76F08A8FB8A40CE93 -20240902012852 2 6 100 8191 2 E90C219E279F374756F460D972C0503655CE6346FD0F611E8808CD4ADDDCE308981860661516592055313E99D7CC26BBCEE76FDE697801AA2827379287137910127F9107DEA68C3FAD7DBC9DADC15102DA2C4D890186E4279C8590E5D3F90E1B93EAFA540386086C4B55AE83AE5C7EB5FD9478B16F1143BB97202E24CE3FEE6E314B308A8CBC1F2938D7013654B6A5D141D4422375EDDEA2C2011231C5C83F318FCBE6A8FBEA20D8E9C2618D45DEBE36611557447900B4B8248A25E4D523C3D9DCAB1F1C1A7CE5EFD7FA4B1BF34486F5737F61A94C20D9268CCC52785FBF8CE06D605997A8DE54E76D7F566582C8C064E244151FD43E7B97368891F274FF1D1EBB9627BEBE9B9B202E656445873198D32286D9D8F9F0387D3ABC6C0C74C9FEC8FA935C5F43287AA191591A6ADF80EBD6EB5B58C2524BE2E2E3000A25345A7D082B7AD136133E87B4BFED4C20EE58055EDA6E9D2E2F15E299D14E11919F2C3029CE1C818D5D30EA68D0458F3B1AB30923F55F84A3BCF14137B547D56CA353F3BB7EC6F22705CC0B14FBD8D7E869325B688AA759C30FAFC74A01567BD785F4ED1F0ED1B7B82F00467A687EC3BB12A246B620B2FE0B9783C222F999CCB7CEF6FA2E3FE4DE652FC0C4B21FC4DF2CEF7981F644FB2158B208C71C68C6974D4D1090C830379707BC30C7748487EB922A4B40CB0FE33B5B4A8E22354ADB2020315D043706D608B1213A2974ED5CC6EA8A520E3147667DD81F4294313AF935C528C82B659B7A169F4B11CD03A3D35546A4E4E2FF79DB6173F3A762B22EBE4BE5B49DD4951A6BC27D5EDD8486E2105561B9BE23F1826BC0579A482AFFD99508E09F17A20419F56A31AEFADCBF816706BC1B47420A7C66A19AF1A725D691CED949F9135404B35237E6B07A037F87F4515B7F1FD5B2A7B3B562ED121A12C1B4BF9E408A0221922B10B78B9D75B81381853BBF734BBE33E12602D4191BCD47B57FA20803F1D75FD4D5A077D50DD537A6B38AB09A1A3C1B30845A0D92AA38BD1B7D1F1AA1AC9FE9CD0A0DE23BD1943A99793D18FC08BD9D7744B62D460263F879087A996FC2868675FE43F7026C6C3C93187C629AF58038F61E3072D8A4B42ABFD1639C5F2289E0A974FFBBC67FD2BAC657BC3C582664A6AD8B940E8F8596FDB8B6429C1A1F06AB1249C9A03F271F66550503E9613277D38DC63031F21AA7C8C9B2D91D6F6B7C036BAB18B5FC8900E4679992DE4BAA2CF202787D521D1545AF4A090E8E17F7E8012C104791D2F6025A41C543F9D85C1DD3EE5757CA2445697075C87D0334FD0F5C9AA8EAFF4A8A4AAEDBE7F2C80151066C7A0F05B3A6B6E5EFD1DE7FE9C53421A00BA9917C732D4735ECEE42CDE994FA6DE2C171207B2A4ADE76EC4411C2171F7C7A0E05C37E3BE842F224A3F8FF6A55DC806FC3F7904147910B6D46ED77CB9B -20240902013705 2 6 100 8191 2 E90C219E279F374756F460D972C0503655CE6346FD0F611E8808CD4ADDDCE308981860661516592055313E99D7CC26BBCEE76FDE697801AA2827379287137910127F9107DEA68C3FAD7DBC9DADC15102DA2C4D890186E4279C8590E5D3F90E1B93EAFA540386086C4B55AE83AE5C7EB5FD9478B16F1143BB97202E24CE3FEE6E314B308A8CBC1F2938D7013654B6A5D141D4422375EDDEA2C2011231C5C83F318FCBE6A8FBEA20D8E9C2618D45DEBE36611557447900B4B8248A25E4D523C3D9DCAB1F1C1A7CE5EFD7FA4B1BF34486F5737F61A94C20D9268CCC52785FBF8CE06D605997A8DE54E76D7F566582C8C064E244151FD43E7B97368891F274FF1D1EBB9627BEBE9B9B202E656445873198D32286D9D8F9F0387D3ABC6C0C74C9FEC8FA935C5F43287AA191591A6ADF80EBD6EB5B58C2524BE2E2E3000A25345A7D082B7AD136133E87B4BFED4C20EE58055EDA6E9D2E2F15E299D14E11919F2C3029CE1C818D5D30EA68D0458F3B1AB30923F55F84A3BCF14137B547D56CA353F3BB7EC6F22705CC0B14FBD8D7E869325B688AA759C30FAFC74A01567BD785F4ED1F0ED1B7B82F00467A687EC3BB12A246B620B2FE0B9783C222F999CCB7CEF6FA2E3FE4DE652FC0C4B21FC4DF2CEF7981F644FB2158B208C71C68C6974D4D1090C830379707BC30C7748487EB922A4B40CB0FE33B5B4A8E22354ADB2020315D043706D608B1213A2974ED5CC6EA8A520E3147667DD81F4294313AF935C528C82B659B7A169F4B11CD03A3D35546A4E4E2FF79DB6173F3A762B22EBE4BE5B49DD4951A6BC27D5EDD8486E2105561B9BE23F1826BC0579A482AFFD99508E09F17A20419F56A31AEFADCBF816706BC1B47420A7C66A19AF1A725D691CED949F9135404B35237E6B07A037F87F4515B7F1FD5B2A7B3B562ED121A12C1B4BF9E408A0221922B10B78B9D75B81381853BBF734BBE33E12602D4191BCD47B57FA20803F1D75FD4D5A077D50DD537A6B38AB09A1A3C1B30845A0D92AA38BD1B7D1F1AA1AC9FE9CD0A0DE23BD1943A99793D18FC08BD9D7744B62D460263F879087A996FC2868675FE43F7026C6C3C93187C629AF58038F61E3072D8A4B42ABFD1639C5F2289E0A974FFBBC67FD2BAC657BC3C582664A6AD8B940E8F8596FDB8B6429C1A1F06AB1249C9A03F271F66550503E9613277D38DC63031F21AA7C8C9B2D91D6F6B7C036BAB18B5FC8900E4679992DE4BAA2CF202787D521D1545AF4A090E8E17F7E8012C104791D2F6025A41C543F9D85C1DD3EE5757CA2445697075C87D0334FD0F5C9AA8EAFF4A8A4AAEDBE7F2C80151066C7A0F05B3A6B6E5EFD1DE7FE9C53421A00BA9917C732D4735ECEE42CDE994FA6DE2C171207B2A4ADE76EC4411C2171F7C7A0E05C37E3BE842F224A3F8FF6A55DC806FC3F7904147910B6D46EDE42B6B -20240902022309 2 6 100 8191 2 E90C219E279F374756F460D972C0503655CE6346FD0F611E8808CD4ADDDCE308981860661516592055313E99D7CC26BBCEE76FDE697801AA2827379287137910127F9107DEA68C3FAD7DBC9DADC15102DA2C4D890186E4279C8590E5D3F90E1B93EAFA540386086C4B55AE83AE5C7EB5FD9478B16F1143BB97202E24CE3FEE6E314B308A8CBC1F2938D7013654B6A5D141D4422375EDDEA2C2011231C5C83F318FCBE6A8FBEA20D8E9C2618D45DEBE36611557447900B4B8248A25E4D523C3D9DCAB1F1C1A7CE5EFD7FA4B1BF34486F5737F61A94C20D9268CCC52785FBF8CE06D605997A8DE54E76D7F566582C8C064E244151FD43E7B97368891F274FF1D1EBB9627BEBE9B9B202E656445873198D32286D9D8F9F0387D3ABC6C0C74C9FEC8FA935C5F43287AA191591A6ADF80EBD6EB5B58C2524BE2E2E3000A25345A7D082B7AD136133E87B4BFED4C20EE58055EDA6E9D2E2F15E299D14E11919F2C3029CE1C818D5D30EA68D0458F3B1AB30923F55F84A3BCF14137B547D56CA353F3BB7EC6F22705CC0B14FBD8D7E869325B688AA759C30FAFC74A01567BD785F4ED1F0ED1B7B82F00467A687EC3BB12A246B620B2FE0B9783C222F999CCB7CEF6FA2E3FE4DE652FC0C4B21FC4DF2CEF7981F644FB2158B208C71C68C6974D4D1090C830379707BC30C7748487EB922A4B40CB0FE33B5B4A8E22354ADB2020315D043706D608B1213A2974ED5CC6EA8A520E3147667DD81F4294313AF935C528C82B659B7A169F4B11CD03A3D35546A4E4E2FF79DB6173F3A762B22EBE4BE5B49DD4951A6BC27D5EDD8486E2105561B9BE23F1826BC0579A482AFFD99508E09F17A20419F56A31AEFADCBF816706BC1B47420A7C66A19AF1A725D691CED949F9135404B35237E6B07A037F87F4515B7F1FD5B2A7B3B562ED121A12C1B4BF9E408A0221922B10B78B9D75B81381853BBF734BBE33E12602D4191BCD47B57FA20803F1D75FD4D5A077D50DD537A6B38AB09A1A3C1B30845A0D92AA38BD1B7D1F1AA1AC9FE9CD0A0DE23BD1943A99793D18FC08BD9D7744B62D460263F879087A996FC2868675FE43F7026C6C3C93187C629AF58038F61E3072D8A4B42ABFD1639C5F2289E0A974FFBBC67FD2BAC657BC3C582664A6AD8B940E8F8596FDB8B6429C1A1F06AB1249C9A03F271F66550503E9613277D38DC63031F21AA7C8C9B2D91D6F6B7C036BAB18B5FC8900E4679992DE4BAA2CF202787D521D1545AF4A090E8E17F7E8012C104791D2F6025A41C543F9D85C1DD3EE5757CA2445697075C87D0334FD0F5C9AA8EAFF4A8A4AAEDBE7F2C80151066C7A0F05B3A6B6E5EFD1DE7FE9C53421A00BA9917C732D4735ECEE42CDE994FA6DE2C171207B2A4ADE76EC4411C2171F7C7A0E05C37E3BE842F224A3F8FF6A55DC806FC3F7904147910B6D46F07C42B3 -20240902023700 2 6 100 8191 2 E90C219E279F374756F460D972C0503655CE6346FD0F611E8808CD4ADDDCE308981860661516592055313E99D7CC26BBCEE76FDE697801AA2827379287137910127F9107DEA68C3FAD7DBC9DADC15102DA2C4D890186E4279C8590E5D3F90E1B93EAFA540386086C4B55AE83AE5C7EB5FD9478B16F1143BB97202E24CE3FEE6E314B308A8CBC1F2938D7013654B6A5D141D4422375EDDEA2C2011231C5C83F318FCBE6A8FBEA20D8E9C2618D45DEBE36611557447900B4B8248A25E4D523C3D9DCAB1F1C1A7CE5EFD7FA4B1BF34486F5737F61A94C20D9268CCC52785FBF8CE06D605997A8DE54E76D7F566582C8C064E244151FD43E7B97368891F274FF1D1EBB9627BEBE9B9B202E656445873198D32286D9D8F9F0387D3ABC6C0C74C9FEC8FA935C5F43287AA191591A6ADF80EBD6EB5B58C2524BE2E2E3000A25345A7D082B7AD136133E87B4BFED4C20EE58055EDA6E9D2E2F15E299D14E11919F2C3029CE1C818D5D30EA68D0458F3B1AB30923F55F84A3BCF14137B547D56CA353F3BB7EC6F22705CC0B14FBD8D7E869325B688AA759C30FAFC74A01567BD785F4ED1F0ED1B7B82F00467A687EC3BB12A246B620B2FE0B9783C222F999CCB7CEF6FA2E3FE4DE652FC0C4B21FC4DF2CEF7981F644FB2158B208C71C68C6974D4D1090C830379707BC30C7748487EB922A4B40CB0FE33B5B4A8E22354ADB2020315D043706D608B1213A2974ED5CC6EA8A520E3147667DD81F4294313AF935C528C82B659B7A169F4B11CD03A3D35546A4E4E2FF79DB6173F3A762B22EBE4BE5B49DD4951A6BC27D5EDD8486E2105561B9BE23F1826BC0579A482AFFD99508E09F17A20419F56A31AEFADCBF816706BC1B47420A7C66A19AF1A725D691CED949F9135404B35237E6B07A037F87F4515B7F1FD5B2A7B3B562ED121A12C1B4BF9E408A0221922B10B78B9D75B81381853BBF734BBE33E12602D4191BCD47B57FA20803F1D75FD4D5A077D50DD537A6B38AB09A1A3C1B30845A0D92AA38BD1B7D1F1AA1AC9FE9CD0A0DE23BD1943A99793D18FC08BD9D7744B62D460263F879087A996FC2868675FE43F7026C6C3C93187C629AF58038F61E3072D8A4B42ABFD1639C5F2289E0A974FFBBC67FD2BAC657BC3C582664A6AD8B940E8F8596FDB8B6429C1A1F06AB1249C9A03F271F66550503E9613277D38DC63031F21AA7C8C9B2D91D6F6B7C036BAB18B5FC8900E4679992DE4BAA2CF202787D521D1545AF4A090E8E17F7E8012C104791D2F6025A41C543F9D85C1DD3EE5757CA2445697075C87D0334FD0F5C9AA8EAFF4A8A4AAEDBE7F2C80151066C7A0F05B3A6B6E5EFD1DE7FE9C53421A00BA9917C732D4735ECEE42CDE994FA6DE2C171207B2A4ADE76EC4411C2171F7C7A0E05C37E3BE842F224A3F8FF6A55DC806FC3F7904147910B6D46F13D6B9B -20240902033157 2 6 100 8191 5 E90C219E279F374756F460D972C0503655CE6346FD0F611E8808CD4ADDDCE308981860661516592055313E99D7CC26BBCEE76FDE697801AA2827379287137910127F9107DEA68C3FAD7DBC9DADC15102DA2C4D890186E4279C8590E5D3F90E1B93EAFA540386086C4B55AE83AE5C7EB5FD9478B16F1143BB97202E24CE3FEE6E314B308A8CBC1F2938D7013654B6A5D141D4422375EDDEA2C2011231C5C83F318FCBE6A8FBEA20D8E9C2618D45DEBE36611557447900B4B8248A25E4D523C3D9DCAB1F1C1A7CE5EFD7FA4B1BF34486F5737F61A94C20D9268CCC52785FBF8CE06D605997A8DE54E76D7F566582C8C064E244151FD43E7B97368891F274FF1D1EBB9627BEBE9B9B202E656445873198D32286D9D8F9F0387D3ABC6C0C74C9FEC8FA935C5F43287AA191591A6ADF80EBD6EB5B58C2524BE2E2E3000A25345A7D082B7AD136133E87B4BFED4C20EE58055EDA6E9D2E2F15E299D14E11919F2C3029CE1C818D5D30EA68D0458F3B1AB30923F55F84A3BCF14137B547D56CA353F3BB7EC6F22705CC0B14FBD8D7E869325B688AA759C30FAFC74A01567BD785F4ED1F0ED1B7B82F00467A687EC3BB12A246B620B2FE0B9783C222F999CCB7CEF6FA2E3FE4DE652FC0C4B21FC4DF2CEF7981F644FB2158B208C71C68C6974D4D1090C830379707BC30C7748487EB922A4B40CB0FE33B5B4A8E22354ADB2020315D043706D608B1213A2974ED5CC6EA8A520E3147667DD81F4294313AF935C528C82B659B7A169F4B11CD03A3D35546A4E4E2FF79DB6173F3A762B22EBE4BE5B49DD4951A6BC27D5EDD8486E2105561B9BE23F1826BC0579A482AFFD99508E09F17A20419F56A31AEFADCBF816706BC1B47420A7C66A19AF1A725D691CED949F9135404B35237E6B07A037F87F4515B7F1FD5B2A7B3B562ED121A12C1B4BF9E408A0221922B10B78B9D75B81381853BBF734BBE33E12602D4191BCD47B57FA20803F1D75FD4D5A077D50DD537A6B38AB09A1A3C1B30845A0D92AA38BD1B7D1F1AA1AC9FE9CD0A0DE23BD1943A99793D18FC08BD9D7744B62D460263F879087A996FC2868675FE43F7026C6C3C93187C629AF58038F61E3072D8A4B42ABFD1639C5F2289E0A974FFBBC67FD2BAC657BC3C582664A6AD8B940E8F8596FDB8B6429C1A1F06AB1249C9A03F271F66550503E9613277D38DC63031F21AA7C8C9B2D91D6F6B7C036BAB18B5FC8900E4679992DE4BAA2CF202787D521D1545AF4A090E8E17F7E8012C104791D2F6025A41C543F9D85C1DD3EE5757CA2445697075C87D0334FD0F5C9AA8EAFF4A8A4AAEDBE7F2C80151066C7A0F05B3A6B6E5EFD1DE7FE9C53421A00BA9917C732D4735ECEE42CDE994FA6DE2C171207B2A4ADE76EC4411C2171F7C7A0E05C37E3BE842F224A3F8FF6A55DC806FC3F7904147910B6D46F444A467 -20240902074115 2 6 100 8191 2 E90C219E279F374756F460D972C0503655CE6346FD0F611E8808CD4ADDDCE308981860661516592055313E99D7CC26BBCEE76FDE697801AA2827379287137910127F9107DEA68C3FAD7DBC9DADC15102DA2C4D890186E4279C8590E5D3F90E1B93EAFA540386086C4B55AE83AE5C7EB5FD9478B16F1143BB97202E24CE3FEE6E314B308A8CBC1F2938D7013654B6A5D141D4422375EDDEA2C2011231C5C83F318FCBE6A8FBEA20D8E9C2618D45DEBE36611557447900B4B8248A25E4D523C3D9DCAB1F1C1A7CE5EFD7FA4B1BF34486F5737F61A94C20D9268CCC52785FBF8CE06D605997A8DE54E76D7F566582C8C064E244151FD43E7B97368891F274FF1D1EBB9627BEBE9B9B202E656445873198D32286D9D8F9F0387D3ABC6C0C74C9FEC8FA935C5F43287AA191591A6ADF80EBD6EB5B58C2524BE2E2E3000A25345A7D082B7AD136133E87B4BFED4C20EE58055EDA6E9D2E2F15E299D14E11919F2C3029CE1C818D5D30EA68D0458F3B1AB30923F55F84A3BCF14137B547D56CA353F3BB7EC6F22705CC0B14FBD8D7E869325B688AA759C30FAFC74A01567BD785F4ED1F0ED1B7B82F00467A687EC3BB12A246B620B2FE0B9783C222F999CCB7CEF6FA2E3FE4DE652FC0C4B21FC4DF2CEF7981F644FB2158B208C71C68C6974D4D1090C830379707BC30C7748487EB922A4B40CB0FE33B5B4A8E22354ADB2020315D043706D608B1213A2974ED5CC6EA8A520E3147667DD81F4294313AF935C528C82B659B7A169F4B11CD03A3D35546A4E4E2FF79DB6173F3A762B22EBE4BE5B49DD4951A6BC27D5EDD8486E2105561B9BE23F1826BC0579A482AFFD99508E09F17A20419F56A31AEFADCBF816706BC1B47420A7C66A19AF1A725D691CED949F9135404B35237E6B07A037F87F4515B7F1FD5B2A7B3B562ED121A12C1B4BF9E408A0221922B10B78B9D75B81381853BBF734BBE33E12602D4191BCD47B57FA20803F1D75FD4D5A077D50DD537A6B38AB09A1A3C1B30845A0D92AA38BD1B7D1F1AA1AC9FE9CD0A0DE23BD1943A99793D18FC08BD9D7744B62D460263F879087A996FC2868675FE43F7026C6C3C93187C629AF58038F61E3072D8A4B42ABFD1639C5F2289E0A974FFBBC67FD2BAC657BC3C582664A6AD8B940E8F8596FDB8B6429C1A1F06AB1249C9A03F271F66550503E9613277D38DC63031F21AA7C8C9B2D91D6F6B7C036BAB18B5FC8900E4679992DE4BAA2CF202787D521D1545AF4A090E8E17F7E8012C104791D2F6025A41C543F9D85C1DD3EE5757CA2445697075C87D0334FD0F5C9AA8EAFF4A8A4AAEDBE7F2C80151066C7A0F05B3A6B6E5EFD1DE7FE9C53421A00BA9917C732D4735ECEE42CDE994FA6DE2C171207B2A4ADE76EC4411C2171F7C7A0E05C37E3BE842F224A3F8FF6A55DC806FC3F7904147910B6D470264825B -20240902081217 2 6 100 8191 2 E90C219E279F374756F460D972C0503655CE6346FD0F611E8808CD4ADDDCE308981860661516592055313E99D7CC26BBCEE76FDE697801AA2827379287137910127F9107DEA68C3FAD7DBC9DADC15102DA2C4D890186E4279C8590E5D3F90E1B93EAFA540386086C4B55AE83AE5C7EB5FD9478B16F1143BB97202E24CE3FEE6E314B308A8CBC1F2938D7013654B6A5D141D4422375EDDEA2C2011231C5C83F318FCBE6A8FBEA20D8E9C2618D45DEBE36611557447900B4B8248A25E4D523C3D9DCAB1F1C1A7CE5EFD7FA4B1BF34486F5737F61A94C20D9268CCC52785FBF8CE06D605997A8DE54E76D7F566582C8C064E244151FD43E7B97368891F274FF1D1EBB9627BEBE9B9B202E656445873198D32286D9D8F9F0387D3ABC6C0C74C9FEC8FA935C5F43287AA191591A6ADF80EBD6EB5B58C2524BE2E2E3000A25345A7D082B7AD136133E87B4BFED4C20EE58055EDA6E9D2E2F15E299D14E11919F2C3029CE1C818D5D30EA68D0458F3B1AB30923F55F84A3BCF14137B547D56CA353F3BB7EC6F22705CC0B14FBD8D7E869325B688AA759C30FAFC74A01567BD785F4ED1F0ED1B7B82F00467A687EC3BB12A246B620B2FE0B9783C222F999CCB7CEF6FA2E3FE4DE652FC0C4B21FC4DF2CEF7981F644FB2158B208C71C68C6974D4D1090C830379707BC30C7748487EB922A4B40CB0FE33B5B4A8E22354ADB2020315D043706D608B1213A2974ED5CC6EA8A520E3147667DD81F4294313AF935C528C82B659B7A169F4B11CD03A3D35546A4E4E2FF79DB6173F3A762B22EBE4BE5B49DD4951A6BC27D5EDD8486E2105561B9BE23F1826BC0579A482AFFD99508E09F17A20419F56A31AEFADCBF816706BC1B47420A7C66A19AF1A725D691CED949F9135404B35237E6B07A037F87F4515B7F1FD5B2A7B3B562ED121A12C1B4BF9E408A0221922B10B78B9D75B81381853BBF734BBE33E12602D4191BCD47B57FA20803F1D75FD4D5A077D50DD537A6B38AB09A1A3C1B30845A0D92AA38BD1B7D1F1AA1AC9FE9CD0A0DE23BD1943A99793D18FC08BD9D7744B62D460263F879087A996FC2868675FE43F7026C6C3C93187C629AF58038F61E3072D8A4B42ABFD1639C5F2289E0A974FFBBC67FD2BAC657BC3C582664A6AD8B940E8F8596FDB8B6429C1A1F06AB1249C9A03F271F66550503E9613277D38DC63031F21AA7C8C9B2D91D6F6B7C036BAB18B5FC8900E4679992DE4BAA2CF202787D521D1545AF4A090E8E17F7E8012C104791D2F6025A41C543F9D85C1DD3EE5757CA2445697075C87D0334FD0F5C9AA8EAFF4A8A4AAEDBE7F2C80151066C7A0F05B3A6B6E5EFD1DE7FE9C53421A00BA9917C732D4735ECEE42CDE994FA6DE2C171207B2A4ADE76EC4411C2171F7C7A0E05C37E3BE842F224A3F8FF6A55DC806FC3F7904147910B6D47041D069B -20240902085634 2 6 100 8191 5 E90C219E279F374756F460D972C0503655CE6346FD0F611E8808CD4ADDDCE308981860661516592055313E99D7CC26BBCEE76FDE697801AA2827379287137910127F9107DEA68C3FAD7DBC9DADC15102DA2C4D890186E4279C8590E5D3F90E1B93EAFA540386086C4B55AE83AE5C7EB5FD9478B16F1143BB97202E24CE3FEE6E314B308A8CBC1F2938D7013654B6A5D141D4422375EDDEA2C2011231C5C83F318FCBE6A8FBEA20D8E9C2618D45DEBE36611557447900B4B8248A25E4D523C3D9DCAB1F1C1A7CE5EFD7FA4B1BF34486F5737F61A94C20D9268CCC52785FBF8CE06D605997A8DE54E76D7F566582C8C064E244151FD43E7B97368891F274FF1D1EBB9627BEBE9B9B202E656445873198D32286D9D8F9F0387D3ABC6C0C74C9FEC8FA935C5F43287AA191591A6ADF80EBD6EB5B58C2524BE2E2E3000A25345A7D082B7AD136133E87B4BFED4C20EE58055EDA6E9D2E2F15E299D14E11919F2C3029CE1C818D5D30EA68D0458F3B1AB30923F55F84A3BCF14137B547D56CA353F3BB7EC6F22705CC0B14FBD8D7E869325B688AA759C30FAFC74A01567BD785F4ED1F0ED1B7B82F00467A687EC3BB12A246B620B2FE0B9783C222F999CCB7CEF6FA2E3FE4DE652FC0C4B21FC4DF2CEF7981F644FB2158B208C71C68C6974D4D1090C830379707BC30C7748487EB922A4B40CB0FE33B5B4A8E22354ADB2020315D043706D608B1213A2974ED5CC6EA8A520E3147667DD81F4294313AF935C528C82B659B7A169F4B11CD03A3D35546A4E4E2FF79DB6173F3A762B22EBE4BE5B49DD4951A6BC27D5EDD8486E2105561B9BE23F1826BC0579A482AFFD99508E09F17A20419F56A31AEFADCBF816706BC1B47420A7C66A19AF1A725D691CED949F9135404B35237E6B07A037F87F4515B7F1FD5B2A7B3B562ED121A12C1B4BF9E408A0221922B10B78B9D75B81381853BBF734BBE33E12602D4191BCD47B57FA20803F1D75FD4D5A077D50DD537A6B38AB09A1A3C1B30845A0D92AA38BD1B7D1F1AA1AC9FE9CD0A0DE23BD1943A99793D18FC08BD9D7744B62D460263F879087A996FC2868675FE43F7026C6C3C93187C629AF58038F61E3072D8A4B42ABFD1639C5F2289E0A974FFBBC67FD2BAC657BC3C582664A6AD8B940E8F8596FDB8B6429C1A1F06AB1249C9A03F271F66550503E9613277D38DC63031F21AA7C8C9B2D91D6F6B7C036BAB18B5FC8900E4679992DE4BAA2CF202787D521D1545AF4A090E8E17F7E8012C104791D2F6025A41C543F9D85C1DD3EE5757CA2445697075C87D0334FD0F5C9AA8EAFF4A8A4AAEDBE7F2C80151066C7A0F05B3A6B6E5EFD1DE7FE9C53421A00BA9917C732D4735ECEE42CDE994FA6DE2C171207B2A4ADE76EC4411C2171F7C7A0E05C37E3BE842F224A3F8FF6A55DC806FC3F7904147910B6D4706993BE7 -20240902095212 2 6 100 8191 2 E90C219E279F374756F460D972C0503655CE6346FD0F611E8808CD4ADDDCE308981860661516592055313E99D7CC26BBCEE76FDE697801AA2827379287137910127F9107DEA68C3FAD7DBC9DADC15102DA2C4D890186E4279C8590E5D3F90E1B93EAFA540386086C4B55AE83AE5C7EB5FD9478B16F1143BB97202E24CE3FEE6E314B308A8CBC1F2938D7013654B6A5D141D4422375EDDEA2C2011231C5C83F318FCBE6A8FBEA20D8E9C2618D45DEBE36611557447900B4B8248A25E4D523C3D9DCAB1F1C1A7CE5EFD7FA4B1BF34486F5737F61A94C20D9268CCC52785FBF8CE06D605997A8DE54E76D7F566582C8C064E244151FD43E7B97368891F274FF1D1EBB9627BEBE9B9B202E656445873198D32286D9D8F9F0387D3ABC6C0C74C9FEC8FA935C5F43287AA191591A6ADF80EBD6EB5B58C2524BE2E2E3000A25345A7D082B7AD136133E87B4BFED4C20EE58055EDA6E9D2E2F15E299D14E11919F2C3029CE1C818D5D30EA68D0458F3B1AB30923F55F84A3BCF14137B547D56CA353F3BB7EC6F22705CC0B14FBD8D7E869325B688AA759C30FAFC74A01567BD785F4ED1F0ED1B7B82F00467A687EC3BB12A246B620B2FE0B9783C222F999CCB7CEF6FA2E3FE4DE652FC0C4B21FC4DF2CEF7981F644FB2158B208C71C68C6974D4D1090C830379707BC30C7748487EB922A4B40CB0FE33B5B4A8E22354ADB2020315D043706D608B1213A2974ED5CC6EA8A520E3147667DD81F4294313AF935C528C82B659B7A169F4B11CD03A3D35546A4E4E2FF79DB6173F3A762B22EBE4BE5B49DD4951A6BC27D5EDD8486E2105561B9BE23F1826BC0579A482AFFD99508E09F17A20419F56A31AEFADCBF816706BC1B47420A7C66A19AF1A725D691CED949F9135404B35237E6B07A037F87F4515B7F1FD5B2A7B3B562ED121A12C1B4BF9E408A0221922B10B78B9D75B81381853BBF734BBE33E12602D4191BCD47B57FA20803F1D75FD4D5A077D50DD537A6B38AB09A1A3C1B30845A0D92AA38BD1B7D1F1AA1AC9FE9CD0A0DE23BD1943A99793D18FC08BD9D7744B62D460263F879087A996FC2868675FE43F7026C6C3C93187C629AF58038F61E3072D8A4B42ABFD1639C5F2289E0A974FFBBC67FD2BAC657BC3C582664A6AD8B940E8F8596FDB8B6429C1A1F06AB1249C9A03F271F66550503E9613277D38DC63031F21AA7C8C9B2D91D6F6B7C036BAB18B5FC8900E4679992DE4BAA2CF202787D521D1545AF4A090E8E17F7E8012C104791D2F6025A41C543F9D85C1DD3EE5757CA2445697075C87D0334FD0F5C9AA8EAFF4A8A4AAEDBE7F2C80151066C7A0F05B3A6B6E5EFD1DE7FE9C53421A00BA9917C732D4735ECEE42CDE994FA6DE2C171207B2A4ADE76EC4411C2171F7C7A0E05C37E3BE842F224A3F8FF6A55DC806FC3F7904147910B6D4709C080DB -20240902103310 2 6 100 8191 2 E90C219E279F374756F460D972C0503655CE6346FD0F611E8808CD4ADDDCE308981860661516592055313E99D7CC26BBCEE76FDE697801AA2827379287137910127F9107DEA68C3FAD7DBC9DADC15102DA2C4D890186E4279C8590E5D3F90E1B93EAFA540386086C4B55AE83AE5C7EB5FD9478B16F1143BB97202E24CE3FEE6E314B308A8CBC1F2938D7013654B6A5D141D4422375EDDEA2C2011231C5C83F318FCBE6A8FBEA20D8E9C2618D45DEBE36611557447900B4B8248A25E4D523C3D9DCAB1F1C1A7CE5EFD7FA4B1BF34486F5737F61A94C20D9268CCC52785FBF8CE06D605997A8DE54E76D7F566582C8C064E244151FD43E7B97368891F274FF1D1EBB9627BEBE9B9B202E656445873198D32286D9D8F9F0387D3ABC6C0C74C9FEC8FA935C5F43287AA191591A6ADF80EBD6EB5B58C2524BE2E2E3000A25345A7D082B7AD136133E87B4BFED4C20EE58055EDA6E9D2E2F15E299D14E11919F2C3029CE1C818D5D30EA68D0458F3B1AB30923F55F84A3BCF14137B547D56CA353F3BB7EC6F22705CC0B14FBD8D7E869325B688AA759C30FAFC74A01567BD785F4ED1F0ED1B7B82F00467A687EC3BB12A246B620B2FE0B9783C222F999CCB7CEF6FA2E3FE4DE652FC0C4B21FC4DF2CEF7981F644FB2158B208C71C68C6974D4D1090C830379707BC30C7748487EB922A4B40CB0FE33B5B4A8E22354ADB2020315D043706D608B1213A2974ED5CC6EA8A520E3147667DD81F4294313AF935C528C82B659B7A169F4B11CD03A3D35546A4E4E2FF79DB6173F3A762B22EBE4BE5B49DD4951A6BC27D5EDD8486E2105561B9BE23F1826BC0579A482AFFD99508E09F17A20419F56A31AEFADCBF816706BC1B47420A7C66A19AF1A725D691CED949F9135404B35237E6B07A037F87F4515B7F1FD5B2A7B3B562ED121A12C1B4BF9E408A0221922B10B78B9D75B81381853BBF734BBE33E12602D4191BCD47B57FA20803F1D75FD4D5A077D50DD537A6B38AB09A1A3C1B30845A0D92AA38BD1B7D1F1AA1AC9FE9CD0A0DE23BD1943A99793D18FC08BD9D7744B62D460263F879087A996FC2868675FE43F7026C6C3C93187C629AF58038F61E3072D8A4B42ABFD1639C5F2289E0A974FFBBC67FD2BAC657BC3C582664A6AD8B940E8F8596FDB8B6429C1A1F06AB1249C9A03F271F66550503E9613277D38DC63031F21AA7C8C9B2D91D6F6B7C036BAB18B5FC8900E4679992DE4BAA2CF202787D521D1545AF4A090E8E17F7E8012C104791D2F6025A41C543F9D85C1DD3EE5757CA2445697075C87D0334FD0F5C9AA8EAFF4A8A4AAEDBE7F2C80151066C7A0F05B3A6B6E5EFD1DE7FE9C53421A00BA9917C732D4735ECEE42CDE994FA6DE2C171207B2A4ADE76EC4411C2171F7C7A0E05C37E3BE842F224A3F8FF6A55DC806FC3F7904147910B6D470C00A7DB -20240902113925 2 6 100 8191 2 E90C219E279F374756F460D972C0503655CE6346FD0F611E8808CD4ADDDCE308981860661516592055313E99D7CC26BBCEE76FDE697801AA2827379287137910127F9107DEA68C3FAD7DBC9DADC15102DA2C4D890186E4279C8590E5D3F90E1B93EAFA540386086C4B55AE83AE5C7EB5FD9478B16F1143BB97202E24CE3FEE6E314B308A8CBC1F2938D7013654B6A5D141D4422375EDDEA2C2011231C5C83F318FCBE6A8FBEA20D8E9C2618D45DEBE36611557447900B4B8248A25E4D523C3D9DCAB1F1C1A7CE5EFD7FA4B1BF34486F5737F61A94C20D9268CCC52785FBF8CE06D605997A8DE54E76D7F566582C8C064E244151FD43E7B97368891F274FF1D1EBB9627BEBE9B9B202E656445873198D32286D9D8F9F0387D3ABC6C0C74C9FEC8FA935C5F43287AA191591A6ADF80EBD6EB5B58C2524BE2E2E3000A25345A7D082B7AD136133E87B4BFED4C20EE58055EDA6E9D2E2F15E299D14E11919F2C3029CE1C818D5D30EA68D0458F3B1AB30923F55F84A3BCF14137B547D56CA353F3BB7EC6F22705CC0B14FBD8D7E869325B688AA759C30FAFC74A01567BD785F4ED1F0ED1B7B82F00467A687EC3BB12A246B620B2FE0B9783C222F999CCB7CEF6FA2E3FE4DE652FC0C4B21FC4DF2CEF7981F644FB2158B208C71C68C6974D4D1090C830379707BC30C7748487EB922A4B40CB0FE33B5B4A8E22354ADB2020315D043706D608B1213A2974ED5CC6EA8A520E3147667DD81F4294313AF935C528C82B659B7A169F4B11CD03A3D35546A4E4E2FF79DB6173F3A762B22EBE4BE5B49DD4951A6BC27D5EDD8486E2105561B9BE23F1826BC0579A482AFFD99508E09F17A20419F56A31AEFADCBF816706BC1B47420A7C66A19AF1A725D691CED949F9135404B35237E6B07A037F87F4515B7F1FD5B2A7B3B562ED121A12C1B4BF9E408A0221922B10B78B9D75B81381853BBF734BBE33E12602D4191BCD47B57FA20803F1D75FD4D5A077D50DD537A6B38AB09A1A3C1B30845A0D92AA38BD1B7D1F1AA1AC9FE9CD0A0DE23BD1943A99793D18FC08BD9D7744B62D460263F879087A996FC2868675FE43F7026C6C3C93187C629AF58038F61E3072D8A4B42ABFD1639C5F2289E0A974FFBBC67FD2BAC657BC3C582664A6AD8B940E8F8596FDB8B6429C1A1F06AB1249C9A03F271F66550503E9613277D38DC63031F21AA7C8C9B2D91D6F6B7C036BAB18B5FC8900E4679992DE4BAA2CF202787D521D1545AF4A090E8E17F7E8012C104791D2F6025A41C543F9D85C1DD3EE5757CA2445697075C87D0334FD0F5C9AA8EAFF4A8A4AAEDBE7F2C80151066C7A0F05B3A6B6E5EFD1DE7FE9C53421A00BA9917C732D4735ECEE42CDE994FA6DE2C171207B2A4ADE76EC4411C2171F7C7A0E05C37E3BE842F224A3F8FF6A55DC806FC3F7904147910B6D470FB7C81B -20240902145636 2 6 100 8191 5 E90C219E279F374756F460D972C0503655CE6346FD0F611E8808CD4ADDDCE308981860661516592055313E99D7CC26BBCEE76FDE697801AA2827379287137910127F9107DEA68C3FAD7DBC9DADC15102DA2C4D890186E4279C8590E5D3F90E1B93EAFA540386086C4B55AE83AE5C7EB5FD9478B16F1143BB97202E24CE3FEE6E314B308A8CBC1F2938D7013654B6A5D141D4422375EDDEA2C2011231C5C83F318FCBE6A8FBEA20D8E9C2618D45DEBE36611557447900B4B8248A25E4D523C3D9DCAB1F1C1A7CE5EFD7FA4B1BF34486F5737F61A94C20D9268CCC52785FBF8CE06D605997A8DE54E76D7F566582C8C064E244151FD43E7B97368891F274FF1D1EBB9627BEBE9B9B202E656445873198D32286D9D8F9F0387D3ABC6C0C74C9FEC8FA935C5F43287AA191591A6ADF80EBD6EB5B58C2524BE2E2E3000A25345A7D082B7AD136133E87B4BFED4C20EE58055EDA6E9D2E2F15E299D14E11919F2C3029CE1C818D5D30EA68D0458F3B1AB30923F55F84A3BCF14137B547D56CA353F3BB7EC6F22705CC0B14FBD8D7E869325B688AA759C30FAFC74A01567BD785F4ED1F0ED1B7B82F00467A687EC3BB12A246B620B2FE0B9783C222F999CCB7CEF6FA2E3FE4DE652FC0C4B21FC4DF2CEF7981F644FB2158B208C71C68C6974D4D1090C830379707BC30C7748487EB922A4B40CB0FE33B5B4A8E22354ADB2020315D043706D608B1213A2974ED5CC6EA8A520E3147667DD81F4294313AF935C528C82B659B7A169F4B11CD03A3D35546A4E4E2FF79DB6173F3A762B22EBE4BE5B49DD4951A6BC27D5EDD8486E2105561B9BE23F1826BC0579A482AFFD99508E09F17A20419F56A31AEFADCBF816706BC1B47420A7C66A19AF1A725D691CED949F9135404B35237E6B07A037F87F4515B7F1FD5B2A7B3B562ED121A12C1B4BF9E408A0221922B10B78B9D75B81381853BBF734BBE33E12602D4191BCD47B57FA20803F1D75FD4D5A077D50DD537A6B38AB09A1A3C1B30845A0D92AA38BD1B7D1F1AA1AC9FE9CD0A0DE23BD1943A99793D18FC08BD9D7744B62D460263F879087A996FC2868675FE43F7026C6C3C93187C629AF58038F61E3072D8A4B42ABFD1639C5F2289E0A974FFBBC67FD2BAC657BC3C582664A6AD8B940E8F8596FDB8B6429C1A1F06AB1249C9A03F271F66550503E9613277D38DC63031F21AA7C8C9B2D91D6F6B7C036BAB18B5FC8900E4679992DE4BAA2CF202787D521D1545AF4A090E8E17F7E8012C104791D2F6025A41C543F9D85C1DD3EE5757CA2445697075C87D0334FD0F5C9AA8EAFF4A8A4AAEDBE7F2C80151066C7A0F05B3A6B6E5EFD1DE7FE9C53421A00BA9917C732D4735ECEE42CDE994FA6DE2C171207B2A4ADE76EC4411C2171F7C7A0E05C37E3BE842F224A3F8FF6A55DC806FC3F7904147910B6D471ADD1BC7 -20240902162039 2 6 100 8191 5 E90C219E279F374756F460D972C0503655CE6346FD0F611E8808CD4ADDDCE308981860661516592055313E99D7CC26BBCEE76FDE697801AA2827379287137910127F9107DEA68C3FAD7DBC9DADC15102DA2C4D890186E4279C8590E5D3F90E1B93EAFA540386086C4B55AE83AE5C7EB5FD9478B16F1143BB97202E24CE3FEE6E314B308A8CBC1F2938D7013654B6A5D141D4422375EDDEA2C2011231C5C83F318FCBE6A8FBEA20D8E9C2618D45DEBE36611557447900B4B8248A25E4D523C3D9DCAB1F1C1A7CE5EFD7FA4B1BF34486F5737F61A94C20D9268CCC52785FBF8CE06D605997A8DE54E76D7F566582C8C064E244151FD43E7B97368891F274FF1D1EBB9627BEBE9B9B202E656445873198D32286D9D8F9F0387D3ABC6C0C74C9FEC8FA935C5F43287AA191591A6ADF80EBD6EB5B58C2524BE2E2E3000A25345A7D082B7AD136133E87B4BFED4C20EE58055EDA6E9D2E2F15E299D14E11919F2C3029CE1C818D5D30EA68D0458F3B1AB30923F55F84A3BCF14137B547D56CA353F3BB7EC6F22705CC0B14FBD8D7E869325B688AA759C30FAFC74A01567BD785F4ED1F0ED1B7B82F00467A687EC3BB12A246B620B2FE0B9783C222F999CCB7CEF6FA2E3FE4DE652FC0C4B21FC4DF2CEF7981F644FB2158B208C71C68C6974D4D1090C830379707BC30C7748487EB922A4B40CB0FE33B5B4A8E22354ADB2020315D043706D608B1213A2974ED5CC6EA8A520E3147667DD81F4294313AF935C528C82B659B7A169F4B11CD03A3D35546A4E4E2FF79DB6173F3A762B22EBE4BE5B49DD4951A6BC27D5EDD8486E2105561B9BE23F1826BC0579A482AFFD99508E09F17A20419F56A31AEFADCBF816706BC1B47420A7C66A19AF1A725D691CED949F9135404B35237E6B07A037F87F4515B7F1FD5B2A7B3B562ED121A12C1B4BF9E408A0221922B10B78B9D75B81381853BBF734BBE33E12602D4191BCD47B57FA20803F1D75FD4D5A077D50DD537A6B38AB09A1A3C1B30845A0D92AA38BD1B7D1F1AA1AC9FE9CD0A0DE23BD1943A99793D18FC08BD9D7744B62D460263F879087A996FC2868675FE43F7026C6C3C93187C629AF58038F61E3072D8A4B42ABFD1639C5F2289E0A974FFBBC67FD2BAC657BC3C582664A6AD8B940E8F8596FDB8B6429C1A1F06AB1249C9A03F271F66550503E9613277D38DC63031F21AA7C8C9B2D91D6F6B7C036BAB18B5FC8900E4679992DE4BAA2CF202787D521D1545AF4A090E8E17F7E8012C104791D2F6025A41C543F9D85C1DD3EE5757CA2445697075C87D0334FD0F5C9AA8EAFF4A8A4AAEDBE7F2C80151066C7A0F05B3A6B6E5EFD1DE7FE9C53421A00BA9917C732D4735ECEE42CDE994FA6DE2C171207B2A4ADE76EC4411C2171F7C7A0E05C37E3BE842F224A3F8FF6A55DC806FC3F7904147910B6D471F910B07 -20240902162513 2 6 100 8191 5 E90C219E279F374756F460D972C0503655CE6346FD0F611E8808CD4ADDDCE308981860661516592055313E99D7CC26BBCEE76FDE697801AA2827379287137910127F9107DEA68C3FAD7DBC9DADC15102DA2C4D890186E4279C8590E5D3F90E1B93EAFA540386086C4B55AE83AE5C7EB5FD9478B16F1143BB97202E24CE3FEE6E314B308A8CBC1F2938D7013654B6A5D141D4422375EDDEA2C2011231C5C83F318FCBE6A8FBEA20D8E9C2618D45DEBE36611557447900B4B8248A25E4D523C3D9DCAB1F1C1A7CE5EFD7FA4B1BF34486F5737F61A94C20D9268CCC52785FBF8CE06D605997A8DE54E76D7F566582C8C064E244151FD43E7B97368891F274FF1D1EBB9627BEBE9B9B202E656445873198D32286D9D8F9F0387D3ABC6C0C74C9FEC8FA935C5F43287AA191591A6ADF80EBD6EB5B58C2524BE2E2E3000A25345A7D082B7AD136133E87B4BFED4C20EE58055EDA6E9D2E2F15E299D14E11919F2C3029CE1C818D5D30EA68D0458F3B1AB30923F55F84A3BCF14137B547D56CA353F3BB7EC6F22705CC0B14FBD8D7E869325B688AA759C30FAFC74A01567BD785F4ED1F0ED1B7B82F00467A687EC3BB12A246B620B2FE0B9783C222F999CCB7CEF6FA2E3FE4DE652FC0C4B21FC4DF2CEF7981F644FB2158B208C71C68C6974D4D1090C830379707BC30C7748487EB922A4B40CB0FE33B5B4A8E22354ADB2020315D043706D608B1213A2974ED5CC6EA8A520E3147667DD81F4294313AF935C528C82B659B7A169F4B11CD03A3D35546A4E4E2FF79DB6173F3A762B22EBE4BE5B49DD4951A6BC27D5EDD8486E2105561B9BE23F1826BC0579A482AFFD99508E09F17A20419F56A31AEFADCBF816706BC1B47420A7C66A19AF1A725D691CED949F9135404B35237E6B07A037F87F4515B7F1FD5B2A7B3B562ED121A12C1B4BF9E408A0221922B10B78B9D75B81381853BBF734BBE33E12602D4191BCD47B57FA20803F1D75FD4D5A077D50DD537A6B38AB09A1A3C1B30845A0D92AA38BD1B7D1F1AA1AC9FE9CD0A0DE23BD1943A99793D18FC08BD9D7744B62D460263F879087A996FC2868675FE43F7026C6C3C93187C629AF58038F61E3072D8A4B42ABFD1639C5F2289E0A974FFBBC67FD2BAC657BC3C582664A6AD8B940E8F8596FDB8B6429C1A1F06AB1249C9A03F271F66550503E9613277D38DC63031F21AA7C8C9B2D91D6F6B7C036BAB18B5FC8900E4679992DE4BAA2CF202787D521D1545AF4A090E8E17F7E8012C104791D2F6025A41C543F9D85C1DD3EE5757CA2445697075C87D0334FD0F5C9AA8EAFF4A8A4AAEDBE7F2C80151066C7A0F05B3A6B6E5EFD1DE7FE9C53421A00BA9917C732D4735ECEE42CDE994FA6DE2C171207B2A4ADE76EC4411C2171F7C7A0E05C37E3BE842F224A3F8FF6A55DC806FC3F7904147910B6D471FCD9837 -20240902170958 2 6 100 8191 5 E90C219E279F374756F460D972C0503655CE6346FD0F611E8808CD4ADDDCE308981860661516592055313E99D7CC26BBCEE76FDE697801AA2827379287137910127F9107DEA68C3FAD7DBC9DADC15102DA2C4D890186E4279C8590E5D3F90E1B93EAFA540386086C4B55AE83AE5C7EB5FD9478B16F1143BB97202E24CE3FEE6E314B308A8CBC1F2938D7013654B6A5D141D4422375EDDEA2C2011231C5C83F318FCBE6A8FBEA20D8E9C2618D45DEBE36611557447900B4B8248A25E4D523C3D9DCAB1F1C1A7CE5EFD7FA4B1BF34486F5737F61A94C20D9268CCC52785FBF8CE06D605997A8DE54E76D7F566582C8C064E244151FD43E7B97368891F274FF1D1EBB9627BEBE9B9B202E656445873198D32286D9D8F9F0387D3ABC6C0C74C9FEC8FA935C5F43287AA191591A6ADF80EBD6EB5B58C2524BE2E2E3000A25345A7D082B7AD136133E87B4BFED4C20EE58055EDA6E9D2E2F15E299D14E11919F2C3029CE1C818D5D30EA68D0458F3B1AB30923F55F84A3BCF14137B547D56CA353F3BB7EC6F22705CC0B14FBD8D7E869325B688AA759C30FAFC74A01567BD785F4ED1F0ED1B7B82F00467A687EC3BB12A246B620B2FE0B9783C222F999CCB7CEF6FA2E3FE4DE652FC0C4B21FC4DF2CEF7981F644FB2158B208C71C68C6974D4D1090C830379707BC30C7748487EB922A4B40CB0FE33B5B4A8E22354ADB2020315D043706D608B1213A2974ED5CC6EA8A520E3147667DD81F4294313AF935C528C82B659B7A169F4B11CD03A3D35546A4E4E2FF79DB6173F3A762B22EBE4BE5B49DD4951A6BC27D5EDD8486E2105561B9BE23F1826BC0579A482AFFD99508E09F17A20419F56A31AEFADCBF816706BC1B47420A7C66A19AF1A725D691CED949F9135404B35237E6B07A037F87F4515B7F1FD5B2A7B3B562ED121A12C1B4BF9E408A0221922B10B78B9D75B81381853BBF734BBE33E12602D4191BCD47B57FA20803F1D75FD4D5A077D50DD537A6B38AB09A1A3C1B30845A0D92AA38BD1B7D1F1AA1AC9FE9CD0A0DE23BD1943A99793D18FC08BD9D7744B62D460263F879087A996FC2868675FE43F7026C6C3C93187C629AF58038F61E3072D8A4B42ABFD1639C5F2289E0A974FFBBC67FD2BAC657BC3C582664A6AD8B940E8F8596FDB8B6429C1A1F06AB1249C9A03F271F66550503E9613277D38DC63031F21AA7C8C9B2D91D6F6B7C036BAB18B5FC8900E4679992DE4BAA2CF202787D521D1545AF4A090E8E17F7E8012C104791D2F6025A41C543F9D85C1DD3EE5757CA2445697075C87D0334FD0F5C9AA8EAFF4A8A4AAEDBE7F2C80151066C7A0F05B3A6B6E5EFD1DE7FE9C53421A00BA9917C732D4735ECEE42CDE994FA6DE2C171207B2A4ADE76EC4411C2171F7C7A0E05C37E3BE842F224A3F8FF6A55DC806FC3F7904147910B6D47224EBF47 -20240902195925 2 6 100 8191 5 E90C219E279F374756F460D972C0503655CE6346FD0F611E8808CD4ADDDCE308981860661516592055313E99D7CC26BBCEE76FDE697801AA2827379287137910127F9107DEA68C3FAD7DBC9DADC15102DA2C4D890186E4279C8590E5D3F90E1B93EAFA540386086C4B55AE83AE5C7EB5FD9478B16F1143BB97202E24CE3FEE6E314B308A8CBC1F2938D7013654B6A5D141D4422375EDDEA2C2011231C5C83F318FCBE6A8FBEA20D8E9C2618D45DEBE36611557447900B4B8248A25E4D523C3D9DCAB1F1C1A7CE5EFD7FA4B1BF34486F5737F61A94C20D9268CCC52785FBF8CE06D605997A8DE54E76D7F566582C8C064E244151FD43E7B97368891F274FF1D1EBB9627BEBE9B9B202E656445873198D32286D9D8F9F0387D3ABC6C0C74C9FEC8FA935C5F43287AA191591A6ADF80EBD6EB5B58C2524BE2E2E3000A25345A7D082B7AD136133E87B4BFED4C20EE58055EDA6E9D2E2F15E299D14E11919F2C3029CE1C818D5D30EA68D0458F3B1AB30923F55F84A3BCF14137B547D56CA353F3BB7EC6F22705CC0B14FBD8D7E869325B688AA759C30FAFC74A01567BD785F4ED1F0ED1B7B82F00467A687EC3BB12A246B620B2FE0B9783C222F999CCB7CEF6FA2E3FE4DE652FC0C4B21FC4DF2CEF7981F644FB2158B208C71C68C6974D4D1090C830379707BC30C7748487EB922A4B40CB0FE33B5B4A8E22354ADB2020315D043706D608B1213A2974ED5CC6EA8A520E3147667DD81F4294313AF935C528C82B659B7A169F4B11CD03A3D35546A4E4E2FF79DB6173F3A762B22EBE4BE5B49DD4951A6BC27D5EDD8486E2105561B9BE23F1826BC0579A482AFFD99508E09F17A20419F56A31AEFADCBF816706BC1B47420A7C66A19AF1A725D691CED949F9135404B35237E6B07A037F87F4515B7F1FD5B2A7B3B562ED121A12C1B4BF9E408A0221922B10B78B9D75B81381853BBF734BBE33E12602D4191BCD47B57FA20803F1D75FD4D5A077D50DD537A6B38AB09A1A3C1B30845A0D92AA38BD1B7D1F1AA1AC9FE9CD0A0DE23BD1943A99793D18FC08BD9D7744B62D460263F879087A996FC2868675FE43F7026C6C3C93187C629AF58038F61E3072D8A4B42ABFD1639C5F2289E0A974FFBBC67FD2BAC657BC3C582664A6AD8B940E8F8596FDB8B6429C1A1F06AB1249C9A03F271F66550503E9613277D38DC63031F21AA7C8C9B2D91D6F6B7C036BAB18B5FC8900E4679992DE4BAA2CF202787D521D1545AF4A090E8E17F7E8012C104791D2F6025A41C543F9D85C1DD3EE5757CA2445697075C87D0334FD0F5C9AA8EAFF4A8A4AAEDBE7F2C80151066C7A0F05B3A6B6E5EFD1DE7FE9C53421A00BA9917C732D4735ECEE42CDE994FA6DE2C171207B2A4ADE76EC4411C2171F7C7A0E05C37E3BE842F224A3F8FF6A55DC806FC3F7904147910B6D472BED92A7 -20240902201041 2 6 100 8191 2 E90C219E279F374756F460D972C0503655CE6346FD0F611E8808CD4ADDDCE308981860661516592055313E99D7CC26BBCEE76FDE697801AA2827379287137910127F9107DEA68C3FAD7DBC9DADC15102DA2C4D890186E4279C8590E5D3F90E1B93EAFA540386086C4B55AE83AE5C7EB5FD9478B16F1143BB97202E24CE3FEE6E314B308A8CBC1F2938D7013654B6A5D141D4422375EDDEA2C2011231C5C83F318FCBE6A8FBEA20D8E9C2618D45DEBE36611557447900B4B8248A25E4D523C3D9DCAB1F1C1A7CE5EFD7FA4B1BF34486F5737F61A94C20D9268CCC52785FBF8CE06D605997A8DE54E76D7F566582C8C064E244151FD43E7B97368891F274FF1D1EBB9627BEBE9B9B202E656445873198D32286D9D8F9F0387D3ABC6C0C74C9FEC8FA935C5F43287AA191591A6ADF80EBD6EB5B58C2524BE2E2E3000A25345A7D082B7AD136133E87B4BFED4C20EE58055EDA6E9D2E2F15E299D14E11919F2C3029CE1C818D5D30EA68D0458F3B1AB30923F55F84A3BCF14137B547D56CA353F3BB7EC6F22705CC0B14FBD8D7E869325B688AA759C30FAFC74A01567BD785F4ED1F0ED1B7B82F00467A687EC3BB12A246B620B2FE0B9783C222F999CCB7CEF6FA2E3FE4DE652FC0C4B21FC4DF2CEF7981F644FB2158B208C71C68C6974D4D1090C830379707BC30C7748487EB922A4B40CB0FE33B5B4A8E22354ADB2020315D043706D608B1213A2974ED5CC6EA8A520E3147667DD81F4294313AF935C528C82B659B7A169F4B11CD03A3D35546A4E4E2FF79DB6173F3A762B22EBE4BE5B49DD4951A6BC27D5EDD8486E2105561B9BE23F1826BC0579A482AFFD99508E09F17A20419F56A31AEFADCBF816706BC1B47420A7C66A19AF1A725D691CED949F9135404B35237E6B07A037F87F4515B7F1FD5B2A7B3B562ED121A12C1B4BF9E408A0221922B10B78B9D75B81381853BBF734BBE33E12602D4191BCD47B57FA20803F1D75FD4D5A077D50DD537A6B38AB09A1A3C1B30845A0D92AA38BD1B7D1F1AA1AC9FE9CD0A0DE23BD1943A99793D18FC08BD9D7744B62D460263F879087A996FC2868675FE43F7026C6C3C93187C629AF58038F61E3072D8A4B42ABFD1639C5F2289E0A974FFBBC67FD2BAC657BC3C582664A6AD8B940E8F8596FDB8B6429C1A1F06AB1249C9A03F271F66550503E9613277D38DC63031F21AA7C8C9B2D91D6F6B7C036BAB18B5FC8900E4679992DE4BAA2CF202787D521D1545AF4A090E8E17F7E8012C104791D2F6025A41C543F9D85C1DD3EE5757CA2445697075C87D0334FD0F5C9AA8EAFF4A8A4AAEDBE7F2C80151066C7A0F05B3A6B6E5EFD1DE7FE9C53421A00BA9917C732D4735ECEE42CDE994FA6DE2C171207B2A4ADE76EC4411C2171F7C7A0E05C37E3BE842F224A3F8FF6A55DC806FC3F7904147910B6D472C8835C3 -20240902212334 2 6 100 8191 5 E90C219E279F374756F460D972C0503655CE6346FD0F611E8808CD4ADDDCE308981860661516592055313E99D7CC26BBCEE76FDE697801AA2827379287137910127F9107DEA68C3FAD7DBC9DADC15102DA2C4D890186E4279C8590E5D3F90E1B93EAFA540386086C4B55AE83AE5C7EB5FD9478B16F1143BB97202E24CE3FEE6E314B308A8CBC1F2938D7013654B6A5D141D4422375EDDEA2C2011231C5C83F318FCBE6A8FBEA20D8E9C2618D45DEBE36611557447900B4B8248A25E4D523C3D9DCAB1F1C1A7CE5EFD7FA4B1BF34486F5737F61A94C20D9268CCC52785FBF8CE06D605997A8DE54E76D7F566582C8C064E244151FD43E7B97368891F274FF1D1EBB9627BEBE9B9B202E656445873198D32286D9D8F9F0387D3ABC6C0C74C9FEC8FA935C5F43287AA191591A6ADF80EBD6EB5B58C2524BE2E2E3000A25345A7D082B7AD136133E87B4BFED4C20EE58055EDA6E9D2E2F15E299D14E11919F2C3029CE1C818D5D30EA68D0458F3B1AB30923F55F84A3BCF14137B547D56CA353F3BB7EC6F22705CC0B14FBD8D7E869325B688AA759C30FAFC74A01567BD785F4ED1F0ED1B7B82F00467A687EC3BB12A246B620B2FE0B9783C222F999CCB7CEF6FA2E3FE4DE652FC0C4B21FC4DF2CEF7981F644FB2158B208C71C68C6974D4D1090C830379707BC30C7748487EB922A4B40CB0FE33B5B4A8E22354ADB2020315D043706D608B1213A2974ED5CC6EA8A520E3147667DD81F4294313AF935C528C82B659B7A169F4B11CD03A3D35546A4E4E2FF79DB6173F3A762B22EBE4BE5B49DD4951A6BC27D5EDD8486E2105561B9BE23F1826BC0579A482AFFD99508E09F17A20419F56A31AEFADCBF816706BC1B47420A7C66A19AF1A725D691CED949F9135404B35237E6B07A037F87F4515B7F1FD5B2A7B3B562ED121A12C1B4BF9E408A0221922B10B78B9D75B81381853BBF734BBE33E12602D4191BCD47B57FA20803F1D75FD4D5A077D50DD537A6B38AB09A1A3C1B30845A0D92AA38BD1B7D1F1AA1AC9FE9CD0A0DE23BD1943A99793D18FC08BD9D7744B62D460263F879087A996FC2868675FE43F7026C6C3C93187C629AF58038F61E3072D8A4B42ABFD1639C5F2289E0A974FFBBC67FD2BAC657BC3C582664A6AD8B940E8F8596FDB8B6429C1A1F06AB1249C9A03F271F66550503E9613277D38DC63031F21AA7C8C9B2D91D6F6B7C036BAB18B5FC8900E4679992DE4BAA2CF202787D521D1545AF4A090E8E17F7E8012C104791D2F6025A41C543F9D85C1DD3EE5757CA2445697075C87D0334FD0F5C9AA8EAFF4A8A4AAEDBE7F2C80151066C7A0F05B3A6B6E5EFD1DE7FE9C53421A00BA9917C732D4735ECEE42CDE994FA6DE2C171207B2A4ADE76EC4411C2171F7C7A0E05C37E3BE842F224A3F8FF6A55DC806FC3F7904147910B6D4730A0A15F -20240903001824 2 6 100 8191 2 E90C219E279F374756F460D972C0503655CE6346FD0F611E8808CD4ADDDCE308981860661516592055313E99D7CC26BBCEE76FDE697801AA2827379287137910127F9107DEA68C3FAD7DBC9DADC15102DA2C4D890186E4279C8590E5D3F90E1B93EAFA540386086C4B55AE83AE5C7EB5FD9478B16F1143BB97202E24CE3FEE6E314B308A8CBC1F2938D7013654B6A5D141D4422375EDDEA2C2011231C5C83F318FCBE6A8FBEA20D8E9C2618D45DEBE36611557447900B4B8248A25E4D523C3D9DCAB1F1C1A7CE5EFD7FA4B1BF34486F5737F61A94C20D9268CCC52785FBF8CE06D605997A8DE54E76D7F566582C8C064E244151FD43E7B97368891F274FF1D1EBB9627BEBE9B9B202E656445873198D32286D9D8F9F0387D3ABC6C0C74C9FEC8FA935C5F43287AA191591A6ADF80EBD6EB5B58C2524BE2E2E3000A25345A7D082B7AD136133E87B4BFED4C20EE58055EDA6E9D2E2F15E299D14E11919F2C3029CE1C818D5D30EA68D0458F3B1AB30923F55F84A3BCF14137B547D56CA353F3BB7EC6F22705CC0B14FBD8D7E869325B688AA759C30FAFC74A01567BD785F4ED1F0ED1B7B82F00467A687EC3BB12A246B620B2FE0B9783C222F999CCB7CEF6FA2E3FE4DE652FC0C4B21FC4DF2CEF7981F644FB2158B208C71C68C6974D4D1090C830379707BC30C7748487EB922A4B40CB0FE33B5B4A8E22354ADB2020315D043706D608B1213A2974ED5CC6EA8A520E3147667DD81F4294313AF935C528C82B659B7A169F4B11CD03A3D35546A4E4E2FF79DB6173F3A762B22EBE4BE5B49DD4951A6BC27D5EDD8486E2105561B9BE23F1826BC0579A482AFFD99508E09F17A20419F56A31AEFADCBF816706BC1B47420A7C66A19AF1A725D691CED949F9135404B35237E6B07A037F87F4515B7F1FD5B2A7B3B562ED121A12C1B4BF9E408A0221922B10B78B9D75B81381853BBF734BBE33E12602D4191BCD47B57FA20803F1D75FD4D5A077D50DD537A6B38AB09A1A3C1B30845A0D92AA38BD1B7D1F1AA1AC9FE9CD0A0DE23BD1943A99793D18FC08BD9D7744B62D460263F879087A996FC2868675FE43F7026C6C3C93187C629AF58038F61E3072D8A4B42ABFD1639C5F2289E0A974FFBBC67FD2BAC657BC3C582664A6AD8B940E8F8596FDB8B6429C1A1F06AB1249C9A03F271F66550503E9613277D38DC63031F21AA7C8C9B2D91D6F6B7C036BAB18B5FC8900E4679992DE4BAA2CF202787D521D1545AF4A090E8E17F7E8012C104791D2F6025A41C543F9D85C1DD3EE5757CA2445697075C87D0334FD0F5C9AA8EAFF4A8A4AAEDBE7F2C80151066C7A0F05B3A6B6E5EFD1DE7FE9C53421A00BA9917C732D4735ECEE42CDE994FA6DE2C171207B2A4ADE76EC4411C2171F7C7A0E05C37E3BE842F224A3F8FF6A55DC806FC3F7904147910B6D473A91EE3B -20240903003705 2 6 100 8191 2 E90C219E279F374756F460D972C0503655CE6346FD0F611E8808CD4ADDDCE308981860661516592055313E99D7CC26BBCEE76FDE697801AA2827379287137910127F9107DEA68C3FAD7DBC9DADC15102DA2C4D890186E4279C8590E5D3F90E1B93EAFA540386086C4B55AE83AE5C7EB5FD9478B16F1143BB97202E24CE3FEE6E314B308A8CBC1F2938D7013654B6A5D141D4422375EDDEA2C2011231C5C83F318FCBE6A8FBEA20D8E9C2618D45DEBE36611557447900B4B8248A25E4D523C3D9DCAB1F1C1A7CE5EFD7FA4B1BF34486F5737F61A94C20D9268CCC52785FBF8CE06D605997A8DE54E76D7F566582C8C064E244151FD43E7B97368891F274FF1D1EBB9627BEBE9B9B202E656445873198D32286D9D8F9F0387D3ABC6C0C74C9FEC8FA935C5F43287AA191591A6ADF80EBD6EB5B58C2524BE2E2E3000A25345A7D082B7AD136133E87B4BFED4C20EE58055EDA6E9D2E2F15E299D14E11919F2C3029CE1C818D5D30EA68D0458F3B1AB30923F55F84A3BCF14137B547D56CA353F3BB7EC6F22705CC0B14FBD8D7E869325B688AA759C30FAFC74A01567BD785F4ED1F0ED1B7B82F00467A687EC3BB12A246B620B2FE0B9783C222F999CCB7CEF6FA2E3FE4DE652FC0C4B21FC4DF2CEF7981F644FB2158B208C71C68C6974D4D1090C830379707BC30C7748487EB922A4B40CB0FE33B5B4A8E22354ADB2020315D043706D608B1213A2974ED5CC6EA8A520E3147667DD81F4294313AF935C528C82B659B7A169F4B11CD03A3D35546A4E4E2FF79DB6173F3A762B22EBE4BE5B49DD4951A6BC27D5EDD8486E2105561B9BE23F1826BC0579A482AFFD99508E09F17A20419F56A31AEFADCBF816706BC1B47420A7C66A19AF1A725D691CED949F9135404B35237E6B07A037F87F4515B7F1FD5B2A7B3B562ED121A12C1B4BF9E408A0221922B10B78B9D75B81381853BBF734BBE33E12602D4191BCD47B57FA20803F1D75FD4D5A077D50DD537A6B38AB09A1A3C1B30845A0D92AA38BD1B7D1F1AA1AC9FE9CD0A0DE23BD1943A99793D18FC08BD9D7744B62D460263F879087A996FC2868675FE43F7026C6C3C93187C629AF58038F61E3072D8A4B42ABFD1639C5F2289E0A974FFBBC67FD2BAC657BC3C582664A6AD8B940E8F8596FDB8B6429C1A1F06AB1249C9A03F271F66550503E9613277D38DC63031F21AA7C8C9B2D91D6F6B7C036BAB18B5FC8900E4679992DE4BAA2CF202787D521D1545AF4A090E8E17F7E8012C104791D2F6025A41C543F9D85C1DD3EE5757CA2445697075C87D0334FD0F5C9AA8EAFF4A8A4AAEDBE7F2C80151066C7A0F05B3A6B6E5EFD1DE7FE9C53421A00BA9917C732D4735ECEE42CDE994FA6DE2C171207B2A4ADE76EC4411C2171F7C7A0E05C37E3BE842F224A3F8FF6A55DC806FC3F7904147910B6D473B9B08CB -20240903010010 2 6 100 8191 2 E90C219E279F374756F460D972C0503655CE6346FD0F611E8808CD4ADDDCE308981860661516592055313E99D7CC26BBCEE76FDE697801AA2827379287137910127F9107DEA68C3FAD7DBC9DADC15102DA2C4D890186E4279C8590E5D3F90E1B93EAFA540386086C4B55AE83AE5C7EB5FD9478B16F1143BB97202E24CE3FEE6E314B308A8CBC1F2938D7013654B6A5D141D4422375EDDEA2C2011231C5C83F318FCBE6A8FBEA20D8E9C2618D45DEBE36611557447900B4B8248A25E4D523C3D9DCAB1F1C1A7CE5EFD7FA4B1BF34486F5737F61A94C20D9268CCC52785FBF8CE06D605997A8DE54E76D7F566582C8C064E244151FD43E7B97368891F274FF1D1EBB9627BEBE9B9B202E656445873198D32286D9D8F9F0387D3ABC6C0C74C9FEC8FA935C5F43287AA191591A6ADF80EBD6EB5B58C2524BE2E2E3000A25345A7D082B7AD136133E87B4BFED4C20EE58055EDA6E9D2E2F15E299D14E11919F2C3029CE1C818D5D30EA68D0458F3B1AB30923F55F84A3BCF14137B547D56CA353F3BB7EC6F22705CC0B14FBD8D7E869325B688AA759C30FAFC74A01567BD785F4ED1F0ED1B7B82F00467A687EC3BB12A246B620B2FE0B9783C222F999CCB7CEF6FA2E3FE4DE652FC0C4B21FC4DF2CEF7981F644FB2158B208C71C68C6974D4D1090C830379707BC30C7748487EB922A4B40CB0FE33B5B4A8E22354ADB2020315D043706D608B1213A2974ED5CC6EA8A520E3147667DD81F4294313AF935C528C82B659B7A169F4B11CD03A3D35546A4E4E2FF79DB6173F3A762B22EBE4BE5B49DD4951A6BC27D5EDD8486E2105561B9BE23F1826BC0579A482AFFD99508E09F17A20419F56A31AEFADCBF816706BC1B47420A7C66A19AF1A725D691CED949F9135404B35237E6B07A037F87F4515B7F1FD5B2A7B3B562ED121A12C1B4BF9E408A0221922B10B78B9D75B81381853BBF734BBE33E12602D4191BCD47B57FA20803F1D75FD4D5A077D50DD537A6B38AB09A1A3C1B30845A0D92AA38BD1B7D1F1AA1AC9FE9CD0A0DE23BD1943A99793D18FC08BD9D7744B62D460263F879087A996FC2868675FE43F7026C6C3C93187C629AF58038F61E3072D8A4B42ABFD1639C5F2289E0A974FFBBC67FD2BAC657BC3C582664A6AD8B940E8F8596FDB8B6429C1A1F06AB1249C9A03F271F66550503E9613277D38DC63031F21AA7C8C9B2D91D6F6B7C036BAB18B5FC8900E4679992DE4BAA2CF202787D521D1545AF4A090E8E17F7E8012C104791D2F6025A41C543F9D85C1DD3EE5757CA2445697075C87D0334FD0F5C9AA8EAFF4A8A4AAEDBE7F2C80151066C7A0F05B3A6B6E5EFD1DE7FE9C53421A00BA9917C732D4735ECEE42CDE994FA6DE2C171207B2A4ADE76EC4411C2171F7C7A0E05C37E3BE842F224A3F8FF6A55DC806FC3F7904147910B6D473CDEB7B3 -20240903010348 2 6 100 8191 5 E90C219E279F374756F460D972C0503655CE6346FD0F611E8808CD4ADDDCE308981860661516592055313E99D7CC26BBCEE76FDE697801AA2827379287137910127F9107DEA68C3FAD7DBC9DADC15102DA2C4D890186E4279C8590E5D3F90E1B93EAFA540386086C4B55AE83AE5C7EB5FD9478B16F1143BB97202E24CE3FEE6E314B308A8CBC1F2938D7013654B6A5D141D4422375EDDEA2C2011231C5C83F318FCBE6A8FBEA20D8E9C2618D45DEBE36611557447900B4B8248A25E4D523C3D9DCAB1F1C1A7CE5EFD7FA4B1BF34486F5737F61A94C20D9268CCC52785FBF8CE06D605997A8DE54E76D7F566582C8C064E244151FD43E7B97368891F274FF1D1EBB9627BEBE9B9B202E656445873198D32286D9D8F9F0387D3ABC6C0C74C9FEC8FA935C5F43287AA191591A6ADF80EBD6EB5B58C2524BE2E2E3000A25345A7D082B7AD136133E87B4BFED4C20EE58055EDA6E9D2E2F15E299D14E11919F2C3029CE1C818D5D30EA68D0458F3B1AB30923F55F84A3BCF14137B547D56CA353F3BB7EC6F22705CC0B14FBD8D7E869325B688AA759C30FAFC74A01567BD785F4ED1F0ED1B7B82F00467A687EC3BB12A246B620B2FE0B9783C222F999CCB7CEF6FA2E3FE4DE652FC0C4B21FC4DF2CEF7981F644FB2158B208C71C68C6974D4D1090C830379707BC30C7748487EB922A4B40CB0FE33B5B4A8E22354ADB2020315D043706D608B1213A2974ED5CC6EA8A520E3147667DD81F4294313AF935C528C82B659B7A169F4B11CD03A3D35546A4E4E2FF79DB6173F3A762B22EBE4BE5B49DD4951A6BC27D5EDD8486E2105561B9BE23F1826BC0579A482AFFD99508E09F17A20419F56A31AEFADCBF816706BC1B47420A7C66A19AF1A725D691CED949F9135404B35237E6B07A037F87F4515B7F1FD5B2A7B3B562ED121A12C1B4BF9E408A0221922B10B78B9D75B81381853BBF734BBE33E12602D4191BCD47B57FA20803F1D75FD4D5A077D50DD537A6B38AB09A1A3C1B30845A0D92AA38BD1B7D1F1AA1AC9FE9CD0A0DE23BD1943A99793D18FC08BD9D7744B62D460263F879087A996FC2868675FE43F7026C6C3C93187C629AF58038F61E3072D8A4B42ABFD1639C5F2289E0A974FFBBC67FD2BAC657BC3C582664A6AD8B940E8F8596FDB8B6429C1A1F06AB1249C9A03F271F66550503E9613277D38DC63031F21AA7C8C9B2D91D6F6B7C036BAB18B5FC8900E4679992DE4BAA2CF202787D521D1545AF4A090E8E17F7E8012C104791D2F6025A41C543F9D85C1DD3EE5757CA2445697075C87D0334FD0F5C9AA8EAFF4A8A4AAEDBE7F2C80151066C7A0F05B3A6B6E5EFD1DE7FE9C53421A00BA9917C732D4735ECEE42CDE994FA6DE2C171207B2A4ADE76EC4411C2171F7C7A0E05C37E3BE842F224A3F8FF6A55DC806FC3F7904147910B6D473D0B3A67 -20240903034119 2 6 100 8191 2 E90C219E279F374756F460D972C0503655CE6346FD0F611E8808CD4ADDDCE308981860661516592055313E99D7CC26BBCEE76FDE697801AA2827379287137910127F9107DEA68C3FAD7DBC9DADC15102DA2C4D890186E4279C8590E5D3F90E1B93EAFA540386086C4B55AE83AE5C7EB5FD9478B16F1143BB97202E24CE3FEE6E314B308A8CBC1F2938D7013654B6A5D141D4422375EDDEA2C2011231C5C83F318FCBE6A8FBEA20D8E9C2618D45DEBE36611557447900B4B8248A25E4D523C3D9DCAB1F1C1A7CE5EFD7FA4B1BF34486F5737F61A94C20D9268CCC52785FBF8CE06D605997A8DE54E76D7F566582C8C064E244151FD43E7B97368891F274FF1D1EBB9627BEBE9B9B202E656445873198D32286D9D8F9F0387D3ABC6C0C74C9FEC8FA935C5F43287AA191591A6ADF80EBD6EB5B58C2524BE2E2E3000A25345A7D082B7AD136133E87B4BFED4C20EE58055EDA6E9D2E2F15E299D14E11919F2C3029CE1C818D5D30EA68D0458F3B1AB30923F55F84A3BCF14137B547D56CA353F3BB7EC6F22705CC0B14FBD8D7E869325B688AA759C30FAFC74A01567BD785F4ED1F0ED1B7B82F00467A687EC3BB12A246B620B2FE0B9783C222F999CCB7CEF6FA2E3FE4DE652FC0C4B21FC4DF2CEF7981F644FB2158B208C71C68C6974D4D1090C830379707BC30C7748487EB922A4B40CB0FE33B5B4A8E22354ADB2020315D043706D608B1213A2974ED5CC6EA8A520E3147667DD81F4294313AF935C528C82B659B7A169F4B11CD03A3D35546A4E4E2FF79DB6173F3A762B22EBE4BE5B49DD4951A6BC27D5EDD8486E2105561B9BE23F1826BC0579A482AFFD99508E09F17A20419F56A31AEFADCBF816706BC1B47420A7C66A19AF1A725D691CED949F9135404B35237E6B07A037F87F4515B7F1FD5B2A7B3B562ED121A12C1B4BF9E408A0221922B10B78B9D75B81381853BBF734BBE33E12602D4191BCD47B57FA20803F1D75FD4D5A077D50DD537A6B38AB09A1A3C1B30845A0D92AA38BD1B7D1F1AA1AC9FE9CD0A0DE23BD1943A99793D18FC08BD9D7744B62D460263F879087A996FC2868675FE43F7026C6C3C93187C629AF58038F61E3072D8A4B42ABFD1639C5F2289E0A974FFBBC67FD2BAC657BC3C582664A6AD8B940E8F8596FDB8B6429C1A1F06AB1249C9A03F271F66550503E9613277D38DC63031F21AA7C8C9B2D91D6F6B7C036BAB18B5FC8900E4679992DE4BAA2CF202787D521D1545AF4A090E8E17F7E8012C104791D2F6025A41C543F9D85C1DD3EE5757CA2445697075C87D0334FD0F5C9AA8EAFF4A8A4AAEDBE7F2C80151066C7A0F05B3A6B6E5EFD1DE7FE9C53421A00BA9917C732D4735ECEE42CDE994FA6DE2C171207B2A4ADE76EC4411C2171F7C7A0E05C37E3BE842F224A3F8FF6A55DC806FC3F7904147910B6D474614297B -20240903040728 2 6 100 8191 2 E90C219E279F374756F460D972C0503655CE6346FD0F611E8808CD4ADDDCE308981860661516592055313E99D7CC26BBCEE76FDE697801AA2827379287137910127F9107DEA68C3FAD7DBC9DADC15102DA2C4D890186E4279C8590E5D3F90E1B93EAFA540386086C4B55AE83AE5C7EB5FD9478B16F1143BB97202E24CE3FEE6E314B308A8CBC1F2938D7013654B6A5D141D4422375EDDEA2C2011231C5C83F318FCBE6A8FBEA20D8E9C2618D45DEBE36611557447900B4B8248A25E4D523C3D9DCAB1F1C1A7CE5EFD7FA4B1BF34486F5737F61A94C20D9268CCC52785FBF8CE06D605997A8DE54E76D7F566582C8C064E244151FD43E7B97368891F274FF1D1EBB9627BEBE9B9B202E656445873198D32286D9D8F9F0387D3ABC6C0C74C9FEC8FA935C5F43287AA191591A6ADF80EBD6EB5B58C2524BE2E2E3000A25345A7D082B7AD136133E87B4BFED4C20EE58055EDA6E9D2E2F15E299D14E11919F2C3029CE1C818D5D30EA68D0458F3B1AB30923F55F84A3BCF14137B547D56CA353F3BB7EC6F22705CC0B14FBD8D7E869325B688AA759C30FAFC74A01567BD785F4ED1F0ED1B7B82F00467A687EC3BB12A246B620B2FE0B9783C222F999CCB7CEF6FA2E3FE4DE652FC0C4B21FC4DF2CEF7981F644FB2158B208C71C68C6974D4D1090C830379707BC30C7748487EB922A4B40CB0FE33B5B4A8E22354ADB2020315D043706D608B1213A2974ED5CC6EA8A520E3147667DD81F4294313AF935C528C82B659B7A169F4B11CD03A3D35546A4E4E2FF79DB6173F3A762B22EBE4BE5B49DD4951A6BC27D5EDD8486E2105561B9BE23F1826BC0579A482AFFD99508E09F17A20419F56A31AEFADCBF816706BC1B47420A7C66A19AF1A725D691CED949F9135404B35237E6B07A037F87F4515B7F1FD5B2A7B3B562ED121A12C1B4BF9E408A0221922B10B78B9D75B81381853BBF734BBE33E12602D4191BCD47B57FA20803F1D75FD4D5A077D50DD537A6B38AB09A1A3C1B30845A0D92AA38BD1B7D1F1AA1AC9FE9CD0A0DE23BD1943A99793D18FC08BD9D7744B62D460263F879087A996FC2868675FE43F7026C6C3C93187C629AF58038F61E3072D8A4B42ABFD1639C5F2289E0A974FFBBC67FD2BAC657BC3C582664A6AD8B940E8F8596FDB8B6429C1A1F06AB1249C9A03F271F66550503E9613277D38DC63031F21AA7C8C9B2D91D6F6B7C036BAB18B5FC8900E4679992DE4BAA2CF202787D521D1545AF4A090E8E17F7E8012C104791D2F6025A41C543F9D85C1DD3EE5757CA2445697075C87D0334FD0F5C9AA8EAFF4A8A4AAEDBE7F2C80151066C7A0F05B3A6B6E5EFD1DE7FE9C53421A00BA9917C732D4735ECEE42CDE994FA6DE2C171207B2A4ADE76EC4411C2171F7C7A0E05C37E3BE842F224A3F8FF6A55DC806FC3F7904147910B6D4747910563 -20240903051146 2 6 100 8191 2 E90C219E279F374756F460D972C0503655CE6346FD0F611E8808CD4ADDDCE308981860661516592055313E99D7CC26BBCEE76FDE697801AA2827379287137910127F9107DEA68C3FAD7DBC9DADC15102DA2C4D890186E4279C8590E5D3F90E1B93EAFA540386086C4B55AE83AE5C7EB5FD9478B16F1143BB97202E24CE3FEE6E314B308A8CBC1F2938D7013654B6A5D141D4422375EDDEA2C2011231C5C83F318FCBE6A8FBEA20D8E9C2618D45DEBE36611557447900B4B8248A25E4D523C3D9DCAB1F1C1A7CE5EFD7FA4B1BF34486F5737F61A94C20D9268CCC52785FBF8CE06D605997A8DE54E76D7F566582C8C064E244151FD43E7B97368891F274FF1D1EBB9627BEBE9B9B202E656445873198D32286D9D8F9F0387D3ABC6C0C74C9FEC8FA935C5F43287AA191591A6ADF80EBD6EB5B58C2524BE2E2E3000A25345A7D082B7AD136133E87B4BFED4C20EE58055EDA6E9D2E2F15E299D14E11919F2C3029CE1C818D5D30EA68D0458F3B1AB30923F55F84A3BCF14137B547D56CA353F3BB7EC6F22705CC0B14FBD8D7E869325B688AA759C30FAFC74A01567BD785F4ED1F0ED1B7B82F00467A687EC3BB12A246B620B2FE0B9783C222F999CCB7CEF6FA2E3FE4DE652FC0C4B21FC4DF2CEF7981F644FB2158B208C71C68C6974D4D1090C830379707BC30C7748487EB922A4B40CB0FE33B5B4A8E22354ADB2020315D043706D608B1213A2974ED5CC6EA8A520E3147667DD81F4294313AF935C528C82B659B7A169F4B11CD03A3D35546A4E4E2FF79DB6173F3A762B22EBE4BE5B49DD4951A6BC27D5EDD8486E2105561B9BE23F1826BC0579A482AFFD99508E09F17A20419F56A31AEFADCBF816706BC1B47420A7C66A19AF1A725D691CED949F9135404B35237E6B07A037F87F4515B7F1FD5B2A7B3B562ED121A12C1B4BF9E408A0221922B10B78B9D75B81381853BBF734BBE33E12602D4191BCD47B57FA20803F1D75FD4D5A077D50DD537A6B38AB09A1A3C1B30845A0D92AA38BD1B7D1F1AA1AC9FE9CD0A0DE23BD1943A99793D18FC08BD9D7744B62D460263F879087A996FC2868675FE43F7026C6C3C93187C629AF58038F61E3072D8A4B42ABFD1639C5F2289E0A974FFBBC67FD2BAC657BC3C582664A6AD8B940E8F8596FDB8B6429C1A1F06AB1249C9A03F271F66550503E9613277D38DC63031F21AA7C8C9B2D91D6F6B7C036BAB18B5FC8900E4679992DE4BAA2CF202787D521D1545AF4A090E8E17F7E8012C104791D2F6025A41C543F9D85C1DD3EE5757CA2445697075C87D0334FD0F5C9AA8EAFF4A8A4AAEDBE7F2C80151066C7A0F05B3A6B6E5EFD1DE7FE9C53421A00BA9917C732D4735ECEE42CDE994FA6DE2C171207B2A4ADE76EC4411C2171F7C7A0E05C37E3BE842F224A3F8FF6A55DC806FC3F7904147910B6D474B45E3DB -20240903064823 2 6 100 8191 2 E90C219E279F374756F460D972C0503655CE6346FD0F611E8808CD4ADDDCE308981860661516592055313E99D7CC26BBCEE76FDE697801AA2827379287137910127F9107DEA68C3FAD7DBC9DADC15102DA2C4D890186E4279C8590E5D3F90E1B93EAFA540386086C4B55AE83AE5C7EB5FD9478B16F1143BB97202E24CE3FEE6E314B308A8CBC1F2938D7013654B6A5D141D4422375EDDEA2C2011231C5C83F318FCBE6A8FBEA20D8E9C2618D45DEBE36611557447900B4B8248A25E4D523C3D9DCAB1F1C1A7CE5EFD7FA4B1BF34486F5737F61A94C20D9268CCC52785FBF8CE06D605997A8DE54E76D7F566582C8C064E244151FD43E7B97368891F274FF1D1EBB9627BEBE9B9B202E656445873198D32286D9D8F9F0387D3ABC6C0C74C9FEC8FA935C5F43287AA191591A6ADF80EBD6EB5B58C2524BE2E2E3000A25345A7D082B7AD136133E87B4BFED4C20EE58055EDA6E9D2E2F15E299D14E11919F2C3029CE1C818D5D30EA68D0458F3B1AB30923F55F84A3BCF14137B547D56CA353F3BB7EC6F22705CC0B14FBD8D7E869325B688AA759C30FAFC74A01567BD785F4ED1F0ED1B7B82F00467A687EC3BB12A246B620B2FE0B9783C222F999CCB7CEF6FA2E3FE4DE652FC0C4B21FC4DF2CEF7981F644FB2158B208C71C68C6974D4D1090C830379707BC30C7748487EB922A4B40CB0FE33B5B4A8E22354ADB2020315D043706D608B1213A2974ED5CC6EA8A520E3147667DD81F4294313AF935C528C82B659B7A169F4B11CD03A3D35546A4E4E2FF79DB6173F3A762B22EBE4BE5B49DD4951A6BC27D5EDD8486E2105561B9BE23F1826BC0579A482AFFD99508E09F17A20419F56A31AEFADCBF816706BC1B47420A7C66A19AF1A725D691CED949F9135404B35237E6B07A037F87F4515B7F1FD5B2A7B3B562ED121A12C1B4BF9E408A0221922B10B78B9D75B81381853BBF734BBE33E12602D4191BCD47B57FA20803F1D75FD4D5A077D50DD537A6B38AB09A1A3C1B30845A0D92AA38BD1B7D1F1AA1AC9FE9CD0A0DE23BD1943A99793D18FC08BD9D7744B62D460263F879087A996FC2868675FE43F7026C6C3C93187C629AF58038F61E3072D8A4B42ABFD1639C5F2289E0A974FFBBC67FD2BAC657BC3C582664A6AD8B940E8F8596FDB8B6429C1A1F06AB1249C9A03F271F66550503E9613277D38DC63031F21AA7C8C9B2D91D6F6B7C036BAB18B5FC8900E4679992DE4BAA2CF202787D521D1545AF4A090E8E17F7E8012C104791D2F6025A41C543F9D85C1DD3EE5757CA2445697075C87D0334FD0F5C9AA8EAFF4A8A4AAEDBE7F2C80151066C7A0F05B3A6B6E5EFD1DE7FE9C53421A00BA9917C732D4735ECEE42CDE994FA6DE2C171207B2A4ADE76EC4411C2171F7C7A0E05C37E3BE842F224A3F8FF6A55DC806FC3F7904147910B6D4750BE2633 -20240903064907 2 6 100 8191 2 E90C219E279F374756F460D972C0503655CE6346FD0F611E8808CD4ADDDCE308981860661516592055313E99D7CC26BBCEE76FDE697801AA2827379287137910127F9107DEA68C3FAD7DBC9DADC15102DA2C4D890186E4279C8590E5D3F90E1B93EAFA540386086C4B55AE83AE5C7EB5FD9478B16F1143BB97202E24CE3FEE6E314B308A8CBC1F2938D7013654B6A5D141D4422375EDDEA2C2011231C5C83F318FCBE6A8FBEA20D8E9C2618D45DEBE36611557447900B4B8248A25E4D523C3D9DCAB1F1C1A7CE5EFD7FA4B1BF34486F5737F61A94C20D9268CCC52785FBF8CE06D605997A8DE54E76D7F566582C8C064E244151FD43E7B97368891F274FF1D1EBB9627BEBE9B9B202E656445873198D32286D9D8F9F0387D3ABC6C0C74C9FEC8FA935C5F43287AA191591A6ADF80EBD6EB5B58C2524BE2E2E3000A25345A7D082B7AD136133E87B4BFED4C20EE58055EDA6E9D2E2F15E299D14E11919F2C3029CE1C818D5D30EA68D0458F3B1AB30923F55F84A3BCF14137B547D56CA353F3BB7EC6F22705CC0B14FBD8D7E869325B688AA759C30FAFC74A01567BD785F4ED1F0ED1B7B82F00467A687EC3BB12A246B620B2FE0B9783C222F999CCB7CEF6FA2E3FE4DE652FC0C4B21FC4DF2CEF7981F644FB2158B208C71C68C6974D4D1090C830379707BC30C7748487EB922A4B40CB0FE33B5B4A8E22354ADB2020315D043706D608B1213A2974ED5CC6EA8A520E3147667DD81F4294313AF935C528C82B659B7A169F4B11CD03A3D35546A4E4E2FF79DB6173F3A762B22EBE4BE5B49DD4951A6BC27D5EDD8486E2105561B9BE23F1826BC0579A482AFFD99508E09F17A20419F56A31AEFADCBF816706BC1B47420A7C66A19AF1A725D691CED949F9135404B35237E6B07A037F87F4515B7F1FD5B2A7B3B562ED121A12C1B4BF9E408A0221922B10B78B9D75B81381853BBF734BBE33E12602D4191BCD47B57FA20803F1D75FD4D5A077D50DD537A6B38AB09A1A3C1B30845A0D92AA38BD1B7D1F1AA1AC9FE9CD0A0DE23BD1943A99793D18FC08BD9D7744B62D460263F879087A996FC2868675FE43F7026C6C3C93187C629AF58038F61E3072D8A4B42ABFD1639C5F2289E0A974FFBBC67FD2BAC657BC3C582664A6AD8B940E8F8596FDB8B6429C1A1F06AB1249C9A03F271F66550503E9613277D38DC63031F21AA7C8C9B2D91D6F6B7C036BAB18B5FC8900E4679992DE4BAA2CF202787D521D1545AF4A090E8E17F7E8012C104791D2F6025A41C543F9D85C1DD3EE5757CA2445697075C87D0334FD0F5C9AA8EAFF4A8A4AAEDBE7F2C80151066C7A0F05B3A6B6E5EFD1DE7FE9C53421A00BA9917C732D4735ECEE42CDE994FA6DE2C171207B2A4ADE76EC4411C2171F7C7A0E05C37E3BE842F224A3F8FF6A55DC806FC3F7904147910B6D4750C0835B -20240903101831 2 6 100 8191 2 E90C219E279F374756F460D972C0503655CE6346FD0F611E8808CD4ADDDCE308981860661516592055313E99D7CC26BBCEE76FDE697801AA2827379287137910127F9107DEA68C3FAD7DBC9DADC15102DA2C4D890186E4279C8590E5D3F90E1B93EAFA540386086C4B55AE83AE5C7EB5FD9478B16F1143BB97202E24CE3FEE6E314B308A8CBC1F2938D7013654B6A5D141D4422375EDDEA2C2011231C5C83F318FCBE6A8FBEA20D8E9C2618D45DEBE36611557447900B4B8248A25E4D523C3D9DCAB1F1C1A7CE5EFD7FA4B1BF34486F5737F61A94C20D9268CCC52785FBF8CE06D605997A8DE54E76D7F566582C8C064E244151FD43E7B97368891F274FF1D1EBB9627BEBE9B9B202E656445873198D32286D9D8F9F0387D3ABC6C0C74C9FEC8FA935C5F43287AA191591A6ADF80EBD6EB5B58C2524BE2E2E3000A25345A7D082B7AD136133E87B4BFED4C20EE58055EDA6E9D2E2F15E299D14E11919F2C3029CE1C818D5D30EA68D0458F3B1AB30923F55F84A3BCF14137B547D56CA353F3BB7EC6F22705CC0B14FBD8D7E869325B688AA759C30FAFC74A01567BD785F4ED1F0ED1B7B82F00467A687EC3BB12A246B620B2FE0B9783C222F999CCB7CEF6FA2E3FE4DE652FC0C4B21FC4DF2CEF7981F644FB2158B208C71C68C6974D4D1090C830379707BC30C7748487EB922A4B40CB0FE33B5B4A8E22354ADB2020315D043706D608B1213A2974ED5CC6EA8A520E3147667DD81F4294313AF935C528C82B659B7A169F4B11CD03A3D35546A4E4E2FF79DB6173F3A762B22EBE4BE5B49DD4951A6BC27D5EDD8486E2105561B9BE23F1826BC0579A482AFFD99508E09F17A20419F56A31AEFADCBF816706BC1B47420A7C66A19AF1A725D691CED949F9135404B35237E6B07A037F87F4515B7F1FD5B2A7B3B562ED121A12C1B4BF9E408A0221922B10B78B9D75B81381853BBF734BBE33E12602D4191BCD47B57FA20803F1D75FD4D5A077D50DD537A6B38AB09A1A3C1B30845A0D92AA38BD1B7D1F1AA1AC9FE9CD0A0DE23BD1943A99793D18FC08BD9D7744B62D460263F879087A996FC2868675FE43F7026C6C3C93187C629AF58038F61E3072D8A4B42ABFD1639C5F2289E0A974FFBBC67FD2BAC657BC3C582664A6AD8B940E8F8596FDB8B6429C1A1F06AB1249C9A03F271F66550503E9613277D38DC63031F21AA7C8C9B2D91D6F6B7C036BAB18B5FC8900E4679992DE4BAA2CF202787D521D1545AF4A090E8E17F7E8012C104791D2F6025A41C543F9D85C1DD3EE5757CA2445697075C87D0334FD0F5C9AA8EAFF4A8A4AAEDBE7F2C80151066C7A0F05B3A6B6E5EFD1DE7FE9C53421A00BA9917C732D4735ECEE42CDE994FA6DE2C171207B2A4ADE76EC4411C2171F7C7A0E05C37E3BE842F224A3F8FF6A55DC806FC3F7904147910B6D475C6B64DB -20240903113322 2 6 100 8191 5 E90C219E279F374756F460D972C0503655CE6346FD0F611E8808CD4ADDDCE308981860661516592055313E99D7CC26BBCEE76FDE697801AA2827379287137910127F9107DEA68C3FAD7DBC9DADC15102DA2C4D890186E4279C8590E5D3F90E1B93EAFA540386086C4B55AE83AE5C7EB5FD9478B16F1143BB97202E24CE3FEE6E314B308A8CBC1F2938D7013654B6A5D141D4422375EDDEA2C2011231C5C83F318FCBE6A8FBEA20D8E9C2618D45DEBE36611557447900B4B8248A25E4D523C3D9DCAB1F1C1A7CE5EFD7FA4B1BF34486F5737F61A94C20D9268CCC52785FBF8CE06D605997A8DE54E76D7F566582C8C064E244151FD43E7B97368891F274FF1D1EBB9627BEBE9B9B202E656445873198D32286D9D8F9F0387D3ABC6C0C74C9FEC8FA935C5F43287AA191591A6ADF80EBD6EB5B58C2524BE2E2E3000A25345A7D082B7AD136133E87B4BFED4C20EE58055EDA6E9D2E2F15E299D14E11919F2C3029CE1C818D5D30EA68D0458F3B1AB30923F55F84A3BCF14137B547D56CA353F3BB7EC6F22705CC0B14FBD8D7E869325B688AA759C30FAFC74A01567BD785F4ED1F0ED1B7B82F00467A687EC3BB12A246B620B2FE0B9783C222F999CCB7CEF6FA2E3FE4DE652FC0C4B21FC4DF2CEF7981F644FB2158B208C71C68C6974D4D1090C830379707BC30C7748487EB922A4B40CB0FE33B5B4A8E22354ADB2020315D043706D608B1213A2974ED5CC6EA8A520E3147667DD81F4294313AF935C528C82B659B7A169F4B11CD03A3D35546A4E4E2FF79DB6173F3A762B22EBE4BE5B49DD4951A6BC27D5EDD8486E2105561B9BE23F1826BC0579A482AFFD99508E09F17A20419F56A31AEFADCBF816706BC1B47420A7C66A19AF1A725D691CED949F9135404B35237E6B07A037F87F4515B7F1FD5B2A7B3B562ED121A12C1B4BF9E408A0221922B10B78B9D75B81381853BBF734BBE33E12602D4191BCD47B57FA20803F1D75FD4D5A077D50DD537A6B38AB09A1A3C1B30845A0D92AA38BD1B7D1F1AA1AC9FE9CD0A0DE23BD1943A99793D18FC08BD9D7744B62D460263F879087A996FC2868675FE43F7026C6C3C93187C629AF58038F61E3072D8A4B42ABFD1639C5F2289E0A974FFBBC67FD2BAC657BC3C582664A6AD8B940E8F8596FDB8B6429C1A1F06AB1249C9A03F271F66550503E9613277D38DC63031F21AA7C8C9B2D91D6F6B7C036BAB18B5FC8900E4679992DE4BAA2CF202787D521D1545AF4A090E8E17F7E8012C104791D2F6025A41C543F9D85C1DD3EE5757CA2445697075C87D0334FD0F5C9AA8EAFF4A8A4AAEDBE7F2C80151066C7A0F05B3A6B6E5EFD1DE7FE9C53421A00BA9917C732D4735ECEE42CDE994FA6DE2C171207B2A4ADE76EC4411C2171F7C7A0E05C37E3BE842F224A3F8FF6A55DC806FC3F7904147910B6D4760A047BF -20240903122505 2 6 100 8191 2 E90C219E279F374756F460D972C0503655CE6346FD0F611E8808CD4ADDDCE308981860661516592055313E99D7CC26BBCEE76FDE697801AA2827379287137910127F9107DEA68C3FAD7DBC9DADC15102DA2C4D890186E4279C8590E5D3F90E1B93EAFA540386086C4B55AE83AE5C7EB5FD9478B16F1143BB97202E24CE3FEE6E314B308A8CBC1F2938D7013654B6A5D141D4422375EDDEA2C2011231C5C83F318FCBE6A8FBEA20D8E9C2618D45DEBE36611557447900B4B8248A25E4D523C3D9DCAB1F1C1A7CE5EFD7FA4B1BF34486F5737F61A94C20D9268CCC52785FBF8CE06D605997A8DE54E76D7F566582C8C064E244151FD43E7B97368891F274FF1D1EBB9627BEBE9B9B202E656445873198D32286D9D8F9F0387D3ABC6C0C74C9FEC8FA935C5F43287AA191591A6ADF80EBD6EB5B58C2524BE2E2E3000A25345A7D082B7AD136133E87B4BFED4C20EE58055EDA6E9D2E2F15E299D14E11919F2C3029CE1C818D5D30EA68D0458F3B1AB30923F55F84A3BCF14137B547D56CA353F3BB7EC6F22705CC0B14FBD8D7E869325B688AA759C30FAFC74A01567BD785F4ED1F0ED1B7B82F00467A687EC3BB12A246B620B2FE0B9783C222F999CCB7CEF6FA2E3FE4DE652FC0C4B21FC4DF2CEF7981F644FB2158B208C71C68C6974D4D1090C830379707BC30C7748487EB922A4B40CB0FE33B5B4A8E22354ADB2020315D043706D608B1213A2974ED5CC6EA8A520E3147667DD81F4294313AF935C528C82B659B7A169F4B11CD03A3D35546A4E4E2FF79DB6173F3A762B22EBE4BE5B49DD4951A6BC27D5EDD8486E2105561B9BE23F1826BC0579A482AFFD99508E09F17A20419F56A31AEFADCBF816706BC1B47420A7C66A19AF1A725D691CED949F9135404B35237E6B07A037F87F4515B7F1FD5B2A7B3B562ED121A12C1B4BF9E408A0221922B10B78B9D75B81381853BBF734BBE33E12602D4191BCD47B57FA20803F1D75FD4D5A077D50DD537A6B38AB09A1A3C1B30845A0D92AA38BD1B7D1F1AA1AC9FE9CD0A0DE23BD1943A99793D18FC08BD9D7744B62D460263F879087A996FC2868675FE43F7026C6C3C93187C629AF58038F61E3072D8A4B42ABFD1639C5F2289E0A974FFBBC67FD2BAC657BC3C582664A6AD8B940E8F8596FDB8B6429C1A1F06AB1249C9A03F271F66550503E9613277D38DC63031F21AA7C8C9B2D91D6F6B7C036BAB18B5FC8900E4679992DE4BAA2CF202787D521D1545AF4A090E8E17F7E8012C104791D2F6025A41C543F9D85C1DD3EE5757CA2445697075C87D0334FD0F5C9AA8EAFF4A8A4AAEDBE7F2C80151066C7A0F05B3A6B6E5EFD1DE7FE9C53421A00BA9917C732D4735ECEE42CDE994FA6DE2C171207B2A4ADE76EC4411C2171F7C7A0E05C37E3BE842F224A3F8FF6A55DC806FC3F7904147910B6D47638D75FB -20240903124220 2 6 100 8191 2 E90C219E279F374756F460D972C0503655CE6346FD0F611E8808CD4ADDDCE308981860661516592055313E99D7CC26BBCEE76FDE697801AA2827379287137910127F9107DEA68C3FAD7DBC9DADC15102DA2C4D890186E4279C8590E5D3F90E1B93EAFA540386086C4B55AE83AE5C7EB5FD9478B16F1143BB97202E24CE3FEE6E314B308A8CBC1F2938D7013654B6A5D141D4422375EDDEA2C2011231C5C83F318FCBE6A8FBEA20D8E9C2618D45DEBE36611557447900B4B8248A25E4D523C3D9DCAB1F1C1A7CE5EFD7FA4B1BF34486F5737F61A94C20D9268CCC52785FBF8CE06D605997A8DE54E76D7F566582C8C064E244151FD43E7B97368891F274FF1D1EBB9627BEBE9B9B202E656445873198D32286D9D8F9F0387D3ABC6C0C74C9FEC8FA935C5F43287AA191591A6ADF80EBD6EB5B58C2524BE2E2E3000A25345A7D082B7AD136133E87B4BFED4C20EE58055EDA6E9D2E2F15E299D14E11919F2C3029CE1C818D5D30EA68D0458F3B1AB30923F55F84A3BCF14137B547D56CA353F3BB7EC6F22705CC0B14FBD8D7E869325B688AA759C30FAFC74A01567BD785F4ED1F0ED1B7B82F00467A687EC3BB12A246B620B2FE0B9783C222F999CCB7CEF6FA2E3FE4DE652FC0C4B21FC4DF2CEF7981F644FB2158B208C71C68C6974D4D1090C830379707BC30C7748487EB922A4B40CB0FE33B5B4A8E22354ADB2020315D043706D608B1213A2974ED5CC6EA8A520E3147667DD81F4294313AF935C528C82B659B7A169F4B11CD03A3D35546A4E4E2FF79DB6173F3A762B22EBE4BE5B49DD4951A6BC27D5EDD8486E2105561B9BE23F1826BC0579A482AFFD99508E09F17A20419F56A31AEFADCBF816706BC1B47420A7C66A19AF1A725D691CED949F9135404B35237E6B07A037F87F4515B7F1FD5B2A7B3B562ED121A12C1B4BF9E408A0221922B10B78B9D75B81381853BBF734BBE33E12602D4191BCD47B57FA20803F1D75FD4D5A077D50DD537A6B38AB09A1A3C1B30845A0D92AA38BD1B7D1F1AA1AC9FE9CD0A0DE23BD1943A99793D18FC08BD9D7744B62D460263F879087A996FC2868675FE43F7026C6C3C93187C629AF58038F61E3072D8A4B42ABFD1639C5F2289E0A974FFBBC67FD2BAC657BC3C582664A6AD8B940E8F8596FDB8B6429C1A1F06AB1249C9A03F271F66550503E9613277D38DC63031F21AA7C8C9B2D91D6F6B7C036BAB18B5FC8900E4679992DE4BAA2CF202787D521D1545AF4A090E8E17F7E8012C104791D2F6025A41C543F9D85C1DD3EE5757CA2445697075C87D0334FD0F5C9AA8EAFF4A8A4AAEDBE7F2C80151066C7A0F05B3A6B6E5EFD1DE7FE9C53421A00BA9917C732D4735ECEE42CDE994FA6DE2C171207B2A4ADE76EC4411C2171F7C7A0E05C37E3BE842F224A3F8FF6A55DC806FC3F7904147910B6D476482E71B -20240903133142 2 6 100 8191 5 E90C219E279F374756F460D972C0503655CE6346FD0F611E8808CD4ADDDCE308981860661516592055313E99D7CC26BBCEE76FDE697801AA2827379287137910127F9107DEA68C3FAD7DBC9DADC15102DA2C4D890186E4279C8590E5D3F90E1B93EAFA540386086C4B55AE83AE5C7EB5FD9478B16F1143BB97202E24CE3FEE6E314B308A8CBC1F2938D7013654B6A5D141D4422375EDDEA2C2011231C5C83F318FCBE6A8FBEA20D8E9C2618D45DEBE36611557447900B4B8248A25E4D523C3D9DCAB1F1C1A7CE5EFD7FA4B1BF34486F5737F61A94C20D9268CCC52785FBF8CE06D605997A8DE54E76D7F566582C8C064E244151FD43E7B97368891F274FF1D1EBB9627BEBE9B9B202E656445873198D32286D9D8F9F0387D3ABC6C0C74C9FEC8FA935C5F43287AA191591A6ADF80EBD6EB5B58C2524BE2E2E3000A25345A7D082B7AD136133E87B4BFED4C20EE58055EDA6E9D2E2F15E299D14E11919F2C3029CE1C818D5D30EA68D0458F3B1AB30923F55F84A3BCF14137B547D56CA353F3BB7EC6F22705CC0B14FBD8D7E869325B688AA759C30FAFC74A01567BD785F4ED1F0ED1B7B82F00467A687EC3BB12A246B620B2FE0B9783C222F999CCB7CEF6FA2E3FE4DE652FC0C4B21FC4DF2CEF7981F644FB2158B208C71C68C6974D4D1090C830379707BC30C7748487EB922A4B40CB0FE33B5B4A8E22354ADB2020315D043706D608B1213A2974ED5CC6EA8A520E3147667DD81F4294313AF935C528C82B659B7A169F4B11CD03A3D35546A4E4E2FF79DB6173F3A762B22EBE4BE5B49DD4951A6BC27D5EDD8486E2105561B9BE23F1826BC0579A482AFFD99508E09F17A20419F56A31AEFADCBF816706BC1B47420A7C66A19AF1A725D691CED949F9135404B35237E6B07A037F87F4515B7F1FD5B2A7B3B562ED121A12C1B4BF9E408A0221922B10B78B9D75B81381853BBF734BBE33E12602D4191BCD47B57FA20803F1D75FD4D5A077D50DD537A6B38AB09A1A3C1B30845A0D92AA38BD1B7D1F1AA1AC9FE9CD0A0DE23BD1943A99793D18FC08BD9D7744B62D460263F879087A996FC2868675FE43F7026C6C3C93187C629AF58038F61E3072D8A4B42ABFD1639C5F2289E0A974FFBBC67FD2BAC657BC3C582664A6AD8B940E8F8596FDB8B6429C1A1F06AB1249C9A03F271F66550503E9613277D38DC63031F21AA7C8C9B2D91D6F6B7C036BAB18B5FC8900E4679992DE4BAA2CF202787D521D1545AF4A090E8E17F7E8012C104791D2F6025A41C543F9D85C1DD3EE5757CA2445697075C87D0334FD0F5C9AA8EAFF4A8A4AAEDBE7F2C80151066C7A0F05B3A6B6E5EFD1DE7FE9C53421A00BA9917C732D4735ECEE42CDE994FA6DE2C171207B2A4ADE76EC4411C2171F7C7A0E05C37E3BE842F224A3F8FF6A55DC806FC3F7904147910B6D476752BA3F -20240903143834 2 6 100 8191 2 E90C219E279F374756F460D972C0503655CE6346FD0F611E8808CD4ADDDCE308981860661516592055313E99D7CC26BBCEE76FDE697801AA2827379287137910127F9107DEA68C3FAD7DBC9DADC15102DA2C4D890186E4279C8590E5D3F90E1B93EAFA540386086C4B55AE83AE5C7EB5FD9478B16F1143BB97202E24CE3FEE6E314B308A8CBC1F2938D7013654B6A5D141D4422375EDDEA2C2011231C5C83F318FCBE6A8FBEA20D8E9C2618D45DEBE36611557447900B4B8248A25E4D523C3D9DCAB1F1C1A7CE5EFD7FA4B1BF34486F5737F61A94C20D9268CCC52785FBF8CE06D605997A8DE54E76D7F566582C8C064E244151FD43E7B97368891F274FF1D1EBB9627BEBE9B9B202E656445873198D32286D9D8F9F0387D3ABC6C0C74C9FEC8FA935C5F43287AA191591A6ADF80EBD6EB5B58C2524BE2E2E3000A25345A7D082B7AD136133E87B4BFED4C20EE58055EDA6E9D2E2F15E299D14E11919F2C3029CE1C818D5D30EA68D0458F3B1AB30923F55F84A3BCF14137B547D56CA353F3BB7EC6F22705CC0B14FBD8D7E869325B688AA759C30FAFC74A01567BD785F4ED1F0ED1B7B82F00467A687EC3BB12A246B620B2FE0B9783C222F999CCB7CEF6FA2E3FE4DE652FC0C4B21FC4DF2CEF7981F644FB2158B208C71C68C6974D4D1090C830379707BC30C7748487EB922A4B40CB0FE33B5B4A8E22354ADB2020315D043706D608B1213A2974ED5CC6EA8A520E3147667DD81F4294313AF935C528C82B659B7A169F4B11CD03A3D35546A4E4E2FF79DB6173F3A762B22EBE4BE5B49DD4951A6BC27D5EDD8486E2105561B9BE23F1826BC0579A482AFFD99508E09F17A20419F56A31AEFADCBF816706BC1B47420A7C66A19AF1A725D691CED949F9135404B35237E6B07A037F87F4515B7F1FD5B2A7B3B562ED121A12C1B4BF9E408A0221922B10B78B9D75B81381853BBF734BBE33E12602D4191BCD47B57FA20803F1D75FD4D5A077D50DD537A6B38AB09A1A3C1B30845A0D92AA38BD1B7D1F1AA1AC9FE9CD0A0DE23BD1943A99793D18FC08BD9D7744B62D460263F879087A996FC2868675FE43F7026C6C3C93187C629AF58038F61E3072D8A4B42ABFD1639C5F2289E0A974FFBBC67FD2BAC657BC3C582664A6AD8B940E8F8596FDB8B6429C1A1F06AB1249C9A03F271F66550503E9613277D38DC63031F21AA7C8C9B2D91D6F6B7C036BAB18B5FC8900E4679992DE4BAA2CF202787D521D1545AF4A090E8E17F7E8012C104791D2F6025A41C543F9D85C1DD3EE5757CA2445697075C87D0334FD0F5C9AA8EAFF4A8A4AAEDBE7F2C80151066C7A0F05B3A6B6E5EFD1DE7FE9C53421A00BA9917C732D4735ECEE42CDE994FA6DE2C171207B2A4ADE76EC4411C2171F7C7A0E05C37E3BE842F224A3F8FF6A55DC806FC3F7904147910B6D476B1AC6BB +20241129001801 2 6 100 2047 5 CAA48956B64FC48DD5A4823E073002797519479815F1B8D4AAAB1748CB28F30774053A901B0A52BB700F0AFB1C23E06C63EEC4326CFA484724954492B3703B50C706447754E091B6F69DEF32413B230FBC521D3912A2A030258ED841F28BD56BF27A3543756DEA1BBD62A44E66D80B22D9B41045E6DB0AFA700156862E4D24F682327787A9E10BC63D2E5F303F19109E1E3BA661635E34BBDC98BA711DFF7F7710CF632D3DDAD5B3B2539B61A309AD1BA93A60A03F1ACF9F89A6B166EDBBBA0B8160993BEF2FE072E278CDACBA5BBE44D9D5F353158DC4AECABC6EF9E16CC7DB9E5D697D3B42E02B675FB800D91F7CE79F553C6B610320EEA13FC56E329A8EFF +20241129001804 2 6 100 2047 5 CAA48956B64FC48DD5A4823E073002797519479815F1B8D4AAAB1748CB28F30774053A901B0A52BB700F0AFB1C23E06C63EEC4326CFA484724954492B3703B50C706447754E091B6F69DEF32413B230FBC521D3912A2A030258ED841F28BD56BF27A3543756DEA1BBD62A44E66D80B22D9B41045E6DB0AFA700156862E4D24F682327787A9E10BC63D2E5F303F19109E1E3BA661635E34BBDC98BA711DFF7F7710CF632D3DDAD5B3B2539B61A309AD1BA93A60A03F1ACF9F89A6B166EDBBBA0B8160993BEF2FE072E278CDACBA5BBE44D9D5F353158DC4AECABC6EF9E16CC7DB9E5D697D3B42E02B675FB800D91F7CE79F553C6B610320EEA13FC56E32AA678F +20241129001808 2 6 100 2047 2 CAA48956B64FC48DD5A4823E073002797519479815F1B8D4AAAB1748CB28F30774053A901B0A52BB700F0AFB1C23E06C63EEC4326CFA484724954492B3703B50C706447754E091B6F69DEF32413B230FBC521D3912A2A030258ED841F28BD56BF27A3543756DEA1BBD62A44E66D80B22D9B41045E6DB0AFA700156862E4D24F682327787A9E10BC63D2E5F303F19109E1E3BA661635E34BBDC98BA711DFF7F7710CF632D3DDAD5B3B2539B61A309AD1BA93A60A03F1ACF9F89A6B166EDBBBA0B8160993BEF2FE072E278CDACBA5BBE44D9D5F353158DC4AECABC6EF9E16CC7DB9E5D697D3B42E02B675FB800D91F7CE79F553C6B610320EEA13FC56E32C4EBAB +20241129001813 2 6 100 2047 2 CAA48956B64FC48DD5A4823E073002797519479815F1B8D4AAAB1748CB28F30774053A901B0A52BB700F0AFB1C23E06C63EEC4326CFA484724954492B3703B50C706447754E091B6F69DEF32413B230FBC521D3912A2A030258ED841F28BD56BF27A3543756DEA1BBD62A44E66D80B22D9B41045E6DB0AFA700156862E4D24F682327787A9E10BC63D2E5F303F19109E1E3BA661635E34BBDC98BA711DFF7F7710CF632D3DDAD5B3B2539B61A309AD1BA93A60A03F1ACF9F89A6B166EDBBBA0B8160993BEF2FE072E278CDACBA5BBE44D9D5F353158DC4AECABC6EF9E16CC7DB9E5D697D3B42E02B675FB800D91F7CE79F553C6B610320EEA13FC56E32EB8EAB +20241129001817 2 6 100 2047 2 CAA48956B64FC48DD5A4823E073002797519479815F1B8D4AAAB1748CB28F30774053A901B0A52BB700F0AFB1C23E06C63EEC4326CFA484724954492B3703B50C706447754E091B6F69DEF32413B230FBC521D3912A2A030258ED841F28BD56BF27A3543756DEA1BBD62A44E66D80B22D9B41045E6DB0AFA700156862E4D24F682327787A9E10BC63D2E5F303F19109E1E3BA661635E34BBDC98BA711DFF7F7710CF632D3DDAD5B3B2539B61A309AD1BA93A60A03F1ACF9F89A6B166EDBBBA0B8160993BEF2FE072E278CDACBA5BBE44D9D5F353158DC4AECABC6EF9E16CC7DB9E5D697D3B42E02B675FB800D91F7CE79F553C6B610320EEA13FC56E3308D17B +20241129001819 2 6 100 2047 5 CAA48956B64FC48DD5A4823E073002797519479815F1B8D4AAAB1748CB28F30774053A901B0A52BB700F0AFB1C23E06C63EEC4326CFA484724954492B3703B50C706447754E091B6F69DEF32413B230FBC521D3912A2A030258ED841F28BD56BF27A3543756DEA1BBD62A44E66D80B22D9B41045E6DB0AFA700156862E4D24F682327787A9E10BC63D2E5F303F19109E1E3BA661635E34BBDC98BA711DFF7F7710CF632D3DDAD5B3B2539B61A309AD1BA93A60A03F1ACF9F89A6B166EDBBBA0B8160993BEF2FE072E278CDACBA5BBE44D9D5F353158DC4AECABC6EF9E16CC7DB9E5D697D3B42E02B675FB800D91F7CE79F553C6B610320EEA13FC56E330EB1EF +20241129001825 2 6 100 2047 2 CAA48956B64FC48DD5A4823E073002797519479815F1B8D4AAAB1748CB28F30774053A901B0A52BB700F0AFB1C23E06C63EEC4326CFA484724954492B3703B50C706447754E091B6F69DEF32413B230FBC521D3912A2A030258ED841F28BD56BF27A3543756DEA1BBD62A44E66D80B22D9B41045E6DB0AFA700156862E4D24F682327787A9E10BC63D2E5F303F19109E1E3BA661635E34BBDC98BA711DFF7F7710CF632D3DDAD5B3B2539B61A309AD1BA93A60A03F1ACF9F89A6B166EDBBBA0B8160993BEF2FE072E278CDACBA5BBE44D9D5F353158DC4AECABC6EF9E16CC7DB9E5D697D3B42E02B675FB800D91F7CE79F553C6B610320EEA13FC56E333E0923 +20241129001832 2 6 100 2047 2 CAA48956B64FC48DD5A4823E073002797519479815F1B8D4AAAB1748CB28F30774053A901B0A52BB700F0AFB1C23E06C63EEC4326CFA484724954492B3703B50C706447754E091B6F69DEF32413B230FBC521D3912A2A030258ED841F28BD56BF27A3543756DEA1BBD62A44E66D80B22D9B41045E6DB0AFA700156862E4D24F682327787A9E10BC63D2E5F303F19109E1E3BA661635E34BBDC98BA711DFF7F7710CF632D3DDAD5B3B2539B61A309AD1BA93A60A03F1ACF9F89A6B166EDBBBA0B8160993BEF2FE072E278CDACBA5BBE44D9D5F353158DC4AECABC6EF9E16CC7DB9E5D697D3B42E02B675FB800D91F7CE79F553C6B610320EEA13FC56E3370EFD3 +20241129001904 2 6 100 2047 2 CAA48956B64FC48DD5A4823E073002797519479815F1B8D4AAAB1748CB28F30774053A901B0A52BB700F0AFB1C23E06C63EEC4326CFA484724954492B3703B50C706447754E091B6F69DEF32413B230FBC521D3912A2A030258ED841F28BD56BF27A3543756DEA1BBD62A44E66D80B22D9B41045E6DB0AFA700156862E4D24F682327787A9E10BC63D2E5F303F19109E1E3BA661635E34BBDC98BA711DFF7F7710CF632D3DDAD5B3B2539B61A309AD1BA93A60A03F1ACF9F89A6B166EDBBBA0B8160993BEF2FE072E278CDACBA5BBE44D9D5F353158DC4AECABC6EF9E16CC7DB9E5D697D3B42E02B675FB800D91F7CE79F553C6B610320EEA13FC56E3471A693 +20241129001908 2 6 100 2047 2 CAA48956B64FC48DD5A4823E073002797519479815F1B8D4AAAB1748CB28F30774053A901B0A52BB700F0AFB1C23E06C63EEC4326CFA484724954492B3703B50C706447754E091B6F69DEF32413B230FBC521D3912A2A030258ED841F28BD56BF27A3543756DEA1BBD62A44E66D80B22D9B41045E6DB0AFA700156862E4D24F682327787A9E10BC63D2E5F303F19109E1E3BA661635E34BBDC98BA711DFF7F7710CF632D3DDAD5B3B2539B61A309AD1BA93A60A03F1ACF9F89A6B166EDBBBA0B8160993BEF2FE072E278CDACBA5BBE44D9D5F353158DC4AECABC6EF9E16CC7DB9E5D697D3B42E02B675FB800D91F7CE79F553C6B610320EEA13FC56E348736C3 +20241129001923 2 6 100 2047 2 CAA48956B64FC48DD5A4823E073002797519479815F1B8D4AAAB1748CB28F30774053A901B0A52BB700F0AFB1C23E06C63EEC4326CFA484724954492B3703B50C706447754E091B6F69DEF32413B230FBC521D3912A2A030258ED841F28BD56BF27A3543756DEA1BBD62A44E66D80B22D9B41045E6DB0AFA700156862E4D24F682327787A9E10BC63D2E5F303F19109E1E3BA661635E34BBDC98BA711DFF7F7710CF632D3DDAD5B3B2539B61A309AD1BA93A60A03F1ACF9F89A6B166EDBBBA0B8160993BEF2FE072E278CDACBA5BBE44D9D5F353158DC4AECABC6EF9E16CC7DB9E5D697D3B42E02B675FB800D91F7CE79F553C6B610320EEA13FC56E35021F83 +20241129001930 2 6 100 2047 2 CAA48956B64FC48DD5A4823E073002797519479815F1B8D4AAAB1748CB28F30774053A901B0A52BB700F0AFB1C23E06C63EEC4326CFA484724954492B3703B50C706447754E091B6F69DEF32413B230FBC521D3912A2A030258ED841F28BD56BF27A3543756DEA1BBD62A44E66D80B22D9B41045E6DB0AFA700156862E4D24F682327787A9E10BC63D2E5F303F19109E1E3BA661635E34BBDC98BA711DFF7F7710CF632D3DDAD5B3B2539B61A309AD1BA93A60A03F1ACF9F89A6B166EDBBBA0B8160993BEF2FE072E278CDACBA5BBE44D9D5F353158DC4AECABC6EF9E16CC7DB9E5D697D3B42E02B675FB800D91F7CE79F553C6B610320EEA13FC56E352FB613 +20241129001942 2 6 100 2047 2 CAA48956B64FC48DD5A4823E073002797519479815F1B8D4AAAB1748CB28F30774053A901B0A52BB700F0AFB1C23E06C63EEC4326CFA484724954492B3703B50C706447754E091B6F69DEF32413B230FBC521D3912A2A030258ED841F28BD56BF27A3543756DEA1BBD62A44E66D80B22D9B41045E6DB0AFA700156862E4D24F682327787A9E10BC63D2E5F303F19109E1E3BA661635E34BBDC98BA711DFF7F7710CF632D3DDAD5B3B2539B61A309AD1BA93A60A03F1ACF9F89A6B166EDBBBA0B8160993BEF2FE072E278CDACBA5BBE44D9D5F353158DC4AECABC6EF9E16CC7DB9E5D697D3B42E02B675FB800D91F7CE79F553C6B610320EEA13FC56E3591257B +20241129001946 2 6 100 2047 2 CAA48956B64FC48DD5A4823E073002797519479815F1B8D4AAAB1748CB28F30774053A901B0A52BB700F0AFB1C23E06C63EEC4326CFA484724954492B3703B50C706447754E091B6F69DEF32413B230FBC521D3912A2A030258ED841F28BD56BF27A3543756DEA1BBD62A44E66D80B22D9B41045E6DB0AFA700156862E4D24F682327787A9E10BC63D2E5F303F19109E1E3BA661635E34BBDC98BA711DFF7F7710CF632D3DDAD5B3B2539B61A309AD1BA93A60A03F1ACF9F89A6B166EDBBBA0B8160993BEF2FE072E278CDACBA5BBE44D9D5F353158DC4AECABC6EF9E16CC7DB9E5D697D3B42E02B675FB800D91F7CE79F553C6B610320EEA13FC56E35AB042B +20241129001947 2 6 100 2047 2 CAA48956B64FC48DD5A4823E073002797519479815F1B8D4AAAB1748CB28F30774053A901B0A52BB700F0AFB1C23E06C63EEC4326CFA484724954492B3703B50C706447754E091B6F69DEF32413B230FBC521D3912A2A030258ED841F28BD56BF27A3543756DEA1BBD62A44E66D80B22D9B41045E6DB0AFA700156862E4D24F682327787A9E10BC63D2E5F303F19109E1E3BA661635E34BBDC98BA711DFF7F7710CF632D3DDAD5B3B2539B61A309AD1BA93A60A03F1ACF9F89A6B166EDBBBA0B8160993BEF2FE072E278CDACBA5BBE44D9D5F353158DC4AECABC6EF9E16CC7DB9E5D697D3B42E02B675FB800D91F7CE79F553C6B610320EEA13FC56E35B082CB +20241129002012 2 6 100 2047 2 CAA48956B64FC48DD5A4823E073002797519479815F1B8D4AAAB1748CB28F30774053A901B0A52BB700F0AFB1C23E06C63EEC4326CFA484724954492B3703B50C706447754E091B6F69DEF32413B230FBC521D3912A2A030258ED841F28BD56BF27A3543756DEA1BBD62A44E66D80B22D9B41045E6DB0AFA700156862E4D24F682327787A9E10BC63D2E5F303F19109E1E3BA661635E34BBDC98BA711DFF7F7710CF632D3DDAD5B3B2539B61A309AD1BA93A60A03F1ACF9F89A6B166EDBBBA0B8160993BEF2FE072E278CDACBA5BBE44D9D5F353158DC4AECABC6EF9E16CC7DB9E5D697D3B42E02B675FB800D91F7CE79F553C6B610320EEA13FC56E36777D7B +20241129002017 2 6 100 2047 2 CAA48956B64FC48DD5A4823E073002797519479815F1B8D4AAAB1748CB28F30774053A901B0A52BB700F0AFB1C23E06C63EEC4326CFA484724954492B3703B50C706447754E091B6F69DEF32413B230FBC521D3912A2A030258ED841F28BD56BF27A3543756DEA1BBD62A44E66D80B22D9B41045E6DB0AFA700156862E4D24F682327787A9E10BC63D2E5F303F19109E1E3BA661635E34BBDC98BA711DFF7F7710CF632D3DDAD5B3B2539B61A309AD1BA93A60A03F1ACF9F89A6B166EDBBBA0B8160993BEF2FE072E278CDACBA5BBE44D9D5F353158DC4AECABC6EF9E16CC7DB9E5D697D3B42E02B675FB800D91F7CE79F553C6B610320EEA13FC56E3697886B +20241129002030 2 6 100 2047 2 CAA48956B64FC48DD5A4823E073002797519479815F1B8D4AAAB1748CB28F30774053A901B0A52BB700F0AFB1C23E06C63EEC4326CFA484724954492B3703B50C706447754E091B6F69DEF32413B230FBC521D3912A2A030258ED841F28BD56BF27A3543756DEA1BBD62A44E66D80B22D9B41045E6DB0AFA700156862E4D24F682327787A9E10BC63D2E5F303F19109E1E3BA661635E34BBDC98BA711DFF7F7710CF632D3DDAD5B3B2539B61A309AD1BA93A60A03F1ACF9F89A6B166EDBBBA0B8160993BEF2FE072E278CDACBA5BBE44D9D5F353158DC4AECABC6EF9E16CC7DB9E5D697D3B42E02B675FB800D91F7CE79F553C6B610320EEA13FC56E36F5B2EB +20241129002036 2 6 100 2047 2 CAA48956B64FC48DD5A4823E073002797519479815F1B8D4AAAB1748CB28F30774053A901B0A52BB700F0AFB1C23E06C63EEC4326CFA484724954492B3703B50C706447754E091B6F69DEF32413B230FBC521D3912A2A030258ED841F28BD56BF27A3543756DEA1BBD62A44E66D80B22D9B41045E6DB0AFA700156862E4D24F682327787A9E10BC63D2E5F303F19109E1E3BA661635E34BBDC98BA711DFF7F7710CF632D3DDAD5B3B2539B61A309AD1BA93A60A03F1ACF9F89A6B166EDBBBA0B8160993BEF2FE072E278CDACBA5BBE44D9D5F353158DC4AECABC6EF9E16CC7DB9E5D697D3B42E02B675FB800D91F7CE79F553C6B610320EEA13FC56E37249BD3 +20241129002045 2 6 100 2047 2 CAA48956B64FC48DD5A4823E073002797519479815F1B8D4AAAB1748CB28F30774053A901B0A52BB700F0AFB1C23E06C63EEC4326CFA484724954492B3703B50C706447754E091B6F69DEF32413B230FBC521D3912A2A030258ED841F28BD56BF27A3543756DEA1BBD62A44E66D80B22D9B41045E6DB0AFA700156862E4D24F682327787A9E10BC63D2E5F303F19109E1E3BA661635E34BBDC98BA711DFF7F7710CF632D3DDAD5B3B2539B61A309AD1BA93A60A03F1ACF9F89A6B166EDBBBA0B8160993BEF2FE072E278CDACBA5BBE44D9D5F353158DC4AECABC6EF9E16CC7DB9E5D697D3B42E02B675FB800D91F7CE79F553C6B610320EEA13FC56E3769C1B3 +20241129002059 2 6 100 2047 5 CAA48956B64FC48DD5A4823E073002797519479815F1B8D4AAAB1748CB28F30774053A901B0A52BB700F0AFB1C23E06C63EEC4326CFA484724954492B3703B50C706447754E091B6F69DEF32413B230FBC521D3912A2A030258ED841F28BD56BF27A3543756DEA1BBD62A44E66D80B22D9B41045E6DB0AFA700156862E4D24F682327787A9E10BC63D2E5F303F19109E1E3BA661635E34BBDC98BA711DFF7F7710CF632D3DDAD5B3B2539B61A309AD1BA93A60A03F1ACF9F89A6B166EDBBBA0B8160993BEF2FE072E278CDACBA5BBE44D9D5F353158DC4AECABC6EF9E16CC7DB9E5D697D3B42E02B675FB800D91F7CE79F553C6B610320EEA13FC56E37D6FDAF +20241129002102 2 6 100 2047 2 CAA48956B64FC48DD5A4823E073002797519479815F1B8D4AAAB1748CB28F30774053A901B0A52BB700F0AFB1C23E06C63EEC4326CFA484724954492B3703B50C706447754E091B6F69DEF32413B230FBC521D3912A2A030258ED841F28BD56BF27A3543756DEA1BBD62A44E66D80B22D9B41045E6DB0AFA700156862E4D24F682327787A9E10BC63D2E5F303F19109E1E3BA661635E34BBDC98BA711DFF7F7710CF632D3DDAD5B3B2539B61A309AD1BA93A60A03F1ACF9F89A6B166EDBBBA0B8160993BEF2FE072E278CDACBA5BBE44D9D5F353158DC4AECABC6EF9E16CC7DB9E5D697D3B42E02B675FB800D91F7CE79F553C6B610320EEA13FC56E37EDB2E3 +20241129002105 2 6 100 2047 5 CAA48956B64FC48DD5A4823E073002797519479815F1B8D4AAAB1748CB28F30774053A901B0A52BB700F0AFB1C23E06C63EEC4326CFA484724954492B3703B50C706447754E091B6F69DEF32413B230FBC521D3912A2A030258ED841F28BD56BF27A3543756DEA1BBD62A44E66D80B22D9B41045E6DB0AFA700156862E4D24F682327787A9E10BC63D2E5F303F19109E1E3BA661635E34BBDC98BA711DFF7F7710CF632D3DDAD5B3B2539B61A309AD1BA93A60A03F1ACF9F89A6B166EDBBBA0B8160993BEF2FE072E278CDACBA5BBE44D9D5F353158DC4AECABC6EF9E16CC7DB9E5D697D3B42E02B675FB800D91F7CE79F553C6B610320EEA13FC56E37FA449F +20241129002109 2 6 100 2047 5 CAA48956B64FC48DD5A4823E073002797519479815F1B8D4AAAB1748CB28F30774053A901B0A52BB700F0AFB1C23E06C63EEC4326CFA484724954492B3703B50C706447754E091B6F69DEF32413B230FBC521D3912A2A030258ED841F28BD56BF27A3543756DEA1BBD62A44E66D80B22D9B41045E6DB0AFA700156862E4D24F682327787A9E10BC63D2E5F303F19109E1E3BA661635E34BBDC98BA711DFF7F7710CF632D3DDAD5B3B2539B61A309AD1BA93A60A03F1ACF9F89A6B166EDBBBA0B8160993BEF2FE072E278CDACBA5BBE44D9D5F353158DC4AECABC6EF9E16CC7DB9E5D697D3B42E02B675FB800D91F7CE79F553C6B610320EEA13FC56E381694E7 +20241129002127 2 6 100 2047 5 CAA48956B64FC48DD5A4823E073002797519479815F1B8D4AAAB1748CB28F30774053A901B0A52BB700F0AFB1C23E06C63EEC4326CFA484724954492B3703B50C706447754E091B6F69DEF32413B230FBC521D3912A2A030258ED841F28BD56BF27A3543756DEA1BBD62A44E66D80B22D9B41045E6DB0AFA700156862E4D24F682327787A9E10BC63D2E5F303F19109E1E3BA661635E34BBDC98BA711DFF7F7710CF632D3DDAD5B3B2539B61A309AD1BA93A60A03F1ACF9F89A6B166EDBBBA0B8160993BEF2FE072E278CDACBA5BBE44D9D5F353158DC4AECABC6EF9E16CC7DB9E5D697D3B42E02B675FB800D91F7CE79F553C6B610320EEA13FC56E38A56437 +20241129002141 2 6 100 2047 2 CAA48956B64FC48DD5A4823E073002797519479815F1B8D4AAAB1748CB28F30774053A901B0A52BB700F0AFB1C23E06C63EEC4326CFA484724954492B3703B50C706447754E091B6F69DEF32413B230FBC521D3912A2A030258ED841F28BD56BF27A3543756DEA1BBD62A44E66D80B22D9B41045E6DB0AFA700156862E4D24F682327787A9E10BC63D2E5F303F19109E1E3BA661635E34BBDC98BA711DFF7F7710CF632D3DDAD5B3B2539B61A309AD1BA93A60A03F1ACF9F89A6B166EDBBBA0B8160993BEF2FE072E278CDACBA5BBE44D9D5F353158DC4AECABC6EF9E16CC7DB9E5D697D3B42E02B675FB800D91F7CE79F553C6B610320EEA13FC56E391852F3 +20241129002144 2 6 100 2047 5 CAA48956B64FC48DD5A4823E073002797519479815F1B8D4AAAB1748CB28F30774053A901B0A52BB700F0AFB1C23E06C63EEC4326CFA484724954492B3703B50C706447754E091B6F69DEF32413B230FBC521D3912A2A030258ED841F28BD56BF27A3543756DEA1BBD62A44E66D80B22D9B41045E6DB0AFA700156862E4D24F682327787A9E10BC63D2E5F303F19109E1E3BA661635E34BBDC98BA711DFF7F7710CF632D3DDAD5B3B2539B61A309AD1BA93A60A03F1ACF9F89A6B166EDBBBA0B8160993BEF2FE072E278CDACBA5BBE44D9D5F353158DC4AECABC6EF9E16CC7DB9E5D697D3B42E02B675FB800D91F7CE79F553C6B610320EEA13FC56E3927ECD7 +20241129002150 2 6 100 2047 5 CAA48956B64FC48DD5A4823E073002797519479815F1B8D4AAAB1748CB28F30774053A901B0A52BB700F0AFB1C23E06C63EEC4326CFA484724954492B3703B50C706447754E091B6F69DEF32413B230FBC521D3912A2A030258ED841F28BD56BF27A3543756DEA1BBD62A44E66D80B22D9B41045E6DB0AFA700156862E4D24F682327787A9E10BC63D2E5F303F19109E1E3BA661635E34BBDC98BA711DFF7F7710CF632D3DDAD5B3B2539B61A309AD1BA93A60A03F1ACF9F89A6B166EDBBBA0B8160993BEF2FE072E278CDACBA5BBE44D9D5F353158DC4AECABC6EF9E16CC7DB9E5D697D3B42E02B675FB800D91F7CE79F553C6B610320EEA13FC56E3952495F +20241129002154 2 6 100 2047 2 CAA48956B64FC48DD5A4823E073002797519479815F1B8D4AAAB1748CB28F30774053A901B0A52BB700F0AFB1C23E06C63EEC4326CFA484724954492B3703B50C706447754E091B6F69DEF32413B230FBC521D3912A2A030258ED841F28BD56BF27A3543756DEA1BBD62A44E66D80B22D9B41045E6DB0AFA700156862E4D24F682327787A9E10BC63D2E5F303F19109E1E3BA661635E34BBDC98BA711DFF7F7710CF632D3DDAD5B3B2539B61A309AD1BA93A60A03F1ACF9F89A6B166EDBBBA0B8160993BEF2FE072E278CDACBA5BBE44D9D5F353158DC4AECABC6EF9E16CC7DB9E5D697D3B42E02B675FB800D91F7CE79F553C6B610320EEA13FC56E3971FEDB +20241129002226 2 6 100 2047 2 D62BDAF38E54FDFF0C708C3A9D5A49ADD950102DDCE4017B0B90CB32FE8736EE054C70F834E7196596829647330A22260674F15C124DFD61BD6304ED8DAA2BAF03E37A43714575DC4E50D30EB36E31B994DA55D6CCE62E854F087F56587D5C04E2907BF39AE275B9B5E0353A50453DA96E714E11E5A00F72680903B482731C04A0791B018B4FDB5D2EA1DE235C20CF300B0C1CED91A218390A09DF78C1877BB35E0D92D22ED647E32EA5C9F877B589B4A8F7F6685715AC5E0E5F93DB5671E028A9DFE1C66662C94A47C19FE0ED1B9C9BCBEA281F705C358F792091DE4A2F110B6B68E4AB15D6B30C59C8850D1E436BDDABADF17ED1E8881271CD1E7C8F34FC6B +20241129002249 2 6 100 2047 5 D62BDAF38E54FDFF0C708C3A9D5A49ADD950102DDCE4017B0B90CB32FE8736EE054C70F834E7196596829647330A22260674F15C124DFD61BD6304ED8DAA2BAF03E37A43714575DC4E50D30EB36E31B994DA55D6CCE62E854F087F56587D5C04E2907BF39AE275B9B5E0353A50453DA96E714E11E5A00F72680903B482731C04A0791B018B4FDB5D2EA1DE235C20CF300B0C1CED91A218390A09DF78C1877BB35E0D92D22ED647E32EA5C9F877B589B4A8F7F6685715AC5E0E5F93DB5671E028A9DFE1C66662C94A47C19FE0ED1B9C9BCBEA281F705C358F792091DE4A2F110B6B68E4AB15D6B30C59C8850D1E436BDDABADF17ED1E8881271CD1E7C8FE809EF +20241129002253 2 6 100 2047 2 D62BDAF38E54FDFF0C708C3A9D5A49ADD950102DDCE4017B0B90CB32FE8736EE054C70F834E7196596829647330A22260674F15C124DFD61BD6304ED8DAA2BAF03E37A43714575DC4E50D30EB36E31B994DA55D6CCE62E854F087F56587D5C04E2907BF39AE275B9B5E0353A50453DA96E714E11E5A00F72680903B482731C04A0791B018B4FDB5D2EA1DE235C20CF300B0C1CED91A218390A09DF78C1877BB35E0D92D22ED647E32EA5C9F877B589B4A8F7F6685715AC5E0E5F93DB5671E028A9DFE1C66662C94A47C19FE0ED1B9C9BCBEA281F705C358F792091DE4A2F110B6B68E4AB15D6B30C59C8850D1E436BDDABADF17ED1E8881271CD1E7C9008BDF3 +20241129002312 2 6 100 2047 2 D62BDAF38E54FDFF0C708C3A9D5A49ADD950102DDCE4017B0B90CB32FE8736EE054C70F834E7196596829647330A22260674F15C124DFD61BD6304ED8DAA2BAF03E37A43714575DC4E50D30EB36E31B994DA55D6CCE62E854F087F56587D5C04E2907BF39AE275B9B5E0353A50453DA96E714E11E5A00F72680903B482731C04A0791B018B4FDB5D2EA1DE235C20CF300B0C1CED91A218390A09DF78C1877BB35E0D92D22ED647E32EA5C9F877B589B4A8F7F6685715AC5E0E5F93DB5671E028A9DFE1C66662C94A47C19FE0ED1B9C9BCBEA281F705C358F792091DE4A2F110B6B68E4AB15D6B30C59C8850D1E436BDDABADF17ED1E8881271CD1E7C9099D883 +20241129002320 2 6 100 2047 2 D62BDAF38E54FDFF0C708C3A9D5A49ADD950102DDCE4017B0B90CB32FE8736EE054C70F834E7196596829647330A22260674F15C124DFD61BD6304ED8DAA2BAF03E37A43714575DC4E50D30EB36E31B994DA55D6CCE62E854F087F56587D5C04E2907BF39AE275B9B5E0353A50453DA96E714E11E5A00F72680903B482731C04A0791B018B4FDB5D2EA1DE235C20CF300B0C1CED91A218390A09DF78C1877BB35E0D92D22ED647E32EA5C9F877B589B4A8F7F6685715AC5E0E5F93DB5671E028A9DFE1C66662C94A47C19FE0ED1B9C9BCBEA281F705C358F792091DE4A2F110B6B68E4AB15D6B30C59C8850D1E436BDDABADF17ED1E8881271CD1E7C90D2E5BB +20241129002328 2 6 100 2047 5 D62BDAF38E54FDFF0C708C3A9D5A49ADD950102DDCE4017B0B90CB32FE8736EE054C70F834E7196596829647330A22260674F15C124DFD61BD6304ED8DAA2BAF03E37A43714575DC4E50D30EB36E31B994DA55D6CCE62E854F087F56587D5C04E2907BF39AE275B9B5E0353A50453DA96E714E11E5A00F72680903B482731C04A0791B018B4FDB5D2EA1DE235C20CF300B0C1CED91A218390A09DF78C1877BB35E0D92D22ED647E32EA5C9F877B589B4A8F7F6685715AC5E0E5F93DB5671E028A9DFE1C66662C94A47C19FE0ED1B9C9BCBEA281F705C358F792091DE4A2F110B6B68E4AB15D6B30C59C8850D1E436BDDABADF17ED1E8881271CD1E7C9111A1E7 +20241129002329 2 6 100 2047 5 D62BDAF38E54FDFF0C708C3A9D5A49ADD950102DDCE4017B0B90CB32FE8736EE054C70F834E7196596829647330A22260674F15C124DFD61BD6304ED8DAA2BAF03E37A43714575DC4E50D30EB36E31B994DA55D6CCE62E854F087F56587D5C04E2907BF39AE275B9B5E0353A50453DA96E714E11E5A00F72680903B482731C04A0791B018B4FDB5D2EA1DE235C20CF300B0C1CED91A218390A09DF78C1877BB35E0D92D22ED647E32EA5C9F877B589B4A8F7F6685715AC5E0E5F93DB5671E028A9DFE1C66662C94A47C19FE0ED1B9C9BCBEA281F705C358F792091DE4A2F110B6B68E4AB15D6B30C59C8850D1E436BDDABADF17ED1E8881271CD1E7C9113E88F +20241129002336 2 6 100 2047 2 D62BDAF38E54FDFF0C708C3A9D5A49ADD950102DDCE4017B0B90CB32FE8736EE054C70F834E7196596829647330A22260674F15C124DFD61BD6304ED8DAA2BAF03E37A43714575DC4E50D30EB36E31B994DA55D6CCE62E854F087F56587D5C04E2907BF39AE275B9B5E0353A50453DA96E714E11E5A00F72680903B482731C04A0791B018B4FDB5D2EA1DE235C20CF300B0C1CED91A218390A09DF78C1877BB35E0D92D22ED647E32EA5C9F877B589B4A8F7F6685715AC5E0E5F93DB5671E028A9DFE1C66662C94A47C19FE0ED1B9C9BCBEA281F705C358F792091DE4A2F110B6B68E4AB15D6B30C59C8850D1E436BDDABADF17ED1E8881271CD1E7C9148164B +20241129002339 2 6 100 2047 2 D62BDAF38E54FDFF0C708C3A9D5A49ADD950102DDCE4017B0B90CB32FE8736EE054C70F834E7196596829647330A22260674F15C124DFD61BD6304ED8DAA2BAF03E37A43714575DC4E50D30EB36E31B994DA55D6CCE62E854F087F56587D5C04E2907BF39AE275B9B5E0353A50453DA96E714E11E5A00F72680903B482731C04A0791B018B4FDB5D2EA1DE235C20CF300B0C1CED91A218390A09DF78C1877BB35E0D92D22ED647E32EA5C9F877B589B4A8F7F6685715AC5E0E5F93DB5671E028A9DFE1C66662C94A47C19FE0ED1B9C9BCBEA281F705C358F792091DE4A2F110B6B68E4AB15D6B30C59C8850D1E436BDDABADF17ED1E8881271CD1E7C915E0DCB +20241129002340 2 6 100 2047 2 D62BDAF38E54FDFF0C708C3A9D5A49ADD950102DDCE4017B0B90CB32FE8736EE054C70F834E7196596829647330A22260674F15C124DFD61BD6304ED8DAA2BAF03E37A43714575DC4E50D30EB36E31B994DA55D6CCE62E854F087F56587D5C04E2907BF39AE275B9B5E0353A50453DA96E714E11E5A00F72680903B482731C04A0791B018B4FDB5D2EA1DE235C20CF300B0C1CED91A218390A09DF78C1877BB35E0D92D22ED647E32EA5C9F877B589B4A8F7F6685715AC5E0E5F93DB5671E028A9DFE1C66662C94A47C19FE0ED1B9C9BCBEA281F705C358F792091DE4A2F110B6B68E4AB15D6B30C59C8850D1E436BDDABADF17ED1E8881271CD1E7C915EB103 +20241129002420 2 6 100 2047 5 D62BDAF38E54FDFF0C708C3A9D5A49ADD950102DDCE4017B0B90CB32FE8736EE054C70F834E7196596829647330A22260674F15C124DFD61BD6304ED8DAA2BAF03E37A43714575DC4E50D30EB36E31B994DA55D6CCE62E854F087F56587D5C04E2907BF39AE275B9B5E0353A50453DA96E714E11E5A00F72680903B482731C04A0791B018B4FDB5D2EA1DE235C20CF300B0C1CED91A218390A09DF78C1877BB35E0D92D22ED647E32EA5C9F877B589B4A8F7F6685715AC5E0E5F93DB5671E028A9DFE1C66662C94A47C19FE0ED1B9C9BCBEA281F705C358F792091DE4A2F110B6B68E4AB15D6B30C59C8850D1E436BDDABADF17ED1E8881271CD1E7C92A19C97 +20241129002428 2 6 100 2047 5 D62BDAF38E54FDFF0C708C3A9D5A49ADD950102DDCE4017B0B90CB32FE8736EE054C70F834E7196596829647330A22260674F15C124DFD61BD6304ED8DAA2BAF03E37A43714575DC4E50D30EB36E31B994DA55D6CCE62E854F087F56587D5C04E2907BF39AE275B9B5E0353A50453DA96E714E11E5A00F72680903B482731C04A0791B018B4FDB5D2EA1DE235C20CF300B0C1CED91A218390A09DF78C1877BB35E0D92D22ED647E32EA5C9F877B589B4A8F7F6685715AC5E0E5F93DB5671E028A9DFE1C66662C94A47C19FE0ED1B9C9BCBEA281F705C358F792091DE4A2F110B6B68E4AB15D6B30C59C8850D1E436BDDABADF17ED1E8881271CD1E7C92E090AF +20241129002433 2 6 100 2047 2 D62BDAF38E54FDFF0C708C3A9D5A49ADD950102DDCE4017B0B90CB32FE8736EE054C70F834E7196596829647330A22260674F15C124DFD61BD6304ED8DAA2BAF03E37A43714575DC4E50D30EB36E31B994DA55D6CCE62E854F087F56587D5C04E2907BF39AE275B9B5E0353A50453DA96E714E11E5A00F72680903B482731C04A0791B018B4FDB5D2EA1DE235C20CF300B0C1CED91A218390A09DF78C1877BB35E0D92D22ED647E32EA5C9F877B589B4A8F7F6685715AC5E0E5F93DB5671E028A9DFE1C66662C94A47C19FE0ED1B9C9BCBEA281F705C358F792091DE4A2F110B6B68E4AB15D6B30C59C8850D1E436BDDABADF17ED1E8881271CD1E7C93040BCB +20241129002434 2 6 100 2047 2 D62BDAF38E54FDFF0C708C3A9D5A49ADD950102DDCE4017B0B90CB32FE8736EE054C70F834E7196596829647330A22260674F15C124DFD61BD6304ED8DAA2BAF03E37A43714575DC4E50D30EB36E31B994DA55D6CCE62E854F087F56587D5C04E2907BF39AE275B9B5E0353A50453DA96E714E11E5A00F72680903B482731C04A0791B018B4FDB5D2EA1DE235C20CF300B0C1CED91A218390A09DF78C1877BB35E0D92D22ED647E32EA5C9F877B589B4A8F7F6685715AC5E0E5F93DB5671E028A9DFE1C66662C94A47C19FE0ED1B9C9BCBEA281F705C358F792091DE4A2F110B6B68E4AB15D6B30C59C8850D1E436BDDABADF17ED1E8881271CD1E7C930B22CB +20241129002436 2 6 100 2047 2 D62BDAF38E54FDFF0C708C3A9D5A49ADD950102DDCE4017B0B90CB32FE8736EE054C70F834E7196596829647330A22260674F15C124DFD61BD6304ED8DAA2BAF03E37A43714575DC4E50D30EB36E31B994DA55D6CCE62E854F087F56587D5C04E2907BF39AE275B9B5E0353A50453DA96E714E11E5A00F72680903B482731C04A0791B018B4FDB5D2EA1DE235C20CF300B0C1CED91A218390A09DF78C1877BB35E0D92D22ED647E32EA5C9F877B589B4A8F7F6685715AC5E0E5F93DB5671E028A9DFE1C66662C94A47C19FE0ED1B9C9BCBEA281F705C358F792091DE4A2F110B6B68E4AB15D6B30C59C8850D1E436BDDABADF17ED1E8881271CD1E7C931188B3 +20241129002446 2 6 100 2047 5 D62BDAF38E54FDFF0C708C3A9D5A49ADD950102DDCE4017B0B90CB32FE8736EE054C70F834E7196596829647330A22260674F15C124DFD61BD6304ED8DAA2BAF03E37A43714575DC4E50D30EB36E31B994DA55D6CCE62E854F087F56587D5C04E2907BF39AE275B9B5E0353A50453DA96E714E11E5A00F72680903B482731C04A0791B018B4FDB5D2EA1DE235C20CF300B0C1CED91A218390A09DF78C1877BB35E0D92D22ED647E32EA5C9F877B589B4A8F7F6685715AC5E0E5F93DB5671E028A9DFE1C66662C94A47C19FE0ED1B9C9BCBEA281F705C358F792091DE4A2F110B6B68E4AB15D6B30C59C8850D1E436BDDABADF17ED1E8881271CD1E7C935DB5F7 +20241129002507 2 6 100 2047 2 D62BDAF38E54FDFF0C708C3A9D5A49ADD950102DDCE4017B0B90CB32FE8736EE054C70F834E7196596829647330A22260674F15C124DFD61BD6304ED8DAA2BAF03E37A43714575DC4E50D30EB36E31B994DA55D6CCE62E854F087F56587D5C04E2907BF39AE275B9B5E0353A50453DA96E714E11E5A00F72680903B482731C04A0791B018B4FDB5D2EA1DE235C20CF300B0C1CED91A218390A09DF78C1877BB35E0D92D22ED647E32EA5C9F877B589B4A8F7F6685715AC5E0E5F93DB5671E028A9DFE1C66662C94A47C19FE0ED1B9C9BCBEA281F705C358F792091DE4A2F110B6B68E4AB15D6B30C59C8850D1E436BDDABADF17ED1E8881271CD1E7C9408C96B +20241129002510 2 6 100 2047 2 D62BDAF38E54FDFF0C708C3A9D5A49ADD950102DDCE4017B0B90CB32FE8736EE054C70F834E7196596829647330A22260674F15C124DFD61BD6304ED8DAA2BAF03E37A43714575DC4E50D30EB36E31B994DA55D6CCE62E854F087F56587D5C04E2907BF39AE275B9B5E0353A50453DA96E714E11E5A00F72680903B482731C04A0791B018B4FDB5D2EA1DE235C20CF300B0C1CED91A218390A09DF78C1877BB35E0D92D22ED647E32EA5C9F877B589B4A8F7F6685715AC5E0E5F93DB5671E028A9DFE1C66662C94A47C19FE0ED1B9C9BCBEA281F705C358F792091DE4A2F110B6B68E4AB15D6B30C59C8850D1E436BDDABADF17ED1E8881271CD1E7C941D429B +20241129002527 2 6 100 2047 2 D62BDAF38E54FDFF0C708C3A9D5A49ADD950102DDCE4017B0B90CB32FE8736EE054C70F834E7196596829647330A22260674F15C124DFD61BD6304ED8DAA2BAF03E37A43714575DC4E50D30EB36E31B994DA55D6CCE62E854F087F56587D5C04E2907BF39AE275B9B5E0353A50453DA96E714E11E5A00F72680903B482731C04A0791B018B4FDB5D2EA1DE235C20CF300B0C1CED91A218390A09DF78C1877BB35E0D92D22ED647E32EA5C9F877B589B4A8F7F6685715AC5E0E5F93DB5671E028A9DFE1C66662C94A47C19FE0ED1B9C9BCBEA281F705C358F792091DE4A2F110B6B68E4AB15D6B30C59C8850D1E436BDDABADF17ED1E8881271CD1E7C94A15E73 +20241129002528 2 6 100 2047 5 D62BDAF38E54FDFF0C708C3A9D5A49ADD950102DDCE4017B0B90CB32FE8736EE054C70F834E7196596829647330A22260674F15C124DFD61BD6304ED8DAA2BAF03E37A43714575DC4E50D30EB36E31B994DA55D6CCE62E854F087F56587D5C04E2907BF39AE275B9B5E0353A50453DA96E714E11E5A00F72680903B482731C04A0791B018B4FDB5D2EA1DE235C20CF300B0C1CED91A218390A09DF78C1877BB35E0D92D22ED647E32EA5C9F877B589B4A8F7F6685715AC5E0E5F93DB5671E028A9DFE1C66662C94A47C19FE0ED1B9C9BCBEA281F705C358F792091DE4A2F110B6B68E4AB15D6B30C59C8850D1E436BDDABADF17ED1E8881271CD1E7C94AA3DAF +20241129002531 2 6 100 2047 5 D62BDAF38E54FDFF0C708C3A9D5A49ADD950102DDCE4017B0B90CB32FE8736EE054C70F834E7196596829647330A22260674F15C124DFD61BD6304ED8DAA2BAF03E37A43714575DC4E50D30EB36E31B994DA55D6CCE62E854F087F56587D5C04E2907BF39AE275B9B5E0353A50453DA96E714E11E5A00F72680903B482731C04A0791B018B4FDB5D2EA1DE235C20CF300B0C1CED91A218390A09DF78C1877BB35E0D92D22ED647E32EA5C9F877B589B4A8F7F6685715AC5E0E5F93DB5671E028A9DFE1C66662C94A47C19FE0ED1B9C9BCBEA281F705C358F792091DE4A2F110B6B68E4AB15D6B30C59C8850D1E436BDDABADF17ED1E8881271CD1E7C94BA0ED7 +20241129002538 2 6 100 2047 5 D62BDAF38E54FDFF0C708C3A9D5A49ADD950102DDCE4017B0B90CB32FE8736EE054C70F834E7196596829647330A22260674F15C124DFD61BD6304ED8DAA2BAF03E37A43714575DC4E50D30EB36E31B994DA55D6CCE62E854F087F56587D5C04E2907BF39AE275B9B5E0353A50453DA96E714E11E5A00F72680903B482731C04A0791B018B4FDB5D2EA1DE235C20CF300B0C1CED91A218390A09DF78C1877BB35E0D92D22ED647E32EA5C9F877B589B4A8F7F6685715AC5E0E5F93DB5671E028A9DFE1C66662C94A47C19FE0ED1B9C9BCBEA281F705C358F792091DE4A2F110B6B68E4AB15D6B30C59C8850D1E436BDDABADF17ED1E8881271CD1E7C94ECC017 +20241129002543 2 6 100 2047 5 D62BDAF38E54FDFF0C708C3A9D5A49ADD950102DDCE4017B0B90CB32FE8736EE054C70F834E7196596829647330A22260674F15C124DFD61BD6304ED8DAA2BAF03E37A43714575DC4E50D30EB36E31B994DA55D6CCE62E854F087F56587D5C04E2907BF39AE275B9B5E0353A50453DA96E714E11E5A00F72680903B482731C04A0791B018B4FDB5D2EA1DE235C20CF300B0C1CED91A218390A09DF78C1877BB35E0D92D22ED647E32EA5C9F877B589B4A8F7F6685715AC5E0E5F93DB5671E028A9DFE1C66662C94A47C19FE0ED1B9C9BCBEA281F705C358F792091DE4A2F110B6B68E4AB15D6B30C59C8850D1E436BDDABADF17ED1E8881271CD1E7C9511A1BF +20241129002558 2 6 100 2047 5 D62BDAF38E54FDFF0C708C3A9D5A49ADD950102DDCE4017B0B90CB32FE8736EE054C70F834E7196596829647330A22260674F15C124DFD61BD6304ED8DAA2BAF03E37A43714575DC4E50D30EB36E31B994DA55D6CCE62E854F087F56587D5C04E2907BF39AE275B9B5E0353A50453DA96E714E11E5A00F72680903B482731C04A0791B018B4FDB5D2EA1DE235C20CF300B0C1CED91A218390A09DF78C1877BB35E0D92D22ED647E32EA5C9F877B589B4A8F7F6685715AC5E0E5F93DB5671E028A9DFE1C66662C94A47C19FE0ED1B9C9BCBEA281F705C358F792091DE4A2F110B6B68E4AB15D6B30C59C8850D1E436BDDABADF17ED1E8881271CD1E7C95871257 +20241129002602 2 6 100 2047 2 D62BDAF38E54FDFF0C708C3A9D5A49ADD950102DDCE4017B0B90CB32FE8736EE054C70F834E7196596829647330A22260674F15C124DFD61BD6304ED8DAA2BAF03E37A43714575DC4E50D30EB36E31B994DA55D6CCE62E854F087F56587D5C04E2907BF39AE275B9B5E0353A50453DA96E714E11E5A00F72680903B482731C04A0791B018B4FDB5D2EA1DE235C20CF300B0C1CED91A218390A09DF78C1877BB35E0D92D22ED647E32EA5C9F877B589B4A8F7F6685715AC5E0E5F93DB5671E028A9DFE1C66662C94A47C19FE0ED1B9C9BCBEA281F705C358F792091DE4A2F110B6B68E4AB15D6B30C59C8850D1E436BDDABADF17ED1E8881271CD1E7C95A7B2AB +20241129002617 2 6 100 2047 2 D62BDAF38E54FDFF0C708C3A9D5A49ADD950102DDCE4017B0B90CB32FE8736EE054C70F834E7196596829647330A22260674F15C124DFD61BD6304ED8DAA2BAF03E37A43714575DC4E50D30EB36E31B994DA55D6CCE62E854F087F56587D5C04E2907BF39AE275B9B5E0353A50453DA96E714E11E5A00F72680903B482731C04A0791B018B4FDB5D2EA1DE235C20CF300B0C1CED91A218390A09DF78C1877BB35E0D92D22ED647E32EA5C9F877B589B4A8F7F6685715AC5E0E5F93DB5671E028A9DFE1C66662C94A47C19FE0ED1B9C9BCBEA281F705C358F792091DE4A2F110B6B68E4AB15D6B30C59C8850D1E436BDDABADF17ED1E8881271CD1E7C961AFC4B +20241129002644 2 6 100 2047 2 D62BDAF38E54FDFF0C708C3A9D5A49ADD950102DDCE4017B0B90CB32FE8736EE054C70F834E7196596829647330A22260674F15C124DFD61BD6304ED8DAA2BAF03E37A43714575DC4E50D30EB36E31B994DA55D6CCE62E854F087F56587D5C04E2907BF39AE275B9B5E0353A50453DA96E714E11E5A00F72680903B482731C04A0791B018B4FDB5D2EA1DE235C20CF300B0C1CED91A218390A09DF78C1877BB35E0D92D22ED647E32EA5C9F877B589B4A8F7F6685715AC5E0E5F93DB5671E028A9DFE1C66662C94A47C19FE0ED1B9C9BCBEA281F705C358F792091DE4A2F110B6B68E4AB15D6B30C59C8850D1E436BDDABADF17ED1E8881271CD1E7C96F5DDA3 +20241129002646 2 6 100 2047 5 D62BDAF38E54FDFF0C708C3A9D5A49ADD950102DDCE4017B0B90CB32FE8736EE054C70F834E7196596829647330A22260674F15C124DFD61BD6304ED8DAA2BAF03E37A43714575DC4E50D30EB36E31B994DA55D6CCE62E854F087F56587D5C04E2907BF39AE275B9B5E0353A50453DA96E714E11E5A00F72680903B482731C04A0791B018B4FDB5D2EA1DE235C20CF300B0C1CED91A218390A09DF78C1877BB35E0D92D22ED647E32EA5C9F877B589B4A8F7F6685715AC5E0E5F93DB5671E028A9DFE1C66662C94A47C19FE0ED1B9C9BCBEA281F705C358F792091DE4A2F110B6B68E4AB15D6B30C59C8850D1E436BDDABADF17ED1E8881271CD1E7C9701A557 +20241129003212 2 6 100 3071 5 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD31A6F92F +20241129003232 2 6 100 3071 2 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD31E1E02B +20241129003238 2 6 100 3071 5 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD31F02307 +20241129003247 2 6 100 3071 2 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD32089003 +20241129003331 2 6 100 3071 2 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD328EF3EB +20241129003450 2 6 100 3071 5 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD3388738F +20241129003549 2 6 100 3071 5 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD344433C7 +20241129003558 2 6 100 3071 2 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD345EB43B +20241129003708 2 6 100 3071 2 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD353F77AB +20241129003723 2 6 100 3071 5 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD356DF4FF +20241129003747 2 6 100 3071 2 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD35B352CB +20241129003812 2 6 100 3071 2 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD36020023 +20241129003842 2 6 100 3071 5 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD3660A2C7 +20241129003859 2 6 100 3071 2 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD368F747B +20241129003902 2 6 100 3071 2 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD3695A29B +20241129003921 2 6 100 3071 2 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD36C9F673 +20241129004005 2 6 100 3071 5 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD3753CA0F +20241129004008 2 6 100 3071 2 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD3758F683 +20241129004208 2 6 100 3071 2 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD38E3CD3B +20241129004221 2 6 100 3071 2 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD390C377B +20241129004322 2 6 100 3071 2 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD39CE5ACB +20241129004335 2 6 100 3071 2 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD39EC486B +20241129004341 2 6 100 3071 5 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD39F7B37F +20241129004348 2 6 100 3071 5 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD3A089907 +20241129004413 2 6 100 3071 2 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD3A5136DB +20241129004447 2 6 100 3071 2 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD3ABE89AB +20241129004614 2 6 100 3071 2 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD3BD9A0DB +20241129004627 2 6 100 3071 2 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD3BFC1AC3 +20241129004630 2 6 100 3071 2 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD3BFE5DDB +20241129004648 2 6 100 3071 2 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD3C3863FB +20241129004754 2 6 100 3071 5 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD3D09984F +20241129004835 2 6 100 3071 2 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD3D875973 +20241129004842 2 6 100 3071 2 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD3D958953 +20241129004906 2 6 100 3071 2 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD3DDF57FB +20241129005005 2 6 100 3071 2 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD3E9E3063 +20241129005036 2 6 100 3071 2 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD3EFEEAC3 +20241129005052 2 6 100 3071 2 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD3F2A5E03 +20241129005537 2 6 100 3071 5 C94F41FDB4E54DBDD1C7A49F586104E6D74F4CD07A2B9730A4FB5D40C24AB929C55B955144ADC62AEF2DF80D151E4F20E946F69C9B7AC7F01D1A916F3C1D23984DAF12A5CF18C5FDD9922AE0DBFFB31E9EAC765DCF315EBB0524E8B9246BC97169BE71440DF64D5884F63D9ECC8C96E312169E71BC1D25DCE1AE142F6C4D265BA36CBAAC0860E6C83C26B287461F4FE90C5D2CAF4A87937E12407CC632618086D75FB5A17ED87F8EEE71893A6890E74AA378BD6B91CD4CF264F0826110494D2492F6A45567AB8FF4C28142582D3E66E9D3961881DFA1877E2EC993E31A35017C8291B0C74BCF285F94BC6E8B5D0EDEE7F571BEDDEB32184688CB221D1E42A74657FE9AC83679E51B925D617069FF259975C40D370D0D51F18D1C17358B9C197B00893AEE90BA06517787E8C4884E783F2A4B7633C62E7843B743688FA6296F11A6F4D584C2905EADA2076D289449F5DB07E2788F021D435DD188563CDAA1C89B0E7E87017788634AF18CAD9ADB8BA18E80C5BD0BE1424FF9135B07DD42DD9C2F +20241129005637 2 6 100 3071 5 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB14E5B5E8F +20241129005819 2 6 100 3071 2 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB14FA714FB +20241129010001 2 6 100 3071 2 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB150F56483 +20241129010010 2 6 100 3071 2 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB1510A25CB +20241129010049 2 6 100 3071 2 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB15189B8EB +20241129010057 2 6 100 3071 2 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB1519DABAB +20241129010104 2 6 100 3071 2 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB151AE01C3 +20241129010114 2 6 100 3071 5 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB151C91AA7 +20241129010216 2 6 100 3071 5 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB1528CD42F +20241129010239 2 6 100 3071 2 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB152D65F33 +20241129010312 2 6 100 3071 5 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB1533E97D7 +20241129010433 2 6 100 3071 5 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB1544811A7 +20241129010523 2 6 100 3071 5 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB154E65E7F +20241129010605 2 6 100 3071 2 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB1556C058B +20241129010625 2 6 100 3071 5 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB155A73F37 +20241129010718 2 6 100 3071 5 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB156533A8F +20241129010827 2 6 100 3071 2 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB15733560B +20241129010830 2 6 100 3071 2 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB15735A50B +20241129011308 2 6 100 3071 5 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB15AD92877 +20241129011325 2 6 100 3071 5 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB15B0BC97F +20241129011417 2 6 100 3071 2 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB15BB2F9E3 +20241129011431 2 6 100 3071 2 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB15BDC12E3 +20241129011445 2 6 100 3071 2 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB15C01B8F3 +20241129011511 2 6 100 3071 5 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB15C508C4F +20241129011527 2 6 100 3071 2 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB15C8110EB +20241129011531 2 6 100 3071 2 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB15C85C703 +20241129011741 2 6 100 3071 2 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB15E32BC9B +20241129011800 2 6 100 3071 2 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB15E6A8F93 +20241129011821 2 6 100 3071 5 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB15EACC9EF +20241129011823 2 6 100 3071 5 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB15EAE50DF +20241129011852 2 6 100 3071 2 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB15F060CCB +20241129011901 2 6 100 3071 2 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB15F1D181B +20241129011909 2 6 100 3071 2 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB15F313CBB +20241129011934 2 6 100 3071 2 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB15F7E3BAB +20241129011958 2 6 100 3071 2 F72B9D5B478FC38253834B862A5C515BA6212BAD106C43D243A9D021FF22434E6A1EA03FBACFA23A6FC66FE5C68B40013BA6D15844D35AA2127408DE731CCA98380661EE30E2480E9DB14A8EB484BF564838B45678ECB78800E41E499307253A0E4462C7E119ECAA096D496FF72C5CB823C5C38CC165B9EE0B5307005F9FE72FE34EF3C2EF456A3A4561245680205533E2C2DC31816DDFFB036922109B985F291F7ADDCA11FADD48E7D20C9F8D0E8AE073C4DD7269B1EF46ACC81BE52A053EFE3BEAB1BFA3822A10ABF2C95B27D406BF960FAA48A79D332A7138AAAB8828B1BD11BCE47ACFE934887A2B2DC6C7061EF8412B4912925FD5A9CE787C434B3FD5B39FA863EDA542574E22331F98E74F69283A9A8F9330FE597B1EE96E37C8DEBB0E861213F3BF5281F3753CC16B2AF1EAB12540517E0482FDF47C92B66C4CD5FA5C8725956DB4C5F435EFC44D2ABD17A078687DD7716CAC4683729BD6211E0CBADA144F28932906724F3B96501D1A897C088607B522F8C7586DAFC64CB15FCAB1D3 +20241129012819 2 6 100 4095 5 D14DC7A20FAA787E8E505E1CCA5C3EC8C5344CE26B9E5E776858C7048EECCB2CE278073BA42E21E4512A91D9A94F6460E86A914FC8D560A29DDC6B3E45CA1F9E8C5C52057BAF6A992E0C04192CEDF05010493D9CED8F97D3891C7DB13865BCD4BC19EA746AFB39E7AC2D60A32D9B77EECFFA53E7022137B7587E5D18E2B100845108104A79B878405B8900A0837BE74494F45DF726B88990607580414CEA1358A78BF832447919460F37395E69BC30E81983D60BB71D4E86164317138B99B545416467AA1F8592A16CEA1B050D2554487A749408A8339FFCA98A5F23D4EEF7A4254C6E56BFD6B95AD3C822B83324BEC5DD85A7064C6233899F7C6D00749D9DEDBAD9ED72CCC9CF154EF3989752DF907B24E587CD6B29A22846CD1B9623A3AEF69D191E8C048046FBCA2BC2C2A0883C8738F72D612745419080B7D72D8EC2E696CF5CB5EB6F23A9BBFF4BDD129970E881DBAA81E2F1A1445C773D4445ED516D1D954C64593DF72B7B31810B7493B8334F57E79FB26554EE1B4E7B7BDAA2C707D8E4798549DB60AE0A064CA8C6AA36021EB1657E72810E676D0F312325F2FAF956DC336D6B8E1496553362292D98225D61A74827C43FD4B4E0242B19FECBA7C102940C24AC56BB287C739608441EAA2EAA6DE0D1323E6D45204A1FF07BC3D3A48F954597EE865531D8A32C1DC2A3A48C8A0D47BE16919C3DF9E0514CE61ABEADA7 +20241129013011 2 6 100 4095 2 D14DC7A20FAA787E8E505E1CCA5C3EC8C5344CE26B9E5E776858C7048EECCB2CE278073BA42E21E4512A91D9A94F6460E86A914FC8D560A29DDC6B3E45CA1F9E8C5C52057BAF6A992E0C04192CEDF05010493D9CED8F97D3891C7DB13865BCD4BC19EA746AFB39E7AC2D60A32D9B77EECFFA53E7022137B7587E5D18E2B100845108104A79B878405B8900A0837BE74494F45DF726B88990607580414CEA1358A78BF832447919460F37395E69BC30E81983D60BB71D4E86164317138B99B545416467AA1F8592A16CEA1B050D2554487A749408A8339FFCA98A5F23D4EEF7A4254C6E56BFD6B95AD3C822B83324BEC5DD85A7064C6233899F7C6D00749D9DEDBAD9ED72CCC9CF154EF3989752DF907B24E587CD6B29A22846CD1B9623A3AEF69D191E8C048046FBCA2BC2C2A0883C8738F72D612745419080B7D72D8EC2E696CF5CB5EB6F23A9BBFF4BDD129970E881DBAA81E2F1A1445C773D4445ED516D1D954C64593DF72B7B31810B7493B8334F57E79FB26554EE1B4E7B7BDAA2C707D8E4798549DB60AE0A064CA8C6AA36021EB1657E72810E676D0F312325F2FAF956DC336D6B8E1496553362292D98225D61A74827C43FD4B4E0242B19FECBA7C102940C24AC56BB287C739608441EAA2EAA6DE0D1323E6D45204A1FF07BC3D3A48F954597EE865531D8A32C1DC2A3A48C8A0D47BE16919C3DF9E0514CE61B67DAEB +20241129013110 2 6 100 4095 2 D14DC7A20FAA787E8E505E1CCA5C3EC8C5344CE26B9E5E776858C7048EECCB2CE278073BA42E21E4512A91D9A94F6460E86A914FC8D560A29DDC6B3E45CA1F9E8C5C52057BAF6A992E0C04192CEDF05010493D9CED8F97D3891C7DB13865BCD4BC19EA746AFB39E7AC2D60A32D9B77EECFFA53E7022137B7587E5D18E2B100845108104A79B878405B8900A0837BE74494F45DF726B88990607580414CEA1358A78BF832447919460F37395E69BC30E81983D60BB71D4E86164317138B99B545416467AA1F8592A16CEA1B050D2554487A749408A8339FFCA98A5F23D4EEF7A4254C6E56BFD6B95AD3C822B83324BEC5DD85A7064C6233899F7C6D00749D9DEDBAD9ED72CCC9CF154EF3989752DF907B24E587CD6B29A22846CD1B9623A3AEF69D191E8C048046FBCA2BC2C2A0883C8738F72D612745419080B7D72D8EC2E696CF5CB5EB6F23A9BBFF4BDD129970E881DBAA81E2F1A1445C773D4445ED516D1D954C64593DF72B7B31810B7493B8334F57E79FB26554EE1B4E7B7BDAA2C707D8E4798549DB60AE0A064CA8C6AA36021EB1657E72810E676D0F312325F2FAF956DC336D6B8E1496553362292D98225D61A74827C43FD4B4E0242B19FECBA7C102940C24AC56BB287C739608441EAA2EAA6DE0D1323E6D45204A1FF07BC3D3A48F954597EE865531D8A32C1DC2A3A48C8A0D47BE16919C3DF9E0514CE61BBE4D2B +20241129013508 2 6 100 4095 5 D14DC7A20FAA787E8E505E1CCA5C3EC8C5344CE26B9E5E776858C7048EECCB2CE278073BA42E21E4512A91D9A94F6460E86A914FC8D560A29DDC6B3E45CA1F9E8C5C52057BAF6A992E0C04192CEDF05010493D9CED8F97D3891C7DB13865BCD4BC19EA746AFB39E7AC2D60A32D9B77EECFFA53E7022137B7587E5D18E2B100845108104A79B878405B8900A0837BE74494F45DF726B88990607580414CEA1358A78BF832447919460F37395E69BC30E81983D60BB71D4E86164317138B99B545416467AA1F8592A16CEA1B050D2554487A749408A8339FFCA98A5F23D4EEF7A4254C6E56BFD6B95AD3C822B83324BEC5DD85A7064C6233899F7C6D00749D9DEDBAD9ED72CCC9CF154EF3989752DF907B24E587CD6B29A22846CD1B9623A3AEF69D191E8C048046FBCA2BC2C2A0883C8738F72D612745419080B7D72D8EC2E696CF5CB5EB6F23A9BBFF4BDD129970E881DBAA81E2F1A1445C773D4445ED516D1D954C64593DF72B7B31810B7493B8334F57E79FB26554EE1B4E7B7BDAA2C707D8E4798549DB60AE0A064CA8C6AA36021EB1657E72810E676D0F312325F2FAF956DC336D6B8E1496553362292D98225D61A74827C43FD4B4E0242B19FECBA7C102940C24AC56BB287C739608441EAA2EAA6DE0D1323E6D45204A1FF07BC3D3A48F954597EE865531D8A32C1DC2A3A48C8A0D47BE16919C3DF9E0514CE61D3A05EF +20241129013753 2 6 100 4095 5 D14DC7A20FAA787E8E505E1CCA5C3EC8C5344CE26B9E5E776858C7048EECCB2CE278073BA42E21E4512A91D9A94F6460E86A914FC8D560A29DDC6B3E45CA1F9E8C5C52057BAF6A992E0C04192CEDF05010493D9CED8F97D3891C7DB13865BCD4BC19EA746AFB39E7AC2D60A32D9B77EECFFA53E7022137B7587E5D18E2B100845108104A79B878405B8900A0837BE74494F45DF726B88990607580414CEA1358A78BF832447919460F37395E69BC30E81983D60BB71D4E86164317138B99B545416467AA1F8592A16CEA1B050D2554487A749408A8339FFCA98A5F23D4EEF7A4254C6E56BFD6B95AD3C822B83324BEC5DD85A7064C6233899F7C6D00749D9DEDBAD9ED72CCC9CF154EF3989752DF907B24E587CD6B29A22846CD1B9623A3AEF69D191E8C048046FBCA2BC2C2A0883C8738F72D612745419080B7D72D8EC2E696CF5CB5EB6F23A9BBFF4BDD129970E881DBAA81E2F1A1445C773D4445ED516D1D954C64593DF72B7B31810B7493B8334F57E79FB26554EE1B4E7B7BDAA2C707D8E4798549DB60AE0A064CA8C6AA36021EB1657E72810E676D0F312325F2FAF956DC336D6B8E1496553362292D98225D61A74827C43FD4B4E0242B19FECBA7C102940C24AC56BB287C739608441EAA2EAA6DE0D1323E6D45204A1FF07BC3D3A48F954597EE865531D8A32C1DC2A3A48C8A0D47BE16919C3DF9E0514CE61E425677 +20241129014404 2 6 100 4095 5 D14DC7A20FAA787E8E505E1CCA5C3EC8C5344CE26B9E5E776858C7048EECCB2CE278073BA42E21E4512A91D9A94F6460E86A914FC8D560A29DDC6B3E45CA1F9E8C5C52057BAF6A992E0C04192CEDF05010493D9CED8F97D3891C7DB13865BCD4BC19EA746AFB39E7AC2D60A32D9B77EECFFA53E7022137B7587E5D18E2B100845108104A79B878405B8900A0837BE74494F45DF726B88990607580414CEA1358A78BF832447919460F37395E69BC30E81983D60BB71D4E86164317138B99B545416467AA1F8592A16CEA1B050D2554487A749408A8339FFCA98A5F23D4EEF7A4254C6E56BFD6B95AD3C822B83324BEC5DD85A7064C6233899F7C6D00749D9DEDBAD9ED72CCC9CF154EF3989752DF907B24E587CD6B29A22846CD1B9623A3AEF69D191E8C048046FBCA2BC2C2A0883C8738F72D612745419080B7D72D8EC2E696CF5CB5EB6F23A9BBFF4BDD129970E881DBAA81E2F1A1445C773D4445ED516D1D954C64593DF72B7B31810B7493B8334F57E79FB26554EE1B4E7B7BDAA2C707D8E4798549DB60AE0A064CA8C6AA36021EB1657E72810E676D0F312325F2FAF956DC336D6B8E1496553362292D98225D61A74827C43FD4B4E0242B19FECBA7C102940C24AC56BB287C739608441EAA2EAA6DE0D1323E6D45204A1FF07BC3D3A48F954597EE865531D8A32C1DC2A3A48C8A0D47BE16919C3DF9E0514CE6208D8717 +20241129014416 2 6 100 4095 2 D14DC7A20FAA787E8E505E1CCA5C3EC8C5344CE26B9E5E776858C7048EECCB2CE278073BA42E21E4512A91D9A94F6460E86A914FC8D560A29DDC6B3E45CA1F9E8C5C52057BAF6A992E0C04192CEDF05010493D9CED8F97D3891C7DB13865BCD4BC19EA746AFB39E7AC2D60A32D9B77EECFFA53E7022137B7587E5D18E2B100845108104A79B878405B8900A0837BE74494F45DF726B88990607580414CEA1358A78BF832447919460F37395E69BC30E81983D60BB71D4E86164317138B99B545416467AA1F8592A16CEA1B050D2554487A749408A8339FFCA98A5F23D4EEF7A4254C6E56BFD6B95AD3C822B83324BEC5DD85A7064C6233899F7C6D00749D9DEDBAD9ED72CCC9CF154EF3989752DF907B24E587CD6B29A22846CD1B9623A3AEF69D191E8C048046FBCA2BC2C2A0883C8738F72D612745419080B7D72D8EC2E696CF5CB5EB6F23A9BBFF4BDD129970E881DBAA81E2F1A1445C773D4445ED516D1D954C64593DF72B7B31810B7493B8334F57E79FB26554EE1B4E7B7BDAA2C707D8E4798549DB60AE0A064CA8C6AA36021EB1657E72810E676D0F312325F2FAF956DC336D6B8E1496553362292D98225D61A74827C43FD4B4E0242B19FECBA7C102940C24AC56BB287C739608441EAA2EAA6DE0D1323E6D45204A1FF07BC3D3A48F954597EE865531D8A32C1DC2A3A48C8A0D47BE16919C3DF9E0514CE6209BD93B +20241129014459 2 6 100 4095 5 D14DC7A20FAA787E8E505E1CCA5C3EC8C5344CE26B9E5E776858C7048EECCB2CE278073BA42E21E4512A91D9A94F6460E86A914FC8D560A29DDC6B3E45CA1F9E8C5C52057BAF6A992E0C04192CEDF05010493D9CED8F97D3891C7DB13865BCD4BC19EA746AFB39E7AC2D60A32D9B77EECFFA53E7022137B7587E5D18E2B100845108104A79B878405B8900A0837BE74494F45DF726B88990607580414CEA1358A78BF832447919460F37395E69BC30E81983D60BB71D4E86164317138B99B545416467AA1F8592A16CEA1B050D2554487A749408A8339FFCA98A5F23D4EEF7A4254C6E56BFD6B95AD3C822B83324BEC5DD85A7064C6233899F7C6D00749D9DEDBAD9ED72CCC9CF154EF3989752DF907B24E587CD6B29A22846CD1B9623A3AEF69D191E8C048046FBCA2BC2C2A0883C8738F72D612745419080B7D72D8EC2E696CF5CB5EB6F23A9BBFF4BDD129970E881DBAA81E2F1A1445C773D4445ED516D1D954C64593DF72B7B31810B7493B8334F57E79FB26554EE1B4E7B7BDAA2C707D8E4798549DB60AE0A064CA8C6AA36021EB1657E72810E676D0F312325F2FAF956DC336D6B8E1496553362292D98225D61A74827C43FD4B4E0242B19FECBA7C102940C24AC56BB287C739608441EAA2EAA6DE0D1323E6D45204A1FF07BC3D3A48F954597EE865531D8A32C1DC2A3A48C8A0D47BE16919C3DF9E0514CE620D787FF +20241129015136 2 6 100 4095 5 D14DC7A20FAA787E8E505E1CCA5C3EC8C5344CE26B9E5E776858C7048EECCB2CE278073BA42E21E4512A91D9A94F6460E86A914FC8D560A29DDC6B3E45CA1F9E8C5C52057BAF6A992E0C04192CEDF05010493D9CED8F97D3891C7DB13865BCD4BC19EA746AFB39E7AC2D60A32D9B77EECFFA53E7022137B7587E5D18E2B100845108104A79B878405B8900A0837BE74494F45DF726B88990607580414CEA1358A78BF832447919460F37395E69BC30E81983D60BB71D4E86164317138B99B545416467AA1F8592A16CEA1B050D2554487A749408A8339FFCA98A5F23D4EEF7A4254C6E56BFD6B95AD3C822B83324BEC5DD85A7064C6233899F7C6D00749D9DEDBAD9ED72CCC9CF154EF3989752DF907B24E587CD6B29A22846CD1B9623A3AEF69D191E8C048046FBCA2BC2C2A0883C8738F72D612745419080B7D72D8EC2E696CF5CB5EB6F23A9BBFF4BDD129970E881DBAA81E2F1A1445C773D4445ED516D1D954C64593DF72B7B31810B7493B8334F57E79FB26554EE1B4E7B7BDAA2C707D8E4798549DB60AE0A064CA8C6AA36021EB1657E72810E676D0F312325F2FAF956DC336D6B8E1496553362292D98225D61A74827C43FD4B4E0242B19FECBA7C102940C24AC56BB287C739608441EAA2EAA6DE0D1323E6D45204A1FF07BC3D3A48F954597EE865531D8A32C1DC2A3A48C8A0D47BE16919C3DF9E0514CE6235DF3D7 +20241129015320 2 6 100 4095 5 D14DC7A20FAA787E8E505E1CCA5C3EC8C5344CE26B9E5E776858C7048EECCB2CE278073BA42E21E4512A91D9A94F6460E86A914FC8D560A29DDC6B3E45CA1F9E8C5C52057BAF6A992E0C04192CEDF05010493D9CED8F97D3891C7DB13865BCD4BC19EA746AFB39E7AC2D60A32D9B77EECFFA53E7022137B7587E5D18E2B100845108104A79B878405B8900A0837BE74494F45DF726B88990607580414CEA1358A78BF832447919460F37395E69BC30E81983D60BB71D4E86164317138B99B545416467AA1F8592A16CEA1B050D2554487A749408A8339FFCA98A5F23D4EEF7A4254C6E56BFD6B95AD3C822B83324BEC5DD85A7064C6233899F7C6D00749D9DEDBAD9ED72CCC9CF154EF3989752DF907B24E587CD6B29A22846CD1B9623A3AEF69D191E8C048046FBCA2BC2C2A0883C8738F72D612745419080B7D72D8EC2E696CF5CB5EB6F23A9BBFF4BDD129970E881DBAA81E2F1A1445C773D4445ED516D1D954C64593DF72B7B31810B7493B8334F57E79FB26554EE1B4E7B7BDAA2C707D8E4798549DB60AE0A064CA8C6AA36021EB1657E72810E676D0F312325F2FAF956DC336D6B8E1496553362292D98225D61A74827C43FD4B4E0242B19FECBA7C102940C24AC56BB287C739608441EAA2EAA6DE0D1323E6D45204A1FF07BC3D3A48F954597EE865531D8A32C1DC2A3A48C8A0D47BE16919C3DF9E0514CE6240443EF +20241129015547 2 6 100 4095 5 D14DC7A20FAA787E8E505E1CCA5C3EC8C5344CE26B9E5E776858C7048EECCB2CE278073BA42E21E4512A91D9A94F6460E86A914FC8D560A29DDC6B3E45CA1F9E8C5C52057BAF6A992E0C04192CEDF05010493D9CED8F97D3891C7DB13865BCD4BC19EA746AFB39E7AC2D60A32D9B77EECFFA53E7022137B7587E5D18E2B100845108104A79B878405B8900A0837BE74494F45DF726B88990607580414CEA1358A78BF832447919460F37395E69BC30E81983D60BB71D4E86164317138B99B545416467AA1F8592A16CEA1B050D2554487A749408A8339FFCA98A5F23D4EEF7A4254C6E56BFD6B95AD3C822B83324BEC5DD85A7064C6233899F7C6D00749D9DEDBAD9ED72CCC9CF154EF3989752DF907B24E587CD6B29A22846CD1B9623A3AEF69D191E8C048046FBCA2BC2C2A0883C8738F72D612745419080B7D72D8EC2E696CF5CB5EB6F23A9BBFF4BDD129970E881DBAA81E2F1A1445C773D4445ED516D1D954C64593DF72B7B31810B7493B8334F57E79FB26554EE1B4E7B7BDAA2C707D8E4798549DB60AE0A064CA8C6AA36021EB1657E72810E676D0F312325F2FAF956DC336D6B8E1496553362292D98225D61A74827C43FD4B4E0242B19FECBA7C102940C24AC56BB287C739608441EAA2EAA6DE0D1323E6D45204A1FF07BC3D3A48F954597EE865531D8A32C1DC2A3A48C8A0D47BE16919C3DF9E0514CE624F1AF5F +20241129015908 2 6 100 4095 2 D14DC7A20FAA787E8E505E1CCA5C3EC8C5344CE26B9E5E776858C7048EECCB2CE278073BA42E21E4512A91D9A94F6460E86A914FC8D560A29DDC6B3E45CA1F9E8C5C52057BAF6A992E0C04192CEDF05010493D9CED8F97D3891C7DB13865BCD4BC19EA746AFB39E7AC2D60A32D9B77EECFFA53E7022137B7587E5D18E2B100845108104A79B878405B8900A0837BE74494F45DF726B88990607580414CEA1358A78BF832447919460F37395E69BC30E81983D60BB71D4E86164317138B99B545416467AA1F8592A16CEA1B050D2554487A749408A8339FFCA98A5F23D4EEF7A4254C6E56BFD6B95AD3C822B83324BEC5DD85A7064C6233899F7C6D00749D9DEDBAD9ED72CCC9CF154EF3989752DF907B24E587CD6B29A22846CD1B9623A3AEF69D191E8C048046FBCA2BC2C2A0883C8738F72D612745419080B7D72D8EC2E696CF5CB5EB6F23A9BBFF4BDD129970E881DBAA81E2F1A1445C773D4445ED516D1D954C64593DF72B7B31810B7493B8334F57E79FB26554EE1B4E7B7BDAA2C707D8E4798549DB60AE0A064CA8C6AA36021EB1657E72810E676D0F312325F2FAF956DC336D6B8E1496553362292D98225D61A74827C43FD4B4E0242B19FECBA7C102940C24AC56BB287C739608441EAA2EAA6DE0D1323E6D45204A1FF07BC3D3A48F954597EE865531D8A32C1DC2A3A48C8A0D47BE16919C3DF9E0514CE626346E0B +20241129020133 2 6 100 4095 2 D14DC7A20FAA787E8E505E1CCA5C3EC8C5344CE26B9E5E776858C7048EECCB2CE278073BA42E21E4512A91D9A94F6460E86A914FC8D560A29DDC6B3E45CA1F9E8C5C52057BAF6A992E0C04192CEDF05010493D9CED8F97D3891C7DB13865BCD4BC19EA746AFB39E7AC2D60A32D9B77EECFFA53E7022137B7587E5D18E2B100845108104A79B878405B8900A0837BE74494F45DF726B88990607580414CEA1358A78BF832447919460F37395E69BC30E81983D60BB71D4E86164317138B99B545416467AA1F8592A16CEA1B050D2554487A749408A8339FFCA98A5F23D4EEF7A4254C6E56BFD6B95AD3C822B83324BEC5DD85A7064C6233899F7C6D00749D9DEDBAD9ED72CCC9CF154EF3989752DF907B24E587CD6B29A22846CD1B9623A3AEF69D191E8C048046FBCA2BC2C2A0883C8738F72D612745419080B7D72D8EC2E696CF5CB5EB6F23A9BBFF4BDD129970E881DBAA81E2F1A1445C773D4445ED516D1D954C64593DF72B7B31810B7493B8334F57E79FB26554EE1B4E7B7BDAA2C707D8E4798549DB60AE0A064CA8C6AA36021EB1657E72810E676D0F312325F2FAF956DC336D6B8E1496553362292D98225D61A74827C43FD4B4E0242B19FECBA7C102940C24AC56BB287C739608441EAA2EAA6DE0D1323E6D45204A1FF07BC3D3A48F954597EE865531D8A32C1DC2A3A48C8A0D47BE16919C3DF9E0514CE6271DA71B +20241129020353 2 6 100 4095 2 D14DC7A20FAA787E8E505E1CCA5C3EC8C5344CE26B9E5E776858C7048EECCB2CE278073BA42E21E4512A91D9A94F6460E86A914FC8D560A29DDC6B3E45CA1F9E8C5C52057BAF6A992E0C04192CEDF05010493D9CED8F97D3891C7DB13865BCD4BC19EA746AFB39E7AC2D60A32D9B77EECFFA53E7022137B7587E5D18E2B100845108104A79B878405B8900A0837BE74494F45DF726B88990607580414CEA1358A78BF832447919460F37395E69BC30E81983D60BB71D4E86164317138B99B545416467AA1F8592A16CEA1B050D2554487A749408A8339FFCA98A5F23D4EEF7A4254C6E56BFD6B95AD3C822B83324BEC5DD85A7064C6233899F7C6D00749D9DEDBAD9ED72CCC9CF154EF3989752DF907B24E587CD6B29A22846CD1B9623A3AEF69D191E8C048046FBCA2BC2C2A0883C8738F72D612745419080B7D72D8EC2E696CF5CB5EB6F23A9BBFF4BDD129970E881DBAA81E2F1A1445C773D4445ED516D1D954C64593DF72B7B31810B7493B8334F57E79FB26554EE1B4E7B7BDAA2C707D8E4798549DB60AE0A064CA8C6AA36021EB1657E72810E676D0F312325F2FAF956DC336D6B8E1496553362292D98225D61A74827C43FD4B4E0242B19FECBA7C102940C24AC56BB287C739608441EAA2EAA6DE0D1323E6D45204A1FF07BC3D3A48F954597EE865531D8A32C1DC2A3A48C8A0D47BE16919C3DF9E0514CE627F5147B +20241129020617 2 6 100 4095 2 D14DC7A20FAA787E8E505E1CCA5C3EC8C5344CE26B9E5E776858C7048EECCB2CE278073BA42E21E4512A91D9A94F6460E86A914FC8D560A29DDC6B3E45CA1F9E8C5C52057BAF6A992E0C04192CEDF05010493D9CED8F97D3891C7DB13865BCD4BC19EA746AFB39E7AC2D60A32D9B77EECFFA53E7022137B7587E5D18E2B100845108104A79B878405B8900A0837BE74494F45DF726B88990607580414CEA1358A78BF832447919460F37395E69BC30E81983D60BB71D4E86164317138B99B545416467AA1F8592A16CEA1B050D2554487A749408A8339FFCA98A5F23D4EEF7A4254C6E56BFD6B95AD3C822B83324BEC5DD85A7064C6233899F7C6D00749D9DEDBAD9ED72CCC9CF154EF3989752DF907B24E587CD6B29A22846CD1B9623A3AEF69D191E8C048046FBCA2BC2C2A0883C8738F72D612745419080B7D72D8EC2E696CF5CB5EB6F23A9BBFF4BDD129970E881DBAA81E2F1A1445C773D4445ED516D1D954C64593DF72B7B31810B7493B8334F57E79FB26554EE1B4E7B7BDAA2C707D8E4798549DB60AE0A064CA8C6AA36021EB1657E72810E676D0F312325F2FAF956DC336D6B8E1496553362292D98225D61A74827C43FD4B4E0242B19FECBA7C102940C24AC56BB287C739608441EAA2EAA6DE0D1323E6D45204A1FF07BC3D3A48F954597EE865531D8A32C1DC2A3A48C8A0D47BE16919C3DF9E0514CE628DC3E63 +20241129021223 2 6 100 4095 2 D14DC7A20FAA787E8E505E1CCA5C3EC8C5344CE26B9E5E776858C7048EECCB2CE278073BA42E21E4512A91D9A94F6460E86A914FC8D560A29DDC6B3E45CA1F9E8C5C52057BAF6A992E0C04192CEDF05010493D9CED8F97D3891C7DB13865BCD4BC19EA746AFB39E7AC2D60A32D9B77EECFFA53E7022137B7587E5D18E2B100845108104A79B878405B8900A0837BE74494F45DF726B88990607580414CEA1358A78BF832447919460F37395E69BC30E81983D60BB71D4E86164317138B99B545416467AA1F8592A16CEA1B050D2554487A749408A8339FFCA98A5F23D4EEF7A4254C6E56BFD6B95AD3C822B83324BEC5DD85A7064C6233899F7C6D00749D9DEDBAD9ED72CCC9CF154EF3989752DF907B24E587CD6B29A22846CD1B9623A3AEF69D191E8C048046FBCA2BC2C2A0883C8738F72D612745419080B7D72D8EC2E696CF5CB5EB6F23A9BBFF4BDD129970E881DBAA81E2F1A1445C773D4445ED516D1D954C64593DF72B7B31810B7493B8334F57E79FB26554EE1B4E7B7BDAA2C707D8E4798549DB60AE0A064CA8C6AA36021EB1657E72810E676D0F312325F2FAF956DC336D6B8E1496553362292D98225D61A74827C43FD4B4E0242B19FECBA7C102940C24AC56BB287C739608441EAA2EAA6DE0D1323E6D45204A1FF07BC3D3A48F954597EE865531D8A32C1DC2A3A48C8A0D47BE16919C3DF9E0514CE62B25B8A3 +20241129021913 2 6 100 4095 5 D14DC7A20FAA787E8E505E1CCA5C3EC8C5344CE26B9E5E776858C7048EECCB2CE278073BA42E21E4512A91D9A94F6460E86A914FC8D560A29DDC6B3E45CA1F9E8C5C52057BAF6A992E0C04192CEDF05010493D9CED8F97D3891C7DB13865BCD4BC19EA746AFB39E7AC2D60A32D9B77EECFFA53E7022137B7587E5D18E2B100845108104A79B878405B8900A0837BE74494F45DF726B88990607580414CEA1358A78BF832447919460F37395E69BC30E81983D60BB71D4E86164317138B99B545416467AA1F8592A16CEA1B050D2554487A749408A8339FFCA98A5F23D4EEF7A4254C6E56BFD6B95AD3C822B83324BEC5DD85A7064C6233899F7C6D00749D9DEDBAD9ED72CCC9CF154EF3989752DF907B24E587CD6B29A22846CD1B9623A3AEF69D191E8C048046FBCA2BC2C2A0883C8738F72D612745419080B7D72D8EC2E696CF5CB5EB6F23A9BBFF4BDD129970E881DBAA81E2F1A1445C773D4445ED516D1D954C64593DF72B7B31810B7493B8334F57E79FB26554EE1B4E7B7BDAA2C707D8E4798549DB60AE0A064CA8C6AA36021EB1657E72810E676D0F312325F2FAF956DC336D6B8E1496553362292D98225D61A74827C43FD4B4E0242B19FECBA7C102940C24AC56BB287C739608441EAA2EAA6DE0D1323E6D45204A1FF07BC3D3A48F954597EE865531D8A32C1DC2A3A48C8A0D47BE16919C3DF9E0514CE62DC6E86F +20241129021949 2 6 100 4095 2 D14DC7A20FAA787E8E505E1CCA5C3EC8C5344CE26B9E5E776858C7048EECCB2CE278073BA42E21E4512A91D9A94F6460E86A914FC8D560A29DDC6B3E45CA1F9E8C5C52057BAF6A992E0C04192CEDF05010493D9CED8F97D3891C7DB13865BCD4BC19EA746AFB39E7AC2D60A32D9B77EECFFA53E7022137B7587E5D18E2B100845108104A79B878405B8900A0837BE74494F45DF726B88990607580414CEA1358A78BF832447919460F37395E69BC30E81983D60BB71D4E86164317138B99B545416467AA1F8592A16CEA1B050D2554487A749408A8339FFCA98A5F23D4EEF7A4254C6E56BFD6B95AD3C822B83324BEC5DD85A7064C6233899F7C6D00749D9DEDBAD9ED72CCC9CF154EF3989752DF907B24E587CD6B29A22846CD1B9623A3AEF69D191E8C048046FBCA2BC2C2A0883C8738F72D612745419080B7D72D8EC2E696CF5CB5EB6F23A9BBFF4BDD129970E881DBAA81E2F1A1445C773D4445ED516D1D954C64593DF72B7B31810B7493B8334F57E79FB26554EE1B4E7B7BDAA2C707D8E4798549DB60AE0A064CA8C6AA36021EB1657E72810E676D0F312325F2FAF956DC336D6B8E1496553362292D98225D61A74827C43FD4B4E0242B19FECBA7C102940C24AC56BB287C739608441EAA2EAA6DE0D1323E6D45204A1FF07BC3D3A48F954597EE865531D8A32C1DC2A3A48C8A0D47BE16919C3DF9E0514CE62DFA5673 +20241129022203 2 6 100 4095 5 D14DC7A20FAA787E8E505E1CCA5C3EC8C5344CE26B9E5E776858C7048EECCB2CE278073BA42E21E4512A91D9A94F6460E86A914FC8D560A29DDC6B3E45CA1F9E8C5C52057BAF6A992E0C04192CEDF05010493D9CED8F97D3891C7DB13865BCD4BC19EA746AFB39E7AC2D60A32D9B77EECFFA53E7022137B7587E5D18E2B100845108104A79B878405B8900A0837BE74494F45DF726B88990607580414CEA1358A78BF832447919460F37395E69BC30E81983D60BB71D4E86164317138B99B545416467AA1F8592A16CEA1B050D2554487A749408A8339FFCA98A5F23D4EEF7A4254C6E56BFD6B95AD3C822B83324BEC5DD85A7064C6233899F7C6D00749D9DEDBAD9ED72CCC9CF154EF3989752DF907B24E587CD6B29A22846CD1B9623A3AEF69D191E8C048046FBCA2BC2C2A0883C8738F72D612745419080B7D72D8EC2E696CF5CB5EB6F23A9BBFF4BDD129970E881DBAA81E2F1A1445C773D4445ED516D1D954C64593DF72B7B31810B7493B8334F57E79FB26554EE1B4E7B7BDAA2C707D8E4798549DB60AE0A064CA8C6AA36021EB1657E72810E676D0F312325F2FAF956DC336D6B8E1496553362292D98225D61A74827C43FD4B4E0242B19FECBA7C102940C24AC56BB287C739608441EAA2EAA6DE0D1323E6D45204A1FF07BC3D3A48F954597EE865531D8A32C1DC2A3A48C8A0D47BE16919C3DF9E0514CE62ED03D1F +20241129022443 2 6 100 4095 5 D14DC7A20FAA787E8E505E1CCA5C3EC8C5344CE26B9E5E776858C7048EECCB2CE278073BA42E21E4512A91D9A94F6460E86A914FC8D560A29DDC6B3E45CA1F9E8C5C52057BAF6A992E0C04192CEDF05010493D9CED8F97D3891C7DB13865BCD4BC19EA746AFB39E7AC2D60A32D9B77EECFFA53E7022137B7587E5D18E2B100845108104A79B878405B8900A0837BE74494F45DF726B88990607580414CEA1358A78BF832447919460F37395E69BC30E81983D60BB71D4E86164317138B99B545416467AA1F8592A16CEA1B050D2554487A749408A8339FFCA98A5F23D4EEF7A4254C6E56BFD6B95AD3C822B83324BEC5DD85A7064C6233899F7C6D00749D9DEDBAD9ED72CCC9CF154EF3989752DF907B24E587CD6B29A22846CD1B9623A3AEF69D191E8C048046FBCA2BC2C2A0883C8738F72D612745419080B7D72D8EC2E696CF5CB5EB6F23A9BBFF4BDD129970E881DBAA81E2F1A1445C773D4445ED516D1D954C64593DF72B7B31810B7493B8334F57E79FB26554EE1B4E7B7BDAA2C707D8E4798549DB60AE0A064CA8C6AA36021EB1657E72810E676D0F312325F2FAF956DC336D6B8E1496553362292D98225D61A74827C43FD4B4E0242B19FECBA7C102940C24AC56BB287C739608441EAA2EAA6DE0D1323E6D45204A1FF07BC3D3A48F954597EE865531D8A32C1DC2A3A48C8A0D47BE16919C3DF9E0514CE62FC9341F +20241129022708 2 6 100 4095 2 D14DC7A20FAA787E8E505E1CCA5C3EC8C5344CE26B9E5E776858C7048EECCB2CE278073BA42E21E4512A91D9A94F6460E86A914FC8D560A29DDC6B3E45CA1F9E8C5C52057BAF6A992E0C04192CEDF05010493D9CED8F97D3891C7DB13865BCD4BC19EA746AFB39E7AC2D60A32D9B77EECFFA53E7022137B7587E5D18E2B100845108104A79B878405B8900A0837BE74494F45DF726B88990607580414CEA1358A78BF832447919460F37395E69BC30E81983D60BB71D4E86164317138B99B545416467AA1F8592A16CEA1B050D2554487A749408A8339FFCA98A5F23D4EEF7A4254C6E56BFD6B95AD3C822B83324BEC5DD85A7064C6233899F7C6D00749D9DEDBAD9ED72CCC9CF154EF3989752DF907B24E587CD6B29A22846CD1B9623A3AEF69D191E8C048046FBCA2BC2C2A0883C8738F72D612745419080B7D72D8EC2E696CF5CB5EB6F23A9BBFF4BDD129970E881DBAA81E2F1A1445C773D4445ED516D1D954C64593DF72B7B31810B7493B8334F57E79FB26554EE1B4E7B7BDAA2C707D8E4798549DB60AE0A064CA8C6AA36021EB1657E72810E676D0F312325F2FAF956DC336D6B8E1496553362292D98225D61A74827C43FD4B4E0242B19FECBA7C102940C24AC56BB287C739608441EAA2EAA6DE0D1323E6D45204A1FF07BC3D3A48F954597EE865531D8A32C1DC2A3A48C8A0D47BE16919C3DF9E0514CE630ACA413 +20241129023102 2 6 100 4095 5 D14DC7A20FAA787E8E505E1CCA5C3EC8C5344CE26B9E5E776858C7048EECCB2CE278073BA42E21E4512A91D9A94F6460E86A914FC8D560A29DDC6B3E45CA1F9E8C5C52057BAF6A992E0C04192CEDF05010493D9CED8F97D3891C7DB13865BCD4BC19EA746AFB39E7AC2D60A32D9B77EECFFA53E7022137B7587E5D18E2B100845108104A79B878405B8900A0837BE74494F45DF726B88990607580414CEA1358A78BF832447919460F37395E69BC30E81983D60BB71D4E86164317138B99B545416467AA1F8592A16CEA1B050D2554487A749408A8339FFCA98A5F23D4EEF7A4254C6E56BFD6B95AD3C822B83324BEC5DD85A7064C6233899F7C6D00749D9DEDBAD9ED72CCC9CF154EF3989752DF907B24E587CD6B29A22846CD1B9623A3AEF69D191E8C048046FBCA2BC2C2A0883C8738F72D612745419080B7D72D8EC2E696CF5CB5EB6F23A9BBFF4BDD129970E881DBAA81E2F1A1445C773D4445ED516D1D954C64593DF72B7B31810B7493B8334F57E79FB26554EE1B4E7B7BDAA2C707D8E4798549DB60AE0A064CA8C6AA36021EB1657E72810E676D0F312325F2FAF956DC336D6B8E1496553362292D98225D61A74827C43FD4B4E0242B19FECBA7C102940C24AC56BB287C739608441EAA2EAA6DE0D1323E6D45204A1FF07BC3D3A48F954597EE865531D8A32C1DC2A3A48C8A0D47BE16919C3DF9E0514CE6322B2317 +20241129023226 2 6 100 4095 2 D14DC7A20FAA787E8E505E1CCA5C3EC8C5344CE26B9E5E776858C7048EECCB2CE278073BA42E21E4512A91D9A94F6460E86A914FC8D560A29DDC6B3E45CA1F9E8C5C52057BAF6A992E0C04192CEDF05010493D9CED8F97D3891C7DB13865BCD4BC19EA746AFB39E7AC2D60A32D9B77EECFFA53E7022137B7587E5D18E2B100845108104A79B878405B8900A0837BE74494F45DF726B88990607580414CEA1358A78BF832447919460F37395E69BC30E81983D60BB71D4E86164317138B99B545416467AA1F8592A16CEA1B050D2554487A749408A8339FFCA98A5F23D4EEF7A4254C6E56BFD6B95AD3C822B83324BEC5DD85A7064C6233899F7C6D00749D9DEDBAD9ED72CCC9CF154EF3989752DF907B24E587CD6B29A22846CD1B9623A3AEF69D191E8C048046FBCA2BC2C2A0883C8738F72D612745419080B7D72D8EC2E696CF5CB5EB6F23A9BBFF4BDD129970E881DBAA81E2F1A1445C773D4445ED516D1D954C64593DF72B7B31810B7493B8334F57E79FB26554EE1B4E7B7BDAA2C707D8E4798549DB60AE0A064CA8C6AA36021EB1657E72810E676D0F312325F2FAF956DC336D6B8E1496553362292D98225D61A74827C43FD4B4E0242B19FECBA7C102940C24AC56BB287C739608441EAA2EAA6DE0D1323E6D45204A1FF07BC3D3A48F954597EE865531D8A32C1DC2A3A48C8A0D47BE16919C3DF9E0514CE632AFA783 +20241129023234 2 6 100 4095 5 D14DC7A20FAA787E8E505E1CCA5C3EC8C5344CE26B9E5E776858C7048EECCB2CE278073BA42E21E4512A91D9A94F6460E86A914FC8D560A29DDC6B3E45CA1F9E8C5C52057BAF6A992E0C04192CEDF05010493D9CED8F97D3891C7DB13865BCD4BC19EA746AFB39E7AC2D60A32D9B77EECFFA53E7022137B7587E5D18E2B100845108104A79B878405B8900A0837BE74494F45DF726B88990607580414CEA1358A78BF832447919460F37395E69BC30E81983D60BB71D4E86164317138B99B545416467AA1F8592A16CEA1B050D2554487A749408A8339FFCA98A5F23D4EEF7A4254C6E56BFD6B95AD3C822B83324BEC5DD85A7064C6233899F7C6D00749D9DEDBAD9ED72CCC9CF154EF3989752DF907B24E587CD6B29A22846CD1B9623A3AEF69D191E8C048046FBCA2BC2C2A0883C8738F72D612745419080B7D72D8EC2E696CF5CB5EB6F23A9BBFF4BDD129970E881DBAA81E2F1A1445C773D4445ED516D1D954C64593DF72B7B31810B7493B8334F57E79FB26554EE1B4E7B7BDAA2C707D8E4798549DB60AE0A064CA8C6AA36021EB1657E72810E676D0F312325F2FAF956DC336D6B8E1496553362292D98225D61A74827C43FD4B4E0242B19FECBA7C102940C24AC56BB287C739608441EAA2EAA6DE0D1323E6D45204A1FF07BC3D3A48F954597EE865531D8A32C1DC2A3A48C8A0D47BE16919C3DF9E0514CE632B59A57 +20241129023429 2 6 100 4095 5 D14DC7A20FAA787E8E505E1CCA5C3EC8C5344CE26B9E5E776858C7048EECCB2CE278073BA42E21E4512A91D9A94F6460E86A914FC8D560A29DDC6B3E45CA1F9E8C5C52057BAF6A992E0C04192CEDF05010493D9CED8F97D3891C7DB13865BCD4BC19EA746AFB39E7AC2D60A32D9B77EECFFA53E7022137B7587E5D18E2B100845108104A79B878405B8900A0837BE74494F45DF726B88990607580414CEA1358A78BF832447919460F37395E69BC30E81983D60BB71D4E86164317138B99B545416467AA1F8592A16CEA1B050D2554487A749408A8339FFCA98A5F23D4EEF7A4254C6E56BFD6B95AD3C822B83324BEC5DD85A7064C6233899F7C6D00749D9DEDBAD9ED72CCC9CF154EF3989752DF907B24E587CD6B29A22846CD1B9623A3AEF69D191E8C048046FBCA2BC2C2A0883C8738F72D612745419080B7D72D8EC2E696CF5CB5EB6F23A9BBFF4BDD129970E881DBAA81E2F1A1445C773D4445ED516D1D954C64593DF72B7B31810B7493B8334F57E79FB26554EE1B4E7B7BDAA2C707D8E4798549DB60AE0A064CA8C6AA36021EB1657E72810E676D0F312325F2FAF956DC336D6B8E1496553362292D98225D61A74827C43FD4B4E0242B19FECBA7C102940C24AC56BB287C739608441EAA2EAA6DE0D1323E6D45204A1FF07BC3D3A48F954597EE865531D8A32C1DC2A3A48C8A0D47BE16919C3DF9E0514CE633681547 +20241129023526 2 6 100 4095 2 D14DC7A20FAA787E8E505E1CCA5C3EC8C5344CE26B9E5E776858C7048EECCB2CE278073BA42E21E4512A91D9A94F6460E86A914FC8D560A29DDC6B3E45CA1F9E8C5C52057BAF6A992E0C04192CEDF05010493D9CED8F97D3891C7DB13865BCD4BC19EA746AFB39E7AC2D60A32D9B77EECFFA53E7022137B7587E5D18E2B100845108104A79B878405B8900A0837BE74494F45DF726B88990607580414CEA1358A78BF832447919460F37395E69BC30E81983D60BB71D4E86164317138B99B545416467AA1F8592A16CEA1B050D2554487A749408A8339FFCA98A5F23D4EEF7A4254C6E56BFD6B95AD3C822B83324BEC5DD85A7064C6233899F7C6D00749D9DEDBAD9ED72CCC9CF154EF3989752DF907B24E587CD6B29A22846CD1B9623A3AEF69D191E8C048046FBCA2BC2C2A0883C8738F72D612745419080B7D72D8EC2E696CF5CB5EB6F23A9BBFF4BDD129970E881DBAA81E2F1A1445C773D4445ED516D1D954C64593DF72B7B31810B7493B8334F57E79FB26554EE1B4E7B7BDAA2C707D8E4798549DB60AE0A064CA8C6AA36021EB1657E72810E676D0F312325F2FAF956DC336D6B8E1496553362292D98225D61A74827C43FD4B4E0242B19FECBA7C102940C24AC56BB287C739608441EAA2EAA6DE0D1323E6D45204A1FF07BC3D3A48F954597EE865531D8A32C1DC2A3A48C8A0D47BE16919C3DF9E0514CE633BFD83B +20241129023744 2 6 100 4095 2 D14DC7A20FAA787E8E505E1CCA5C3EC8C5344CE26B9E5E776858C7048EECCB2CE278073BA42E21E4512A91D9A94F6460E86A914FC8D560A29DDC6B3E45CA1F9E8C5C52057BAF6A992E0C04192CEDF05010493D9CED8F97D3891C7DB13865BCD4BC19EA746AFB39E7AC2D60A32D9B77EECFFA53E7022137B7587E5D18E2B100845108104A79B878405B8900A0837BE74494F45DF726B88990607580414CEA1358A78BF832447919460F37395E69BC30E81983D60BB71D4E86164317138B99B545416467AA1F8592A16CEA1B050D2554487A749408A8339FFCA98A5F23D4EEF7A4254C6E56BFD6B95AD3C822B83324BEC5DD85A7064C6233899F7C6D00749D9DEDBAD9ED72CCC9CF154EF3989752DF907B24E587CD6B29A22846CD1B9623A3AEF69D191E8C048046FBCA2BC2C2A0883C8738F72D612745419080B7D72D8EC2E696CF5CB5EB6F23A9BBFF4BDD129970E881DBAA81E2F1A1445C773D4445ED516D1D954C64593DF72B7B31810B7493B8334F57E79FB26554EE1B4E7B7BDAA2C707D8E4798549DB60AE0A064CA8C6AA36021EB1657E72810E676D0F312325F2FAF956DC336D6B8E1496553362292D98225D61A74827C43FD4B4E0242B19FECBA7C102940C24AC56BB287C739608441EAA2EAA6DE0D1323E6D45204A1FF07BC3D3A48F954597EE865531D8A32C1DC2A3A48C8A0D47BE16919C3DF9E0514CE634998373 +20241129023820 2 6 100 4095 5 D14DC7A20FAA787E8E505E1CCA5C3EC8C5344CE26B9E5E776858C7048EECCB2CE278073BA42E21E4512A91D9A94F6460E86A914FC8D560A29DDC6B3E45CA1F9E8C5C52057BAF6A992E0C04192CEDF05010493D9CED8F97D3891C7DB13865BCD4BC19EA746AFB39E7AC2D60A32D9B77EECFFA53E7022137B7587E5D18E2B100845108104A79B878405B8900A0837BE74494F45DF726B88990607580414CEA1358A78BF832447919460F37395E69BC30E81983D60BB71D4E86164317138B99B545416467AA1F8592A16CEA1B050D2554487A749408A8339FFCA98A5F23D4EEF7A4254C6E56BFD6B95AD3C822B83324BEC5DD85A7064C6233899F7C6D00749D9DEDBAD9ED72CCC9CF154EF3989752DF907B24E587CD6B29A22846CD1B9623A3AEF69D191E8C048046FBCA2BC2C2A0883C8738F72D612745419080B7D72D8EC2E696CF5CB5EB6F23A9BBFF4BDD129970E881DBAA81E2F1A1445C773D4445ED516D1D954C64593DF72B7B31810B7493B8334F57E79FB26554EE1B4E7B7BDAA2C707D8E4798549DB60AE0A064CA8C6AA36021EB1657E72810E676D0F312325F2FAF956DC336D6B8E1496553362292D98225D61A74827C43FD4B4E0242B19FECBA7C102940C24AC56BB287C739608441EAA2EAA6DE0D1323E6D45204A1FF07BC3D3A48F954597EE865531D8A32C1DC2A3A48C8A0D47BE16919C3DF9E0514CE634CA05CF +20241129023919 2 6 100 4095 2 D14DC7A20FAA787E8E505E1CCA5C3EC8C5344CE26B9E5E776858C7048EECCB2CE278073BA42E21E4512A91D9A94F6460E86A914FC8D560A29DDC6B3E45CA1F9E8C5C52057BAF6A992E0C04192CEDF05010493D9CED8F97D3891C7DB13865BCD4BC19EA746AFB39E7AC2D60A32D9B77EECFFA53E7022137B7587E5D18E2B100845108104A79B878405B8900A0837BE74494F45DF726B88990607580414CEA1358A78BF832447919460F37395E69BC30E81983D60BB71D4E86164317138B99B545416467AA1F8592A16CEA1B050D2554487A749408A8339FFCA98A5F23D4EEF7A4254C6E56BFD6B95AD3C822B83324BEC5DD85A7064C6233899F7C6D00749D9DEDBAD9ED72CCC9CF154EF3989752DF907B24E587CD6B29A22846CD1B9623A3AEF69D191E8C048046FBCA2BC2C2A0883C8738F72D612745419080B7D72D8EC2E696CF5CB5EB6F23A9BBFF4BDD129970E881DBAA81E2F1A1445C773D4445ED516D1D954C64593DF72B7B31810B7493B8334F57E79FB26554EE1B4E7B7BDAA2C707D8E4798549DB60AE0A064CA8C6AA36021EB1657E72810E676D0F312325F2FAF956DC336D6B8E1496553362292D98225D61A74827C43FD4B4E0242B19FECBA7C102940C24AC56BB287C739608441EAA2EAA6DE0D1323E6D45204A1FF07BC3D3A48F954597EE865531D8A32C1DC2A3A48C8A0D47BE16919C3DF9E0514CE635285DD3 +20241129024116 2 6 100 4095 5 D14DC7A20FAA787E8E505E1CCA5C3EC8C5344CE26B9E5E776858C7048EECCB2CE278073BA42E21E4512A91D9A94F6460E86A914FC8D560A29DDC6B3E45CA1F9E8C5C52057BAF6A992E0C04192CEDF05010493D9CED8F97D3891C7DB13865BCD4BC19EA746AFB39E7AC2D60A32D9B77EECFFA53E7022137B7587E5D18E2B100845108104A79B878405B8900A0837BE74494F45DF726B88990607580414CEA1358A78BF832447919460F37395E69BC30E81983D60BB71D4E86164317138B99B545416467AA1F8592A16CEA1B050D2554487A749408A8339FFCA98A5F23D4EEF7A4254C6E56BFD6B95AD3C822B83324BEC5DD85A7064C6233899F7C6D00749D9DEDBAD9ED72CCC9CF154EF3989752DF907B24E587CD6B29A22846CD1B9623A3AEF69D191E8C048046FBCA2BC2C2A0883C8738F72D612745419080B7D72D8EC2E696CF5CB5EB6F23A9BBFF4BDD129970E881DBAA81E2F1A1445C773D4445ED516D1D954C64593DF72B7B31810B7493B8334F57E79FB26554EE1B4E7B7BDAA2C707D8E4798549DB60AE0A064CA8C6AA36021EB1657E72810E676D0F312325F2FAF956DC336D6B8E1496553362292D98225D61A74827C43FD4B4E0242B19FECBA7C102940C24AC56BB287C739608441EAA2EAA6DE0D1323E6D45204A1FF07BC3D3A48F954597EE865531D8A32C1DC2A3A48C8A0D47BE16919C3DF9E0514CE635E04407 +20241129024436 2 6 100 4095 5 D14DC7A20FAA787E8E505E1CCA5C3EC8C5344CE26B9E5E776858C7048EECCB2CE278073BA42E21E4512A91D9A94F6460E86A914FC8D560A29DDC6B3E45CA1F9E8C5C52057BAF6A992E0C04192CEDF05010493D9CED8F97D3891C7DB13865BCD4BC19EA746AFB39E7AC2D60A32D9B77EECFFA53E7022137B7587E5D18E2B100845108104A79B878405B8900A0837BE74494F45DF726B88990607580414CEA1358A78BF832447919460F37395E69BC30E81983D60BB71D4E86164317138B99B545416467AA1F8592A16CEA1B050D2554487A749408A8339FFCA98A5F23D4EEF7A4254C6E56BFD6B95AD3C822B83324BEC5DD85A7064C6233899F7C6D00749D9DEDBAD9ED72CCC9CF154EF3989752DF907B24E587CD6B29A22846CD1B9623A3AEF69D191E8C048046FBCA2BC2C2A0883C8738F72D612745419080B7D72D8EC2E696CF5CB5EB6F23A9BBFF4BDD129970E881DBAA81E2F1A1445C773D4445ED516D1D954C64593DF72B7B31810B7493B8334F57E79FB26554EE1B4E7B7BDAA2C707D8E4798549DB60AE0A064CA8C6AA36021EB1657E72810E676D0F312325F2FAF956DC336D6B8E1496553362292D98225D61A74827C43FD4B4E0242B19FECBA7C102940C24AC56BB287C739608441EAA2EAA6DE0D1323E6D45204A1FF07BC3D3A48F954597EE865531D8A32C1DC2A3A48C8A0D47BE16919C3DF9E0514CE637222687 +20241129024611 2 6 100 4095 5 D14DC7A20FAA787E8E505E1CCA5C3EC8C5344CE26B9E5E776858C7048EECCB2CE278073BA42E21E4512A91D9A94F6460E86A914FC8D560A29DDC6B3E45CA1F9E8C5C52057BAF6A992E0C04192CEDF05010493D9CED8F97D3891C7DB13865BCD4BC19EA746AFB39E7AC2D60A32D9B77EECFFA53E7022137B7587E5D18E2B100845108104A79B878405B8900A0837BE74494F45DF726B88990607580414CEA1358A78BF832447919460F37395E69BC30E81983D60BB71D4E86164317138B99B545416467AA1F8592A16CEA1B050D2554487A749408A8339FFCA98A5F23D4EEF7A4254C6E56BFD6B95AD3C822B83324BEC5DD85A7064C6233899F7C6D00749D9DEDBAD9ED72CCC9CF154EF3989752DF907B24E587CD6B29A22846CD1B9623A3AEF69D191E8C048046FBCA2BC2C2A0883C8738F72D612745419080B7D72D8EC2E696CF5CB5EB6F23A9BBFF4BDD129970E881DBAA81E2F1A1445C773D4445ED516D1D954C64593DF72B7B31810B7493B8334F57E79FB26554EE1B4E7B7BDAA2C707D8E4798549DB60AE0A064CA8C6AA36021EB1657E72810E676D0F312325F2FAF956DC336D6B8E1496553362292D98225D61A74827C43FD4B4E0242B19FECBA7C102940C24AC56BB287C739608441EAA2EAA6DE0D1323E6D45204A1FF07BC3D3A48F954597EE865531D8A32C1DC2A3A48C8A0D47BE16919C3DF9E0514CE637B833A7 +20241129024935 2 6 100 4095 2 D14DC7A20FAA787E8E505E1CCA5C3EC8C5344CE26B9E5E776858C7048EECCB2CE278073BA42E21E4512A91D9A94F6460E86A914FC8D560A29DDC6B3E45CA1F9E8C5C52057BAF6A992E0C04192CEDF05010493D9CED8F97D3891C7DB13865BCD4BC19EA746AFB39E7AC2D60A32D9B77EECFFA53E7022137B7587E5D18E2B100845108104A79B878405B8900A0837BE74494F45DF726B88990607580414CEA1358A78BF832447919460F37395E69BC30E81983D60BB71D4E86164317138B99B545416467AA1F8592A16CEA1B050D2554487A749408A8339FFCA98A5F23D4EEF7A4254C6E56BFD6B95AD3C822B83324BEC5DD85A7064C6233899F7C6D00749D9DEDBAD9ED72CCC9CF154EF3989752DF907B24E587CD6B29A22846CD1B9623A3AEF69D191E8C048046FBCA2BC2C2A0883C8738F72D612745419080B7D72D8EC2E696CF5CB5EB6F23A9BBFF4BDD129970E881DBAA81E2F1A1445C773D4445ED516D1D954C64593DF72B7B31810B7493B8334F57E79FB26554EE1B4E7B7BDAA2C707D8E4798549DB60AE0A064CA8C6AA36021EB1657E72810E676D0F312325F2FAF956DC336D6B8E1496553362292D98225D61A74827C43FD4B4E0242B19FECBA7C102940C24AC56BB287C739608441EAA2EAA6DE0D1323E6D45204A1FF07BC3D3A48F954597EE865531D8A32C1DC2A3A48C8A0D47BE16919C3DF9E0514CE63905717B +20241129025344 2 6 100 4095 2 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FD87AD5A3B +20241129025405 2 6 100 4095 5 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FD87C61B07 +20241129025445 2 6 100 4095 2 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FD88010893 +20241129025701 2 6 100 4095 2 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FD88DA8ABB +20241129025807 2 6 100 4095 2 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FD893E4473 +20241129025930 2 6 100 4095 5 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FD89BD17B7 +20241129025947 2 6 100 4095 2 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FD89D220C3 +20241129030824 2 6 100 4095 2 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FD8D22E89B +20241129031329 2 6 100 4095 2 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FD8F0BC07B +20241129031515 2 6 100 4095 5 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FD8FB3CF27 +20241129031807 2 6 100 4095 5 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FD90C1CCE7 +20241129032416 2 6 100 4095 2 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FD9313280B +20241129032613 2 6 100 4095 5 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FD93CCA2C7 +20241129032705 2 6 100 4095 5 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FD941819BF +20241129033035 2 6 100 4095 5 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FD9564B557 +20241129033357 2 6 100 4095 2 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FD96B187EB +20241129033421 2 6 100 4095 2 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FD96CEF60B +20241129033539 2 6 100 4095 2 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FD974904EB +20241129033708 2 6 100 4095 2 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FD97D1728B +20241129033818 2 6 100 4095 5 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FD983ADCCF +20241129033844 2 6 100 4095 5 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FD985DB957 +20241129033919 2 6 100 4095 5 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FD9890287F +20241129034126 2 6 100 4095 5 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FD9958DADF +20241129034406 2 6 100 4095 2 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FD9A557F5B +20241129034820 2 6 100 4095 5 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FD9BEF30FF +20241129035154 2 6 100 4095 2 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FD9D4E229B +20241129035209 2 6 100 4095 5 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FD9D5EE0CF +20241129035316 2 6 100 4095 5 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FD9DC2D03F +20241129035349 2 6 100 4095 2 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FD9DF64ABB +20241129035856 2 6 100 4095 5 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FD9FE86E1F +20241129040054 2 6 100 4095 2 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FDA0A085D3 +20241129040234 2 6 100 4095 2 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FDA13D2323 +20241129040334 2 6 100 4095 2 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FDA19957FB +20241129040452 2 6 100 4095 5 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FDA2168307 +20241129040614 2 6 100 4095 2 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FDA29615EB +20241129040924 2 6 100 4095 2 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FDA3C1BBEB +20241129041726 2 6 100 4095 2 F32300D8DFCB79ECFB80E433E6CFA1923915D80120F52648A7AE7E8058B5DB869F2B3A9DD940E53B7D74E3214FA03234F8B026AFF16B646B39F003882F1DC17D3F6DBB89283A01B4C22168A354D6D2FDBDE3F2B0C91E9472AF1DB386DD34477F47CB24D4AFB71BB283A9760CF4EC582F1401A4F259D4AADE2BC7648A6920207DFB149BB7A4483D5E22D9DC627A8A4954C18AAAEF921CE0C597C11C95EC7C8888050124D01C43E6A33A02DACDB2EEE70920BAF2A296EB38CEADCB98CC7789BA309A5AD7916B9F7F86B0D808346E28447C4E3F31C5BC319D29A0D338EE8FC88BC9288C75004CC278BB218AA86929360079EAA71628FEFB796FFFBAD3764F677FECC0F274582ED2E371ACB500F35F378DDEDB0FA32B1B55699E41EBE958E6614811999433D934CCD54A03CC4BF359798F90EC809CFA6E58C1CE68B5AF397E8E35951F9CC4BCD0EC8655486543B4CF7605CE15969A2D88E8CD6BCA82671A06FC54397840BBA9DB2750B0F1FBC61ECF6E514450A7E06C6E6BBBB2CFA5E045335F04A5C407EC6467D471226ED2CB3AE9FBA9E956F8F3D05A911F9CD131BC3D95A10792097AC1C4339F8C12E40ABD274A25CF26EF286187E91261273E39856C471D861056EC3F6F5E58EB727134F9BFB870C8DD6978F247EAF67C1368BCB0BA105CDDC2BA067EBAC9C00DC15F1667664AA2A688D45E843F62467892EE9348FDA6CBD37B +20241129044525 2 6 100 6143 5 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F33DDF12A47 +20241129045351 2 6 100 6143 2 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F33DEF75143 +20241129045821 2 6 100 6143 2 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F33DF7D9E33 +20241129045943 2 6 100 6143 5 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F33DFA1A9DF +20241129050501 2 6 100 6143 2 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F33E044C313 +20241129051930 2 6 100 6143 5 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F33E20AE0AF +20241129052029 2 6 100 6143 2 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F33E221299B +20241129052420 2 6 100 6143 2 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F33E294985B +20241129053040 2 6 100 6143 5 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F33E35A621F +20241129053505 2 6 100 6143 2 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F33E3E2DAAB +20241129054958 2 6 100 6143 5 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F33E5C2C407 +20241129060731 2 6 100 6143 2 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F33E7EF06DB +20241129060801 2 6 100 6143 2 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F33E7F7359B +20241129063045 2 6 100 6143 2 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F33EAD325DB +20241129065049 2 6 100 6143 2 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F33ED529283 +20241129065931 2 6 100 6143 5 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F33EE615997 +20241129070906 2 6 100 6143 5 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F33EF8D1D07 +20241129072522 2 6 100 6143 5 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F33F19250B7 +20241129080348 2 6 100 6143 2 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F33F6682AF3 +20241129082342 2 6 100 6143 5 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F33F8DD796F +20241129082407 2 6 100 6143 2 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F33F8E28AB3 +20241129082555 2 6 100 6143 2 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F33F917C303 +20241129082910 2 6 100 6143 2 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F33F97B2DB3 +20241129083433 2 6 100 6143 5 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F33FA1DB177 +20241129090902 2 6 100 6143 2 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F33FE76C9B3 +20241129090942 2 6 100 6143 5 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F33FE840CCF +20241129091044 2 6 100 6143 2 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F33FE9F0AB3 +20241129091214 2 6 100 6143 2 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F33FEC8962B +20241129100858 2 6 100 6143 2 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F3405C51773 +20241129101114 2 6 100 6143 2 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F3405F7D2BB +20241129101614 2 6 100 6143 2 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F34068F4943 +20241129103634 2 6 100 6143 2 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F340916E6EB +20241129103953 2 6 100 6143 2 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F34097696F3 +20241129104959 2 6 100 6143 2 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F340AAE5B3B +20241129112051 2 6 100 6143 5 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F340E9853AF +20241129124108 2 6 100 6143 2 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F3418BD011B +20241129125049 2 6 100 6143 5 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F3419E8F797 +20241129125233 2 6 100 6143 5 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F341A1B7937 +20241129130334 2 6 100 6143 2 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F341B7BA49B +20241129130855 2 6 100 6143 2 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F341C2258EB +20241129130953 2 6 100 6143 5 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F341C3B9397 +20241129131555 2 6 100 6143 2 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F341CF54C93 +20241129131844 2 6 100 6143 5 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F341D474B9F +20241129132228 2 6 100 6143 5 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F341DB5BA4F +20241129134604 2 6 100 6143 2 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F3420A2EA6B +20241129135907 2 6 100 6143 5 DCBE8A152DD5DE612BFCCD18CAB2BDE17391AF9DA865DCC59A1B454144ADE2EB8BE3CDBA7948CD1236CFC25D66DDC0E91095FB7E17715247413BBFD5435223F46488AD93808AF9FAF7D473C7CCE55DAA83B417FC6C09BFF7E332BD4B3BC59CBA4FE035A6C416D32BDCF8C3B9AFC5E1120CFD420023FD8EB207DB965509E2D362B0EB3D8CBD191D2750EBEB05F32C4BE08154D991F08DE4914BC40FAA7172440F2FEFB0FBF604DDA9C18BA9FD55F34218FD5D7CA2AC491CEDC3C5743D143BAF6C06CCAB7E5B22AB4E46CD51962CC7931F4D35581D5DD3047B946044BF7E71955EB63DD546644D7D2A19777DA39A48B4CF5A011A5C41F1BFF7C463F057F2F7AF6F910E7E06398B0AF7EF38CD5BBAE4C5FF42572CFFFCA6A8E9D34F64A7BECDC93216B55C20FAECAF04A8956C4D26DEE34493510BC49144A32A1B0AAE64B50DCA0C27361692242FE3145A6B36B830DEBF9E8A07A886E8DA6F38F3E99906F6AC9317ADF73222C4C75ABD153F1112E01E7CBB49665F213A1C1470CDC442D7CDC72EE2DD80D37251333C34FFDC5C38ADA3F5E52F5A5B2A1224B0CA60211B430E9554F0C4CA672476562C4A182B6707EBE80DFA6247A1F870F74EC81D03558F2718409EBF8E7F2FD2C6AB1F246F7E3FE0D919DB4016A7D76F6378D05EA74766CBB93340F2CBDDF18073F39242F3E9EC88020D1E8F801183C00F0239B2F2B4E8F6B46DBC17F469A857C291C985D8AC2099A6FEDC462B5EAEF737831EA2B6C9D787DC5AC8DA2C2E8F7F676FDA4CDD79E400EED959882C78C279C4D0A5918A0F5FC3B695E0034F7C2665D52D94106744D6B0CD6A66AB3275324EFDC06ECCF431D446446A00818ECDBE77B845699FB4F699825702D00F71373D80452039ECA1237AD2A0DF9112BA1EC90FB9FB87CF4E46BD0319B64F2EFD4B9640469707DB549468781D0BA6F3C49AF035D441173786BB1F2F5DCCE07BBF5536A0EB5B976814ABFDB44B90E55455972701A8F0D8EFB860A082ABA960E704754F61C2E3956922833F3D7E1656476DEE3C4F09244AC15697EA4A73041F03EEDE1F30BF899098A70F34223A233F +20241129143314 2 6 100 6143 2 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708C7A9949CB +20241129150941 2 6 100 6143 2 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708C7F2EAC9B +20241129152304 2 6 100 6143 2 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708C80D59DCB +20241129153351 2 6 100 6143 5 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708C82259357 +20241129153442 2 6 100 6143 5 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708C8239CBD7 +20241129154346 2 6 100 6143 2 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708C835408BB +20241129154536 2 6 100 6143 5 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708C8387126F +20241129161648 2 6 100 6143 5 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708C87770FCF +20241129162459 2 6 100 6143 5 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708C887B826F +20241129162918 2 6 100 6143 2 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708C89023DAB +20241129165526 2 6 100 6143 2 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708C8C3FAA43 +20241129170725 2 6 100 6143 5 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708C8DB7E57F +20241129171144 2 6 100 6143 5 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708C8E389D1F +20241129172847 2 6 100 6143 2 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708C90533393 +20241129173154 2 6 100 6143 2 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708C90AFE143 +20241129174539 2 6 100 6143 2 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708C92621483 +20241129180732 2 6 100 6143 5 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708C951D8D97 +20241129181538 2 6 100 6143 2 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708C961A0AFB +20241129182310 2 6 100 6143 5 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708C97054E47 +20241129183550 2 6 100 6143 5 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708C989CFDEF +20241129184809 2 6 100 6143 2 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708C9A2A2BAB +20241129185633 2 6 100 6143 2 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708C9B335EE3 +20241129190213 2 6 100 6143 5 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708C9BDDE8CF +20241129203945 2 6 100 6143 2 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708CA834CF13 +20241129204138 2 6 100 6143 5 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708CA86A90F7 +20241129205210 2 6 100 6143 5 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708CA9BFC2E7 +20241129210035 2 6 100 6143 2 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708CAAC70D2B +20241129210423 2 6 100 6143 5 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708CAB389E37 +20241129213344 2 6 100 6143 5 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708CAEE209F7 +20241129215808 2 6 100 6143 2 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708CB1F2A1D3 +20241129221635 2 6 100 6143 2 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708CB440830B +20241129222503 2 6 100 6143 5 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708CB545F1FF +20241129233015 2 6 100 6143 5 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708CBD76AB7F +20241129234110 2 6 100 6143 2 D530FFAD12BC56C29F02BEFEC6CFD700AE6DA852D7256FC0A8978C13FABF9851425A26917CD40A9919A06A5B17FA05456642891442CCBBBD9BB5B74068213AA6F029B3419F6B2CCB828CF9F6F0069F43A2496921ED8133BF2D9C598486282EB38B3B6E849B7D80B33869CDE1D71379C694BB9C229B5CCE5E96692F81DA73EC38942CE60A81657F34A6B1B536ADEADD76144A209815A88E081E0B96438B11A34E4F8082ACC6DD77D787EEA90E1764F7393D3869707FCFCD4BFEEA3582BBD39C17E2CE70B6A193700A055A50D2F5ED473DD9B4401C2138BAD8FA3331BDD4FF79E230C10B13FFE7CCDB3210F8DB42147BB8349CAEA97EBCBC708B9CE16360D573D3327BBCAA6387234E9A4DCB2E67784408ADB72B2E05643520211C581EBB38E57C2F69C9034143DBAB4C13221D501B892918779C6E9AC5B39F2F412E31EF7F7F0610C2AFE150FA56A5E3CF9DACA6C96F3BC6B57D56B2869019C5114247C080752E4D42B1A0E34302B69B8516E8FB93BE58CC45F6E5ADB47A89A00050A12D560BEEA8997F5A0FA526C107BA34ECB0C678079C6DD4C1F4666BBD45733E019C292A17661B79E6AEED002EF4F6E7F4D569690E140C8BA1BA47E626499E01DA1EACDA4B917507A472DDB03A86734994C4B16551C5DFED3C8C976D15B5BF68CC6C982355930E37F096629E6F3BDC8027C722C12EF76854F1C607341E48FBF8C9064EB48EFDA87E1D111B557FBE7A15A580EDD87AC2CEC0EB25BE057FC20D578DF34632977F4698D58B2025C50AD4AD77D16D32E6157F89F58C692A83279A2EB58F8E448A13AA32B8C3DF07A58100EC4BB319F824446ECDD643C4A7F959CBA4E356A9E5DB7332107B2EB478703BF44383DDF80CA297F5E52A4424AF64B50CAB4E9C95C7288B96F8E77CDC63D07C6394853DF32F926652A12122B5531F90CFDFDAAC5D0642F84CF3901717B652122E8622CF31C06D134AD921EC80D175BBFC45B855EB9ABF001686BC52730F754DBFAE781BB629F1E530632D813AA256D0063202AEEE0AB64C7829C1A6C4702E27C88219FF31500D8F76BEFE4AEF726D6E3B708CBED26FD3 +20241130004028 2 6 100 7679 2 C4FD13B23C1EF3F1B888E9E24F6E6F0D1E538D5C17287A04247451367BAAC3EB0FF3633A10C1B2BEA19F91DA18C0C52A465FA0F0371A2189AC36BFEA58F33B013352F321A0B71BF61553330EC7735E66BF920F0AB9C918AC6796F3B2C5CC7B0E9F6695400B692026845D93807363115D8E1EF92072B84941DE896DC222F2493FA43169DC5C94E9F7C645CDDC38AC8C8F8790A2078B755BF65EB099CA5682E186E7DE95CBCF7036B0BFC761137EB0B297A140C1683E9A14E78F31935D873DFB2CC33563980FD7C6EB609427A9A63D9A7ECE43889783FAF17D129A4F00A7DBA8FAFCBDD57FA7599C944D03297B7106E02A82D695E8BC0ACC860295F357FD2F60CC4A09E49450CF735A8756174A8E1458E3BE2BEA10F38D2C30E6AD7DBFA6835328A64BDFCA2318E1753C922D3AA467BB770C03BE0D3381E31655F4969009A35E4CF90B1EF5CB71A7BE424E952AEF1368142BB6E5AEECB9F7EC2034179009B7E57DF234CDDC3818BE6E637DAC7F44B109BCAA519CA77B27E4A119712A325ACC29E82C5A3E43CDED00A550ABF99495C802578A6ACB7DBCCCECD3A3857F01A9582671D87C9407409355199D627D316938076334BCDEC6635E0D6696A53E2475AAF9412167245779FA0C89CC3C08BF90313C68710D0153A3B8FA06862B6670E9498296D2C1840812D51FFEADDAE3D714A6EA7D0DAF18C134A0E26AAA99AB8B605E5FAC1814D13F5BCA134DBCF40B5C21F39EF9B4089A759876E5F22DEAF3C64DAA159B9AFEB76109429E3E42FF8DB74EF84954405C4D7B826CFBE041FF996CB053ED44BD32742681CCC843CBD031CD9DDF299EF150378F87B5F67768C77A69F779AABC032BCC3031DDAD83701E475D16040D1E064208D99313C4047BA2AA44E15CF631E4337A47318F34060DAE2ED3FB2F77F26CAF51805D86F82786B8CED61C0A0A7A8CBECD9AE3FDD266BDA632E6F6095A8E2C82A709EF2ACE20D66CC6709A5EF4EBFBA3B020BD15A5451673CA3780A459C277EEA72A1C9EF8502281BF903B2409971DC1F215C899CBBDED194CAB8A5EBB2273E3B67AEEE9A18CD03A1CC46312AAE59AEA0EFB0E5EAC8A62D6C49DC5B5D5CAC7B12CC2B293ED1D258149C6E8ADFB311328C1D5ACD4A92DFC71E9575A62920166893D715358DAE87159E39267079FA5D2EF41D756E01E0D9701BE7F715E4DCEF5667576A883DC034E36022AB62707C4E9FF9C7400BD29770FC07C66BB041F17204A63B6A52177F32B1E8AF15A818E946421552673488AA76253A5CCAEF2368C6464A36DEA011A56FFACF5F592099BADEFA4B7A72059FF1869864BDDBD14B4D32460CFD30E78C4F057F011C6132BC003 +20241130023838 2 6 100 7679 5 C4FD13B23C1EF3F1B888E9E24F6E6F0D1E538D5C17287A04247451367BAAC3EB0FF3633A10C1B2BEA19F91DA18C0C52A465FA0F0371A2189AC36BFEA58F33B013352F321A0B71BF61553330EC7735E66BF920F0AB9C918AC6796F3B2C5CC7B0E9F6695400B692026845D93807363115D8E1EF92072B84941DE896DC222F2493FA43169DC5C94E9F7C645CDDC38AC8C8F8790A2078B755BF65EB099CA5682E186E7DE95CBCF7036B0BFC761137EB0B297A140C1683E9A14E78F31935D873DFB2CC33563980FD7C6EB609427A9A63D9A7ECE43889783FAF17D129A4F00A7DBA8FAFCBDD57FA7599C944D03297B7106E02A82D695E8BC0ACC860295F357FD2F60CC4A09E49450CF735A8756174A8E1458E3BE2BEA10F38D2C30E6AD7DBFA6835328A64BDFCA2318E1753C922D3AA467BB770C03BE0D3381E31655F4969009A35E4CF90B1EF5CB71A7BE424E952AEF1368142BB6E5AEECB9F7EC2034179009B7E57DF234CDDC3818BE6E637DAC7F44B109BCAA519CA77B27E4A119712A325ACC29E82C5A3E43CDED00A550ABF99495C802578A6ACB7DBCCCECD3A3857F01A9582671D87C9407409355199D627D316938076334BCDEC6635E0D6696A53E2475AAF9412167245779FA0C89CC3C08BF90313C68710D0153A3B8FA06862B6670E9498296D2C1840812D51FFEADDAE3D714A6EA7D0DAF18C134A0E26AAA99AB8B605E5FAC1814D13F5BCA134DBCF40B5C21F39EF9B4089A759876E5F22DEAF3C64DAA159B9AFEB76109429E3E42FF8DB74EF84954405C4D7B826CFBE041FF996CB053ED44BD32742681CCC843CBD031CD9DDF299EF150378F87B5F67768C77A69F779AABC032BCC3031DDAD83701E475D16040D1E064208D99313C4047BA2AA44E15CF631E4337A47318F34060DAE2ED3FB2F77F26CAF51805D86F82786B8CED61C0A0A7A8CBECD9AE3FDD266BDA632E6F6095A8E2C82A709EF2ACE20D66CC6709A5EF4EBFBA3B020BD15A5451673CA3780A459C277EEA72A1C9EF8502281BF903B2409971DC1F215C899CBBDED194CAB8A5EBB2273E3B67AEEE9A18CD03A1CC46312AAE59AEA0EFB0E5EAC8A62D6C49DC5B5D5CAC7B12CC2B293ED1D258149C6E8ADFB311328C1D5ACD4A92DFC71E9575A62920166893D715358DAE87159E39267079FA5D2EF41D756E01E0D9701BE7F715E4DCEF5667576A883DC034E36022AB62707C4E9FF9C7400BD29770FC07C66BB041F17204A63B6A52177F32B1E8AF15A818E946421552673488AA76253A5CCAEF2368C6464A36DEA011A56FFACF5F592099BADEFA4B7A72059FF1869864BDDBD14B4D32460CFD30E78C4F057F011C61B09AE47 +20241130030155 2 6 100 7679 2 C4FD13B23C1EF3F1B888E9E24F6E6F0D1E538D5C17287A04247451367BAAC3EB0FF3633A10C1B2BEA19F91DA18C0C52A465FA0F0371A2189AC36BFEA58F33B013352F321A0B71BF61553330EC7735E66BF920F0AB9C918AC6796F3B2C5CC7B0E9F6695400B692026845D93807363115D8E1EF92072B84941DE896DC222F2493FA43169DC5C94E9F7C645CDDC38AC8C8F8790A2078B755BF65EB099CA5682E186E7DE95CBCF7036B0BFC761137EB0B297A140C1683E9A14E78F31935D873DFB2CC33563980FD7C6EB609427A9A63D9A7ECE43889783FAF17D129A4F00A7DBA8FAFCBDD57FA7599C944D03297B7106E02A82D695E8BC0ACC860295F357FD2F60CC4A09E49450CF735A8756174A8E1458E3BE2BEA10F38D2C30E6AD7DBFA6835328A64BDFCA2318E1753C922D3AA467BB770C03BE0D3381E31655F4969009A35E4CF90B1EF5CB71A7BE424E952AEF1368142BB6E5AEECB9F7EC2034179009B7E57DF234CDDC3818BE6E637DAC7F44B109BCAA519CA77B27E4A119712A325ACC29E82C5A3E43CDED00A550ABF99495C802578A6ACB7DBCCCECD3A3857F01A9582671D87C9407409355199D627D316938076334BCDEC6635E0D6696A53E2475AAF9412167245779FA0C89CC3C08BF90313C68710D0153A3B8FA06862B6670E9498296D2C1840812D51FFEADDAE3D714A6EA7D0DAF18C134A0E26AAA99AB8B605E5FAC1814D13F5BCA134DBCF40B5C21F39EF9B4089A759876E5F22DEAF3C64DAA159B9AFEB76109429E3E42FF8DB74EF84954405C4D7B826CFBE041FF996CB053ED44BD32742681CCC843CBD031CD9DDF299EF150378F87B5F67768C77A69F779AABC032BCC3031DDAD83701E475D16040D1E064208D99313C4047BA2AA44E15CF631E4337A47318F34060DAE2ED3FB2F77F26CAF51805D86F82786B8CED61C0A0A7A8CBECD9AE3FDD266BDA632E6F6095A8E2C82A709EF2ACE20D66CC6709A5EF4EBFBA3B020BD15A5451673CA3780A459C277EEA72A1C9EF8502281BF903B2409971DC1F215C899CBBDED194CAB8A5EBB2273E3B67AEEE9A18CD03A1CC46312AAE59AEA0EFB0E5EAC8A62D6C49DC5B5D5CAC7B12CC2B293ED1D258149C6E8ADFB311328C1D5ACD4A92DFC71E9575A62920166893D715358DAE87159E39267079FA5D2EF41D756E01E0D9701BE7F715E4DCEF5667576A883DC034E36022AB62707C4E9FF9C7400BD29770FC07C66BB041F17204A63B6A52177F32B1E8AF15A818E946421552673488AA76253A5CCAEF2368C6464A36DEA011A56FFACF5F592099BADEFA4B7A72059FF1869864BDDBD14B4D32460CFD30E78C4F057F011C61C91151B +20241130032532 2 6 100 7679 2 C4FD13B23C1EF3F1B888E9E24F6E6F0D1E538D5C17287A04247451367BAAC3EB0FF3633A10C1B2BEA19F91DA18C0C52A465FA0F0371A2189AC36BFEA58F33B013352F321A0B71BF61553330EC7735E66BF920F0AB9C918AC6796F3B2C5CC7B0E9F6695400B692026845D93807363115D8E1EF92072B84941DE896DC222F2493FA43169DC5C94E9F7C645CDDC38AC8C8F8790A2078B755BF65EB099CA5682E186E7DE95CBCF7036B0BFC761137EB0B297A140C1683E9A14E78F31935D873DFB2CC33563980FD7C6EB609427A9A63D9A7ECE43889783FAF17D129A4F00A7DBA8FAFCBDD57FA7599C944D03297B7106E02A82D695E8BC0ACC860295F357FD2F60CC4A09E49450CF735A8756174A8E1458E3BE2BEA10F38D2C30E6AD7DBFA6835328A64BDFCA2318E1753C922D3AA467BB770C03BE0D3381E31655F4969009A35E4CF90B1EF5CB71A7BE424E952AEF1368142BB6E5AEECB9F7EC2034179009B7E57DF234CDDC3818BE6E637DAC7F44B109BCAA519CA77B27E4A119712A325ACC29E82C5A3E43CDED00A550ABF99495C802578A6ACB7DBCCCECD3A3857F01A9582671D87C9407409355199D627D316938076334BCDEC6635E0D6696A53E2475AAF9412167245779FA0C89CC3C08BF90313C68710D0153A3B8FA06862B6670E9498296D2C1840812D51FFEADDAE3D714A6EA7D0DAF18C134A0E26AAA99AB8B605E5FAC1814D13F5BCA134DBCF40B5C21F39EF9B4089A759876E5F22DEAF3C64DAA159B9AFEB76109429E3E42FF8DB74EF84954405C4D7B826CFBE041FF996CB053ED44BD32742681CCC843CBD031CD9DDF299EF150378F87B5F67768C77A69F779AABC032BCC3031DDAD83701E475D16040D1E064208D99313C4047BA2AA44E15CF631E4337A47318F34060DAE2ED3FB2F77F26CAF51805D86F82786B8CED61C0A0A7A8CBECD9AE3FDD266BDA632E6F6095A8E2C82A709EF2ACE20D66CC6709A5EF4EBFBA3B020BD15A5451673CA3780A459C277EEA72A1C9EF8502281BF903B2409971DC1F215C899CBBDED194CAB8A5EBB2273E3B67AEEE9A18CD03A1CC46312AAE59AEA0EFB0E5EAC8A62D6C49DC5B5D5CAC7B12CC2B293ED1D258149C6E8ADFB311328C1D5ACD4A92DFC71E9575A62920166893D715358DAE87159E39267079FA5D2EF41D756E01E0D9701BE7F715E4DCEF5667576A883DC034E36022AB62707C4E9FF9C7400BD29770FC07C66BB041F17204A63B6A52177F32B1E8AF15A818E946421552673488AA76253A5CCAEF2368C6464A36DEA011A56FFACF5F592099BADEFA4B7A72059FF1869864BDDBD14B4D32460CFD30E78C4F057F011C61E1854B3 +20241130035131 2 6 100 7679 2 C4FD13B23C1EF3F1B888E9E24F6E6F0D1E538D5C17287A04247451367BAAC3EB0FF3633A10C1B2BEA19F91DA18C0C52A465FA0F0371A2189AC36BFEA58F33B013352F321A0B71BF61553330EC7735E66BF920F0AB9C918AC6796F3B2C5CC7B0E9F6695400B692026845D93807363115D8E1EF92072B84941DE896DC222F2493FA43169DC5C94E9F7C645CDDC38AC8C8F8790A2078B755BF65EB099CA5682E186E7DE95CBCF7036B0BFC761137EB0B297A140C1683E9A14E78F31935D873DFB2CC33563980FD7C6EB609427A9A63D9A7ECE43889783FAF17D129A4F00A7DBA8FAFCBDD57FA7599C944D03297B7106E02A82D695E8BC0ACC860295F357FD2F60CC4A09E49450CF735A8756174A8E1458E3BE2BEA10F38D2C30E6AD7DBFA6835328A64BDFCA2318E1753C922D3AA467BB770C03BE0D3381E31655F4969009A35E4CF90B1EF5CB71A7BE424E952AEF1368142BB6E5AEECB9F7EC2034179009B7E57DF234CDDC3818BE6E637DAC7F44B109BCAA519CA77B27E4A119712A325ACC29E82C5A3E43CDED00A550ABF99495C802578A6ACB7DBCCCECD3A3857F01A9582671D87C9407409355199D627D316938076334BCDEC6635E0D6696A53E2475AAF9412167245779FA0C89CC3C08BF90313C68710D0153A3B8FA06862B6670E9498296D2C1840812D51FFEADDAE3D714A6EA7D0DAF18C134A0E26AAA99AB8B605E5FAC1814D13F5BCA134DBCF40B5C21F39EF9B4089A759876E5F22DEAF3C64DAA159B9AFEB76109429E3E42FF8DB74EF84954405C4D7B826CFBE041FF996CB053ED44BD32742681CCC843CBD031CD9DDF299EF150378F87B5F67768C77A69F779AABC032BCC3031DDAD83701E475D16040D1E064208D99313C4047BA2AA44E15CF631E4337A47318F34060DAE2ED3FB2F77F26CAF51805D86F82786B8CED61C0A0A7A8CBECD9AE3FDD266BDA632E6F6095A8E2C82A709EF2ACE20D66CC6709A5EF4EBFBA3B020BD15A5451673CA3780A459C277EEA72A1C9EF8502281BF903B2409971DC1F215C899CBBDED194CAB8A5EBB2273E3B67AEEE9A18CD03A1CC46312AAE59AEA0EFB0E5EAC8A62D6C49DC5B5D5CAC7B12CC2B293ED1D258149C6E8ADFB311328C1D5ACD4A92DFC71E9575A62920166893D715358DAE87159E39267079FA5D2EF41D756E01E0D9701BE7F715E4DCEF5667576A883DC034E36022AB62707C4E9FF9C7400BD29770FC07C66BB041F17204A63B6A52177F32B1E8AF15A818E946421552673488AA76253A5CCAEF2368C6464A36DEA011A56FFACF5F592099BADEFA4B7A72059FF1869864BDDBD14B4D32460CFD30E78C4F057F011C61FD56C8B +20241130035951 2 6 100 7679 5 C4FD13B23C1EF3F1B888E9E24F6E6F0D1E538D5C17287A04247451367BAAC3EB0FF3633A10C1B2BEA19F91DA18C0C52A465FA0F0371A2189AC36BFEA58F33B013352F321A0B71BF61553330EC7735E66BF920F0AB9C918AC6796F3B2C5CC7B0E9F6695400B692026845D93807363115D8E1EF92072B84941DE896DC222F2493FA43169DC5C94E9F7C645CDDC38AC8C8F8790A2078B755BF65EB099CA5682E186E7DE95CBCF7036B0BFC761137EB0B297A140C1683E9A14E78F31935D873DFB2CC33563980FD7C6EB609427A9A63D9A7ECE43889783FAF17D129A4F00A7DBA8FAFCBDD57FA7599C944D03297B7106E02A82D695E8BC0ACC860295F357FD2F60CC4A09E49450CF735A8756174A8E1458E3BE2BEA10F38D2C30E6AD7DBFA6835328A64BDFCA2318E1753C922D3AA467BB770C03BE0D3381E31655F4969009A35E4CF90B1EF5CB71A7BE424E952AEF1368142BB6E5AEECB9F7EC2034179009B7E57DF234CDDC3818BE6E637DAC7F44B109BCAA519CA77B27E4A119712A325ACC29E82C5A3E43CDED00A550ABF99495C802578A6ACB7DBCCCECD3A3857F01A9582671D87C9407409355199D627D316938076334BCDEC6635E0D6696A53E2475AAF9412167245779FA0C89CC3C08BF90313C68710D0153A3B8FA06862B6670E9498296D2C1840812D51FFEADDAE3D714A6EA7D0DAF18C134A0E26AAA99AB8B605E5FAC1814D13F5BCA134DBCF40B5C21F39EF9B4089A759876E5F22DEAF3C64DAA159B9AFEB76109429E3E42FF8DB74EF84954405C4D7B826CFBE041FF996CB053ED44BD32742681CCC843CBD031CD9DDF299EF150378F87B5F67768C77A69F779AABC032BCC3031DDAD83701E475D16040D1E064208D99313C4047BA2AA44E15CF631E4337A47318F34060DAE2ED3FB2F77F26CAF51805D86F82786B8CED61C0A0A7A8CBECD9AE3FDD266BDA632E6F6095A8E2C82A709EF2ACE20D66CC6709A5EF4EBFBA3B020BD15A5451673CA3780A459C277EEA72A1C9EF8502281BF903B2409971DC1F215C899CBBDED194CAB8A5EBB2273E3B67AEEE9A18CD03A1CC46312AAE59AEA0EFB0E5EAC8A62D6C49DC5B5D5CAC7B12CC2B293ED1D258149C6E8ADFB311328C1D5ACD4A92DFC71E9575A62920166893D715358DAE87159E39267079FA5D2EF41D756E01E0D9701BE7F715E4DCEF5667576A883DC034E36022AB62707C4E9FF9C7400BD29770FC07C66BB041F17204A63B6A52177F32B1E8AF15A818E946421552673488AA76253A5CCAEF2368C6464A36DEA011A56FFACF5F592099BADEFA4B7A72059FF1869864BDDBD14B4D32460CFD30E78C4F057F011C6205D0C3F +20241130040156 2 6 100 7679 2 C4FD13B23C1EF3F1B888E9E24F6E6F0D1E538D5C17287A04247451367BAAC3EB0FF3633A10C1B2BEA19F91DA18C0C52A465FA0F0371A2189AC36BFEA58F33B013352F321A0B71BF61553330EC7735E66BF920F0AB9C918AC6796F3B2C5CC7B0E9F6695400B692026845D93807363115D8E1EF92072B84941DE896DC222F2493FA43169DC5C94E9F7C645CDDC38AC8C8F8790A2078B755BF65EB099CA5682E186E7DE95CBCF7036B0BFC761137EB0B297A140C1683E9A14E78F31935D873DFB2CC33563980FD7C6EB609427A9A63D9A7ECE43889783FAF17D129A4F00A7DBA8FAFCBDD57FA7599C944D03297B7106E02A82D695E8BC0ACC860295F357FD2F60CC4A09E49450CF735A8756174A8E1458E3BE2BEA10F38D2C30E6AD7DBFA6835328A64BDFCA2318E1753C922D3AA467BB770C03BE0D3381E31655F4969009A35E4CF90B1EF5CB71A7BE424E952AEF1368142BB6E5AEECB9F7EC2034179009B7E57DF234CDDC3818BE6E637DAC7F44B109BCAA519CA77B27E4A119712A325ACC29E82C5A3E43CDED00A550ABF99495C802578A6ACB7DBCCCECD3A3857F01A9582671D87C9407409355199D627D316938076334BCDEC6635E0D6696A53E2475AAF9412167245779FA0C89CC3C08BF90313C68710D0153A3B8FA06862B6670E9498296D2C1840812D51FFEADDAE3D714A6EA7D0DAF18C134A0E26AAA99AB8B605E5FAC1814D13F5BCA134DBCF40B5C21F39EF9B4089A759876E5F22DEAF3C64DAA159B9AFEB76109429E3E42FF8DB74EF84954405C4D7B826CFBE041FF996CB053ED44BD32742681CCC843CBD031CD9DDF299EF150378F87B5F67768C77A69F779AABC032BCC3031DDAD83701E475D16040D1E064208D99313C4047BA2AA44E15CF631E4337A47318F34060DAE2ED3FB2F77F26CAF51805D86F82786B8CED61C0A0A7A8CBECD9AE3FDD266BDA632E6F6095A8E2C82A709EF2ACE20D66CC6709A5EF4EBFBA3B020BD15A5451673CA3780A459C277EEA72A1C9EF8502281BF903B2409971DC1F215C899CBBDED194CAB8A5EBB2273E3B67AEEE9A18CD03A1CC46312AAE59AEA0EFB0E5EAC8A62D6C49DC5B5D5CAC7B12CC2B293ED1D258149C6E8ADFB311328C1D5ACD4A92DFC71E9575A62920166893D715358DAE87159E39267079FA5D2EF41D756E01E0D9701BE7F715E4DCEF5667576A883DC034E36022AB62707C4E9FF9C7400BD29770FC07C66BB041F17204A63B6A52177F32B1E8AF15A818E946421552673488AA76253A5CCAEF2368C6464A36DEA011A56FFACF5F592099BADEFA4B7A72059FF1869864BDDBD14B4D32460CFD30E78C4F057F011C6207AF313 +20241130042927 2 6 100 7679 2 C4FD13B23C1EF3F1B888E9E24F6E6F0D1E538D5C17287A04247451367BAAC3EB0FF3633A10C1B2BEA19F91DA18C0C52A465FA0F0371A2189AC36BFEA58F33B013352F321A0B71BF61553330EC7735E66BF920F0AB9C918AC6796F3B2C5CC7B0E9F6695400B692026845D93807363115D8E1EF92072B84941DE896DC222F2493FA43169DC5C94E9F7C645CDDC38AC8C8F8790A2078B755BF65EB099CA5682E186E7DE95CBCF7036B0BFC761137EB0B297A140C1683E9A14E78F31935D873DFB2CC33563980FD7C6EB609427A9A63D9A7ECE43889783FAF17D129A4F00A7DBA8FAFCBDD57FA7599C944D03297B7106E02A82D695E8BC0ACC860295F357FD2F60CC4A09E49450CF735A8756174A8E1458E3BE2BEA10F38D2C30E6AD7DBFA6835328A64BDFCA2318E1753C922D3AA467BB770C03BE0D3381E31655F4969009A35E4CF90B1EF5CB71A7BE424E952AEF1368142BB6E5AEECB9F7EC2034179009B7E57DF234CDDC3818BE6E637DAC7F44B109BCAA519CA77B27E4A119712A325ACC29E82C5A3E43CDED00A550ABF99495C802578A6ACB7DBCCCECD3A3857F01A9582671D87C9407409355199D627D316938076334BCDEC6635E0D6696A53E2475AAF9412167245779FA0C89CC3C08BF90313C68710D0153A3B8FA06862B6670E9498296D2C1840812D51FFEADDAE3D714A6EA7D0DAF18C134A0E26AAA99AB8B605E5FAC1814D13F5BCA134DBCF40B5C21F39EF9B4089A759876E5F22DEAF3C64DAA159B9AFEB76109429E3E42FF8DB74EF84954405C4D7B826CFBE041FF996CB053ED44BD32742681CCC843CBD031CD9DDF299EF150378F87B5F67768C77A69F779AABC032BCC3031DDAD83701E475D16040D1E064208D99313C4047BA2AA44E15CF631E4337A47318F34060DAE2ED3FB2F77F26CAF51805D86F82786B8CED61C0A0A7A8CBECD9AE3FDD266BDA632E6F6095A8E2C82A709EF2ACE20D66CC6709A5EF4EBFBA3B020BD15A5451673CA3780A459C277EEA72A1C9EF8502281BF903B2409971DC1F215C899CBBDED194CAB8A5EBB2273E3B67AEEE9A18CD03A1CC46312AAE59AEA0EFB0E5EAC8A62D6C49DC5B5D5CAC7B12CC2B293ED1D258149C6E8ADFB311328C1D5ACD4A92DFC71E9575A62920166893D715358DAE87159E39267079FA5D2EF41D756E01E0D9701BE7F715E4DCEF5667576A883DC034E36022AB62707C4E9FF9C7400BD29770FC07C66BB041F17204A63B6A52177F32B1E8AF15A818E946421552673488AA76253A5CCAEF2368C6464A36DEA011A56FFACF5F592099BADEFA4B7A72059FF1869864BDDBD14B4D32460CFD30E78C4F057F011C6224FB4F3 +20241130043039 2 6 100 7679 5 C4FD13B23C1EF3F1B888E9E24F6E6F0D1E538D5C17287A04247451367BAAC3EB0FF3633A10C1B2BEA19F91DA18C0C52A465FA0F0371A2189AC36BFEA58F33B013352F321A0B71BF61553330EC7735E66BF920F0AB9C918AC6796F3B2C5CC7B0E9F6695400B692026845D93807363115D8E1EF92072B84941DE896DC222F2493FA43169DC5C94E9F7C645CDDC38AC8C8F8790A2078B755BF65EB099CA5682E186E7DE95CBCF7036B0BFC761137EB0B297A140C1683E9A14E78F31935D873DFB2CC33563980FD7C6EB609427A9A63D9A7ECE43889783FAF17D129A4F00A7DBA8FAFCBDD57FA7599C944D03297B7106E02A82D695E8BC0ACC860295F357FD2F60CC4A09E49450CF735A8756174A8E1458E3BE2BEA10F38D2C30E6AD7DBFA6835328A64BDFCA2318E1753C922D3AA467BB770C03BE0D3381E31655F4969009A35E4CF90B1EF5CB71A7BE424E952AEF1368142BB6E5AEECB9F7EC2034179009B7E57DF234CDDC3818BE6E637DAC7F44B109BCAA519CA77B27E4A119712A325ACC29E82C5A3E43CDED00A550ABF99495C802578A6ACB7DBCCCECD3A3857F01A9582671D87C9407409355199D627D316938076334BCDEC6635E0D6696A53E2475AAF9412167245779FA0C89CC3C08BF90313C68710D0153A3B8FA06862B6670E9498296D2C1840812D51FFEADDAE3D714A6EA7D0DAF18C134A0E26AAA99AB8B605E5FAC1814D13F5BCA134DBCF40B5C21F39EF9B4089A759876E5F22DEAF3C64DAA159B9AFEB76109429E3E42FF8DB74EF84954405C4D7B826CFBE041FF996CB053ED44BD32742681CCC843CBD031CD9DDF299EF150378F87B5F67768C77A69F779AABC032BCC3031DDAD83701E475D16040D1E064208D99313C4047BA2AA44E15CF631E4337A47318F34060DAE2ED3FB2F77F26CAF51805D86F82786B8CED61C0A0A7A8CBECD9AE3FDD266BDA632E6F6095A8E2C82A709EF2ACE20D66CC6709A5EF4EBFBA3B020BD15A5451673CA3780A459C277EEA72A1C9EF8502281BF903B2409971DC1F215C899CBBDED194CAB8A5EBB2273E3B67AEEE9A18CD03A1CC46312AAE59AEA0EFB0E5EAC8A62D6C49DC5B5D5CAC7B12CC2B293ED1D258149C6E8ADFB311328C1D5ACD4A92DFC71E9575A62920166893D715358DAE87159E39267079FA5D2EF41D756E01E0D9701BE7F715E4DCEF5667576A883DC034E36022AB62707C4E9FF9C7400BD29770FC07C66BB041F17204A63B6A52177F32B1E8AF15A818E946421552673488AA76253A5CCAEF2368C6464A36DEA011A56FFACF5F592099BADEFA4B7A72059FF1869864BDDBD14B4D32460CFD30E78C4F057F011C6225C64C7 +20241130054524 2 6 100 7679 2 C4FD13B23C1EF3F1B888E9E24F6E6F0D1E538D5C17287A04247451367BAAC3EB0FF3633A10C1B2BEA19F91DA18C0C52A465FA0F0371A2189AC36BFEA58F33B013352F321A0B71BF61553330EC7735E66BF920F0AB9C918AC6796F3B2C5CC7B0E9F6695400B692026845D93807363115D8E1EF92072B84941DE896DC222F2493FA43169DC5C94E9F7C645CDDC38AC8C8F8790A2078B755BF65EB099CA5682E186E7DE95CBCF7036B0BFC761137EB0B297A140C1683E9A14E78F31935D873DFB2CC33563980FD7C6EB609427A9A63D9A7ECE43889783FAF17D129A4F00A7DBA8FAFCBDD57FA7599C944D03297B7106E02A82D695E8BC0ACC860295F357FD2F60CC4A09E49450CF735A8756174A8E1458E3BE2BEA10F38D2C30E6AD7DBFA6835328A64BDFCA2318E1753C922D3AA467BB770C03BE0D3381E31655F4969009A35E4CF90B1EF5CB71A7BE424E952AEF1368142BB6E5AEECB9F7EC2034179009B7E57DF234CDDC3818BE6E637DAC7F44B109BCAA519CA77B27E4A119712A325ACC29E82C5A3E43CDED00A550ABF99495C802578A6ACB7DBCCCECD3A3857F01A9582671D87C9407409355199D627D316938076334BCDEC6635E0D6696A53E2475AAF9412167245779FA0C89CC3C08BF90313C68710D0153A3B8FA06862B6670E9498296D2C1840812D51FFEADDAE3D714A6EA7D0DAF18C134A0E26AAA99AB8B605E5FAC1814D13F5BCA134DBCF40B5C21F39EF9B4089A759876E5F22DEAF3C64DAA159B9AFEB76109429E3E42FF8DB74EF84954405C4D7B826CFBE041FF996CB053ED44BD32742681CCC843CBD031CD9DDF299EF150378F87B5F67768C77A69F779AABC032BCC3031DDAD83701E475D16040D1E064208D99313C4047BA2AA44E15CF631E4337A47318F34060DAE2ED3FB2F77F26CAF51805D86F82786B8CED61C0A0A7A8CBECD9AE3FDD266BDA632E6F6095A8E2C82A709EF2ACE20D66CC6709A5EF4EBFBA3B020BD15A5451673CA3780A459C277EEA72A1C9EF8502281BF903B2409971DC1F215C899CBBDED194CAB8A5EBB2273E3B67AEEE9A18CD03A1CC46312AAE59AEA0EFB0E5EAC8A62D6C49DC5B5D5CAC7B12CC2B293ED1D258149C6E8ADFB311328C1D5ACD4A92DFC71E9575A62920166893D715358DAE87159E39267079FA5D2EF41D756E01E0D9701BE7F715E4DCEF5667576A883DC034E36022AB62707C4E9FF9C7400BD29770FC07C66BB041F17204A63B6A52177F32B1E8AF15A818E946421552673488AA76253A5CCAEF2368C6464A36DEA011A56FFACF5F592099BADEFA4B7A72059FF1869864BDDBD14B4D32460CFD30E78C4F057F011C62750439B +20241130063335 2 6 100 7679 5 C4FD13B23C1EF3F1B888E9E24F6E6F0D1E538D5C17287A04247451367BAAC3EB0FF3633A10C1B2BEA19F91DA18C0C52A465FA0F0371A2189AC36BFEA58F33B013352F321A0B71BF61553330EC7735E66BF920F0AB9C918AC6796F3B2C5CC7B0E9F6695400B692026845D93807363115D8E1EF92072B84941DE896DC222F2493FA43169DC5C94E9F7C645CDDC38AC8C8F8790A2078B755BF65EB099CA5682E186E7DE95CBCF7036B0BFC761137EB0B297A140C1683E9A14E78F31935D873DFB2CC33563980FD7C6EB609427A9A63D9A7ECE43889783FAF17D129A4F00A7DBA8FAFCBDD57FA7599C944D03297B7106E02A82D695E8BC0ACC860295F357FD2F60CC4A09E49450CF735A8756174A8E1458E3BE2BEA10F38D2C30E6AD7DBFA6835328A64BDFCA2318E1753C922D3AA467BB770C03BE0D3381E31655F4969009A35E4CF90B1EF5CB71A7BE424E952AEF1368142BB6E5AEECB9F7EC2034179009B7E57DF234CDDC3818BE6E637DAC7F44B109BCAA519CA77B27E4A119712A325ACC29E82C5A3E43CDED00A550ABF99495C802578A6ACB7DBCCCECD3A3857F01A9582671D87C9407409355199D627D316938076334BCDEC6635E0D6696A53E2475AAF9412167245779FA0C89CC3C08BF90313C68710D0153A3B8FA06862B6670E9498296D2C1840812D51FFEADDAE3D714A6EA7D0DAF18C134A0E26AAA99AB8B605E5FAC1814D13F5BCA134DBCF40B5C21F39EF9B4089A759876E5F22DEAF3C64DAA159B9AFEB76109429E3E42FF8DB74EF84954405C4D7B826CFBE041FF996CB053ED44BD32742681CCC843CBD031CD9DDF299EF150378F87B5F67768C77A69F779AABC032BCC3031DDAD83701E475D16040D1E064208D99313C4047BA2AA44E15CF631E4337A47318F34060DAE2ED3FB2F77F26CAF51805D86F82786B8CED61C0A0A7A8CBECD9AE3FDD266BDA632E6F6095A8E2C82A709EF2ACE20D66CC6709A5EF4EBFBA3B020BD15A5451673CA3780A459C277EEA72A1C9EF8502281BF903B2409971DC1F215C899CBBDED194CAB8A5EBB2273E3B67AEEE9A18CD03A1CC46312AAE59AEA0EFB0E5EAC8A62D6C49DC5B5D5CAC7B12CC2B293ED1D258149C6E8ADFB311328C1D5ACD4A92DFC71E9575A62920166893D715358DAE87159E39267079FA5D2EF41D756E01E0D9701BE7F715E4DCEF5667576A883DC034E36022AB62707C4E9FF9C7400BD29770FC07C66BB041F17204A63B6A52177F32B1E8AF15A818E946421552673488AA76253A5CCAEF2368C6464A36DEA011A56FFACF5F592099BADEFA4B7A72059FF1869864BDDBD14B4D32460CFD30E78C4F057F011C62A7BB5C7 +20241130074248 2 6 100 7679 2 C4FD13B23C1EF3F1B888E9E24F6E6F0D1E538D5C17287A04247451367BAAC3EB0FF3633A10C1B2BEA19F91DA18C0C52A465FA0F0371A2189AC36BFEA58F33B013352F321A0B71BF61553330EC7735E66BF920F0AB9C918AC6796F3B2C5CC7B0E9F6695400B692026845D93807363115D8E1EF92072B84941DE896DC222F2493FA43169DC5C94E9F7C645CDDC38AC8C8F8790A2078B755BF65EB099CA5682E186E7DE95CBCF7036B0BFC761137EB0B297A140C1683E9A14E78F31935D873DFB2CC33563980FD7C6EB609427A9A63D9A7ECE43889783FAF17D129A4F00A7DBA8FAFCBDD57FA7599C944D03297B7106E02A82D695E8BC0ACC860295F357FD2F60CC4A09E49450CF735A8756174A8E1458E3BE2BEA10F38D2C30E6AD7DBFA6835328A64BDFCA2318E1753C922D3AA467BB770C03BE0D3381E31655F4969009A35E4CF90B1EF5CB71A7BE424E952AEF1368142BB6E5AEECB9F7EC2034179009B7E57DF234CDDC3818BE6E637DAC7F44B109BCAA519CA77B27E4A119712A325ACC29E82C5A3E43CDED00A550ABF99495C802578A6ACB7DBCCCECD3A3857F01A9582671D87C9407409355199D627D316938076334BCDEC6635E0D6696A53E2475AAF9412167245779FA0C89CC3C08BF90313C68710D0153A3B8FA06862B6670E9498296D2C1840812D51FFEADDAE3D714A6EA7D0DAF18C134A0E26AAA99AB8B605E5FAC1814D13F5BCA134DBCF40B5C21F39EF9B4089A759876E5F22DEAF3C64DAA159B9AFEB76109429E3E42FF8DB74EF84954405C4D7B826CFBE041FF996CB053ED44BD32742681CCC843CBD031CD9DDF299EF150378F87B5F67768C77A69F779AABC032BCC3031DDAD83701E475D16040D1E064208D99313C4047BA2AA44E15CF631E4337A47318F34060DAE2ED3FB2F77F26CAF51805D86F82786B8CED61C0A0A7A8CBECD9AE3FDD266BDA632E6F6095A8E2C82A709EF2ACE20D66CC6709A5EF4EBFBA3B020BD15A5451673CA3780A459C277EEA72A1C9EF8502281BF903B2409971DC1F215C899CBBDED194CAB8A5EBB2273E3B67AEEE9A18CD03A1CC46312AAE59AEA0EFB0E5EAC8A62D6C49DC5B5D5CAC7B12CC2B293ED1D258149C6E8ADFB311328C1D5ACD4A92DFC71E9575A62920166893D715358DAE87159E39267079FA5D2EF41D756E01E0D9701BE7F715E4DCEF5667576A883DC034E36022AB62707C4E9FF9C7400BD29770FC07C66BB041F17204A63B6A52177F32B1E8AF15A818E946421552673488AA76253A5CCAEF2368C6464A36DEA011A56FFACF5F592099BADEFA4B7A72059FF1869864BDDBD14B4D32460CFD30E78C4F057F011C62F113613 +20241130074437 2 6 100 7679 2 C4FD13B23C1EF3F1B888E9E24F6E6F0D1E538D5C17287A04247451367BAAC3EB0FF3633A10C1B2BEA19F91DA18C0C52A465FA0F0371A2189AC36BFEA58F33B013352F321A0B71BF61553330EC7735E66BF920F0AB9C918AC6796F3B2C5CC7B0E9F6695400B692026845D93807363115D8E1EF92072B84941DE896DC222F2493FA43169DC5C94E9F7C645CDDC38AC8C8F8790A2078B755BF65EB099CA5682E186E7DE95CBCF7036B0BFC761137EB0B297A140C1683E9A14E78F31935D873DFB2CC33563980FD7C6EB609427A9A63D9A7ECE43889783FAF17D129A4F00A7DBA8FAFCBDD57FA7599C944D03297B7106E02A82D695E8BC0ACC860295F357FD2F60CC4A09E49450CF735A8756174A8E1458E3BE2BEA10F38D2C30E6AD7DBFA6835328A64BDFCA2318E1753C922D3AA467BB770C03BE0D3381E31655F4969009A35E4CF90B1EF5CB71A7BE424E952AEF1368142BB6E5AEECB9F7EC2034179009B7E57DF234CDDC3818BE6E637DAC7F44B109BCAA519CA77B27E4A119712A325ACC29E82C5A3E43CDED00A550ABF99495C802578A6ACB7DBCCCECD3A3857F01A9582671D87C9407409355199D627D316938076334BCDEC6635E0D6696A53E2475AAF9412167245779FA0C89CC3C08BF90313C68710D0153A3B8FA06862B6670E9498296D2C1840812D51FFEADDAE3D714A6EA7D0DAF18C134A0E26AAA99AB8B605E5FAC1814D13F5BCA134DBCF40B5C21F39EF9B4089A759876E5F22DEAF3C64DAA159B9AFEB76109429E3E42FF8DB74EF84954405C4D7B826CFBE041FF996CB053ED44BD32742681CCC843CBD031CD9DDF299EF150378F87B5F67768C77A69F779AABC032BCC3031DDAD83701E475D16040D1E064208D99313C4047BA2AA44E15CF631E4337A47318F34060DAE2ED3FB2F77F26CAF51805D86F82786B8CED61C0A0A7A8CBECD9AE3FDD266BDA632E6F6095A8E2C82A709EF2ACE20D66CC6709A5EF4EBFBA3B020BD15A5451673CA3780A459C277EEA72A1C9EF8502281BF903B2409971DC1F215C899CBBDED194CAB8A5EBB2273E3B67AEEE9A18CD03A1CC46312AAE59AEA0EFB0E5EAC8A62D6C49DC5B5D5CAC7B12CC2B293ED1D258149C6E8ADFB311328C1D5ACD4A92DFC71E9575A62920166893D715358DAE87159E39267079FA5D2EF41D756E01E0D9701BE7F715E4DCEF5667576A883DC034E36022AB62707C4E9FF9C7400BD29770FC07C66BB041F17204A63B6A52177F32B1E8AF15A818E946421552673488AA76253A5CCAEF2368C6464A36DEA011A56FFACF5F592099BADEFA4B7A72059FF1869864BDDBD14B4D32460CFD30E78C4F057F011C62F28387B +20241130083311 2 6 100 7679 2 C4FD13B23C1EF3F1B888E9E24F6E6F0D1E538D5C17287A04247451367BAAC3EB0FF3633A10C1B2BEA19F91DA18C0C52A465FA0F0371A2189AC36BFEA58F33B013352F321A0B71BF61553330EC7735E66BF920F0AB9C918AC6796F3B2C5CC7B0E9F6695400B692026845D93807363115D8E1EF92072B84941DE896DC222F2493FA43169DC5C94E9F7C645CDDC38AC8C8F8790A2078B755BF65EB099CA5682E186E7DE95CBCF7036B0BFC761137EB0B297A140C1683E9A14E78F31935D873DFB2CC33563980FD7C6EB609427A9A63D9A7ECE43889783FAF17D129A4F00A7DBA8FAFCBDD57FA7599C944D03297B7106E02A82D695E8BC0ACC860295F357FD2F60CC4A09E49450CF735A8756174A8E1458E3BE2BEA10F38D2C30E6AD7DBFA6835328A64BDFCA2318E1753C922D3AA467BB770C03BE0D3381E31655F4969009A35E4CF90B1EF5CB71A7BE424E952AEF1368142BB6E5AEECB9F7EC2034179009B7E57DF234CDDC3818BE6E637DAC7F44B109BCAA519CA77B27E4A119712A325ACC29E82C5A3E43CDED00A550ABF99495C802578A6ACB7DBCCCECD3A3857F01A9582671D87C9407409355199D627D316938076334BCDEC6635E0D6696A53E2475AAF9412167245779FA0C89CC3C08BF90313C68710D0153A3B8FA06862B6670E9498296D2C1840812D51FFEADDAE3D714A6EA7D0DAF18C134A0E26AAA99AB8B605E5FAC1814D13F5BCA134DBCF40B5C21F39EF9B4089A759876E5F22DEAF3C64DAA159B9AFEB76109429E3E42FF8DB74EF84954405C4D7B826CFBE041FF996CB053ED44BD32742681CCC843CBD031CD9DDF299EF150378F87B5F67768C77A69F779AABC032BCC3031DDAD83701E475D16040D1E064208D99313C4047BA2AA44E15CF631E4337A47318F34060DAE2ED3FB2F77F26CAF51805D86F82786B8CED61C0A0A7A8CBECD9AE3FDD266BDA632E6F6095A8E2C82A709EF2ACE20D66CC6709A5EF4EBFBA3B020BD15A5451673CA3780A459C277EEA72A1C9EF8502281BF903B2409971DC1F215C899CBBDED194CAB8A5EBB2273E3B67AEEE9A18CD03A1CC46312AAE59AEA0EFB0E5EAC8A62D6C49DC5B5D5CAC7B12CC2B293ED1D258149C6E8ADFB311328C1D5ACD4A92DFC71E9575A62920166893D715358DAE87159E39267079FA5D2EF41D756E01E0D9701BE7F715E4DCEF5667576A883DC034E36022AB62707C4E9FF9C7400BD29770FC07C66BB041F17204A63B6A52177F32B1E8AF15A818E946421552673488AA76253A5CCAEF2368C6464A36DEA011A56FFACF5F592099BADEFA4B7A72059FF1869864BDDBD14B4D32460CFD30E78C4F057F011C6325DE613 +20241130093434 2 6 100 7679 5 C4FD13B23C1EF3F1B888E9E24F6E6F0D1E538D5C17287A04247451367BAAC3EB0FF3633A10C1B2BEA19F91DA18C0C52A465FA0F0371A2189AC36BFEA58F33B013352F321A0B71BF61553330EC7735E66BF920F0AB9C918AC6796F3B2C5CC7B0E9F6695400B692026845D93807363115D8E1EF92072B84941DE896DC222F2493FA43169DC5C94E9F7C645CDDC38AC8C8F8790A2078B755BF65EB099CA5682E186E7DE95CBCF7036B0BFC761137EB0B297A140C1683E9A14E78F31935D873DFB2CC33563980FD7C6EB609427A9A63D9A7ECE43889783FAF17D129A4F00A7DBA8FAFCBDD57FA7599C944D03297B7106E02A82D695E8BC0ACC860295F357FD2F60CC4A09E49450CF735A8756174A8E1458E3BE2BEA10F38D2C30E6AD7DBFA6835328A64BDFCA2318E1753C922D3AA467BB770C03BE0D3381E31655F4969009A35E4CF90B1EF5CB71A7BE424E952AEF1368142BB6E5AEECB9F7EC2034179009B7E57DF234CDDC3818BE6E637DAC7F44B109BCAA519CA77B27E4A119712A325ACC29E82C5A3E43CDED00A550ABF99495C802578A6ACB7DBCCCECD3A3857F01A9582671D87C9407409355199D627D316938076334BCDEC6635E0D6696A53E2475AAF9412167245779FA0C89CC3C08BF90313C68710D0153A3B8FA06862B6670E9498296D2C1840812D51FFEADDAE3D714A6EA7D0DAF18C134A0E26AAA99AB8B605E5FAC1814D13F5BCA134DBCF40B5C21F39EF9B4089A759876E5F22DEAF3C64DAA159B9AFEB76109429E3E42FF8DB74EF84954405C4D7B826CFBE041FF996CB053ED44BD32742681CCC843CBD031CD9DDF299EF150378F87B5F67768C77A69F779AABC032BCC3031DDAD83701E475D16040D1E064208D99313C4047BA2AA44E15CF631E4337A47318F34060DAE2ED3FB2F77F26CAF51805D86F82786B8CED61C0A0A7A8CBECD9AE3FDD266BDA632E6F6095A8E2C82A709EF2ACE20D66CC6709A5EF4EBFBA3B020BD15A5451673CA3780A459C277EEA72A1C9EF8502281BF903B2409971DC1F215C899CBBDED194CAB8A5EBB2273E3B67AEEE9A18CD03A1CC46312AAE59AEA0EFB0E5EAC8A62D6C49DC5B5D5CAC7B12CC2B293ED1D258149C6E8ADFB311328C1D5ACD4A92DFC71E9575A62920166893D715358DAE87159E39267079FA5D2EF41D756E01E0D9701BE7F715E4DCEF5667576A883DC034E36022AB62707C4E9FF9C7400BD29770FC07C66BB041F17204A63B6A52177F32B1E8AF15A818E946421552673488AA76253A5CCAEF2368C6464A36DEA011A56FFACF5F592099BADEFA4B7A72059FF1869864BDDBD14B4D32460CFD30E78C4F057F011C636728027 +20241130105425 2 6 100 7679 2 C4FD13B23C1EF3F1B888E9E24F6E6F0D1E538D5C17287A04247451367BAAC3EB0FF3633A10C1B2BEA19F91DA18C0C52A465FA0F0371A2189AC36BFEA58F33B013352F321A0B71BF61553330EC7735E66BF920F0AB9C918AC6796F3B2C5CC7B0E9F6695400B692026845D93807363115D8E1EF92072B84941DE896DC222F2493FA43169DC5C94E9F7C645CDDC38AC8C8F8790A2078B755BF65EB099CA5682E186E7DE95CBCF7036B0BFC761137EB0B297A140C1683E9A14E78F31935D873DFB2CC33563980FD7C6EB609427A9A63D9A7ECE43889783FAF17D129A4F00A7DBA8FAFCBDD57FA7599C944D03297B7106E02A82D695E8BC0ACC860295F357FD2F60CC4A09E49450CF735A8756174A8E1458E3BE2BEA10F38D2C30E6AD7DBFA6835328A64BDFCA2318E1753C922D3AA467BB770C03BE0D3381E31655F4969009A35E4CF90B1EF5CB71A7BE424E952AEF1368142BB6E5AEECB9F7EC2034179009B7E57DF234CDDC3818BE6E637DAC7F44B109BCAA519CA77B27E4A119712A325ACC29E82C5A3E43CDED00A550ABF99495C802578A6ACB7DBCCCECD3A3857F01A9582671D87C9407409355199D627D316938076334BCDEC6635E0D6696A53E2475AAF9412167245779FA0C89CC3C08BF90313C68710D0153A3B8FA06862B6670E9498296D2C1840812D51FFEADDAE3D714A6EA7D0DAF18C134A0E26AAA99AB8B605E5FAC1814D13F5BCA134DBCF40B5C21F39EF9B4089A759876E5F22DEAF3C64DAA159B9AFEB76109429E3E42FF8DB74EF84954405C4D7B826CFBE041FF996CB053ED44BD32742681CCC843CBD031CD9DDF299EF150378F87B5F67768C77A69F779AABC032BCC3031DDAD83701E475D16040D1E064208D99313C4047BA2AA44E15CF631E4337A47318F34060DAE2ED3FB2F77F26CAF51805D86F82786B8CED61C0A0A7A8CBECD9AE3FDD266BDA632E6F6095A8E2C82A709EF2ACE20D66CC6709A5EF4EBFBA3B020BD15A5451673CA3780A459C277EEA72A1C9EF8502281BF903B2409971DC1F215C899CBBDED194CAB8A5EBB2273E3B67AEEE9A18CD03A1CC46312AAE59AEA0EFB0E5EAC8A62D6C49DC5B5D5CAC7B12CC2B293ED1D258149C6E8ADFB311328C1D5ACD4A92DFC71E9575A62920166893D715358DAE87159E39267079FA5D2EF41D756E01E0D9701BE7F715E4DCEF5667576A883DC034E36022AB62707C4E9FF9C7400BD29770FC07C66BB041F17204A63B6A52177F32B1E8AF15A818E946421552673488AA76253A5CCAEF2368C6464A36DEA011A56FFACF5F592099BADEFA4B7A72059FF1869864BDDBD14B4D32460CFD30E78C4F057F011C63BCFA3E3 +20241130105534 2 6 100 7679 5 C4FD13B23C1EF3F1B888E9E24F6E6F0D1E538D5C17287A04247451367BAAC3EB0FF3633A10C1B2BEA19F91DA18C0C52A465FA0F0371A2189AC36BFEA58F33B013352F321A0B71BF61553330EC7735E66BF920F0AB9C918AC6796F3B2C5CC7B0E9F6695400B692026845D93807363115D8E1EF92072B84941DE896DC222F2493FA43169DC5C94E9F7C645CDDC38AC8C8F8790A2078B755BF65EB099CA5682E186E7DE95CBCF7036B0BFC761137EB0B297A140C1683E9A14E78F31935D873DFB2CC33563980FD7C6EB609427A9A63D9A7ECE43889783FAF17D129A4F00A7DBA8FAFCBDD57FA7599C944D03297B7106E02A82D695E8BC0ACC860295F357FD2F60CC4A09E49450CF735A8756174A8E1458E3BE2BEA10F38D2C30E6AD7DBFA6835328A64BDFCA2318E1753C922D3AA467BB770C03BE0D3381E31655F4969009A35E4CF90B1EF5CB71A7BE424E952AEF1368142BB6E5AEECB9F7EC2034179009B7E57DF234CDDC3818BE6E637DAC7F44B109BCAA519CA77B27E4A119712A325ACC29E82C5A3E43CDED00A550ABF99495C802578A6ACB7DBCCCECD3A3857F01A9582671D87C9407409355199D627D316938076334BCDEC6635E0D6696A53E2475AAF9412167245779FA0C89CC3C08BF90313C68710D0153A3B8FA06862B6670E9498296D2C1840812D51FFEADDAE3D714A6EA7D0DAF18C134A0E26AAA99AB8B605E5FAC1814D13F5BCA134DBCF40B5C21F39EF9B4089A759876E5F22DEAF3C64DAA159B9AFEB76109429E3E42FF8DB74EF84954405C4D7B826CFBE041FF996CB053ED44BD32742681CCC843CBD031CD9DDF299EF150378F87B5F67768C77A69F779AABC032BCC3031DDAD83701E475D16040D1E064208D99313C4047BA2AA44E15CF631E4337A47318F34060DAE2ED3FB2F77F26CAF51805D86F82786B8CED61C0A0A7A8CBECD9AE3FDD266BDA632E6F6095A8E2C82A709EF2ACE20D66CC6709A5EF4EBFBA3B020BD15A5451673CA3780A459C277EEA72A1C9EF8502281BF903B2409971DC1F215C899CBBDED194CAB8A5EBB2273E3B67AEEE9A18CD03A1CC46312AAE59AEA0EFB0E5EAC8A62D6C49DC5B5D5CAC7B12CC2B293ED1D258149C6E8ADFB311328C1D5ACD4A92DFC71E9575A62920166893D715358DAE87159E39267079FA5D2EF41D756E01E0D9701BE7F715E4DCEF5667576A883DC034E36022AB62707C4E9FF9C7400BD29770FC07C66BB041F17204A63B6A52177F32B1E8AF15A818E946421552673488AA76253A5CCAEF2368C6464A36DEA011A56FFACF5F592099BADEFA4B7A72059FF1869864BDDBD14B4D32460CFD30E78C4F057F011C63BDA41EF +20241130105809 2 6 100 7679 2 C4FD13B23C1EF3F1B888E9E24F6E6F0D1E538D5C17287A04247451367BAAC3EB0FF3633A10C1B2BEA19F91DA18C0C52A465FA0F0371A2189AC36BFEA58F33B013352F321A0B71BF61553330EC7735E66BF920F0AB9C918AC6796F3B2C5CC7B0E9F6695400B692026845D93807363115D8E1EF92072B84941DE896DC222F2493FA43169DC5C94E9F7C645CDDC38AC8C8F8790A2078B755BF65EB099CA5682E186E7DE95CBCF7036B0BFC761137EB0B297A140C1683E9A14E78F31935D873DFB2CC33563980FD7C6EB609427A9A63D9A7ECE43889783FAF17D129A4F00A7DBA8FAFCBDD57FA7599C944D03297B7106E02A82D695E8BC0ACC860295F357FD2F60CC4A09E49450CF735A8756174A8E1458E3BE2BEA10F38D2C30E6AD7DBFA6835328A64BDFCA2318E1753C922D3AA467BB770C03BE0D3381E31655F4969009A35E4CF90B1EF5CB71A7BE424E952AEF1368142BB6E5AEECB9F7EC2034179009B7E57DF234CDDC3818BE6E637DAC7F44B109BCAA519CA77B27E4A119712A325ACC29E82C5A3E43CDED00A550ABF99495C802578A6ACB7DBCCCECD3A3857F01A9582671D87C9407409355199D627D316938076334BCDEC6635E0D6696A53E2475AAF9412167245779FA0C89CC3C08BF90313C68710D0153A3B8FA06862B6670E9498296D2C1840812D51FFEADDAE3D714A6EA7D0DAF18C134A0E26AAA99AB8B605E5FAC1814D13F5BCA134DBCF40B5C21F39EF9B4089A759876E5F22DEAF3C64DAA159B9AFEB76109429E3E42FF8DB74EF84954405C4D7B826CFBE041FF996CB053ED44BD32742681CCC843CBD031CD9DDF299EF150378F87B5F67768C77A69F779AABC032BCC3031DDAD83701E475D16040D1E064208D99313C4047BA2AA44E15CF631E4337A47318F34060DAE2ED3FB2F77F26CAF51805D86F82786B8CED61C0A0A7A8CBECD9AE3FDD266BDA632E6F6095A8E2C82A709EF2ACE20D66CC6709A5EF4EBFBA3B020BD15A5451673CA3780A459C277EEA72A1C9EF8502281BF903B2409971DC1F215C899CBBDED194CAB8A5EBB2273E3B67AEEE9A18CD03A1CC46312AAE59AEA0EFB0E5EAC8A62D6C49DC5B5D5CAC7B12CC2B293ED1D258149C6E8ADFB311328C1D5ACD4A92DFC71E9575A62920166893D715358DAE87159E39267079FA5D2EF41D756E01E0D9701BE7F715E4DCEF5667576A883DC034E36022AB62707C4E9FF9C7400BD29770FC07C66BB041F17204A63B6A52177F32B1E8AF15A818E946421552673488AA76253A5CCAEF2368C6464A36DEA011A56FFACF5F592099BADEFA4B7A72059FF1869864BDDBD14B4D32460CFD30E78C4F057F011C63BFFF55B +20241130123724 2 6 100 7679 2 C4FD13B23C1EF3F1B888E9E24F6E6F0D1E538D5C17287A04247451367BAAC3EB0FF3633A10C1B2BEA19F91DA18C0C52A465FA0F0371A2189AC36BFEA58F33B013352F321A0B71BF61553330EC7735E66BF920F0AB9C918AC6796F3B2C5CC7B0E9F6695400B692026845D93807363115D8E1EF92072B84941DE896DC222F2493FA43169DC5C94E9F7C645CDDC38AC8C8F8790A2078B755BF65EB099CA5682E186E7DE95CBCF7036B0BFC761137EB0B297A140C1683E9A14E78F31935D873DFB2CC33563980FD7C6EB609427A9A63D9A7ECE43889783FAF17D129A4F00A7DBA8FAFCBDD57FA7599C944D03297B7106E02A82D695E8BC0ACC860295F357FD2F60CC4A09E49450CF735A8756174A8E1458E3BE2BEA10F38D2C30E6AD7DBFA6835328A64BDFCA2318E1753C922D3AA467BB770C03BE0D3381E31655F4969009A35E4CF90B1EF5CB71A7BE424E952AEF1368142BB6E5AEECB9F7EC2034179009B7E57DF234CDDC3818BE6E637DAC7F44B109BCAA519CA77B27E4A119712A325ACC29E82C5A3E43CDED00A550ABF99495C802578A6ACB7DBCCCECD3A3857F01A9582671D87C9407409355199D627D316938076334BCDEC6635E0D6696A53E2475AAF9412167245779FA0C89CC3C08BF90313C68710D0153A3B8FA06862B6670E9498296D2C1840812D51FFEADDAE3D714A6EA7D0DAF18C134A0E26AAA99AB8B605E5FAC1814D13F5BCA134DBCF40B5C21F39EF9B4089A759876E5F22DEAF3C64DAA159B9AFEB76109429E3E42FF8DB74EF84954405C4D7B826CFBE041FF996CB053ED44BD32742681CCC843CBD031CD9DDF299EF150378F87B5F67768C77A69F779AABC032BCC3031DDAD83701E475D16040D1E064208D99313C4047BA2AA44E15CF631E4337A47318F34060DAE2ED3FB2F77F26CAF51805D86F82786B8CED61C0A0A7A8CBECD9AE3FDD266BDA632E6F6095A8E2C82A709EF2ACE20D66CC6709A5EF4EBFBA3B020BD15A5451673CA3780A459C277EEA72A1C9EF8502281BF903B2409971DC1F215C899CBBDED194CAB8A5EBB2273E3B67AEEE9A18CD03A1CC46312AAE59AEA0EFB0E5EAC8A62D6C49DC5B5D5CAC7B12CC2B293ED1D258149C6E8ADFB311328C1D5ACD4A92DFC71E9575A62920166893D715358DAE87159E39267079FA5D2EF41D756E01E0D9701BE7F715E4DCEF5667576A883DC034E36022AB62707C4E9FF9C7400BD29770FC07C66BB041F17204A63B6A52177F32B1E8AF15A818E946421552673488AA76253A5CCAEF2368C6464A36DEA011A56FFACF5F592099BADEFA4B7A72059FF1869864BDDBD14B4D32460CFD30E78C4F057F011C642A90F43 +20241130131041 2 6 100 7679 5 C4FD13B23C1EF3F1B888E9E24F6E6F0D1E538D5C17287A04247451367BAAC3EB0FF3633A10C1B2BEA19F91DA18C0C52A465FA0F0371A2189AC36BFEA58F33B013352F321A0B71BF61553330EC7735E66BF920F0AB9C918AC6796F3B2C5CC7B0E9F6695400B692026845D93807363115D8E1EF92072B84941DE896DC222F2493FA43169DC5C94E9F7C645CDDC38AC8C8F8790A2078B755BF65EB099CA5682E186E7DE95CBCF7036B0BFC761137EB0B297A140C1683E9A14E78F31935D873DFB2CC33563980FD7C6EB609427A9A63D9A7ECE43889783FAF17D129A4F00A7DBA8FAFCBDD57FA7599C944D03297B7106E02A82D695E8BC0ACC860295F357FD2F60CC4A09E49450CF735A8756174A8E1458E3BE2BEA10F38D2C30E6AD7DBFA6835328A64BDFCA2318E1753C922D3AA467BB770C03BE0D3381E31655F4969009A35E4CF90B1EF5CB71A7BE424E952AEF1368142BB6E5AEECB9F7EC2034179009B7E57DF234CDDC3818BE6E637DAC7F44B109BCAA519CA77B27E4A119712A325ACC29E82C5A3E43CDED00A550ABF99495C802578A6ACB7DBCCCECD3A3857F01A9582671D87C9407409355199D627D316938076334BCDEC6635E0D6696A53E2475AAF9412167245779FA0C89CC3C08BF90313C68710D0153A3B8FA06862B6670E9498296D2C1840812D51FFEADDAE3D714A6EA7D0DAF18C134A0E26AAA99AB8B605E5FAC1814D13F5BCA134DBCF40B5C21F39EF9B4089A759876E5F22DEAF3C64DAA159B9AFEB76109429E3E42FF8DB74EF84954405C4D7B826CFBE041FF996CB053ED44BD32742681CCC843CBD031CD9DDF299EF150378F87B5F67768C77A69F779AABC032BCC3031DDAD83701E475D16040D1E064208D99313C4047BA2AA44E15CF631E4337A47318F34060DAE2ED3FB2F77F26CAF51805D86F82786B8CED61C0A0A7A8CBECD9AE3FDD266BDA632E6F6095A8E2C82A709EF2ACE20D66CC6709A5EF4EBFBA3B020BD15A5451673CA3780A459C277EEA72A1C9EF8502281BF903B2409971DC1F215C899CBBDED194CAB8A5EBB2273E3B67AEEE9A18CD03A1CC46312AAE59AEA0EFB0E5EAC8A62D6C49DC5B5D5CAC7B12CC2B293ED1D258149C6E8ADFB311328C1D5ACD4A92DFC71E9575A62920166893D715358DAE87159E39267079FA5D2EF41D756E01E0D9701BE7F715E4DCEF5667576A883DC034E36022AB62707C4E9FF9C7400BD29770FC07C66BB041F17204A63B6A52177F32B1E8AF15A818E946421552673488AA76253A5CCAEF2368C6464A36DEA011A56FFACF5F592099BADEFA4B7A72059FF1869864BDDBD14B4D32460CFD30E78C4F057F011C644DFE51F +20241130150424 2 6 100 7679 2 C4FD13B23C1EF3F1B888E9E24F6E6F0D1E538D5C17287A04247451367BAAC3EB0FF3633A10C1B2BEA19F91DA18C0C52A465FA0F0371A2189AC36BFEA58F33B013352F321A0B71BF61553330EC7735E66BF920F0AB9C918AC6796F3B2C5CC7B0E9F6695400B692026845D93807363115D8E1EF92072B84941DE896DC222F2493FA43169DC5C94E9F7C645CDDC38AC8C8F8790A2078B755BF65EB099CA5682E186E7DE95CBCF7036B0BFC761137EB0B297A140C1683E9A14E78F31935D873DFB2CC33563980FD7C6EB609427A9A63D9A7ECE43889783FAF17D129A4F00A7DBA8FAFCBDD57FA7599C944D03297B7106E02A82D695E8BC0ACC860295F357FD2F60CC4A09E49450CF735A8756174A8E1458E3BE2BEA10F38D2C30E6AD7DBFA6835328A64BDFCA2318E1753C922D3AA467BB770C03BE0D3381E31655F4969009A35E4CF90B1EF5CB71A7BE424E952AEF1368142BB6E5AEECB9F7EC2034179009B7E57DF234CDDC3818BE6E637DAC7F44B109BCAA519CA77B27E4A119712A325ACC29E82C5A3E43CDED00A550ABF99495C802578A6ACB7DBCCCECD3A3857F01A9582671D87C9407409355199D627D316938076334BCDEC6635E0D6696A53E2475AAF9412167245779FA0C89CC3C08BF90313C68710D0153A3B8FA06862B6670E9498296D2C1840812D51FFEADDAE3D714A6EA7D0DAF18C134A0E26AAA99AB8B605E5FAC1814D13F5BCA134DBCF40B5C21F39EF9B4089A759876E5F22DEAF3C64DAA159B9AFEB76109429E3E42FF8DB74EF84954405C4D7B826CFBE041FF996CB053ED44BD32742681CCC843CBD031CD9DDF299EF150378F87B5F67768C77A69F779AABC032BCC3031DDAD83701E475D16040D1E064208D99313C4047BA2AA44E15CF631E4337A47318F34060DAE2ED3FB2F77F26CAF51805D86F82786B8CED61C0A0A7A8CBECD9AE3FDD266BDA632E6F6095A8E2C82A709EF2ACE20D66CC6709A5EF4EBFBA3B020BD15A5451673CA3780A459C277EEA72A1C9EF8502281BF903B2409971DC1F215C899CBBDED194CAB8A5EBB2273E3B67AEEE9A18CD03A1CC46312AAE59AEA0EFB0E5EAC8A62D6C49DC5B5D5CAC7B12CC2B293ED1D258149C6E8ADFB311328C1D5ACD4A92DFC71E9575A62920166893D715358DAE87159E39267079FA5D2EF41D756E01E0D9701BE7F715E4DCEF5667576A883DC034E36022AB62707C4E9FF9C7400BD29770FC07C66BB041F17204A63B6A52177F32B1E8AF15A818E946421552673488AA76253A5CCAEF2368C6464A36DEA011A56FFACF5F592099BADEFA4B7A72059FF1869864BDDBD14B4D32460CFD30E78C4F057F011C64C717C8B +20241130162824 2 6 100 7679 2 C4FD13B23C1EF3F1B888E9E24F6E6F0D1E538D5C17287A04247451367BAAC3EB0FF3633A10C1B2BEA19F91DA18C0C52A465FA0F0371A2189AC36BFEA58F33B013352F321A0B71BF61553330EC7735E66BF920F0AB9C918AC6796F3B2C5CC7B0E9F6695400B692026845D93807363115D8E1EF92072B84941DE896DC222F2493FA43169DC5C94E9F7C645CDDC38AC8C8F8790A2078B755BF65EB099CA5682E186E7DE95CBCF7036B0BFC761137EB0B297A140C1683E9A14E78F31935D873DFB2CC33563980FD7C6EB609427A9A63D9A7ECE43889783FAF17D129A4F00A7DBA8FAFCBDD57FA7599C944D03297B7106E02A82D695E8BC0ACC860295F357FD2F60CC4A09E49450CF735A8756174A8E1458E3BE2BEA10F38D2C30E6AD7DBFA6835328A64BDFCA2318E1753C922D3AA467BB770C03BE0D3381E31655F4969009A35E4CF90B1EF5CB71A7BE424E952AEF1368142BB6E5AEECB9F7EC2034179009B7E57DF234CDDC3818BE6E637DAC7F44B109BCAA519CA77B27E4A119712A325ACC29E82C5A3E43CDED00A550ABF99495C802578A6ACB7DBCCCECD3A3857F01A9582671D87C9407409355199D627D316938076334BCDEC6635E0D6696A53E2475AAF9412167245779FA0C89CC3C08BF90313C68710D0153A3B8FA06862B6670E9498296D2C1840812D51FFEADDAE3D714A6EA7D0DAF18C134A0E26AAA99AB8B605E5FAC1814D13F5BCA134DBCF40B5C21F39EF9B4089A759876E5F22DEAF3C64DAA159B9AFEB76109429E3E42FF8DB74EF84954405C4D7B826CFBE041FF996CB053ED44BD32742681CCC843CBD031CD9DDF299EF150378F87B5F67768C77A69F779AABC032BCC3031DDAD83701E475D16040D1E064208D99313C4047BA2AA44E15CF631E4337A47318F34060DAE2ED3FB2F77F26CAF51805D86F82786B8CED61C0A0A7A8CBECD9AE3FDD266BDA632E6F6095A8E2C82A709EF2ACE20D66CC6709A5EF4EBFBA3B020BD15A5451673CA3780A459C277EEA72A1C9EF8502281BF903B2409971DC1F215C899CBBDED194CAB8A5EBB2273E3B67AEEE9A18CD03A1CC46312AAE59AEA0EFB0E5EAC8A62D6C49DC5B5D5CAC7B12CC2B293ED1D258149C6E8ADFB311328C1D5ACD4A92DFC71E9575A62920166893D715358DAE87159E39267079FA5D2EF41D756E01E0D9701BE7F715E4DCEF5667576A883DC034E36022AB62707C4E9FF9C7400BD29770FC07C66BB041F17204A63B6A52177F32B1E8AF15A818E946421552673488AA76253A5CCAEF2368C6464A36DEA011A56FFACF5F592099BADEFA4B7A72059FF1869864BDDBD14B4D32460CFD30E78C4F057F011C65210D3FB +20241130172212 2 6 100 7679 5 C4FD13B23C1EF3F1B888E9E24F6E6F0D1E538D5C17287A04247451367BAAC3EB0FF3633A10C1B2BEA19F91DA18C0C52A465FA0F0371A2189AC36BFEA58F33B013352F321A0B71BF61553330EC7735E66BF920F0AB9C918AC6796F3B2C5CC7B0E9F6695400B692026845D93807363115D8E1EF92072B84941DE896DC222F2493FA43169DC5C94E9F7C645CDDC38AC8C8F8790A2078B755BF65EB099CA5682E186E7DE95CBCF7036B0BFC761137EB0B297A140C1683E9A14E78F31935D873DFB2CC33563980FD7C6EB609427A9A63D9A7ECE43889783FAF17D129A4F00A7DBA8FAFCBDD57FA7599C944D03297B7106E02A82D695E8BC0ACC860295F357FD2F60CC4A09E49450CF735A8756174A8E1458E3BE2BEA10F38D2C30E6AD7DBFA6835328A64BDFCA2318E1753C922D3AA467BB770C03BE0D3381E31655F4969009A35E4CF90B1EF5CB71A7BE424E952AEF1368142BB6E5AEECB9F7EC2034179009B7E57DF234CDDC3818BE6E637DAC7F44B109BCAA519CA77B27E4A119712A325ACC29E82C5A3E43CDED00A550ABF99495C802578A6ACB7DBCCCECD3A3857F01A9582671D87C9407409355199D627D316938076334BCDEC6635E0D6696A53E2475AAF9412167245779FA0C89CC3C08BF90313C68710D0153A3B8FA06862B6670E9498296D2C1840812D51FFEADDAE3D714A6EA7D0DAF18C134A0E26AAA99AB8B605E5FAC1814D13F5BCA134DBCF40B5C21F39EF9B4089A759876E5F22DEAF3C64DAA159B9AFEB76109429E3E42FF8DB74EF84954405C4D7B826CFBE041FF996CB053ED44BD32742681CCC843CBD031CD9DDF299EF150378F87B5F67768C77A69F779AABC032BCC3031DDAD83701E475D16040D1E064208D99313C4047BA2AA44E15CF631E4337A47318F34060DAE2ED3FB2F77F26CAF51805D86F82786B8CED61C0A0A7A8CBECD9AE3FDD266BDA632E6F6095A8E2C82A709EF2ACE20D66CC6709A5EF4EBFBA3B020BD15A5451673CA3780A459C277EEA72A1C9EF8502281BF903B2409971DC1F215C899CBBDED194CAB8A5EBB2273E3B67AEEE9A18CD03A1CC46312AAE59AEA0EFB0E5EAC8A62D6C49DC5B5D5CAC7B12CC2B293ED1D258149C6E8ADFB311328C1D5ACD4A92DFC71E9575A62920166893D715358DAE87159E39267079FA5D2EF41D756E01E0D9701BE7F715E4DCEF5667576A883DC034E36022AB62707C4E9FF9C7400BD29770FC07C66BB041F17204A63B6A52177F32B1E8AF15A818E946421552673488AA76253A5CCAEF2368C6464A36DEA011A56FFACF5F592099BADEFA4B7A72059FF1869864BDDBD14B4D32460CFD30E78C4F057F011C655A47F4F +20241130174557 2 6 100 7679 2 C4FD13B23C1EF3F1B888E9E24F6E6F0D1E538D5C17287A04247451367BAAC3EB0FF3633A10C1B2BEA19F91DA18C0C52A465FA0F0371A2189AC36BFEA58F33B013352F321A0B71BF61553330EC7735E66BF920F0AB9C918AC6796F3B2C5CC7B0E9F6695400B692026845D93807363115D8E1EF92072B84941DE896DC222F2493FA43169DC5C94E9F7C645CDDC38AC8C8F8790A2078B755BF65EB099CA5682E186E7DE95CBCF7036B0BFC761137EB0B297A140C1683E9A14E78F31935D873DFB2CC33563980FD7C6EB609427A9A63D9A7ECE43889783FAF17D129A4F00A7DBA8FAFCBDD57FA7599C944D03297B7106E02A82D695E8BC0ACC860295F357FD2F60CC4A09E49450CF735A8756174A8E1458E3BE2BEA10F38D2C30E6AD7DBFA6835328A64BDFCA2318E1753C922D3AA467BB770C03BE0D3381E31655F4969009A35E4CF90B1EF5CB71A7BE424E952AEF1368142BB6E5AEECB9F7EC2034179009B7E57DF234CDDC3818BE6E637DAC7F44B109BCAA519CA77B27E4A119712A325ACC29E82C5A3E43CDED00A550ABF99495C802578A6ACB7DBCCCECD3A3857F01A9582671D87C9407409355199D627D316938076334BCDEC6635E0D6696A53E2475AAF9412167245779FA0C89CC3C08BF90313C68710D0153A3B8FA06862B6670E9498296D2C1840812D51FFEADDAE3D714A6EA7D0DAF18C134A0E26AAA99AB8B605E5FAC1814D13F5BCA134DBCF40B5C21F39EF9B4089A759876E5F22DEAF3C64DAA159B9AFEB76109429E3E42FF8DB74EF84954405C4D7B826CFBE041FF996CB053ED44BD32742681CCC843CBD031CD9DDF299EF150378F87B5F67768C77A69F779AABC032BCC3031DDAD83701E475D16040D1E064208D99313C4047BA2AA44E15CF631E4337A47318F34060DAE2ED3FB2F77F26CAF51805D86F82786B8CED61C0A0A7A8CBECD9AE3FDD266BDA632E6F6095A8E2C82A709EF2ACE20D66CC6709A5EF4EBFBA3B020BD15A5451673CA3780A459C277EEA72A1C9EF8502281BF903B2409971DC1F215C899CBBDED194CAB8A5EBB2273E3B67AEEE9A18CD03A1CC46312AAE59AEA0EFB0E5EAC8A62D6C49DC5B5D5CAC7B12CC2B293ED1D258149C6E8ADFB311328C1D5ACD4A92DFC71E9575A62920166893D715358DAE87159E39267079FA5D2EF41D756E01E0D9701BE7F715E4DCEF5667576A883DC034E36022AB62707C4E9FF9C7400BD29770FC07C66BB041F17204A63B6A52177F32B1E8AF15A818E946421552673488AA76253A5CCAEF2368C6464A36DEA011A56FFACF5F592099BADEFA4B7A72059FF1869864BDDBD14B4D32460CFD30E78C4F057F011C657367ECB +20241130215425 2 6 100 7679 5 C4FD13B23C1EF3F1B888E9E24F6E6F0D1E538D5C17287A04247451367BAAC3EB0FF3633A10C1B2BEA19F91DA18C0C52A465FA0F0371A2189AC36BFEA58F33B013352F321A0B71BF61553330EC7735E66BF920F0AB9C918AC6796F3B2C5CC7B0E9F6695400B692026845D93807363115D8E1EF92072B84941DE896DC222F2493FA43169DC5C94E9F7C645CDDC38AC8C8F8790A2078B755BF65EB099CA5682E186E7DE95CBCF7036B0BFC761137EB0B297A140C1683E9A14E78F31935D873DFB2CC33563980FD7C6EB609427A9A63D9A7ECE43889783FAF17D129A4F00A7DBA8FAFCBDD57FA7599C944D03297B7106E02A82D695E8BC0ACC860295F357FD2F60CC4A09E49450CF735A8756174A8E1458E3BE2BEA10F38D2C30E6AD7DBFA6835328A64BDFCA2318E1753C922D3AA467BB770C03BE0D3381E31655F4969009A35E4CF90B1EF5CB71A7BE424E952AEF1368142BB6E5AEECB9F7EC2034179009B7E57DF234CDDC3818BE6E637DAC7F44B109BCAA519CA77B27E4A119712A325ACC29E82C5A3E43CDED00A550ABF99495C802578A6ACB7DBCCCECD3A3857F01A9582671D87C9407409355199D627D316938076334BCDEC6635E0D6696A53E2475AAF9412167245779FA0C89CC3C08BF90313C68710D0153A3B8FA06862B6670E9498296D2C1840812D51FFEADDAE3D714A6EA7D0DAF18C134A0E26AAA99AB8B605E5FAC1814D13F5BCA134DBCF40B5C21F39EF9B4089A759876E5F22DEAF3C64DAA159B9AFEB76109429E3E42FF8DB74EF84954405C4D7B826CFBE041FF996CB053ED44BD32742681CCC843CBD031CD9DDF299EF150378F87B5F67768C77A69F779AABC032BCC3031DDAD83701E475D16040D1E064208D99313C4047BA2AA44E15CF631E4337A47318F34060DAE2ED3FB2F77F26CAF51805D86F82786B8CED61C0A0A7A8CBECD9AE3FDD266BDA632E6F6095A8E2C82A709EF2ACE20D66CC6709A5EF4EBFBA3B020BD15A5451673CA3780A459C277EEA72A1C9EF8502281BF903B2409971DC1F215C899CBBDED194CAB8A5EBB2273E3B67AEEE9A18CD03A1CC46312AAE59AEA0EFB0E5EAC8A62D6C49DC5B5D5CAC7B12CC2B293ED1D258149C6E8ADFB311328C1D5ACD4A92DFC71E9575A62920166893D715358DAE87159E39267079FA5D2EF41D756E01E0D9701BE7F715E4DCEF5667576A883DC034E36022AB62707C4E9FF9C7400BD29770FC07C66BB041F17204A63B6A52177F32B1E8AF15A818E946421552673488AA76253A5CCAEF2368C6464A36DEA011A56FFACF5F592099BADEFA4B7A72059FF1869864BDDBD14B4D32460CFD30E78C4F057F011C66800A377 +20241130230337 2 6 100 7679 5 C4FD13B23C1EF3F1B888E9E24F6E6F0D1E538D5C17287A04247451367BAAC3EB0FF3633A10C1B2BEA19F91DA18C0C52A465FA0F0371A2189AC36BFEA58F33B013352F321A0B71BF61553330EC7735E66BF920F0AB9C918AC6796F3B2C5CC7B0E9F6695400B692026845D93807363115D8E1EF92072B84941DE896DC222F2493FA43169DC5C94E9F7C645CDDC38AC8C8F8790A2078B755BF65EB099CA5682E186E7DE95CBCF7036B0BFC761137EB0B297A140C1683E9A14E78F31935D873DFB2CC33563980FD7C6EB609427A9A63D9A7ECE43889783FAF17D129A4F00A7DBA8FAFCBDD57FA7599C944D03297B7106E02A82D695E8BC0ACC860295F357FD2F60CC4A09E49450CF735A8756174A8E1458E3BE2BEA10F38D2C30E6AD7DBFA6835328A64BDFCA2318E1753C922D3AA467BB770C03BE0D3381E31655F4969009A35E4CF90B1EF5CB71A7BE424E952AEF1368142BB6E5AEECB9F7EC2034179009B7E57DF234CDDC3818BE6E637DAC7F44B109BCAA519CA77B27E4A119712A325ACC29E82C5A3E43CDED00A550ABF99495C802578A6ACB7DBCCCECD3A3857F01A9582671D87C9407409355199D627D316938076334BCDEC6635E0D6696A53E2475AAF9412167245779FA0C89CC3C08BF90313C68710D0153A3B8FA06862B6670E9498296D2C1840812D51FFEADDAE3D714A6EA7D0DAF18C134A0E26AAA99AB8B605E5FAC1814D13F5BCA134DBCF40B5C21F39EF9B4089A759876E5F22DEAF3C64DAA159B9AFEB76109429E3E42FF8DB74EF84954405C4D7B826CFBE041FF996CB053ED44BD32742681CCC843CBD031CD9DDF299EF150378F87B5F67768C77A69F779AABC032BCC3031DDAD83701E475D16040D1E064208D99313C4047BA2AA44E15CF631E4337A47318F34060DAE2ED3FB2F77F26CAF51805D86F82786B8CED61C0A0A7A8CBECD9AE3FDD266BDA632E6F6095A8E2C82A709EF2ACE20D66CC6709A5EF4EBFBA3B020BD15A5451673CA3780A459C277EEA72A1C9EF8502281BF903B2409971DC1F215C899CBBDED194CAB8A5EBB2273E3B67AEEE9A18CD03A1CC46312AAE59AEA0EFB0E5EAC8A62D6C49DC5B5D5CAC7B12CC2B293ED1D258149C6E8ADFB311328C1D5ACD4A92DFC71E9575A62920166893D715358DAE87159E39267079FA5D2EF41D756E01E0D9701BE7F715E4DCEF5667576A883DC034E36022AB62707C4E9FF9C7400BD29770FC07C66BB041F17204A63B6A52177F32B1E8AF15A818E946421552673488AA76253A5CCAEF2368C6464A36DEA011A56FFACF5F592099BADEFA4B7A72059FF1869864BDDBD14B4D32460CFD30E78C4F057F011C66C9D27F7 +20241201025521 2 6 100 7679 5 C4FD13B23C1EF3F1B888E9E24F6E6F0D1E538D5C17287A04247451367BAAC3EB0FF3633A10C1B2BEA19F91DA18C0C52A465FA0F0371A2189AC36BFEA58F33B013352F321A0B71BF61553330EC7735E66BF920F0AB9C918AC6796F3B2C5CC7B0E9F6695400B692026845D93807363115D8E1EF92072B84941DE896DC222F2493FA43169DC5C94E9F7C645CDDC38AC8C8F8790A2078B755BF65EB099CA5682E186E7DE95CBCF7036B0BFC761137EB0B297A140C1683E9A14E78F31935D873DFB2CC33563980FD7C6EB609427A9A63D9A7ECE43889783FAF17D129A4F00A7DBA8FAFCBDD57FA7599C944D03297B7106E02A82D695E8BC0ACC860295F357FD2F60CC4A09E49450CF735A8756174A8E1458E3BE2BEA10F38D2C30E6AD7DBFA6835328A64BDFCA2318E1753C922D3AA467BB770C03BE0D3381E31655F4969009A35E4CF90B1EF5CB71A7BE424E952AEF1368142BB6E5AEECB9F7EC2034179009B7E57DF234CDDC3818BE6E637DAC7F44B109BCAA519CA77B27E4A119712A325ACC29E82C5A3E43CDED00A550ABF99495C802578A6ACB7DBCCCECD3A3857F01A9582671D87C9407409355199D627D316938076334BCDEC6635E0D6696A53E2475AAF9412167245779FA0C89CC3C08BF90313C68710D0153A3B8FA06862B6670E9498296D2C1840812D51FFEADDAE3D714A6EA7D0DAF18C134A0E26AAA99AB8B605E5FAC1814D13F5BCA134DBCF40B5C21F39EF9B4089A759876E5F22DEAF3C64DAA159B9AFEB76109429E3E42FF8DB74EF84954405C4D7B826CFBE041FF996CB053ED44BD32742681CCC843CBD031CD9DDF299EF150378F87B5F67768C77A69F779AABC032BCC3031DDAD83701E475D16040D1E064208D99313C4047BA2AA44E15CF631E4337A47318F34060DAE2ED3FB2F77F26CAF51805D86F82786B8CED61C0A0A7A8CBECD9AE3FDD266BDA632E6F6095A8E2C82A709EF2ACE20D66CC6709A5EF4EBFBA3B020BD15A5451673CA3780A459C277EEA72A1C9EF8502281BF903B2409971DC1F215C899CBBDED194CAB8A5EBB2273E3B67AEEE9A18CD03A1CC46312AAE59AEA0EFB0E5EAC8A62D6C49DC5B5D5CAC7B12CC2B293ED1D258149C6E8ADFB311328C1D5ACD4A92DFC71E9575A62920166893D715358DAE87159E39267079FA5D2EF41D756E01E0D9701BE7F715E4DCEF5667576A883DC034E36022AB62707C4E9FF9C7400BD29770FC07C66BB041F17204A63B6A52177F32B1E8AF15A818E946421552673488AA76253A5CCAEF2368C6464A36DEA011A56FFACF5F592099BADEFA4B7A72059FF1869864BDDBD14B4D32460CFD30E78C4F057F011C67C131CEF +20241201034250 2 6 100 7679 5 C4FD13B23C1EF3F1B888E9E24F6E6F0D1E538D5C17287A04247451367BAAC3EB0FF3633A10C1B2BEA19F91DA18C0C52A465FA0F0371A2189AC36BFEA58F33B013352F321A0B71BF61553330EC7735E66BF920F0AB9C918AC6796F3B2C5CC7B0E9F6695400B692026845D93807363115D8E1EF92072B84941DE896DC222F2493FA43169DC5C94E9F7C645CDDC38AC8C8F8790A2078B755BF65EB099CA5682E186E7DE95CBCF7036B0BFC761137EB0B297A140C1683E9A14E78F31935D873DFB2CC33563980FD7C6EB609427A9A63D9A7ECE43889783FAF17D129A4F00A7DBA8FAFCBDD57FA7599C944D03297B7106E02A82D695E8BC0ACC860295F357FD2F60CC4A09E49450CF735A8756174A8E1458E3BE2BEA10F38D2C30E6AD7DBFA6835328A64BDFCA2318E1753C922D3AA467BB770C03BE0D3381E31655F4969009A35E4CF90B1EF5CB71A7BE424E952AEF1368142BB6E5AEECB9F7EC2034179009B7E57DF234CDDC3818BE6E637DAC7F44B109BCAA519CA77B27E4A119712A325ACC29E82C5A3E43CDED00A550ABF99495C802578A6ACB7DBCCCECD3A3857F01A9582671D87C9407409355199D627D316938076334BCDEC6635E0D6696A53E2475AAF9412167245779FA0C89CC3C08BF90313C68710D0153A3B8FA06862B6670E9498296D2C1840812D51FFEADDAE3D714A6EA7D0DAF18C134A0E26AAA99AB8B605E5FAC1814D13F5BCA134DBCF40B5C21F39EF9B4089A759876E5F22DEAF3C64DAA159B9AFEB76109429E3E42FF8DB74EF84954405C4D7B826CFBE041FF996CB053ED44BD32742681CCC843CBD031CD9DDF299EF150378F87B5F67768C77A69F779AABC032BCC3031DDAD83701E475D16040D1E064208D99313C4047BA2AA44E15CF631E4337A47318F34060DAE2ED3FB2F77F26CAF51805D86F82786B8CED61C0A0A7A8CBECD9AE3FDD266BDA632E6F6095A8E2C82A709EF2ACE20D66CC6709A5EF4EBFBA3B020BD15A5451673CA3780A459C277EEA72A1C9EF8502281BF903B2409971DC1F215C899CBBDED194CAB8A5EBB2273E3B67AEEE9A18CD03A1CC46312AAE59AEA0EFB0E5EAC8A62D6C49DC5B5D5CAC7B12CC2B293ED1D258149C6E8ADFB311328C1D5ACD4A92DFC71E9575A62920166893D715358DAE87159E39267079FA5D2EF41D756E01E0D9701BE7F715E4DCEF5667576A883DC034E36022AB62707C4E9FF9C7400BD29770FC07C66BB041F17204A63B6A52177F32B1E8AF15A818E946421552673488AA76253A5CCAEF2368C6464A36DEA011A56FFACF5F592099BADEFA4B7A72059FF1869864BDDBD14B4D32460CFD30E78C4F057F011C67F375247 +20241201035354 2 6 100 7679 2 C4FD13B23C1EF3F1B888E9E24F6E6F0D1E538D5C17287A04247451367BAAC3EB0FF3633A10C1B2BEA19F91DA18C0C52A465FA0F0371A2189AC36BFEA58F33B013352F321A0B71BF61553330EC7735E66BF920F0AB9C918AC6796F3B2C5CC7B0E9F6695400B692026845D93807363115D8E1EF92072B84941DE896DC222F2493FA43169DC5C94E9F7C645CDDC38AC8C8F8790A2078B755BF65EB099CA5682E186E7DE95CBCF7036B0BFC761137EB0B297A140C1683E9A14E78F31935D873DFB2CC33563980FD7C6EB609427A9A63D9A7ECE43889783FAF17D129A4F00A7DBA8FAFCBDD57FA7599C944D03297B7106E02A82D695E8BC0ACC860295F357FD2F60CC4A09E49450CF735A8756174A8E1458E3BE2BEA10F38D2C30E6AD7DBFA6835328A64BDFCA2318E1753C922D3AA467BB770C03BE0D3381E31655F4969009A35E4CF90B1EF5CB71A7BE424E952AEF1368142BB6E5AEECB9F7EC2034179009B7E57DF234CDDC3818BE6E637DAC7F44B109BCAA519CA77B27E4A119712A325ACC29E82C5A3E43CDED00A550ABF99495C802578A6ACB7DBCCCECD3A3857F01A9582671D87C9407409355199D627D316938076334BCDEC6635E0D6696A53E2475AAF9412167245779FA0C89CC3C08BF90313C68710D0153A3B8FA06862B6670E9498296D2C1840812D51FFEADDAE3D714A6EA7D0DAF18C134A0E26AAA99AB8B605E5FAC1814D13F5BCA134DBCF40B5C21F39EF9B4089A759876E5F22DEAF3C64DAA159B9AFEB76109429E3E42FF8DB74EF84954405C4D7B826CFBE041FF996CB053ED44BD32742681CCC843CBD031CD9DDF299EF150378F87B5F67768C77A69F779AABC032BCC3031DDAD83701E475D16040D1E064208D99313C4047BA2AA44E15CF631E4337A47318F34060DAE2ED3FB2F77F26CAF51805D86F82786B8CED61C0A0A7A8CBECD9AE3FDD266BDA632E6F6095A8E2C82A709EF2ACE20D66CC6709A5EF4EBFBA3B020BD15A5451673CA3780A459C277EEA72A1C9EF8502281BF903B2409971DC1F215C899CBBDED194CAB8A5EBB2273E3B67AEEE9A18CD03A1CC46312AAE59AEA0EFB0E5EAC8A62D6C49DC5B5D5CAC7B12CC2B293ED1D258149C6E8ADFB311328C1D5ACD4A92DFC71E9575A62920166893D715358DAE87159E39267079FA5D2EF41D756E01E0D9701BE7F715E4DCEF5667576A883DC034E36022AB62707C4E9FF9C7400BD29770FC07C66BB041F17204A63B6A52177F32B1E8AF15A818E946421552673488AA76253A5CCAEF2368C6464A36DEA011A56FFACF5F592099BADEFA4B7A72059FF1869864BDDBD14B4D32460CFD30E78C4F057F011C67FEC05DB +20241201043654 2 6 100 7679 2 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED0D77EFCE3 +20241201045113 2 6 100 7679 2 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED0D867EE3B +20241201061048 2 6 100 7679 5 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED0DDAE0C8F +20241201072458 2 6 100 7679 5 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED0E29A61DF +20241201073945 2 6 100 7679 2 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED0E39422AB +20241201081137 2 6 100 7679 2 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED0E5B1C16B +20241201084445 2 6 100 7679 2 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED0E7E0CB7B +20241201085943 2 6 100 7679 2 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED0E8D1F5CB +20241201092406 2 6 100 7679 2 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED0EA661BD3 +20241201094424 2 6 100 7679 2 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED0EBB93913 +20241201104106 2 6 100 7679 5 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED0EF85D8F7 +20241201104452 2 6 100 7679 5 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED0EFBC6D8F +20241201115450 2 6 100 7679 2 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED0F464B243 +20241201120212 2 6 100 7679 5 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED0F4DBBAFF +20241201123240 2 6 100 7679 2 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED0F6DA27E3 +20241201130824 2 6 100 7679 5 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED0F939BADF +20241201171234 2 6 100 7679 2 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED109A1419B +20241201182756 2 6 100 7679 2 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED10EB1D8A3 +20241201190812 2 6 100 7679 5 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED11163FE8F +20241201191642 2 6 100 7679 2 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED111F0947B +20241201195706 2 6 100 7679 2 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED11498BEA3 +20241201200433 2 6 100 7679 5 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED115134B17 +20241201200527 2 6 100 7679 5 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED1151A85B7 +20241201205110 2 6 100 7679 5 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED1181F734F +20241201205604 2 6 100 7679 5 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED1186965DF +20241201232404 2 6 100 7679 5 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED1224C1B97 +20241202014307 2 6 100 7679 5 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED12B98711F +20241202022245 2 6 100 7679 5 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED12E394097 +20241202032328 2 6 100 7679 2 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED1324BD55B +20241202042741 2 6 100 7679 5 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED1368D4BB7 +20241202043950 2 6 100 7679 2 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED1375589FB +20241202051314 2 6 100 7679 2 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED1398AB80B +20241202054231 2 6 100 7679 2 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED13B77C653 +20241202054750 2 6 100 7679 5 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED13BCC7297 +20241202061721 2 6 100 7679 2 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED13DC0C9B3 +20241202074137 2 6 100 7679 2 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED1435661B3 +20241202074315 2 6 100 7679 2 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED14369BF1B +20241202081741 2 6 100 7679 2 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED145AABB1B +20241202082834 2 6 100 7679 2 F02D40B37C40876939E4D2A62AF7EC21A676D8E2B04081BA98E23F464A47514FB40DC99F7B8046B48CD3052C7AC080E4B496C16ED18695CA27493A129088F5829BBEAD02DFD521829FFD8B1120330E2BBA10C55A1EAD0641006827DA4725BFD2A2559C363C33BC78C2D83B4A075099EC57634D0AD4AEDA3302441B7005C728C0371B51877A97B442C5E3C3D53C244EFF3B65CDCCB0C017723F1EBD0B91E220116ACF14703268A11B7FC7564F7BEDBFFB3CE046261DD9D83E6078CD7AB5AC97595EF53D6C4C56D24588C6D130C0CD2C967AB90C31497186A06A93FB9338D4F30E0104BC8EFF2518D0644174BD1FF1FD7BAC2AAFF151D733A14F456A189ECA2D5F11D7C3AF1DA06192D36251B050E1AC576E3C369678D12823870FFC6E5809903382F9FBE36156F294C94FF5369E8D24D085A326870A998A10683495CEF15EFF0A45C781B5156B82D9AA07852040A96A0D5ACDF094B9DD91EA893382F95A6B72F0A2090F036A1B23CF9CF544753EA5B9ED86FA52EBB4C5421C5B485AE932F5837822C91257EC4953ACA79F2D94261DC40B3D44CB44056D4025EC459563865000B8C5F5D7724ED27CA4A8ADE299E5C898F4BD09F430781A68C261E4FA0BA2FEE567434B057C5D5F2899A1547B780B91315CC631C0552DB403DF53A6059BE895242FDA4AE1F6C5129E3643DF1A20C28BBF4328B4E623DCBC1149CE838BBC4A9944A6B6ACB4AA29B50FC7AFFAB0075BB4CC190F15B2C17847560F1B4C591EFE90D5AAA307A3FCC091DF44E3B219F7EE86EA01704D652983CE0D475896C1EB94E09314D386233D706FE0F5415BAF51746F3E8A6AC74E6F68CCF665CCEC4BE0B9CE19308C0423491F5914EA8ABE6081F38282D4994A4B640DCE56F4D616CED59B80938E4E7C486AB64E7C740FCD6ADB5494906520FD66A02069D3C11085157142CDDBFB004023C5CDFCCEAC5296636A77C127DEC4182A36D6A34D980F778452271C80CABAFE15A629302EFE9CD9105353B719581D4DD2E1BCF9411A4CCB0D010B5954291453E761A3B9EAF533119EEF1C30C4E53FEFAF2D2300162786963D54ECE0376CC797CBBDD757B596FAB26716ECEA7C47FB6C6DC6A80FC435D5CADB36D5ACB6760CAC6272B61E64A920EC7D4E5FBD680B2B906F1CF78EFD380A47692E1DC6C06AC21255E65C3757E32C301B5ACD8BA136FEE7C19B858D8B60595946BF1D0520912ACD17E397C9FC156C741AD1104F403B363B4E6B4AD06E8C60928CCD6AB3FE6AEFECBC57DB5CFF431A2D44533D9A92C483B56AE56698F02622D3A65E09B6EBFDFD5DCAF34E09DEDA100B40DD4C40ADCEF30787E527C4F613A08BDED1465C7B4B +20241202090408 2 6 100 8191 2 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F474B4AD895B +20241202092818 2 6 100 8191 2 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F474B5FD49CB +20241202101356 2 6 100 8191 5 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F474B8749EB7 +20241202105709 2 6 100 8191 2 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F474BACEBBE3 +20241202110503 2 6 100 8191 2 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F474BB359FFB +20241202111809 2 6 100 8191 5 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F474BBDFE367 +20241202113338 2 6 100 8191 5 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F474BCAC42D7 +20241202114109 2 6 100 8191 2 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F474BD0F195B +20241202140045 2 6 100 8191 2 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F474C4C2C8C3 +20241202145509 2 6 100 8191 2 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F474C7B5B2B3 +20241202180737 2 6 100 8191 5 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F474D23791E7 +20241202190603 2 6 100 8191 5 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F474D562B49F +20241202192303 2 6 100 8191 5 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F474D64A0887 +20241202194604 2 6 100 8191 2 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F474D788F30B +20241202202723 2 6 100 8191 5 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F474D9CE5387 +20241202210310 2 6 100 8191 5 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F474DBCBA17F +20241202232141 2 6 100 8191 5 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F474E3833667 +20241202234441 2 6 100 8191 2 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F474E4C55853 +20241202234813 2 6 100 8191 5 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F474E4ED7847 +20241203020245 2 6 100 8191 5 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F474EC649497 +20241203022338 2 6 100 8191 5 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F474ED8847BF +20241203022652 2 6 100 8191 2 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F474EDAC6223 +20241203031204 2 6 100 8191 2 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F474F0205823 +20241203043100 2 6 100 8191 2 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F474F484158B +20241203044332 2 6 100 8191 2 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F474F537BA23 +20241203051425 2 6 100 8191 2 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F474F6E6415B +20241203055801 2 6 100 8191 5 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F474F953468F +20241203062624 2 6 100 8191 5 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F474FAD661D7 +20241203075312 2 6 100 8191 2 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F474FFA46B5B +20241203095857 2 6 100 8191 2 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F4750696836B +20241203111915 2 6 100 8191 2 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F4750B055A7B +20241203151709 2 6 100 8191 2 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F4751817A103 +20241203162310 2 6 100 8191 5 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F4751BBFB51F +20241203173052 2 6 100 8191 5 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F4751F72906F +20241203182303 2 6 100 8191 2 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F475224CDDDB +20241203194121 2 6 100 8191 5 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F47526993A97 +20241203203340 2 6 100 8191 2 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F475298312DB +20241203203518 2 6 100 8191 5 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F475299334C7 +20241203220054 2 6 100 8191 5 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F4752E4DBDDF +20241203220341 2 6 100 8191 2 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F4752E6D1DC3 +20241203221452 2 6 100 8191 2 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F4752F062A3B +20241203224318 2 6 100 8191 5 C3301F39F3E2DCD097FBF5454401BF52BF4745AFD35F3DEBDFB34DE2518B0F7BB10DE2FDBE6C35E1B63AA67E9FC179EB3DB8A0FA7E01618BB625B3EC326A001A253FB737B2461999BAB5A5FBCA4AFAD88A8BCBEB5990D4E25225F203B2CE75A3A1C23BFFD78E697275BDB6B6153AA3C21D2063047D44EDDF0483220CD672280D4D67C4726EA476A5C094B7E8DBE62B760EBA6B62C200D456A99E87875B4B2FFF4AA87661D89CAF8CA36D9CE00E0C3BDA443B7CCC3EA892F524AD10DD6960196EC4497E1DDC9F5C13BAED9A8F240196633AB9EC597D0A2FFEEE9320147E73FB295039605EA79376C00D1C60EB421D1BF2BD36A9B68A32E5F5003F0C984E1A57B3C8A261E451D912FCBF27924078BAB0879F85B78D097B2651A17AD9266B39E7AF73DAE54319B2902E0A0D11653B38EDA14B9DE8431E9382AC7EF5F1705C05239DDEA7F533234FA640D2E1EE392D23BF46D57D6FD0E167174E6242F5455DC299BB03BF2EBAEDB14539E9025B84BF66C185AD45C6B1FBF47E3C17D4A1F2C99DCA7151039D71DB7BD2E025E67C2ABB9A2DE6D9C5150651385B270511AA50E8728707B1E0920F3A83DEC0F733090CE96DCACDB93CD756AB1F572DA2BBF4908C17E905848C09CF31424833D1D4894FCB6BD93162EC74E836A523E97F35152EBA28AF63DEC47A32C09E0F0451A4D60949C8CDB07642F5A705075F4A1380B327596C319A135C9C43BBAF2D25C90030BA43FC55701B2854ABFEA710D98AFB8341E46778616A9E9B31CF11652B47A76A99F096BDB35C9CFA78E47CFC980E5E8683E1E13AA3FCA5171C07B5E27C1A5002C02643DC760431C2750A29E838F6ED5A892146D8015F5879DA988DF030BB2FA4D501FB7F0AD9A82ED3C48B70979428C39DB04116DCC8337567B6DB4A0DFE0C704B3F46983BBF092847AED87699EE88AEB27756850D008583CD37FC8521968EB1D17FC42D742B7E6756303412A3AD011DD5CE2BA1A4E3B0B2EBB68736C76B02164C41204734B731DF4C00C937CFB49D4648A7808A34E6162526240AB221071C6C2669DB4787AF7D516F4E72EF81C7D907A37634E8CEC5BF4B3502A6A05224B269B29A8E44603DB2A890F9B64BC94AEC7D2923DC52985CC18E123C7D6CC3DEF885725E0BD2D3EC0466DBE2E94350368068E5FC1CFB6BAC40F47600EB8520A8E29E855D96B556002207CA234BE3620189767ED74ABA3D1A1CF3F66864312B7502C37C9543A36F24FD38A25137128FFE4C6CC7C078AEF1F799DA7F3E3BA0E19F21A707E66EE95189BDD74EDF32E0F18052384A2A180D90545EF1B9F2710074BC8AED5F7625C0851C34E9F3AE5C57BE65862CEE2891052CC442574EBFAAE1BEC7AB63F25C80951AD65A41089DE526946D858146E446FCAD6915BD59B0D112255083A711279990F87453A6D8F7D057055217F4753098A4FF +20241204023709 2 6 100 8191 2 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C4569DF3BDB +20241204025228 2 6 100 8191 5 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C456AB453E7 +20241204030908 2 6 100 8191 5 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C456B95242F +20241204033647 2 6 100 8191 5 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C456D1E7FC7 +20241204055147 2 6 100 8191 5 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C45749787B7 +20241204060833 2 6 100 8191 2 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C45757D2FFB +20241204064719 2 6 100 8191 2 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C45779594EB +20241204075858 2 6 100 8191 2 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C457B89C8B3 +20241204095845 2 6 100 8191 5 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C4582223CAF +20241204102632 2 6 100 8191 2 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C4583A5E7A3 +20241204133310 2 6 100 8191 5 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C458E07A8DF +20241204134006 2 6 100 8191 2 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C458E603BF3 +20241204153923 2 6 100 8191 5 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C459507D47F +20241204154043 2 6 100 8191 2 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C45951265E3 +20241204161206 2 6 100 8191 2 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C4596CC6423 +20241204161425 2 6 100 8191 2 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C4596E4BA93 +20241204172055 2 6 100 8191 2 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C459A8DA68B +20241204192705 2 6 100 8191 5 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C45A16C53A7 +20241204212358 2 6 100 8191 5 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C45A7E3BB4F +20241204213330 2 6 100 8191 2 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C45A86569BB +20241204221629 2 6 100 8191 2 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C45AAC0BC23 +20241205021404 2 6 100 8191 5 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C45B80CC4F7 +20241205023328 2 6 100 8191 2 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C45B9166F1B +20241205040105 2 6 100 8191 5 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C45BE03F83F +20241205055343 2 6 100 8191 2 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C45C44A5013 +20241205065151 2 6 100 8191 2 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C45C77D34CB +20241205065416 2 6 100 8191 2 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C45C79803AB +20241205074544 2 6 100 8191 5 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C45CA71FBC7 +20241205081641 2 6 100 8191 2 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C45CC1BDF6B +20241205092757 2 6 100 8191 2 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C45CFFBAE8B +20241205110223 2 6 100 8191 2 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C45D53D4193 +20241205112040 2 6 100 8191 5 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C45D6362177 +20241205112359 2 6 100 8191 5 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C45D65CAD37 +20241205134041 2 6 100 8191 5 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C45DDF2FF47 +20241205135041 2 6 100 8191 2 DC5E734609D91DA7E5180C89891C148715345D3A56F96DDFF41EE0B90992E9901E55850A78D9DF296A83F5AAF22675720E58E1F6D01F3B45315B818EF9CE880CE92F022763911796D4F86361BEB151ACB400BA017186C1DDCDE5F1853260ECF1082E072C2B7E2FD33E51B5076675269EC247AAE3DF3C1E6853E5D0E58FF7268255E91A9BF6FD43750F114BCA5DC70176ECACAF59C812798941D04FFFF200B53F9843066568A5EF6B324692239A9DC94383C53DA447D942BD51E17F51C22106DC3A2FC7A8942E20E5DA369D19124D184A96589E66EE15C4A8E4CB0FBB6B5E629875DEB3C6AAF622ABC4A4057E0B95533A03C94C514D2129CD6ECE739D9E3A98A54461DF577CC508BF4D5EE7FBE6178B248E3F51C59FE57BFBDE33DD833D0CF22DB22AE0F4F9F03EEF8E0E1DB0EDF7BB4C755148AD2D3FECED23DE1F028A3A6396D7F8F721D11023BD58335ADE175939E140A92C7B532A3D77168E566B7AADEA6F137A158AF3D2608FD4C1081018C1BC2B860A2830A097BDAFA96A3D5B5E1130D2C0778837C63ACBE958573B4ADAC2AE629D17728313AB9064D890006B2F0EC1869E35480B96651B9B3837B876190D5F1876A151A87C58A1CE2A9AD0744BE4CF955BFA9FA5653300FF6ECD64667ECD836D61DC3675048A8EB5AE945B50CB699F7FB4E36167515A2054199687DEC77D5117DF28B63F383403C49097F23AA4DE5857A0D865AFC7E4D0994B46386C20A41E9B41963CD425A82B30C4EE72FB3EFACD6C4090D740E44C196E51F41894FDB26142B72EF1E65A676C30EFB65C937C0F64CDEC167ECC16F0CAA3C932F3DD5C6F7A1EB073F03F2CB9F2059BE75EBAE32FA3170B5FA93D69CAB8275935686242E1F43ED23FE8784A0AD694442D35193DAAF5F7DA49B267B716C38F36C92AE7986DF8126904B11EA74323F3AB3AF436D64AC41996529AB95876EE4DF3739130460A50E2EC8463F2306454F08745CE40938858B6237A5D38B33FD6541BB98EFB39A7B0B501B7943FF594DF0964BF535CBD35105E35BA14C40E62D57F3B110AE82CD7F9FF73C3A28740C8EB397494F6D7CF5F0F147385424D70B276C6AD849E56C9985115EAF2CCF3D3A6C828F2A303178EC48BB08F36AF3800739E841F7B758FF06EFA10F6467E98DA4B1B302EFED0EF5A7D3AD74100E41C168ACBBF10EC5FFC497B43409D02D942C144408C32C83ED49334BC48FD1D446FDEBB71CA1F9276F3180ECA057E4B8F19FAFE368D0097EE2A5736D72BE661382939491A244B068D26A071E55E25DF2C8706ADEFD8245BC97A691AB57A8D39CE24469E9CC69198F4F795CACCB45053F464CA0C2F04C71E9CD6BB6D378E917C413B7FADEACD41A7A43E9A1FC04576658DBF7420A35252A899B51F9ED9B2D0B5534A696C2465C950EF5880636D96CC963AF6C314D00834969C45DE752163 From a79a2c1190bd3124da21d9e1582dd94877c7f972 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Fri, 23 May 2025 16:11:48 +1000 Subject: [PATCH 080/244] chown regress logs before uploading. --- .github/workflows/c-cpp.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 8c3d64b8cc7f..887d54af2102 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -152,6 +152,9 @@ jobs: - name: show logs if: failure() run: for i in regress/failed*.log; do echo ====; echo logfile $i; echo =====; cat $i; done + - name: chown logs + if: failure() + run: test -x "$(which sudo 2>&1)" && sudo chown -R "${LOGNAME}" regress - name: save logs if: failure() uses: actions/upload-artifact@main From d8b5bd36078e5b6d78da4633f0cc9b90ffda8b50 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Fri, 23 May 2025 16:26:20 +1000 Subject: [PATCH 081/244] Rename debugging variable RUN_ONLY_TEST. to RUN_ONLY_TARGET_CONFIG to make it more obvious what it matches. --- .github/workflows/c-cpp.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 887d54af2102..43380df42088 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -111,12 +111,12 @@ jobs: - { target: macos-15, config: pam } runs-on: ${{ matrix.target }} steps: - - name: check RUN_ONLY_TEST - # For testing, you can set the repo variable RUN_ONLY_TEST in your repo - # (Repo -> Settings -> Security -> Actions -> Variables) to run only - # that test config. - if: vars.RUN_ONLY_TEST != '' - run: sh -c 'if [ "${{ vars.RUN_ONLY_TEST }}" != "${{ matrix.target }} ${{matrix.config }}" ]; then exit 1; else exit 0; fi' + - name: check RUN_ONLY_TARGET_CONFIG + # For testing, you can set the repo variable RUN_ONLY_TARGET_CONFIG in + # your repo (Repo -> Settings -> Security -> Actions -> Variables) to + # run only that test config, eg "ubuntu-latest default". + if: vars.RUN_ONLY_TARGET_CONFIG != '' + run: sh -c 'if [ "${{ vars.RUN_ONLY_TARGET_CONFIG }}" != "${{ matrix.target }} ${{matrix.config }}" ]; then exit 1; else exit 0; fi' - name: set cygwin git params if: ${{ startsWith(matrix.target, 'windows') }} run: git config --global core.autocrlf input From 7674c03caed80cb3565d14690c92068a14051967 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Fri, 23 May 2025 16:39:18 +1000 Subject: [PATCH 082/244] Allow setting LTESTS in repo variables. --- .github/configs | 9 +++++++++ .github/workflows/c-cpp.yml | 14 +++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/.github/configs b/.github/configs index a1059f935943..aa363be7d3ff 100755 --- a/.github/configs +++ b/.github/configs @@ -13,6 +13,10 @@ if [ "$config" = "" ]; then config="default" fi +if [ ! -z "${LTESTS}" ]; then + OVERRIDE_LTESTS="${LTESTS}" +fi + unset CC CFLAGS CPPFLAGS LDFLAGS LTESTS SUDO TEST_TARGET="tests compat-tests" @@ -394,5 +398,10 @@ if [ -x "$(which plink 2>/dev/null)" ]; then export REGRESS_INTEROP_PUTTY fi +if [ ! -z "${OVERRIDE_LTESTS}" ]; then + echo >&2 "Overriding LTESTS, was '${LTESTS}', now '${OVERRIDE_LTESTS}'" + LTESTS="${OVERRIDE_LTESTS}" +fi + export CC CFLAGS CPPFLAGS LDFLAGS LTESTS SUDO export TEST_TARGET TEST_SSH_UNSAFE_PERMISSIONS TEST_SSH_FAIL_FATAL diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 43380df42088..4acb1f5f2478 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -1,5 +1,15 @@ name: C/C++ CI +# For testing, you can set variables in your repo (Repo -> Settings -> +# Security -> Actions -> Variables) to restrict the tests that are run. +# The supported variables are: +# +# RUN_ONLY_TARGET_CONFIG: Run only the single matching target and config, +# separated by spaces, eg "ubuntu-latest default". All other tests will +# fail immediately. +# +# LTESTS: Override the set of tests run. + on: push: paths: [ '**.c', '**.h', '**.m4', '**.sh', '**/Makefile.in', 'configure.ac', '.github/configs', '.github/workflows/c-cpp.yml' ] @@ -112,9 +122,6 @@ jobs: runs-on: ${{ matrix.target }} steps: - name: check RUN_ONLY_TARGET_CONFIG - # For testing, you can set the repo variable RUN_ONLY_TARGET_CONFIG in - # your repo (Repo -> Settings -> Security -> Actions -> Variables) to - # run only that test config, eg "ubuntu-latest default". if: vars.RUN_ONLY_TARGET_CONFIG != '' run: sh -c 'if [ "${{ vars.RUN_ONLY_TARGET_CONFIG }}" != "${{ matrix.target }} ${{matrix.config }}" ]; then exit 1; else exit 0; fi' - name: set cygwin git params @@ -149,6 +156,7 @@ jobs: env: TEST_SSH_UNSAFE_PERMISSIONS: 1 TEST_SSH_HOSTBASED_AUTH: yes + LTESTS: ${{ vars.LTESTS }} - name: show logs if: failure() run: for i in regress/failed*.log; do echo ====; echo logfile $i; echo =====; cat $i; done From a4ea7f6042f25b41061a83445016a1ea4f470f7b Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Fri, 23 May 2025 08:40:13 +0000 Subject: [PATCH 083/244] upstream: Explictly set LC_ALL=C on each sort invocation. Remove it from sshd_config (where it could be overridden by shell startup scripts, eg on macos-15) causing random test failures. with & ok djm@ OpenBSD-Regress-ID: ad0a6678964784096e9a9e6d15ead36beed92f18 --- regress/agent-restrict.sh | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/regress/agent-restrict.sh b/regress/agent-restrict.sh index 057856f1bbdf..7fc30fa5467c 100644 --- a/regress/agent-restrict.sh +++ b/regress/agent-restrict.sh @@ -1,4 +1,4 @@ -# $OpenBSD: agent-restrict.sh,v 1.7 2025/03/28 21:45:55 dtucker Exp $ +# $OpenBSD: agent-restrict.sh,v 1.8 2025/05/23 08:40:13 dtucker Exp $ # Placed in the Public Domain. tid="agent restrictions" @@ -52,10 +52,6 @@ done cat $OBJ/ssh_proxy.bak >> $OBJ/ssh_proxy cat $OBJ/ssh_proxy.bak >> $OBJ/ssh_proxy_noid -LC_ALL=C -export LC_ALL -echo "SetEnv LC_ALL=${LC_ALL}" >> sshd_proxy - verbose "prepare known_hosts" rm -f $OBJ/known_hosts for h in a b c x ; do @@ -84,7 +80,8 @@ reset_keys() { _command="" case "$_whichcmd" in authinfo) _command="cat \$SSH_USER_AUTH" ;; - keylist) _command="$SSHADD -L | cut -d' ' -f-2 | sort" ;; + keylist) _command="$SSHADD -L | cut -d' ' -f-2 | \ + env LC_ALL=C sort" ;; *) fatal "unsupported command $_whichcmd" ;; esac trace "reset keys" @@ -227,7 +224,7 @@ rm -f $OBJ/expect_list.pre for u in a b c d e x; do cut -d " " -f-2 $OBJ/user_${u}.pub >> $OBJ/expect_list.pre done -sort $OBJ/expect_list.pre > $OBJ/expect_list +env LC_ALL=C sort $OBJ/expect_list.pre > $OBJ/expect_list for h in a b c d e; do cp $OBJ/expect_list $OBJ/expect_$h expect_succeed $h "unrestricted keylist" @@ -332,7 +329,7 @@ if test ! -z "\$me" ; then cat \$SSH_USER_AUTH fi echo AGENT -$SSHADD -L | egrep "^ssh" | cut -d" " -f-2 | sort +$SSHADD -L | egrep "^ssh" | cut -d" " -f-2 | env LC_ALL=C sort if test -z "\$next" ; then touch $OBJ/done echo "FINISH" @@ -369,7 +366,7 @@ prepare_multihop_expected() { done rm -f $OBJ/expect_a echo "AGENT" >> $OBJ/expect_a - test "x$_keys" = "xnone" || sort $OBJ/expect_keys >> $OBJ/expect_a + test "x$_keys" = "xnone" || env LC_ALL=C sort $OBJ/expect_keys >> $OBJ/expect_a echo "NEXT" >> $OBJ/expect_a for h in $_hops ; do echo "HOSTNAME host_$h" >> $OBJ/expect_a @@ -377,7 +374,7 @@ prepare_multihop_expected() { (printf "publickey " ; cut -d" " -f-2 $OBJ/user_a.pub) >> $OBJ/expect_a echo "AGENT" >> $OBJ/expect_a if test "x$_keys" = "xall" ; then - sort $OBJ/expect_keys >> $OBJ/expect_a + env LC_ALL=C sort $OBJ/expect_keys >> $OBJ/expect_a fi if test "x$h" != "x$_lasthop" ; then if test "x$_keys" = "xfiltered" ; then From f097d7bd07da4634c1a723d1dc4fcf56e7d0e147 Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Fri, 23 May 2025 09:26:25 +0000 Subject: [PATCH 084/244] upstream: Don't leak the args list. Coverity CIDs 481569 & 481570, ok job@ tb@. OpenBSD-Commit-ID: becabcd00513d13d1435b68b7ccffa7151b72393 --- scp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scp.c b/scp.c index 57c242ffc755..ab8ab22950ca 100644 --- a/scp.c +++ b/scp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: scp.c,v 1.263 2025/03/28 06:04:07 dtucker Exp $ */ +/* $OpenBSD: scp.c,v 1.264 2025/05/23 09:26:25 dtucker Exp $ */ /* * scp - secure remote copy. This is basically patched BSD rcp which * uses ssh to do the data transfer (instead of using rcmd). @@ -1224,6 +1224,7 @@ toremote(int argc, char **argv, enum scp_mode_e mode, char *sftp_direct) out: if (mode == MODE_SFTP) free(conn); + freeargs(&alist); free(tuser); free(thost); free(targ); @@ -1306,6 +1307,7 @@ tolocal(int argc, char **argv, enum scp_mode_e mode, char *sftp_direct) (void) close(remin); remin = remout = -1; } + freeargs(&alist); free(suser); free(host); free(src); From 3e11478f585408888defa56fa47e8dc6567378d0 Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Fri, 23 May 2025 11:25:35 +0000 Subject: [PATCH 085/244] upstream: Ensure args to nh_update() fit within uint32, which it should always anyway. Placates Coverity CID 470520. While there, fix the upstream URL. ok djm@ OpenBSD-Commit-ID: 2478e89fde089a49fa02f9faf6287d35959c9f92 --- umac.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/umac.c b/umac.c index d5958babfd34..df90352604be 100644 --- a/umac.c +++ b/umac.c @@ -1,4 +1,4 @@ -/* $OpenBSD: umac.c,v 1.23 2023/03/07 01:30:52 djm Exp $ */ +/* $OpenBSD: umac.c,v 1.24 2025/05/23 11:25:35 dtucker Exp $ */ /* ----------------------------------------------------------------------- * * umac.c -- C Implementation UMAC Message Authentication @@ -6,7 +6,7 @@ * Version 0.93b of rfc4418.txt -- 2006 July 18 * * For a full description of UMAC message authentication see the UMAC - * world-wide-web page at http://www.cs.ucdavis.edu/~rogaway/umac + * world-wide-web page at https://fastcrypto.org/umac/ * Please report bugs and suggestions to the UMAC webpage. * * Copyright (c) 1999-2006 Ted Krovetz @@ -1089,7 +1089,7 @@ static int uhash_update(uhash_ctx_t ctx, const u_char *input, long len) } /* pass remaining < L1_KEY_LEN bytes of input data to NH */ - if (len) { + if (len > 0 && len <= UINT32_MAX) { nh_update(&ctx->hash, (const UINT8 *)input, len); ctx->msg_len += len; } From 0c64d69e4e24a3ab06f7922ef389e7399c4dfb88 Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Fri, 23 May 2025 11:54:50 +0000 Subject: [PATCH 086/244] upstream: Include stdint.h for UINT32_MAX. OpenBSD-Commit-ID: edc29ed67e8bd03bac729d9b4849066d1d3a8cb9 --- umac.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/umac.c b/umac.c index df90352604be..5bf2e43a66fa 100644 --- a/umac.c +++ b/umac.c @@ -1,4 +1,4 @@ -/* $OpenBSD: umac.c,v 1.24 2025/05/23 11:25:35 dtucker Exp $ */ +/* $OpenBSD: umac.c,v 1.25 2025/05/23 11:54:50 dtucker Exp $ */ /* ----------------------------------------------------------------------- * * umac.c -- C Implementation UMAC Message Authentication @@ -76,6 +76,9 @@ #include #include #include +#ifdef HAVE_STDINT_H +#include +#endif #include #include From 91903511d0597c3bea218167f9ca5a176fa0dc20 Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Fri, 23 May 2025 12:52:45 +0000 Subject: [PATCH 087/244] upstream: Replace strncmp and strncasecmp with hand-counting bytes with strprefix. nits lucas@, ok lucas@ djm@ OpenBSD-Commit-ID: f0888807f151ea2bdaf6fed36303ae81f259d1d4 --- ssh-keygen.c | 132 +++++++++++++++++++++++++-------------------------- 1 file changed, 65 insertions(+), 67 deletions(-) diff --git a/ssh-keygen.c b/ssh-keygen.c index 3217f084d384..e0cc35a77a83 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keygen.c,v 1.478 2025/05/06 05:40:56 djm Exp $ */ +/* $OpenBSD: ssh-keygen.c,v 1.479 2025/05/23 12:52:45 dtucker Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1994 Tatu Ylonen , Espoo, Finland @@ -1454,13 +1454,14 @@ do_print_resource_record(struct passwd *pw, char *fname, char *hname, { struct sshkey *public; char *comment = NULL; + const char *p; struct stat st; int r, hash = -1; size_t i; for (i = 0; i < nopts; i++) { - if (strncasecmp(opts[i], "hashalg=", 8) == 0) { - if ((hash = ssh_digest_alg_by_name(opts[i] + 8)) == -1) + if ((p = strprefix(opts[i], "hashalg=", 1)) != NULL) { + if ((hash = ssh_digest_alg_by_name(p)) == -1) fatal("Unsupported hash algorithm"); } else { error("Invalid option \"%s\"", opts[i]); @@ -1970,6 +1971,7 @@ static void add_cert_option(char *opt) { char *val, *cp; + const char *p; int iscrit = 0; if (strcasecmp(opt, "clear") == 0) @@ -2002,24 +2004,22 @@ add_cert_option(char *opt) certflags_flags &= ~CERTOPT_REQUIRE_VERIFY; else if (strcasecmp(opt, "verify-required") == 0) certflags_flags |= CERTOPT_REQUIRE_VERIFY; - else if (strncasecmp(opt, "force-command=", 14) == 0) { - val = opt + 14; - if (*val == '\0') + else if ((p = strprefix(opt, "force-command=", 1)) != NULL) { + if (*p == '\0') fatal("Empty force-command option"); if (certflags_command != NULL) fatal("force-command already specified"); - certflags_command = xstrdup(val); - } else if (strncasecmp(opt, "source-address=", 15) == 0) { - val = opt + 15; - if (*val == '\0') + certflags_command = xstrdup(p); + } else if ((p = strprefix(opt, "source-address=", 1)) != NULL) { + if (*p == '\0') fatal("Empty source-address option"); if (certflags_src_addr != NULL) fatal("source-address already specified"); - if (addr_match_cidr_list(NULL, val) != 0) + if (addr_match_cidr_list(NULL, p) != 0) fatal("Invalid source-address list"); - certflags_src_addr = xstrdup(val); - } else if (strncasecmp(opt, "extension:", 10) == 0 || - (iscrit = (strncasecmp(opt, "critical:", 9) == 0))) { + certflags_src_addr = xstrdup(p); + } else if (strprefix(opt, "extension:", 1) != NULL || + (iscrit = (strprefix(opt, "critical:", 1) != NULL))) { val = xstrdup(strchr(opt, ':') + 1); if ((cp = strchr(val, '=')) != NULL) *cp++ = '\0'; @@ -2206,9 +2206,8 @@ hash_to_blob(const char *cp, u_char **blobp, size_t *lenp, struct sshbuf *b; int r; - if (strncmp(cp, "SHA256:", 7) != 0) + if ((cp = strprefix(cp, "SHA256:", 0)) == NULL) fatal("%s:%lu: unsupported hash algorithm", file, lnum); - cp += 7; /* * OpenSSH base64 hashes omit trailing '=' @@ -2633,6 +2632,7 @@ sig_process_opts(char * const *opts, size_t nopts, char **hashalgp, { size_t i; time_t now; + const char *p; if (verify_timep != NULL) *verify_timep = 0; @@ -2642,12 +2642,12 @@ sig_process_opts(char * const *opts, size_t nopts, char **hashalgp, *hashalgp = NULL; for (i = 0; i < nopts; i++) { if (hashalgp != NULL && - strncasecmp(opts[i], "hashalg=", 8) == 0) { - *hashalgp = xstrdup(opts[i] + 8); + (p = strprefix(opts[i], "hashalg=", 1)) != NULL) { + *hashalgp = xstrdup(p); } else if (verify_timep && - strncasecmp(opts[i], "verify-time=", 12) == 0) { - if (parse_absolute_time(opts[i] + 12, - verify_timep) != 0 || *verify_timep == 0) { + (p = strprefix(opts[i], "verify-time=", 1)) != NULL) { + if (parse_absolute_time(p, verify_timep) != 0 || + *verify_timep == 0) { error("Invalid \"verify-time\" option"); return SSH_ERR_INVALID_ARGUMENT; } @@ -2928,24 +2928,22 @@ do_moduli_gen(const char *out_file, char **opts, size_t nopts) int moduli_bits = 0; FILE *out; size_t i; - const char *errstr; + const char *errstr, *p; /* Parse options */ for (i = 0; i < nopts; i++) { - if (strncmp(opts[i], "memory=", 7) == 0) { - memory = (u_int32_t)strtonum(opts[i]+7, 1, - UINT_MAX, &errstr); + if ((p = strprefix(opts[i], "memory=", 0)) != NULL) { + memory = (u_int32_t)strtonum(p, 1, UINT_MAX, &errstr); if (errstr) { fatal("Memory limit is %s: %s", errstr, opts[i]+7); } - } else if (strncmp(opts[i], "start=", 6) == 0) { + } else if ((p = strprefix(opts[i], "start=", 0)) != NULL) { /* XXX - also compare length against bits */ - if (BN_hex2bn(&start, opts[i]+6) == 0) + if (BN_hex2bn(&start, p) == 0) fatal("Invalid start point."); - } else if (strncmp(opts[i], "bits=", 5) == 0) { - moduli_bits = (int)strtonum(opts[i]+5, 1, - INT_MAX, &errstr); + } else if ((p = strprefix(opts[i], "bits=", 0)) != NULL) { + moduli_bits = (int)strtonum(p, 1, INT_MAX, &errstr); if (errstr) { fatal("Invalid number: %s (%s)", opts[i]+12, errstr); @@ -2984,30 +2982,27 @@ do_moduli_screen(const char *out_file, char **opts, size_t nopts) int prime_tests = 0; FILE *out, *in = stdin; size_t i; - const char *errstr; + const char *errstr, *p; /* Parse options */ for (i = 0; i < nopts; i++) { - if (strncmp(opts[i], "lines=", 6) == 0) { - lines_to_process = strtoul(opts[i]+6, NULL, 10); - } else if (strncmp(opts[i], "start-line=", 11) == 0) { - start_lineno = strtoul(opts[i]+11, NULL, 10); - } else if (strncmp(opts[i], "checkpoint=", 11) == 0) { + if ((p = strprefix(opts[i], "lines=", 0)) != NULL) { + lines_to_process = strtoul(p, NULL, 10); + } else if ((p = strprefix(opts[i], "start-line=", 0)) != NULL) { + start_lineno = strtoul(p, NULL, 10); + } else if ((p = strprefix(opts[i], "checkpoint=", 0)) != NULL) { free(checkpoint); - checkpoint = xstrdup(opts[i]+11); - } else if (strncmp(opts[i], "generator=", 10) == 0) { - generator_wanted = (u_int32_t)strtonum( - opts[i]+10, 1, UINT_MAX, &errstr); + checkpoint = xstrdup(p); + } else if ((p = strprefix(opts[i], "generator=", 0)) != NULL) { + generator_wanted = (u_int32_t)strtonum(p, 1, UINT_MAX, + &errstr); if (errstr != NULL) { - fatal("Generator invalid: %s (%s)", - opts[i]+10, errstr); + fatal("Generator invalid: %s (%s)", p, errstr); } - } else if (strncmp(opts[i], "prime-tests=", 12) == 0) { - prime_tests = (int)strtonum(opts[i]+12, 1, - INT_MAX, &errstr); + } else if ((p = strprefix(opts[i], "prime-tests=", 0)) != NULL) { + prime_tests = (int)strtonum(p, 1, INT_MAX, &errstr); if (errstr) { - fatal("Invalid number: %s (%s)", - opts[i]+12, errstr); + fatal("Invalid number: %s (%s)", p, errstr); } } else { fatal("Option \"%s\" is unsupported for moduli " @@ -3090,13 +3085,14 @@ static char * sk_suffix(const char *application, const uint8_t *user, size_t userlen) { char *ret, *cp; + const char *p; size_t slen, i; /* Trim off URL-like preamble */ - if (strncmp(application, "ssh://", 6) == 0) - ret = xstrdup(application + 6); - else if (strncmp(application, "ssh:", 4) == 0) - ret = xstrdup(application + 4); + if ((p = strprefix(application, "ssh://", 0)) != NULL) + ret = xstrdup(p); + else if ((p = strprefix(application, "ssh:", 0)) != NULL) + ret = xstrdup(p); else ret = xstrdup(application); @@ -3325,7 +3321,7 @@ main(int argc, char **argv) size_t i, nopts = 0; u_int32_t bits = 0; uint8_t sk_flags = SSH_SK_USER_PRESENCE_REQD; - const char *errstr; + const char *errstr, *p; int log_level = SYSLOG_LEVEL_INFO; char *sign_op = NULL; @@ -3560,7 +3556,7 @@ main(int argc, char **argv) argc -= optind; if (sign_op != NULL) { - if (strncmp(sign_op, "find-principals", 15) == 0) { + if (strprefix(sign_op, "find-principals", 0) != NULL) { if (ca_key_path == NULL) { error("Too few arguments for find-principals:" "missing signature file"); @@ -3573,7 +3569,7 @@ main(int argc, char **argv) } return sig_find_principals(ca_key_path, identity_file, opts, nopts); - } else if (strncmp(sign_op, "match-principals", 16) == 0) { + } else if (strprefix(sign_op, "match-principals", 0) != NULL) { if (!have_identity) { error("Too few arguments for match-principals:" "missing allowed keys file"); @@ -3586,7 +3582,7 @@ main(int argc, char **argv) } return sig_match_principals(identity_file, cert_key_id, opts, nopts); - } else if (strncmp(sign_op, "sign", 4) == 0) { + } else if (strprefix(sign_op, "sign", 0) != NULL) { /* NB. cert_principals is actually namespace, via -n */ if (cert_principals == NULL || *cert_principals == '\0') { @@ -3601,7 +3597,7 @@ main(int argc, char **argv) } return sig_sign(identity_file, cert_principals, prefer_agent, argc, argv, opts, nopts); - } else if (strncmp(sign_op, "check-novalidate", 16) == 0) { + } else if (strprefix(sign_op, "check-novalidate", 0) != NULL) { /* NB. cert_principals is actually namespace, via -n */ if (cert_principals == NULL || *cert_principals == '\0') { @@ -3616,7 +3612,7 @@ main(int argc, char **argv) } return sig_verify(ca_key_path, cert_principals, NULL, NULL, NULL, opts, nopts); - } else if (strncmp(sign_op, "verify", 6) == 0) { + } else if (strprefix(sign_op, "verify", 0) != NULL) { /* NB. cert_principals is actually namespace, via -n */ if (cert_principals == NULL || *cert_principals == '\0') { @@ -3693,8 +3689,8 @@ main(int argc, char **argv) do_download(pw); if (download_sk) { for (i = 0; i < nopts; i++) { - if (strncasecmp(opts[i], "device=", 7) == 0) { - sk_device = xstrdup(opts[i] + 7); + if ((p = strprefix(opts[i], "device=", 1)) != NULL) { + sk_device = xstrdup(p); } else { fatal("Option \"%s\" is unsupported for " "FIDO authenticator download", opts[i]); @@ -3787,16 +3783,18 @@ main(int argc, char **argv) sk_flags |= SSH_SK_USER_VERIFICATION_REQD; } else if (strcasecmp(opts[i], "resident") == 0) { sk_flags |= SSH_SK_RESIDENT_KEY; - } else if (strncasecmp(opts[i], "device=", 7) == 0) { - sk_device = xstrdup(opts[i] + 7); - } else if (strncasecmp(opts[i], "user=", 5) == 0) { - sk_user = xstrdup(opts[i] + 5); - } else if (strncasecmp(opts[i], "challenge=", 10) == 0) { - if ((r = sshbuf_load_file(opts[i] + 10, + } else if ((p = strprefix(opts[i], "device=", 1)) + != NULL ) { + sk_device = xstrdup(p); + } else if ((p = strprefix(opts[i], "user=", 1)) + != NULL) { + sk_user = xstrdup(p); + } else if ((p = strprefix(opts[i], "challenge=", 1)) + != NULL) { + if ((r = sshbuf_load_file(p, &challenge)) != 0) { fatal_r(r, "Unable to load FIDO " - "enrollment challenge \"%s\"", - opts[i] + 10); + "enrollment challenge \"%s\"", p); } } else if (strncasecmp(opts[i], "write-attestation=", 18) == 0) { From eccc15014fe146e8590568e6737a3097bfac3415 Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Sat, 24 May 2025 02:01:28 +0000 Subject: [PATCH 088/244] upstream: Use pointer from strprefix in error message, missed in previous. OpenBSD-Commit-ID: d2cdec6cf0fcd4b0ee25e4e3fad8bc8cf0ee657d --- ssh-keygen.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ssh-keygen.c b/ssh-keygen.c index e0cc35a77a83..ac0170de4938 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keygen.c,v 1.479 2025/05/23 12:52:45 dtucker Exp $ */ +/* $OpenBSD: ssh-keygen.c,v 1.480 2025/05/24 02:01:28 dtucker Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1994 Tatu Ylonen , Espoo, Finland @@ -2935,8 +2935,7 @@ do_moduli_gen(const char *out_file, char **opts, size_t nopts) if ((p = strprefix(opts[i], "memory=", 0)) != NULL) { memory = (u_int32_t)strtonum(p, 1, UINT_MAX, &errstr); if (errstr) { - fatal("Memory limit is %s: %s", - errstr, opts[i]+7); + fatal("Memory limit is %s: %s", errstr, p); } } else if ((p = strprefix(opts[i], "start=", 0)) != NULL) { /* XXX - also compare length against bits */ @@ -2945,8 +2944,7 @@ do_moduli_gen(const char *out_file, char **opts, size_t nopts) } else if ((p = strprefix(opts[i], "bits=", 0)) != NULL) { moduli_bits = (int)strtonum(p, 1, INT_MAX, &errstr); if (errstr) { - fatal("Invalid number: %s (%s)", - opts[i]+12, errstr); + fatal("Invalid number: %s (%s)", p, errstr); } } else { fatal("Option \"%s\" is unsupported for moduli " From f5cd14e81fa29b4924959cb2e1f9c206aae2d502 Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Sat, 24 May 2025 02:33:33 +0000 Subject: [PATCH 089/244] upstream: Fix compile error on 32bit platforms. Spotted by & ok tb@ OpenBSD-Commit-ID: cbcf518247886f3c7518fc54cb3bd911ffc69db7 --- umac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/umac.c b/umac.c index 5bf2e43a66fa..94c5e817c76d 100644 --- a/umac.c +++ b/umac.c @@ -1,4 +1,4 @@ -/* $OpenBSD: umac.c,v 1.25 2025/05/23 11:54:50 dtucker Exp $ */ +/* $OpenBSD: umac.c,v 1.26 2025/05/24 02:33:33 dtucker Exp $ */ /* ----------------------------------------------------------------------- * * umac.c -- C Implementation UMAC Message Authentication @@ -1092,7 +1092,7 @@ static int uhash_update(uhash_ctx_t ctx, const u_char *input, long len) } /* pass remaining < L1_KEY_LEN bytes of input data to NH */ - if (len > 0 && len <= UINT32_MAX) { + if (len > 0 && (unsigned long)len <= UINT32_MAX) { nh_update(&ctx->hash, (const UINT8 *)input, len); ctx->msg_len += len; } From 216824172724a50a4a75439fb2b4b8edccf5b733 Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Sat, 24 May 2025 03:37:40 +0000 Subject: [PATCH 090/244] upstream: Remove ssh-keygen's moduli screen -Omemory option. This vaguely made sense 20 years ago, but these days you'd be hard pressed to *find* a machine small enough to not support the maximum (127MB), and no one is screening moduli on such machines anyway, so just use the max. This also fixes Coverity CID 470522 by deleting code in question. "kill it with fire" djm@. OpenBSD-Commit-ID: 39036aa406a99f0a91923aa3a96afff1205558e6 --- moduli.c | 59 +++++++--------------------------------------------- ssh-keygen.1 | 7 ++----- ssh-keygen.c | 14 ++++--------- 3 files changed, 13 insertions(+), 67 deletions(-) diff --git a/moduli.c b/moduli.c index 481ca2aa8ffc..999a90984e18 100644 --- a/moduli.c +++ b/moduli.c @@ -1,4 +1,4 @@ -/* $OpenBSD: moduli.c,v 1.39 2023/03/02 06:41:56 dtucker Exp $ */ +/* $OpenBSD: moduli.c,v 1.40 2025/05/24 03:39:48 dtucker Exp $ */ /* * Copyright 1994 Phil Karn * Copyright 1996-1998, 2003 William Allen Simpson @@ -87,13 +87,6 @@ #define SHIFT_MEGABYTE (20) #define SHIFT_MEGAWORD (SHIFT_MEGABYTE-SHIFT_BYTE) -/* - * Using virtual memory can cause thrashing. This should be the largest - * number that is supported without a large amount of disk activity -- - * that would increase the run time from hours to days or weeks! - */ -#define LARGE_MINIMUM (8UL) /* megabytes */ - /* * Do not increase this number beyond the unsigned integer bit size. * Due to a multiple of 4, it must be LESS than 128 (yielding 2**30 bits). @@ -142,7 +135,7 @@ static u_int32_t *LargeSieve, largewords, largetries, largenumbers; static u_int32_t largebits, largememory; /* megabytes */ static BIGNUM *largebase; -int gen_candidates(FILE *, u_int32_t, u_int32_t, BIGNUM *); +int gen_candidates(FILE *, u_int32_t, BIGNUM *); int prime_test(FILE *, FILE *, u_int32_t, u_int32_t, char *, unsigned long, unsigned long); @@ -242,7 +235,7 @@ sieve_large(u_int32_t s32) * The list is checked against small known primes (less than 2**30). */ int -gen_candidates(FILE *out, u_int32_t memory, u_int32_t power, BIGNUM *start) +gen_candidates(FILE *out, u_int32_t power, BIGNUM *start) { BIGNUM *q; u_int32_t j, r, s, t; @@ -252,15 +245,6 @@ gen_candidates(FILE *out, u_int32_t memory, u_int32_t power, BIGNUM *start) u_int32_t i; int ret = 0; - largememory = memory; - - if (memory != 0 && - (memory < LARGE_MINIMUM || memory > LARGE_MAXIMUM)) { - error("Invalid memory amount (min %ld, max %ld)", - LARGE_MINIMUM, LARGE_MAXIMUM); - return (-1); - } - /* * Set power to the length in bits of the prime to be generated. * This is changed to 1 less than the desired safe prime moduli p. @@ -274,33 +258,9 @@ gen_candidates(FILE *out, u_int32_t memory, u_int32_t power, BIGNUM *start) } power--; /* decrement before squaring */ - /* - * The density of ordinary primes is on the order of 1/bits, so the - * density of safe primes should be about (1/bits)**2. Set test range - * to something well above bits**2 to be reasonably sure (but not - * guaranteed) of catching at least one safe prime. - */ - largewords = ((power * power) >> (SHIFT_WORD - TEST_POWER)); - - /* - * Need idea of how much memory is available. We don't have to use all - * of it. - */ - if (largememory > LARGE_MAXIMUM) { - logit("Limited memory: %u MB; limit %lu MB", - largememory, LARGE_MAXIMUM); - largememory = LARGE_MAXIMUM; - } - - if (largewords <= (largememory << SHIFT_MEGAWORD)) { - logit("Increased memory: %u MB; need %u bytes", - largememory, (largewords << SHIFT_BYTE)); - largewords = (largememory << SHIFT_MEGAWORD); - } else if (largememory > 0) { - logit("Decreased memory: %u MB; want %u bytes", - largememory, (largewords << SHIFT_BYTE)); - largewords = (largememory << SHIFT_MEGAWORD); - } + /* Always use the maximum amount of memory supported by the algorithm. */ + largememory = LARGE_MAXIMUM; + largewords = (largememory << SHIFT_MEGAWORD); TinySieve = xcalloc(tinywords, sizeof(u_int32_t)); tinybits = tinywords << SHIFT_WORD; @@ -308,12 +268,7 @@ gen_candidates(FILE *out, u_int32_t memory, u_int32_t power, BIGNUM *start) SmallSieve = xcalloc(smallwords, sizeof(u_int32_t)); smallbits = smallwords << SHIFT_WORD; - /* - * dynamically determine available memory - */ - while ((LargeSieve = calloc(largewords, sizeof(u_int32_t))) == NULL) - largewords -= (1L << (SHIFT_MEGAWORD - 2)); /* 1/4 MB chunks */ - + LargeSieve = xcalloc(largewords, sizeof(u_int32_t)); largebits = largewords << SHIFT_WORD; largenumbers = largebits * 2; /* even numbers excluded */ diff --git a/ssh-keygen.1 b/ssh-keygen.1 index 00246a861ac9..3caf097129c3 100644 --- a/ssh-keygen.1 +++ b/ssh-keygen.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-keygen.1,v 1.234 2024/11/27 13:00:23 djm Exp $ +.\" $OpenBSD: ssh-keygen.1,v 1.235 2025/05/24 03:40:54 dtucker Exp $ .\" .\" Author: Tatu Ylonen .\" Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -35,7 +35,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd $Mdocdate: November 27 2024 $ +.Dd $Mdocdate: May 24 2025 $ .Dt SSH-KEYGEN 1 .Os .Sh NAME @@ -878,9 +878,6 @@ Write the last line processed to the specified file while performing DH candidate screening. This will be used to skip lines in the input file that have already been processed if the job is restarted. -.It Ic memory Ns = Ns Ar mbytes -Specify the amount of memory to use (in megabytes) when generating -candidate moduli for DH-GEX. .It Ic start Ns = Ns Ar hex-value Specify start point (in hex) when generating candidate moduli for DH-GEX. .It Ic generator Ns = Ns Ar value diff --git a/ssh-keygen.c b/ssh-keygen.c index ac0170de4938..867fbd1ca014 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keygen.c,v 1.480 2025/05/24 02:01:28 dtucker Exp $ */ +/* $OpenBSD: ssh-keygen.c,v 1.481 2025/05/24 03:37:40 dtucker Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1994 Tatu Ylonen , Espoo, Finland @@ -166,7 +166,7 @@ static char hostname[NI_MAXHOST]; #ifdef WITH_OPENSSL /* moduli.c */ -int gen_candidates(FILE *, u_int32_t, u_int32_t, BIGNUM *); +int gen_candidates(FILE *, u_int32_t, BIGNUM *); int prime_test(FILE *, FILE *, u_int32_t, u_int32_t, char *, unsigned long, unsigned long); #endif @@ -2923,7 +2923,6 @@ do_moduli_gen(const char *out_file, char **opts, size_t nopts) { #ifdef WITH_OPENSSL /* Moduli generation/screening */ - u_int32_t memory = 0; BIGNUM *start = NULL; int moduli_bits = 0; FILE *out; @@ -2932,12 +2931,7 @@ do_moduli_gen(const char *out_file, char **opts, size_t nopts) /* Parse options */ for (i = 0; i < nopts; i++) { - if ((p = strprefix(opts[i], "memory=", 0)) != NULL) { - memory = (u_int32_t)strtonum(p, 1, UINT_MAX, &errstr); - if (errstr) { - fatal("Memory limit is %s: %s", errstr, p); - } - } else if ((p = strprefix(opts[i], "start=", 0)) != NULL) { + if ((p = strprefix(opts[i], "start=", 0)) != NULL) { /* XXX - also compare length against bits */ if (BN_hex2bn(&start, p) == 0) fatal("Invalid start point."); @@ -2962,7 +2956,7 @@ do_moduli_gen(const char *out_file, char **opts, size_t nopts) if (moduli_bits == 0) moduli_bits = DEFAULT_BITS; - if (gen_candidates(out, memory, moduli_bits, start) != 0) + if (gen_candidates(out, moduli_bits, start) != 0) fatal("modulus candidate generation failed"); #else /* WITH_OPENSSL */ fatal("Moduli generation is not supported"); From 140bae1df2b7246bb43439d039bf994159973585 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Mon, 30 Sep 2024 13:14:11 +0200 Subject: [PATCH 091/244] auth-pam: Check the user didn't change during PAM transaction PAM modules can change the user during their execution, in such case ssh would still use the user that has been provided giving potentially access to another user with the credentials of another one. So prevent this to happen, by ensuring that the final PAM user is matching the one that initiated the transaction. --- auth-pam.c | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/auth-pam.c b/auth-pam.c index 13c0a792e99e..2481db45fd89 100644 --- a/auth-pam.c +++ b/auth-pam.c @@ -467,6 +467,32 @@ sshpam_thread_conv(int n, sshpam_const struct pam_message **msg, return (PAM_CONV_ERR); } +static int +check_pam_user(Authctxt *authctxt) +{ + const char *pam_user; + + if (authctxt == NULL || authctxt->pw == NULL || + authctxt->pw->pw_name == NULL) + fatal("%s: PAM authctxt user not initialized", __func__); + + if ((sshpam_err = pam_get_item(sshpam_handle, PAM_USER, + (sshpam_const void **) &pam_user)) != PAM_SUCCESS) + return sshpam_err; + + if (pam_user == NULL) { + debug("PAM error: PAM_USER is NULL"); + return PAM_USER_UNKNOWN; + } + + if (strcmp(authctxt->pw->pw_name, pam_user) != 0) { + debug("PAM user \"%s\" does not match expected \"%s\"", + pam_user, authctxt->pw->pw_name); + return PAM_USER_UNKNOWN; + } + return PAM_SUCCESS; +} + /* * Authentication thread. */ @@ -521,6 +547,8 @@ sshpam_thread(void *ctxtp) sshpam_set_maxtries_reached(1); if (sshpam_err != PAM_SUCCESS) goto auth_fail; + if ((sshpam_err = check_pam_user(sshpam_authctxt)) != PAM_SUCCESS) + goto auth_fail; if (!do_pam_account()) { sshpam_err = PAM_ACCT_EXPIRED; @@ -686,8 +714,7 @@ sshpam_cleanup(void) static int sshpam_init(struct ssh *ssh, Authctxt *authctxt) { - const char *pam_user, *user = authctxt->user; - const char **ptr_pam_user = &pam_user; + const char *user = authctxt->user; int r; if (options.pam_service_name == NULL) @@ -706,12 +733,8 @@ sshpam_init(struct ssh *ssh, Authctxt *authctxt) } if (sshpam_handle != NULL) { /* We already have a PAM context; check if the user matches */ - sshpam_err = pam_get_item(sshpam_handle, - PAM_USER, (sshpam_const void **)ptr_pam_user); - if (sshpam_err == PAM_SUCCESS && strcmp(user, pam_user) == 0) - return (0); - pam_end(sshpam_handle, sshpam_err); - sshpam_handle = NULL; + if ((sshpam_err = check_pam_user(authctxt)) != PAM_SUCCESS) + fatal("PAM user mismatch"); } debug("PAM: initializing for \"%s\" with service \"%s\"", user, options.pam_service_name); @@ -1378,6 +1401,8 @@ sshpam_auth_passwd(Authctxt *authctxt, const char *password) sshpam_err = pam_authenticate(sshpam_handle, flags); sshpam_password = NULL; free(fake); + if (sshpam_err == PAM_SUCCESS) + sshpam_err = check_pam_user(authctxt); if (sshpam_err == PAM_MAXTRIES) sshpam_set_maxtries_reached(1); if (sshpam_err == PAM_SUCCESS && authctxt->valid) { From d0245389bc55f16082cadd0a39dda5af1c415dfa Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Sat, 24 May 2025 17:11:38 +1000 Subject: [PATCH 092/244] ssh-keygen changes were fixup'ed into single commit. --- .skipped-commit-ids | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.skipped-commit-ids b/.skipped-commit-ids index 319beea0dee6..382dde52ba4e 100644 --- a/.skipped-commit-ids +++ b/.skipped-commit-ids @@ -40,6 +40,8 @@ fb39324748824cb0387e9d67c41d1bef945c54ea Makefile change a959fc45ea3431b36f52eda04faefc58bcde00db groupaccess.c changes 6d07e4606997e36b860621a14dd41975f2902f8f Makefile.inc c7246a6b519ac390ca550719f91acfdaef1fa0f0 Makefile relink change +ef7ecdb6dd2542f42fa7236d17ac0b144851f0b5 ssh-keygen, fixup'ed into 21682417 +da414a364c25b187fc686da7aacec2c35d29238a ssh-keygen, fixup'ed into 21682417 Old upstream tree: From 3de011ef7a761751afe28ac7ef97fe330d784595 Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Sat, 24 May 2025 06:43:37 +0000 Subject: [PATCH 093/244] upstream: Plug leak of startup_pollfd in debug and child paths. Coverity CID 405024, ok djm@ OpenBSD-Commit-ID: db46047229253e9c4470c8bbf5f82706ac021377 --- sshd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sshd.c b/sshd.c index 03732bb09c50..91608eff760c 100644 --- a/sshd.c +++ b/sshd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd.c,v 1.618 2025/05/06 05:40:56 djm Exp $ */ +/* $OpenBSD: sshd.c,v 1.619 2025/05/24 06:43:37 dtucker Exp $ */ /* * Copyright (c) 2000, 2001, 2002 Markus Friedl. All rights reserved. * Copyright (c) 2002 Niels Provos. All rights reserved. @@ -1169,6 +1169,7 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s, send_rexec_state(config_s[0]); close(config_s[0]); free(pfd); + free(startup_pollfd); return; } @@ -1201,6 +1202,7 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s, log_stderr); close(config_s[0]); free(pfd); + free(startup_pollfd); return; } From e3c58113ebb3397b252ff26e0e94f726b7db7a8a Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Sat, 24 May 2025 04:40:37 +0000 Subject: [PATCH 094/244] upstream: add a start_ssh_agent() function that sets up an agent with logging OpenBSD-Regress-ID: 7f9f30f9c64acbd4b418a5e1a19140cc988071a8 --- regress/test-exec.sh | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/regress/test-exec.sh b/regress/test-exec.sh index 714636f6ebfc..d4d40c2ae893 100644 --- a/regress/test-exec.sh +++ b/regress/test-exec.sh @@ -1,4 +1,4 @@ -# $OpenBSD: test-exec.sh,v 1.128 2025/05/21 08:36:39 djm Exp $ +# $OpenBSD: test-exec.sh,v 1.129 2025/05/24 04:40:37 djm Exp $ # Placed in the Public Domain. #SUDO=sudo @@ -927,7 +927,7 @@ p11_setup() { /usr/lib64/pkcs11/libsofthsm2.so \ /usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so test -z "$TEST_SSH_PKCS11" && return 1 - verbose "using token library $TEST_SSH_PKCS11" + trace "using token library $TEST_SSH_PKCS11" TEST_SSH_PIN=1234 TEST_SSH_SOPIN=12345678 if [ "x$TEST_SSH_SSHPKCS11HELPER" != "x" ]; then @@ -995,6 +995,28 @@ p11_ssh_add() { env SSH_ASKPASS="$PIN_SH" SSH_ASKPASS_REQUIRE=force ${SSHADD} "$@" } +start_ssh_agent() { + EXTRA_AGENT_ARGS="$1" + SSH_AUTH_SOCK="$OBJ/agent.sock" + export SSH_AUTH_SOCK + rm -f $SSH_AUTH_SOCK $OBJ/agent.log + trace "start agent" + ${SSHAGENT} ${EXTRA_AGENT_ARGS} -d -a $SSH_AUTH_SOCK \ + > $OBJ/agent.log 2>&1 & + AGENT_PID=$! + trap "kill $AGENT_PID" EXIT + for x in 0 1 2 3 4 ; do + # Give it a chance to start + ${SSHADD} -l > /dev/null 2>&1 + r=$? + test $r -eq 1 && break + sleep 1 + done + if [ $r -ne 1 ]; then + fatal "ssh-add -l did not fail with exit code 1 (got $r)" + fi +} + # source test body . $SCRIPT From 484563ec70e30472ab4484d49bca9a83771d785c Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Sat, 24 May 2025 04:41:03 +0000 Subject: [PATCH 095/244] upstream: use start_ssh_agent() to ensure we get logging add some verbosity OpenBSD-Regress-ID: a89bf64696b9fb1b91be318e6b8940c9ab21c616 --- regress/agent-pkcs11.sh | 72 ++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 40 deletions(-) diff --git a/regress/agent-pkcs11.sh b/regress/agent-pkcs11.sh index 304734f4b484..731c1f9ddc96 100644 --- a/regress/agent-pkcs11.sh +++ b/regress/agent-pkcs11.sh @@ -1,54 +1,46 @@ -# $OpenBSD: agent-pkcs11.sh,v 1.13 2023/10/30 23:00:25 djm Exp $ +# $OpenBSD: agent-pkcs11.sh,v 1.14 2025/05/24 04:41:03 djm Exp $ # Placed in the Public Domain. tid="pkcs11 agent test" p11_setup || skip "No PKCS#11 library found" -trace "start agent" -eval `${SSHAGENT} ${EXTRA_AGENT_ARGS} -s` > /dev/null +start_ssh_agent + +trace "add pkcs11 key to agent" +p11_ssh_add -s ${TEST_SSH_PKCS11} > /dev/null 2>&1 r=$? if [ $r -ne 0 ]; then - fail "could not start ssh-agent: exit code $r" -else - trace "add pkcs11 key to agent" - p11_ssh_add -s ${TEST_SSH_PKCS11} > /dev/null 2>&1 - r=$? - if [ $r -ne 0 ]; then - fail "ssh-add -s failed: exit code $r" - fi + fail "ssh-add -s failed: exit code $r" +fi - trace "pkcs11 list via agent" - ${SSHADD} -l > /dev/null 2>&1 - r=$? - if [ $r -ne 0 ]; then - fail "ssh-add -l failed: exit code $r" - fi +trace "pkcs11 list via agent" +${SSHADD} -l > /dev/null 2>&1 +r=$? +if [ $r -ne 0 ]; then + fail "ssh-add -l failed: exit code $r" +fi - for k in $RSA $EC; do - trace "testing $k" - pub=$(cat $k.pub) - ${SSHADD} -L | grep -q "$pub" || \ - fail "key $k missing in ssh-add -L" - ${SSHADD} -T $k.pub || fail "ssh-add -T with $k failed" - - # add to authorized keys - cat $k.pub > $OBJ/authorized_keys_$USER - trace "pkcs11 connect via agent ($k)" - ${SSH} -F $OBJ/ssh_proxy somehost exit 5 - r=$? - if [ $r -ne 5 ]; then - fail "ssh connect failed (exit code $r)" - fi - done - - trace "remove pkcs11 keys" - p11_ssh_add -e ${TEST_SSH_PKCS11} > /dev/null 2>&1 +for k in $RSA $EC; do + trace "testing $k" + pub=$(cat $k.pub) + ${SSHADD} -L | grep -q "$pub" || \ + fail "key $k missing in ssh-add -L" + ${SSHADD} -T $k.pub || fail "ssh-add -T with $k failed" + + # add to authorized keys + cat $k.pub > $OBJ/authorized_keys_$USER + trace "pkcs11 connect via agent ($k)" + ${SSH} -F $OBJ/ssh_proxy somehost exit 5 r=$? - if [ $r -ne 0 ]; then - fail "ssh-add -e failed: exit code $r" + if [ $r -ne 5 ]; then + fail "ssh connect failed (exit code $r)" fi +done - trace "kill agent" - ${SSHAGENT} -k > /dev/null +trace "remove pkcs11 keys" +p11_ssh_add -e ${TEST_SSH_PKCS11} > /dev/null 2>&1 +r=$? +if [ $r -ne 0 ]; then + fail "ssh-add -e failed: exit code $r" fi From a26091ecdb2a3d72b77baf3c253e676a3c835a24 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Sat, 24 May 2025 04:41:12 +0000 Subject: [PATCH 096/244] upstream: add some verbosity OpenBSD-Regress-ID: 11c86cda4435b5f9ab6172c4742b95899666c977 --- regress/agent-pkcs11-cert.sh | 31 ++++++++++--------------------- regress/agent-pkcs11-restrict.sh | 30 +++++++----------------------- 2 files changed, 17 insertions(+), 44 deletions(-) diff --git a/regress/agent-pkcs11-cert.sh b/regress/agent-pkcs11-cert.sh index 4e8f748465a3..39e839f9c26a 100644 --- a/regress/agent-pkcs11-cert.sh +++ b/regress/agent-pkcs11-cert.sh @@ -1,15 +1,12 @@ -# $OpenBSD: agent-pkcs11-cert.sh,v 1.1 2023/12/18 14:50:08 djm Exp $ +# $OpenBSD: agent-pkcs11-cert.sh,v 1.2 2025/05/24 04:41:12 djm Exp $ # Placed in the Public Domain. tid="pkcs11 agent certificate test" -SSH_AUTH_SOCK="$OBJ/agent.sock" -export SSH_AUTH_SOCK LC_ALL=C export LC_ALL p11_setup || skip "No PKCS#11 library found" -rm -f $SSH_AUTH_SOCK $OBJ/agent.log rm -f $OBJ/output_* $OBJ/expect_* rm -f $OBJ/ca* @@ -22,23 +19,9 @@ $SSHKEYGEN -qs $OBJ/ca -I "rsa_key" -n $USER -z 2 ${SSH_SOFTHSM_DIR}/RSA.pub || $SSHKEYGEN -qs $OBJ/ca -I "ca_ca" -n $USER -z 3 $OBJ/ca.pub || fatal "certify CA key failed" -rm -f $SSH_AUTH_SOCK -trace "start agent" -${SSHAGENT} ${EXTRA_AGENT_ARGS} -d -a $SSH_AUTH_SOCK > $OBJ/agent.log 2>&1 & -AGENT_PID=$! -trap "kill $AGENT_PID" EXIT -for x in 0 1 2 3 4 ; do - # Give it a chance to start - ${SSHADD} -l > /dev/null 2>&1 - r=$? - test $r -eq 1 && break - sleep 1 -done -if [ $r -ne 1 ]; then - fatal "ssh-add -l did not fail with exit code 1 (got $r)" -fi +start_ssh_agent -trace "load pkcs11 keys and certs" +verbose "load pkcs11 keys and certs" # Note: deliberately contains non-cert keys and non-matching cert on commandline p11_ssh_add -qs ${TEST_SSH_PKCS11} \ $OBJ/ca.pub \ @@ -48,6 +31,7 @@ p11_ssh_add -qs ${TEST_SSH_PKCS11} \ ${SSH_SOFTHSM_DIR}/RSA-cert.pub || fatal "failed to add keys" # Verify their presence +verbose "verify presence" cut -d' ' -f1-2 \ ${SSH_SOFTHSM_DIR}/EC.pub \ ${SSH_SOFTHSM_DIR}/RSA.pub \ @@ -57,21 +41,24 @@ $SSHADD -L | cut -d' ' -f1-2 | sort > $OBJ/output_list diff $OBJ/expect_list $OBJ/output_list # Verify that all can perform signatures. +verbose "check signatures" for x in ${SSH_SOFTHSM_DIR}/EC.pub ${SSH_SOFTHSM_DIR}/RSA.pub \ ${SSH_SOFTHSM_DIR}/EC-cert.pub ${SSH_SOFTHSM_DIR}/RSA-cert.pub ; do $SSHADD -T $x || fail "Signing failed for $x" done # Delete plain keys. +verbose "delete plain keys" $SSHADD -qd ${SSH_SOFTHSM_DIR}/EC.pub ${SSH_SOFTHSM_DIR}/RSA.pub # Verify that certs can still perform signatures. +verbose "reverify certificate signatures" for x in ${SSH_SOFTHSM_DIR}/EC-cert.pub ${SSH_SOFTHSM_DIR}/RSA-cert.pub ; do $SSHADD -T $x || fail "Signing failed for $x" done $SSHADD -qD >/dev/null || fatal "clear agent failed" -trace "load pkcs11 certs only" +verbose "load pkcs11 certs only" p11_ssh_add -qCs ${TEST_SSH_PKCS11} \ $OBJ/ca.pub \ ${SSH_SOFTHSM_DIR}/EC.pub \ @@ -80,6 +67,7 @@ p11_ssh_add -qCs ${TEST_SSH_PKCS11} \ ${SSH_SOFTHSM_DIR}/RSA-cert.pub || fatal "failed to add keys" # Verify their presence +verbose "verify presence" cut -d' ' -f1-2 \ ${SSH_SOFTHSM_DIR}/EC-cert.pub \ ${SSH_SOFTHSM_DIR}/RSA-cert.pub | sort > $OBJ/expect_list @@ -87,6 +75,7 @@ $SSHADD -L | cut -d' ' -f1-2 | sort > $OBJ/output_list diff $OBJ/expect_list $OBJ/output_list # Verify that certs can perform signatures. +verbose "check signatures" for x in ${SSH_SOFTHSM_DIR}/EC-cert.pub ${SSH_SOFTHSM_DIR}/RSA-cert.pub ; do $SSHADD -T $x || fail "Signing failed for $x" done diff --git a/regress/agent-pkcs11-restrict.sh b/regress/agent-pkcs11-restrict.sh index 867253211714..e5763ea8f6d0 100644 --- a/regress/agent-pkcs11-restrict.sh +++ b/regress/agent-pkcs11-restrict.sh @@ -1,11 +1,11 @@ -# $OpenBSD: agent-pkcs11-restrict.sh,v 1.1 2023/12/18 14:49:39 djm Exp $ +# $OpenBSD: agent-pkcs11-restrict.sh,v 1.2 2025/05/24 04:41:12 djm Exp $ # Placed in the Public Domain. tid="pkcs11 agent constraint test" p11_setup || skip "No PKCS#11 library found" -rm -f $SSH_AUTH_SOCK $OBJ/agent.log $OBJ/host_[abcx]* $OBJ/user_[abcx]* +rm -f $OBJ/host_[abcx]* $OBJ/user_[abcx]* rm -f $OBJ/sshd_proxy_host* $OBJ/ssh_output* $OBJ/expect_* rm -f $OBJ/ssh_proxy[._]* $OBJ/command $OBJ/authorized_keys_* @@ -26,23 +26,7 @@ key_for() { export K } -SSH_AUTH_SOCK="$OBJ/agent.sock" -export SSH_AUTH_SOCK -rm -f $SSH_AUTH_SOCK -trace "start agent" -${SSHAGENT} ${EXTRA_AGENT_ARGS} -d -a $SSH_AUTH_SOCK > $OBJ/agent.log 2>&1 & -AGENT_PID=$! -trap "kill $AGENT_PID" EXIT -for x in 0 1 2 3 4 ; do - # Give it a chance to start - ${SSHADD} -l > /dev/null 2>&1 - r=$? - test $r -eq 1 && break - sleep 1 -done -if [ $r -ne 1 ]; then - fatal "ssh-add -l did not fail with exit code 1 (got $r)" -fi +start_ssh_agent # XXX a lot of this is a copy of agent-restrict.sh, but I couldn't see a nice # way to factor it out -djm @@ -118,7 +102,7 @@ for h in a b ; do cat $K) >> $OBJ/authorized_keys_$USER done -trace "unrestricted keys" +verbose "unrestricted keys" $SSHADD -qD >/dev/null || fatal "clear agent failed" p11_ssh_add -qs ${TEST_SSH_PKCS11} || fatal "failed to add keys" @@ -134,7 +118,7 @@ for h in a b ; do cmp $OBJ/expect_$h $OBJ/ssh_output || fatal "unexpected output" done -trace "restricted to different host" +verbose "restricted to different host" $SSHADD -qD >/dev/null || fatal "clear agent failed" p11_ssh_add -q -h host_x -s ${TEST_SSH_PKCS11} -H $OBJ/known_hosts || fatal "failed to add keys" @@ -144,7 +128,7 @@ for h in a b ; do host_$h true > $OBJ/ssh_output && fatal "test ssh $h succeeded" done -trace "restricted to destination host" +verbose "restricted to destination host" $SSHADD -qD >/dev/null || fatal "clear agent failed" p11_ssh_add -q -h host_a -h host_b -s ${TEST_SSH_PKCS11} -H $OBJ/known_hosts || fatal "failed to add keys" @@ -160,7 +144,7 @@ for h in a b ; do cmp $OBJ/expect_$h $OBJ/ssh_output || fatal "unexpected output" done -trace "restricted multihop" +verbose "restricted multihop" $SSHADD -qD >/dev/null || fatal "clear agent failed" p11_ssh_add -q -h host_a -h "host_a>host_b" \ -s ${TEST_SSH_PKCS11} -H $OBJ/known_hosts || fatal "failed to add keys" From f8967045ad9d588bc11426642070bf8549065e62 Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Sat, 24 May 2025 06:50:28 +0000 Subject: [PATCH 097/244] upstream: Null out keys between test runs. BENCH_START and BENCH_FINISH are actually a while() loop in disguise, so if sshkey_generate does not reset the key pointer on failure the test may incorrectly pass. It also confuses Coverity (CID 551234). OpenBSD-Regress-ID: bf4d32079fc6df6dce1f26c2025f4ed492f13936 --- regress/unittests/sshkey/test_sshkey.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/regress/unittests/sshkey/test_sshkey.c b/regress/unittests/sshkey/test_sshkey.c index 832ef9b202cc..9dbd913066a8 100644 --- a/regress/unittests/sshkey/test_sshkey.c +++ b/regress/unittests/sshkey/test_sshkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: test_sshkey.c,v 1.29 2025/05/06 06:05:48 djm Exp $ */ +/* $OpenBSD: test_sshkey.c,v 1.30 2025/05/24 06:50:28 dtucker Exp $ */ /* * Regress test for sshkey.h key management API * @@ -560,6 +560,7 @@ sshkey_benchmarks(void) ASSERT_INT_EQ(sshkey_generate(KEY_RSA, 1024, &k), 0); ASSERT_PTR_NE(k, NULL); sshkey_free(k); + k = NULL; TEST_DONE(); BENCH_FINISH("keys"); @@ -568,15 +569,16 @@ sshkey_benchmarks(void) ASSERT_INT_EQ(sshkey_generate(KEY_RSA, 2048, &k), 0); ASSERT_PTR_NE(k, NULL); sshkey_free(k); + k = NULL; TEST_DONE(); BENCH_FINISH("keys"); - BENCH_START("generate ECDSA-256"); TEST_START("generate KEY_ECDSA"); ASSERT_INT_EQ(sshkey_generate(KEY_ECDSA, 256, &k), 0); ASSERT_PTR_NE(k, NULL); sshkey_free(k); + k = NULL; TEST_DONE(); BENCH_FINISH("keys"); @@ -585,6 +587,7 @@ sshkey_benchmarks(void) ASSERT_INT_EQ(sshkey_generate(KEY_ECDSA, 384, &k), 0); ASSERT_PTR_NE(k, NULL); sshkey_free(k); + k = NULL; TEST_DONE(); BENCH_FINISH("keys"); @@ -593,6 +596,7 @@ sshkey_benchmarks(void) ASSERT_INT_EQ(sshkey_generate(KEY_ECDSA, 521, &k), 0); ASSERT_PTR_NE(k, NULL); sshkey_free(k); + k = NULL; TEST_DONE(); BENCH_FINISH("keys"); #endif /* WITH_OPENSSL */ @@ -602,6 +606,7 @@ sshkey_benchmarks(void) ASSERT_INT_EQ(sshkey_generate(KEY_ED25519, 256, &k), 0); ASSERT_PTR_NE(k, NULL); sshkey_free(k); + k = NULL; TEST_DONE(); BENCH_FINISH("keys"); From e18983d03ab969e2f12485d5c0ee61e6d745a649 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Sat, 24 May 2025 17:20:57 +1000 Subject: [PATCH 098/244] Remove progressmeter.o from libssh.a. It's now explicitly included by the binaries that need it (scp & sftp). bz#3810, patch from jlduran at gmail.com --- Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.in b/Makefile.in index 410a29a123ab..eb6f08e4df9b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -107,7 +107,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ atomicio.o dispatch.o mac.o misc.o utf8.o \ monitor_fdpass.o rijndael.o ssh-ecdsa.o ssh-ecdsa-sk.o \ ssh-ed25519-sk.o ssh-rsa.o dh.o \ - msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \ + msg.o dns.o entropy.o gss-genr.o umac.o umac128.o \ ssh-pkcs11.o smult_curve25519_ref.o \ poly1305.o chacha.o cipher-chachapoly.o cipher-chachapoly-libcrypto.o \ ssh-ed25519.o digest-openssl.o digest-libc.o \ From a356d978e30dd9870c0b3a7d8edca535b0cd2809 Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Sat, 24 May 2025 08:09:32 +0000 Subject: [PATCH 099/244] upstream: Make the display number check relative to X11DisplayOffset. This will allows people to use X11DisplayOffset to configure much higher port ranges if they really want, while not changing the default behaviour. Patch from Roman Gubarev via github PR#559, ok djm@ OpenBSD-Commit-ID: e0926af5dc0c11e364452b624c3ad0cda88550b5 --- channels.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/channels.c b/channels.c index bfe2e3b2d4f7..5d503025fec2 100644 --- a/channels.c +++ b/channels.c @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.c,v 1.442 2024/12/05 06:49:26 dtucker Exp $ */ +/* $OpenBSD: channels.c,v 1.443 2025/05/24 08:09:32 dtucker Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -5010,7 +5010,7 @@ x11_create_display_inet(struct ssh *ssh, int x11_display_offset, return -1; for (display_number = x11_display_offset; - display_number < MAX_DISPLAYS; + display_number < x11_display_offset + MAX_DISPLAYS; display_number++) { port = X11_BASE_PORT + display_number; memset(&hints, 0, sizeof(hints)); @@ -5065,7 +5065,7 @@ x11_create_display_inet(struct ssh *ssh, int x11_display_offset, if (num_socks > 0) break; } - if (display_number >= MAX_DISPLAYS) { + if (display_number >= x11_display_offset + MAX_DISPLAYS) { error("Failed to allocate internet-domain X11 display socket."); return -1; } From b12d4ab1e16f57c6c348b483b1dbdd4530aaaddd Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Sat, 24 May 2025 08:13:29 +0000 Subject: [PATCH 100/244] upstream: Replace strncmp + byte count with strprefix in Penalty config parsing. ok kn@, djm@ OpenBSD-Commit-ID: 34a41bb1b9ba37fb6c7eb29a7ea909547bf02a5a --- servconf.c | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/servconf.c b/servconf.c index f2a540dad54e..14165429f20f 100644 --- a/servconf.c +++ b/servconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.c,v 1.426 2025/05/22 04:22:03 dtucker Exp $ */ +/* $OpenBSD: servconf.c,v 1.427 2025/05/24 08:13:29 dtucker Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -2084,10 +2084,11 @@ process_server_config_line_depth(ServerOptions *options, char *line, case sPerSourcePenalties: while ((arg = argv_next(&ac, &av)) != NULL) { + const char *q = NULL; + found = 1; value = -1; value2 = 0; - p = NULL; /* Allow no/yes only in first position */ if (strcasecmp(arg, "no") == 0 || (value2 = (strcasecmp(arg, "yes") == 0))) { @@ -2100,35 +2101,28 @@ process_server_config_line_depth(ServerOptions *options, char *line, options->per_source_penalty.enabled == -1) options->per_source_penalty.enabled = value2; continue; - } else if (strncmp(arg, "crash:", 6) == 0) { - p = arg + 6; + } else if ((q = strprefix(arg, "crash:", 0)) != NULL) { intptr = &options->per_source_penalty.penalty_crash; - } else if (strncmp(arg, "authfail:", 9) == 0) { - p = arg + 9; + } else if ((q = strprefix(arg, "authfail:", 0)) != NULL) { intptr = &options->per_source_penalty.penalty_authfail; - } else if (strncmp(arg, "noauth:", 7) == 0) { - p = arg + 7; + } else if ((q = strprefix(arg, "noauth:", 0)) != NULL) { intptr = &options->per_source_penalty.penalty_noauth; - } else if (strncmp(arg, "grace-exceeded:", 15) == 0) { - p = arg + 15; + } else if ((q = strprefix(arg, "grace-exceeded:", 0)) != NULL) { intptr = &options->per_source_penalty.penalty_grace; - } else if (strncmp(arg, "refuseconnection:", 17) == 0) { - p = arg + 17; + } else if ((q = strprefix(arg, "refuseconnection:", 0)) != NULL) { intptr = &options->per_source_penalty.penalty_refuseconnection; - } else if (strncmp(arg, "max:", 4) == 0) { - p = arg + 4; + } else if ((q = strprefix(arg, "max:", 0)) != NULL) { intptr = &options->per_source_penalty.penalty_max; - } else if (strncmp(arg, "min:", 4) == 0) { - p = arg + 4; + } else if ((q = strprefix(arg, "min:", 0)) != NULL) { intptr = &options->per_source_penalty.penalty_min; - } else if (strncmp(arg, "max-sources4:", 13) == 0) { + } else if ((q = strprefix(arg, "max-sources4:", 0)) != NULL) { intptr = &options->per_source_penalty.max_sources4; - if ((errstr = atoi_err(arg+13, &value)) != NULL) + if ((errstr = atoi_err(q, &value)) != NULL) fatal("%s line %d: %s value %s.", filename, linenum, keyword, errstr); - } else if (strncmp(arg, "max-sources6:", 13) == 0) { + } else if ((q = strprefix(arg, "max-sources6:", 0)) != NULL) { intptr = &options->per_source_penalty.max_sources6; - if ((errstr = atoi_err(arg+13, &value)) != NULL) + if ((errstr = atoi_err(q, &value)) != NULL) fatal("%s line %d: %s value %s.", filename, linenum, keyword, errstr); } else if (strcmp(arg, "overflow:deny-all") == 0) { @@ -2148,7 +2142,7 @@ process_server_config_line_depth(ServerOptions *options, char *line, filename, linenum, keyword, arg); } /* If no value was parsed above, assume it's a time */ - if (value == -1 && (value = convtime(p)) == -1) { + if (value == -1 && (value = convtime(q)) == -1) { fatal("%s line %d: invalid %s time value.", filename, linenum, keyword); } From 3a61f5ed66231881bee432c7e7c6add066c086af Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Sat, 24 May 2025 09:46:16 +0000 Subject: [PATCH 101/244] upstream: fix punctuation around host key fingerprints to make them easier to copy and paste. Patch from Till Maas via GHPR556; ok dtucker@ OpenBSD-Commit-ID: c0100182a30b6925c8cdb2225b18140264594b7b --- sshconnect.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sshconnect.c b/sshconnect.c index b306fa3cc24f..a90167fd6dae 100644 --- a/sshconnect.c +++ b/sshconnect.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshconnect.c,v 1.370 2025/05/06 05:40:56 djm Exp $ */ +/* $OpenBSD: sshconnect.c,v 1.371 2025/05/24 09:46:16 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1145,7 +1145,7 @@ check_host_key(char *hostname, const struct ssh_conn_info *cinfo, options.fingerprint_hash, SSH_FP_RANDOMART); if (fp == NULL || ra == NULL) fatal_f("sshkey_fingerprint failed"); - logit("Host key fingerprint is %s\n%s", fp, ra); + logit("Host key fingerprint is: %s\n%s", fp, ra); free(ra); free(fp); } @@ -1196,7 +1196,7 @@ check_host_key(char *hostname, const struct ssh_conn_info *cinfo, options.fingerprint_hash, SSH_FP_RANDOMART); if (fp == NULL || ra == NULL) fatal_f("sshkey_fingerprint failed"); - xextendf(&msg1, "\n", "%s key fingerprint is %s.", + xextendf(&msg1, "\n", "%s key fingerprint is: %s", type, fp); if (options.visual_host_key) xextendf(&msg1, "\n", "%s", ra); From 73ef0563a59f90324f8426c017f38e20341b555f Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Sat, 24 May 2025 11:41:51 +0000 Subject: [PATCH 102/244] upstream: replace xmalloc+memset(0) with xcalloc(); from AZero13 via GHPR417 OpenBSD-Commit-ID: 921079436a4900325d22bd3b6a90c8d0d54f62f8 --- channels.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/channels.c b/channels.c index 5d503025fec2..cd27faab2cf3 100644 --- a/channels.c +++ b/channels.c @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.c,v 1.443 2025/05/24 08:09:32 dtucker Exp $ */ +/* $OpenBSD: channels.c,v 1.444 2025/05/24 11:41:51 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -4677,8 +4677,7 @@ connect_to_helper(struct ssh *ssh, const char *name, int port, int socktype, * channel_connect_ctx_free() must check ai_family * and use free() not freeaddirinfo() for AF_UNIX. */ - ai = xmalloc(sizeof(*ai) + sizeof(*sunaddr)); - memset(ai, 0, sizeof(*ai) + sizeof(*sunaddr)); + ai = xcalloc(1, sizeof(*ai) + sizeof(*sunaddr)); ai->ai_addr = (struct sockaddr *)(ai + 1); ai->ai_addrlen = sizeof(*sunaddr); ai->ai_family = AF_UNIX; From dc6c134b48ba4bcfadedcea17b4eddac329601d9 Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Thu, 29 May 2025 13:27:27 +0000 Subject: [PATCH 103/244] upstream: When there's more than one x11 channel in use, return lastused of most recently used x11 channel instead of the last one found. ok djm@ OpenBSD-Commit-ID: 94a72bf988d40a5bae2e38608f4e117f712569fe --- channels.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/channels.c b/channels.c index cd27faab2cf3..f71f82466f2f 100644 --- a/channels.c +++ b/channels.c @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.c,v 1.444 2025/05/24 11:41:51 djm Exp $ */ +/* $OpenBSD: channels.c,v 1.445 2025/05/29 13:27:27 dtucker Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -5353,7 +5353,8 @@ x11_channel_used_recently(struct ssh *ssh) { if (c == NULL || c->ctype == NULL || c->lastused == 0 || strcmp(c->ctype, "x11-connection") != 0) continue; - lastused = c->lastused; + if (c->lastused > lastused) + lastused = c->lastused; } return lastused != 0 && monotime() > lastused + 1; } From 203bb886797677aa5d61b57be83cfdc1b634bc9c Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Mon, 2 Jun 2025 14:09:34 +0000 Subject: [PATCH 104/244] upstream: Fix x11_channel_used_recently() to return true when channel has been used within the last second, instead of more than a second ago. Should fix ~5s delay on X client startup when ObscureKeystrokeTiming is enabled. bz#3820, ok (& sigh) djm@ OpenBSD-Commit-ID: b741011e81fb3e3d42711d9bd3ed8a959924dee4 --- channels.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/channels.c b/channels.c index f71f82466f2f..0efbd8d174c7 100644 --- a/channels.c +++ b/channels.c @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.c,v 1.445 2025/05/29 13:27:27 dtucker Exp $ */ +/* $OpenBSD: channels.c,v 1.446 2025/06/02 14:09:34 dtucker Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -5356,5 +5356,5 @@ x11_channel_used_recently(struct ssh *ssh) { if (c->lastused > lastused) lastused = c->lastused; } - return lastused != 0 && monotime() > lastused + 1; + return lastused != 0 && monotime() <= lastused + 1; } From a22ff3c6f11edd00c19981f9cb85d3b25d305a56 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Wed, 4 Jun 2025 18:33:52 +1000 Subject: [PATCH 105/244] Disable _FORTIFY_SOURCE during snprintf test. Prevents mistakenly detecting snprintf as broken on FreeBSD 15 with _FORTIFY_SOURCE enabled. bz#3809, patch from jlduran at gmail.com --- configure.ac | 3 +++ 1 file changed, 3 insertions(+) diff --git a/configure.ac b/configure.ac index 94e782e1563b..9bc664172b0d 100644 --- a/configure.ac +++ b/configure.ac @@ -2503,6 +2503,9 @@ fi # This is only useful for when BROKEN_SNPRINTF AC_MSG_CHECKING([whether snprintf can declare const char *fmt]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#ifdef _FORTIFY_SOURCE +#undef _FORTIFY_SOURCE +#endif #include int snprintf(char *a, size_t b, const char *c, ...) { return 0; } ]], [[ From 5530e5f83b3cd3425ea3dbab02da15140befdd91 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Tue, 10 Jun 2025 18:40:56 +1000 Subject: [PATCH 106/244] Replace Windows 2019 runners with 2025 ones. The windows-2019 runners are being decomissioned. --- .github/workflows/c-cpp.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 4acb1f5f2478..7ee1796463f0 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -32,14 +32,14 @@ jobs: - macos-13 - macos-14 - macos-15 - - windows-2019 - windows-2022 + - windows-2025 config: [default] # Then we include any extra configs we want to test for specific VMs. # Valgrind slows things down quite a bit, so start them first. include: - - { target: windows-2019, config: cygwin-release } - { target: windows-2022, config: cygwin-release } + - { target: windows-2025, config: cygwin-release } - { target: ubuntu-22.04, config: c89 } - { target: ubuntu-22.04, config: clang-11 } - { target: ubuntu-22.04, config: clang-12-Werror } From 4b3d27032ba88dd089b721f3bbe3e4a8d23b4ae1 Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Wed, 11 Jun 2025 13:24:05 +0000 Subject: [PATCH 107/244] upstream: Improve termination condition of while loop to compare size_t's. Assuming read() does what it's supposed to this shouldn't matter, but should be more robust. Flagged by Coverity CID 470514, ok djm@ OpenBSD-Commit-ID: d7b5ad60feb797b3464964b9ea67fd78fb9d6cc6 --- readpass.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readpass.c b/readpass.c index d42b1185d017..5a88824b4f6c 100644 --- a/readpass.c +++ b/readpass.c @@ -1,4 +1,4 @@ -/* $OpenBSD: readpass.c,v 1.71 2024/03/30 04:27:44 djm Exp $ */ +/* $OpenBSD: readpass.c,v 1.72 2025/06/11 13:24:05 dtucker Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. * @@ -91,7 +91,7 @@ ssh_askpass(char *askpass, const char *msg, const char *env_hint) if (r <= 0) break; len += r; - } while (sizeof(buf) - 1 - len > 0); + } while (len < sizeof(buf) - 1); buf[len] = '\0'; close(p[0]); From 5d415897ac04e237f1fa73b9dcb9ba8fb3ac812b Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Wed, 11 Jun 2025 13:27:11 +0000 Subject: [PATCH 108/244] upstream: Remove dead code ternary. We always report at least KB/s, so B/s is never used. Coverity CID 291809, ok djm@ OpenBSD-Commit-ID: a67c5bcc9e19c8965bfeace0e337b13660efa058 --- progressmeter.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/progressmeter.c b/progressmeter.c index 0d1faba398c1..2c169768f60f 100644 --- a/progressmeter.c +++ b/progressmeter.c @@ -1,4 +1,4 @@ -/* $OpenBSD: progressmeter.c,v 1.55 2025/05/09 02:42:03 djm Exp $ */ +/* $OpenBSD: progressmeter.c,v 1.56 2025/06/11 13:27:11 dtucker Exp $ */ /* * Copyright (c) 2003 Nils Nordman. All rights reserved. * @@ -93,15 +93,15 @@ format_rate(off_t bytes) bytes *= 100; for (i = 0; bytes >= 100*1000 && unit[i] != 'T'; i++) bytes = (bytes + 512) / 1024; + /* Display at least KB, even when rate is low or zero. */ if (i == 0) { i++; bytes = (bytes + 512) / 1024; } - snprintf(buf, sizeof(buf), "%3lld.%1lld%c%s", + snprintf(buf, sizeof(buf), "%3lld.%1lld%cB", (long long) (bytes + 5) / 100, (long long) (bytes + 5) / 10 % 10, - unit[i], - i ? "B" : " "); + unit[i]); return buf; } From 567ef4e7ddc5c1e7a461560963a1dc759669821d Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Thu, 12 Jun 2025 09:19:43 +0000 Subject: [PATCH 109/244] upstream: Plug mem leak on error path. Coverity CID 307776. OpenBSD-Regress-ID: c44246690973e1b8643e51079a2faa7ace26490c --- regress/misc/sk-dummy/sk-dummy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/regress/misc/sk-dummy/sk-dummy.c b/regress/misc/sk-dummy/sk-dummy.c index 347b212271ec..b4cbc1324ecc 100644 --- a/regress/misc/sk-dummy/sk-dummy.c +++ b/regress/misc/sk-dummy/sk-dummy.c @@ -263,7 +263,7 @@ sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len, break; default: skdebug(__func__, "unsupported key type %d", alg); - return -1; + goto out; } /* Have to return something here */ if ((response->signature = calloc(1, 1)) == NULL) { From 2314d87f9b8b430532111fd6e5e8df0cf9068c9c Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Thu, 12 Jun 2025 09:26:57 +0000 Subject: [PATCH 110/244] upstream: Plug mem leak on error path here too. Coverity CID 307781. OpenBSD-Regress-ID: 18e053d9b661fbb4227d3db03172077c1216bb2e --- regress/misc/sk-dummy/sk-dummy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/regress/misc/sk-dummy/sk-dummy.c b/regress/misc/sk-dummy/sk-dummy.c index b4cbc1324ecc..8a33d18695ed 100644 --- a/regress/misc/sk-dummy/sk-dummy.c +++ b/regress/misc/sk-dummy/sk-dummy.c @@ -520,7 +520,7 @@ sk_sign(uint32_t alg, const uint8_t *data, size_t datalen, break; default: skdebug(__func__, "unsupported key type %d", alg); - return -1; + goto out; } *sign_response = response; response = NULL; From 930a45ee759728c8ba711c45a2a985b8191bd297 Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Thu, 12 Jun 2025 10:09:39 +0000 Subject: [PATCH 111/244] upstream: Set user, host and path to NULL immediately before calling parse_user_host_path in tests. This ensures that we don't accidentally use the previous value if the function under test doesn't set them Also fixes Coverity CIDs 405056 405065 405066. OpenBSD-Regress-ID: 43678ff59001712f32214fe303b1c21c163c2960 --- regress/unittests/misc/test_parse.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/regress/unittests/misc/test_parse.c b/regress/unittests/misc/test_parse.c index 1f1ea31d149c..c66028aec5e6 100644 --- a/regress/unittests/misc/test_parse.c +++ b/regress/unittests/misc/test_parse.c @@ -1,4 +1,4 @@ -/* $OpenBSD: test_parse.c,v 1.2 2021/12/14 21:25:27 deraadt Exp $ */ +/* $OpenBSD: test_parse.c,v 1.3 2025/06/12 10:09:39 dtucker Exp $ */ /* * Regress test for misc user/host/URI parsing functions. * @@ -29,6 +29,7 @@ test_parse(void) char *user, *host, *path; TEST_START("misc_parse_user_host_path"); + user = host = path = NULL; ASSERT_INT_EQ(parse_user_host_path("someuser@some.host:some/path", &user, &host, &path), 0); ASSERT_STRING_EQ(user, "someuser"); @@ -38,6 +39,7 @@ test_parse(void) TEST_DONE(); TEST_START("misc_parse_user_ipv4_path"); + user = host = path = NULL; ASSERT_INT_EQ(parse_user_host_path("someuser@1.22.33.144:some/path", &user, &host, &path), 0); ASSERT_STRING_EQ(user, "someuser"); @@ -47,6 +49,7 @@ test_parse(void) TEST_DONE(); TEST_START("misc_parse_user_[ipv4]_path"); + user = host = path = NULL; ASSERT_INT_EQ(parse_user_host_path("someuser@[1.22.33.144]:some/path", &user, &host, &path), 0); ASSERT_STRING_EQ(user, "someuser"); @@ -56,6 +59,7 @@ test_parse(void) TEST_DONE(); TEST_START("misc_parse_user_[ipv4]_nopath"); + user = host = path = NULL; ASSERT_INT_EQ(parse_user_host_path("someuser@[1.22.33.144]:", &user, &host, &path), 0); ASSERT_STRING_EQ(user, "someuser"); @@ -65,6 +69,7 @@ test_parse(void) TEST_DONE(); TEST_START("misc_parse_user_ipv6_path"); + user = host = path = NULL; ASSERT_INT_EQ(parse_user_host_path("someuser@[::1]:some/path", &user, &host, &path), 0); ASSERT_STRING_EQ(user, "someuser"); @@ -74,6 +79,7 @@ test_parse(void) TEST_DONE(); TEST_START("misc_parse_uri"); + user = host = path = NULL; ASSERT_INT_EQ(parse_uri("ssh", "ssh://someuser@some.host:22/some/path", &user, &host, &port, &path), 0); ASSERT_STRING_EQ(user, "someuser"); From 9cdc72b829e9f0e24dedc533cbe87291d8a88c9e Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Fri, 13 Jun 2025 07:23:07 +0000 Subject: [PATCH 112/244] upstream: Remove dead code flagged by Coverity CID 307783. ok djm@ OpenBSD-Regress-ID: e579f5ec2fd2eb2fe2bad654d16f2ba655a3e035 --- regress/unittests/test_helper/fuzz.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/regress/unittests/test_helper/fuzz.c b/regress/unittests/test_helper/fuzz.c index 9995b26a630a..edad5e1f5197 100644 --- a/regress/unittests/test_helper/fuzz.c +++ b/regress/unittests/test_helper/fuzz.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fuzz.c,v 1.8 2015/03/03 20:42:49 djm Exp $ */ +/* $OpenBSD: fuzz.c,v 1.9 2025/06/13 07:23:07 dtucker Exp $ */ /* * Copyright (c) 2011 Damien Miller * @@ -150,7 +150,6 @@ fuzz_fmt(struct fuzz *fuzz, char *s, size_t n) return 0; default: return -1; - abort(); } } From 2827b6ac304ded8f99e8fbc12e7299133fadb2c2 Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Fri, 13 Jun 2025 07:35:14 +0000 Subject: [PATCH 113/244] upstream: Plug leak. Coverity CID 405058. OpenBSD-Regress-ID: 7fb2fce68d2cb063cdb94d5d66f84fa3a2902792 --- regress/unittests/sshbuf/test_sshbuf_getput_basic.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/regress/unittests/sshbuf/test_sshbuf_getput_basic.c b/regress/unittests/sshbuf/test_sshbuf_getput_basic.c index 3da413edd35c..b5aca1fb1f9c 100644 --- a/regress/unittests/sshbuf/test_sshbuf_getput_basic.c +++ b/regress/unittests/sshbuf/test_sshbuf_getput_basic.c @@ -1,4 +1,4 @@ -/* $OpenBSD: test_sshbuf_getput_basic.c,v 1.3 2021/12/14 21:25:27 deraadt Exp $ */ +/* $OpenBSD: test_sshbuf_getput_basic.c,v 1.4 2025/06/13 07:35:14 dtucker Exp $ */ /* * Regress test for sshbuf.h buffer API * @@ -576,6 +576,7 @@ sshbuf_getput_basic_tests(void) ASSERT_PTR_NE(s2, NULL); ASSERT_STRING_EQ(s2, "00000000000000000000"); sshbuf_free(p1); + free(s2); TEST_DONE(); TEST_START("sshbuf_poke_u32"); From bd1bd7e8296aa51a4b3958cef2fbb17894ba94e9 Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Mon, 16 Jun 2025 08:49:27 +0000 Subject: [PATCH 114/244] upstream: Save return value from sshbuf_len instead of calling it multiple times. Fixes Coverity CID 470521. OpenBSD-Regress-ID: 356b8b43c8a232deaf445c1ff7526577b177a8e9 --- regress/unittests/sshkey/common.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/regress/unittests/sshkey/common.c b/regress/unittests/sshkey/common.c index a579eccb29d5..edb1d95fa794 100644 --- a/regress/unittests/sshkey/common.c +++ b/regress/unittests/sshkey/common.c @@ -1,4 +1,4 @@ -/* $OpenBSD: common.c,v 1.7 2025/05/06 06:05:48 djm Exp $ */ +/* $OpenBSD: common.c,v 1.8 2025/06/16 08:49:27 dtucker Exp $ */ /* * Helpers for key API tests * @@ -53,13 +53,13 @@ load_text_file(const char *name) { struct sshbuf *ret = load_file(name); const u_char *p; + size_t len; /* Trim whitespace at EOL */ - for (p = sshbuf_ptr(ret); sshbuf_len(ret) > 0;) { - if (p[sshbuf_len(ret) - 1] == '\r' || - p[sshbuf_len(ret) - 1] == '\t' || - p[sshbuf_len(ret) - 1] == ' ' || - p[sshbuf_len(ret) - 1] == '\n') + for (p = sshbuf_ptr(ret); (len = sshbuf_len(ret)) > 0;) { + len--; + if (p[len] == '\r' || p[len] == '\t' || + p[len] == ' ' || p[len] == '\n') ASSERT_INT_EQ(sshbuf_consume_end(ret, 1), 0); else break; From 80916d0d3794e2f92dd6998d7c45daba484e4f18 Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Mon, 16 Jun 2025 08:53:04 +0000 Subject: [PATCH 115/244] upstream: Plug mem leak. Patch from afonot via github PR#574, ok djm@ OpenBSD-Commit-ID: 65619f14ef206028ce39bc31f704b832a0609688 --- clientloop.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clientloop.c b/clientloop.c index 916fc077bdc9..b98413342e20 100644 --- a/clientloop.c +++ b/clientloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.c,v 1.410 2024/12/03 22:30:03 jsg Exp $ */ +/* $OpenBSD: clientloop.c,v 1.411 2025/06/16 08:53:04 dtucker Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -2420,6 +2420,7 @@ client_global_hostkeys_prove_confirm(struct ssh *ssh, int type, /* Make the edits to known_hosts */ update_known_hosts(ctx); out: + sshbuf_free(signdata); hostkeys_update_ctx_free(ctx); hostkeys_update_complete = 1; client_repledge(); From df3f903d616763a105570610a616dacf0f83438e Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Mon, 16 Jun 2025 09:02:19 +0000 Subject: [PATCH 116/244] upstream: Fix overflow check in sshbuf_dup_string. It's already constrained by SSHBUF_SIZE_MAX, but still worth fixing the check. Patch from afonot via github PR#573, with & ok djm@ OpenBSD-Commit-ID: 438888498e66472fc6a48133196d6538d27bff18 --- sshbuf-misc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sshbuf-misc.c b/sshbuf-misc.c index adbf9903b4d8..201279faf0f2 100644 --- a/sshbuf-misc.c +++ b/sshbuf-misc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshbuf-misc.c,v 1.19 2025/05/21 06:43:48 djm Exp $ */ +/* $OpenBSD: sshbuf-misc.c,v 1.20 2025/06/16 09:02:19 dtucker Exp $ */ /* * Copyright (c) 2011 Damien Miller * @@ -254,7 +254,7 @@ sshbuf_dup_string(struct sshbuf *buf) size_t l = sshbuf_len(buf); char *r; - if (s == NULL || l > SIZE_MAX) + if (s == NULL || l >= SIZE_MAX) return NULL; /* accept a nul only as the last character in the buffer */ if (l > 0 && (p = memchr(s, '\0', l)) != NULL) { From 05f7bf46d1e2c101e9cbdd3df2ccee484bed969f Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Mon, 16 Jun 2025 09:07:08 +0000 Subject: [PATCH 117/244] upstream: Now that ssh-keygen defaults to the maximum memory for moduli generation we no longer need to run it twice to get enough. Use mkdir -p instead of a conditional, which allows "make -jN" to work without error. OpenBSD-Commit-ID: c2eb57285424f819f9520fa33e0d6d3c4a361a5e --- .skipped-commit-ids | 1 + 1 file changed, 1 insertion(+) diff --git a/.skipped-commit-ids b/.skipped-commit-ids index 382dde52ba4e..8ed0befb7590 100644 --- a/.skipped-commit-ids +++ b/.skipped-commit-ids @@ -1,3 +1,4 @@ +c2eb57285424f819f9520fa33e0d6d3c4a361a5e moduli-gen.sh tweak 509bb19bb9762a4b3b589af98bac2e730541b6d4 clean sshd random relinking kit 5317f294d63a876bfc861e19773b1575f96f027d remove libssh from makefiles a337e886a49f96701ccbc4832bed086a68abfa85 Makefile changes From dd800444943bd64913507f6005586136d49f63db Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Mon, 16 Jun 2025 09:09:42 +0000 Subject: [PATCH 118/244] upstream: Limit each moduli size to a max of 100 entries. OpenBSD-Commit-ID: 747219d54565030ff7c45298b9f5e971801f6cb2 --- .skipped-commit-ids | 1 + 1 file changed, 1 insertion(+) diff --git a/.skipped-commit-ids b/.skipped-commit-ids index 8ed0befb7590..2ccd3a6626fa 100644 --- a/.skipped-commit-ids +++ b/.skipped-commit-ids @@ -1,3 +1,4 @@ +747219d54565030ff7c45298b9f5e971801f6cb2 moduli-gen Makefile tweak c2eb57285424f819f9520fa33e0d6d3c4a361a5e moduli-gen.sh tweak 509bb19bb9762a4b3b589af98bac2e730541b6d4 clean sshd random relinking kit 5317f294d63a876bfc861e19773b1575f96f027d remove libssh from makefiles From 1e8347e3543a415067ccc556aefea97656ecafb7 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Tue, 17 Jun 2025 09:48:47 +1000 Subject: [PATCH 119/244] add sshd-auth to RPM spec files --- contrib/redhat/openssh.spec | 1 + contrib/suse/openssh.spec | 1 + 2 files changed, 2 insertions(+) diff --git a/contrib/redhat/openssh.spec b/contrib/redhat/openssh.spec index b60695f09f95..0ba34ee8a152 100644 --- a/contrib/redhat/openssh.spec +++ b/contrib/redhat/openssh.spec @@ -353,6 +353,7 @@ fi %defattr(-,root,root) %dir %attr(0111,root,root) %{_var}/empty/sshd %attr(0755,root,root) %{_sbindir}/sshd +%attr(0755,root,root) %{_libexecdir}/openssh/sshd-auth %attr(0755,root,root) %{_libexecdir}/openssh/sshd-session %attr(0755,root,root) %{_libexecdir}/openssh/sftp-server %attr(0644,root,root) %{_mandir}/man8/sshd.8* diff --git a/contrib/suse/openssh.spec b/contrib/suse/openssh.spec index 849e9b61f3b8..6b95d73064b5 100644 --- a/contrib/suse/openssh.spec +++ b/contrib/suse/openssh.spec @@ -211,6 +211,7 @@ rm -rf $RPM_BUILD_ROOT %attr(0755,root,root) %{_sbindir}/sshd %attr(0755,root,root) %dir %{_libdir}/ssh %attr(0755,root,root) %{_libdir}/ssh/sftp-server +%attr(0755,root,root) %{_libdir}/ssh/sshd-auth %attr(0755,root,root) %{_libdir}/ssh/sshd-session %attr(4711,root,root) %{_libdir}/ssh/ssh-keysign %attr(0755,root,root) %{_libdir}/ssh/ssh-pkcs11-helper From 5f761cdb2331a12318bde24db5ca84ee144a51d1 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Tue, 17 Jun 2025 21:46:37 +1000 Subject: [PATCH 120/244] Update obsd tests to use current images. --- .github/workflows/selfhosted.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/selfhosted.yml b/.github/workflows/selfhosted.yml index 9f2bd99eb131..2f425fe2f39c 100644 --- a/.github/workflows/selfhosted.yml +++ b/.github/workflows/selfhosted.yml @@ -49,8 +49,9 @@ jobs: - obsd51 - obsd67 - obsd72 - - obsd73 - obsd74 + - obsd76 + - obsd77 - obsdsnap - obsdsnap-i386 - omnios From ad38ec5f1b6768944d64ed7709da8706538b5509 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Tue, 17 Jun 2025 01:19:27 +0000 Subject: [PATCH 121/244] upstream: fix leak on error path; Coverity CID 481976 OpenBSD-Commit-ID: 963dba2c804e2fd8efea2256092899874d0dbc7b --- misc-agent.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/misc-agent.c b/misc-agent.c index cf9b0fa0cb77..5ea91ebe3fbc 100644 --- a/misc-agent.c +++ b/misc-agent.c @@ -1,4 +1,4 @@ -/* $OpenBSD: misc-agent.c,v 1.5 2025/05/22 12:14:19 dtucker Exp $ */ +/* $OpenBSD: misc-agent.c,v 1.6 2025/06/17 01:19:27 djm Exp $ */ /* * Copyright (c) 2025 Damien Miller * @@ -169,6 +169,7 @@ ensure_mkdir(const char *homedir, const char *subdir) debug("created directory %s", path); else if (errno != EEXIST) { error_f("mkdir %s: %s", path, strerror(errno)); + free(path); return -1; } free(path); From b360f3a675e24b0dbb2ec30d985e3b6756996c0d Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Tue, 17 Jun 2025 01:20:17 +0000 Subject: [PATCH 122/244] upstream: whitespace OpenBSD-Commit-ID: 6e96814bcf70d0edbb0749ec61cc4fd8707f286d --- clientloop.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clientloop.c b/clientloop.c index b98413342e20..5f6577f65632 100644 --- a/clientloop.c +++ b/clientloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.c,v 1.411 2025/06/16 08:53:04 dtucker Exp $ */ +/* $OpenBSD: clientloop.c,v 1.412 2025/06/17 01:20:17 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -2420,7 +2420,7 @@ client_global_hostkeys_prove_confirm(struct ssh *ssh, int type, /* Make the edits to known_hosts */ update_known_hosts(ctx); out: - sshbuf_free(signdata); + sshbuf_free(signdata); hostkeys_update_ctx_free(ctx); hostkeys_update_complete = 1; client_repledge(); From 5ba8391d697740a838fd8811434f707f0e079baa Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Thu, 19 Jun 2025 05:49:05 +0000 Subject: [PATCH 123/244] upstream: better debug diagnostics when loading keys. Will now list key fingerprint and algorithm (not just algorithm number) as well as making it explicit which keys didn't load. OpenBSD-Commit-ID: ee3e77a0271ab502e653922c6d161b1e091f8fee --- ssh.c | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/ssh.c b/ssh.c index b2172b810a61..b44a943134ee 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.613 2025/05/06 05:40:56 djm Exp $ */ +/* $OpenBSD: ssh.c,v 1.614 2025/06/19 05:49:05 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -529,16 +529,28 @@ resolve_canonicalize(char **hostp, int port) static void check_load(int r, struct sshkey **k, const char *path, const char *message) { + char *fp; + switch (r) { case 0: + if (k == NULL || *k == NULL) + return; /* Check RSA keys size and discard if undersized */ - if (k != NULL && *k != NULL && - (r = sshkey_check_rsa_length(*k, + if ((r = sshkey_check_rsa_length(*k, options.required_rsa_size)) != 0) { error_r(r, "load %s \"%s\"", message, path); free(*k); *k = NULL; + break; + } + if ((fp = sshkey_fingerprint(*k, + options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) { + fatal_f("failed to fingerprint %s %s key from %s", + sshkey_type(*k), message, path); } + debug("loaded %s from %s: %s %s", message, path, + sshkey_type(*k), fp); + free(fp); break; case SSH_ERR_INTERNAL_ERROR: case SSH_ERR_ALLOC_FAIL: @@ -552,6 +564,8 @@ check_load(int r, struct sshkey **k, const char *path, const char *message) error_r(r, "load %s \"%s\"", message, path); break; } + if (k != NULL && *k == NULL) + debug("no %s loaded from %s", message, path); } /* @@ -1723,10 +1737,9 @@ main(int ac, char **av) if ((o) >= sensitive_data.nkeys) \ fatal_f("pubkey out of array bounds"); \ check_load(sshkey_load_public(p, &(sensitive_data.keys[o]), NULL), \ - &(sensitive_data.keys[o]), p, "pubkey"); \ + &(sensitive_data.keys[o]), p, "hostbased pubkey"); \ if (sensitive_data.keys[o] != NULL) { \ - debug2("hostbased key %d: %s key from \"%s\"", o, \ - sshkey_ssh_name(sensitive_data.keys[o]), p); \ + debug2("hostbased pubkey \"%s\" in slot %d", p, o); \ loaded++; \ } \ } while (0) @@ -1734,10 +1747,9 @@ main(int ac, char **av) if ((o) >= sensitive_data.nkeys) \ fatal_f("cert out of array bounds"); \ check_load(sshkey_load_cert(p, &(sensitive_data.keys[o])), \ - &(sensitive_data.keys[o]), p, "cert"); \ + &(sensitive_data.keys[o]), p, "hostbased cert"); \ if (sensitive_data.keys[o] != NULL) { \ - debug2("hostbased key %d: %s cert from \"%s\"", o, \ - sshkey_ssh_name(sensitive_data.keys[o]), p); \ + debug2("hostbased cert \"%s\" in slot %d", p, o); \ loaded++; \ } \ } while (0) @@ -2442,9 +2454,7 @@ load_public_identity_files(const struct ssh_conn_info *cinfo) continue; xasprintf(&cp, "%s-cert", filename); check_load(sshkey_load_public(cp, &public, NULL), - &public, filename, "pubkey"); - debug("identity file %s type %d", cp, - public ? public->type : -1); + &public, filename, "identity pubkey"); if (public == NULL) { free(cp); continue; @@ -2473,9 +2483,7 @@ load_public_identity_files(const struct ssh_conn_info *cinfo) free(cp); check_load(sshkey_load_public(filename, &public, NULL), - &public, filename, "certificate"); - debug("certificate file %s type %d", filename, - public ? public->type : -1); + &public, filename, "identity cert"); free(options.certificate_files[i]); options.certificate_files[i] = NULL; if (public == NULL) { From 688fa02728f2efbf18388bc1a8e94e7ba7ee4f11 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Tue, 24 Jun 2025 09:22:03 +0000 Subject: [PATCH 124/244] upstream: make "Match !final" not trigger a 2nd pass ssh_config parsing pass (unless hostname canonicalisation or a separate "Match final" does). bz3843 ok dtucker@ OpenBSD-Commit-ID: ce82b6034828888f0f3f1c812e08f5e87400d802 --- readconf.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/readconf.c b/readconf.c index a56cbe0da7d0..97f34abff108 100644 --- a/readconf.c +++ b/readconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.c,v 1.399 2025/05/06 05:40:56 djm Exp $ */ +/* $OpenBSD: readconf.c,v 1.400 2025/06/24 09:22:03 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -768,12 +768,13 @@ match_cfg_line(Options *options, const char *full_line, int *acp, char ***avp, if (strcasecmp(attrib, "canonical") == 0 || strcasecmp(attrib, "final") == 0) { /* - * If the config requests "Match final" then remember - * this so we can perform a second pass later. + * If the config requests "Match final" without + * negation then remember this so we can perform a + * second pass later. */ if (strcasecmp(attrib, "final") == 0 && want_final_pass != NULL) - *want_final_pass = 1; + *want_final_pass |= !negate; r = !!final_pass; /* force bitmask member to boolean */ if (r == (negate ? 1 : 0)) this_result = result = 0; From 57fb460165ae3b2d591f2468d7fe13cc1abda26d Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Tue, 17 Jun 2025 01:24:32 +0000 Subject: [PATCH 125/244] upstream: add RCS ID OpenBSD-Regress-ID: 6e30094e3bf0a1c65efb75c67a87093304a3e619 --- regress/misc/sk-dummy/sk-dummy.c | 1 + 1 file changed, 1 insertion(+) diff --git a/regress/misc/sk-dummy/sk-dummy.c b/regress/misc/sk-dummy/sk-dummy.c index 8a33d18695ed..afa0314da838 100644 --- a/regress/misc/sk-dummy/sk-dummy.c +++ b/regress/misc/sk-dummy/sk-dummy.c @@ -1,3 +1,4 @@ +/* $OpenBSD: sk-dummy.c,v 1.16 2025/06/17 01:24:32 djm Exp $ */ /* * Copyright (c) 2019 Markus Friedl * From 838d5ec4b12fb519ed9db76e5beccf11b7ee212f Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Tue, 24 Jun 2025 12:28:23 +0000 Subject: [PATCH 126/244] upstream: Add simple test for password auth. Requires some setup so does not run by default. OpenBSD-Regress-ID: d5ded47a266b031fc91f99882f07161ab6d1bb70 --- regress/Makefile | 3 ++- regress/password.sh | 59 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 regress/password.sh diff --git a/regress/Makefile b/regress/Makefile index d97ea34a2050..d0298d45e009 100644 --- a/regress/Makefile +++ b/regress/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.136 2025/03/11 07:50:20 dtucker Exp $ +# $OpenBSD: Makefile,v 1.138 2025/06/24 12:28:23 dtucker Exp $ tests: prep file-tests t-exec unit @@ -106,6 +106,7 @@ LTESTS= connect \ knownhosts-command \ agent-restrict \ hostbased \ + password \ channel-timeout \ connection-timeout \ match-subsystem \ diff --git a/regress/password.sh b/regress/password.sh new file mode 100644 index 000000000000..1c5218d6b1f4 --- /dev/null +++ b/regress/password.sh @@ -0,0 +1,59 @@ +# $OpenBSD: password.sh,v 1.1 2025/06/24 12:28:23 dtucker Exp $ +# Placed in the Public Domain. +# +# This tests standard "password" authentication. It does not run by default, +# and needs to be enabled by putting the password of the user running the tests +# into ${OBJ}/password. Since this obviously puts the password at risk it is +# recommended to do this on a throwaway VM by setting a random password +# (and randomizing it again after the test, if you can't immediately dispose +# of the VM). + +tid="password" + +if [ -z "$SUDO" -o ! -f ${OBJ}/password ]; then + skip "Password auth requires SUDO and password file." +fi + +# Enable password auth +echo "PasswordAuthentication yes" >>sshd_proxy + +# Create askpass script to replay a series of password responses. +# Keep a counter of the number of times it has been called and +# reply with the next line of the replypass file. +cat >${OBJ}/replypass.sh <${OBJ}/replypass.N +EOD +chmod 700 ${OBJ}/replypass.sh + +SSH_ASKPASS=${OBJ}/replypass.sh +SSH_ASKPASS_REQUIRE=force +export SSH_ASKPASS SSH_ASKPASS_REQUIRE + +opts="-oPasswordAuthentication=yes -oPreferredAuthentications=password" +opts="-oBatchMode=no $opts" + +trace plain password +cat ${OBJ}/password >${OBJ}/replypass +echo 1 >${OBJ}/replypass.N +${SSH} $opts -F $OBJ/ssh_proxy somehost true +if [ $? -ne 0 ]; then + fail "ssh password failed" +fi + +trace 2-round password +(echo; cat ${OBJ}/password) >${OBJ}/replypass +echo 1 >${OBJ}/replypass.N +${SSH} $opts -F $OBJ/ssh_proxy somehost true +if [ $? -ne 0 ]; then + fail "ssh 2-round password failed" +fi + +trace empty password +echo >${OBJ}/replypass +echo 1 >${OBJ}/replypass.N +${SSH} $opts -F $OBJ/ssh_proxy somehost true +if [ $? -eq 0 ]; then + fail "ssh password failed" +fi From bcfe7340d9b622ecd978c87dbf885c8b5a503ca2 Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Sat, 28 Jun 2025 13:34:08 +0000 Subject: [PATCH 127/244] upstream: Add simple regression test for dropbear as a server. OpenBSD-Regress-ID: 7abe1f6607d0cd49839918aade8f135d2462d389 --- regress/Makefile | 4 +-- regress/dropbear-server.sh | 62 ++++++++++++++++++++++++++++++++++++++ regress/test-exec.sh | 4 +-- 3 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 regress/dropbear-server.sh diff --git a/regress/Makefile b/regress/Makefile index d0298d45e009..b8787205a15f 100644 --- a/regress/Makefile +++ b/regress/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.138 2025/06/24 12:28:23 dtucker Exp $ +# $OpenBSD: Makefile,v 1.139 2025/06/28 13:34:08 dtucker Exp $ tests: prep file-tests t-exec unit @@ -116,7 +116,7 @@ LTESTS= connect \ penalty-expire INTEROP_TESTS= putty-transfer putty-ciphers putty-kex conch-ciphers -INTEROP_TESTS+= dropbear-ciphers dropbear-kex +INTEROP_TESTS+= dropbear-ciphers dropbear-kex dropbear-server #INTEROP_TESTS+=ssh-com ssh-com-client ssh-com-keygen ssh-com-sftp EXTRA_TESTS= agent-pkcs11 diff --git a/regress/dropbear-server.sh b/regress/dropbear-server.sh new file mode 100644 index 000000000000..d3ea6dcc5c12 --- /dev/null +++ b/regress/dropbear-server.sh @@ -0,0 +1,62 @@ +# $OpenBSD: dropbear-server.sh,v 1.1 2025/06/28 13:34:08 dtucker Exp $ +# Placed in the Public Domain. + +tid="dropbear server" + +if test "x$REGRESS_INTEROP_DROPBEAR" != "xyes" ; then + skip "dropbear interop tests not enabled" +fi + +if [ -z "$SUDO" -a ! -w /var/run ]; then + skip "need SUDO to create dir in /var/run, test won't work without" +fi +authkeydir=/var/run/dropbear-regress + +ciphers=`$DBCLIENT -c help hst 2>&1 | awk '/ ciphers: /{print $4}' | tr ',' ' '` +macs=`$DBCLIENT -m help hst 2>&1 | awk '/ MACs: /{print $4}' | tr ',' ' '` +if [ -z "$macs" ] || [ -z "$ciphers" ]; then + skip "dbclient query ciphers '$ciphers' or macs '$macs' failed" +fi + +# Set up authorized_keys for dropbear. +umask 077 +$SUDO mkdir -p $authkeydir +$SUDO chown -R $USER $authkeydir +cp $OBJ/authorized_keys_$USER $authkeydir/authorized_keys + +for i in `$SUDO $SSHD -f $OBJ/sshd_config -T | grep -v sk- | \ + awk '$1=="hostkey" {print $2}'`; do + file=`basename "$i"` + file=`echo "$file" | sed s/^host\./db\./g` + if $SUDO $DROPBEARCONVERT openssh dropbear "$i" "$OBJ/$file" \ + >/dev/null 2>&1; then + $SUDO chown $USER $OBJ/$file + hkeys="-r $OBJ/$file" + fi +done + +rm -f $OBJ/dropbear.pid +$DROPBEAR -D $authkeydir -p $PORT -P $OBJ/dropbear.pid $hkeys -E \ + 2>$OBJ/sshd.log +if [ $? -ne 0 ]; then + fatal "starting dropbear server failed" +fi +while [ ! -f $OBJ/dropbear.pid ]; do + sleep 1 +done + +pid=`cat $OBJ/dropbear.pid` +trap "kill $pid; $SUDO rm -rf $authkeydir" 0 + +for c in $ciphers; do + for m in $macs; do + trace "$tid: cipher $c mac $m hk $hk" + rm -f ${COPY} + ${SSH} -F $OBJ/ssh_config -oCiphers=$c -oMacs=$m \ + somehost cat ${DATA} > ${COPY} + if [ $? -ne 0 ]; then + fail "connect dropbear server failed" + fi + cmp ${DATA} ${COPY} || fail "corrupted copy" + done +done diff --git a/regress/test-exec.sh b/regress/test-exec.sh index d4d40c2ae893..0ecf6c5a83c0 100644 --- a/regress/test-exec.sh +++ b/regress/test-exec.sh @@ -1,4 +1,4 @@ -# $OpenBSD: test-exec.sh,v 1.129 2025/05/24 04:40:37 djm Exp $ +# $OpenBSD: test-exec.sh,v 1.130 2025/06/28 13:34:08 dtucker Exp $ # Placed in the Public Domain. #SUDO=sudo @@ -101,7 +101,7 @@ SSH_REGRESS_TMP= PLINK=/usr/local/bin/plink PUTTYGEN=/usr/local/bin/puttygen CONCH=/usr/local/bin/conch -DROPBEAR=/usr/local/bin/dropbear +DROPBEAR=/usr/local/sbin/dropbear DBCLIENT=/usr/local/bin/dbclient DROPBEARKEY=/usr/local/bin/dropbearkey DROPBEARCONVERT=/usr/local/bin/dropbearconvert From 8a9384de483b8fb69a800e0347273686a5715fc3 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Sun, 29 Jun 2025 11:14:18 +1000 Subject: [PATCH 128/244] Enable password tests on Github ephemeral VMs. --- .github/setup_ci.sh | 18 +++++++++++++----- .github/workflows/c-cpp.yml | 2 ++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/.github/setup_ci.sh b/.github/setup_ci.sh index 5e778d377136..598b0624a6d9 100755 --- a/.github/setup_ci.sh +++ b/.github/setup_ci.sh @@ -299,12 +299,20 @@ if [ ! -z "${INSTALL_PUTTY}" ]; then /usr/local/bin/plink -V fi -# This is the github "target" as specificed in the yml file. -case "${target}" in -ubuntu-latest) - echo ubuntu-latest target: setting random password string. +# If we're running on an ephemeral VM, set a random password and set +# up to run the password auth test. +if [ ! -z "${EPHEMERAL_VM}" ]; then + + # This is the github "target" as specified in the yml file. + # In particular, ubuntu-latest sets the password field to the locked + # value, so unless we reset it here most of the tests will fail. + case "${target}" in + ubuntu-*) + echo ${target} target: setting random password string. pw=$(openssl rand -base64 9) sudo usermod --password "${pw}" runner sudo usermod --unlock runner + echo "${pw}" > regress/password ;; -esac + esac +fi diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 7ee1796463f0..82087c057aef 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -121,6 +121,8 @@ jobs: - { target: macos-15, config: pam } runs-on: ${{ matrix.target }} steps: + - env: + EPHEMERAL_VM: yes - name: check RUN_ONLY_TARGET_CONFIG if: vars.RUN_ONLY_TARGET_CONFIG != '' run: sh -c 'if [ "${{ vars.RUN_ONLY_TARGET_CONFIG }}" != "${{ matrix.target }} ${{matrix.config }}" ]; then exit 1; else exit 0; fi' From d32614b448528ac08a65caac323a34b4f559a204 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Sun, 29 Jun 2025 11:22:00 +1000 Subject: [PATCH 129/244] Move env to where it (hopefully) belongs. --- .github/workflows/c-cpp.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 82087c057aef..385b2a94a123 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -120,9 +120,9 @@ jobs: - { target: macos-14, config: pam } - { target: macos-15, config: pam } runs-on: ${{ matrix.target }} + - env: + EPHEMERAL_VM: yes steps: - - env: - EPHEMERAL_VM: yes - name: check RUN_ONLY_TARGET_CONFIG if: vars.RUN_ONLY_TARGET_CONFIG != '' run: sh -c 'if [ "${{ vars.RUN_ONLY_TARGET_CONFIG }}" != "${{ matrix.target }} ${{matrix.config }}" ]; then exit 1; else exit 0; fi' From 223a1beac7b7be9252f69055781c9c15f4d8a607 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Sun, 29 Jun 2025 11:24:42 +1000 Subject: [PATCH 130/244] Move env again. --- .github/workflows/c-cpp.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 385b2a94a123..0ba00962b3c1 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -20,6 +20,8 @@ jobs: ci: name: "${{ matrix.target }} ${{ matrix.config }}" if: github.repository != 'openssh/openssh-portable-selfhosted' + env: + - EPHEMERAL_VM: yes strategy: fail-fast: false matrix: @@ -120,8 +122,6 @@ jobs: - { target: macos-14, config: pam } - { target: macos-15, config: pam } runs-on: ${{ matrix.target }} - - env: - EPHEMERAL_VM: yes steps: - name: check RUN_ONLY_TARGET_CONFIG if: vars.RUN_ONLY_TARGET_CONFIG != '' From 700205bd861c25cc7564010cf63d984d8db5098a Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Sun, 29 Jun 2025 11:27:17 +1000 Subject: [PATCH 131/244] Fix env again. --- .github/workflows/c-cpp.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 0ba00962b3c1..ccf6a7822dd4 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -20,8 +20,6 @@ jobs: ci: name: "${{ matrix.target }} ${{ matrix.config }}" if: github.repository != 'openssh/openssh-portable-selfhosted' - env: - - EPHEMERAL_VM: yes strategy: fail-fast: false matrix: @@ -122,6 +120,8 @@ jobs: - { target: macos-14, config: pam } - { target: macos-15, config: pam } runs-on: ${{ matrix.target }} + env: + EPHEMERAL_VM: yes steps: - name: check RUN_ONLY_TARGET_CONFIG if: vars.RUN_ONLY_TARGET_CONFIG != '' From 0b17d564cfae82f2a52e9b4d588657da47ea4e43 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Sun, 29 Jun 2025 14:34:48 +1000 Subject: [PATCH 132/244] Encrypt temporary password we're setting. Now that we want to actually use the random password for tests, we need to correctly encrypt it, instead of just setting it to a random string that's not the "locked" value. --- .github/setup_ci.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/setup_ci.sh b/.github/setup_ci.sh index 598b0624a6d9..8ed1d178325f 100755 --- a/.github/setup_ci.sh +++ b/.github/setup_ci.sh @@ -308,11 +308,11 @@ if [ ! -z "${EPHEMERAL_VM}" ]; then # value, so unless we reset it here most of the tests will fail. case "${target}" in ubuntu-*) - echo ${target} target: setting random password string. - pw=$(openssl rand -base64 9) + echo ${target} target: setting random password. + openssl rand -base64 9 >regress/password + pw=$(tr -d '\n' regress/password ;; esac fi From 83d3ffc0fc0f5e4473ab43f0d42a1cf9497ce0b5 Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Sun, 29 Jun 2025 05:35:00 +0000 Subject: [PATCH 133/244] upstream: Check dropbear server version for required features. Dropbear added the '-D' flag in version 2025.87. We need that for the dropbear-server test, so skip on older versions. OpenBSD-Regress-ID: 9db0b84edd54d3c00ab17db1dc6d62af4644c550 --- regress/dropbear-server.sh | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/regress/dropbear-server.sh b/regress/dropbear-server.sh index d3ea6dcc5c12..c72c86bfd39e 100644 --- a/regress/dropbear-server.sh +++ b/regress/dropbear-server.sh @@ -1,4 +1,4 @@ -# $OpenBSD: dropbear-server.sh,v 1.1 2025/06/28 13:34:08 dtucker Exp $ +# $OpenBSD: dropbear-server.sh,v 1.2 2025/06/29 05:35:00 dtucker Exp $ # Placed in the Public Domain. tid="dropbear server" @@ -7,6 +7,20 @@ if test "x$REGRESS_INTEROP_DROPBEAR" != "xyes" ; then skip "dropbear interop tests not enabled" fi +ver="`$DROPBEAR -V 2>&1 | sed 's/Dropbear v//'`" +if [ -z "$ver" ]; then + skip "can't determine dropbear version" +fi + +major=`echo $ver | cut -f1 -d.` +minor=`echo $ver | cut -f2 -d.` + +if [ "$major" -lt "2025" ] || [ "$minor" -lt "87" ]; then + skip "dropbear version $ver (${major}.${minor}) does not support '-D'" +else + trace "dropbear version $ver (${major}.${minor}) ok" +fi + if [ -z "$SUDO" -a ! -w /var/run ]; then skip "need SUDO to create dir in /var/run, test won't work without" fi From b28e91aff80fd24341de8cb3c34dc454d6b75228 Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Sun, 29 Jun 2025 08:20:21 +0000 Subject: [PATCH 134/244] upstream: Add shebang path to askpass script. Required for exec on some platforms (musl, probably others). OpenBSD-Regress-ID: 35cdeed12ae701afcb812f800c04d817325cd22a --- regress/password.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/regress/password.sh b/regress/password.sh index 1c5218d6b1f4..10f507e4472c 100644 --- a/regress/password.sh +++ b/regress/password.sh @@ -1,4 +1,4 @@ -# $OpenBSD: password.sh,v 1.1 2025/06/24 12:28:23 dtucker Exp $ +# $OpenBSD: password.sh,v 1.2 2025/06/29 08:20:21 dtucker Exp $ # Placed in the Public Domain. # # This tests standard "password" authentication. It does not run by default, @@ -21,6 +21,7 @@ echo "PasswordAuthentication yes" >>sshd_proxy # Keep a counter of the number of times it has been called and # reply with the next line of the replypass file. cat >${OBJ}/replypass.sh <${OBJ}/replypass.N From 29cf521486bf97ab9de5b9b356f812107e0671bc Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Wed, 2 Jul 2025 13:47:38 +1000 Subject: [PATCH 135/244] wrap some autoconf macros in AC_CACHE_CHECK This allows skipping/overriding the OSSH_CHECK_CFLAG_COMPILE and OSSH_CHECK_CFLAG_LINK macros used to discover supported compiler or linker flags. E.g. $ ./configure ossh_cv_cflag__fzero_call_used_regs_used=no [...] checking if cc supports compile flag -ftrapv and linking succeeds... yes checking if cc supports compile flag -fzero-call-used-regs=used and linking succeeds... (cached) no checking if cc supports compile flag -ftrivial-auto-var-init=zero... yes Patch from Colin Watson, ok dtucker@ --- m4/openssh.m4 | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/m4/openssh.m4 b/m4/openssh.m4 index 176a8d1c9282..f420146f1442 100644 --- a/m4/openssh.m4 +++ b/m4/openssh.m4 @@ -62,7 +62,8 @@ dnl Check that $CC accepts a flag 'check_flag'. If it is supported append dnl 'define_flag' to $CFLAGS. If 'define_flag' is not specified, then append dnl 'check_flag'. AC_DEFUN([OSSH_CHECK_CFLAG_COMPILE], [{ - AC_MSG_CHECKING([if $CC supports compile flag $1]) + ossh_cache_var=AS_TR_SH([ossh_cv_cflag_$1]) + AC_CACHE_CHECK([if $CC supports compile flag $1], [$ossh_cache_var], [ saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $WERROR $1" _define_flag="$2" @@ -71,22 +72,23 @@ AC_DEFUN([OSSH_CHECK_CFLAG_COMPILE], [{ [ if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null then - AC_MSG_RESULT([no]) + eval "$ossh_cache_var=no" CFLAGS="$saved_CFLAGS" else dnl If we are compiling natively, try running the program. AC_RUN_IFELSE([OSSH_COMPILER_FLAG_TEST_PROGRAM], - [ AC_MSG_RESULT([yes]) + [ eval "$ossh_cache_var=yes" CFLAGS="$saved_CFLAGS $_define_flag" ], - [ AC_MSG_RESULT([no, fails at run time]) + [ eval "$ossh_cache_var='no, fails at run time'" CFLAGS="$saved_CFLAGS" ], - [ AC_MSG_RESULT([yes]) + [ eval "$ossh_cache_var=yes" CFLAGS="$saved_CFLAGS $_define_flag" ], ) fi], - [ AC_MSG_RESULT([no]) + [ eval "$ossh_cache_var=no" CFLAGS="$saved_CFLAGS" ] ) + ]) }]) dnl OSSH_CHECK_CFLAG_LINK(check_flag[, define_flag]) @@ -94,7 +96,8 @@ dnl Check that $CC accepts a flag 'check_flag'. If it is supported append dnl 'define_flag' to $CFLAGS. If 'define_flag' is not specified, then append dnl 'check_flag'. AC_DEFUN([OSSH_CHECK_CFLAG_LINK], [{ - AC_MSG_CHECKING([if $CC supports compile flag $1 and linking succeeds]) + ossh_cache_var=AS_TR_SH([ossh_cv_cflag_$1]) + AC_CACHE_CHECK([if $CC supports compile flag $1 and linking succeeds], [$ossh_cache_var], [ saved_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $WERROR $1" _define_flag="$2" @@ -103,22 +106,23 @@ AC_DEFUN([OSSH_CHECK_CFLAG_LINK], [{ [ if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null then - AC_MSG_RESULT([no]) + eval "$ossh_cache_var=no" CFLAGS="$saved_CFLAGS" else dnl If we are compiling natively, try running the program. AC_RUN_IFELSE([OSSH_COMPILER_FLAG_TEST_PROGRAM], - [ AC_MSG_RESULT([yes]) + [ eval "$ossh_cache_var=yes" CFLAGS="$saved_CFLAGS $_define_flag" ], - [ AC_MSG_RESULT([no, fails at run time]) + [ eval "$ossh_cache_var='no, fails at run time'" CFLAGS="$saved_CFLAGS" ], - [ AC_MSG_RESULT([yes]) + [ eval "$ossh_cache_var=yes" CFLAGS="$saved_CFLAGS $_define_flag" ], ) fi], - [ AC_MSG_RESULT([no]) + [ eval "$ossh_cache_var=no" CFLAGS="$saved_CFLAGS" ] ) + ]) }]) dnl OSSH_CHECK_LDFLAG_LINK(check_flag[, define_flag]) @@ -126,7 +130,8 @@ dnl Check that $LD accepts a flag 'check_flag'. If it is supported append dnl 'define_flag' to $LDFLAGS. If 'define_flag' is not specified, then append dnl 'check_flag'. AC_DEFUN([OSSH_CHECK_LDFLAG_LINK], [{ - AC_MSG_CHECKING([if $LD supports link flag $1]) + ossh_cache_var=AS_TR_SH([ossh_cv_ldflag_$1]) + AC_CACHE_CHECK([if $LD supports link flag $1], [$ossh_cache_var], [ saved_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $WERROR $1" _define_flag="$2" @@ -135,22 +140,23 @@ AC_DEFUN([OSSH_CHECK_LDFLAG_LINK], [{ [ if $ac_cv_path_EGREP -i "unrecognized option|warning.*ignored" conftest.err >/dev/null then - AC_MSG_RESULT([no]) + eval "$ossh_cache_var=no" LDFLAGS="$saved_LDFLAGS" else dnl If we are compiling natively, try running the program. AC_RUN_IFELSE([OSSH_COMPILER_FLAG_TEST_PROGRAM], - [ AC_MSG_RESULT([yes]) + [ eval "$ossh_cache_var=yes" LDFLAGS="$saved_LDFLAGS $_define_flag" ], - [ AC_MSG_RESULT([no, fails at run time]) + [ eval "$ossh_cache_var='no, fails at run time'" LDFLAGS="$saved_LDFLAGS" ], - [ AC_MSG_RESULT([yes]) + [ eval "$ossh_cache_var=yes" LDFLAGS="$saved_LDFLAGS $_define_flag" ] ) fi ], - [ AC_MSG_RESULT([no]) + [ eval "$ossh_cache_var=no" LDFLAGS="$saved_LDFLAGS" ] ) + ]) }]) dnl OSSH_CHECK_HEADER_FOR_FIELD(field, header, symbol) From fd10cea0f16e928ae2b52fbeadccd475d0438eb4 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Fri, 4 Jul 2025 00:17:55 +0000 Subject: [PATCH 136/244] upstream: mux: fix incorrect return value check in local forward cancellation channel_cancel_lport_listener() returns 1 on success and 0 on failure. The previous code incorrectly checked for `== -1`, a value the function never returns, so failure was not detected and the "port not found" error message was never shown when cancelling dynamic or local port forwards. From: Boris Tonofa OpenBSD-Commit-ID: 3e9d2252a4d0bd318d4f25e2b518afb44acea170 --- mux.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mux.c b/mux.c index 415024f74e8f..1a4f357d46f0 100644 --- a/mux.c +++ b/mux.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mux.c,v 1.103 2024/10/12 10:50:37 jsg Exp $ */ +/* $OpenBSD: mux.c,v 1.104 2025/07/04 00:17:55 djm Exp $ */ /* * Copyright (c) 2002-2008 Damien Miller * @@ -931,7 +931,7 @@ mux_master_process_close_fwd(struct ssh *ssh, u_int rid, } else { /* local and dynamic forwards */ /* Ditto */ if (channel_cancel_lport_listener(ssh, &fwd, fwd.connect_port, - &options.fwd_opts) == -1) + &options.fwd_opts) != 1) error_reason = "port not found"; } From 0cf38d74463bcf80510e7fd1b3d9328e7d91eb00 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Fri, 4 Jul 2025 07:47:35 +0000 Subject: [PATCH 137/244] upstream: the messaging layer between sshd-session and sshd-auth had a maximum message size of 256KB. Some people apparently have configurations larger than this and would hit this limit. Worse, there was no good logging that could help diagnose what was going wrong. So this bumps the maximum message size to 4MB and implements an early check (usable via the sshd -t test mode) that will report it to the user where it is hopefully more visible. bz3808, reported by Dmitry Belyavskiy, ok dtucker@ OpenBSD-Commit-ID: 69c303fb68cbd1a4735936835d67a71e7b57f63b --- monitor_wrap.c | 6 +++--- monitor_wrap.h | 6 +++++- sshd.c | 11 ++++++++--- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/monitor_wrap.c b/monitor_wrap.c index c30a7902d386..fea576213993 100644 --- a/monitor_wrap.c +++ b/monitor_wrap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor_wrap.c,v 1.139 2025/05/05 02:40:30 djm Exp $ */ +/* $OpenBSD: monitor_wrap.c,v 1.140 2025/07/04 07:47:35 djm Exp $ */ /* * Copyright 2002 Niels Provos * Copyright 2002 Markus Friedl @@ -150,7 +150,7 @@ mm_request_send(int sock, enum monitor_reqtype type, struct sshbuf *m) debug3_f("entering, type %d", type); - if (mlen >= 0xffffffff) + if (mlen >= MONITOR_MAX_MSGLEN) fatal_f("bad length %zu", mlen); POKE_U32(buf, mlen + 1); buf[4] = (u_char) type; /* 1st byte of payload is mesg-type */ @@ -183,7 +183,7 @@ mm_request_receive(int sock, struct sshbuf *m) fatal_f("read: %s", strerror(errno)); } msg_len = PEEK_U32(buf); - if (msg_len > 256 * 1024) + if (msg_len > MONITOR_MAX_MSGLEN) fatal_f("read: bad msg_len %d", msg_len); sshbuf_reset(m); if ((r = sshbuf_reserve(m, msg_len, &p)) != 0) diff --git a/monitor_wrap.h b/monitor_wrap.h index 7134afeecf4e..c87295388fd0 100644 --- a/monitor_wrap.h +++ b/monitor_wrap.h @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor_wrap.h,v 1.51 2024/05/17 06:42:04 jsg Exp $ */ +/* $OpenBSD: monitor_wrap.h,v 1.53 2025/07/04 07:47:35 djm Exp $ */ /* * Copyright 2002 Niels Provos @@ -28,6 +28,10 @@ #ifndef _MM_WRAP_H_ #define _MM_WRAP_H_ +#define MONITOR_MAX_MSGLEN (4 * 1024 * 1024) +/* The configuration has to fit in a monitor message along with other state */ +#define MONITOR_MAX_CFGLEN (MONITOR_MAX_MSGLEN - (64 * 1024)) + enum mm_keytype { MM_NOKEY, MM_HOSTKEY, MM_USERKEY }; struct ssh; diff --git a/sshd.c b/sshd.c index 91608eff760c..5a4db309d23b 100644 --- a/sshd.c +++ b/sshd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd.c,v 1.619 2025/05/24 06:43:37 dtucker Exp $ */ +/* $OpenBSD: sshd.c,v 1.620 2025/07/04 07:47:35 djm Exp $ */ /* * Copyright (c) 2000, 2001, 2002 Markus Friedl. All rights reserved. * Copyright (c) 2002 Niels Provos. All rights reserved. @@ -94,6 +94,7 @@ #include "addr.h" #include "srclimit.h" #include "atomicio.h" +#include "monitor_wrap.h" /* Re-exec fds */ #define REEXEC_DEVCRYPTO_RESERVED_FD (STDERR_FILENO + 1) @@ -1753,6 +1754,12 @@ main(int ac, char **av) if (test_flag > 1) print_config(&connection_info); + config = pack_config(cfg); + if (sshbuf_len(config) > MONITOR_MAX_CFGLEN) { + fatal("Configuration file is too large (have %zu, max %d)", + sshbuf_len(config), MONITOR_MAX_CFGLEN); + } + /* Configuration looks good, so exit if in test mode. */ if (test_flag) exit(0); @@ -1830,8 +1837,6 @@ main(int ac, char **av) /* ignore SIGPIPE */ ssh_signal(SIGPIPE, SIG_IGN); - config = pack_config(cfg); - /* Get a connection, either from inetd or a listening TCP socket */ if (inetd_flag) { /* Send configuration to ancestor sshd-session process */ From 007b69f21cf9e64125b241d4411a5e47f5028aa8 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Fri, 4 Jul 2025 07:52:17 +0000 Subject: [PATCH 138/244] upstream: add a regress test for configurations > 256KB mostly by Dmitry Belyavskiy OpenBSD-Regress-ID: fcedb249e4cf2447e078a839877f99730ee79024 --- regress/Makefile | 5 +++-- regress/connect-bigconf.sh | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 regress/connect-bigconf.sh diff --git a/regress/Makefile b/regress/Makefile index b8787205a15f..ece093a2ba87 100644 --- a/regress/Makefile +++ b/regress/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.139 2025/06/28 13:34:08 dtucker Exp $ +# $OpenBSD: Makefile,v 1.140 2025/07/04 07:52:17 djm Exp $ tests: prep file-tests t-exec unit @@ -113,7 +113,8 @@ LTESTS= connect \ agent-pkcs11-restrict \ agent-pkcs11-cert \ penalty \ - penalty-expire + penalty-expire \ + connect-bigconf INTEROP_TESTS= putty-transfer putty-ciphers putty-kex conch-ciphers INTEROP_TESTS+= dropbear-ciphers dropbear-kex dropbear-server diff --git a/regress/connect-bigconf.sh b/regress/connect-bigconf.sh new file mode 100644 index 000000000000..56cf0ea649fc --- /dev/null +++ b/regress/connect-bigconf.sh @@ -0,0 +1,17 @@ +# $OpenBSD: connect-bigconf.sh,v 1.1 2025/07/04 07:52:17 djm Exp $ +# Placed in the Public Domain. + +tid="simple connect" + +for x in `jot 10000 1` ; do + echo "Match group NONEXIST" >> $OBJ/sshd_config + echo "ChrootDirectory /some/path/for/group/NONEXIST" >> $OBJ/sshd_config +done +#cat $OBJ/sshd_config +start_sshd + +trace "direct connect with large sshd_config" +${SSH} -F $OBJ/ssh_config somehost true +if [ $? -ne 0 ]; then + fail "ssh direct connect with large sshd_config failed" +fi From c971f3d93efe4c00d73b276cdbab66e7c66c9b5c Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Sat, 5 Jul 2025 20:50:50 +1000 Subject: [PATCH 139/244] Add include for gssapi definitions. Patch from dbelyavs at redhat.com via bz#3846. --- sshd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sshd.c b/sshd.c index 5a4db309d23b..b8345fca0fba 100644 --- a/sshd.c +++ b/sshd.c @@ -94,6 +94,9 @@ #include "addr.h" #include "srclimit.h" #include "atomicio.h" +#ifdef GSSAPI +#include "ssh-gss.h" +#endif #include "monitor_wrap.h" /* Re-exec fds */ From eddd1d2daa64a6ab1a915ca88436fa41aede44d4 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Fri, 4 Jul 2025 09:51:01 +0000 Subject: [PATCH 140/244] upstream: Fix mistracking of MaxStartups process exits in some situations. At worst, this can cause all MaxStartups slots to fill and sshd to refuse new connections. Diagnosis by xnor; ok dtucker@ OpenBSD-Commit-ID: 10273033055552557196730f898ed6308b36a78d --- sshd.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/sshd.c b/sshd.c index b8345fca0fba..6960193816f5 100644 --- a/sshd.c +++ b/sshd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd.c,v 1.620 2025/07/04 07:47:35 djm Exp $ */ +/* $OpenBSD: sshd.c,v 1.621 2025/07/04 09:51:01 djm Exp $ */ /* * Copyright (c) 2000, 2001, 2002 Markus Friedl. All rights reserved. * Copyright (c) 2002 Niels Provos. All rights reserved. @@ -293,8 +293,10 @@ child_finish(struct early_child *child) { if (children_active == 0) fatal_f("internal error: children_active underflow"); - if (child->pipefd != -1) + if (child->pipefd != -1) { + srclimit_done(child->pipefd); close(child->pipefd); + } sshbuf_free(child->config); sshbuf_free(child->keys); free(child->id); @@ -315,6 +317,7 @@ child_close(struct early_child *child, int force_final, int quiet) if (!quiet) debug_f("enter%s", force_final ? " (forcing)" : ""); if (child->pipefd != -1) { + srclimit_done(child->pipefd); close(child->pipefd); child->pipefd = -1; } @@ -1043,7 +1046,6 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s, if (ret <= 0) { if (children[i].early) listening--; - srclimit_done(children[i].pipefd); child_close(&(children[i]), 0, 0); continue; } @@ -1082,23 +1084,19 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s, } /* FALLTHROUGH */ case 0: - /* child exited preauth */ + /* child closed pipe */ if (children[i].early) listening--; - srclimit_done(children[i].pipefd); + debug3_f("child %lu for %s closed pipe", + (long)children[i].pid, children[i].id); child_close(&(children[i]), 0, 0); break; case 1: if (children[i].config) { error_f("startup pipe %d (fd=%d)" - " early read", i, children[i].pipefd); - if (children[i].early) - listening--; - if (children[i].pid > 0) - kill(children[i].pid, SIGTERM); - srclimit_done(children[i].pipefd); - child_close(&(children[i]), 0, 0); - break; + " early read", + i, children[i].pipefd); + goto problem_child; } if (children[i].early && c == '\0') { /* child has finished preliminaries */ @@ -1118,6 +1116,12 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s, "child %ld for %s in state %d", (int)c, (long)children[i].pid, children[i].id, children[i].early); + problem_child: + if (children[i].early) + listening--; + if (children[i].pid > 0) + kill(children[i].pid, SIGTERM); + child_close(&(children[i]), 0, 0); } break; } From 1052fa62b35e0bb25b0c1efb9fdd7870e4a68ab6 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Fri, 11 Jul 2025 15:36:49 -0700 Subject: [PATCH 141/244] more diagnostics when getgrouplist fails --- groupaccess.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/groupaccess.c b/groupaccess.c index 9d03ded0cd5d..b85782472b85 100644 --- a/groupaccess.c +++ b/groupaccess.c @@ -50,21 +50,24 @@ int ga_init(const char *user, gid_t base) { gid_t *groups_bygid; - int i, j, retry = 0; + int ongroups, i, j, retry = 0; struct group *gr; if (ngroups > 0) ga_free(); - ngroups = NGROUPS_MAX; + ongroups = ngroups = NGROUPS_MAX; #if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX) - ngroups = MAX(NGROUPS_MAX, sysconf(_SC_NGROUPS_MAX)); + ongroups = ngroups = MAX(NGROUPS_MAX, sysconf(_SC_NGROUPS_MAX)); #endif groups_bygid = xcalloc(ngroups, sizeof(*groups_bygid)); while (getgrouplist(user, base, groups_bygid, &ngroups) == -1) { - if (retry++ > 0) - fatal("getgrouplist: groups list too small"); + if (retry++ > 0) { + fatal("getgrouplist(\"%s\", %ld): groups list too big " + "(have %ld, need %ld)", user, (long)base, + (long)ongroups, (long)ngroups); + } groups_bygid = xreallocarray(groups_bygid, ngroups, sizeof(*groups_bygid)); } From f01a899b92ab8c5e6ff71214658bd09636c47e87 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Fri, 11 Jul 2025 23:26:59 +0000 Subject: [PATCH 142/244] upstream: add a "Match Group NoSuchGroup" to exercise groupaccess.c OpenBSD-Regress-ID: 7ff58e6f0eb21eb9064dd0cfa78c3b6f34b5f713 --- regress/cfgmatch.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/regress/cfgmatch.sh b/regress/cfgmatch.sh index 2737a5f977ef..8b9d80f0a239 100644 --- a/regress/cfgmatch.sh +++ b/regress/cfgmatch.sh @@ -1,4 +1,4 @@ -# $OpenBSD: cfgmatch.sh,v 1.14 2024/09/27 01:05:54 djm Exp $ +# $OpenBSD: cfgmatch.sh,v 1.15 2025/07/11 23:26:59 djm Exp $ # Placed in the Public Domain. tid="sshd_config match" @@ -106,6 +106,8 @@ cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy echo "PermitOpen 127.0.0.1:1 127.0.0.1:$PORT 127.0.0.2:2" >>$OBJ/sshd_proxy echo "Match User NoSuchUser" >>$OBJ/sshd_proxy echo "PermitOpen 127.0.0.1:1 127.0.0.1:2" >>$OBJ/sshd_proxy +echo "Match Group NoSuchGroup" >>$OBJ/sshd_proxy +echo "PermitOpen 127.0.0.1:1 127.0.0.1:2" >>$OBJ/sshd_proxy # Test that a rule that doesn't match doesn't override, plus test a # PermitOpen entry that's not at the start of the list From f9dc519259804702cab0fa0ca8b193a360e3ec38 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Fri, 11 Jul 2025 17:20:27 -0700 Subject: [PATCH 143/244] let ga_init() fail gracefully if getgrouplist does Apparently getgrouplist() can fail on OSX for when passed a non-existent group name. Other platforms seem to return a group list consisting of the numeric gid passed to the function. This makes ga_init() handle this failure case gracefully, where it will return success but with an empty group list array. bz3848; ok dtucker@ --- groupaccess.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/groupaccess.c b/groupaccess.c index b85782472b85..046d0e6bcaf9 100644 --- a/groupaccess.c +++ b/groupaccess.c @@ -63,6 +63,14 @@ ga_init(const char *user, gid_t base) groups_bygid = xcalloc(ngroups, sizeof(*groups_bygid)); while (getgrouplist(user, base, groups_bygid, &ngroups) == -1) { + if (ngroups <= ongroups) { + error("getgrouplist(\"%s\", %ld): failed", + user, (long)base); + free(groups_bygid); + groups_bygid = NULL; + ngroups = 0; + return 0; + } if (retry++ > 0) { fatal("getgrouplist(\"%s\", %ld): groups list too big " "(have %ld, need %ld)", user, (long)base, From e6805e2a6b33e001e1a7257b85ab779fd592a578 Mon Sep 17 00:00:00 2001 From: Jan Tojnar Date: Thu, 18 May 2023 16:30:35 +0200 Subject: [PATCH 144/244] Add gnome-ssh-askpass4 for GNOME 40+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GTK 3 has been in maintenance mode for a while now, and it is on the road to being abandoned. As a result, the dialogue looks out of place on modern systems. We could port it to GTK 4 but without the program being registered as an application (i.e. having a .desktop file), GNOME Shell would ask for permission to grab input every time. Let’s instead use the GNOME Shell’s native prompt through the unstable Gcr API. --- contrib/Makefile | 7 +- contrib/README | 8 +- contrib/gnome-ssh-askpass4.c | 249 +++++++++++++++++++++++++++++++++++ 3 files changed, 260 insertions(+), 4 deletions(-) create mode 100644 contrib/gnome-ssh-askpass4.c diff --git a/contrib/Makefile b/contrib/Makefile index 45d878bdcf22..1482783a8097 100644 --- a/contrib/Makefile +++ b/contrib/Makefile @@ -1,7 +1,7 @@ PKG_CONFIG = pkg-config all: - @echo "Valid targets: gnome-ssh-askpass1 gnome-ssh-askpass2 gnome-ssk-askpass3" + @echo "Valid targets: gnome-ssh-askpass1 gnome-ssh-askpass2 gnome-ssk-askpass3 gnome-ssh-askpass4" gnome-ssh-askpass1: gnome-ssh-askpass1.c $(CC) $(CFLAGS) `gnome-config --cflags gnome gnomeui` \ @@ -18,5 +18,10 @@ gnome-ssh-askpass3: gnome-ssh-askpass3.c gnome-ssh-askpass3.c -o gnome-ssh-askpass3 \ `$(PKG_CONFIG) --libs gtk+-3.0 x11` +gnome-ssh-askpass4: gnome-ssh-askpass4.c + $(CC) $(CFLAGS) `$(PKG_CONFIG) --cflags gcr-4 gio-2.0` \ + gnome-ssh-askpass4.c -o gnome-ssh-askpass4 \ + `$(PKG_CONFIG) --libs gcr-4 gio-2.0` + clean: rm -f *.o gnome-ssh-askpass gnome-ssh-askpass[123] diff --git a/contrib/README b/contrib/README index 60e19ba9faa8..614152a123aa 100644 --- a/contrib/README +++ b/contrib/README @@ -30,10 +30,12 @@ ssh-copy-id: Phil Hands' shell script to automate the process of adding your public key to a remote machine's ~/.ssh/authorized_keys file. -gnome-ssh-askpass[12]: +gnome-ssh-askpass[1234]: -A GNOME and Gtk2 passphrase requesters. Use "make gnome-ssh-askpass1" or -"make gnome-ssh-askpass2" to build. +Graphical passhrase requesters. Use "make gnome-ssh-askpass1" to build +a variant for ancient GNOME desktop, "make gnome-ssh-askpass2" +for a GTK 2-based one, "make gnome-ssh-askpass3" for a GTK 3-based one, +or "make gnome-ssh-askpass4" for a version for modern GNOME. sshd.pam.generic: diff --git a/contrib/gnome-ssh-askpass4.c b/contrib/gnome-ssh-askpass4.c new file mode 100644 index 000000000000..182bce0cc63b --- /dev/null +++ b/contrib/gnome-ssh-askpass4.c @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2000-2002 Damien Miller. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* GCR support by Jan Tojnar */ + +/* + * This is a simple SSH passphrase grabber for GNOME. To use it, set the + * environment variable SSH_ASKPASS to point to the location of + * gnome-ssh-askpass before calling "ssh-add < /dev/null". + */ + +/* + * Known problems: + * - This depends on unstable libgcr features + * - long key fingerprints may be truncted: + * https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/6781 + */ + +/* + * Compile with: + * + * cc -Wall `pkg-config --cflags gcr-4 gio-2.0` \ + * gnome-ssh-askpass4.c -o gnome-ssh-askpass \ + * `pkg-config --libs gcr-4 gio-2.0` + * + */ + +#include +#include + +#include + +#define GCR_API_SUBJECT_TO_CHANGE 1 +#include + +typedef enum _PromptType { + PROMPT_ENTRY, + PROMPT_CONFIRM, + PROMPT_NONE, +} PromptType; + +typedef struct _PromptState { + GApplication *app; + char* message; + PromptType type; + int exit_status; +} PromptState; + +static PromptState * +prompt_state_new(GApplication *app, char* message, PromptType type) +{ + PromptState *state = g_malloc(sizeof(PromptState)); + state->app = g_object_ref(app); + state->message = g_strdup(message); + state->type = type; + state->exit_status = -1; + return state; +} + +static void +prompt_state_free(PromptState *state) +{ + g_clear_object(&state->app); + g_free(state->message); + g_free(state); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(PromptState, prompt_state_free) + +static void +prompt_password_done(GObject *source_object, GAsyncResult *res, + gpointer user_data) +{ + GcrPrompt *prompt = GCR_PROMPT(source_object); + PromptState *state = user_data; + g_autoptr(GError) error = NULL; + + /* + * “The returned password is valid until the next time a method + * is called to display another prompt.” + */ + const char *pw = gcr_prompt_password_finish(prompt, res, &error); + + if ((!pw && !error) || (error && error->code == G_IO_ERROR_CANCELLED)) { + /* Operation was cancelled or timed out. */ + state->exit_status = -1; + } else if (error) { + warnx("Failed to prompt for ssh-askpass: %s", error->message); + state->exit_status = 1; + } else { + /* Report passphrase if user selected Continue. */ + g_autofree char *local = g_locale_from_utf8(pw, strlen(pw), + NULL, NULL, NULL); + + if (local != NULL) { + puts(local); + memset(local, '\0', strlen(local)); + } else { + puts(pw); + } + state->exit_status = 0; + } + + g_application_release(state->app); +} + +static void +prompt_confirm_done(GObject *source_object, GAsyncResult *res, + gpointer user_data) +{ + GcrPrompt *prompt = GCR_PROMPT(source_object); + PromptState *state = user_data; + g_autoptr(GError) error = NULL; + + GcrPromptReply reply = gcr_prompt_confirm_finish(prompt, res, &error); + if (error) { + if (error->code == G_IO_ERROR_CANCELLED) { + /* Operation was cancelled or timed out. */ + state->exit_status = -1; + } else { + state->exit_status = 1; + warnx("Failed to prompt for ssh-askpass: %s", + error->message); + } + } else if (reply == GCR_PROMPT_REPLY_CONTINUE || + state->type == PROMPT_NONE) { + /* + * Since Gcr doesn’t yet support one button message + * boxes treat Cancel the same as Continue. + */ + state->exit_status = 0; + } else { + /* GCR_PROMPT_REPLY_CANCEL */ + state->exit_status = -1; + } + + g_application_release(state->app); +} + +static int +command_line(GApplication* app, G_GNUC_UNUSED GApplicationCommandLine *cmdline, + gpointer user_data) +{ + PromptState *state = user_data; + + /* Prevent app from exiting while waiting for the async callback. */ + g_application_hold(app); + + /* Wait indefinitely. */ + int timeout_seconds = -1; + g_autoptr(GError) error = NULL; + GcrPrompt* prompt = gcr_system_prompt_open(timeout_seconds, NULL, &error); + + if (!prompt) { + if (error->code == GCR_SYSTEM_PROMPT_IN_PROGRESS) { + /* + * This means the timeout elapsed, but no prompt + * was ever shown. + */ + warnx("Timeout: the Gcr system prompter was " + "already in use."); + } else { + warnx("Couldn’t create prompt for ssh-askpass: %s", + error->message); + } + + return 1; + } + + gcr_prompt_set_message(prompt, "OpenSSH"); + gcr_prompt_set_description(prompt, state->message); + + /* + * XXX: Remove the Cancel button for PROMPT_NONE when GCR + * supports that. + */ + if (state->type == PROMPT_ENTRY) { + gcr_prompt_password_async(prompt, NULL, prompt_password_done, state); + } else { + gcr_prompt_confirm_async(prompt, NULL, prompt_confirm_done, state); + } + + /* The exit status will be changed in the async callbacks. */ + return 1; +} + +int +main(int argc, char **argv) +{ + g_autoptr(GApplication) app = g_application_new( + "com.openssh.gnome-ssh-askpass4", + G_APPLICATION_HANDLES_COMMAND_LINE); + g_autofree char *message = NULL; + + if (argc > 1) { + message = g_strjoinv(" ", argv + 1); + } else { + message = g_strdup("Enter your OpenSSH passphrase:"); + } + + const char *prompt_mode = getenv("SSH_ASKPASS_PROMPT"); + PromptType type = PROMPT_ENTRY; + if (prompt_mode != NULL) { + if (strcasecmp(prompt_mode, "confirm") == 0) { + type = PROMPT_CONFIRM; + } else if (strcasecmp(prompt_mode, "none") == 0) { + type = PROMPT_NONE; + } + } + + g_autoptr(PromptState) state = prompt_state_new(app, message, type); + + g_signal_connect(app, "command-line", G_CALLBACK(command_line), state); + + /* + * Since we are calling g_application_hold, we cannot use + * g_application_command_line_set_exit_status. + * To change the exit status returned by g_application_run: + * “If the commandline invocation results in the mainloop running + * (ie: because the use-count of the application increased to a + * non-zero value) then the application is considered to have been + * ‘successful’ in a certain sense, and the exit status is always + * zero.” + */ + (void)(g_application_run(app, argc, argv)); + + return state->exit_status; +} From defc806574d2256036d69a291caf0f3484844de6 Mon Sep 17 00:00:00 2001 From: "miod@openbsd.org" Date: Sat, 12 Jul 2025 05:28:33 +0000 Subject: [PATCH 145/244] upstream: Add missing inter-library dependencies to LDADD and DPADD. ok tb@ deraadt@ OpenBSD-Commit-ID: a05e13a7e2c0b65bb4b47184fef731243431c6ff --- .skipped-commit-ids | 1 + 1 file changed, 1 insertion(+) diff --git a/.skipped-commit-ids b/.skipped-commit-ids index 2ccd3a6626fa..46271b34a830 100644 --- a/.skipped-commit-ids +++ b/.skipped-commit-ids @@ -44,6 +44,7 @@ a959fc45ea3431b36f52eda04faefc58bcde00db groupaccess.c changes c7246a6b519ac390ca550719f91acfdaef1fa0f0 Makefile relink change ef7ecdb6dd2542f42fa7236d17ac0b144851f0b5 ssh-keygen, fixup'ed into 21682417 da414a364c25b187fc686da7aacec2c35d29238a ssh-keygen, fixup'ed into 21682417 +a05e13a7e2c0b65bb4b47184fef731243431c6ff Makefile.inc Old upstream tree: From 40fb2dc4ece76c8f0c624d90a17bc1bbf47f3729 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Wed, 23 Jul 2025 05:07:19 +0000 Subject: [PATCH 146/244] upstream: add a ssh_config RefuseConnection option that, when encountered while processing an active section in a configuration file, terminates ssh(1) with an error message that contains the argument to the option. This may be useful for expressing reminders or warnings in config files, for example: Match host foo RefuseConnection "foo is deprecated, use splork instead" ok djg OpenBSD-Commit-ID: 5b0072fcd08ad3932ab21e27bbaa66b008d44237 --- readconf.c | 18 ++++++++++++++++-- ssh_config.5 | 13 +++++++++++-- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/readconf.c b/readconf.c index 97f34abff108..b5a9f925fc4a 100644 --- a/readconf.c +++ b/readconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.c,v 1.400 2025/06/24 09:22:03 djm Exp $ */ +/* $OpenBSD: readconf.c,v 1.401 2025/07/23 05:07:19 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -180,7 +180,7 @@ typedef enum { oPubkeyAcceptedAlgorithms, oCASignatureAlgorithms, oProxyJump, oSecurityKeyProvider, oKnownHostsCommand, oRequiredRSASize, oEnableEscapeCommandline, oObscureKeystrokeTiming, oChannelTimeout, - oVersionAddendum, + oVersionAddendum, oRefuseConnection, oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported } OpCodes; @@ -332,6 +332,7 @@ static struct { { "obscurekeystroketiming", oObscureKeystrokeTiming }, { "channeltimeout", oChannelTimeout }, { "versionaddendum", oVersionAddendum }, + { "refuseconnection", oRefuseConnection }, { NULL, oBadOption } }; @@ -2509,6 +2510,19 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host, argv_consume(&ac); break; + case oRefuseConnection: + arg = argv_next(&ac, &av); + if (!arg || *arg == '\0') { + error("%.200s line %d: Missing argument.", + filename, linenum); + goto out; + } + if (*activep) { + fatal("%.200s line %d: RefuseConnection: %s", + filename, linenum, arg); + } + break; + case oDeprecated: debug("%s line %d: Deprecated option \"%s\"", filename, linenum, keyword); diff --git a/ssh_config.5 b/ssh_config.5 index 894d738310c8..14115fff1e1e 100644 --- a/ssh_config.5 +++ b/ssh_config.5 @@ -33,8 +33,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh_config.5,v 1.413 2025/03/03 06:53:09 dtucker Exp $ -.Dd $Mdocdate: March 3 2025 $ +.\" $OpenBSD: ssh_config.5,v 1.414 2025/07/23 05:07:19 djm Exp $ +.Dd $Mdocdate: July 23 2025 $ .Dt SSH_CONFIG 5 .Os .Sh NAME @@ -1715,6 +1715,15 @@ disabling or enabling the OpenSSH host-bound authentication protocol extension required for restricted .Xr ssh-agent 1 forwarding. +.It Cm RefuseConnection +Allows a connection to be refused by the configuration file. +If this option is specified, then +.Xr ssh 1 +will terminate immediately before attempting to connect to the remote +host, display an error message that contains the argument to this keyword +and return a non-zero exit status. +This option may be useful to express reminders or warnings to the user via +.Nm . .It Cm RekeyLimit Specifies the maximum amount of data that may be transmitted or received before the session key is renegotiated, optionally followed by a maximum From 259c66aebe4e1f9d60e548f728ff74083bcccddf Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Thu, 24 Jul 2025 22:02:49 +1000 Subject: [PATCH 147/244] Remove DEBUG_ACTIONS variable. If needed it can be set in github if needed. --- .github/workflows/selfhosted.yml | 1 - .github/workflows/upstream.yml | 1 - 2 files changed, 2 deletions(-) diff --git a/.github/workflows/selfhosted.yml b/.github/workflows/selfhosted.yml index 2f425fe2f39c..281b2fc84dee 100644 --- a/.github/workflows/selfhosted.yml +++ b/.github/workflows/selfhosted.yml @@ -11,7 +11,6 @@ jobs: runs-on: ${{ matrix.host }} timeout-minutes: 600 env: - DEBUG_ACTIONS: false HOST: ${{ matrix.host }} TARGET_HOST: ${{ matrix.target }} TARGET_CONFIG: ${{ matrix.config }} diff --git a/.github/workflows/upstream.yml b/.github/workflows/upstream.yml index 9e74f94a74d1..e9e431373a39 100644 --- a/.github/workflows/upstream.yml +++ b/.github/workflows/upstream.yml @@ -11,7 +11,6 @@ jobs: if: github.repository == 'openssh/openssh-portable-selfhosted' runs-on: ${{ matrix.host }} env: - DEBUG_ACTIONS: true EPHEMERAL: true HOST: ${{ matrix.host }} TARGET_HOST: ${{ matrix.target }} From a8c0e5c871c0c7ee5ae93e353b1499a53c09c71d Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Thu, 24 Jul 2025 05:44:55 +0000 Subject: [PATCH 148/244] upstream: Help OpenSSH's PKCS#11 support kick its meth habit. The PKCS#11 code in OpenSSH used the libcrypto public key method API (e.g. the delightfully named RSA_meth_free()) to delegate signing operations to external keys. This had one advantage - that it was basically transparent to callers, but also had a big disadvantage - that we'd manually have to track the method implementations, their state and their relationships to the underlying PKCS#11 objects. This rips this out and replaces it with explicit delegation to PKCS#11 code for externally hosted keys via the ssh-pkcs11-helper subprocess. This is very similar to how we handle FIDO keys in OpenSSH (i.e. via ssh-sk-helper). All we need to track now is a much simpler mapping of public key -> helper subprocess. Kicking our libcrypto meth dependency also makes it much easier to support Ed25519 keys in PKCS#11, which will happen in a subsequent commit. feedback / ok tb@ OpenBSD-Commit-ID: a5a1eaf57971cf15e0cdc5a513e313541c8a35f0 --- .depend | 10 +- Makefile.in | 22 +- ssh-ecdsa.c | 35 ++- ssh-pkcs11-client.c | 510 +++++++++++------------------------- ssh-pkcs11-helper.c | 215 ++++------------ ssh-pkcs11.c | 615 ++++++++++++++++++++++++++++---------------- ssh-pkcs11.h | 12 +- ssh-rsa.c | 46 +++- ssh-sk-helper.c | 19 +- sshbuf-misc.c | 16 +- sshbuf.h | 11 +- sshkey.c | 29 ++- sshkey.h | 9 +- 13 files changed, 754 insertions(+), 795 deletions(-) diff --git a/.depend b/.depend index 3e64eb84a6a5..f569b603d450 100644 --- a/.depend +++ b/.depend @@ -138,12 +138,12 @@ ssh-keygen.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-co ssh-keyscan.o: dispatch.h log.h ssherr.h atomicio.h misc.h hostfile.h ssh_api.h ssh2.h dns.h addr.h ssh-keyscan.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/sys-queue.h xmalloc.h ssh.h sshbuf.h sshkey.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h digest.h kex.h mac.h crypto_api.h compat.h myproposal.h packet.h ssh-keysign.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h log.h ssherr.h sshkey.h ssh.h ssh2.h misc.h sshbuf.h authfile.h msg.h canohost.h pathnames.h readconf.h uidswap.h -ssh-pkcs11-client.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h -ssh-pkcs11-helper.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/sys-queue.h xmalloc.h sshbuf.h log.h ssherr.h misc.h sshkey.h authfd.h ssh-pkcs11.h +ssh-pkcs11-client.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h pathnames.h xmalloc.h sshbuf.h log.h ssherr.h misc.h sshkey.h authfd.h atomicio.h ssh-pkcs11.h +ssh-pkcs11-helper.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h sshbuf.h log.h ssherr.h misc.h sshkey.h authfd.h ssh-pkcs11.h ssh-pkcs11.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h log.h ssherr.h sshkey.h ssh-rsa.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ssh-sk-client.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h log.h ssherr.h sshbuf.h sshkey.h msg.h digest.h pathnames.h ssh-sk.h misc.h -ssh-sk-helper.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h log.h ssherr.h sshkey.h authfd.h misc.h sshbuf.h msg.h uidswap.h ssh-sk.h +ssh-sk-helper.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h log.h ssherr.h sshkey.h authfd.h misc.h sshbuf.h msg.h uidswap.h ssh-sk.h ssh-pkcs11.h ssh-sk.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ssh-xmss.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ssh.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/openssl-compat.h openbsd-compat/sys-queue.h xmalloc.h ssh.h ssh2.h canohost.h compat.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h packet.h dispatch.h sshbuf.h channels.h @@ -163,11 +163,11 @@ sshd-auth.o: chacha.h poly1305.h cipher-aesctr.h rijndael.h digest.h sshkey.h ke sshd-auth.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ./openbsd-compat/sys-tree.h openbsd-compat/sys-queue.h xmalloc.h ssh.h ssh2.h sshpty.h packet.h dispatch.h log.h ssherr.h sshbuf.h misc.h match.h servconf.h uidswap.h compat.h cipher.h cipher-chachapoly.h sshd-session.o: chacha.h poly1305.h cipher-aesctr.h rijndael.h digest.h sshkey.h kex.h mac.h crypto_api.h authfile.h pathnames.h atomicio.h canohost.h hostfile.h auth.h auth-pam.h audit.h loginrec.h authfd.h msg.h channels.h session.h monitor.h monitor_wrap.h auth-options.h version.h sk-api.h srclimit.h dh.h sshd-session.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ./openbsd-compat/sys-tree.h openbsd-compat/sys-queue.h xmalloc.h ssh.h ssh2.h sshpty.h packet.h dispatch.h log.h ssherr.h sshbuf.h misc.h match.h servconf.h uidswap.h compat.h cipher.h cipher-chachapoly.h -sshd.o: audit.h loginrec.h authfd.h msg.h version.h sk-api.h addr.h srclimit.h atomicio.h +sshd.o: audit.h loginrec.h authfd.h msg.h version.h sk-api.h addr.h srclimit.h atomicio.h monitor_wrap.h sshd.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ./openbsd-compat/sys-tree.h openbsd-compat/sys-queue.h xmalloc.h ssh.h sshpty.h log.h ssherr.h sshbuf.h misc.h servconf.h compat.h digest.h sshkey.h authfile.h pathnames.h canohost.h hostfile.h auth.h auth-pam.h ssherr.o: ssherr.h sshkey-xmss.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h -sshkey.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h crypto_api.h ssh2.h ssherr.h misc.h sshbuf.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h digest.h sshkey.h match.h ssh-sk.h openbsd-compat/openssl-compat.h +sshkey.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h crypto_api.h ssh2.h ssherr.h misc.h sshbuf.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h digest.h sshkey.h match.h ssh-sk.h ssh-pkcs11.h openbsd-compat/openssl-compat.h sshlogin.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h sshlogin.h ssherr.h loginrec.h log.h sshbuf.h misc.h servconf.h openbsd-compat/sys-queue.h sshpty.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h sshpty.h log.h ssherr.h misc.h sshsig.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h authfd.h authfile.h log.h ssherr.h misc.h sshbuf.h sshsig.h sshkey.h match.h digest.h diff --git a/Makefile.in b/Makefile.in index eb6f08e4df9b..399c8ae6ec56 100644 --- a/Makefile.in +++ b/Makefile.in @@ -108,7 +108,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ monitor_fdpass.o rijndael.o ssh-ecdsa.o ssh-ecdsa-sk.o \ ssh-ed25519-sk.o ssh-rsa.o dh.o \ msg.o dns.o entropy.o gss-genr.o umac.o umac128.o \ - ssh-pkcs11.o smult_curve25519_ref.o \ + smult_curve25519_ref.o \ poly1305.o chacha.o cipher-chachapoly.o cipher-chachapoly-libcrypto.o \ ssh-ed25519.o digest-openssl.o digest-libc.o \ hmac.o ed25519.o hash.o \ @@ -118,16 +118,18 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ sftp-realpath.o platform-pledge.o platform-tracing.o platform-misc.o \ sshbuf-io.o misc-agent.o +P11OBJS= ssh-pkcs11-client.o + SKOBJS= ssh-sk-client.o SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ - sshconnect.o sshconnect2.o mux.o $(SKOBJS) + sshconnect.o sshconnect2.o mux.o $(P11OBJS) $(SKOBJS) SSHDOBJS=sshd.o \ platform-listen.o \ servconf.o sshpty.o srclimit.o groupaccess.o auth2-methods.o \ dns.o fatal.o compat.o utf8.o authfd.o canohost.o \ - $(SKOBJS) + $(P11OBJS) $(SKOBJS) SSHD_SESSION_OBJS=sshd-session.o auth-rhosts.o auth-passwd.o \ audit.o audit-bsm.o audit-linux.o platform.o \ @@ -140,7 +142,7 @@ SSHD_SESSION_OBJS=sshd-session.o auth-rhosts.o auth-passwd.o \ auth2-gss.o gss-serv.o gss-serv-krb5.o \ loginrec.o auth-pam.o auth-shadow.o auth-sia.o \ sftp-server.o sftp-common.o \ - uidswap.o platform-listen.o $(SKOBJS) + uidswap.o platform-listen.o $(P11OBJS) $(SKOBJS) SSHD_AUTH_OBJS=sshd-auth.o \ auth2-methods.o \ @@ -155,25 +157,25 @@ SSHD_AUTH_OBJS=sshd-auth.o \ sandbox-null.o sandbox-rlimit.o sandbox-darwin.o \ sandbox-seccomp-filter.o sandbox-capsicum.o sandbox-solaris.o \ sftp-server.o sftp-common.o \ - uidswap.o $(SKOBJS) + uidswap.o $(P11OBJS) $(SKOBJS) SFTP_CLIENT_OBJS=sftp-common.o sftp-client.o sftp-glob.o SCP_OBJS= scp.o progressmeter.o $(SFTP_CLIENT_OBJS) -SSHADD_OBJS= ssh-add.o $(SKOBJS) +SSHADD_OBJS= ssh-add.o $(P11OBJS) $(SKOBJS) -SSHAGENT_OBJS= ssh-agent.o ssh-pkcs11-client.o $(SKOBJS) +SSHAGENT_OBJS= ssh-agent.o $(P11OBJS) $(SKOBJS) -SSHKEYGEN_OBJS= ssh-keygen.o sshsig.o $(SKOBJS) +SSHKEYGEN_OBJS= ssh-keygen.o sshsig.o $(P11OBJS) $(SKOBJS) -SSHKEYSIGN_OBJS=ssh-keysign.o readconf.o uidswap.o $(SKOBJS) +SSHKEYSIGN_OBJS=ssh-keysign.o readconf.o uidswap.o $(P11OBJS) $(SKOBJS) P11HELPER_OBJS= ssh-pkcs11-helper.o ssh-pkcs11.o $(SKOBJS) SKHELPER_OBJS= ssh-sk-helper.o ssh-sk.o sk-usbhid.o -SSHKEYSCAN_OBJS=ssh-keyscan.o $(SKOBJS) +SSHKEYSCAN_OBJS=ssh-keyscan.o $(P11OBJS) $(SKOBJS) SFTPSERVER_OBJS=sftp-common.o sftp-server.o sftp-server-main.o diff --git a/ssh-ecdsa.c b/ssh-ecdsa.c index 695ed451e63d..b423bfb65685 100644 --- a/ssh-ecdsa.c +++ b/ssh-ecdsa.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-ecdsa.c,v 1.27 2024/08/15 00:51:51 djm Exp $ */ +/* $OpenBSD: ssh-ecdsa.c,v 1.28 2025/07/24 05:44:55 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2010 Damien Miller. All rights reserved. @@ -328,8 +328,7 @@ ssh_ecdsa_sign(struct sshkey *key, const BIGNUM *sig_r, *sig_s; int hash_alg; size_t slen = 0; - struct sshbuf *b = NULL, *bb = NULL; - int len = 0, ret = SSH_ERR_INTERNAL_ERROR; + int ret = SSH_ERR_INTERNAL_ERROR; if (lenp != NULL) *lenp = 0; @@ -352,11 +351,37 @@ ssh_ecdsa_sign(struct sshkey *key, ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } + ECDSA_SIG_get0(esig, &sig_r, &sig_s); + + if ((ret = ssh_ecdsa_encode_store_sig(key, sig_r, sig_s, + sigp, lenp)) != 0) + goto out; + /* success */ + ret = 0; + out: + freezero(sigb, slen); + ECDSA_SIG_free(esig); + return ret; +} + +int +ssh_ecdsa_encode_store_sig(const struct sshkey *key, + const BIGNUM *sig_r, const BIGNUM *sig_s, + u_char **sigp, size_t *lenp) +{ + struct sshbuf *b = NULL, *bb = NULL; + int ret; + size_t len; + + if (lenp != NULL) + *lenp = 0; + if (sigp != NULL) + *sigp = NULL; + if ((bb = sshbuf_new()) == NULL || (b = sshbuf_new()) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } - ECDSA_SIG_get0(esig, &sig_r, &sig_s); if ((ret = sshbuf_put_bignum2(bb, sig_r)) != 0 || (ret = sshbuf_put_bignum2(bb, sig_s)) != 0) goto out; @@ -375,10 +400,8 @@ ssh_ecdsa_sign(struct sshkey *key, *lenp = len; ret = 0; out: - freezero(sigb, slen); sshbuf_free(b); sshbuf_free(bb); - ECDSA_SIG_free(esig); return ret; } diff --git a/ssh-pkcs11-client.c b/ssh-pkcs11-client.c index b8d1700f0296..8aaa4d2d684c 100644 --- a/ssh-pkcs11-client.c +++ b/ssh-pkcs11-client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-pkcs11-client.c,v 1.20 2024/08/15 00:51:51 djm Exp $ */ +/* $OpenBSD: ssh-pkcs11-client.c,v 1.21 2025/07/24 05:44:55 djm Exp $ */ /* * Copyright (c) 2010 Markus Friedl. All rights reserved. * Copyright (c) 2014 Pedro Martelletto. All rights reserved. @@ -18,8 +18,6 @@ #include "includes.h" -#ifdef ENABLE_PKCS11 - #include #ifdef HAVE_SYS_TIME_H # include @@ -27,14 +25,12 @@ #include #include +#include #include #include #include #include -#include -#include - #include "pathnames.h" #include "xmalloc.h" #include "sshbuf.h" @@ -46,28 +42,18 @@ #include "ssh-pkcs11.h" #include "ssherr.h" -#include "openbsd-compat/openssl-compat.h" - -#if !defined(OPENSSL_HAS_ECC) || !defined(HAVE_EC_KEY_METHOD_NEW) -#define EC_KEY_METHOD void -#define EC_KEY void -#endif - /* borrows code from sftp-server and ssh-agent */ /* * Maintain a list of ssh-pkcs11-helper subprocesses. These may be looked up - * by provider path or their unique EC/RSA METHOD pointers. + * by provider path or their unique keyblobs. */ struct helper { char *path; pid_t pid; int fd; - RSA_METHOD *rsa_meth; - EC_KEY_METHOD *ec_meth; - int (*rsa_finish)(RSA *rsa); - void (*ec_finish)(EC_KEY *key); - size_t nrsa, nec; /* number of active keys of each type */ + size_t nkeyblobs; + struct sshbuf **keyblobs; /* XXX use a tree or something faster */ }; static struct helper **helpers; static size_t nhelpers; @@ -88,58 +74,75 @@ helper_by_provider(const char *path) } static struct helper * -helper_by_rsa(const RSA *rsa) +helper_by_key(const struct sshkey *key) { - size_t i; - const RSA_METHOD *meth; + size_t i, j; + struct sshbuf *keyblob = NULL; + int r; + + if ((keyblob = sshbuf_new()) == NULL) + fatal_f("sshbuf_new failed"); + if ((r = sshkey_putb(key, keyblob)) != 0) + fatal_fr(r, "serialise key"); - if ((meth = RSA_get_method(rsa)) == NULL) - return NULL; for (i = 0; i < nhelpers; i++) { - if (helpers[i] != NULL && helpers[i]->rsa_meth == meth) - return helpers[i]; + if (helpers[i] == NULL) + continue; + for (j = 0; j < helpers[i]->nkeyblobs; j++) { + if (sshbuf_equals(keyblob, + helpers[i]->keyblobs[j]) == 0) { + sshbuf_free(keyblob); + return helpers[i]; + } + } } + sshbuf_free(keyblob); return NULL; } -#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW) -static struct helper * -helper_by_ec(const EC_KEY *ec) +static void +helper_add_key(struct helper *helper, struct sshkey *key) { - size_t i; - const EC_KEY_METHOD *meth; - - if ((meth = EC_KEY_get_method(ec)) == NULL) - return NULL; - for (i = 0; i < nhelpers; i++) { - if (helpers[i] != NULL && helpers[i]->ec_meth == meth) - return helpers[i]; - } - return NULL; + int r; + helper->keyblobs = xrecallocarray(helper->keyblobs, helper->nkeyblobs, + helper->nkeyblobs + 1, sizeof(*helper->keyblobs)); + if ((helper->keyblobs[helper->nkeyblobs] = sshbuf_new()) == NULL) + fatal_f("sshbuf_new failed"); + if ((r = sshkey_putb(key, helper->keyblobs[helper->nkeyblobs])) != 0) + fatal_fr(r, "shkey_putb failed"); + helper->nkeyblobs++; + debug3_f("added %s key for provider %s, now has %zu keys", + sshkey_type(key), helper->path, helper->nkeyblobs); } -#endif /* defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW) */ static void -helper_free(struct helper *helper) +helper_terminate(struct helper *helper) { size_t i; int found = 0; if (helper == NULL) return; - if (helper->path == NULL || helper->ec_meth == NULL || - helper->rsa_meth == NULL) + if (helper->path == NULL) fatal_f("inconsistent helper"); - debug3_f("free helper for provider %s", helper->path); + + debug3_f("terminating helper for %s; remaining %zu keys", + helper->path, helper->nkeyblobs); + + close(helper->fd); + /* XXX waitpid() */ + helper->fd = -1; + helper->pid = -1; + + /* repack helpers */ for (i = 0; i < nhelpers; i++) { if (helpers[i] == helper) { if (found) fatal_f("helper recorded more than once"); found = 1; - } - else if (found) + } else if (found) helpers[i - 1] = helpers[i]; } if (found) { @@ -147,39 +150,12 @@ helper_free(struct helper *helper) nhelpers - 1, sizeof(*helpers)); nhelpers--; } + for (i = 0; i < helper->nkeyblobs; i++) + sshbuf_free(helper->keyblobs[i]); free(helper->path); -#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW) - EC_KEY_METHOD_free(helper->ec_meth); -#endif - RSA_meth_free(helper->rsa_meth); free(helper); } -static void -helper_terminate(struct helper *helper) -{ - if (helper == NULL) { - return; - } else if (helper->fd == -1) { - debug3_f("already terminated"); - } else { - debug3_f("terminating helper for %s; " - "remaining %zu RSA %zu ECDSA", - helper->path, helper->nrsa, helper->nec); - close(helper->fd); - /* XXX waitpid() */ - helper->fd = -1; - helper->pid = -1; - } - /* - * Don't delete the helper entry until there are no remaining keys - * that reference it. Otherwise, any signing operation would call - * a free'd METHOD pointer and that would be bad. - */ - if (helper->nrsa == 0 && helper->nec == 0) - helper_free(helper); -} - static void send_msg(int fd, struct sshbuf *m) { @@ -249,200 +225,61 @@ pkcs11_terminate(void) helper_terminate(helpers[i]); } -static int -rsa_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, int padding) +int +pkcs11_sign(struct sshkey *key, + u_char **sigp, size_t *lenp, + const u_char *data, size_t datalen, + const char *alg, const char *sk_provider, + const char *sk_pin, u_int compat) { - struct sshkey *key = NULL; struct sshbuf *msg = NULL; - u_char *blob = NULL, *signature = NULL; - size_t blen, slen = 0; - int r, ret = -1; struct helper *helper; + int status, r; + u_char *signature = NULL; + size_t signature_len = 0; + int ret = SSH_ERR_INTERNAL_ERROR; - if ((helper = helper_by_rsa(rsa)) == NULL || helper->fd == -1) - fatal_f("no helper for PKCS11 key"); - debug3_f("signing with PKCS11 provider %s", helper->path); - if (padding != RSA_PKCS1_PADDING) - goto fail; - if ((key = sshkey_new(KEY_UNSPEC)) == NULL) { - error_f("sshkey_new failed"); - goto fail; - } - if ((key->pkey = EVP_PKEY_new()) == NULL || - EVP_PKEY_set1_RSA(key->pkey, rsa) != 1) { - error_f("pkey setup failed"); - goto fail; - } + if (sigp != NULL) + *sigp = NULL; + if (lenp != NULL) + *lenp = 0; + + if ((helper = helper_by_key(key)) == NULL || helper->fd == -1) + fatal_f("no helper for %s key", sshkey_type(key)); - key->type = KEY_RSA; - if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) { - error_fr(r, "encode key"); - goto fail; - } if ((msg = sshbuf_new()) == NULL) - fatal_f("sshbuf_new failed"); + return SSH_ERR_ALLOC_FAIL; if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 || - (r = sshbuf_put_string(msg, blob, blen)) != 0 || - (r = sshbuf_put_string(msg, from, flen)) != 0 || - (r = sshbuf_put_u32(msg, 0)) != 0) + (r = sshkey_puts_plain(key, msg)) != 0 || + (r = sshbuf_put_string(msg, data, datalen)) != 0 || + (r = sshbuf_put_cstring(msg, alg == NULL ? "" : alg)) != 0 || + (r = sshbuf_put_u32(msg, compat)) != 0) fatal_fr(r, "compose"); send_msg(helper->fd, msg); sshbuf_reset(msg); - if (recv_msg(helper->fd, msg) == SSH2_AGENT_SIGN_RESPONSE) { - if ((r = sshbuf_get_string(msg, &signature, &slen)) != 0) - fatal_fr(r, "parse"); - if (slen <= (size_t)RSA_size(rsa)) { - memcpy(to, signature, slen); - ret = slen; - } - free(signature); - } - fail: - free(blob); - sshkey_free(key); - sshbuf_free(msg); - return (ret); -} - -static int -rsa_finish(RSA *rsa) -{ - struct helper *helper; - - if ((helper = helper_by_rsa(rsa)) == NULL) - fatal_f("no helper for PKCS11 key"); - debug3_f("free PKCS11 RSA key for provider %s", helper->path); - if (helper->rsa_finish != NULL) - helper->rsa_finish(rsa); - if (helper->nrsa == 0) - fatal_f("RSA refcount error"); - helper->nrsa--; - debug3_f("provider %s remaining keys: %zu RSA %zu ECDSA", - helper->path, helper->nrsa, helper->nec); - if (helper->nrsa == 0 && helper->nec == 0) - helper_terminate(helper); - return 1; -} - -#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW) -static ECDSA_SIG * -ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv, - const BIGNUM *rp, EC_KEY *ec) -{ - struct sshkey *key = NULL; - struct sshbuf *msg = NULL; - ECDSA_SIG *ret = NULL; - const u_char *cp; - u_char *blob = NULL, *signature = NULL; - size_t blen, slen = 0; - int r, nid; - struct helper *helper; - - if ((helper = helper_by_ec(ec)) == NULL || helper->fd == -1) - fatal_f("no helper for PKCS11 key"); - debug3_f("signing with PKCS11 provider %s", helper->path); - - if ((key = sshkey_new(KEY_UNSPEC)) == NULL) { - error_f("sshkey_new failed"); - goto fail; - } - if ((key->pkey = EVP_PKEY_new()) == NULL || - EVP_PKEY_set1_EC_KEY(key->pkey, ec) != 1) { - error("pkey setup failed"); - goto fail; - } - if ((nid = sshkey_ecdsa_pkey_to_nid(key->pkey)) < 0) { - error("couldn't get curve nid"); + if ((status = recv_msg(helper->fd, msg)) != SSH2_AGENT_SIGN_RESPONSE) { + /* XXX translate status to something useful */ + debug_fr(r, "recv_msg"); + ret = SSH_ERR_AGENT_FAILURE; goto fail; } - key->ecdsa_nid = nid; - key->type = KEY_ECDSA; - if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) { - error_fr(r, "encode key"); - goto fail; - } - if ((msg = sshbuf_new()) == NULL) - fatal_f("sshbuf_new failed"); - if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 || - (r = sshbuf_put_string(msg, blob, blen)) != 0 || - (r = sshbuf_put_string(msg, dgst, dgst_len)) != 0 || - (r = sshbuf_put_u32(msg, 0)) != 0) - fatal_fr(r, "compose"); - send_msg(helper->fd, msg); - sshbuf_reset(msg); + if ((r = sshbuf_get_string(msg, &signature, &signature_len)) != 0) + fatal_fr(r, "parse"); - if (recv_msg(helper->fd, msg) == SSH2_AGENT_SIGN_RESPONSE) { - if ((r = sshbuf_get_string(msg, &signature, &slen)) != 0) - fatal_fr(r, "parse"); - cp = signature; - ret = d2i_ECDSA_SIG(NULL, &cp, slen); - free(signature); + /* success */ + if (sigp != NULL) { + *sigp = signature; + signature = NULL; } + if (lenp != NULL) + *lenp = signature_len; + ret = 0; fail: - free(blob); - sshkey_free(key); sshbuf_free(msg); - return (ret); -} - -static void -ecdsa_do_finish(EC_KEY *ec) -{ - struct helper *helper; - - if ((helper = helper_by_ec(ec)) == NULL) - fatal_f("no helper for PKCS11 key"); - debug3_f("free PKCS11 ECDSA key for provider %s", helper->path); - if (helper->ec_finish != NULL) - helper->ec_finish(ec); - if (helper->nec == 0) - fatal_f("ECDSA refcount error"); - helper->nec--; - debug3_f("provider %s remaining keys: %zu RSA %zu ECDSA", - helper->path, helper->nrsa, helper->nec); - if (helper->nrsa == 0 && helper->nec == 0) - helper_terminate(helper); -} -#endif /* defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW) */ - -/* redirect private key crypto operations to the ssh-pkcs11-helper */ -static void -wrap_key(struct helper *helper, struct sshkey *k) -{ - RSA *rsa = NULL; - EC_KEY *ecdsa = NULL; - - debug3_f("wrap %s for provider %s", sshkey_type(k), helper->path); - if (k->type == KEY_RSA) { - if ((rsa = EVP_PKEY_get1_RSA(k->pkey)) == NULL) - fatal_f("no RSA key"); - if (RSA_set_method(rsa, helper->rsa_meth) != 1) - fatal_f("RSA_set_method failed"); - if (helper->nrsa++ >= INT_MAX) - fatal_f("RSA refcount error"); - if (EVP_PKEY_set1_RSA(k->pkey, rsa) != 1) - fatal_f("EVP_PKEY_set1_RSA failed"); - RSA_free(rsa); -#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW) - } else if (k->type == KEY_ECDSA) { - if ((ecdsa = EVP_PKEY_get1_EC_KEY(k->pkey)) == NULL) - fatal_f("no ECDSA key"); - if (EC_KEY_set_method(ecdsa, helper->ec_meth) != 1) - fatal_f("EC_KEY_set_method failed"); - if (helper->nec++ >= INT_MAX) - fatal_f("EC refcount error"); - if (EVP_PKEY_set1_EC_KEY(k->pkey, ecdsa) != 1) - fatal_f("EVP_PKEY_set1_EC_KEY failed"); - EC_KEY_free(ecdsa); -#endif - } else - fatal_f("unknown key type"); - k->flags |= SSHKEY_FLAG_EXT; - debug3_f("provider %s remaining keys: %zu RSA %zu ECDSA", - helper->path, helper->nrsa, helper->nec); + return ret; } /* @@ -456,13 +293,13 @@ pkcs11_make_cert(const struct sshkey *priv, struct helper *helper = NULL; struct sshkey *ret; int r; - RSA *rsa_priv = NULL, *rsa_cert = NULL; -#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW) - EC_KEY *ec_priv = NULL, *ec_cert = NULL; -#endif - debug3_f("private key type %s cert type %s", sshkey_type(priv), - sshkey_type(certpub)); + if ((helper = helper_by_key(priv)) == NULL || helper->fd == -1) + fatal_f("no helper for %s key", sshkey_type(priv)); + + debug3_f("private key type %s cert type %s on provider %s", + sshkey_type(priv), sshkey_type(certpub), helper->path); + *certprivp = NULL; if (!sshkey_is_cert(certpub) || sshkey_is_cert(priv) || !sshkey_equal_public(priv, certpub)) { @@ -471,95 +308,24 @@ pkcs11_make_cert(const struct sshkey *priv, return SSH_ERR_INVALID_ARGUMENT; } *certprivp = NULL; - if (priv->type == KEY_RSA) { - if ((rsa_priv = EVP_PKEY_get1_RSA(priv->pkey)) == NULL) - fatal_f("no RSA pkey"); - if ((helper = helper_by_rsa(rsa_priv)) == NULL || - helper->fd == -1) - fatal_f("no helper for PKCS11 RSA key"); - if ((r = sshkey_from_private(priv, &ret)) != 0) - fatal_fr(r, "copy key"); - if ((rsa_cert = EVP_PKEY_get1_RSA(ret->pkey)) == NULL) - fatal_f("no RSA cert pkey"); - if (RSA_set_method(rsa_cert, helper->rsa_meth) != 1) - fatal_f("RSA_set_method failed"); - if (helper->nrsa++ >= INT_MAX) - fatal_f("RSA refcount error"); - if (EVP_PKEY_set1_RSA(ret->pkey, rsa_cert) != 1) - fatal_f("EVP_PKEY_set1_RSA failed"); - RSA_free(rsa_priv); - RSA_free(rsa_cert); -#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW) - } else if (priv->type == KEY_ECDSA) { - if ((ec_priv = EVP_PKEY_get1_EC_KEY(priv->pkey)) == NULL) - fatal_f("no EC pkey"); - if ((helper = helper_by_ec(ec_priv)) == NULL || - helper->fd == -1) - fatal_f("no helper for PKCS11 EC key"); - if ((r = sshkey_from_private(priv, &ret)) != 0) - fatal_fr(r, "copy key"); - if ((ec_cert = EVP_PKEY_get1_EC_KEY(ret->pkey)) == NULL) - fatal_f("no EC cert pkey"); - if (EC_KEY_set_method(ec_cert, helper->ec_meth) != 1) - fatal_f("EC_KEY_set_method failed"); - if (helper->nec++ >= INT_MAX) - fatal_f("EC refcount error"); - if (EVP_PKEY_set1_EC_KEY(ret->pkey, ec_cert) != 1) - fatal_f("EVP_PKEY_set1_EC_KEY failed"); - EC_KEY_free(ec_priv); - EC_KEY_free(ec_cert); -#endif - } else - fatal_f("unknown key type %s", sshkey_type(priv)); + if ((r = sshkey_from_private(priv, &ret)) != 0) + fatal_fr(r, "copy key"); ret->flags |= SSHKEY_FLAG_EXT; if ((r = sshkey_to_certified(ret)) != 0 || (r = sshkey_cert_copy(certpub, ret)) != 0) fatal_fr(r, "graft certificate"); - debug3_f("provider %s remaining keys: %zu RSA %zu ECDSA", - helper->path, helper->nrsa, helper->nec); + + helper_add_key(helper, ret); + + debug3_f("provider %s: %zu remaining keys", + helper->path, helper->nkeyblobs); + /* success */ *certprivp = ret; return 0; } -static int -pkcs11_start_helper_methods(struct helper *helper) -{ - RSA_METHOD *rsa_meth = NULL; - EC_KEY_METHOD *ec_meth = NULL; -#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW) - int (*ec_init)(EC_KEY *key); - int (*ec_copy)(EC_KEY *dest, const EC_KEY *src); - int (*ec_set_group)(EC_KEY *key, const EC_GROUP *grp); - int (*ec_set_private)(EC_KEY *key, const BIGNUM *priv_key); - int (*ec_set_public)(EC_KEY *key, const EC_POINT *pub_key); - int (*ec_sign)(int, const unsigned char *, int, unsigned char *, - unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *) = NULL; - - if ((ec_meth = EC_KEY_METHOD_new(EC_KEY_OpenSSL())) == NULL) - return -1; - EC_KEY_METHOD_get_sign(ec_meth, &ec_sign, NULL, NULL); - EC_KEY_METHOD_set_sign(ec_meth, ec_sign, NULL, ecdsa_do_sign); - EC_KEY_METHOD_get_init(ec_meth, &ec_init, &helper->ec_finish, - &ec_copy, &ec_set_group, &ec_set_private, &ec_set_public); - EC_KEY_METHOD_set_init(ec_meth, ec_init, ecdsa_do_finish, - ec_copy, ec_set_group, ec_set_private, ec_set_public); -#endif /* defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW) */ - - if ((rsa_meth = RSA_meth_dup(RSA_get_default_method())) == NULL) - fatal_f("RSA_meth_dup failed"); - helper->rsa_finish = RSA_meth_get_finish(rsa_meth); - if (!RSA_meth_set1_name(rsa_meth, "ssh-pkcs11-helper") || - !RSA_meth_set_priv_enc(rsa_meth, rsa_encrypt) || - !RSA_meth_set_finish(rsa_meth, rsa_finish)) - fatal_f("failed to prepare method"); - - helper->ec_meth = ec_meth; - helper->rsa_meth = rsa_meth; - return 0; -} - static struct helper * pkcs11_start_helper(const char *path) { @@ -576,19 +342,10 @@ pkcs11_start_helper(const char *path) return NULL; } helper = xcalloc(1, sizeof(*helper)); - if (pkcs11_start_helper_methods(helper) == -1) { - error_f("pkcs11_start_helper_methods failed"); - goto fail; - } if ((pid = fork()) == -1) { error_f("fork: %s", strerror(errno)); - fail: close(pair[0]); close(pair[1]); - RSA_meth_free(helper->rsa_meth); -#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW) - EC_KEY_METHOD_free(helper->ec_meth); -#endif free(helper); return NULL; } else if (pid == 0) { @@ -628,10 +385,8 @@ pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp, { struct sshkey *k; int r, type; - u_char *blob; char *label; - size_t blen; - u_int nkeys, i; + u_int ret = -1, nkeys, i; struct sshbuf *msg; struct helper *helper; @@ -639,6 +394,8 @@ pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp, (helper = pkcs11_start_helper(name)) == NULL) return -1; + debug3_f("add %s", helper->path); + if ((msg = sshbuf_new()) == NULL) fatal_f("sshbuf_new failed"); if ((r = sshbuf_put_u8(msg, SSH_AGENTC_ADD_SMARTCARD_KEY)) != 0 || @@ -649,35 +406,39 @@ pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp, sshbuf_reset(msg); type = recv_msg(helper->fd, msg); + debug3_f("response %d", type); if (type == SSH2_AGENT_IDENTITIES_ANSWER) { if ((r = sshbuf_get_u32(msg, &nkeys)) != 0) fatal_fr(r, "parse nkeys"); + debug3_f("helper return %u keys", nkeys); *keysp = xcalloc(nkeys, sizeof(struct sshkey *)); if (labelsp) *labelsp = xcalloc(nkeys, sizeof(char *)); for (i = 0; i < nkeys; i++) { /* XXX clean up properly instead of fatal() */ - if ((r = sshbuf_get_string(msg, &blob, &blen)) != 0 || + if ((r = sshkey_froms(msg, &k)) != 0 || (r = sshbuf_get_cstring(msg, &label, NULL)) != 0) fatal_fr(r, "parse key"); - if ((r = sshkey_from_blob(blob, blen, &k)) != 0) - fatal_fr(r, "decode key"); - wrap_key(helper, k); + k->flags |= SSHKEY_FLAG_EXT; + helper_add_key(helper, k); (*keysp)[i] = k; if (labelsp) (*labelsp)[i] = label; else free(label); - free(blob); } + /* success */ + ret = 0; } else if (type == SSH2_AGENT_FAILURE) { if ((r = sshbuf_get_u32(msg, &nkeys)) != 0) - nkeys = -1; - } else { - nkeys = -1; + error_fr(r, "failed to parse failure response"); + } + if (ret != 0) { + debug_f("no keys; terminate helper"); + helper_terminate(helper); } sshbuf_free(msg); - return (nkeys); + return ret == 0 ? (int)nkeys : -1; } int @@ -694,4 +455,39 @@ pkcs11_del_provider(char *name) helper_terminate(helper); return 0; } -#endif /* ENABLE_PKCS11 */ + +void +pkcs11_key_free(struct sshkey *key) +{ + struct helper *helper; + struct sshbuf *keyblob = NULL; + size_t i; + int r, found = 0; + + debug3_f("free %s key", sshkey_type(key)); + + if ((helper = helper_by_key(key)) == NULL || helper->fd == -1) + fatal_f("no helper for %s key", sshkey_type(key)); + if ((keyblob = sshbuf_new()) == NULL) + fatal_f("sshbuf_new failed"); + if ((r = sshkey_putb(key, keyblob)) != 0) + fatal_fr(r, "serialise key"); + + /* repack keys */ + for (i = 0; i < helper->nkeyblobs; i++) { + if (sshbuf_equals(keyblob, helper->keyblobs[i]) == 0) { + if (found) + fatal_f("key recorded more than once"); + found = 1; + } else if (found) + helper->keyblobs[i - 1] = helper->keyblobs[i]; + } + if (found) { + helper->keyblobs = xrecallocarray(helper->keyblobs, + helper->nkeyblobs, helper->nkeyblobs - 1, + sizeof(*helper->keyblobs)); + helper->nkeyblobs--; + } + if (helper->nkeyblobs == 0) + helper_terminate(helper); +} diff --git a/ssh-pkcs11-helper.c b/ssh-pkcs11-helper.c index a8154f21c058..2d818b8970a4 100644 --- a/ssh-pkcs11-helper.c +++ b/ssh-pkcs11-helper.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-pkcs11-helper.c,v 1.27 2024/08/15 00:51:51 djm Exp $ */ +/* $OpenBSD: ssh-pkcs11-helper.c,v 1.28 2025/07/24 05:44:55 djm Exp $ */ /* * Copyright (c) 2010 Markus Friedl. All rights reserved. * @@ -22,8 +22,6 @@ # include #endif -#include "openbsd-compat/sys-queue.h" - #include #include #ifdef HAVE_POLL_H @@ -44,20 +42,9 @@ #ifdef ENABLE_PKCS11 -#ifdef WITH_OPENSSL -#include -#include -#include - /* borrows code from sftp-server and ssh-agent */ -struct pkcs11_keyinfo { - struct sshkey *key; - char *providername, *label; - TAILQ_ENTRY(pkcs11_keyinfo) next; -}; - -TAILQ_HEAD(, pkcs11_keyinfo) pkcs11_keylist; +static char *providername; /* Provider for this helper */ #define MAX_MSG_LENGTH 10240 /*XXX*/ @@ -65,50 +52,6 @@ TAILQ_HEAD(, pkcs11_keyinfo) pkcs11_keylist; struct sshbuf *iqueue; struct sshbuf *oqueue; -static void -add_key(struct sshkey *k, char *name, char *label) -{ - struct pkcs11_keyinfo *ki; - - ki = xcalloc(1, sizeof(*ki)); - ki->providername = xstrdup(name); - ki->key = k; - ki->label = xstrdup(label); - TAILQ_INSERT_TAIL(&pkcs11_keylist, ki, next); -} - -static void -del_keys_by_name(char *name) -{ - struct pkcs11_keyinfo *ki, *nxt; - - for (ki = TAILQ_FIRST(&pkcs11_keylist); ki; ki = nxt) { - nxt = TAILQ_NEXT(ki, next); - if (!strcmp(ki->providername, name)) { - TAILQ_REMOVE(&pkcs11_keylist, ki, next); - free(ki->providername); - free(ki->label); - sshkey_free(ki->key); - free(ki); - } - } -} - -/* lookup matching 'private' key */ -static struct sshkey * -lookup_key(struct sshkey *k) -{ - struct pkcs11_keyinfo *ki; - - TAILQ_FOREACH(ki, &pkcs11_keylist, next) { - debug("check %s %s %s", sshkey_type(ki->key), - ki->providername, ki->label); - if (sshkey_equal(k, ki->key)) - return (ki->key); - } - return (NULL); -} - static void send_msg(struct sshbuf *m) { @@ -121,34 +64,32 @@ send_msg(struct sshbuf *m) static void process_add(void) { - char *name, *pin; + char *pin; struct sshkey **keys = NULL; int r, i, nkeys; - u_char *blob; - size_t blen; struct sshbuf *msg; char **labels = NULL; + if (providername != NULL) + fatal_f("provider already set"); if ((msg = sshbuf_new()) == NULL) fatal_f("sshbuf_new failed"); - if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 || + if ((r = sshbuf_get_cstring(iqueue, &providername, NULL)) != 0 || (r = sshbuf_get_cstring(iqueue, &pin, NULL)) != 0) fatal_fr(r, "parse"); - if ((nkeys = pkcs11_add_provider(name, pin, &keys, &labels)) > 0) { + debug3_f("add %s", providername); + if ((nkeys = pkcs11_add_provider(providername, pin, + &keys, &labels)) > 0) { if ((r = sshbuf_put_u8(msg, SSH2_AGENT_IDENTITIES_ANSWER)) != 0 || (r = sshbuf_put_u32(msg, nkeys)) != 0) fatal_fr(r, "compose"); for (i = 0; i < nkeys; i++) { - if ((r = sshkey_to_blob(keys[i], &blob, &blen)) != 0) { - debug_fr(r, "encode key"); - continue; - } - if ((r = sshbuf_put_string(msg, blob, blen)) != 0 || + if ((r = sshkey_puts(keys[i], msg)) != 0 || (r = sshbuf_put_cstring(msg, labels[i])) != 0) fatal_fr(r, "compose key"); - free(blob); - add_key(keys[i], name, labels[i]); + debug3_f("%s: %s \"%s\"", providername, + sshkey_type(keys[i]), labels[i]); free(labels[i]); } } else if ((r = sshbuf_put_u8(msg, SSH_AGENT_FAILURE)) != 0 || @@ -157,95 +98,39 @@ process_add(void) free(labels); free(keys); /* keys themselves are transferred to pkcs11_keylist */ free(pin); - free(name); send_msg(msg); sshbuf_free(msg); } static void -process_del(void) +process_sign(void) { - char *name, *pin; + const u_char *data; + u_char *signature = NULL; + size_t dlen, slen = 0; + u_int compat; + int r, ok = -1; + struct sshkey *key = NULL; struct sshbuf *msg; - int r; + char *alg = NULL; - if ((msg = sshbuf_new()) == NULL) - fatal_f("sshbuf_new failed"); - if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 || - (r = sshbuf_get_cstring(iqueue, &pin, NULL)) != 0) + if ((r = sshkey_froms(iqueue, &key)) != 0 || + (r = sshbuf_get_string_direct(iqueue, &data, &dlen)) != 0 || + (r = sshbuf_get_cstring(iqueue, &alg, NULL)) != 0 || + (r = sshbuf_get_u32(iqueue, &compat)) != 0) fatal_fr(r, "parse"); - del_keys_by_name(name); - if ((r = sshbuf_put_u8(msg, pkcs11_del_provider(name) == 0 ? - SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE)) != 0) - fatal_fr(r, "compose"); - free(pin); - free(name); - send_msg(msg); - sshbuf_free(msg); -} -static void -process_sign(void) -{ - u_char *blob, *data, *signature = NULL; - size_t blen, dlen; - u_int slen = 0; - int len, r, ok = -1; - struct sshkey *key = NULL, *found; - struct sshbuf *msg; -#ifdef WITH_OPENSSL - RSA *rsa = NULL; -#ifdef OPENSSL_HAS_ECC - EC_KEY *ecdsa = NULL; -#endif /* OPENSSL_HAS_ECC */ -#endif /* WITH_OPENSSL */ - - /* XXX support SHA2 signature flags */ - if ((r = sshbuf_get_string(iqueue, &blob, &blen)) != 0 || - (r = sshbuf_get_string(iqueue, &data, &dlen)) != 0 || - (r = sshbuf_get_u32(iqueue, NULL)) != 0) - fatal_fr(r, "parse"); + if (*alg == '\0') { + free(alg); + alg = NULL; + } - if ((r = sshkey_from_blob(blob, blen, &key)) != 0) - fatal_fr(r, "decode key"); - if ((found = lookup_key(key)) == NULL) + if ((r = pkcs11_sign(key, &signature, &slen, data, dlen, + alg, NULL, NULL, compat)) != 0) { + error_fr(r, "sign %s", sshkey_type(key)); goto reply; - - /* XXX use pkey API properly for signing */ - switch (key->type) { -#ifdef WITH_OPENSSL - case KEY_RSA: - if ((rsa = EVP_PKEY_get1_RSA(found->pkey)) == NULL) - fatal_f("no RSA in pkey"); - if ((len = RSA_size(rsa)) < 0) - fatal_f("bad RSA length"); - signature = xmalloc(len); - if ((len = RSA_private_encrypt(dlen, data, signature, - rsa, RSA_PKCS1_PADDING)) < 0) { - error_f("RSA_private_encrypt failed"); - goto reply; - } - slen = (u_int)len; - break; -#ifdef OPENSSL_HAS_ECC - case KEY_ECDSA: - if ((ecdsa = EVP_PKEY_get1_EC_KEY(found->pkey)) == NULL) - fatal_f("no ECDSA in pkey"); - if ((len = ECDSA_size(ecdsa)) < 0) - fatal_f("bad ECDSA length"); - slen = (u_int)len; - signature = xmalloc(slen); - /* "The parameter type is ignored." */ - if (!ECDSA_sign(-1, data, dlen, signature, &slen, ecdsa)) { - error_f("ECDSA_sign failed"); - goto reply; - } - break; -#endif /* OPENSSL_HAS_ECC */ -#endif /* WITH_OPENSSL */ - default: - fatal_f("unsupported key type %d", key->type); } + /* success */ ok = 0; reply: @@ -260,12 +145,7 @@ process_sign(void) fatal_fr(r, "compose failure response"); } sshkey_free(key); - RSA_free(rsa); -#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) - EC_KEY_free(ecdsa); -#endif - free(data); - free(blob); + free(alg); free(signature); send_msg(msg); sshbuf_free(msg); @@ -301,10 +181,6 @@ process(void) debug("process_add"); process_add(); break; - case SSH_AGENTC_REMOVE_SMARTCARD_KEY: - debug("process_del"); - process_del(); - break; case SSH2_AGENTC_SIGN_REQUEST: debug("process_sign"); process_sign(); @@ -336,7 +212,6 @@ cleanup_exit(int i) _exit(i); } - int main(int argc, char **argv) { @@ -350,7 +225,6 @@ main(int argc, char **argv) __progname = ssh_get_progname(argv[0]); seed_rng(); - TAILQ_INIT(&pkcs11_keylist); log_init(__progname, log_level, log_facility, log_stderr); @@ -439,22 +313,23 @@ main(int argc, char **argv) fatal_fr(r, "reserve"); } } - -#else /* WITH_OPENSSL */ -void -cleanup_exit(int i) +#else /* ENABLE_PKCS11 */ +/* stubs */ +int +pkcs11_sign(struct sshkey *key, + u_char **sigp, size_t *lenp, + const u_char *data, size_t datalen, + const char *alg, const char *sk_provider, + const char *sk_pin, u_int compat) { - _exit(i); + return SSH_ERR_INTERNAL_ERROR; } -int -main(int argc, char **argv) +void +pkcs11_key_free(struct sshkey *key) { - fprintf(stderr, "PKCS#11 code is not enabled\n"); - return 1; } -#endif /* WITH_OPENSSL */ -#else /* ENABLE_PKCS11 */ + int main(int argc, char **argv) { diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c index 31b9360f0adb..147c52049500 100644 --- a/ssh-pkcs11.c +++ b/ssh-pkcs11.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-pkcs11.c,v 1.64 2024/09/20 02:00:46 jsg Exp $ */ +/* $OpenBSD: ssh-pkcs11.c,v 1.65 2025/07/24 05:44:55 djm Exp $ */ /* * Copyright (c) 2010 Markus Friedl. All rights reserved. * Copyright (c) 2014 Pedro Martelletto. All rights reserved. @@ -42,9 +42,12 @@ #define CRYPTOKI_COMPAT #include "pkcs11.h" +#define SSHKEY_INTERNAL +#include "sshkey.h" + #include "log.h" #include "misc.h" -#include "sshkey.h" +#include "sshbuf.h" #include "ssh-pkcs11.h" #include "digest.h" #include "xmalloc.h" @@ -71,15 +74,19 @@ struct pkcs11_provider { TAILQ_HEAD(, pkcs11_provider) pkcs11_providers; struct pkcs11_key { + struct sshbuf *keyblob; struct pkcs11_provider *provider; CK_ULONG slotidx; char *keyid; int keyid_len; + TAILQ_ENTRY(pkcs11_key) next; }; +TAILQ_HEAD(, pkcs11_key) pkcs11_keys; /* XXX a tree would be better */ + int pkcs11_interactive = 0; -#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW) +#ifdef WITH_OPENSSL static void ossl_error(const char *msg) { @@ -89,15 +96,7 @@ ossl_error(const char *msg) while ((e = ERR_get_error()) != 0) error_f("libcrypto error: %s", ERR_error_string(e, NULL)); } -#endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */ - -int -pkcs11_init(int interactive) -{ - pkcs11_interactive = interactive; - TAILQ_INIT(&pkcs11_providers); - return (0); -} +#endif /* * finalize a provider shared library, it's no longer usable. @@ -146,19 +145,6 @@ pkcs11_provider_unref(struct pkcs11_provider *p) } } -/* unregister all providers, keys might still point to the providers */ -void -pkcs11_terminate(void) -{ - struct pkcs11_provider *p; - - while ((p = TAILQ_FIRST(&pkcs11_providers)) != NULL) { - TAILQ_REMOVE(&pkcs11_providers, p, next); - pkcs11_provider_finalize(p); - pkcs11_provider_unref(p); - } -} - /* lookup provider by name */ static struct pkcs11_provider * pkcs11_provider_lookup(char *provider_id) @@ -188,26 +174,16 @@ pkcs11_del_provider(char *provider_id) return (-1); } -static RSA_METHOD *rsa_method; -static int rsa_idx = 0; -#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW) -static EC_KEY_METHOD *ec_key_method; -static int ec_key_idx = 0; -#endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */ - /* release a wrapped object */ static void -pkcs11_k11_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx, - long argl, void *argp) +pkcs11_k11_free(struct pkcs11_key *k11) { - struct pkcs11_key *k11 = ptr; - - debug_f("parent %p ptr %p idx %d", parent, ptr, idx); if (k11 == NULL) return; if (k11->provider) pkcs11_provider_unref(k11->provider); free(k11->keyid); + sshbuf_free(k11->keyblob); free(k11); } @@ -417,214 +393,324 @@ pkcs11_get_key(struct pkcs11_key *k11, CK_MECHANISM_TYPE mech_type) return (0); } -/* openssl callback doing the actual signing operation */ +/* record the key information later use lookup by keyblob */ static int -pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, - int padding) +pkcs11_record_key(struct pkcs11_provider *provider, CK_ULONG slotidx, + CK_ATTRIBUTE *keyid_attrib, struct sshkey *key) { - struct pkcs11_key *k11; - struct pkcs11_slotinfo *si; - CK_FUNCTION_LIST *f; - CK_ULONG tlen = 0; - CK_RV rv; - int rval = -1; - - if ((k11 = RSA_get_ex_data(rsa, rsa_idx)) == NULL) { - error("RSA_get_ex_data failed"); - return (-1); + struct sshbuf *keyblob; + struct pkcs11_key *k11; + int r; + char *hex; + + hex = tohex(keyid_attrib->pValue, keyid_attrib->ulValueLen); + debug_f("%s key: provider %s slot %lu keyid %s", + sshkey_type(key), provider->name, (u_long)slotidx, hex); + free(hex); + + if ((keyblob = sshbuf_new()) == NULL) + fatal_f("sshbuf_new failed"); + if ((r = sshkey_putb(key, keyblob)) != 0) + fatal_fr(r, "sshkey_putb"); + + /* Check if we've already recorded this key in a different slot */ + TAILQ_FOREACH(k11, &pkcs11_keys, next) { + if (sshbuf_equals(k11->keyblob, keyblob) == 0) { + hex = tohex(k11->keyid, k11->keyid_len); + debug_f("Already seen this key at " + "provider %s slot %lu keyid %s", + k11->provider->name, k11->slotidx, hex); + free(hex); + sshbuf_free(keyblob); + return -1; + } } - if (pkcs11_get_key(k11, CKM_RSA_PKCS) == -1) { - error("pkcs11_get_key failed"); - return (-1); + k11 = xcalloc(1, sizeof(*k11)); + k11->provider = provider; + k11->keyblob = keyblob; + provider->refcount++; /* provider referenced by RSA key */ + k11->slotidx = slotidx; + /* identify key object on smartcard */ + k11->keyid_len = keyid_attrib->ulValueLen; + if (k11->keyid_len > 0) { + k11->keyid = xmalloc(k11->keyid_len); + memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len); } + TAILQ_INSERT_TAIL(&pkcs11_keys, k11, next); - f = k11->provider->function_list; - si = &k11->provider->slotinfo[k11->slotidx]; - tlen = RSA_size(rsa); - - /* XXX handle CKR_BUFFER_TOO_SMALL */ - rv = f->C_Sign(si->session, (CK_BYTE *)from, flen, to, &tlen); - if (rv == CKR_OK) - rval = tlen; - else - error("C_Sign failed: %lu", rv); - - return (rval); + return 0; } -static int -pkcs11_rsa_private_decrypt(int flen, const u_char *from, u_char *to, RSA *rsa, - int padding) +/* retrieve the key information by keyblob */ +static struct pkcs11_key * +pkcs11_lookup_key(struct sshkey *key) { - return (-1); + struct pkcs11_key *k11, *found = NULL; + struct sshbuf *keyblob; + int r; + + if ((keyblob = sshbuf_new()) == NULL) + fatal_f("sshbuf_new failed"); + if ((r = sshkey_putb(key, keyblob)) != 0) + fatal_fr(r, "sshkey_putb"); + TAILQ_FOREACH(k11, &pkcs11_keys, next) { + if (sshbuf_equals(k11->keyblob, keyblob) == 0) { + found = k11; + break; + } + } + sshbuf_free(keyblob); + return found; } +#ifdef WITH_OPENSSL +/* + * See: + * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/ + * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn + */ + +/* + * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) + * oiw(14) secsig(3) algorithms(2) 26 } + */ +static const u_char id_sha1[] = { + 0x30, 0x21, /* type Sequence, length 0x21 (33) */ + 0x30, 0x09, /* type Sequence, length 0x09 */ + 0x06, 0x05, /* type OID, length 0x05 */ + 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */ + 0x05, 0x00, /* NULL */ + 0x04, 0x14 /* Octet string, length 0x14 (20), followed by sha1 hash */ +}; + +/* + * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html + * id-sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) + * organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2) + * id-sha256(1) } + */ +static const u_char id_sha256[] = { + 0x30, 0x31, /* type Sequence, length 0x31 (49) */ + 0x30, 0x0d, /* type Sequence, length 0x0d (13) */ + 0x06, 0x09, /* type OID, length 0x09 */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, /* id-sha256 */ + 0x05, 0x00, /* NULL */ + 0x04, 0x20 /* Octet string, length 0x20 (32), followed by sha256 hash */ +}; + +/* + * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html + * id-sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) + * organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2) + * id-sha256(3) } + */ +static const u_char id_sha512[] = { + 0x30, 0x51, /* type Sequence, length 0x51 (81) */ + 0x30, 0x0d, /* type Sequence, length 0x0d (13) */ + 0x06, 0x09, /* type OID, length 0x09 */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, /* id-sha512 */ + 0x05, 0x00, /* NULL */ + 0x04, 0x40 /* Octet string, length 0x40 (64), followed by sha512 hash */ +}; + static int -pkcs11_rsa_start_wrapper(void) +rsa_hash_alg_oid(int hash_alg, const u_char **oidp, size_t *oidlenp) { - if (rsa_method != NULL) - return (0); - rsa_method = RSA_meth_dup(RSA_get_default_method()); - if (rsa_method == NULL) - return (-1); - rsa_idx = RSA_get_ex_new_index(0, "ssh-pkcs11-rsa", - NULL, NULL, pkcs11_k11_free); - if (rsa_idx == -1) - return (-1); - if (!RSA_meth_set1_name(rsa_method, "pkcs11") || - !RSA_meth_set_priv_enc(rsa_method, pkcs11_rsa_private_encrypt) || - !RSA_meth_set_priv_dec(rsa_method, pkcs11_rsa_private_decrypt)) { - error_f("setup pkcs11 method failed"); - return (-1); + switch (hash_alg) { + case SSH_DIGEST_SHA1: + *oidp = id_sha1; + *oidlenp = sizeof(id_sha1); + break; + case SSH_DIGEST_SHA256: + *oidp = id_sha256; + *oidlenp = sizeof(id_sha256); + break; + case SSH_DIGEST_SHA512: + *oidp = id_sha512; + *oidlenp = sizeof(id_sha512); + break; + default: + return SSH_ERR_INVALID_ARGUMENT; } - return (0); + return 0; } -/* redirect private key operations for rsa key to pkcs11 token */ static int -pkcs11_rsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx, - CK_ATTRIBUTE *keyid_attrib, RSA *rsa) +pkcs11_sign_rsa(struct sshkey *key, + u_char **sigp, size_t *lenp, + const u_char *data, size_t datalen, + const char *alg, const char *sk_provider, + const char *sk_pin, u_int compat) { struct pkcs11_key *k11; + struct pkcs11_slotinfo *si; + CK_FUNCTION_LIST *f; + CK_ULONG slen = 0; + CK_RV rv; + int hashalg, r, diff, siglen, ret = -1; + u_char *oid_dgst = NULL, *sig = NULL; + size_t dgst_len, oid_len, oid_dgst_len = 0; + const u_char *oid; - if (pkcs11_rsa_start_wrapper() == -1) - return (-1); + if (sigp != NULL) + *sigp = 0; + if (lenp != NULL) + *lenp = 0; - k11 = xcalloc(1, sizeof(*k11)); - k11->provider = provider; - provider->refcount++; /* provider referenced by RSA key */ - k11->slotidx = slotidx; - /* identify key object on smartcard */ - k11->keyid_len = keyid_attrib->ulValueLen; - if (k11->keyid_len > 0) { - k11->keyid = xmalloc(k11->keyid_len); - memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len); + if ((k11 = pkcs11_lookup_key(key)) == NULL) { + error_f("no key found"); + return SSH_ERR_KEY_NOT_FOUND; } - if (RSA_set_method(rsa, rsa_method) != 1) - fatal_f("RSA_set_method failed"); - if (RSA_set_ex_data(rsa, rsa_idx, k11) != 1) - fatal_f("RSA_set_ex_data failed"); - return (0); + debug3_f("sign with alg \"%s\" using provider %s slotidx %lu", + alg == NULL ? "" : alg, k11->provider->name, (u_long)k11->slotidx); + + if (pkcs11_get_key(k11, CKM_RSA_PKCS) == -1) { + error("pkcs11_get_key failed"); + return SSH_ERR_AGENT_FAILURE; + } + + f = k11->provider->function_list; + si = &k11->provider->slotinfo[k11->slotidx]; + + if ((siglen = EVP_PKEY_size(key->pkey)) <= 0) + return SSH_ERR_INVALID_ARGUMENT; + sig = xmalloc(siglen); + slen = (CK_ULONG)siglen; + + /* Determine hash algorithm and OID for signature */ + if (alg == NULL || *alg == '\0') + hashalg = SSH_DIGEST_SHA1; + else if ((hashalg = ssh_rsa_hash_id_from_keyname(alg)) == -1) + fatal_f("couldn't determine RSA hash alg \"%s\"", alg); + if ((r = rsa_hash_alg_oid(hashalg, &oid, &oid_len)) != 0) + fatal_fr(r, "rsa_hash_alg_oid failed"); + if ((dgst_len = ssh_digest_bytes(hashalg)) == 0) + fatal_f("bad hash alg %d", hashalg); + + /* Prepare { oid || digest } */ + oid_dgst_len = oid_len + dgst_len; + oid_dgst = xcalloc(1, oid_dgst_len); + memcpy(oid_dgst, oid, oid_len); + if ((r = ssh_digest_memory(hashalg, data, datalen, + oid_dgst + oid_len, dgst_len)) == -1) + fatal_fr(r, "hash failed"); + + /* XXX handle CKR_BUFFER_TOO_SMALL */ + if ((rv = f->C_Sign(si->session, (CK_BYTE *)oid_dgst, + oid_dgst_len, sig, &slen)) != CKR_OK) { + error("C_Sign failed: %lu", rv); + goto done; + } + + if (slen < (CK_ULONG)siglen) { + diff = siglen - slen; + debug3_f("repack %lu < %d (diff %d)", + (u_long)slen, siglen, diff); + memmove(sig + diff, sig, slen); + explicit_bzero(sig, diff); + } else if (slen > (size_t)siglen) + fatal_f("bad C_Sign length"); + + if ((ret = ssh_rsa_encode_store_sig(hashalg, sig, siglen, + sigp, lenp)) != 0) + fatal_fr(ret, "couldn't store signature"); + + /* success */ + ret = 0; + done: + freezero(oid_dgst, oid_dgst_len); + free(sig); + return ret; } -#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW) -/* openssl callback doing the actual signing operation */ -static ECDSA_SIG * -ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv, - const BIGNUM *rp, EC_KEY *ec) +#ifdef OPENSSL_HAS_ECC +static int +pkcs11_sign_ecdsa(struct sshkey *key, + u_char **sigp, size_t *lenp, + const u_char *data, size_t datalen, + const char *alg, const char *sk_provider, + const char *sk_pin, u_int compat) { struct pkcs11_key *k11; struct pkcs11_slotinfo *si; CK_FUNCTION_LIST *f; - CK_ULONG siglen = 0, bnlen; + CK_ULONG slen = 0, bnlen; CK_RV rv; - ECDSA_SIG *ret = NULL; - u_char *sig; - BIGNUM *r = NULL, *s = NULL; + BIGNUM *sig_r = NULL, *sig_s = NULL; + u_char *sig = NULL, *dgst = NULL; + size_t dgst_len = 0; + int hashalg, ret = -1, r, siglen; - if ((k11 = EC_KEY_get_ex_data(ec, ec_key_idx)) == NULL) { - ossl_error("EC_KEY_get_ex_data failed for ec"); - return (NULL); + if (sigp != NULL) + *sigp = 0; + if (lenp != NULL) + *lenp = 0; + + if ((k11 = pkcs11_lookup_key(key)) == NULL) { + error_f("no key found"); + return SSH_ERR_KEY_NOT_FOUND; } if (pkcs11_get_key(k11, CKM_ECDSA) == -1) { error("pkcs11_get_key failed"); - return (NULL); + return SSH_ERR_AGENT_FAILURE; } + debug3_f("sign using provider %s slotidx %lu", + k11->provider->name, (u_long)k11->slotidx); + f = k11->provider->function_list; si = &k11->provider->slotinfo[k11->slotidx]; - siglen = ECDSA_size(ec); + /* Prepare digest to be signed */ + if ((hashalg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1) + fatal_f("couldn't determine ECDSA hash alg"); + if ((dgst_len = ssh_digest_bytes(hashalg)) == 0) + fatal_f("bad hash alg %d", hashalg); + dgst = xcalloc(1, dgst_len); + if ((r = ssh_digest_memory(hashalg, data, datalen, + dgst, dgst_len)) == -1) + fatal_fr(r, "hash failed"); + + if ((siglen = EVP_PKEY_size(key->pkey)) <= 0) + return SSH_ERR_INVALID_ARGUMENT; sig = xmalloc(siglen); + slen = (CK_ULONG)siglen; /* XXX handle CKR_BUFFER_TOO_SMALL */ - rv = f->C_Sign(si->session, (CK_BYTE *)dgst, dgst_len, sig, &siglen); + rv = f->C_Sign(si->session, (CK_BYTE *)dgst, dgst_len, sig, &slen); if (rv != CKR_OK) { error("C_Sign failed: %lu", rv); goto done; } - if (siglen < 64 || siglen > 132 || siglen % 2) { - error_f("bad signature length: %lu", (u_long)siglen); - goto done; - } - bnlen = siglen/2; - if ((ret = ECDSA_SIG_new()) == NULL) { - error("ECDSA_SIG_new failed"); + if (slen < 64 || slen > 132 || slen % 2) { + error_f("bad signature length: %lu", (u_long)slen); goto done; } - if ((r = BN_bin2bn(sig, bnlen, NULL)) == NULL || - (s = BN_bin2bn(sig+bnlen, bnlen, NULL)) == NULL) { + bnlen = slen/2; + if ((sig_r = BN_bin2bn(sig, bnlen, NULL)) == NULL || + (sig_s = BN_bin2bn(sig+bnlen, bnlen, NULL)) == NULL) { ossl_error("BN_bin2bn failed"); - ECDSA_SIG_free(ret); - ret = NULL; goto done; } - if (!ECDSA_SIG_set0(ret, r, s)) { - error_f("ECDSA_SIG_set0 failed"); - ECDSA_SIG_free(ret); - ret = NULL; - goto done; - } - r = s = NULL; /* now owned by ret */ + + if ((ret = ssh_ecdsa_encode_store_sig(key, sig_r, sig_s, + sigp, lenp)) != 0) + fatal_fr(ret, "couldn't store signature"); + /* success */ + ret = 0; done: - BN_free(r); - BN_free(s); + freezero(dgst, dgst_len); + BN_free(sig_r); + BN_free(sig_s); free(sig); - - return (ret); + return ret; } - -static int -pkcs11_ecdsa_start_wrapper(void) -{ - int (*orig_sign)(int, const unsigned char *, int, unsigned char *, - unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *) = NULL; - - if (ec_key_method != NULL) - return (0); - ec_key_idx = EC_KEY_get_ex_new_index(0, "ssh-pkcs11-ecdsa", - NULL, NULL, pkcs11_k11_free); - if (ec_key_idx == -1) - return (-1); - ec_key_method = EC_KEY_METHOD_new(EC_KEY_OpenSSL()); - if (ec_key_method == NULL) - return (-1); - EC_KEY_METHOD_get_sign(ec_key_method, &orig_sign, NULL, NULL); - EC_KEY_METHOD_set_sign(ec_key_method, orig_sign, NULL, ecdsa_do_sign); - return (0); -} - -static int -pkcs11_ecdsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx, - CK_ATTRIBUTE *keyid_attrib, EC_KEY *ec) -{ - struct pkcs11_key *k11; - - if (pkcs11_ecdsa_start_wrapper() == -1) - return (-1); - - k11 = xcalloc(1, sizeof(*k11)); - k11->provider = provider; - provider->refcount++; /* provider referenced by ECDSA key */ - k11->slotidx = slotidx; - /* identify key object on smartcard */ - k11->keyid_len = keyid_attrib->ulValueLen; - if (k11->keyid_len > 0) { - k11->keyid = xmalloc(k11->keyid_len); - memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len); - } - if (EC_KEY_set_method(ec, ec_key_method) != 1) - fatal_f("EC_KEY_set_method failed"); - if (EC_KEY_set_ex_data(ec, ec_key_idx, k11) != 1) - fatal_f("EC_KEY_set_ex_data failed"); - - return (0); -} -#endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */ +#endif /* OPENSSL_HAS_ECC */ +#endif /* WITH_OPENSSL */ /* remove trailing spaces */ static char * @@ -702,7 +788,8 @@ pkcs11_key_included(struct sshkey ***keysp, int *nkeys, struct sshkey *key) return (0); } -#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW) +#ifdef WITH_OPENSSL +#ifdef OPENSSL_HAS_ECC static struct sshkey * pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, CK_OBJECT_HANDLE *obj) @@ -716,8 +803,7 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, EC_GROUP *group = NULL; struct sshkey *key = NULL; const unsigned char *attrp = NULL; - int i; - int nid; + int success = -1, r, i, nid; memset(&key_attr, 0, sizeof(key_attr)); key_attr[0].type = CKA_ID; @@ -791,6 +877,11 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, ossl_error("o2i_ECPublicKey failed"); goto fail; } + if ((r = sshkey_ec_validate_public(EC_KEY_get0_group(ec), + EC_KEY_get0_public_key(ec))) != 0) { + error_fr(r, "invalid EC key"); + goto fail; + } nid = sshkey_ecdsa_key_to_nid(ec); if (nid < 0) { @@ -798,9 +889,6 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, goto fail; } - if (pkcs11_ecdsa_wrap(p, slotidx, &key_attr[0], ec)) - goto fail; - key = sshkey_new(KEY_UNSPEC); if (key == NULL) { error("sshkey_new failed"); @@ -815,8 +903,15 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, key->ecdsa_nid = nid; key->type = KEY_ECDSA; key->flags |= SSHKEY_FLAG_EXT; - + if (pkcs11_record_key(p, slotidx, &key_attr[0], key)) + goto fail; + /* success */ + success = 0; fail: + if (success != 0) { + sshkey_free(key); + key = NULL; + } for (i = 0; i < 3; i++) free(key_attr[i].pValue); if (ec) @@ -828,7 +923,7 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, return (key); } -#endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */ +#endif /* OPENSSL_HAS_ECC */ static struct sshkey * pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, @@ -841,7 +936,7 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, RSA *rsa = NULL; BIGNUM *rsa_n, *rsa_e; struct sshkey *key = NULL; - int i; + int i, success = -1; memset(&key_attr, 0, sizeof(key_attr)); key_attr[0].type = CKA_ID; @@ -897,9 +992,6 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, fatal_f("set key"); rsa_n = rsa_e = NULL; /* transferred */ - if (pkcs11_rsa_wrap(p, slotidx, &key_attr[0], rsa)) - goto fail; - key = sshkey_new(KEY_UNSPEC); if (key == NULL) { error("sshkey_new failed"); @@ -913,13 +1005,24 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, fatal("EVP_PKEY_set1_RSA failed"); key->type = KEY_RSA; key->flags |= SSHKEY_FLAG_EXT; - + if (EVP_PKEY_bits(key->pkey) < SSH_RSA_MINIMUM_MODULUS_SIZE) { + error_f("RSA key too small %d < minumum %d", + EVP_PKEY_bits(key->pkey), SSH_RSA_MINIMUM_MODULUS_SIZE); + goto fail; + } + if (pkcs11_record_key(p, slotidx, &key_attr[0], key)) + goto fail; + /* success */ + success = 0; fail: for (i = 0; i < 3; i++) free(key_attr[i].pValue); RSA_free(rsa); - - return (key); + if (success != 0) { + sshkey_free(key); + key = NULL; + } + return key; } static int @@ -934,14 +1037,9 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, X509_NAME *x509_name = NULL; EVP_PKEY *evp; RSA *rsa = NULL; -#ifdef OPENSSL_HAS_ECC EC_KEY *ec = NULL; -#endif struct sshkey *key = NULL; - int i; -#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW) - int nid; -#endif + int r, i, nid, success = -1; const u_char *cp; char *subject = NULL; @@ -1015,9 +1113,6 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, goto out; } - if (pkcs11_rsa_wrap(p, slotidx, &cert_attr[0], rsa)) - goto out; - key = sshkey_new(KEY_UNSPEC); if (key == NULL) { error("sshkey_new failed"); @@ -1031,7 +1126,16 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, fatal("EVP_PKEY_set1_RSA failed"); key->type = KEY_RSA; key->flags |= SSHKEY_FLAG_EXT; -#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW) + if (EVP_PKEY_bits(key->pkey) < SSH_RSA_MINIMUM_MODULUS_SIZE) { + error_f("RSA key too small %d < minumum %d", + EVP_PKEY_bits(key->pkey), + SSH_RSA_MINIMUM_MODULUS_SIZE); + goto out; + } + if (pkcs11_record_key(p, slotidx, &cert_attr[0], key)) + goto out; + /* success */ + success = 0; } else if (EVP_PKEY_base_id(evp) == EVP_PKEY_EC) { if (EVP_PKEY_get0_EC_KEY(evp) == NULL) { error("invalid x509; no ec key"); @@ -1041,16 +1145,17 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, error("EC_KEY_dup failed"); goto out; } - + if ((r = sshkey_ec_validate_public(EC_KEY_get0_group(ec), + EC_KEY_get0_public_key(ec))) != 0) { + error_fr(r, "invalid EC key"); + goto out; + } nid = sshkey_ecdsa_key_to_nid(ec); if (nid < 0) { error("couldn't get curve nid"); goto out; } - if (pkcs11_ecdsa_wrap(p, slotidx, &cert_attr[0], ec)) - goto out; - key = sshkey_new(KEY_UNSPEC); if (key == NULL) { error("sshkey_new failed"); @@ -1065,7 +1170,10 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, key->ecdsa_nid = nid; key->type = KEY_ECDSA; key->flags |= SSHKEY_FLAG_EXT; -#endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */ + if (pkcs11_record_key(p, slotidx, &cert_attr[0], key)) + goto out; + /* success */ + success = 0; } else { error("unknown certificate key type"); goto out; @@ -1075,10 +1183,9 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, free(cert_attr[i].pValue); X509_free(x509); RSA_free(rsa); -#ifdef OPENSSL_HAS_ECC EC_KEY_free(ec); -#endif - if (key == NULL) { + if (success != 0 || key == NULL) { + sshkey_free(key); free(subject); return -1; } @@ -1098,6 +1205,7 @@ have_rsa_key(const RSA *rsa) return rsa_n != NULL && rsa_e != NULL; } #endif +#endif /* WITH_OPENSSL */ static void note_key(struct pkcs11_provider *p, CK_ULONG slotidx, const char *context, @@ -1289,15 +1397,16 @@ pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, case CKK_RSA: key = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj); break; -#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW) +#if defined(OPENSSL_HAS_ECC) case CKK_ECDSA: key = pkcs11_fetch_ecdsa_pubkey(p, slotidx, &obj); break; -#endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */ +#endif /* OPENSSL_HAS_ECC */ default: /* XXX print key type? */ key = NULL; - error("skipping unsupported key type"); + error("skipping unsupported key type 0x%lx", + (u_long)ck_key_type); } if (key == NULL) { @@ -1693,6 +1802,35 @@ pkcs11_register_provider(char *provider_id, char *pin, return (ret); } +int +pkcs11_init(int interactive) +{ + debug3_f("called, interactive = %d", interactive); + + pkcs11_interactive = interactive; + TAILQ_INIT(&pkcs11_providers); + TAILQ_INIT(&pkcs11_keys); + return (0); +} + +/* unregister all providers, keys might still point to the providers */ +void +pkcs11_terminate(void) +{ + struct pkcs11_provider *p; + struct pkcs11_key *k11; + + debug3_f("called"); + + while ((k11 = TAILQ_FIRST(&pkcs11_keys)) != NULL) + pkcs11_k11_free(k11); + while ((p = TAILQ_FIRST(&pkcs11_providers)) != NULL) { + TAILQ_REMOVE(&pkcs11_providers, p, next); + pkcs11_provider_finalize(p); + pkcs11_provider_unref(p); + } +} + /* * register a new provider and get number of keys hold by the token, * fails if provider already exists @@ -1719,6 +1857,33 @@ pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp, return (nkeys); } +int +pkcs11_sign(struct sshkey *key, + u_char **sigp, size_t *lenp, + const u_char *data, size_t datalen, + const char *alg, const char *sk_provider, + const char *sk_pin, u_int compat) +{ + switch (key->type) { + case KEY_RSA: + case KEY_RSA_CERT: + return pkcs11_sign_rsa(key, sigp, lenp, data, datalen, + alg, sk_provider, sk_pin, compat); + case KEY_ECDSA: + case KEY_ECDSA_CERT: + return pkcs11_sign_ecdsa(key, sigp, lenp, data, datalen, + alg, sk_provider, sk_pin, compat); + default: + return SSH_ERR_KEY_TYPE_UNKNOWN; + } +} + +void +pkcs11_key_free(struct sshkey *key) +{ + /* never called */ +} + #ifdef WITH_PKCS11_KEYGEN struct sshkey * pkcs11_gakp(char *provider_id, char *pin, unsigned int slotidx, char *label, diff --git a/ssh-pkcs11.h b/ssh-pkcs11.h index 526022319b4b..f3a03b6fa913 100644 --- a/ssh-pkcs11.h +++ b/ssh-pkcs11.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-pkcs11.h,v 1.7 2023/12/18 14:46:56 djm Exp $ */ +/* $OpenBSD: ssh-pkcs11.h,v 1.8 2025/07/24 05:44:55 djm Exp $ */ /* * Copyright (c) 2010 Markus Friedl. All rights reserved. * @@ -22,10 +22,17 @@ #define SSH_PKCS11_ERR_PIN_REQUIRED 4 #define SSH_PKCS11_ERR_PIN_LOCKED 5 +struct sshkey; + int pkcs11_init(int); void pkcs11_terminate(void); int pkcs11_add_provider(char *, char *, struct sshkey ***, char ***); int pkcs11_del_provider(char *); +int pkcs11_sign(struct sshkey *, u_char **, size_t *, + const u_char *, size_t, const char *, const char *, + const char *, u_int); +void pkcs11_key_free(struct sshkey *); + #ifdef WITH_PKCS11_KEYGEN struct sshkey * pkcs11_gakp(char *, char *, unsigned int, char *, unsigned int, @@ -35,9 +42,10 @@ struct sshkey * u_int32_t *); #endif -/* Only available in ssh-pkcs11-client.c so far */ +/* Only available in ssh-pkcs11-client.c */ int pkcs11_make_cert(const struct sshkey *, const struct sshkey *, struct sshkey **); + #if !defined(WITH_OPENSSL) && defined(ENABLE_PKCS11) #undef ENABLE_PKCS11 #endif diff --git a/ssh-rsa.c b/ssh-rsa.c index 3ad1fddc4e16..abc5b17fbeb7 100644 --- a/ssh-rsa.c +++ b/ssh-rsa.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-rsa.c,v 1.80 2024/08/15 00:51:51 djm Exp $ */ +/* $OpenBSD: ssh-rsa.c,v 1.81 2025/07/24 05:44:55 djm Exp $ */ /* * Copyright (c) 2000, 2003 Markus Friedl * @@ -309,8 +309,8 @@ ssh_rsa_deserialize_private(const char *ktype, struct sshbuf *b, return r; } -static const char * -rsa_hash_alg_ident(int hash_alg) +const char * +ssh_rsa_hash_alg_ident(int hash_alg) { switch (hash_alg) { case SSH_DIGEST_SHA1: @@ -344,8 +344,8 @@ rsa_hash_id_from_ident(const char *ident) * all the cases of rsa_hash_id_from_ident() but also the certificate key * types. */ -static int -rsa_hash_id_from_keyname(const char *alg) +int +ssh_rsa_hash_id_from_keyname(const char *alg) { int r; @@ -410,7 +410,6 @@ ssh_rsa_sign(struct sshkey *key, size_t diff, len = 0; int slen = 0; int hash_alg, ret = SSH_ERR_INTERNAL_ERROR; - struct sshbuf *b = NULL; if (lenp != NULL) *lenp = 0; @@ -420,7 +419,7 @@ ssh_rsa_sign(struct sshkey *key, if (alg == NULL || strlen(alg) == 0) hash_alg = SSH_DIGEST_SHA1; else - hash_alg = rsa_hash_id_from_keyname(alg); + hash_alg = ssh_rsa_hash_id_from_keyname(alg); if (key == NULL || key->pkey == NULL || hash_alg == -1 || sshkey_type_plain(key->type) != KEY_RSA) @@ -442,16 +441,42 @@ ssh_rsa_sign(struct sshkey *key, ret = SSH_ERR_INTERNAL_ERROR; goto out; } + if ((ret = ssh_rsa_encode_store_sig(hash_alg, sig, slen, + sigp, lenp)) != 0) + goto out; + + /* success */ + ret = 0; + out: + freezero(sig, slen); + return ret; +} - /* encode signature */ +int +ssh_rsa_encode_store_sig(int hash_alg, const u_char *sig, size_t slen, + u_char **sigp, size_t *lenp) +{ + struct sshbuf *b = NULL; + int ret = SSH_ERR_INTERNAL_ERROR; + size_t len; + + if (lenp != NULL) + *lenp = 0; + if (sigp != NULL) + *sigp = NULL; + + /* Encode signature */ if ((b = sshbuf_new()) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } - if ((ret = sshbuf_put_cstring(b, rsa_hash_alg_ident(hash_alg))) != 0 || + if ((ret = sshbuf_put_cstring(b, + ssh_rsa_hash_alg_ident(hash_alg))) != 0 || (ret = sshbuf_put_string(b, sig, slen)) != 0) goto out; len = sshbuf_len(b); + + /* Store signature */ if (sigp != NULL) { if ((*sigp = malloc(len)) == NULL) { ret = SSH_ERR_ALLOC_FAIL; @@ -463,7 +488,6 @@ ssh_rsa_sign(struct sshkey *key, *lenp = len; ret = 0; out: - freezero(sig, slen); sshbuf_free(b); return ret; } @@ -502,7 +526,7 @@ ssh_rsa_verify(const struct sshkey *key, * legacy reasons, but otherwise the signature type should match. */ if (alg != NULL && strcmp(alg, "ssh-rsa-cert-v01@openssh.com") != 0) { - if ((want_alg = rsa_hash_id_from_keyname(alg)) == -1) { + if ((want_alg = ssh_rsa_hash_id_from_keyname(alg)) == -1) { ret = SSH_ERR_INVALID_ARGUMENT; goto out; } diff --git a/ssh-sk-helper.c b/ssh-sk-helper.c index 9857b632bfcb..806019c46a3d 100644 --- a/ssh-sk-helper.c +++ b/ssh-sk-helper.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-sk-helper.c,v 1.14 2022/12/04 11:03:11 dtucker Exp $ */ +/* $OpenBSD: ssh-sk-helper.c,v 1.15 2025/07/24 05:44:55 djm Exp $ */ /* * Copyright (c) 2019 Google LLC * @@ -45,6 +45,7 @@ #include "uidswap.h" #include "ssherr.h" #include "ssh-sk.h" +#include "ssh-pkcs11.h" #ifdef ENABLE_SK extern char *__progname; @@ -87,6 +88,22 @@ null_empty(char **s) *s = NULL; } +/* stubs */ +int +pkcs11_sign(struct sshkey *key, + u_char **sigp, size_t *lenp, + const u_char *data, size_t datalen, + const char *alg, const char *sk_provider, + const char *sk_pin, u_int compat) +{ + return SSH_ERR_INTERNAL_ERROR; +} + +void +pkcs11_key_free(struct sshkey *key) +{ +} + static struct sshbuf * process_sign(struct sshbuf *req) { diff --git a/sshbuf-misc.c b/sshbuf-misc.c index 201279faf0f2..bc92866db60a 100644 --- a/sshbuf-misc.c +++ b/sshbuf-misc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshbuf-misc.c,v 1.20 2025/06/16 09:02:19 dtucker Exp $ */ +/* $OpenBSD: sshbuf-misc.c,v 1.21 2025/07/24 05:44:55 djm Exp $ */ /* * Copyright (c) 2011 Damien Miller * @@ -285,6 +285,20 @@ sshbuf_cmp(const struct sshbuf *b, size_t offset, return 0; } +int +sshbuf_equals(const struct sshbuf *a, const struct sshbuf *b) +{ + if (sshbuf_ptr(a) == NULL || sshbuf_ptr(b) == NULL) + return SSH_ERR_INTERNAL_ERROR; + if (sshbuf_len(a) != sshbuf_len(b)) + return SSH_ERR_MESSAGE_INCOMPLETE; + if (sshbuf_len(a) == 0) + return 0; + if (memcmp(sshbuf_ptr(a), sshbuf_ptr(b), sshbuf_len(a)) != 0) + return SSH_ERR_INVALID_FORMAT; + return 0; +} + int sshbuf_find(const struct sshbuf *b, size_t start_offset, const void *s, size_t len, size_t *offsetp) diff --git a/sshbuf.h b/sshbuf.h index 681abb9eec03..f0cc4c5f8e38 100644 --- a/sshbuf.h +++ b/sshbuf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sshbuf.h,v 1.30 2025/05/21 06:43:48 djm Exp $ */ +/* $OpenBSD: sshbuf.h,v 1.31 2025/07/24 05:44:55 djm Exp $ */ /* * Copyright (c) 2011 Damien Miller * @@ -263,6 +263,15 @@ int sshbuf_b64tod(struct sshbuf *buf, const char *b64); int sshbuf_cmp(const struct sshbuf *b, size_t offset, const void *s, size_t len); +/* + * Test whether two buffers have identical contents. + * SSH_ERR_MESSAGE_INCOMPLETE indicates the buffers had differing size. + * SSH_ERR_INVALID_FORMAT indicates the buffers were the same size but + * had differing contents. + * Returns 0 on successful compare (comparing two empty buffers returns 0). + */ +int sshbuf_equals(const struct sshbuf *a, const struct sshbuf *b); + /* * Searches the buffer for the specified string. Returns 0 on success * and updates *offsetp with the offset of the first match, relative to diff --git a/sshkey.c b/sshkey.c index 9e31411e21d6..3b1335d99725 100644 --- a/sshkey.c +++ b/sshkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshkey.c,v 1.150 2025/05/12 05:41:20 tb Exp $ */ +/* $OpenBSD: sshkey.c,v 1.151 2025/07/24 05:44:55 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * Copyright (c) 2008 Alexander von Gernler. All rights reserved. @@ -60,6 +60,7 @@ #include "sshkey.h" #include "match.h" #include "ssh-sk.h" +#include "ssh-pkcs11.h" #ifdef WITH_XMSS #include "sshkey-xmss.h" @@ -778,6 +779,8 @@ sshkey_free_contents(struct sshkey *k) if (k == NULL) return; + if ((k->flags & SSHKEY_FLAG_EXT) != 0) + pkcs11_key_free(k); if ((impl = sshkey_impl_from_type(k->type)) != NULL && impl->funcs->cleanup != NULL) impl->funcs->cleanup(k); @@ -900,22 +903,29 @@ sshkey_putb(const struct sshkey *key, struct sshbuf *b) return to_blob_buf(key, b, 0, SSHKEY_SERIALIZE_DEFAULT); } -int -sshkey_puts_opts(const struct sshkey *key, struct sshbuf *b, - enum sshkey_serialize_rep opts) +static int +sshkey_puts_opts_internal(const struct sshkey *key, struct sshbuf *b, + enum sshkey_serialize_rep opts, int force_plain) { struct sshbuf *tmp; int r; if ((tmp = sshbuf_new()) == NULL) return SSH_ERR_ALLOC_FAIL; - r = to_blob_buf(key, tmp, 0, opts); + r = to_blob_buf(key, tmp, force_plain, opts); if (r == 0) r = sshbuf_put_stringb(b, tmp); sshbuf_free(tmp); return r; } +int +sshkey_puts_opts(const struct sshkey *key, struct sshbuf *b, + enum sshkey_serialize_rep opts) +{ + return sshkey_puts_opts_internal(key, b, opts, 0); +} + int sshkey_puts(const struct sshkey *key, struct sshbuf *b) { @@ -928,6 +938,12 @@ sshkey_putb_plain(const struct sshkey *key, struct sshbuf *b) return to_blob_buf(key, b, 1, SSHKEY_SERIALIZE_DEFAULT); } +int +sshkey_puts_plain(const struct sshkey *key, struct sshbuf *b) +{ + return sshkey_puts_opts_internal(key, b, SSHKEY_SERIALIZE_DEFAULT, 1); +} + static int to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp, int force_plain, enum sshkey_serialize_rep opts) @@ -2200,6 +2216,9 @@ sshkey_sign(struct sshkey *key, if (sshkey_is_sk(key)) { r = sshsk_sign(sk_provider, key, sigp, lenp, data, datalen, compat, sk_pin); + } else if ((key->flags & SSHKEY_FLAG_EXT) != 0) { + r = pkcs11_sign(key, sigp, lenp, data, datalen, + alg, sk_provider, sk_pin, compat); } else { if (impl->funcs->sign == NULL) r = SSH_ERR_SIGN_ALG_UNSUPPORTED; diff --git a/sshkey.h b/sshkey.h index 5fa410b9431d..13309416b6c8 100644 --- a/sshkey.h +++ b/sshkey.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sshkey.h,v 1.67 2025/05/06 05:40:56 djm Exp $ */ +/* $OpenBSD: sshkey.h,v 1.68 2025/07/24 05:44:55 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. @@ -275,6 +275,7 @@ int sshkey_puts_opts(const struct sshkey *, struct sshbuf *, enum sshkey_serialize_rep); int sshkey_plain_to_blob(const struct sshkey *, u_char **, size_t *); int sshkey_putb_plain(const struct sshkey *, struct sshbuf *); +int sshkey_puts_plain(const struct sshkey *, struct sshbuf *); int sshkey_sign(struct sshkey *, u_char **, size_t *, const u_char *, size_t, const char *, const char *, const char *, u_int); @@ -312,6 +313,12 @@ int sshkey_parse_pubkey_from_private_fileblob_type(struct sshbuf *blob, int type, struct sshkey **pubkeyp); int sshkey_check_rsa_length(const struct sshkey *, int); +int ssh_rsa_hash_id_from_keyname(const char *); +const char *ssh_rsa_hash_alg_ident(int); +int ssh_rsa_encode_store_sig(int, const u_char *, size_t, + u_char **, size_t *); +int ssh_ecdsa_encode_store_sig(const struct sshkey *, + const BIGNUM *, const BIGNUM *, u_char **, size_t *); /* XXX should be internal, but used by ssh-keygen */ int ssh_rsa_complete_crt_parameters(const BIGNUM *, const BIGNUM *, const BIGNUM *, const BIGNUM *, BIGNUM **, BIGNUM **); From 1641ab8744f500f55f12155d03f1a3116aaea374 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Thu, 24 Jul 2025 06:12:08 +0000 Subject: [PATCH 149/244] upstream: factor out encoding of a raw ed25519 signature into its ssh form into a separate function OpenBSD-Commit-ID: 3711c6d6b52dde0bd1f17884da5cddb8716f1b64 --- ssh-ed25519.c | 37 ++++++++++++++++++++++++++++++------- sshkey.h | 4 +++- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/ssh-ed25519.c b/ssh-ed25519.c index 22d8db026b4c..c8caa22214b7 100644 --- a/ssh-ed25519.c +++ b/ssh-ed25519.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-ed25519.c,v 1.19 2022/10/28 00:44:44 djm Exp $ */ +/* $OpenBSD: ssh-ed25519.c,v 1.20 2025/07/24 06:12:08 djm Exp $ */ /* * Copyright (c) 2013 Markus Friedl * @@ -149,10 +149,9 @@ ssh_ed25519_sign(struct sshkey *key, const char *alg, const char *sk_provider, const char *sk_pin, u_int compat) { u_char *sig = NULL; - size_t slen = 0, len; + size_t slen = 0; unsigned long long smlen; int r, ret; - struct sshbuf *b = NULL; if (lenp != NULL) *lenp = 0; @@ -173,13 +172,40 @@ ssh_ed25519_sign(struct sshkey *key, r = SSH_ERR_INVALID_ARGUMENT; /* XXX better error? */ goto out; } + if ((r = ssh_ed25519_encode_store_sig(sig, smlen - datalen, + sigp, lenp)) != 0) + goto out; + + /* success */ + r = 0; + out: + freezero(sig, slen); + return r; +} + +int +ssh_ed25519_encode_store_sig(const u_char *sig, size_t slen, + u_char **sigp, size_t *lenp) +{ + struct sshbuf *b = NULL; + int r = -1; + size_t len; + + if (lenp != NULL) + *lenp = 0; + if (sigp != NULL) + *sigp = NULL; + + if (slen != crypto_sign_ed25519_BYTES) + return SSH_ERR_INVALID_ARGUMENT; + /* encode signature */ if ((b = sshbuf_new()) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } if ((r = sshbuf_put_cstring(b, "ssh-ed25519")) != 0 || - (r = sshbuf_put_string(b, sig, smlen - datalen)) != 0) + (r = sshbuf_put_string(b, sig, slen)) != 0) goto out; len = sshbuf_len(b); if (sigp != NULL) { @@ -195,9 +221,6 @@ ssh_ed25519_sign(struct sshkey *key, r = 0; out: sshbuf_free(b); - if (sig != NULL) - freezero(sig, slen); - return r; } diff --git a/sshkey.h b/sshkey.h index 13309416b6c8..77253bc4e12a 100644 --- a/sshkey.h +++ b/sshkey.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sshkey.h,v 1.68 2025/07/24 05:44:55 djm Exp $ */ +/* $OpenBSD: sshkey.h,v 1.69 2025/07/24 06:12:08 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. @@ -319,6 +319,8 @@ int ssh_rsa_encode_store_sig(int, const u_char *, size_t, u_char **, size_t *); int ssh_ecdsa_encode_store_sig(const struct sshkey *, const BIGNUM *, const BIGNUM *, u_char **, size_t *); +int ssh_ed25519_encode_store_sig(const u_char *, size_t, + u_char **, size_t *); /* XXX should be internal, but used by ssh-keygen */ int ssh_rsa_complete_crt_parameters(const BIGNUM *, const BIGNUM *, const BIGNUM *, const BIGNUM *, BIGNUM **, BIGNUM **); From 9f8ccc3b81b53324cc489f3fe00f03c329c0acb2 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Thu, 24 Jul 2025 06:59:51 +0000 Subject: [PATCH 150/244] upstream: less stale reference to PKCS#1 1.5 hash OIDs; feedback from tb@ OpenBSD-Commit-ID: 9fda77978491a130a7b77d87d40c79277b796721 --- ssh-pkcs11.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c index 147c52049500..c28da677d4db 100644 --- a/ssh-pkcs11.c +++ b/ssh-pkcs11.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-pkcs11.c,v 1.65 2025/07/24 05:44:55 djm Exp $ */ +/* $OpenBSD: ssh-pkcs11.c,v 1.66 2025/07/24 06:59:51 djm Exp $ */ /* * Copyright (c) 2010 Markus Friedl. All rights reserved. * Copyright (c) 2014 Pedro Martelletto. All rights reserved. @@ -467,8 +467,7 @@ pkcs11_lookup_key(struct sshkey *key) #ifdef WITH_OPENSSL /* * See: - * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/ - * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn + * https://datatracker.ietf.org/doc/html/rfc8017#section-9.2 */ /* @@ -485,7 +484,6 @@ static const u_char id_sha1[] = { }; /* - * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html * id-sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) * organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2) * id-sha256(1) } @@ -500,7 +498,6 @@ static const u_char id_sha256[] = { }; /* - * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html * id-sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) * organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2) * id-sha256(3) } From bf33a73c40522ce60961d4fff316a7187fb06ca0 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Thu, 24 Jul 2025 23:27:04 +0000 Subject: [PATCH 151/244] upstream: this should include stdlib.h explicitly OpenBSD-Commit-ID: 1c0cc5c3838344b33ae4ab7aa62c01530357bf29 --- ssh-pkcs11-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssh-pkcs11-client.c b/ssh-pkcs11-client.c index 8aaa4d2d684c..a1bf85aa6b64 100644 --- a/ssh-pkcs11-client.c +++ b/ssh-pkcs11-client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-pkcs11-client.c,v 1.21 2025/07/24 05:44:55 djm Exp $ */ +/* $OpenBSD: ssh-pkcs11-client.c,v 1.22 2025/07/24 23:27:04 djm Exp $ */ /* * Copyright (c) 2010 Markus Friedl. All rights reserved. * Copyright (c) 2014 Pedro Martelletto. All rights reserved. From 2f5269938a8e4769f484c9d45419a86529078ede Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Fri, 25 Jul 2025 12:46:10 +1000 Subject: [PATCH 152/244] remove vestigial stub --- regress/misc/fuzz-harness/agent_fuzz_helper.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/regress/misc/fuzz-harness/agent_fuzz_helper.c b/regress/misc/fuzz-harness/agent_fuzz_helper.c index 2750221154e6..400b63156b7a 100644 --- a/regress/misc/fuzz-harness/agent_fuzz_helper.c +++ b/regress/misc/fuzz-harness/agent_fuzz_helper.c @@ -175,10 +175,3 @@ test_one(const uint8_t* s, size_t slen) cleanup_idtab(); cleanup_sockettab(); } - -int -pkcs11_make_cert(const struct sshkey *priv, - const struct sshkey *certpub, struct sshkey **certprivp) -{ - return -1; /* XXX */ -} From 03e9e993ef1ef5accc6457152278cab5988f9b3d Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Fri, 25 Jul 2025 12:46:59 +1000 Subject: [PATCH 153/244] include ssh-pkcs11-client.o as common dep --- regress/misc/fuzz-harness/Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/regress/misc/fuzz-harness/Makefile b/regress/misc/fuzz-harness/Makefile index 55dcc17175c4..999e0d32c5af 100644 --- a/regress/misc/fuzz-harness/Makefile +++ b/regress/misc/fuzz-harness/Makefile @@ -7,9 +7,10 @@ FUZZ_LIBS=-L/usr/lib/llvm-16/lib -lFuzzer CFLAGS=-D_GNU_SOURCE=1 -O2 -g -Wall -Wextra -Wno-unused-parameter -Wno-exceptions -Wno-deprecated -I ../../.. CXXFLAGS=$(CFLAGS) $(FUZZ_FLAGS) LDFLAGS=-L ../../.. -L ../../../openbsd-compat -g -LIBS=-lssh -lopenbsd-compat -lmd -lcrypto -lfido2 -lcbor $(FUZZ_LIBS) +COMMON_OBJS=../../../ssh-pkcs11-client.o +LIBS=$(COMMON_OBJS) -lssh -lopenbsd-compat -lmd -lcrypto -lfido2 -lcbor $(FUZZ_LIBS) SK_NULL_OBJS=ssh-sk-null.o -COMMON_DEPS=../../../libssh.a +COMMON_DEPS=../../../libssh.a $(COMMON_OBJS) TARGETS=pubkey_fuzz sig_fuzz authopt_fuzz authkeys_fuzz sshsig_fuzz \ sshsigopt_fuzz privkey_fuzz kex_fuzz agent_fuzz \ From 33b4f05c8ddab24aa6c47afb313b8cbd0d4b77f4 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Fri, 25 Jul 2025 12:47:17 +1000 Subject: [PATCH 154/244] update clang-16 -> clang-19 --- regress/misc/fuzz-harness/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/regress/misc/fuzz-harness/Makefile b/regress/misc/fuzz-harness/Makefile index 999e0d32c5af..2963ba6824e8 100644 --- a/regress/misc/fuzz-harness/Makefile +++ b/regress/misc/fuzz-harness/Makefile @@ -1,8 +1,8 @@ # NB. libssh and libopenbsd-compat should be built with the same sanitizer opts. -CC=clang-16 -CXX=clang++-16 +CC=clang-19 +CXX=clang++-19 FUZZ_FLAGS=-fsanitize=address,fuzzer -fno-omit-frame-pointer -FUZZ_LIBS=-L/usr/lib/llvm-16/lib -lFuzzer +FUZZ_LIBS=-L/usr/lib/llvm-19/lib -lFuzzer CFLAGS=-D_GNU_SOURCE=1 -O2 -g -Wall -Wextra -Wno-unused-parameter -Wno-exceptions -Wno-deprecated -I ../../.. CXXFLAGS=$(CFLAGS) $(FUZZ_FLAGS) From 203f5ac6cfa0e257db7509d4bb830e8a4bba6211 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Thu, 24 Jul 2025 06:04:47 +0000 Subject: [PATCH 155/244] upstream: test code now needs to link ssh-pkcs11-client.c any time sshkey.c is included OpenBSD-Regress-ID: 9d07188eae9a96801c3150b3433bb220626d4443 --- Makefile.in | 12 ++++++------ regress/unittests/authopt/Makefile | 4 ++-- regress/unittests/hostkeys/Makefile | 4 ++-- regress/unittests/kex/Makefile | 4 ++-- regress/unittests/sshkey/Makefile | 4 ++-- regress/unittests/sshsig/Makefile | 4 ++-- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Makefile.in b/Makefile.in index 399c8ae6ec56..9e45d522088b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -613,7 +613,7 @@ UNITTESTS_TEST_SSHKEY_OBJS=\ regress/unittests/sshkey/common.o \ regress/unittests/sshkey/test_file.o \ regress/unittests/sshkey/test_sshkey.o \ - $(SKOBJS) + $(P11OBJS) $(SKOBJS) regress/unittests/sshkey/test_sshkey$(EXEEXT): ${UNITTESTS_TEST_SSHKEY_OBJS} \ regress/unittests/test_helper/libtest_helper.a libssh.a @@ -624,7 +624,7 @@ regress/unittests/sshkey/test_sshkey$(EXEEXT): ${UNITTESTS_TEST_SSHKEY_OBJS} \ UNITTESTS_TEST_SSHSIG_OBJS=\ sshsig.o \ regress/unittests/sshsig/tests.o \ - $(SKOBJS) + $(P11OBJS) $(SKOBJS) regress/unittests/sshsig/test_sshsig$(EXEEXT): ${UNITTESTS_TEST_SSHSIG_OBJS} \ regress/unittests/test_helper/libtest_helper.a libssh.a @@ -644,7 +644,7 @@ regress/unittests/bitmap/test_bitmap$(EXEEXT): ${UNITTESTS_TEST_BITMAP_OBJS} \ UNITTESTS_TEST_AUTHOPT_OBJS=\ regress/unittests/authopt/tests.o \ auth-options.o \ - $(SKOBJS) + $(P11OBJS) $(SKOBJS) regress/unittests/authopt/test_authopt$(EXEEXT): \ ${UNITTESTS_TEST_AUTHOPT_OBJS} \ @@ -667,7 +667,7 @@ UNITTESTS_TEST_KEX_OBJS=\ regress/unittests/kex/tests.o \ regress/unittests/kex/test_kex.o \ regress/unittests/kex/test_proposal.o \ - $(SKOBJS) + $(P11OBJS) $(SKOBJS) regress/unittests/kex/test_kex$(EXEEXT): ${UNITTESTS_TEST_KEX_OBJS} \ regress/unittests/test_helper/libtest_helper.a libssh.a @@ -678,7 +678,7 @@ regress/unittests/kex/test_kex$(EXEEXT): ${UNITTESTS_TEST_KEX_OBJS} \ UNITTESTS_TEST_HOSTKEYS_OBJS=\ regress/unittests/hostkeys/tests.o \ regress/unittests/hostkeys/test_iterate.o \ - $(SKOBJS) + $(P11OBJS) $(SKOBJS) regress/unittests/hostkeys/test_hostkeys$(EXEEXT): \ ${UNITTESTS_TEST_HOSTKEYS_OBJS} \ @@ -741,7 +741,7 @@ regress/misc/sk-dummy/sk-dummy.so: $(SK_DUMMY_OBJS) SSH_VERIFY_ATTESTATION_OBJS=\ regress/misc/ssh-verify-attestation/ssh-verify-attestation.o \ - $(SKOBJS) + $(P11OBJS) $(SKOBJS) ssh-verify-attestation: regress/misc/ssh-verify-attestation/ssh-verify-attestation$(EXEEXT) diff --git a/regress/unittests/authopt/Makefile b/regress/unittests/authopt/Makefile index d5ea2c796be1..1ecaa30ce343 100644 --- a/regress/unittests/authopt/Makefile +++ b/regress/unittests/authopt/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.9 2025/05/06 06:05:48 djm Exp $ +# $OpenBSD: Makefile,v 1.10 2025/07/24 06:04:47 djm Exp $ PROG=test_authopt SRCS=tests.c @@ -13,7 +13,7 @@ SRCS+=ssherr.c uidswap.c cleanup.c xmalloc.c match.c krl.c fatal.c SRCS+=addr.c addrmatch.c bitmap.c SRCS+=ed25519.c hash.c SRCS+=cipher-chachapoly.c chacha.c poly1305.c ssh-ecdsa-sk.c ssh-sk.c -SRCS+=ssh-ed25519-sk.c sk-usbhid.c +SRCS+=ssh-ed25519-sk.c sk-usbhid.c ssh-pkcs11-client.c SRCS+=digest-openssl.c #SRCS+=digest-libc.c diff --git a/regress/unittests/hostkeys/Makefile b/regress/unittests/hostkeys/Makefile index 142ffa632aad..76c8e67f8aa1 100644 --- a/regress/unittests/hostkeys/Makefile +++ b/regress/unittests/hostkeys/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.12 2025/05/06 06:05:48 djm Exp $ +# $OpenBSD: Makefile,v 1.13 2025/07/24 06:04:47 djm Exp $ PROG=test_hostkeys SRCS=tests.c test_iterate.c @@ -11,7 +11,7 @@ SRCS+=ssherr.c uidswap.c cleanup.c xmalloc.c match.c krl.c fatal.c SRCS+=addr.c addrmatch.c bitmap.c hostfile.c SRCS+=ed25519.c hash.c SRCS+=cipher-chachapoly.c chacha.c poly1305.c ssh-ecdsa-sk.c ssh-sk.c -SRCS+=ssh-ed25519-sk.c sk-usbhid.c +SRCS+=ssh-ed25519-sk.c sk-usbhid.c ssh-pkcs11-client.c SRCS+=digest-openssl.c #SRCS+=digest-libc.c diff --git a/regress/unittests/kex/Makefile b/regress/unittests/kex/Makefile index 645fb0609733..5201a35df5bc 100644 --- a/regress/unittests/kex/Makefile +++ b/regress/unittests/kex/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.18 2025/05/06 06:05:48 djm Exp $ +# $OpenBSD: Makefile,v 1.19 2025/07/24 06:04:47 djm Exp $ PROG=test_kex SRCS=tests.c test_kex.c test_proposal.c @@ -11,7 +11,7 @@ SRCS+=ssherr.c uidswap.c cleanup.c xmalloc.c match.c krl.c fatal.c SRCS+=addr.c addrmatch.c bitmap.c packet.c dispatch.c canohost.c ssh_api.c SRCS+=compat.c ed25519.c hash.c SRCS+=cipher-chachapoly.c chacha.c poly1305.c ssh-ecdsa-sk.c ssh-sk.c -SRCS+=ssh-ed25519-sk.c sk-usbhid.c +SRCS+=ssh-ed25519-sk.c sk-usbhid.c ssh-pkcs11-client.c SRCS+= kex.c SRCS+= kex-names.c diff --git a/regress/unittests/sshkey/Makefile b/regress/unittests/sshkey/Makefile index b237ff55c8d3..77d07d1b550e 100644 --- a/regress/unittests/sshkey/Makefile +++ b/regress/unittests/sshkey/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.13 2025/05/06 06:05:48 djm Exp $ +# $OpenBSD: Makefile,v 1.14 2025/07/24 06:04:47 djm Exp $ PROG=test_sshkey SRCS=tests.c test_sshkey.c test_file.c test_fuzz.c common.c @@ -11,7 +11,7 @@ SRCS+=ssherr.c uidswap.c cleanup.c xmalloc.c match.c krl.c fatal.c SRCS+=addr.c addrmatch.c bitmap.c SRCS+=ed25519.c hash.c SRCS+=cipher-chachapoly.c chacha.c poly1305.c ssh-ecdsa-sk.c ssh-sk.c -SRCS+=ssh-ed25519-sk.c sk-usbhid.c +SRCS+=ssh-ed25519-sk.c sk-usbhid.c ssh-pkcs11-client.c SRCS+=digest-openssl.c #SRCS+=digest-libc.c diff --git a/regress/unittests/sshsig/Makefile b/regress/unittests/sshsig/Makefile index f8b6560eba18..f2f03e843856 100644 --- a/regress/unittests/sshsig/Makefile +++ b/regress/unittests/sshsig/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.4 2025/05/06 06:05:48 djm Exp $ +# $OpenBSD: Makefile,v 1.5 2025/07/24 06:04:47 djm Exp $ PROG=test_sshsig SRCS=tests.c @@ -11,7 +11,7 @@ SRCS+=ssherr.c uidswap.c cleanup.c xmalloc.c match.c krl.c fatal.c SRCS+=addr.c addrmatch.c bitmap.c sshsig.c SRCS+=ed25519.c hash.c SRCS+=cipher-chachapoly.c chacha.c poly1305.c ssh-ecdsa-sk.c ssh-sk.c -SRCS+=ssh-ed25519-sk.c sk-usbhid.c +SRCS+=ssh-ed25519-sk.c sk-usbhid.c ssh-pkcs11-client.c SRCS+=digest-openssl.c #SRCS+=digest-libc.c From eedab8db12d57c4f4583f6b60e48a4ce25b47b9c Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Fri, 25 Jul 2025 16:21:43 +1000 Subject: [PATCH 156/244] unbreak !EC builds --- ssh-pkcs11.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c index c28da677d4db..ee6bf77d83b9 100644 --- a/ssh-pkcs11.c +++ b/ssh-pkcs11.c @@ -86,7 +86,7 @@ TAILQ_HEAD(, pkcs11_key) pkcs11_keys; /* XXX a tree would be better */ int pkcs11_interactive = 0; -#ifdef WITH_OPENSSL +#ifdef OPENSSL_HAS_ECC static void ossl_error(const char *msg) { @@ -1133,6 +1133,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, goto out; /* success */ success = 0; +#if defined(OPENSSL_HAS_ECC) } else if (EVP_PKEY_base_id(evp) == EVP_PKEY_EC) { if (EVP_PKEY_get0_EC_KEY(evp) == NULL) { error("invalid x509; no ec key"); @@ -1171,6 +1172,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, goto out; /* success */ success = 0; +#endif /* OPENSSL_HAS_ECC */ } else { error("unknown certificate key type"); goto out; @@ -1866,10 +1868,12 @@ pkcs11_sign(struct sshkey *key, case KEY_RSA_CERT: return pkcs11_sign_rsa(key, sigp, lenp, data, datalen, alg, sk_provider, sk_pin, compat); +#if defined(OPENSSL_HAS_ECC) case KEY_ECDSA: case KEY_ECDSA_CERT: return pkcs11_sign_ecdsa(key, sigp, lenp, data, datalen, alg, sk_provider, sk_pin, compat); +#endif /* OPENSSL_HAS_ECC */ default: return SSH_ERR_KEY_TYPE_UNKNOWN; } From ed1e370d84e9dc39bc31c19cca12222d991fdc6f Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Fri, 25 Jul 2025 11:50:45 +0000 Subject: [PATCH 157/244] upstream: Don't snprintf a NULL since not all platforms support it. OpenBSD-Commit-ID: 6e0c268e40047e96fab6bc56dc340580b537183b --- ssh-pkcs11-client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssh-pkcs11-client.c b/ssh-pkcs11-client.c index a1bf85aa6b64..64b8f4c1c0ac 100644 --- a/ssh-pkcs11-client.c +++ b/ssh-pkcs11-client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-pkcs11-client.c,v 1.22 2025/07/24 23:27:04 djm Exp $ */ +/* $OpenBSD: ssh-pkcs11-client.c,v 1.23 2025/07/25 11:50:45 dtucker Exp $ */ /* * Copyright (c) 2010 Markus Friedl. All rights reserved. * Copyright (c) 2014 Pedro Martelletto. All rights reserved. @@ -450,7 +450,7 @@ pkcs11_del_provider(char *name) * ssh-agent deletes keys before calling this, so the helper entry * should be gone before we get here. */ - debug3_f("delete %s", name); + debug3_f("delete %s", name ? name : "(null)"); if ((helper = helper_by_provider(name)) != NULL) helper_terminate(helper); return 0; From 550d2a4a66c50f7641563a63b900761d99efb24a Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Fri, 25 Jul 2025 23:04:33 +1000 Subject: [PATCH 158/244] another attempt at fixing !EC builds --- ssh-pkcs11.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c index ee6bf77d83b9..e22b3e419fb5 100644 --- a/ssh-pkcs11.c +++ b/ssh-pkcs11.c @@ -1036,9 +1036,12 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, RSA *rsa = NULL; EC_KEY *ec = NULL; struct sshkey *key = NULL; - int r, i, nid, success = -1; + int i, success = -1; const u_char *cp; char *subject = NULL; +#ifdef OPENSSL_HAS_ECC + int r, nid; +#endif *keyp = NULL; *labelp = NULL; @@ -1133,7 +1136,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, goto out; /* success */ success = 0; -#if defined(OPENSSL_HAS_ECC) +#ifdef OPENSSL_HAS_ECC } else if (EVP_PKEY_base_id(evp) == EVP_PKEY_EC) { if (EVP_PKEY_get0_EC_KEY(evp) == NULL) { error("invalid x509; no ec key"); @@ -1182,7 +1185,9 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, free(cert_attr[i].pValue); X509_free(x509); RSA_free(rsa); +#ifdef OPENSSL_HAS_ECC EC_KEY_free(ec); +#endif /* OPENSSL_HAS_ECC */ if (success != 0 || key == NULL) { sshkey_free(key); free(subject); @@ -1396,7 +1401,7 @@ pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, case CKK_RSA: key = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj); break; -#if defined(OPENSSL_HAS_ECC) +#ifdef OPENSSL_HAS_ECC case CKK_ECDSA: key = pkcs11_fetch_ecdsa_pubkey(p, slotidx, &obj); break; @@ -1868,7 +1873,7 @@ pkcs11_sign(struct sshkey *key, case KEY_RSA_CERT: return pkcs11_sign_rsa(key, sigp, lenp, data, datalen, alg, sk_provider, sk_pin, compat); -#if defined(OPENSSL_HAS_ECC) +#ifdef OPENSSL_HAS_ECC case KEY_ECDSA: case KEY_ECDSA_CERT: return pkcs11_sign_ecdsa(key, sigp, lenp, data, datalen, From 2b530cc3005a71c5ba6b712978872fc9c147439c Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Fri, 25 Jul 2025 13:06:07 +0000 Subject: [PATCH 159/244] upstream: update our PKCS#11 API header to v3.0; feedback/ok tb@ OpenBSD-Commit-ID: e67fa6a26e515c2b1fb7b0d1519d138aafb3e017 --- pkcs11.h | 1502 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 1023 insertions(+), 479 deletions(-) diff --git a/pkcs11.h b/pkcs11.h index b01d58f9483a..707333f02f0f 100644 --- a/pkcs11.h +++ b/pkcs11.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pkcs11.h,v 1.3 2013/11/26 19:15:09 deraadt Exp $ */ +/* $OpenBSD: pkcs11.h,v 1.4 2025/07/25 13:06:07 djm Exp $ */ /* pkcs11.h Copyright 2006, 2007 g10 Code GmbH Copyright 2006 Andreas Jellinghaus @@ -64,9 +64,9 @@ extern "C" { version of this file, please consider deleting the revision macro (you may use a macro with a different name to keep track of your versions). */ -#define CRYPTOKI_VERSION_MAJOR 2 -#define CRYPTOKI_VERSION_MINOR 20 -#define CRYPTOKI_VERSION_REVISION 6 +#define CRYPTOKI_VERSION_MAJOR 3 +#define CRYPTOKI_VERSION_MINOR 0 +#define CRYPTOKI_VERSION_REVISION 0 /* Compatibility interface is default, unless CRYPTOKI_GNU is @@ -96,7 +96,6 @@ extern "C" { #endif - #ifdef CRYPTOKI_COMPAT /* If we are in compatibility mode, switch all exposed names to the PKCS #11 variant. There are corresponding #undefs below. */ @@ -155,6 +154,8 @@ extern "C" { #define ck_mechanism_type_t CK_MECHANISM_TYPE +#define ck_rsa_pkcs_mgf_type_t CK_RSA_PKCS_MGF_TYPE + #define ck_mechanism _CK_MECHANISM #define parameter pParameter #define parameter_len ulParameterLen @@ -166,7 +167,10 @@ extern "C" { #define ck_rv_t CK_RV #define ck_notify_t CK_NOTIFY +#define ck_interface CK_INTERFACE + #define ck_function_list _CK_FUNCTION_LIST +#define ck_function_list_3_0 _CK_FUNCTION_LIST_3_0 #define ck_createmutex_t CK_CREATEMUTEX #define ck_destroymutex_t CK_DESTROYMUTEX @@ -183,7 +187,6 @@ extern "C" { #endif /* CRYPTOKI_COMPAT */ - typedef unsigned long ck_flags_t; struct ck_version @@ -205,7 +208,7 @@ struct ck_info typedef unsigned long ck_notification_t; -#define CKN_SURRENDER (0) +#define CKN_SURRENDER (0UL) typedef unsigned long ck_slot_id_t; @@ -221,10 +224,10 @@ struct ck_slot_info }; -#define CKF_TOKEN_PRESENT (1 << 0) -#define CKF_REMOVABLE_DEVICE (1 << 1) -#define CKF_HW_SLOT (1 << 2) -#define CKF_ARRAY_ATTRIBUTE (1 << 30) +#define CKF_TOKEN_PRESENT (1UL << 0) +#define CKF_REMOVABLE_DEVICE (1UL << 1) +#define CKF_HW_SLOT (1UL << 2) +#define CKF_ARRAY_ATTRIBUTE (1UL << 30) struct ck_token_info @@ -250,48 +253,48 @@ struct ck_token_info }; -#define CKF_RNG (1 << 0) -#define CKF_WRITE_PROTECTED (1 << 1) -#define CKF_LOGIN_REQUIRED (1 << 2) -#define CKF_USER_PIN_INITIALIZED (1 << 3) -#define CKF_RESTORE_KEY_NOT_NEEDED (1 << 5) -#define CKF_CLOCK_ON_TOKEN (1 << 6) -#define CKF_PROTECTED_AUTHENTICATION_PATH (1 << 8) -#define CKF_DUAL_CRYPTO_OPERATIONS (1 << 9) -#define CKF_TOKEN_INITIALIZED (1 << 10) -#define CKF_SECONDARY_AUTHENTICATION (1 << 11) -#define CKF_USER_PIN_COUNT_LOW (1 << 16) -#define CKF_USER_PIN_FINAL_TRY (1 << 17) -#define CKF_USER_PIN_LOCKED (1 << 18) -#define CKF_USER_PIN_TO_BE_CHANGED (1 << 19) -#define CKF_SO_PIN_COUNT_LOW (1 << 20) -#define CKF_SO_PIN_FINAL_TRY (1 << 21) -#define CKF_SO_PIN_LOCKED (1 << 22) -#define CKF_SO_PIN_TO_BE_CHANGED (1 << 23) +#define CKF_RNG (1UL << 0) +#define CKF_WRITE_PROTECTED (1UL << 1) +#define CKF_LOGIN_REQUIRED (1UL << 2) +#define CKF_USER_PIN_INITIALIZED (1UL << 3) +#define CKF_RESTORE_KEY_NOT_NEEDED (1UL << 5) +#define CKF_CLOCK_ON_TOKEN (1UL << 6) +#define CKF_PROTECTED_AUTHENTICATION_PATH (1UL << 8) +#define CKF_DUAL_CRYPTO_OPERATIONS (1UL << 9) +#define CKF_TOKEN_INITIALIZED (1UL << 10) +#define CKF_SECONDARY_AUTHENTICATION (1UL << 11) +#define CKF_USER_PIN_COUNT_LOW (1UL << 16) +#define CKF_USER_PIN_FINAL_TRY (1UL << 17) +#define CKF_USER_PIN_LOCKED (1UL << 18) +#define CKF_USER_PIN_TO_BE_CHANGED (1UL << 19) +#define CKF_SO_PIN_COUNT_LOW (1UL << 20) +#define CKF_SO_PIN_FINAL_TRY (1UL << 21) +#define CKF_SO_PIN_LOCKED (1UL << 22) +#define CKF_SO_PIN_TO_BE_CHANGED (1UL << 23) #define CK_UNAVAILABLE_INFORMATION ((unsigned long) -1) -#define CK_EFFECTIVELY_INFINITE (0) +#define CK_EFFECTIVELY_INFINITE (0UL) typedef unsigned long ck_session_handle_t; -#define CK_INVALID_HANDLE (0) +#define CK_INVALID_HANDLE (0UL) typedef unsigned long ck_user_type_t; -#define CKU_SO (0) -#define CKU_USER (1) -#define CKU_CONTEXT_SPECIFIC (2) +#define CKU_SO (0UL) +#define CKU_USER (1UL) +#define CKU_CONTEXT_SPECIFIC (2UL) typedef unsigned long ck_state_t; -#define CKS_RO_PUBLIC_SESSION (0) -#define CKS_RO_USER_FUNCTIONS (1) -#define CKS_RW_PUBLIC_SESSION (2) -#define CKS_RW_USER_FUNCTIONS (3) -#define CKS_RW_SO_FUNCTIONS (4) +#define CKS_RO_PUBLIC_SESSION (0UL) +#define CKS_RO_USER_FUNCTIONS (1UL) +#define CKS_RW_PUBLIC_SESSION (2UL) +#define CKS_RW_USER_FUNCTIONS (3UL) +#define CKS_RW_SO_FUNCTIONS (4UL) struct ck_session_info @@ -302,8 +305,8 @@ struct ck_session_info unsigned long device_error; }; -#define CKF_RW_SESSION (1 << 1) -#define CKF_SERIAL_SESSION (1 << 2) +#define CKF_RW_SESSION (1UL << 1) +#define CKF_SERIAL_SESSION (1UL << 2) typedef unsigned long ck_object_handle_t; @@ -311,149 +314,194 @@ typedef unsigned long ck_object_handle_t; typedef unsigned long ck_object_class_t; -#define CKO_DATA (0) -#define CKO_CERTIFICATE (1) -#define CKO_PUBLIC_KEY (2) -#define CKO_PRIVATE_KEY (3) -#define CKO_SECRET_KEY (4) -#define CKO_HW_FEATURE (5) -#define CKO_DOMAIN_PARAMETERS (6) -#define CKO_MECHANISM (7) -#define CKO_VENDOR_DEFINED (1U << 31) - +#define CKO_DATA (0UL) +#define CKO_CERTIFICATE (1UL) +#define CKO_PUBLIC_KEY (2UL) +#define CKO_PRIVATE_KEY (3UL) +#define CKO_SECRET_KEY (4UL) +#define CKO_HW_FEATURE (5UL) +#define CKO_DOMAIN_PARAMETERS (6UL) +#define CKO_MECHANISM (7UL) +#define CKO_OTP_KEY (8UL) +#define CKO_PROFILE (9UL) +#define CKO_VENDOR_DEFINED (1UL << 31) + +#define CKP_INVALID_ID (0UL) +#define CKP_BASELINE_PROVIDER (1UL) +#define CKP_EXTENDED_PROVIDER (2UL) +#define CKP_AUTHENTICATION_TOKEN (3UL) +#define CKP_PUBLIC_CERTIFICATES_TOKEN (4UL) +#define CKP_VENDOR_DEFINED (1UL << 31) typedef unsigned long ck_hw_feature_type_t; -#define CKH_MONOTONIC_COUNTER (1) -#define CKH_CLOCK (2) -#define CKH_USER_INTERFACE (3) -#define CKH_VENDOR_DEFINED (1U << 31) +#define CKH_MONOTONIC_COUNTER (1UL) +#define CKH_CLOCK (2UL) +#define CKH_USER_INTERFACE (3UL) +#define CKH_VENDOR_DEFINED (1UL << 31) typedef unsigned long ck_key_type_t; -#define CKK_RSA (0) -#define CKK_DSA (1) -#define CKK_DH (2) -#define CKK_ECDSA (3) -#define CKK_EC (3) -#define CKK_X9_42_DH (4) -#define CKK_KEA (5) -#define CKK_GENERIC_SECRET (0x10) -#define CKK_RC2 (0x11) -#define CKK_RC4 (0x12) -#define CKK_DES (0x13) -#define CKK_DES2 (0x14) -#define CKK_DES3 (0x15) -#define CKK_CAST (0x16) -#define CKK_CAST3 (0x17) -#define CKK_CAST128 (0x18) -#define CKK_RC5 (0x19) -#define CKK_IDEA (0x1a) -#define CKK_SKIPJACK (0x1b) -#define CKK_BATON (0x1c) -#define CKK_JUNIPER (0x1d) -#define CKK_CDMF (0x1e) -#define CKK_AES (0x1f) -#define CKK_BLOWFISH (0x20) -#define CKK_TWOFISH (0x21) -#define CKK_VENDOR_DEFINED (1U << 31) +#define CKK_RSA (0UL) +#define CKK_DSA (1UL) +#define CKK_DH (2UL) +#define CKK_ECDSA (3UL) +#define CKK_EC (3UL) +#define CKK_X9_42_DH (4UL) +#define CKK_KEA (5UL) +#define CKK_GENERIC_SECRET (0x10UL) +#define CKK_RC2 (0x11UL) +#define CKK_RC4 (0x12UL) +#define CKK_DES (0x13UL) +#define CKK_DES2 (0x14UL) +#define CKK_DES3 (0x15UL) +#define CKK_CAST (0x16UL) +#define CKK_CAST3 (0x17UL) +#define CKK_CAST128 (0x18UL) +#define CKK_RC5 (0x19UL) +#define CKK_IDEA (0x1aUL) +#define CKK_SKIPJACK (0x1bUL) +#define CKK_BATON (0x1cUL) +#define CKK_JUNIPER (0x1dUL) +#define CKK_CDMF (0x1eUL) +#define CKK_AES (0x1fUL) +#define CKK_BLOWFISH (0x20UL) +#define CKK_TWOFISH (0x21UL) +#define CKK_GOSTR3410 (0x30UL) +#define CKK_GOSTR3411 (0x31UL) +#define CKK_GOST28147 (0x32UL) +#define CKK_EC_EDWARDS (0x40UL) +#define CKK_EC_MONTGOMERY (0x41UL) +#define CKK_HKDF (0x42UL) +#define CKK_VENDOR_DEFINED (1UL << 31) + +/* + * A mask for new GOST algorithms. + * For details visit https://tc26.ru/standarts/perevody/guidelines-the-pkcs-11-extensions-for-implementing-the-gost-r-34-10-2012-and-gost-r-34-11-2012-russian-standards-.html + */ +#define NSSCK_VENDOR_PKCS11_RU_TEAM (CKK_VENDOR_DEFINED | 0x54321000) +#define CK_VENDOR_PKCS11_RU_TEAM_TK26 NSSCK_VENDOR_PKCS11_RU_TEAM + +#define CKK_GOSTR3410_512 (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x003) typedef unsigned long ck_certificate_type_t; -#define CKC_X_509 (0) -#define CKC_X_509_ATTR_CERT (1) -#define CKC_WTLS (2) -#define CKC_VENDOR_DEFINED (1U << 31) +#define CKC_X_509 (0UL) +#define CKC_X_509_ATTR_CERT (1UL) +#define CKC_WTLS (2UL) +#define CKC_VENDOR_DEFINED (1UL << 31) typedef unsigned long ck_attribute_type_t; -#define CKA_CLASS (0) -#define CKA_TOKEN (1) -#define CKA_PRIVATE (2) -#define CKA_LABEL (3) -#define CKA_APPLICATION (0x10) -#define CKA_VALUE (0x11) -#define CKA_OBJECT_ID (0x12) -#define CKA_CERTIFICATE_TYPE (0x80) -#define CKA_ISSUER (0x81) -#define CKA_SERIAL_NUMBER (0x82) -#define CKA_AC_ISSUER (0x83) -#define CKA_OWNER (0x84) -#define CKA_ATTR_TYPES (0x85) -#define CKA_TRUSTED (0x86) -#define CKA_CERTIFICATE_CATEGORY (0x87) -#define CKA_JAVA_MIDP_SECURITY_DOMAIN (0x88) -#define CKA_URL (0x89) -#define CKA_HASH_OF_SUBJECT_PUBLIC_KEY (0x8a) -#define CKA_HASH_OF_ISSUER_PUBLIC_KEY (0x8b) -#define CKA_CHECK_VALUE (0x90) -#define CKA_KEY_TYPE (0x100) -#define CKA_SUBJECT (0x101) -#define CKA_ID (0x102) -#define CKA_SENSITIVE (0x103) -#define CKA_ENCRYPT (0x104) -#define CKA_DECRYPT (0x105) -#define CKA_WRAP (0x106) -#define CKA_UNWRAP (0x107) -#define CKA_SIGN (0x108) -#define CKA_SIGN_RECOVER (0x109) -#define CKA_VERIFY (0x10a) -#define CKA_VERIFY_RECOVER (0x10b) -#define CKA_DERIVE (0x10c) -#define CKA_START_DATE (0x110) -#define CKA_END_DATE (0x111) -#define CKA_MODULUS (0x120) -#define CKA_MODULUS_BITS (0x121) -#define CKA_PUBLIC_EXPONENT (0x122) -#define CKA_PRIVATE_EXPONENT (0x123) -#define CKA_PRIME_1 (0x124) -#define CKA_PRIME_2 (0x125) -#define CKA_EXPONENT_1 (0x126) -#define CKA_EXPONENT_2 (0x127) -#define CKA_COEFFICIENT (0x128) -#define CKA_PRIME (0x130) -#define CKA_SUBPRIME (0x131) -#define CKA_BASE (0x132) -#define CKA_PRIME_BITS (0x133) -#define CKA_SUB_PRIME_BITS (0x134) -#define CKA_VALUE_BITS (0x160) -#define CKA_VALUE_LEN (0x161) -#define CKA_EXTRACTABLE (0x162) -#define CKA_LOCAL (0x163) -#define CKA_NEVER_EXTRACTABLE (0x164) -#define CKA_ALWAYS_SENSITIVE (0x165) -#define CKA_KEY_GEN_MECHANISM (0x166) -#define CKA_MODIFIABLE (0x170) -#define CKA_ECDSA_PARAMS (0x180) -#define CKA_EC_PARAMS (0x180) -#define CKA_EC_POINT (0x181) -#define CKA_SECONDARY_AUTH (0x200) -#define CKA_AUTH_PIN_FLAGS (0x201) -#define CKA_ALWAYS_AUTHENTICATE (0x202) -#define CKA_WRAP_WITH_TRUSTED (0x210) -#define CKA_HW_FEATURE_TYPE (0x300) -#define CKA_RESET_ON_INIT (0x301) -#define CKA_HAS_RESET (0x302) -#define CKA_PIXEL_X (0x400) -#define CKA_PIXEL_Y (0x401) -#define CKA_RESOLUTION (0x402) -#define CKA_CHAR_ROWS (0x403) -#define CKA_CHAR_COLUMNS (0x404) -#define CKA_COLOR (0x405) -#define CKA_BITS_PER_PIXEL (0x406) -#define CKA_CHAR_SETS (0x480) -#define CKA_ENCODING_METHODS (0x481) -#define CKA_MIME_TYPES (0x482) -#define CKA_MECHANISM_TYPE (0x500) -#define CKA_REQUIRED_CMS_ATTRIBUTES (0x501) -#define CKA_DEFAULT_CMS_ATTRIBUTES (0x502) -#define CKA_SUPPORTED_CMS_ATTRIBUTES (0x503) -#define CKA_WRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE | 0x211) -#define CKA_UNWRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE | 0x212) -#define CKA_ALLOWED_MECHANISMS (CKF_ARRAY_ATTRIBUTE | 0x600) -#define CKA_VENDOR_DEFINED (1U << 31) +#define CKA_CLASS (0UL) +#define CKA_TOKEN (1UL) +#define CKA_PRIVATE (2UL) +#define CKA_LABEL (3UL) +#define CKA_UNIQUE_ID (4UL) +#define CKA_APPLICATION (0x10UL) +#define CKA_VALUE (0x11UL) +#define CKA_OBJECT_ID (0x12UL) +#define CKA_CERTIFICATE_TYPE (0x80UL) +#define CKA_ISSUER (0x81UL) +#define CKA_SERIAL_NUMBER (0x82UL) +#define CKA_AC_ISSUER (0x83UL) +#define CKA_OWNER (0x84UL) +#define CKA_ATTR_TYPES (0x85UL) +#define CKA_TRUSTED (0x86UL) +#define CKA_CERTIFICATE_CATEGORY (0x87UL) +#define CKA_JAVA_MIDP_SECURITY_DOMAIN (0x88UL) +#define CKA_URL (0x89UL) +#define CKA_HASH_OF_SUBJECT_PUBLIC_KEY (0x8aUL) +#define CKA_HASH_OF_ISSUER_PUBLIC_KEY (0x8bUL) +#define CKA_CHECK_VALUE (0x90UL) +#define CKA_KEY_TYPE (0x100UL) +#define CKA_SUBJECT (0x101UL) +#define CKA_ID (0x102UL) +#define CKA_SENSITIVE (0x103UL) +#define CKA_ENCRYPT (0x104UL) +#define CKA_DECRYPT (0x105UL) +#define CKA_WRAP (0x106UL) +#define CKA_UNWRAP (0x107UL) +#define CKA_SIGN (0x108UL) +#define CKA_SIGN_RECOVER (0x109UL) +#define CKA_VERIFY (0x10aUL) +#define CKA_VERIFY_RECOVER (0x10bUL) +#define CKA_DERIVE (0x10cUL) +#define CKA_START_DATE (0x110UL) +#define CKA_END_DATE (0x111UL) +#define CKA_MODULUS (0x120UL) +#define CKA_MODULUS_BITS (0x121UL) +#define CKA_PUBLIC_EXPONENT (0x122UL) +#define CKA_PRIVATE_EXPONENT (0x123UL) +#define CKA_PRIME_1 (0x124UL) +#define CKA_PRIME_2 (0x125UL) +#define CKA_EXPONENT_1 (0x126UL) +#define CKA_EXPONENT_2 (0x127UL) +#define CKA_COEFFICIENT (0x128UL) +#define CKA_PUBLIC_KEY_INFO (0x129UL) +#define CKA_PRIME (0x130UL) +#define CKA_SUBPRIME (0x131UL) +#define CKA_BASE (0x132UL) +#define CKA_PRIME_BITS (0x133UL) +#define CKA_SUB_PRIME_BITS (0x134UL) +#define CKA_VALUE_BITS (0x160UL) +#define CKA_VALUE_LEN (0x161UL) +#define CKA_EXTRACTABLE (0x162UL) +#define CKA_LOCAL (0x163UL) +#define CKA_NEVER_EXTRACTABLE (0x164UL) +#define CKA_ALWAYS_SENSITIVE (0x165UL) +#define CKA_KEY_GEN_MECHANISM (0x166UL) +#define CKA_MODIFIABLE (0x170UL) +#define CKA_COPYABLE (0x171UL) +#define CKA_DESTROYABLE (0x172UL) +#define CKA_ECDSA_PARAMS (0x180UL) +#define CKA_EC_PARAMS (0x180UL) +#define CKA_EC_POINT (0x181UL) +#define CKA_SECONDARY_AUTH (0x200UL) +#define CKA_AUTH_PIN_FLAGS (0x201UL) +#define CKA_ALWAYS_AUTHENTICATE (0x202UL) +#define CKA_WRAP_WITH_TRUSTED (0x210UL) +#define CKA_GOSTR3410_PARAMS (0x250UL) +#define CKA_GOSTR3411_PARAMS (0x251UL) +#define CKA_GOST28147_PARAMS (0x252UL) +#define CKA_HW_FEATURE_TYPE (0x300UL) +#define CKA_RESET_ON_INIT (0x301UL) +#define CKA_HAS_RESET (0x302UL) +#define CKA_PIXEL_X (0x400UL) +#define CKA_PIXEL_Y (0x401UL) +#define CKA_RESOLUTION (0x402UL) +#define CKA_CHAR_ROWS (0x403UL) +#define CKA_CHAR_COLUMNS (0x404UL) +#define CKA_COLOR (0x405UL) +#define CKA_BITS_PER_PIXEL (0x406UL) +#define CKA_CHAR_SETS (0x480UL) +#define CKA_ENCODING_METHODS (0x481UL) +#define CKA_MIME_TYPES (0x482UL) +#define CKA_MECHANISM_TYPE (0x500UL) +#define CKA_REQUIRED_CMS_ATTRIBUTES (0x501UL) +#define CKA_DEFAULT_CMS_ATTRIBUTES (0x502UL) +#define CKA_SUPPORTED_CMS_ATTRIBUTES (0x503UL) +#define CKA_WRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE | 0x211UL) +#define CKA_UNWRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE | 0x212UL) +#define CKA_OTP_FORMAT (0x220UL) +#define CKA_OTP_LENGTH (0x221UL) +#define CKA_OTP_TIME_INTERVAL (0x222UL) +#define CKA_OTP_USER_FRIENDLY_MODE (0x223UL) +#define CKA_OTP_CHALLENGE_REQUIREMENT (0x224UL) +#define CKA_OTP_TIME_REQUIREMENT (0x225UL) +#define CKA_OTP_COUNTER_REQUIREMENT (0x226UL) +#define CKA_OTP_PIN_REQUIREMENT (0x227UL) +#define CKA_OTP_USER_IDENTIFIER (0x22AUL) +#define CKA_OTP_SERVICE_IDENTIFIER (0x22BUL) +#define CKA_OTP_SERVICE_LOGO (0x22CUL) +#define CKA_OTP_SERVICE_LOGO_TYPE (0x22DUL) +#define CKA_OTP_COUNTER (0x22EUL) +#define CKA_OTP_TIME (0x22FUL) +#define CKA_ALLOWED_MECHANISMS (CKF_ARRAY_ATTRIBUTE | 0x600UL) +#define CKA_PROFILE_ID (0x601UL) +#define CKA_VENDOR_DEFINED (1UL << 31) struct ck_attribute @@ -474,206 +522,304 @@ struct ck_date typedef unsigned long ck_mechanism_type_t; -#define CKM_RSA_PKCS_KEY_PAIR_GEN (0) -#define CKM_RSA_PKCS (1) -#define CKM_RSA_9796 (2) -#define CKM_RSA_X_509 (3) -#define CKM_MD2_RSA_PKCS (4) -#define CKM_MD5_RSA_PKCS (5) -#define CKM_SHA1_RSA_PKCS (6) -#define CKM_RIPEMD128_RSA_PKCS (7) -#define CKM_RIPEMD160_RSA_PKCS (8) -#define CKM_RSA_PKCS_OAEP (9) -#define CKM_RSA_X9_31_KEY_PAIR_GEN (0xa) -#define CKM_RSA_X9_31 (0xb) -#define CKM_SHA1_RSA_X9_31 (0xc) -#define CKM_RSA_PKCS_PSS (0xd) -#define CKM_SHA1_RSA_PKCS_PSS (0xe) -#define CKM_DSA_KEY_PAIR_GEN (0x10) -#define CKM_DSA (0x11) -#define CKM_DSA_SHA1 (0x12) -#define CKM_DH_PKCS_KEY_PAIR_GEN (0x20) -#define CKM_DH_PKCS_DERIVE (0x21) -#define CKM_X9_42_DH_KEY_PAIR_GEN (0x30) -#define CKM_X9_42_DH_DERIVE (0x31) -#define CKM_X9_42_DH_HYBRID_DERIVE (0x32) -#define CKM_X9_42_MQV_DERIVE (0x33) -#define CKM_SHA256_RSA_PKCS (0x40) -#define CKM_SHA384_RSA_PKCS (0x41) -#define CKM_SHA512_RSA_PKCS (0x42) -#define CKM_SHA256_RSA_PKCS_PSS (0x43) -#define CKM_SHA384_RSA_PKCS_PSS (0x44) -#define CKM_SHA512_RSA_PKCS_PSS (0x45) -#define CKM_RC2_KEY_GEN (0x100) -#define CKM_RC2_ECB (0x101) -#define CKM_RC2_CBC (0x102) -#define CKM_RC2_MAC (0x103) -#define CKM_RC2_MAC_GENERAL (0x104) -#define CKM_RC2_CBC_PAD (0x105) -#define CKM_RC4_KEY_GEN (0x110) -#define CKM_RC4 (0x111) -#define CKM_DES_KEY_GEN (0x120) -#define CKM_DES_ECB (0x121) -#define CKM_DES_CBC (0x122) -#define CKM_DES_MAC (0x123) -#define CKM_DES_MAC_GENERAL (0x124) -#define CKM_DES_CBC_PAD (0x125) -#define CKM_DES2_KEY_GEN (0x130) -#define CKM_DES3_KEY_GEN (0x131) -#define CKM_DES3_ECB (0x132) -#define CKM_DES3_CBC (0x133) -#define CKM_DES3_MAC (0x134) -#define CKM_DES3_MAC_GENERAL (0x135) -#define CKM_DES3_CBC_PAD (0x136) -#define CKM_CDMF_KEY_GEN (0x140) -#define CKM_CDMF_ECB (0x141) -#define CKM_CDMF_CBC (0x142) -#define CKM_CDMF_MAC (0x143) -#define CKM_CDMF_MAC_GENERAL (0x144) -#define CKM_CDMF_CBC_PAD (0x145) -#define CKM_MD2 (0x200) -#define CKM_MD2_HMAC (0x201) -#define CKM_MD2_HMAC_GENERAL (0x202) -#define CKM_MD5 (0x210) -#define CKM_MD5_HMAC (0x211) -#define CKM_MD5_HMAC_GENERAL (0x212) -#define CKM_SHA_1 (0x220) -#define CKM_SHA_1_HMAC (0x221) -#define CKM_SHA_1_HMAC_GENERAL (0x222) -#define CKM_RIPEMD128 (0x230) -#define CKM_RIPEMD128_HMAC (0x231) -#define CKM_RIPEMD128_HMAC_GENERAL (0x232) -#define CKM_RIPEMD160 (0x240) -#define CKM_RIPEMD160_HMAC (0x241) -#define CKM_RIPEMD160_HMAC_GENERAL (0x242) -#define CKM_SHA256 (0x250) -#define CKM_SHA256_HMAC (0x251) -#define CKM_SHA256_HMAC_GENERAL (0x252) -#define CKM_SHA384 (0x260) -#define CKM_SHA384_HMAC (0x261) -#define CKM_SHA384_HMAC_GENERAL (0x262) -#define CKM_SHA512 (0x270) -#define CKM_SHA512_HMAC (0x271) -#define CKM_SHA512_HMAC_GENERAL (0x272) -#define CKM_CAST_KEY_GEN (0x300) -#define CKM_CAST_ECB (0x301) -#define CKM_CAST_CBC (0x302) -#define CKM_CAST_MAC (0x303) -#define CKM_CAST_MAC_GENERAL (0x304) -#define CKM_CAST_CBC_PAD (0x305) -#define CKM_CAST3_KEY_GEN (0x310) -#define CKM_CAST3_ECB (0x311) -#define CKM_CAST3_CBC (0x312) -#define CKM_CAST3_MAC (0x313) -#define CKM_CAST3_MAC_GENERAL (0x314) -#define CKM_CAST3_CBC_PAD (0x315) -#define CKM_CAST5_KEY_GEN (0x320) -#define CKM_CAST128_KEY_GEN (0x320) -#define CKM_CAST5_ECB (0x321) -#define CKM_CAST128_ECB (0x321) -#define CKM_CAST5_CBC (0x322) -#define CKM_CAST128_CBC (0x322) -#define CKM_CAST5_MAC (0x323) -#define CKM_CAST128_MAC (0x323) -#define CKM_CAST5_MAC_GENERAL (0x324) -#define CKM_CAST128_MAC_GENERAL (0x324) -#define CKM_CAST5_CBC_PAD (0x325) -#define CKM_CAST128_CBC_PAD (0x325) -#define CKM_RC5_KEY_GEN (0x330) -#define CKM_RC5_ECB (0x331) -#define CKM_RC5_CBC (0x332) -#define CKM_RC5_MAC (0x333) -#define CKM_RC5_MAC_GENERAL (0x334) -#define CKM_RC5_CBC_PAD (0x335) -#define CKM_IDEA_KEY_GEN (0x340) -#define CKM_IDEA_ECB (0x341) -#define CKM_IDEA_CBC (0x342) -#define CKM_IDEA_MAC (0x343) -#define CKM_IDEA_MAC_GENERAL (0x344) -#define CKM_IDEA_CBC_PAD (0x345) -#define CKM_GENERIC_SECRET_KEY_GEN (0x350) -#define CKM_CONCATENATE_BASE_AND_KEY (0x360) -#define CKM_CONCATENATE_BASE_AND_DATA (0x362) -#define CKM_CONCATENATE_DATA_AND_BASE (0x363) -#define CKM_XOR_BASE_AND_DATA (0x364) -#define CKM_EXTRACT_KEY_FROM_KEY (0x365) -#define CKM_SSL3_PRE_MASTER_KEY_GEN (0x370) -#define CKM_SSL3_MASTER_KEY_DERIVE (0x371) -#define CKM_SSL3_KEY_AND_MAC_DERIVE (0x372) -#define CKM_SSL3_MASTER_KEY_DERIVE_DH (0x373) -#define CKM_TLS_PRE_MASTER_KEY_GEN (0x374) -#define CKM_TLS_MASTER_KEY_DERIVE (0x375) -#define CKM_TLS_KEY_AND_MAC_DERIVE (0x376) -#define CKM_TLS_MASTER_KEY_DERIVE_DH (0x377) -#define CKM_SSL3_MD5_MAC (0x380) -#define CKM_SSL3_SHA1_MAC (0x381) -#define CKM_MD5_KEY_DERIVATION (0x390) -#define CKM_MD2_KEY_DERIVATION (0x391) -#define CKM_SHA1_KEY_DERIVATION (0x392) -#define CKM_PBE_MD2_DES_CBC (0x3a0) -#define CKM_PBE_MD5_DES_CBC (0x3a1) -#define CKM_PBE_MD5_CAST_CBC (0x3a2) -#define CKM_PBE_MD5_CAST3_CBC (0x3a3) -#define CKM_PBE_MD5_CAST5_CBC (0x3a4) -#define CKM_PBE_MD5_CAST128_CBC (0x3a4) -#define CKM_PBE_SHA1_CAST5_CBC (0x3a5) -#define CKM_PBE_SHA1_CAST128_CBC (0x3a5) -#define CKM_PBE_SHA1_RC4_128 (0x3a6) -#define CKM_PBE_SHA1_RC4_40 (0x3a7) -#define CKM_PBE_SHA1_DES3_EDE_CBC (0x3a8) -#define CKM_PBE_SHA1_DES2_EDE_CBC (0x3a9) -#define CKM_PBE_SHA1_RC2_128_CBC (0x3aa) -#define CKM_PBE_SHA1_RC2_40_CBC (0x3ab) -#define CKM_PKCS5_PBKD2 (0x3b0) -#define CKM_PBA_SHA1_WITH_SHA1_HMAC (0x3c0) -#define CKM_KEY_WRAP_LYNKS (0x400) -#define CKM_KEY_WRAP_SET_OAEP (0x401) -#define CKM_SKIPJACK_KEY_GEN (0x1000) -#define CKM_SKIPJACK_ECB64 (0x1001) -#define CKM_SKIPJACK_CBC64 (0x1002) -#define CKM_SKIPJACK_OFB64 (0x1003) -#define CKM_SKIPJACK_CFB64 (0x1004) -#define CKM_SKIPJACK_CFB32 (0x1005) -#define CKM_SKIPJACK_CFB16 (0x1006) -#define CKM_SKIPJACK_CFB8 (0x1007) -#define CKM_SKIPJACK_WRAP (0x1008) -#define CKM_SKIPJACK_PRIVATE_WRAP (0x1009) -#define CKM_SKIPJACK_RELAYX (0x100a) -#define CKM_KEA_KEY_PAIR_GEN (0x1010) -#define CKM_KEA_KEY_DERIVE (0x1011) -#define CKM_FORTEZZA_TIMESTAMP (0x1020) -#define CKM_BATON_KEY_GEN (0x1030) -#define CKM_BATON_ECB128 (0x1031) -#define CKM_BATON_ECB96 (0x1032) -#define CKM_BATON_CBC128 (0x1033) -#define CKM_BATON_COUNTER (0x1034) -#define CKM_BATON_SHUFFLE (0x1035) -#define CKM_BATON_WRAP (0x1036) -#define CKM_ECDSA_KEY_PAIR_GEN (0x1040) -#define CKM_EC_KEY_PAIR_GEN (0x1040) -#define CKM_ECDSA (0x1041) -#define CKM_ECDSA_SHA1 (0x1042) -#define CKM_ECDH1_DERIVE (0x1050) -#define CKM_ECDH1_COFACTOR_DERIVE (0x1051) -#define CKM_ECMQV_DERIVE (0x1052) -#define CKM_JUNIPER_KEY_GEN (0x1060) -#define CKM_JUNIPER_ECB128 (0x1061) -#define CKM_JUNIPER_CBC128 (0x1062) -#define CKM_JUNIPER_COUNTER (0x1063) -#define CKM_JUNIPER_SHUFFLE (0x1064) -#define CKM_JUNIPER_WRAP (0x1065) -#define CKM_FASTHASH (0x1070) -#define CKM_AES_KEY_GEN (0x1080) -#define CKM_AES_ECB (0x1081) -#define CKM_AES_CBC (0x1082) -#define CKM_AES_MAC (0x1083) -#define CKM_AES_MAC_GENERAL (0x1084) -#define CKM_AES_CBC_PAD (0x1085) -#define CKM_DSA_PARAMETER_GEN (0x2000) -#define CKM_DH_PKCS_PARAMETER_GEN (0x2001) -#define CKM_X9_42_DH_PARAMETER_GEN (0x2002) -#define CKM_VENDOR_DEFINED (1U << 31) - +#define CKM_RSA_PKCS_KEY_PAIR_GEN (0UL) +#define CKM_RSA_PKCS (1UL) +#define CKM_RSA_9796 (2UL) +#define CKM_RSA_X_509 (3UL) +#define CKM_MD2_RSA_PKCS (4UL) +#define CKM_MD5_RSA_PKCS (5UL) +#define CKM_SHA1_RSA_PKCS (6UL) +#define CKM_RIPEMD128_RSA_PKCS (7UL) +#define CKM_RIPEMD160_RSA_PKCS (8UL) +#define CKM_RSA_PKCS_OAEP (9UL) +#define CKM_RSA_X9_31_KEY_PAIR_GEN (0xaUL) +#define CKM_RSA_X9_31 (0xbUL) +#define CKM_SHA1_RSA_X9_31 (0xcUL) +#define CKM_RSA_PKCS_PSS (0xdUL) +#define CKM_SHA1_RSA_PKCS_PSS (0xeUL) +#define CKM_DSA_KEY_PAIR_GEN (0x10UL) +#define CKM_DSA (0x11UL) +#define CKM_DSA_SHA1 (0x12UL) +#define CKM_DSA_SHA224 (0x13UL) +#define CKM_DSA_SHA256 (0x14UL) +#define CKM_DSA_SHA384 (0x15UL) +#define CKM_DSA_SHA512 (0x16UL) +#define CKM_DH_PKCS_KEY_PAIR_GEN (0x20UL) +#define CKM_DH_PKCS_DERIVE (0x21UL) +#define CKM_X9_42_DH_KEY_PAIR_GEN (0x30UL) +#define CKM_X9_42_DH_DERIVE (0x31UL) +#define CKM_X9_42_DH_HYBRID_DERIVE (0x32UL) +#define CKM_X9_42_MQV_DERIVE (0x33UL) +#define CKM_SHA256_RSA_PKCS (0x40UL) +#define CKM_SHA384_RSA_PKCS (0x41UL) +#define CKM_SHA512_RSA_PKCS (0x42UL) +#define CKM_SHA256_RSA_PKCS_PSS (0x43UL) +#define CKM_SHA384_RSA_PKCS_PSS (0x44UL) +#define CKM_SHA512_RSA_PKCS_PSS (0x45UL) +#define CKM_SHA224_RSA_PKCS (0x46UL) +#define CKM_SHA224_RSA_PKCS_PSS (0x47UL) +#define CKM_SHA3_256_RSA_PKCS (0x60UL) +#define CKM_SHA3_384_RSA_PKCS (0x61UL) +#define CKM_SHA3_512_RSA_PKCS (0x62UL) +#define CKM_SHA3_256_RSA_PKCS_PSS (0x63UL) +#define CKM_SHA3_384_RSA_PKCS_PSS (0x64UL) +#define CKM_SHA3_512_RSA_PKCS_PSS (0x65UL) +#define CKM_SHA3_224_RSA_PKCS (0x66UL) +#define CKM_SHA3_224_RSA_PKCS_PSS (0x67UL) +#define CKM_RC2_KEY_GEN (0x100UL) +#define CKM_RC2_ECB (0x101UL) +#define CKM_RC2_CBC (0x102UL) +#define CKM_RC2_MAC (0x103UL) +#define CKM_RC2_MAC_GENERAL (0x104UL) +#define CKM_RC2_CBC_PAD (0x105UL) +#define CKM_RC4_KEY_GEN (0x110UL) +#define CKM_RC4 (0x111UL) +#define CKM_DES_KEY_GEN (0x120UL) +#define CKM_DES_ECB (0x121UL) +#define CKM_DES_CBC (0x122UL) +#define CKM_DES_MAC (0x123UL) +#define CKM_DES_MAC_GENERAL (0x124UL) +#define CKM_DES_CBC_PAD (0x125UL) +#define CKM_DES2_KEY_GEN (0x130UL) +#define CKM_DES3_KEY_GEN (0x131UL) +#define CKM_DES3_ECB (0x132UL) +#define CKM_DES3_CBC (0x133UL) +#define CKM_DES3_MAC (0x134UL) +#define CKM_DES3_MAC_GENERAL (0x135UL) +#define CKM_DES3_CBC_PAD (0x136UL) +#define CKM_DES3_CMAC_GENERAL (0x137UL) +#define CKM_DES3_CMAC (0x138UL) +#define CKM_CDMF_KEY_GEN (0x140UL) +#define CKM_CDMF_ECB (0x141UL) +#define CKM_CDMF_CBC (0x142UL) +#define CKM_CDMF_MAC (0x143UL) +#define CKM_CDMF_MAC_GENERAL (0x144UL) +#define CKM_CDMF_CBC_PAD (0x145UL) +#define CKM_MD2 (0x200UL) +#define CKM_MD2_HMAC (0x201UL) +#define CKM_MD2_HMAC_GENERAL (0x202UL) +#define CKM_MD5 (0x210UL) +#define CKM_MD5_HMAC (0x211UL) +#define CKM_MD5_HMAC_GENERAL (0x212UL) +#define CKM_SHA_1 (0x220UL) +#define CKM_SHA_1_HMAC (0x221UL) +#define CKM_SHA_1_HMAC_GENERAL (0x222UL) +#define CKM_RIPEMD128 (0x230UL) +#define CKM_RIPEMD128_HMAC (0x231UL) +#define CKM_RIPEMD128_HMAC_GENERAL (0x232UL) +#define CKM_RIPEMD160 (0x240UL) +#define CKM_RIPEMD160_HMAC (0x241UL) +#define CKM_RIPEMD160_HMAC_GENERAL (0x242UL) +#define CKM_SHA256 (0x250UL) +#define CKM_SHA256_HMAC (0x251UL) +#define CKM_SHA256_HMAC_GENERAL (0x252UL) +#define CKM_SHA224 (0x255UL) +#define CKM_SHA224_HMAC (0x256UL) +#define CKM_SHA224_HMAC_GENERAL (0x257UL) +#define CKM_SHA384 (0x260UL) +#define CKM_SHA384_HMAC (0x261UL) +#define CKM_SHA384_HMAC_GENERAL (0x262UL) +#define CKM_SHA512 (0x270UL) +#define CKM_SHA512_HMAC (0x271UL) +#define CKM_SHA512_HMAC_GENERAL (0x272UL) +#define CKM_SHA3_256 (0x2B0UL) +#define CKM_SHA3_256_HMAC (0x2B1UL) +#define CKM_SHA3_256_HMAC_GENERAL (0x2B2UL) +#define CKM_SHA3_256_KEY_GEN (0x2B3UL) +#define CKM_SHA3_224 (0x2B5UL) +#define CKM_SHA3_224_HMAC (0x2B6UL) +#define CKM_SHA3_224_HMAC_GENERAL (0x2B7UL) +#define CKM_SHA3_224_KEY_GEN (0x2B8UL) +#define CKM_SHA3_384 (0x2C0UL) +#define CKM_SHA3_384_HMAC (0x2C1UL) +#define CKM_SHA3_384_HMAC_GENERAL (0x2C2UL) +#define CKM_SHA3_384_KEY_GEN (0x2C3UL) +#define CKM_SHA3_512 (0x2D0UL) +#define CKM_SHA3_512_HMAC (0x2D1UL) +#define CKM_SHA3_512_HMAC_GENERAL (0x2D2UL) +#define CKM_SHA3_512_KEY_GEN (0x2D3UL) +#define CKM_CAST_KEY_GEN (0x300UL) +#define CKM_CAST_ECB (0x301UL) +#define CKM_CAST_CBC (0x302UL) +#define CKM_CAST_MAC (0x303UL) +#define CKM_CAST_MAC_GENERAL (0x304UL) +#define CKM_CAST_CBC_PAD (0x305UL) +#define CKM_CAST3_KEY_GEN (0x310UL) +#define CKM_CAST3_ECB (0x311UL) +#define CKM_CAST3_CBC (0x312UL) +#define CKM_CAST3_MAC (0x313UL) +#define CKM_CAST3_MAC_GENERAL (0x314UL) +#define CKM_CAST3_CBC_PAD (0x315UL) +#define CKM_CAST5_KEY_GEN (0x320UL) +#define CKM_CAST128_KEY_GEN (0x320UL) +#define CKM_CAST5_ECB (0x321UL) +#define CKM_CAST128_ECB (0x321UL) +#define CKM_CAST5_CBC (0x322UL) +#define CKM_CAST128_CBC (0x322UL) +#define CKM_CAST5_MAC (0x323UL) +#define CKM_CAST128_MAC (0x323UL) +#define CKM_CAST5_MAC_GENERAL (0x324UL) +#define CKM_CAST128_MAC_GENERAL (0x324UL) +#define CKM_CAST5_CBC_PAD (0x325UL) +#define CKM_CAST128_CBC_PAD (0x325UL) +#define CKM_RC5_KEY_GEN (0x330UL) +#define CKM_RC5_ECB (0x331UL) +#define CKM_RC5_CBC (0x332UL) +#define CKM_RC5_MAC (0x333UL) +#define CKM_RC5_MAC_GENERAL (0x334UL) +#define CKM_RC5_CBC_PAD (0x335UL) +#define CKM_IDEA_KEY_GEN (0x340UL) +#define CKM_IDEA_ECB (0x341UL) +#define CKM_IDEA_CBC (0x342UL) +#define CKM_IDEA_MAC (0x343UL) +#define CKM_IDEA_MAC_GENERAL (0x344UL) +#define CKM_IDEA_CBC_PAD (0x345UL) +#define CKM_GENERIC_SECRET_KEY_GEN (0x350UL) +#define CKM_CONCATENATE_BASE_AND_KEY (0x360UL) +#define CKM_CONCATENATE_BASE_AND_DATA (0x362UL) +#define CKM_CONCATENATE_DATA_AND_BASE (0x363UL) +#define CKM_XOR_BASE_AND_DATA (0x364UL) +#define CKM_EXTRACT_KEY_FROM_KEY (0x365UL) +#define CKM_SSL3_PRE_MASTER_KEY_GEN (0x370UL) +#define CKM_SSL3_MASTER_KEY_DERIVE (0x371UL) +#define CKM_SSL3_KEY_AND_MAC_DERIVE (0x372UL) +#define CKM_SSL3_MASTER_KEY_DERIVE_DH (0x373UL) +#define CKM_TLS_PRE_MASTER_KEY_GEN (0x374UL) +#define CKM_TLS_MASTER_KEY_DERIVE (0x375UL) +#define CKM_TLS_KEY_AND_MAC_DERIVE (0x376UL) +#define CKM_TLS_MASTER_KEY_DERIVE_DH (0x377UL) +#define CKM_SSL3_MD5_MAC (0x380UL) +#define CKM_SSL3_SHA1_MAC (0x381UL) +#define CKM_MD5_KEY_DERIVATION (0x390UL) +#define CKM_MD2_KEY_DERIVATION (0x391UL) +#define CKM_SHA1_KEY_DERIVATION (0x392UL) +#define CKM_PBE_MD2_DES_CBC (0x3a0UL) +#define CKM_PBE_MD5_DES_CBC (0x3a1UL) +#define CKM_PBE_MD5_CAST_CBC (0x3a2UL) +#define CKM_PBE_MD5_CAST3_CBC (0x3a3UL) +#define CKM_PBE_MD5_CAST5_CBC (0x3a4UL) +#define CKM_PBE_MD5_CAST128_CBC (0x3a4UL) +#define CKM_PBE_SHA1_CAST5_CBC (0x3a5UL) +#define CKM_PBE_SHA1_CAST128_CBC (0x3a5UL) +#define CKM_PBE_SHA1_RC4_128 (0x3a6UL) +#define CKM_PBE_SHA1_RC4_40 (0x3a7UL) +#define CKM_PBE_SHA1_DES3_EDE_CBC (0x3a8UL) +#define CKM_PBE_SHA1_DES2_EDE_CBC (0x3a9UL) +#define CKM_PBE_SHA1_RC2_128_CBC (0x3aaUL) +#define CKM_PBE_SHA1_RC2_40_CBC (0x3abUL) +#define CKM_PKCS5_PBKD2 (0x3b0UL) +#define CKM_PBA_SHA1_WITH_SHA1_HMAC (0x3c0UL) +#define CKM_KEY_WRAP_LYNKS (0x400UL) +#define CKM_KEY_WRAP_SET_OAEP (0x401UL) +#define CKM_SKIPJACK_KEY_GEN (0x1000UL) +#define CKM_SKIPJACK_ECB64 (0x1001UL) +#define CKM_SKIPJACK_CBC64 (0x1002UL) +#define CKM_SKIPJACK_OFB64 (0x1003UL) +#define CKM_SKIPJACK_CFB64 (0x1004UL) +#define CKM_SKIPJACK_CFB32 (0x1005UL) +#define CKM_SKIPJACK_CFB16 (0x1006UL) +#define CKM_SKIPJACK_CFB8 (0x1007UL) +#define CKM_SKIPJACK_WRAP (0x1008UL) +#define CKM_SKIPJACK_PRIVATE_WRAP (0x1009UL) +#define CKM_SKIPJACK_RELAYX (0x100aUL) +#define CKM_KEA_KEY_PAIR_GEN (0x1010UL) +#define CKM_KEA_KEY_DERIVE (0x1011UL) +#define CKM_FORTEZZA_TIMESTAMP (0x1020UL) +#define CKM_BATON_KEY_GEN (0x1030UL) +#define CKM_BATON_ECB128 (0x1031UL) +#define CKM_BATON_ECB96 (0x1032UL) +#define CKM_BATON_CBC128 (0x1033UL) +#define CKM_BATON_COUNTER (0x1034UL) +#define CKM_BATON_SHUFFLE (0x1035UL) +#define CKM_BATON_WRAP (0x1036UL) +#define CKM_ECDSA_KEY_PAIR_GEN (0x1040UL) +#define CKM_EC_KEY_PAIR_GEN (0x1040UL) +#define CKM_ECDSA (0x1041UL) +#define CKM_ECDSA_SHA1 (0x1042UL) +#define CKM_ECDSA_SHA224 (0x1043UL) +#define CKM_ECDSA_SHA256 (0x1044UL) +#define CKM_ECDSA_SHA384 (0x1045UL) +#define CKM_ECDSA_SHA512 (0x1046UL) +#define CKM_ECDSA_SHA3_224 (0x1047UL) +#define CKM_ECDSA_SHA3_256 (0x1048UL) +#define CKM_ECDSA_SHA3_384 (0x1049UL) +#define CKM_ECDSA_SHA3_512 (0x104AUL) +#define CKM_ECDH1_DERIVE (0x1050UL) +#define CKM_ECDH1_COFACTOR_DERIVE (0x1051UL) +#define CKM_ECMQV_DERIVE (0x1052UL) +#define CKM_EC_EDWARDS_KEY_PAIR_GEN (0x1055UL) +#define CKM_EC_MONTGOMERY_KEY_PAIR_GEN (0x1056UL) +#define CKM_EDDSA (0x1057UL) +#define CKM_JUNIPER_KEY_GEN (0x1060UL) +#define CKM_JUNIPER_ECB128 (0x1061UL) +#define CKM_JUNIPER_CBC128 (0x1062UL) +#define CKM_JUNIPER_COUNTER (0x1063UL) +#define CKM_JUNIPER_SHUFFLE (0x1064UL) +#define CKM_JUNIPER_WRAP (0x1065UL) +#define CKM_FASTHASH (0x1070UL) +#define CKM_AES_KEY_GEN (0x1080UL) +#define CKM_AES_ECB (0x1081UL) +#define CKM_AES_CBC (0x1082UL) +#define CKM_AES_MAC (0x1083UL) +#define CKM_AES_MAC_GENERAL (0x1084UL) +#define CKM_AES_CBC_PAD (0x1085UL) +#define CKM_AES_CTR (0x1086UL) +#define CKM_AES_GCM (0x1087UL) +#define CKM_AES_CCM (0x1088UL) +#define CKM_AES_CTS (0x1089UL) +#define CKM_AES_CMAC (0x108AUL) +#define CKM_AES_CMAC_GENERAL (0x108BUL) +#define CKM_AES_XCBC_MAC (0x108CUL) +#define CKM_AES_XCBC_MAC_96 (0x108DUL) +#define CKM_AES_GMAC (0x108EUL) +#define CKM_BLOWFISH_KEY_GEN (0x1090UL) +#define CKM_BLOWFISH_CBC (0x1091UL) +#define CKM_TWOFISH_KEY_GEN (0x1092UL) +#define CKM_TWOFISH_CBC (0x1093UL) +#define CKM_DES_ECB_ENCRYPT_DATA (0x1100UL) +#define CKM_DES_CBC_ENCRYPT_DATA (0x1101UL) +#define CKM_DES3_ECB_ENCRYPT_DATA (0x1102UL) +#define CKM_DES3_CBC_ENCRYPT_DATA (0x1103UL) +#define CKM_AES_ECB_ENCRYPT_DATA (0x1104UL) +#define CKM_AES_CBC_ENCRYPT_DATA (0x1105UL) +#define CKM_GOSTR3410_KEY_PAIR_GEN (0x1200UL) +#define CKM_GOSTR3410 (0x1201UL) +#define CKM_GOSTR3410_WITH_GOSTR3411 (0x1202UL) +#define CKM_GOSTR3410_KEY_WRAP (0x1203UL) +#define CKM_GOSTR3410_DERIVE (0x1204UL) +#define CKM_GOSTR3410_512_KEY_PAIR_GEN (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x005) +#define CKM_GOSTR3410_512 (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x006) +#define CKM_GOSTR3410_12_DERIVE (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x007) +#define CKM_GOSTR3410_WITH_GOSTR3411_12_256 (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x008) +#define CKM_GOSTR3410_WITH_GOSTR3411_12_512 (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x009) +#define CKM_GOSTR3411 (0x1210UL) +#define CKM_GOSTR3411_HMAC (0x1211UL) +#define CKM_GOSTR3411_12_256 (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x012) +#define CKM_GOSTR3411_12_512 (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x013) +#define CKM_GOSTR3411_12_256_HMAC (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x014) +#define CKM_GOSTR3411_12_512_HMAC (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x015) +#define CKM_GOST28147_KEY_GEN (0x1220UL) +#define CKM_GOST28147_ECB (0x1221UL) +#define CKM_GOST28147 (0x1222UL) +#define CKM_GOST28147_MAC (0x1223UL) +#define CKM_GOST28147_KEY_WRAP (0x1224UL) + +#define CKM_DSA_PARAMETER_GEN (0x2000UL) +#define CKM_DH_PKCS_PARAMETER_GEN (0x2001UL) +#define CKM_X9_42_DH_PARAMETER_GEN (0x2002UL) +#define CKM_AES_OFB (0x2104UL) +#define CKM_AES_CFB64 (0x2105UL) +#define CKM_AES_CFB8 (0x2106UL) +#define CKM_AES_CFB128 (0x2107UL) +#define CKM_AES_CFB1 (0x2108UL) +#define CKM_AES_KEY_WRAP (0x2109UL) +#define CKM_AES_KEY_WRAP_PAD (0x210AUL) +#define CKM_XEDDSA (0x4029UL) +#define CKM_HKDF_DERIVE (0x402AUL) +#define CKM_HKDF_DATA (0x402BUL) +#define CKM_HKDF_KEY_GEN (0x402CUL) + +#define CKM_VENDOR_DEFINED (1UL << 31) struct ck_mechanism { @@ -690,25 +836,143 @@ struct ck_mechanism_info ck_flags_t flags; }; -#define CKF_HW (1 << 0) -#define CKF_ENCRYPT (1 << 8) -#define CKF_DECRYPT (1 << 9) -#define CKF_DIGEST (1 << 10) -#define CKF_SIGN (1 << 11) -#define CKF_SIGN_RECOVER (1 << 12) -#define CKF_VERIFY (1 << 13) -#define CKF_VERIFY_RECOVER (1 << 14) -#define CKF_GENERATE (1 << 15) -#define CKF_GENERATE_KEY_PAIR (1 << 16) -#define CKF_WRAP (1 << 17) -#define CKF_UNWRAP (1 << 18) -#define CKF_DERIVE (1 << 19) -#define CKF_EXTENSION (1U << 31) - +#define CKF_HW (1UL << 0) + +#define CKF_MESSAGE_ENCRYPT (1UL << 1) +#define CKF_MESSAGE_DECRYPT (1UL << 2) +#define CKF_MESSAGE_SIGN (1UL << 3) +#define CKF_MESSAGE_VERIFY (1UL << 4) +#define CKF_MULTI_MESSAGE (1UL << 5) +#define CKF_FIND_OBJECTS (1UL << 6) + +#define CKF_ENCRYPT (1UL << 8) +#define CKF_DECRYPT (1UL << 9) +#define CKF_DIGEST (1UL << 10) +#define CKF_SIGN (1UL << 11) +#define CKF_SIGN_RECOVER (1UL << 12) +#define CKF_VERIFY (1UL << 13) +#define CKF_VERIFY_RECOVER (1UL << 14) +#define CKF_GENERATE (1UL << 15) +#define CKF_GENERATE_KEY_PAIR (1UL << 16) +#define CKF_WRAP (1UL << 17) +#define CKF_UNWRAP (1UL << 18) +#define CKF_DERIVE (1UL << 19) +#define CKF_EXTENSION (1UL << 31) + +#define CKF_EC_F_P (1UL << 20) +#define CKF_EC_F_2M (1UL << 21) +#define CKF_EC_ECPARAMETERS (1UL << 22) +#define CKF_EC_OID (1UL << 23) +#define CKF_EC_NAMEDCURVE CKF_EC_OID +#define CKF_EC_UNCOMPRESS (1UL << 24) +#define CKF_EC_COMPRESS (1UL << 25) +#define CKF_EC_CURVENAME (1UL << 26) /* Flags for C_WaitForSlotEvent. */ -#define CKF_DONT_BLOCK (1) - +#define CKF_DONT_BLOCK (1UL) + +/* Flags for Key derivation */ +#define CKD_NULL (0x1UL) +#define CKD_SHA1_KDF (0x2UL) +#define CKD_SHA224_KDF (0x5UL) +#define CKD_SHA256_KDF (0x6UL) +#define CKD_SHA384_KDF (0x7UL) +#define CKD_SHA512_KDF (0x8UL) + +typedef struct CK_ECDH1_DERIVE_PARAMS { + unsigned long kdf; + unsigned long ulSharedDataLen; + unsigned char * pSharedData; + unsigned long ulPublicDataLen; + unsigned char * pPublicData; +} CK_ECDH1_DERIVE_PARAMS; + +typedef struct CK_ECMQV_DERIVE_PARAMS { + unsigned long kdf; + unsigned long ulSharedDataLen; + unsigned char * pSharedData; + unsigned long ulPublicDataLen; + unsigned char * pPublicData; + unsigned long ulPrivateDataLen; + CK_OBJECT_HANDLE hPrivateData; + unsigned long ulPublicDataLen2; + unsigned char * pPublicData2; + CK_OBJECT_HANDLE publicKey; +} CK_ECMQV_DERIVE_PARAMS; + +typedef unsigned long ck_rsa_pkcs_mgf_type_t; +typedef unsigned long CK_RSA_PKCS_OAEP_SOURCE_TYPE; + +typedef struct CK_RSA_PKCS_OAEP_PARAMS { + CK_MECHANISM_TYPE hashAlg; + CK_RSA_PKCS_MGF_TYPE mgf; + CK_RSA_PKCS_OAEP_SOURCE_TYPE source; + void *pSourceData; + unsigned long ulSourceDataLen; +} CK_RSA_PKCS_OAEP_PARAMS; + +typedef struct CK_RSA_PKCS_PSS_PARAMS { + ck_mechanism_type_t hashAlg; + CK_RSA_PKCS_MGF_TYPE mgf; + unsigned long sLen; +} CK_RSA_PKCS_PSS_PARAMS; + +#define CKG_MGF1_SHA1 (0x00000001UL) +#define CKG_MGF1_SHA224 (0x00000005UL) +#define CKG_MGF1_SHA256 (0x00000002UL) +#define CKG_MGF1_SHA384 (0x00000003UL) +#define CKG_MGF1_SHA512 (0x00000004UL) +#define CKG_MGF1_SHA3_224 (0x00000006UL) +#define CKG_MGF1_SHA3_256 (0x00000007UL) +#define CKG_MGF1_SHA3_384 (0x00000008UL) +#define CKG_MGF1_SHA3_512 (0x00000009UL) + +#define CKZ_DATA_SPECIFIED (0x00000001UL) + +typedef struct CK_GCM_PARAMS { + void * pIv; + unsigned long ulIvLen; + unsigned long ulIvBits; + void * pAAD; + unsigned long ulAADLen; + unsigned long ulTagBits; +} CK_GCM_PARAMS; + +typedef struct CK_CCM_PARAMS { + unsigned long ulDataLen; + unsigned char *pNonce; + unsigned long ulNonceLen; + unsigned char *pAAD; + unsigned long ulAADLen; + unsigned long ulMACLen; +} CK_CCM_PARAMS; + +/* EDDSA */ +typedef struct CK_EDDSA_PARAMS { + unsigned char phFlag; + unsigned long ulContextDataLen; + unsigned char *pContextData; +} CK_EDDSA_PARAMS; + +typedef CK_EDDSA_PARAMS *CK_EDDSA_PARAMS_PTR; + +/* XEDDSA */ +typedef struct CK_XEDDSA_PARAMS { + unsigned long hash; +} CK_XEDDSA_PARAMS; + +typedef CK_XEDDSA_PARAMS *CK_XEDDSA_PARAMS_PTR; + +typedef struct CK_AES_CTR_PARAMS { + unsigned long ulCounterBits; + unsigned char cb[16]; +} CK_AES_CTR_PARAMS; + +typedef CK_AES_CTR_PARAMS *CK_AES_CTR_PARAMS_PTR; + +typedef unsigned long CK_MAC_GENERAL_PARAMS; + +typedef CK_MAC_GENERAL_PARAMS *CK_MAC_GENERAL_PARAMS_PTR; typedef unsigned long ck_rv_t; @@ -716,8 +980,17 @@ typedef unsigned long ck_rv_t; typedef ck_rv_t (*ck_notify_t) (ck_session_handle_t session, ck_notification_t event, void *application); +struct ck_interface { + char * pInterfaceName; + void * pFunctionList; + ck_flags_t flags; +}; + +#define CKF_INTERFACE_FORK_SAFE (0x00000001UL) + /* Forward reference. */ struct ck_function_list; +struct ck_function_list_3_0; #define _CK_DECLARE_FUNCTION(name, args) \ typedef ck_rv_t (*CK_ ## name) args; \ @@ -774,7 +1047,7 @@ _CK_DECLARE_FUNCTION (C_SetOperationState, unsigned char *operation_state, unsigned long operation_state_len, ck_object_handle_t encryption_key, - ck_object_handle_t authentiation_key)); + ck_object_handle_t authentication_key)); _CK_DECLARE_FUNCTION (C_Login, (ck_session_handle_t session, ck_user_type_t user_type, unsigned char *pin, unsigned long pin_len)); @@ -999,6 +1272,147 @@ _CK_DECLARE_FUNCTION (C_GenerateRandom, _CK_DECLARE_FUNCTION (C_GetFunctionStatus, (ck_session_handle_t session)); _CK_DECLARE_FUNCTION (C_CancelFunction, (ck_session_handle_t session)); +_CK_DECLARE_FUNCTION (C_GetInterfaceList, + (struct ck_interface *interfaces_list, + unsigned long *count)); +_CK_DECLARE_FUNCTION (C_GetInterface, + (unsigned char *interface_name, + struct ck_version *version, + struct ck_interface **interface_ptr, + ck_flags_t flags)); + +_CK_DECLARE_FUNCTION (C_LoginUser, + (ck_session_handle_t session, + ck_user_type_t user_type, + unsigned char *pin, + unsigned long pin_len, + unsigned char *username, + unsigned long username_len)); + +_CK_DECLARE_FUNCTION (C_SessionCancel, + (ck_session_handle_t session, + ck_flags_t flags)); + +_CK_DECLARE_FUNCTION (C_MessageEncryptInit, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t key)); +_CK_DECLARE_FUNCTION (C_EncryptMessage, + (ck_session_handle_t session, + void *parameter, + unsigned long parameter_len, + unsigned char *associated_data, + unsigned long associated_data_len, + unsigned char *plaintext, + unsigned long plaintext_len, + unsigned char *ciphertext, + unsigned long *ciphertext_len)); +_CK_DECLARE_FUNCTION (C_EncryptMessageBegin, + (ck_session_handle_t session, + void *parameter, + unsigned long parameter_len, + unsigned char *associated_data, + unsigned long associated_data_len)); +_CK_DECLARE_FUNCTION (C_EncryptMessageNext, + (ck_session_handle_t session, + void *parameter, + unsigned long parameter_len, + unsigned char *plaintext_part, + unsigned long plaintext_part_len, + unsigned char *ciphertext_part, + unsigned long *ciphertext_part_len, + ck_flags_t flags)); +_CK_DECLARE_FUNCTION (C_MessageEncryptFinal, + (ck_session_handle_t session)); + +_CK_DECLARE_FUNCTION (C_MessageDecryptInit, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t key)); +_CK_DECLARE_FUNCTION (C_DecryptMessage, + (ck_session_handle_t session, + void *parameter, + unsigned long parameter_len, + unsigned char *associated_data, + unsigned long associated_data_len, + unsigned char *ciphertext, + unsigned long ciphertext_len, + unsigned char *plaintext, + unsigned long *plaintext_len)); +_CK_DECLARE_FUNCTION (C_DecryptMessageBegin, + (ck_session_handle_t session, + void *parameter, + unsigned long parameter_len, + unsigned char *associated_data, + unsigned long associated_data_len)); +_CK_DECLARE_FUNCTION (C_DecryptMessageNext, + (ck_session_handle_t session, + void *parameter, + unsigned long parameter_len, + unsigned char *ciphertext_part, + unsigned long ciphertext_part_len, + unsigned char *plaintext_part, + unsigned long *plaintext_part_len, + ck_flags_t flags)); +_CK_DECLARE_FUNCTION (C_MessageDecryptFinal, + (ck_session_handle_t session)); + +_CK_DECLARE_FUNCTION (C_MessageSignInit, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t key)); +_CK_DECLARE_FUNCTION (C_SignMessage, + (ck_session_handle_t session, + void *parameter, + unsigned long parameter_len, + unsigned char *data, + unsigned long data_len, + unsigned char *signature, + unsigned long *signature_len)); +_CK_DECLARE_FUNCTION (C_SignMessageBegin, + (ck_session_handle_t session, + void *parameter, + unsigned long parameter_len)); +_CK_DECLARE_FUNCTION (C_SignMessageNext, + (ck_session_handle_t session, + void *parameter, + unsigned long parameter_len, + unsigned char *data, + unsigned long data_len, + unsigned char *signature, + unsigned long *signature_len)); +_CK_DECLARE_FUNCTION (C_MessageSignFinal, + (ck_session_handle_t session)); + +_CK_DECLARE_FUNCTION (C_MessageVerifyInit, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t key)); +_CK_DECLARE_FUNCTION (C_VerifyMessage, + (ck_session_handle_t session, + void *parameter, + unsigned long parameter_len, + unsigned char *data, + unsigned long data_len, + unsigned char *signature, + unsigned long signature_len)); +_CK_DECLARE_FUNCTION (C_VerifyMessageBegin, + (ck_session_handle_t session, + void *parameter, + unsigned long parameter_len)); +_CK_DECLARE_FUNCTION (C_VerifyMessageNext, + (ck_session_handle_t session, + void *parameter, + unsigned long parameter_len, + unsigned char *data, + unsigned long data_len, + unsigned char *signature, + unsigned long signature_len)); +_CK_DECLARE_FUNCTION (C_MessageVerifyFinal, + (ck_session_handle_t session)); + +/* Flags in Message-based encryption/decryption API */ +#define CKF_END_OF_MESSAGE (0x00000001UL) struct ck_function_list { @@ -1073,6 +1487,105 @@ struct ck_function_list CK_C_WaitForSlotEvent C_WaitForSlotEvent; }; +struct ck_function_list_3_0 +{ + struct ck_version version; + CK_C_Initialize C_Initialize; + CK_C_Finalize C_Finalize; + CK_C_GetInfo C_GetInfo; + CK_C_GetFunctionList C_GetFunctionList; + CK_C_GetSlotList C_GetSlotList; + CK_C_GetSlotInfo C_GetSlotInfo; + CK_C_GetTokenInfo C_GetTokenInfo; + CK_C_GetMechanismList C_GetMechanismList; + CK_C_GetMechanismInfo C_GetMechanismInfo; + CK_C_InitToken C_InitToken; + CK_C_InitPIN C_InitPIN; + CK_C_SetPIN C_SetPIN; + CK_C_OpenSession C_OpenSession; + CK_C_CloseSession C_CloseSession; + CK_C_CloseAllSessions C_CloseAllSessions; + CK_C_GetSessionInfo C_GetSessionInfo; + CK_C_GetOperationState C_GetOperationState; + CK_C_SetOperationState C_SetOperationState; + CK_C_Login C_Login; + CK_C_Logout C_Logout; + CK_C_CreateObject C_CreateObject; + CK_C_CopyObject C_CopyObject; + CK_C_DestroyObject C_DestroyObject; + CK_C_GetObjectSize C_GetObjectSize; + CK_C_GetAttributeValue C_GetAttributeValue; + CK_C_SetAttributeValue C_SetAttributeValue; + CK_C_FindObjectsInit C_FindObjectsInit; + CK_C_FindObjects C_FindObjects; + CK_C_FindObjectsFinal C_FindObjectsFinal; + CK_C_EncryptInit C_EncryptInit; + CK_C_Encrypt C_Encrypt; + CK_C_EncryptUpdate C_EncryptUpdate; + CK_C_EncryptFinal C_EncryptFinal; + CK_C_DecryptInit C_DecryptInit; + CK_C_Decrypt C_Decrypt; + CK_C_DecryptUpdate C_DecryptUpdate; + CK_C_DecryptFinal C_DecryptFinal; + CK_C_DigestInit C_DigestInit; + CK_C_Digest C_Digest; + CK_C_DigestUpdate C_DigestUpdate; + CK_C_DigestKey C_DigestKey; + CK_C_DigestFinal C_DigestFinal; + CK_C_SignInit C_SignInit; + CK_C_Sign C_Sign; + CK_C_SignUpdate C_SignUpdate; + CK_C_SignFinal C_SignFinal; + CK_C_SignRecoverInit C_SignRecoverInit; + CK_C_SignRecover C_SignRecover; + CK_C_VerifyInit C_VerifyInit; + CK_C_Verify C_Verify; + CK_C_VerifyUpdate C_VerifyUpdate; + CK_C_VerifyFinal C_VerifyFinal; + CK_C_VerifyRecoverInit C_VerifyRecoverInit; + CK_C_VerifyRecover C_VerifyRecover; + CK_C_DigestEncryptUpdate C_DigestEncryptUpdate; + CK_C_DecryptDigestUpdate C_DecryptDigestUpdate; + CK_C_SignEncryptUpdate C_SignEncryptUpdate; + CK_C_DecryptVerifyUpdate C_DecryptVerifyUpdate; + CK_C_GenerateKey C_GenerateKey; + CK_C_GenerateKeyPair C_GenerateKeyPair; + CK_C_WrapKey C_WrapKey; + CK_C_UnwrapKey C_UnwrapKey; + CK_C_DeriveKey C_DeriveKey; + CK_C_SeedRandom C_SeedRandom; + CK_C_GenerateRandom C_GenerateRandom; + CK_C_GetFunctionStatus C_GetFunctionStatus; + CK_C_CancelFunction C_CancelFunction; + CK_C_WaitForSlotEvent C_WaitForSlotEvent; + /* PKCS #11 3.0 functions */ + CK_C_GetInterfaceList C_GetInterfaceList; + CK_C_GetInterface C_GetInterface; + CK_C_LoginUser C_LoginUser; + CK_C_SessionCancel C_SessionCancel; + CK_C_MessageEncryptInit C_MessageEncryptInit; + CK_C_EncryptMessage C_EncryptMessage; + CK_C_EncryptMessageBegin C_EncryptMessageBegin; + CK_C_EncryptMessageNext C_EncryptMessageNext; + CK_C_MessageEncryptFinal C_MessageEncryptFinal; + CK_C_MessageDecryptInit C_MessageDecryptInit; + CK_C_DecryptMessage C_DecryptMessage; + CK_C_DecryptMessageBegin C_DecryptMessageBegin; + CK_C_DecryptMessageNext C_DecryptMessageNext; + CK_C_MessageDecryptFinal C_MessageDecryptFinal; + CK_C_MessageSignInit C_MessageSignInit; + CK_C_SignMessage C_SignMessage; + CK_C_SignMessageBegin C_SignMessageBegin; + CK_C_SignMessageNext C_SignMessageNext; + CK_C_MessageSignFinal C_MessageSignFinal; + CK_C_MessageVerifyInit C_MessageVerifyInit; + CK_C_VerifyMessage C_VerifyMessage; + CK_C_VerifyMessageBegin C_VerifyMessageBegin; + CK_C_VerifyMessageNext C_VerifyMessageNext; + CK_C_MessageVerifyFinal C_MessageVerifyFinal; +}; + + typedef ck_rv_t (*ck_createmutex_t) (void **mutex); typedef ck_rv_t (*ck_destroymutex_t) (void *mutex); @@ -1091,96 +1604,97 @@ struct ck_c_initialize_args }; -#define CKF_LIBRARY_CANT_CREATE_OS_THREADS (1 << 0) -#define CKF_OS_LOCKING_OK (1 << 1) - -#define CKR_OK (0) -#define CKR_CANCEL (1) -#define CKR_HOST_MEMORY (2) -#define CKR_SLOT_ID_INVALID (3) -#define CKR_GENERAL_ERROR (5) -#define CKR_FUNCTION_FAILED (6) -#define CKR_ARGUMENTS_BAD (7) -#define CKR_NO_EVENT (8) -#define CKR_NEED_TO_CREATE_THREADS (9) -#define CKR_CANT_LOCK (0xa) -#define CKR_ATTRIBUTE_READ_ONLY (0x10) -#define CKR_ATTRIBUTE_SENSITIVE (0x11) -#define CKR_ATTRIBUTE_TYPE_INVALID (0x12) -#define CKR_ATTRIBUTE_VALUE_INVALID (0x13) -#define CKR_DATA_INVALID (0x20) -#define CKR_DATA_LEN_RANGE (0x21) -#define CKR_DEVICE_ERROR (0x30) -#define CKR_DEVICE_MEMORY (0x31) -#define CKR_DEVICE_REMOVED (0x32) -#define CKR_ENCRYPTED_DATA_INVALID (0x40) -#define CKR_ENCRYPTED_DATA_LEN_RANGE (0x41) -#define CKR_FUNCTION_CANCELED (0x50) -#define CKR_FUNCTION_NOT_PARALLEL (0x51) -#define CKR_FUNCTION_NOT_SUPPORTED (0x54) -#define CKR_KEY_HANDLE_INVALID (0x60) -#define CKR_KEY_SIZE_RANGE (0x62) -#define CKR_KEY_TYPE_INCONSISTENT (0x63) -#define CKR_KEY_NOT_NEEDED (0x64) -#define CKR_KEY_CHANGED (0x65) -#define CKR_KEY_NEEDED (0x66) -#define CKR_KEY_INDIGESTIBLE (0x67) -#define CKR_KEY_FUNCTION_NOT_PERMITTED (0x68) -#define CKR_KEY_NOT_WRAPPABLE (0x69) -#define CKR_KEY_UNEXTRACTABLE (0x6a) -#define CKR_MECHANISM_INVALID (0x70) -#define CKR_MECHANISM_PARAM_INVALID (0x71) -#define CKR_OBJECT_HANDLE_INVALID (0x82) -#define CKR_OPERATION_ACTIVE (0x90) -#define CKR_OPERATION_NOT_INITIALIZED (0x91) -#define CKR_PIN_INCORRECT (0xa0) -#define CKR_PIN_INVALID (0xa1) -#define CKR_PIN_LEN_RANGE (0xa2) -#define CKR_PIN_EXPIRED (0xa3) -#define CKR_PIN_LOCKED (0xa4) -#define CKR_SESSION_CLOSED (0xb0) -#define CKR_SESSION_COUNT (0xb1) -#define CKR_SESSION_HANDLE_INVALID (0xb3) -#define CKR_SESSION_PARALLEL_NOT_SUPPORTED (0xb4) -#define CKR_SESSION_READ_ONLY (0xb5) -#define CKR_SESSION_EXISTS (0xb6) -#define CKR_SESSION_READ_ONLY_EXISTS (0xb7) -#define CKR_SESSION_READ_WRITE_SO_EXISTS (0xb8) -#define CKR_SIGNATURE_INVALID (0xc0) -#define CKR_SIGNATURE_LEN_RANGE (0xc1) -#define CKR_TEMPLATE_INCOMPLETE (0xd0) -#define CKR_TEMPLATE_INCONSISTENT (0xd1) -#define CKR_TOKEN_NOT_PRESENT (0xe0) -#define CKR_TOKEN_NOT_RECOGNIZED (0xe1) -#define CKR_TOKEN_WRITE_PROTECTED (0xe2) -#define CKR_UNWRAPPING_KEY_HANDLE_INVALID (0xf0) -#define CKR_UNWRAPPING_KEY_SIZE_RANGE (0xf1) -#define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT (0xf2) -#define CKR_USER_ALREADY_LOGGED_IN (0x100) -#define CKR_USER_NOT_LOGGED_IN (0x101) -#define CKR_USER_PIN_NOT_INITIALIZED (0x102) -#define CKR_USER_TYPE_INVALID (0x103) -#define CKR_USER_ANOTHER_ALREADY_LOGGED_IN (0x104) -#define CKR_USER_TOO_MANY_TYPES (0x105) -#define CKR_WRAPPED_KEY_INVALID (0x110) -#define CKR_WRAPPED_KEY_LEN_RANGE (0x112) -#define CKR_WRAPPING_KEY_HANDLE_INVALID (0x113) -#define CKR_WRAPPING_KEY_SIZE_RANGE (0x114) -#define CKR_WRAPPING_KEY_TYPE_INCONSISTENT (0x115) -#define CKR_RANDOM_SEED_NOT_SUPPORTED (0x120) -#define CKR_RANDOM_NO_RNG (0x121) -#define CKR_DOMAIN_PARAMS_INVALID (0x130) -#define CKR_BUFFER_TOO_SMALL (0x150) -#define CKR_SAVED_STATE_INVALID (0x160) -#define CKR_INFORMATION_SENSITIVE (0x170) -#define CKR_STATE_UNSAVEABLE (0x180) -#define CKR_CRYPTOKI_NOT_INITIALIZED (0x190) -#define CKR_CRYPTOKI_ALREADY_INITIALIZED (0x191) -#define CKR_MUTEX_BAD (0x1a0) -#define CKR_MUTEX_NOT_LOCKED (0x1a1) -#define CKR_FUNCTION_REJECTED (0x200) -#define CKR_VENDOR_DEFINED (1U << 31) - +#define CKF_LIBRARY_CANT_CREATE_OS_THREADS (1UL << 0) +#define CKF_OS_LOCKING_OK (1UL << 1) + +#define CKR_OK (0UL) +#define CKR_CANCEL (1UL) +#define CKR_HOST_MEMORY (2UL) +#define CKR_SLOT_ID_INVALID (3UL) +#define CKR_GENERAL_ERROR (5UL) +#define CKR_FUNCTION_FAILED (6UL) +#define CKR_ARGUMENTS_BAD (7UL) +#define CKR_NO_EVENT (8UL) +#define CKR_NEED_TO_CREATE_THREADS (9UL) +#define CKR_CANT_LOCK (0xaUL) +#define CKR_ATTRIBUTE_READ_ONLY (0x10UL) +#define CKR_ATTRIBUTE_SENSITIVE (0x11UL) +#define CKR_ATTRIBUTE_TYPE_INVALID (0x12UL) +#define CKR_ATTRIBUTE_VALUE_INVALID (0x13UL) +#define CKR_ACTION_PROHIBITED (0x1BUL) +#define CKR_DATA_INVALID (0x20UL) +#define CKR_DATA_LEN_RANGE (0x21UL) +#define CKR_DEVICE_ERROR (0x30UL) +#define CKR_DEVICE_MEMORY (0x31UL) +#define CKR_DEVICE_REMOVED (0x32UL) +#define CKR_ENCRYPTED_DATA_INVALID (0x40UL) +#define CKR_ENCRYPTED_DATA_LEN_RANGE (0x41UL) +#define CKR_FUNCTION_CANCELED (0x50UL) +#define CKR_FUNCTION_NOT_PARALLEL (0x51UL) +#define CKR_FUNCTION_NOT_SUPPORTED (0x54UL) +#define CKR_KEY_HANDLE_INVALID (0x60UL) +#define CKR_KEY_SIZE_RANGE (0x62UL) +#define CKR_KEY_TYPE_INCONSISTENT (0x63UL) +#define CKR_KEY_NOT_NEEDED (0x64UL) +#define CKR_KEY_CHANGED (0x65UL) +#define CKR_KEY_NEEDED (0x66UL) +#define CKR_KEY_INDIGESTIBLE (0x67UL) +#define CKR_KEY_FUNCTION_NOT_PERMITTED (0x68UL) +#define CKR_KEY_NOT_WRAPPABLE (0x69UL) +#define CKR_KEY_UNEXTRACTABLE (0x6aUL) +#define CKR_MECHANISM_INVALID (0x70UL) +#define CKR_MECHANISM_PARAM_INVALID (0x71UL) +#define CKR_OBJECT_HANDLE_INVALID (0x82UL) +#define CKR_OPERATION_ACTIVE (0x90UL) +#define CKR_OPERATION_NOT_INITIALIZED (0x91UL) +#define CKR_PIN_INCORRECT (0xa0UL) +#define CKR_PIN_INVALID (0xa1UL) +#define CKR_PIN_LEN_RANGE (0xa2UL) +#define CKR_PIN_EXPIRED (0xa3UL) +#define CKR_PIN_LOCKED (0xa4UL) +#define CKR_SESSION_CLOSED (0xb0UL) +#define CKR_SESSION_COUNT (0xb1UL) +#define CKR_SESSION_HANDLE_INVALID (0xb3UL) +#define CKR_SESSION_PARALLEL_NOT_SUPPORTED (0xb4UL) +#define CKR_SESSION_READ_ONLY (0xb5UL) +#define CKR_SESSION_EXISTS (0xb6UL) +#define CKR_SESSION_READ_ONLY_EXISTS (0xb7UL) +#define CKR_SESSION_READ_WRITE_SO_EXISTS (0xb8UL) +#define CKR_SIGNATURE_INVALID (0xc0UL) +#define CKR_SIGNATURE_LEN_RANGE (0xc1UL) +#define CKR_TEMPLATE_INCOMPLETE (0xd0UL) +#define CKR_TEMPLATE_INCONSISTENT (0xd1UL) +#define CKR_TOKEN_NOT_PRESENT (0xe0UL) +#define CKR_TOKEN_NOT_RECOGNIZED (0xe1UL) +#define CKR_TOKEN_WRITE_PROTECTED (0xe2UL) +#define CKR_UNWRAPPING_KEY_HANDLE_INVALID (0xf0UL) +#define CKR_UNWRAPPING_KEY_SIZE_RANGE (0xf1UL) +#define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT (0xf2UL) +#define CKR_USER_ALREADY_LOGGED_IN (0x100UL) +#define CKR_USER_NOT_LOGGED_IN (0x101UL) +#define CKR_USER_PIN_NOT_INITIALIZED (0x102UL) +#define CKR_USER_TYPE_INVALID (0x103UL) +#define CKR_USER_ANOTHER_ALREADY_LOGGED_IN (0x104UL) +#define CKR_USER_TOO_MANY_TYPES (0x105UL) +#define CKR_WRAPPED_KEY_INVALID (0x110UL) +#define CKR_WRAPPED_KEY_LEN_RANGE (0x112UL) +#define CKR_WRAPPING_KEY_HANDLE_INVALID (0x113UL) +#define CKR_WRAPPING_KEY_SIZE_RANGE (0x114UL) +#define CKR_WRAPPING_KEY_TYPE_INCONSISTENT (0x115UL) +#define CKR_RANDOM_SEED_NOT_SUPPORTED (0x120UL) +#define CKR_RANDOM_NO_RNG (0x121UL) +#define CKR_DOMAIN_PARAMS_INVALID (0x130UL) +#define CKR_CURVE_NOT_SUPPORTED (0x140UL) +#define CKR_BUFFER_TOO_SMALL (0x150UL) +#define CKR_SAVED_STATE_INVALID (0x160UL) +#define CKR_INFORMATION_SENSITIVE (0x170UL) +#define CKR_STATE_UNSAVEABLE (0x180UL) +#define CKR_CRYPTOKI_NOT_INITIALIZED (0x190UL) +#define CKR_CRYPTOKI_ALREADY_INITIALIZED (0x191UL) +#define CKR_MUTEX_BAD (0x1a0UL) +#define CKR_MUTEX_NOT_LOCKED (0x1a1UL) +#define CKR_FUNCTION_REJECTED (0x200UL) +#define CKR_VENDOR_DEFINED (1UL << 31) /* Compatibility layer. */ @@ -1216,6 +1730,22 @@ typedef void **CK_VOID_PTR_PTR; #endif #endif +typedef struct CK_HKDF_PARAMS { + CK_BBOOL bExtract; + CK_BBOOL bExpand; + CK_MECHANISM_TYPE prfHashMechanism; + CK_ULONG ulSaltType; + CK_BYTE_PTR pSalt; + CK_ULONG ulSaltLen; + CK_OBJECT_HANDLE hSaltKey; + CK_BYTE_PTR pInfo; + CK_ULONG ulInfoLen; +} CK_HKDF_PARAMS; + +#define CKF_HKDF_SALT_NULL 0x00000001UL +#define CKF_HKDF_SALT_DATA 0x00000002UL +#define CKF_HKDF_SALT_KEY 0x00000004UL + typedef struct ck_version CK_VERSION; typedef struct ck_version *CK_VERSION_PTR; @@ -1247,16 +1777,26 @@ typedef struct ck_date *CK_DATE_PTR; typedef ck_mechanism_type_t *CK_MECHANISM_TYPE_PTR; +typedef ck_rsa_pkcs_mgf_type_t *CK_RSA_PKCS_MGF_TYPE_PTR; + typedef struct ck_mechanism CK_MECHANISM; typedef struct ck_mechanism *CK_MECHANISM_PTR; typedef struct ck_mechanism_info CK_MECHANISM_INFO; typedef struct ck_mechanism_info *CK_MECHANISM_INFO_PTR; +typedef struct ck_interface CK_INTERFACE; +typedef struct ck_interface *CK_INTERFACE_PTR; +typedef struct ck_interface **CK_INTERFACE_PTR_PTR; + typedef struct ck_function_list CK_FUNCTION_LIST; typedef struct ck_function_list *CK_FUNCTION_LIST_PTR; typedef struct ck_function_list **CK_FUNCTION_LIST_PTR_PTR; +typedef struct ck_function_list_3_0 CK_FUNCTION_LIST_3_0; +typedef struct ck_function_list_3_0 *CK_FUNCTION_LIST_3_0_PTR; +typedef struct ck_function_list_3_0 **CK_FUNCTION_LIST_3_0_PTR_PTR; + typedef struct ck_c_initialize_args CK_C_INITIALIZE_ARGS; typedef struct ck_c_initialize_args *CK_C_INITIALIZE_ARGS_PTR; @@ -1317,6 +1857,8 @@ typedef struct ck_c_initialize_args *CK_C_INITIALIZE_ARGS_PTR; #undef ck_mechanism_type_t +#undef ck_rsa_pkcs_mgf_type_t + #undef ck_mechanism #undef parameter #undef parameter_len @@ -1328,7 +1870,10 @@ typedef struct ck_c_initialize_args *CK_C_INITIALIZE_ARGS_PTR; #undef ck_rv_t #undef ck_notify_t +#undef ck_interface + #undef ck_function_list +#undef ck_function_list_3_0 #undef ck_createmutex_t #undef ck_destroymutex_t @@ -1344,7 +1889,6 @@ typedef struct ck_c_initialize_args *CK_C_INITIALIZE_ARGS_PTR; #endif /* CRYPTOKI_COMPAT */ - /* System dependencies. */ #if defined(_WIN32) || defined(CRYPTOKI_FORCE_WIN32) #pragma pack(pop, cryptoki) From 361ff0ca308ac02449e71689fc5ea72114db43db Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Sat, 26 Jul 2025 01:51:44 +0000 Subject: [PATCH 160/244] upstream: Support ed25519 keys hosted on PKCS#11 tokens. Tested on Yubikeys and against SoftHSM2. feedback/ok tb@ OpenBSD-Commit-ID: 90ddb6529f2e12e98e8bba21d8592e60579ce2e4 --- ssh-pkcs11.c | 217 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 214 insertions(+), 3 deletions(-) diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c index e22b3e419fb5..34e430875510 100644 --- a/ssh-pkcs11.c +++ b/ssh-pkcs11.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-pkcs11.c,v 1.66 2025/07/24 06:59:51 djm Exp $ */ +/* $OpenBSD: ssh-pkcs11.c,v 1.67 2025/07/26 01:51:44 djm Exp $ */ /* * Copyright (c) 2010 Markus Friedl. All rights reserved. * Copyright (c) 2014 Pedro Martelletto. All rights reserved. @@ -51,6 +51,7 @@ #include "ssh-pkcs11.h" #include "digest.h" #include "xmalloc.h" +#include "crypto_api.h" struct pkcs11_slotinfo { CK_TOKEN_INFO token; @@ -709,6 +710,69 @@ pkcs11_sign_ecdsa(struct sshkey *key, #endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ +static int +pkcs11_sign_ed25519(struct sshkey *key, + u_char **sigp, size_t *lenp, + const u_char *data, size_t datalen, + const char *alg, const char *sk_provider, + const char *sk_pin, u_int compat) +{ + struct pkcs11_key *k11; + struct pkcs11_slotinfo *si; + CK_FUNCTION_LIST *f; + CK_ULONG slen = 0; + CK_RV rv; + u_char *sig = NULL; + CK_BYTE *xdata = NULL; + int ret = -1; + + if (sigp != NULL) + *sigp = 0; + if (lenp != NULL) + *lenp = 0; + + if ((k11 = pkcs11_lookup_key(key)) == NULL) { + error_f("no key found"); + return SSH_ERR_KEY_NOT_FOUND; + } + + if (pkcs11_get_key(k11, CKM_EDDSA) == -1) { + error("pkcs11_get_key failed"); + return SSH_ERR_AGENT_FAILURE; + } + + debug3_f("sign using provider %s slotidx %lu", + k11->provider->name, (u_long)k11->slotidx); + + f = k11->provider->function_list; + si = &k11->provider->slotinfo[k11->slotidx]; + + xdata = xmalloc(datalen); + memcpy(xdata, data, datalen); + sig = xmalloc(crypto_sign_ed25519_BYTES); + slen = crypto_sign_ed25519_BYTES; + + rv = f->C_Sign(si->session, xdata, datalen, sig, &slen); + if (rv != CKR_OK) { + error("C_Sign failed: %lu", rv); + goto done; + } + if (slen != crypto_sign_ed25519_BYTES) { + error_f("bad signature length: %lu", (u_long)slen); + goto done; + } + if ((ret = ssh_ed25519_encode_store_sig(sig, slen, sigp, lenp)) != 0) + fatal_fr(ret, "couldn't store signature"); + + /* success */ + ret = 0; + done: + if (xdata != NULL) + freezero(xdata, datalen); + free(sig); + return ret; +} + /* remove trailing spaces */ static char * rmspace(u_char *buf, size_t len) @@ -1022,6 +1086,115 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, return key; } +static struct sshkey * +pkcs11_fetch_ed25519_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, + CK_OBJECT_HANDLE *obj) +{ + CK_ATTRIBUTE key_attr[3]; + CK_SESSION_HANDLE session; + CK_FUNCTION_LIST *f = NULL; + CK_RV rv; + struct sshkey *key = NULL; + const unsigned char *d = NULL; + size_t len; + char *hex = NULL; + int success = -1, i; + /* https://docs.oasis-open.org/pkcs11/pkcs11-curr/v3.0/os/pkcs11-curr-v3.0-os.html#_Toc30061180 */ + const u_char id1[14] = { + 0x13, 0x0c, 0x65, 0x64, 0x77, 0x61, 0x72, 0x64, + 0x73, 0x32, 0x35, 0x35, 0x31, 0x39, + }; /* PrintableString { "edwards25519" } */ + const u_char id2[5] = { + 0x06, 0x03, 0x2b, 0x65, 0x70, + }; /* OBJECT_IDENTIFIER { 1.3.101.112 } */ + + memset(&key_attr, 0, sizeof(key_attr)); + key_attr[0].type = CKA_ID; + key_attr[1].type = CKA_EC_POINT; /* XXX or CKA_VALUE ? */ + key_attr[2].type = CKA_EC_PARAMS; + + session = p->slotinfo[slotidx].session; + f = p->function_list; + + /* figure out size of the attributes */ + rv = f->C_GetAttributeValue(session, *obj, key_attr, 3); + if (rv != CKR_OK) { + error("C_GetAttributeValue failed: %lu", rv); + return (NULL); + } + + /* + * Allow CKA_ID (always first attribute) to be empty, but + * ensure that none of the others are zero length. + * XXX assumes CKA_ID is always first. + */ + if (key_attr[1].ulValueLen == 0 || + key_attr[2].ulValueLen == 0) { + error("invalid attribute length"); + return (NULL); + } + + /* allocate buffers for attributes */ + for (i = 0; i < 3; i++) { + if (key_attr[i].ulValueLen > 0) + key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen); + } + + /* retrieve ID, public point and curve parameters of EC key */ + rv = f->C_GetAttributeValue(session, *obj, key_attr, 3); + if (rv != CKR_OK) { + error("C_GetAttributeValue failed: %lu", rv); + goto fail; + } + + /* Expect one of the supported identifiers in CKA_EC_PARAMS */ + d = (u_char *)key_attr[2].pValue; + len = key_attr[2].ulValueLen; + if ((len != sizeof(id1) || memcmp(d, id1, sizeof(id1)) != 0) && + (len != sizeof(id2) || memcmp(d, id2, sizeof(id2)) != 0)) { + hex = tohex(d, len); + logit_f("unsupported CKA_EC_PARAMS: %s (len %zu)", hex, len); + goto fail; + } + + /* + * Expect either a raw 32 byte pubkey or an OCTET STRING with + * a 32 byte pubkey in CKA_VALUE + */ + d = (u_char *)key_attr[1].pValue; + len = key_attr[1].ulValueLen; + if (len == ED25519_PK_SZ + 2 && d[0] == 0x04 && d[1] == ED25519_PK_SZ) { + d += 2; + len -= 2; + } + if (len != ED25519_PK_SZ) { + hex = tohex(key_attr[1].pValue, key_attr[1].ulValueLen); + logit_f("CKA_EC_POINT invalid octet str: %s (len %lu)", + hex, (u_long)key_attr[1].ulValueLen); + goto fail; + } + + if ((key = sshkey_new(KEY_UNSPEC)) == NULL) + fatal_f("sshkey_new failed"); + key->ed25519_pk = xmalloc(ED25519_PK_SZ); + memcpy(key->ed25519_pk, d, ED25519_PK_SZ); + key->type = KEY_ED25519; + key->flags |= SSHKEY_FLAG_EXT; + if (pkcs11_record_key(p, slotidx, &key_attr[0], key)) + goto fail; + /* success */ + success = 0; + fail: + if (success != 0) { + sshkey_free(key); + key = NULL; + } + free(hex); + for (i = 0; i < 3; i++) + free(key_attr[i].pValue); + return key; +} + static int pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, CK_OBJECT_HANDLE *obj, struct sshkey **keyp, char **labelp) @@ -1039,6 +1212,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, int i, success = -1; const u_char *cp; char *subject = NULL; + size_t len; #ifdef OPENSSL_HAS_ECC int r, nid; #endif @@ -1176,6 +1350,26 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, /* success */ success = 0; #endif /* OPENSSL_HAS_ECC */ + } else if (EVP_PKEY_base_id(evp) == EVP_PKEY_ED25519) { + if ((key = sshkey_new(KEY_UNSPEC)) == NULL || + (key->ed25519_pk = calloc(1, ED25519_PK_SZ)) == NULL) + fatal_f("allocation failed"); + len = ED25519_PK_SZ; + if (!EVP_PKEY_get_raw_public_key(evp, key->ed25519_pk, &len)) { + ossl_error("EVP_PKEY_get_raw_public_key failed"); + goto out; + } + if (len != ED25519_PK_SZ) { + error_f("incorrect returned public key " + "length for ed25519"); + goto out; + } + key->type = KEY_ED25519; + key->flags |= SSHKEY_FLAG_EXT; + if (pkcs11_record_key(p, slotidx, &cert_attr[0], key)) + goto out; + /* success */ + success = 0; } else { error("unknown certificate key type"); goto out; @@ -1406,6 +1600,9 @@ pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, key = pkcs11_fetch_ecdsa_pubkey(p, slotidx, &obj); break; #endif /* OPENSSL_HAS_ECC */ + case CKK_EC_EDWARDS: + key = pkcs11_fetch_ed25519_pubkey(p, slotidx, &obj); + break; default: /* XXX print key type? */ key = NULL; @@ -1879,6 +2076,10 @@ pkcs11_sign(struct sshkey *key, return pkcs11_sign_ecdsa(key, sigp, lenp, data, datalen, alg, sk_provider, sk_pin, compat); #endif /* OPENSSL_HAS_ECC */ + case KEY_ED25519: + case KEY_ED25519_CERT: + return pkcs11_sign_ed25519(key, sigp, lenp, data, datalen, + alg, sk_provider, sk_pin, compat); default: return SSH_ERR_KEY_TYPE_UNKNOWN; } @@ -2033,10 +2234,20 @@ pkcs11_destroy_keypair(char *provider_id, char *pin, unsigned long slotidx, *err = rv; key_type = -1; } - if (key_type == CKK_RSA) + switch (key_type) { + case CKK_RSA: k = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj); - else if (key_type == CKK_ECDSA) + break; + case CKK_ECDSA: k = pkcs11_fetch_ecdsa_pubkey(p, slotidx, &obj); + break; + case CKK_EC_EDWARDS: + k = pkcs11_fetch_ed25519_pubkey(p, slotidx, &obj); + break; + default: + debug_f("unsupported key type %lu", (u_long)key_type); + continue; + } if ((rv = f->C_DestroyObject(session, obj)) != CKR_OK) { debug_f("could not destroy public key 0x%hhx", keyid); From a729163c56ecc002c0cb04db56e7d86ceec2e8b0 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Sat, 26 Jul 2025 01:53:31 +0000 Subject: [PATCH 161/244] upstream: regression tests for Ed25519 keys in PKCS#11 tokens OpenBSD-Regress-ID: 50067c0716abfea3a526b4a0c8f1fe15e7665c0f --- regress/agent-pkcs11-cert.sh | 28 +++++++++++++++++++++------- regress/agent-pkcs11-restrict.sh | 3 ++- regress/agent-pkcs11.sh | 4 ++-- regress/test-exec.sh | 14 +++++++++++++- 4 files changed, 38 insertions(+), 11 deletions(-) diff --git a/regress/agent-pkcs11-cert.sh b/regress/agent-pkcs11-cert.sh index 39e839f9c26a..551067d23f5f 100644 --- a/regress/agent-pkcs11-cert.sh +++ b/regress/agent-pkcs11-cert.sh @@ -1,4 +1,4 @@ -# $OpenBSD: agent-pkcs11-cert.sh,v 1.2 2025/05/24 04:41:12 djm Exp $ +# $OpenBSD: agent-pkcs11-cert.sh,v 1.3 2025/07/26 01:53:31 djm Exp $ # Placed in the Public Domain. tid="pkcs11 agent certificate test" @@ -16,7 +16,10 @@ $SSHKEYGEN -qs $OBJ/ca -I "ecdsa_key" -n $USER -z 1 ${SSH_SOFTHSM_DIR}/EC.pub || fatal "certify ECDSA key failed" $SSHKEYGEN -qs $OBJ/ca -I "rsa_key" -n $USER -z 2 ${SSH_SOFTHSM_DIR}/RSA.pub || fatal "certify RSA key failed" -$SSHKEYGEN -qs $OBJ/ca -I "ca_ca" -n $USER -z 3 $OBJ/ca.pub || +$SSHKEYGEN -qs $OBJ/ca -I "ed25519_key" -n $USER -z 3 \ + ${SSH_SOFTHSM_DIR}/ED25519.pub || + fatal "certify ed25519 key failed" +$SSHKEYGEN -qs $OBJ/ca -I "ca_ca" -n $USER -z 4 $OBJ/ca.pub || fatal "certify CA key failed" start_ssh_agent @@ -25,6 +28,8 @@ verbose "load pkcs11 keys and certs" # Note: deliberately contains non-cert keys and non-matching cert on commandline p11_ssh_add -qs ${TEST_SSH_PKCS11} \ $OBJ/ca.pub \ + ${SSH_SOFTHSM_DIR}/ED25519.pub \ + ${SSH_SOFTHSM_DIR}/ED25519-cert.pub \ ${SSH_SOFTHSM_DIR}/EC.pub \ ${SSH_SOFTHSM_DIR}/EC-cert.pub \ ${SSH_SOFTHSM_DIR}/RSA.pub \ @@ -33,8 +38,10 @@ p11_ssh_add -qs ${TEST_SSH_PKCS11} \ # Verify their presence verbose "verify presence" cut -d' ' -f1-2 \ + ${SSH_SOFTHSM_DIR}/ED25519.pub \ ${SSH_SOFTHSM_DIR}/EC.pub \ ${SSH_SOFTHSM_DIR}/RSA.pub \ + ${SSH_SOFTHSM_DIR}/ED25519-cert.pub \ ${SSH_SOFTHSM_DIR}/EC-cert.pub \ ${SSH_SOFTHSM_DIR}/RSA-cert.pub | sort > $OBJ/expect_list $SSHADD -L | cut -d' ' -f1-2 | sort > $OBJ/output_list @@ -43,16 +50,19 @@ diff $OBJ/expect_list $OBJ/output_list # Verify that all can perform signatures. verbose "check signatures" for x in ${SSH_SOFTHSM_DIR}/EC.pub ${SSH_SOFTHSM_DIR}/RSA.pub \ - ${SSH_SOFTHSM_DIR}/EC-cert.pub ${SSH_SOFTHSM_DIR}/RSA-cert.pub ; do + ${SSH_SOFTHSM_DIR}/EC-cert.pub ${SSH_SOFTHSM_DIR}/RSA-cert.pub \ + ${SSH_SOFTHSM_DIR}/ED25519.pub ${SSH_SOFTHSM_DIR}/ED25519-cert.pub ; do $SSHADD -T $x || fail "Signing failed for $x" done # Delete plain keys. verbose "delete plain keys" $SSHADD -qd ${SSH_SOFTHSM_DIR}/EC.pub ${SSH_SOFTHSM_DIR}/RSA.pub +$SSHADD -qd ${SSH_SOFTHSM_DIR}/ED25519.pub # Verify that certs can still perform signatures. verbose "reverify certificate signatures" -for x in ${SSH_SOFTHSM_DIR}/EC-cert.pub ${SSH_SOFTHSM_DIR}/RSA-cert.pub ; do +for x in ${SSH_SOFTHSM_DIR}/EC-cert.pub ${SSH_SOFTHSM_DIR}/RSA-cert.pub \ + ${SSH_SOFTHSM_DIR}/ED25519-cert.pub ; do $SSHADD -T $x || fail "Signing failed for $x" done @@ -64,18 +74,22 @@ p11_ssh_add -qCs ${TEST_SSH_PKCS11} \ ${SSH_SOFTHSM_DIR}/EC.pub \ ${SSH_SOFTHSM_DIR}/EC-cert.pub \ ${SSH_SOFTHSM_DIR}/RSA.pub \ - ${SSH_SOFTHSM_DIR}/RSA-cert.pub || + ${SSH_SOFTHSM_DIR}/RSA-cert.pub \ + ${SSH_SOFTHSM_DIR}/ED25519.pub \ + ${SSH_SOFTHSM_DIR}/ED25519-cert.pub || fatal "failed to add keys" # Verify their presence verbose "verify presence" cut -d' ' -f1-2 \ ${SSH_SOFTHSM_DIR}/EC-cert.pub \ - ${SSH_SOFTHSM_DIR}/RSA-cert.pub | sort > $OBJ/expect_list + ${SSH_SOFTHSM_DIR}/RSA-cert.pub \ + ${SSH_SOFTHSM_DIR}/ED25519-cert.pub | sort > $OBJ/expect_list $SSHADD -L | cut -d' ' -f1-2 | sort > $OBJ/output_list diff $OBJ/expect_list $OBJ/output_list # Verify that certs can perform signatures. verbose "check signatures" -for x in ${SSH_SOFTHSM_DIR}/EC-cert.pub ${SSH_SOFTHSM_DIR}/RSA-cert.pub ; do +for x in ${SSH_SOFTHSM_DIR}/EC-cert.pub ${SSH_SOFTHSM_DIR}/RSA-cert.pub \ + ${SSH_SOFTHSM_DIR}/ED25519-cert.pub ; do $SSHADD -T $x || fail "Signing failed for $x" done diff --git a/regress/agent-pkcs11-restrict.sh b/regress/agent-pkcs11-restrict.sh index e5763ea8f6d0..9fc5e1c69f50 100644 --- a/regress/agent-pkcs11-restrict.sh +++ b/regress/agent-pkcs11-restrict.sh @@ -1,4 +1,4 @@ -# $OpenBSD: agent-pkcs11-restrict.sh,v 1.2 2025/05/24 04:41:12 djm Exp $ +# $OpenBSD: agent-pkcs11-restrict.sh,v 1.3 2025/07/26 01:53:31 djm Exp $ # Placed in the Public Domain. tid="pkcs11 agent constraint test" @@ -16,6 +16,7 @@ for h in a b x ca ; do done # XXX test CA hostcerts too. +# XXX test ed25519 keys key_for() { case $h in diff --git a/regress/agent-pkcs11.sh b/regress/agent-pkcs11.sh index 731c1f9ddc96..491466659211 100644 --- a/regress/agent-pkcs11.sh +++ b/regress/agent-pkcs11.sh @@ -1,4 +1,4 @@ -# $OpenBSD: agent-pkcs11.sh,v 1.14 2025/05/24 04:41:03 djm Exp $ +# $OpenBSD: agent-pkcs11.sh,v 1.15 2025/07/26 01:53:31 djm Exp $ # Placed in the Public Domain. tid="pkcs11 agent test" @@ -21,7 +21,7 @@ if [ $r -ne 0 ]; then fail "ssh-add -l failed: exit code $r" fi -for k in $RSA $EC; do +for k in $ED25519 $RSA $EC; do trace "testing $k" pub=$(cat $k.pub) ${SSHADD} -L | grep -q "$pub" || \ diff --git a/regress/test-exec.sh b/regress/test-exec.sh index 0ecf6c5a83c0..c5270042e6a9 100644 --- a/regress/test-exec.sh +++ b/regress/test-exec.sh @@ -1,4 +1,4 @@ -# $OpenBSD: test-exec.sh,v 1.130 2025/06/28 13:34:08 dtucker Exp $ +# $OpenBSD: test-exec.sh,v 1.131 2025/07/26 01:53:31 djm Exp $ # Placed in the Public Domain. #SUDO=sudo @@ -979,6 +979,18 @@ EOF --import $ECP8 >/dev/null || fatal "softhsm import EC fail" chmod 600 $EC ssh-keygen -y -f $EC > ${EC}.pub + # Ed25519 key + ED25519=${SSH_SOFTHSM_DIR}/ED25519 + ED25519P8=${SSH_SOFTHSM_DIR}/ED25519P8 + $OPENSSL_BIN genpkey -algorithm ed25519 > $ED25519 || \ + fatal "genpkey Ed25519 fail" + $OPENSSL_BIN pkcs8 -nocrypt -in $ED25519 > $ED25519P8 || \ + fatal "pkcs8 Ed25519 fail" + softhsm2-util --slot "$slot" --label 03 --id 03 --pin "$TEST_SSH_PIN" \ + --import $ED25519P8 >/dev/null || \ + fatal "softhsm import ed25519 fail" + chmod 600 $ED25519 + ssh-keygen -y -f $ED25519 > ${ED25519}.pub # Prepare askpass script to load PIN. PIN_SH=$SSH_SOFTHSM_DIR/pin.sh cat > $PIN_SH << EOF From 2603098959eff55cbe188c3dfcbe5302808a80fc Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Sat, 26 Jul 2025 14:27:53 +1000 Subject: [PATCH 162/244] repair build for libcrypto without ed25519 support --- ssh-pkcs11.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c index 34e430875510..4ab1fa90e9b0 100644 --- a/ssh-pkcs11.c +++ b/ssh-pkcs11.c @@ -1212,7 +1212,9 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, int i, success = -1; const u_char *cp; char *subject = NULL; +#ifdef OPENSSL_HAS_ED25519 size_t len; +#endif /* OPENSSL_HAS_ED25519 */ #ifdef OPENSSL_HAS_ECC int r, nid; #endif @@ -1350,6 +1352,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, /* success */ success = 0; #endif /* OPENSSL_HAS_ECC */ +#ifdef OPENSSL_HAS_ED25519 } else if (EVP_PKEY_base_id(evp) == EVP_PKEY_ED25519) { if ((key = sshkey_new(KEY_UNSPEC)) == NULL || (key->ed25519_pk = calloc(1, ED25519_PK_SZ)) == NULL) @@ -1370,6 +1373,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, goto out; /* success */ success = 0; +#endif /* OPENSSL_HAS_ED25519 */ } else { error("unknown certificate key type"); goto out; From 5e4bfe6c16924b1c21a733f3e218cfcba98e301e Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Sat, 26 Jul 2025 19:19:46 +1000 Subject: [PATCH 163/244] more ec/ed25519 fixing --- ssh-pkcs11.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c index 4ab1fa90e9b0..98d1732bbed6 100644 --- a/ssh-pkcs11.c +++ b/ssh-pkcs11.c @@ -87,7 +87,7 @@ TAILQ_HEAD(, pkcs11_key) pkcs11_keys; /* XXX a tree would be better */ int pkcs11_interactive = 0; -#ifdef OPENSSL_HAS_ECC +#if defined(OPENSSL_HAS_ECC) || defined(OPENSSL_HAS_ED25519) static void ossl_error(const char *msg) { @@ -1207,7 +1207,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, X509_NAME *x509_name = NULL; EVP_PKEY *evp; RSA *rsa = NULL; - EC_KEY *ec = NULL; + struct sshkey *key = NULL; int i, success = -1; const u_char *cp; @@ -1216,6 +1216,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, size_t len; #endif /* OPENSSL_HAS_ED25519 */ #ifdef OPENSSL_HAS_ECC + EC_KEY *ec = NULL; int r, nid; #endif From a5bec2cdfc4f38ddb6211809851aae29ba99a35a Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Wed, 30 Jul 2025 04:19:17 +0000 Subject: [PATCH 164/244] upstream: fix variable name in disabled code OpenBSD-Commit-ID: 5612e979575d5da933c8b720d296423fd84392f5 --- ssh-pkcs11.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c index 98d1732bbed6..18e6c1ff7821 100644 --- a/ssh-pkcs11.c +++ b/ssh-pkcs11.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-pkcs11.c,v 1.67 2025/07/26 01:51:44 djm Exp $ */ +/* $OpenBSD: ssh-pkcs11.c,v 1.68 2025/07/30 04:19:17 djm Exp $ */ /* * Copyright (c) 2010 Markus Friedl. All rights reserved. * Copyright (c) 2014 Pedro Martelletto. All rights reserved. @@ -1746,7 +1746,7 @@ pkcs11_decode_hex(const char *hex, unsigned char **dest, size_t *rlen) *dest = xmalloc(len); for (i = 0; i < len; i++) { - int hi, low; + int hi, lo; hi = h2i(hex[2 * i]); lo = h2i(hex[(2 * i) + 1]); @@ -2251,7 +2251,7 @@ pkcs11_destroy_keypair(char *provider_id, char *pin, unsigned long slotidx, break; default: debug_f("unsupported key type %lu", (u_long)key_type); - continue; + break; } if ((rv = f->C_DestroyObject(session, obj)) != CKR_OK) { From dc630e6d81be8aa495254839731e4f3521cf9e31 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Wed, 30 Jul 2025 04:27:42 +0000 Subject: [PATCH 165/244] upstream: unbreak WITH_OPENSSL=no builds, also allowing ed25519 keys to be used via PKCS#11 when OpenSSH is built without libcrypto. OpenBSD-Commit-ID: ecf26fdf7591bf2c98bac5136fbc36e0b59c3fc2 --- configure.ac | 3 --- ssh-pkcs11-helper.c | 2 +- ssh-pkcs11.c | 31 +++++++++++++++++++------------ ssh-pkcs11.h | 6 +----- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/configure.ac b/configure.ac index 9bc664172b0d..460ebd3b476c 100644 --- a/configure.ac +++ b/configure.ac @@ -3322,9 +3322,6 @@ AC_CHECK_DECL([OPENSSL_IS_AWSLC], [], [#include ] ) -if test "x$openssl" != "xyes" ; then - enable_pkcs11="disabled; missing libcrypto" -fi if test "x$ac_cv_func_dlopen" != "xyes" ; then enable_pkcs11="disabled; missing dlopen(3)" enable_sk="disabled; missing dlopen(3)" diff --git a/ssh-pkcs11-helper.c b/ssh-pkcs11-helper.c index 2d818b8970a4..32111fef6b29 100644 --- a/ssh-pkcs11-helper.c +++ b/ssh-pkcs11-helper.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-pkcs11-helper.c,v 1.28 2025/07/24 05:44:55 djm Exp $ */ +/* $OpenBSD: ssh-pkcs11-helper.c,v 1.29 2025/07/30 04:27:42 djm Exp $ */ /* * Copyright (c) 2010 Markus Friedl. All rights reserved. * diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c index 18e6c1ff7821..5b0ce304e925 100644 --- a/ssh-pkcs11.c +++ b/ssh-pkcs11.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-pkcs11.c,v 1.68 2025/07/30 04:19:17 djm Exp $ */ +/* $OpenBSD: ssh-pkcs11.c,v 1.69 2025/07/30 04:27:42 djm Exp $ */ /* * Copyright (c) 2010 Markus Friedl. All rights reserved. * Copyright (c) 2014 Pedro Martelletto. All rights reserved. @@ -35,9 +35,11 @@ #include "openbsd-compat/sys-queue.h" #include "openbsd-compat/openssl-compat.h" +#ifdef WITH_OPENSSL #include #include #include +#endif #define CRYPTOKI_COMPAT #include "pkcs11.h" @@ -1085,6 +1087,7 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, } return key; } +#endif /* WITH_OPENSSL */ static struct sshkey * pkcs11_fetch_ed25519_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, @@ -1195,6 +1198,7 @@ pkcs11_fetch_ed25519_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, return key; } +#ifdef WITH_OPENSSL static int pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, CK_OBJECT_HANDLE *obj, struct sshkey **keyp, char **labelp) @@ -1397,17 +1401,6 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, *labelp = subject; return 0; } - -#if 0 -static int -have_rsa_key(const RSA *rsa) -{ - const BIGNUM *rsa_n, *rsa_e; - - RSA_get0_key(rsa, &rsa_n, &rsa_e, NULL); - return rsa_n != NULL && rsa_e != NULL; -} -#endif #endif /* WITH_OPENSSL */ static void @@ -1426,6 +1419,7 @@ note_key(struct pkcs11_provider *p, CK_ULONG slotidx, const char *context, free(fp); } +#ifdef WITH_OPENSSL /* libcrypto needed for certificate parsing */ /* * lookup certificates for token in slot identified by slotidx, * add 'wrapped' public keys to the 'keysp' array and increment nkeys. @@ -1530,6 +1524,7 @@ pkcs11_fetch_certs(struct pkcs11_provider *p, CK_ULONG slotidx, return (ret); } +#endif /* WITH_OPENSSL */ /* * lookup public keys for token in slot identified by slotidx, @@ -1597,6 +1592,7 @@ pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, label[key_attr[1].ulValueLen] = '\0'; switch (ck_key_type) { +#ifdef WITH_OPENSSL case CKK_RSA: key = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj); break; @@ -1605,6 +1601,7 @@ pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, key = pkcs11_fetch_ecdsa_pubkey(p, slotidx, &obj); break; #endif /* OPENSSL_HAS_ECC */ +#endif /* WITH_OPENSSL */ case CKK_EC_EDWARDS: key = pkcs11_fetch_ed25519_pubkey(p, slotidx, &obj); break; @@ -1967,7 +1964,9 @@ pkcs11_register_provider(char *provider_id, char *pin, keyp == NULL) continue; pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys); +#ifdef WITH_OPENSSL pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys); +#endif if (nkeys == 0 && !p->slotinfo[i].logged_in && pkcs11_interactive) { /* @@ -1980,7 +1979,9 @@ pkcs11_register_provider(char *provider_id, char *pin, continue; } pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys); +#ifdef WITH_OPENSSL pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys); +#endif } } @@ -2073,6 +2074,7 @@ pkcs11_sign(struct sshkey *key, switch (key->type) { case KEY_RSA: case KEY_RSA_CERT: +#ifdef WITH_OPENSSL return pkcs11_sign_rsa(key, sigp, lenp, data, datalen, alg, sk_provider, sk_pin, compat); #ifdef OPENSSL_HAS_ECC @@ -2081,6 +2083,7 @@ pkcs11_sign(struct sshkey *key, return pkcs11_sign_ecdsa(key, sigp, lenp, data, datalen, alg, sk_provider, sk_pin, compat); #endif /* OPENSSL_HAS_ECC */ +#endif /* WITH_OPENSSL */ case KEY_ED25519: case KEY_ED25519_CERT: return pkcs11_sign_ed25519(key, sigp, lenp, data, datalen, @@ -2240,12 +2243,16 @@ pkcs11_destroy_keypair(char *provider_id, char *pin, unsigned long slotidx, key_type = -1; } switch (key_type) { +#ifdef WITH_OPENSSL case CKK_RSA: k = pkcs11_fetch_rsa_pubkey(p, slotidx, &obj); break; +#ifdef OPENSSL_HAS_ECC case CKK_ECDSA: k = pkcs11_fetch_ecdsa_pubkey(p, slotidx, &obj); break; +#endif /* OPENSSL_HAS_ECC */ +#endif /* WITH_OPENSSL */ case CKK_EC_EDWARDS: k = pkcs11_fetch_ed25519_pubkey(p, slotidx, &obj); break; diff --git a/ssh-pkcs11.h b/ssh-pkcs11.h index f3a03b6fa913..d86c506c1c57 100644 --- a/ssh-pkcs11.h +++ b/ssh-pkcs11.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-pkcs11.h,v 1.8 2025/07/24 05:44:55 djm Exp $ */ +/* $OpenBSD: ssh-pkcs11.h,v 1.9 2025/07/30 04:27:42 djm Exp $ */ /* * Copyright (c) 2010 Markus Friedl. All rights reserved. * @@ -45,7 +45,3 @@ struct sshkey * /* Only available in ssh-pkcs11-client.c */ int pkcs11_make_cert(const struct sshkey *, const struct sshkey *, struct sshkey **); - -#if !defined(WITH_OPENSSL) && defined(ENABLE_PKCS11) -#undef ENABLE_PKCS11 -#endif From 284abbed9a8d815b1ec5e96aff885d77e26537e7 Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Wed, 30 Jul 2025 10:17:13 +0000 Subject: [PATCH 166/244] upstream: Plug leak in case where sigp is passed as NULL. Coverity CID 483725, ok djm@ OpenBSD-Commit-ID: 47cf7b399c84e102b670b9f97ab6926c9a7256b5 --- ssh-pkcs11-client.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ssh-pkcs11-client.c b/ssh-pkcs11-client.c index 64b8f4c1c0ac..8be0d8aecff0 100644 --- a/ssh-pkcs11-client.c +++ b/ssh-pkcs11-client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-pkcs11-client.c,v 1.23 2025/07/25 11:50:45 dtucker Exp $ */ +/* $OpenBSD: ssh-pkcs11-client.c,v 1.24 2025/07/30 10:17:13 dtucker Exp $ */ /* * Copyright (c) 2010 Markus Friedl. All rights reserved. * Copyright (c) 2014 Pedro Martelletto. All rights reserved. @@ -278,6 +278,7 @@ pkcs11_sign(struct sshkey *key, ret = 0; fail: + free(signature); sshbuf_free(msg); return ret; } From b1c4cedbee107dc611ce091f27ea9f1de28ee378 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Fri, 1 Aug 2025 19:29:00 +1000 Subject: [PATCH 167/244] Replace fbsd64ppc VM with physical host. Run 64bit bigendian interop test on NetBSD arm64be instead. --- .github/workflows/selfhosted.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/selfhosted.yml b/.github/workflows/selfhosted.yml index 281b2fc84dee..3bc54d64b1ed 100644 --- a/.github/workflows/selfhosted.yml +++ b/.github/workflows/selfhosted.yml @@ -20,7 +20,7 @@ jobs: REMOTE: ${{ startsWith(matrix.host, 'remote') }} VM: ${{ startsWith(matrix.host, 'libvirt') || startsWith(matrix.host, 'persist') }} SSHFS: ${{ startsWith(matrix.host, 'libvirt') || startsWith(matrix.host, 'persist') || startsWith(matrix.host, 'remote') }} - BIGENDIAN: ${{ matrix.target == 'aix51' || matrix.target == 'fbsd14-ppc64' || matrix.target == 'openwrt-mips' }} + BIGENDIAN: ${{ matrix.target == 'aix51' || matrix.target == 'nbsd-arm64be' || matrix.target == 'openwrt-mips' }} strategy: fail-fast: false # We use a matrix in two parts: firstly all of the VMs are tested with the @@ -63,7 +63,6 @@ jobs: include: # Long-running/slow tests have access to high priority runners. - { target: aix51, config: default, host: libvirt-hipri } - - { target: fbsd14-ppc64, config: default, host: libvirt-hipri } - { target: openindiana, config: pam, host: libvirt-hipri } - { target: sol10, config: default, host: libvirt-hipri } - { target: sol10, config: pam, host: libvirt-hipri } @@ -100,6 +99,7 @@ jobs: - { target: debian-riscv64, config: default, host: remote-debian-riscv64 } - { target: openwrt-mips, config: default, host: remote-openwrt-mips } - { target: openwrt-mipsel, config: default, host: remote-openwrt-mipsel } + - { target: nbsd-arm64be, config: default, host: remote-nbsd-arm64be } steps: - name: shutdown VM if running if: env.VM == 'true' From e85248df3f1073343da87a6b00512e6a1e4a863d Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Sat, 2 Aug 2025 12:51:42 +1000 Subject: [PATCH 168/244] Comment out atime restore test. This works on filesystems mounted 'noatime', but on others the stat() resets atime causing the test to fail. --- openbsd-compat/regress/utimensattest.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/openbsd-compat/regress/utimensattest.c b/openbsd-compat/regress/utimensattest.c index bbc66c48523e..b4405e464d03 100644 --- a/openbsd-compat/regress/utimensattest.c +++ b/openbsd-compat/regress/utimensattest.c @@ -77,11 +77,17 @@ main(void) fail("utimensat", 0, 0); if (stat(TMPFILE, &sb) == -1) - fail("stat", 0, 0 ); + fail("stat", 0, 0); +#if 0 + /* + * This test only works on filesystems mounted 'noatime', otherwise the + * stat() above resets atime. Skip by default. + */ if (sb.st_atime != 12345678) - fail("st_atime", 0, 0 ); + fail("st_atime", 0, 0); +#endif if (sb.st_mtime != 34567890) - fail("st_mtime", 0, 0 ); + fail("st_mtime", 0, 0); #if 0 /* * Results expected to be rounded to the nearest microsecond. From d1c6c67a50fc957010fa027c6ab970424e9b9142 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Sat, 2 Aug 2025 14:49:00 +1000 Subject: [PATCH 169/244] Disable security key tests for bigendian interop --- .github/configs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/configs b/.github/configs index aa363be7d3ff..230258f93f24 100755 --- a/.github/configs +++ b/.github/configs @@ -283,7 +283,7 @@ case "${TARGET_HOST}" in # Native linker is not great with PIC so OpenSSL is built w/out. CONFIGFLAGS="${CONFIGFLAGS} --disable-security-key" ;; - fbsd14-ppc64) + fbsd14-ppc64|nbsd-arm64be) # Disable security key tests for bigendian interop test. CONFIGFLAGS="${CONFIGFLAGS} --disable-security-key" ;; From 65909fa114e7dd7511800db2b7bacb8774afe887 Mon Sep 17 00:00:00 2001 From: "job@openbsd.org" Date: Thu, 31 Jul 2025 09:38:41 +0000 Subject: [PATCH 170/244] upstream: Set default IPQoS for interactive sessions to Expedited Forwarding (EF) Marking interactive session data with DSCP value EF (RFC3246, RFC3247) helps inform the network on relative priority compared to other traffic. This is especially useful for differentiated treatment over wireless media. Following the reconciled IETF Diffserv to IEEE 802.11 mappings (RFC 8325), traffic marked with DSCP value EF maps to User Priority 6 in QoS Control, in turn mapping to the high priority WMM AC_VO access category. OK djm@ OpenBSD-Commit-ID: aadda7b9da794d70d7c6b381a861a0610afce1b3 --- readconf.c | 4 ++-- servconf.c | 4 ++-- ssh_config.5 | 8 ++++---- sshd_config.5 | 8 ++++---- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/readconf.c b/readconf.c index b5a9f925fc4a..5e97d710e7cd 100644 --- a/readconf.c +++ b/readconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.c,v 1.401 2025/07/23 05:07:19 djm Exp $ */ +/* $OpenBSD: readconf.c,v 1.402 2025/07/31 09:38:41 job Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -2947,7 +2947,7 @@ fill_default_options(Options * options) if (options->visual_host_key == -1) options->visual_host_key = 0; if (options->ip_qos_interactive == -1) - options->ip_qos_interactive = IPTOS_DSCP_AF21; + options->ip_qos_interactive = IPTOS_DSCP_EF; if (options->ip_qos_bulk == -1) options->ip_qos_bulk = IPTOS_DSCP_CS1; if (options->request_tty == -1) diff --git a/servconf.c b/servconf.c index 14165429f20f..63176d0d0086 100644 --- a/servconf.c +++ b/servconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.c,v 1.427 2025/05/24 08:13:29 dtucker Exp $ */ +/* $OpenBSD: servconf.c,v 1.428 2025/07/31 09:38:41 job Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -472,7 +472,7 @@ fill_default_server_options(ServerOptions *options) if (options->permit_tun == -1) options->permit_tun = SSH_TUNMODE_NO; if (options->ip_qos_interactive == -1) - options->ip_qos_interactive = IPTOS_DSCP_AF21; + options->ip_qos_interactive = IPTOS_DSCP_EF; if (options->ip_qos_bulk == -1) options->ip_qos_bulk = IPTOS_DSCP_CS1; if (options->version_addendum == NULL) diff --git a/ssh_config.5 b/ssh_config.5 index 14115fff1e1e..4b5b62408f15 100644 --- a/ssh_config.5 +++ b/ssh_config.5 @@ -33,8 +33,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh_config.5,v 1.414 2025/07/23 05:07:19 djm Exp $ -.Dd $Mdocdate: July 23 2025 $ +.\" $OpenBSD: ssh_config.5,v 1.415 2025/07/31 09:38:41 job Exp $ +.Dd $Mdocdate: July 31 2025 $ .Dt SSH_CONFIG 5 .Os .Sh NAME @@ -1277,8 +1277,8 @@ If one argument is specified, it is used as the packet class unconditionally. If two values are specified, the first is automatically selected for interactive sessions and the second for non-interactive sessions. The default is -.Cm af21 -(Low-Latency Data) +.Cm ef +(Expedited Forwarding) for interactive sessions and .Cm cs1 (Lower Effort) diff --git a/sshd_config.5 b/sshd_config.5 index c07717375d90..ae57d0cb9c86 100644 --- a/sshd_config.5 +++ b/sshd_config.5 @@ -33,8 +33,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd_config.5,v 1.381 2025/02/15 01:52:07 djm Exp $ -.Dd $Mdocdate: February 15 2025 $ +.\" $OpenBSD: sshd_config.5,v 1.382 2025/07/31 09:38:41 job Exp $ +.Dd $Mdocdate: July 31 2025 $ .Dt SSHD_CONFIG 5 .Os .Sh NAME @@ -958,8 +958,8 @@ If one argument is specified, it is used as the packet class unconditionally. If two values are specified, the first is automatically selected for interactive sessions and the second for non-interactive sessions. The default is -.Cm af21 -(Low-Latency Data) +.Cm ef +(Expedited Forwarding) for interactive sessions and .Cm cs1 (Lower Effort) From ec3465f59c651405e395092f3ad606f8992328d8 Mon Sep 17 00:00:00 2001 From: "job@openbsd.org" Date: Thu, 31 Jul 2025 11:23:39 +0000 Subject: [PATCH 171/244] upstream: Deprecate support for IPv4 type-of-service (TOS) IPQoS keywords Type of Service (ToS) was deprecated in the late nineties and replaced with the Differentiated Services architecture. Diffserv has significant advantages for operators because this mechanism offers more granularity. OpenSSH switched its default IPQoS from ToS to DSCP values in 2018. IPQoS configurations with 'lowdelay', 'reliability', or 'throughput' will be ignored and instead the system default QoS settings apply. Additionally, a debug message is logged about the deprecation with a suggestion to use DSCP. with/OK deraadt@ sthen@ djm@ OpenBSD-Commit-ID: 40c8c0c5cb20151a348728703536af2ec1c754ba --- misc.c | 8 ++++---- readconf.c | 14 +++++++++++++- readconf.h | 6 +++--- servconf.c | 14 +++++++++++++- ssh_config.5 | 9 ++++----- sshd_config.5 | 9 ++++----- 6 files changed, 41 insertions(+), 19 deletions(-) diff --git a/misc.c b/misc.c index f4e02bd04a78..838a7f788a7f 100644 --- a/misc.c +++ b/misc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: misc.c,v 1.200 2025/05/22 03:53:46 dtucker Exp $ */ +/* $OpenBSD: misc.c,v 1.201 2025/07/31 11:23:39 job Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2005-2020 Damien Miller. All rights reserved. @@ -1885,9 +1885,9 @@ static const struct { { "cs7", IPTOS_DSCP_CS7 }, { "ef", IPTOS_DSCP_EF }, { "le", IPTOS_DSCP_LE }, - { "lowdelay", IPTOS_LOWDELAY }, - { "throughput", IPTOS_THROUGHPUT }, - { "reliability", IPTOS_RELIABILITY }, + { "lowdelay", INT_MIN }, /* deprecated */ + { "throughput", INT_MIN }, /* deprecated */ + { "reliability", INT_MIN }, /* deprecated */ { NULL, -1 } }; diff --git a/readconf.c b/readconf.c index 5e97d710e7cd..02452edbf1d2 100644 --- a/readconf.c +++ b/readconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.c,v 1.402 2025/07/31 09:38:41 job Exp $ */ +/* $OpenBSD: readconf.c,v 1.403 2025/07/31 11:23:39 job Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -2160,6 +2160,12 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host, filename, linenum, arg); goto out; } + if (value == INT_MIN) { + debug("%s line %d: Deprecated IPQoS value \"%s\" " + "ignored - using system default instead. Consider" + " using DSCP values.", filename, linenum, arg); + value = INT_MAX; + } arg = argv_next(&ac, &av); if (arg == NULL) value2 = value; @@ -2168,6 +2174,12 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host, filename, linenum, arg); goto out; } + if (value2 == INT_MIN) { + debug("%s line %d: Deprecated IPQoS value \"%s\" " + "ignored - using system default instead. Consider" + " using DSCP values.", filename, linenum, arg); + value2 = INT_MAX; + } if (*activep && options->ip_qos_interactive == -1) { options->ip_qos_interactive = value; options->ip_qos_bulk = value2; diff --git a/readconf.h b/readconf.h index cd49139b13c0..153fa62260d3 100644 --- a/readconf.h +++ b/readconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.h,v 1.159 2025/02/15 01:48:30 djm Exp $ */ +/* $OpenBSD: readconf.h,v 1.160 2025/07/31 11:23:39 job Exp $ */ /* * Author: Tatu Ylonen @@ -49,8 +49,8 @@ typedef struct { int strict_host_key_checking; /* Strict host key checking. */ int compression; /* Compress packets in both directions. */ int tcp_keep_alive; /* Set SO_KEEPALIVE. */ - int ip_qos_interactive; /* IP ToS/DSCP/class for interactive */ - int ip_qos_bulk; /* IP ToS/DSCP/class for bulk traffic */ + int ip_qos_interactive; /* DSCP value for interactive */ + int ip_qos_bulk; /* DSCP value for bulk traffic */ SyslogFacility log_facility; /* Facility for system logging. */ LogLevel log_level; /* Level for logging. */ u_int num_log_verbose; /* Verbose log overrides */ diff --git a/servconf.c b/servconf.c index 63176d0d0086..2bd9d11916ad 100644 --- a/servconf.c +++ b/servconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.c,v 1.428 2025/07/31 09:38:41 job Exp $ */ +/* $OpenBSD: servconf.c,v 1.429 2025/07/31 11:23:39 job Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -2512,12 +2512,24 @@ process_server_config_line_depth(ServerOptions *options, char *line, if ((value = parse_ipqos(arg)) == -1) fatal("%s line %d: Bad %s value: %s", filename, linenum, keyword, arg); + if (value == INT_MIN) { + debug("%s line %d: Deprecated IPQoS value \"%s\" " + "ignored - using system default instead. Consider" + " using DSCP values.", filename, linenum, arg); + value = INT_MAX; + } arg = argv_next(&ac, &av); if (arg == NULL) value2 = value; else if ((value2 = parse_ipqos(arg)) == -1) fatal("%s line %d: Bad %s value: %s", filename, linenum, keyword, arg); + if (value2 == INT_MIN) { + debug("%s line %d: Deprecated IPQoS value \"%s\" " + "ignored - using system default instead. Consider" + " using DSCP values.", filename, linenum, arg); + value2 = INT_MAX; + } if (*activep) { options->ip_qos_interactive = value; options->ip_qos_bulk = value2; diff --git a/ssh_config.5 b/ssh_config.5 index 4b5b62408f15..390bc44aba8e 100644 --- a/ssh_config.5 +++ b/ssh_config.5 @@ -33,7 +33,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh_config.5,v 1.415 2025/07/31 09:38:41 job Exp $ +.\" $OpenBSD: ssh_config.5,v 1.416 2025/07/31 11:23:39 job Exp $ .Dd $Mdocdate: July 31 2025 $ .Dt SSH_CONFIG 5 .Os @@ -1242,7 +1242,9 @@ or block to perform conditional inclusion. .It Cm IPQoS -Specifies the IPv4 type-of-service or DSCP class for connections. +Specifies the +.Em Differentiated Services Field Codepoint Pq DSCP +value for connections. Accepted values are .Cm af11 , .Cm af12 , @@ -1266,9 +1268,6 @@ Accepted values are .Cm cs7 , .Cm ef , .Cm le , -.Cm lowdelay , -.Cm throughput , -.Cm reliability , a numeric value, or .Cm none to use the operating system default. diff --git a/sshd_config.5 b/sshd_config.5 index ae57d0cb9c86..ee1b2934138d 100644 --- a/sshd_config.5 +++ b/sshd_config.5 @@ -33,7 +33,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd_config.5,v 1.382 2025/07/31 09:38:41 job Exp $ +.\" $OpenBSD: sshd_config.5,v 1.383 2025/07/31 11:23:39 job Exp $ .Dd $Mdocdate: July 31 2025 $ .Dt SSHD_CONFIG 5 .Os @@ -923,7 +923,9 @@ directive may appear inside a block to perform conditional inclusion. .It Cm IPQoS -Specifies the IPv4 type-of-service or DSCP class for the connection. +Specifies the +.Em Differentiated Services Field Codepoint Pq DSCP +value for the connection. Accepted values are .Cm af11 , .Cm af12 , @@ -947,9 +949,6 @@ Accepted values are .Cm cs7 , .Cm ef , .Cm le , -.Cm lowdelay , -.Cm throughput , -.Cm reliability , a numeric value, or .Cm none to use the operating system default. From 6ebd472c391a73574abe02771712d407c48e130d Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Tue, 5 Aug 2025 04:00:15 +0000 Subject: [PATCH 172/244] upstream: a bunch of the protocol extensions we support now have RFCs and I-Ds that are more complete and detailed than what we have in the PROTOCOL.* files. Refer to these when possible instead of documenting them here. OpenBSD-Commit-ID: 4fa5b0fcf5d5f24093d33d9e82c7ca4850d50d70 --- PROTOCOL | 115 +++++++------------------------------- PROTOCOL.chacha20poly1305 | 107 ----------------------------------- 2 files changed, 21 insertions(+), 201 deletions(-) delete mode 100644 PROTOCOL.chacha20poly1305 diff --git a/PROTOCOL b/PROTOCOL index f99173c527b7..af2a813f9df8 100644 --- a/PROTOCOL +++ b/PROTOCOL @@ -33,10 +33,7 @@ The method is documented in: https://www.openssh.com/txt/draft-miller-secsh-compression-delayed-00.txt -1.3. transport: New public key algorithms "ssh-rsa-cert-v01@openssh.com", - "ecdsa-sha2-nistp256-cert-v01@openssh.com", - "ecdsa-sha2-nistp384-cert-v01@openssh.com" and - "ecdsa-sha2-nistp521-cert-v01@openssh.com" +1.3. transport: Certificate key algorithms OpenSSH introduces new public key algorithms to support certificate authentication for users and host keys. These methods are documented @@ -81,29 +78,20 @@ contains: 1.6 transport: AES-GCM OpenSSH supports the AES-GCM algorithm as specified in RFC 5647. -Because of problems with the specification of the key exchange -the behaviour of OpenSSH differs from the RFC as follows: +Because of problems with design of algorithm negotiation in this +RFC, OpenSSH (and other SSH implementation) use different rules as +described in: -AES-GCM is only negotiated as the cipher algorithms -"aes128-gcm@openssh.com" or "aes256-gcm@openssh.com" and never as -an MAC algorithm. Additionally, if AES-GCM is selected as the cipher -the exchanged MAC algorithms are ignored and there doesn't have to be -a matching MAC. +https://datatracker.ietf.org/doc/draft-miller-sshm-aes-gcm/ 1.7 transport: chacha20-poly1305@openssh.com authenticated encryption OpenSSH supports authenticated encryption using ChaCha20 and Poly1305 -as described in PROTOCOL.chacha20poly1305. +as described in: -1.8 transport: curve25519-sha256@libssh.org key exchange algorithm +https://datatracker.ietf.org/doc/draft-ietf-sshm-chacha20-poly1305/ -OpenSSH supports the use of ECDH in Curve25519 for key exchange as -described at: -http://git.libssh.org/users/aris/libssh.git/plain/doc/curve25519-sha256@libssh.org.txt?h=curve25519 - -This is identical to curve25519-sha256 as later published in RFC8731. - -1.9 transport: ping facility +1.8 transport: ping facility OpenSSH implements a transport level ping message SSH2_MSG_PING and a corresponding SSH2_MSG_PONG reply. @@ -136,34 +124,16 @@ than as a named global or channel request to allow pings with very short packet lengths, which would not be possible with other approaches. -1.10 transport: strict key exchange extension - -OpenSSH supports a number of transport-layer hardening measures under -a "strict KEX" feature. This feature is signalled similarly to the -RFC8308 ext-info feature: by including a additional algorithm in the -initial SSH2_MSG_KEXINIT kex_algorithms field. The client may append -"kex-strict-c-v00@openssh.com" to its kex_algorithms and the server -may append "kex-strict-s-v00@openssh.com". These pseudo-algorithms -are only valid in the initial SSH2_MSG_KEXINIT and MUST be ignored -if they are present in subsequent SSH2_MSG_KEXINIT packets. - -When an endpoint that supports this extension observes this algorithm -name in a peer's KEXINIT packet, it MUST make the following changes to -the protocol: - -a) During initial KEX, terminate the connection if out-of-sequence - packet or any message that is not strictly required by KEX is - received. This includes terminating the connection if the first - packet received is not SSH2_MSG_KEXINIT. Unexpected packets for - the purpose of strict KEX include messages that are otherwise - valid at any time during the connection such as SSH2_MSG_DEBUG, - SSH2_MSG_IGNORE or SSH2_MSG_UNIMPLEMENTED. -b) After sending or receiving a SSH2_MSG_NEWKEYS message, reset the - packet sequence number to zero. This behaviour persists for the - duration of the connection (i.e. not just the first - SSH2_MSG_NEWKEYS). - -1.11 transport: SSH2_MSG_EXT_INFO during user authentication +1.9 transport: strict key exchange extension + +OpenSSH supports a number of transport-layer hardening measures +designed to thwart the so-called "Terrapin" attack against the +early SSH protocol. These are collectively referred to as +"strict KEX" and documented in an Internet-Draft: + +https://datatracker.ietf.org/doc/draft-miller-sshm-strict-kex/ + +1.10 transport: SSH2_MSG_EXT_INFO during user authentication This protocol extension allows the SSH2_MSG_EXT_INFO to be sent during user authentication. RFC8308 does allow a second @@ -368,52 +338,9 @@ and "hostkeys-prove-00@openssh.com" OpenSSH supports a protocol extension allowing a server to inform a client of all its protocol v.2 host keys after user-authentication -has completed. - - byte SSH_MSG_GLOBAL_REQUEST - string "hostkeys-00@openssh.com" - char 0 /* want-reply */ - string[] hostkeys - -Upon receiving this message, a client should check which of the -supplied host keys are present in known_hosts. - -Note that the server may send key types that the client does not -support. The client should disregard such keys if they are received. - -If the client identifies any keys that are not present for the host, -it should send a "hostkeys-prove@openssh.com" message to request the -server prove ownership of the private half of the key. - - byte SSH_MSG_GLOBAL_REQUEST - string "hostkeys-prove-00@openssh.com" - char 1 /* want-reply */ - string[] hostkeys - -When a server receives this message, it should generate a signature -using each requested key over the following: - - string "hostkeys-prove-00@openssh.com" - string session identifier - string hostkey - -These signatures should be included in the reply, in the order matching -the hostkeys in the request: - - byte SSH_MSG_REQUEST_SUCCESS - string[] signatures - -When the client receives this reply (and not a failure), it should -validate the signatures and may update its known_hosts file, adding keys -that it has not seen before and deleting keys for the server host that -are no longer offered. +has completed. This is documented in an Internet-Draft -These extensions let a client learn key types that it had not previously -encountered, thereby allowing it to potentially upgrade from weaker -key algorithms to better ones. It also supports graceful key rotation: -a server may offer multiple keys of the same type for a period (to -give clients an opportunity to learn them using this extension) before -removing the deprecated key from those offered. +https://datatracker.ietf.org/doc/draft-miller-sshm-hostkey-update/ 2.6. connection: SIGINFO support for "signal" channel request @@ -791,4 +718,4 @@ master instance and later clients. OpenSSH extends the usual agent protocol. These changes are documented in the PROTOCOL.agent file. -$OpenBSD: PROTOCOL,v 1.57 2025/05/06 05:40:56 djm Exp $ +$OpenBSD: PROTOCOL,v 1.58 2025/08/05 04:00:15 djm Exp $ diff --git a/PROTOCOL.chacha20poly1305 b/PROTOCOL.chacha20poly1305 deleted file mode 100644 index 0bfff28d70ef..000000000000 --- a/PROTOCOL.chacha20poly1305 +++ /dev/null @@ -1,107 +0,0 @@ -This document describes the chacha20-poly1305@openssh.com authenticated -encryption cipher supported by OpenSSH. - -Background ----------- - -ChaCha20 is a stream cipher designed by Daniel Bernstein and described -in [1]. It operates by permuting 128 fixed bits, 128 or 256 bits of key, -a 64 bit nonce and a 64 bit counter into 64 bytes of output. This output -is used as a keystream, with any unused bytes simply discarded. - -Poly1305[2], also by Daniel Bernstein, is a one-time Carter-Wegman MAC -that computes a 128 bit integrity tag given a message and a single-use -256 bit secret key. - -The chacha20-poly1305@openssh.com combines these two primitives into an -authenticated encryption mode. The construction used is based on that -proposed for TLS by Adam Langley in [3], but differs in the layout of -data passed to the MAC and in the addition of encryption of the packet -lengths. - -Negotiation ------------ - -The chacha20-poly1305@openssh.com offers both encryption and -authentication. As such, no separate MAC is required. If the -chacha20-poly1305@openssh.com cipher is selected in key exchange, -the offered MAC algorithms are ignored and no MAC is required to be -negotiated. - -Detailed Construction ---------------------- - -The chacha20-poly1305@openssh.com cipher requires 512 bits of key -material as output from the SSH key exchange. This forms two 256 bit -keys (K_1 and K_2), used by two separate instances of chacha20. -The first 256 bits constitute K_2 and the second 256 bits become -K_1. - -The instance keyed by K_1 is a stream cipher that is used only -to encrypt the 4 byte packet length field. The second instance, -keyed by K_2, is used in conjunction with poly1305 to build an AEAD -(Authenticated Encryption with Associated Data) that is used to encrypt -and authenticate the entire packet. - -Two separate cipher instances are used here so as to keep the packet -lengths confidential but not create an oracle for the packet payload -cipher by decrypting and using the packet length prior to checking -the MAC. By using an independently-keyed cipher instance to encrypt the -length, an active attacker seeking to exploit the packet input handling -as a decryption oracle can learn nothing about the payload contents or -its MAC (assuming key derivation, ChaCha20 and Poly1305 are secure). - -The AEAD is constructed as follows: for each packet, generate a Poly1305 -key by taking the first 256 bits of ChaCha20 stream output generated -using K_2, an IV consisting of the packet sequence number encoded as an -uint64 under the SSH wire encoding rules and a ChaCha20 block counter of -zero. The K_2 ChaCha20 block counter is then set to the little-endian -encoding of 1 (i.e. {1, 0, 0, 0, 0, 0, 0, 0}) and this instance is used -for encryption of the packet payload. - -Packet Handling ---------------- - -When receiving a packet, the length must be decrypted first. When 4 -bytes of ciphertext length have been received, they may be decrypted -using the K_1 key, a nonce consisting of the packet sequence number -encoded as a uint64 under the usual SSH wire encoding and a zero block -counter to obtain the plaintext length. - -Once the entire packet has been received, the MAC MUST be checked -before decryption. A per-packet Poly1305 key is generated as described -above and the MAC tag calculated using Poly1305 with this key over the -ciphertext of the packet length and the payload together. The calculated -MAC is then compared in constant time with the one appended to the -packet and the packet decrypted using ChaCha20 as described above (with -K_2, the packet sequence number as nonce and a starting block counter of -1). - -To send a packet, first encode the 4 byte length and encrypt it using -K_1. Encrypt the packet payload (using K_2) and append it to the -encrypted length. Finally, calculate a MAC tag and append it. - -Rekeying --------- - -ChaCha20 must never reuse a {key, nonce} for encryption nor may it be -used to encrypt more than 2^70 bytes under the same {key, nonce}. The -SSH Transport protocol (RFC4253) recommends a far more conservative -rekeying every 1GB of data sent or received. If this recommendation -is followed, then chacha20-poly1305@openssh.com requires no special -handling in this area. - -References ----------- - -[1] "ChaCha, a variant of Salsa20", Daniel Bernstein - http://cr.yp.to/chacha/chacha-20080128.pdf - -[2] "The Poly1305-AES message-authentication code", Daniel Bernstein - http://cr.yp.to/mac/poly1305-20050329.pdf - -[3] "ChaCha20 and Poly1305 based Cipher Suites for TLS", Adam Langley - http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-03 - -$OpenBSD: PROTOCOL.chacha20poly1305,v 1.5 2020/02/21 00:04:43 dtucker Exp $ - From 2a31009c36eb2da412c2784fe131fcb6ba800978 Mon Sep 17 00:00:00 2001 From: "job@openbsd.org" Date: Tue, 5 Aug 2025 09:08:16 +0000 Subject: [PATCH 173/244] upstream: Use the operating system default DSCP marking for non-interactive traffic It seems the CS1 traffic class mark is considered ambiguous and therefore somewhat unhelpful (see RFC 8622 for more considerations). But, the new 'LE' scavenger class (also proposed in RFC 8622) offers high probability of excessive delays & high packet loss, which would be inappropriate for use with, for example, X11 forwardings. In fact, it is not known to SSH what's appropriate because SSH is not aware of the content of what passing through session forwardings. Therefore, no marking is appropriate. Non-interactive traffic simply is best effort. OK djm@ deraadt@ OpenBSD-Commit-ID: db1da1a432ecd53fc28feb84287aedb6bec80b01 --- readconf.c | 4 ++-- servconf.c | 4 ++-- ssh_config.5 | 8 ++++---- sshd_config.5 | 8 ++++---- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/readconf.c b/readconf.c index 02452edbf1d2..781e5b004068 100644 --- a/readconf.c +++ b/readconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.c,v 1.403 2025/07/31 11:23:39 job Exp $ */ +/* $OpenBSD: readconf.c,v 1.404 2025/08/05 09:08:16 job Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -2961,7 +2961,7 @@ fill_default_options(Options * options) if (options->ip_qos_interactive == -1) options->ip_qos_interactive = IPTOS_DSCP_EF; if (options->ip_qos_bulk == -1) - options->ip_qos_bulk = IPTOS_DSCP_CS1; + options->ip_qos_bulk = IPTOS_DSCP_CS0; if (options->request_tty == -1) options->request_tty = REQUEST_TTY_AUTO; if (options->session_type == -1) diff --git a/servconf.c b/servconf.c index 2bd9d11916ad..92f924e6015c 100644 --- a/servconf.c +++ b/servconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.c,v 1.429 2025/07/31 11:23:39 job Exp $ */ +/* $OpenBSD: servconf.c,v 1.430 2025/08/05 09:08:16 job Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -474,7 +474,7 @@ fill_default_server_options(ServerOptions *options) if (options->ip_qos_interactive == -1) options->ip_qos_interactive = IPTOS_DSCP_EF; if (options->ip_qos_bulk == -1) - options->ip_qos_bulk = IPTOS_DSCP_CS1; + options->ip_qos_bulk = IPTOS_DSCP_CS0; if (options->version_addendum == NULL) options->version_addendum = xstrdup(""); if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1) diff --git a/ssh_config.5 b/ssh_config.5 index 390bc44aba8e..f1673e014910 100644 --- a/ssh_config.5 +++ b/ssh_config.5 @@ -33,8 +33,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh_config.5,v 1.416 2025/07/31 11:23:39 job Exp $ -.Dd $Mdocdate: July 31 2025 $ +.\" $OpenBSD: ssh_config.5,v 1.417 2025/08/05 09:08:16 job Exp $ +.Dd $Mdocdate: August 5 2025 $ .Dt SSH_CONFIG 5 .Os .Sh NAME @@ -1279,8 +1279,8 @@ The default is .Cm ef (Expedited Forwarding) for interactive sessions and -.Cm cs1 -(Lower Effort) +.Cm none +(the operating system default) for non-interactive sessions. .It Cm KbdInteractiveAuthentication Specifies whether to use keyboard-interactive authentication. diff --git a/sshd_config.5 b/sshd_config.5 index ee1b2934138d..4536286b750d 100644 --- a/sshd_config.5 +++ b/sshd_config.5 @@ -33,8 +33,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd_config.5,v 1.383 2025/07/31 11:23:39 job Exp $ -.Dd $Mdocdate: July 31 2025 $ +.\" $OpenBSD: sshd_config.5,v 1.384 2025/08/05 09:08:16 job Exp $ +.Dd $Mdocdate: August 5 2025 $ .Dt SSHD_CONFIG 5 .Os .Sh NAME @@ -960,8 +960,8 @@ The default is .Cm ef (Expedited Forwarding) for interactive sessions and -.Cm cs1 -(Lower Effort) +.Cm none +(the operating system default) for non-interactive sessions. .It Cm KbdInteractiveAuthentication Specifies whether to allow keyboard-interactive authentication. From 9ffa98111dbe53bf86d07da8e01ded8c5c25456b Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Wed, 6 Aug 2025 04:53:04 +0000 Subject: [PATCH 174/244] upstream: when refusing a certificate for user authentication, log enough information to identify the certificate in addition to the reason why it was being denied. Makes debugging certificate authz problems a bit easier. ok dlg@ OpenBSD-Commit-ID: 4c4621b2e70412754b3fe7540af8f4bf02b722b1 --- auth2-hostbased.c | 14 +++++++++++--- auth2-pubkey.c | 12 +++++++++--- auth2-pubkeyfile.c | 23 ++++++++++++++++------- 3 files changed, 36 insertions(+), 13 deletions(-) diff --git a/auth2-hostbased.c b/auth2-hostbased.c index eb21479a0270..e28134a1ae2c 100644 --- a/auth2-hostbased.c +++ b/auth2-hostbased.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-hostbased.c,v 1.53 2024/05/17 00:30:23 djm Exp $ */ +/* $OpenBSD: auth2-hostbased.c,v 1.54 2025/08/06 04:53:04 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -213,8 +213,16 @@ hostbased_key_allowed(struct ssh *ssh, struct passwd *pw, if (sshkey_is_cert(key) && sshkey_cert_check_authority_now(key, 1, 0, 0, lookup, &reason)) { - error("%s", reason); - auth_debug_add("%s", reason); + if ((fp = sshkey_fingerprint(key->cert->signature_key, + options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) + fatal_f("sshkey_fingerprint fail"); + error("Refusing certificate ID \"%s\" serial=%llu signed by " + "%s CA %s: %s", key->cert->key_id, key->cert->serial, + sshkey_type(key->cert->signature_key), fp, reason); + auth_debug_add("Refused Certificate ID \"%s\" serial=%llu: %s", + key->cert->key_id, (unsigned long long)key->cert->serial, + reason); + free(fp); return 0; } diff --git a/auth2-pubkey.c b/auth2-pubkey.c index aa24fda05753..221b242f831d 100644 --- a/auth2-pubkey.c +++ b/auth2-pubkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-pubkey.c,v 1.122 2024/12/12 09:09:09 dtucker Exp $ */ +/* $OpenBSD: auth2-pubkey.c,v 1.123 2025/08/06 04:53:04 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2010 Damien Miller. All rights reserved. @@ -590,8 +590,14 @@ user_cert_trusted_ca(struct passwd *pw, struct sshkey *key, if ((final_opts = sshauthopt_merge(principals_opts, cert_opts, &reason)) == NULL) { fail_reason: - error("%s", reason); - auth_debug_add("%s", reason); + error("Refusing certificate ID \"%s\" serial=%llu " + "signed by %s CA %s: %s", key->cert->key_id, + key->cert->serial, + sshkey_type(key->cert->signature_key), ca_fp, + reason); + auth_debug_add("Refused Certificate ID \"%s\" " + "serial=%llu: %s", key->cert->key_id, + (unsigned long long)key->cert->serial, reason); goto out; } } diff --git a/auth2-pubkeyfile.c b/auth2-pubkeyfile.c index 31e7481fbe55..531a266ac336 100644 --- a/auth2-pubkeyfile.c +++ b/auth2-pubkeyfile.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-pubkeyfile.c,v 1.4 2023/03/05 05:34:09 dtucker Exp $ */ +/* $OpenBSD: auth2-pubkeyfile.c,v 1.5 2025/08/06 04:53:04 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2010 Damien Miller. All rights reserved. @@ -344,15 +344,15 @@ auth_check_authkey_line(struct passwd *pw, struct sshkey *key, /* Parse and check options present in certificate */ if ((certopts = sshauthopt_from_cert(key)) == NULL) { reason = "Invalid certificate options"; - goto fail_reason; + goto cert_fail_reason; } if (auth_authorise_keyopts(pw, certopts, 0, remote_ip, remote_host, loc) != 0) { reason = "Refused by certificate options"; - goto fail_reason; + goto cert_fail_reason; } if ((finalopts = sshauthopt_merge(keyopts, certopts, &reason)) == NULL) - goto fail_reason; + goto cert_fail_reason; /* * If the user has specified a list of principals as @@ -362,12 +362,12 @@ auth_check_authkey_line(struct passwd *pw, struct sshkey *key, if (keyopts->cert_principals != NULL && !match_principals_option(keyopts->cert_principals, key->cert)) { reason = "Certificate does not contain an authorized principal"; - goto fail_reason; + goto cert_fail_reason; } if (sshkey_cert_check_authority_now(key, 0, 0, 0, keyopts->cert_principals == NULL ? pw->pw_name : NULL, &reason) != 0) - goto fail_reason; + goto cert_fail_reason; verbose("Accepted certificate ID \"%s\" (serial %llu) " "signed by CA %s %s found at %s", @@ -386,8 +386,17 @@ auth_check_authkey_line(struct passwd *pw, struct sshkey *key, ret = 0; goto out; + cert_fail_reason: + error("Refusing certificate ID \"%s\" serial=%llu " + "signed by %s CA %s via %s: %s", key->cert->key_id, + key->cert->serial, sshkey_type(key->cert->signature_key), + fp, loc, reason); + auth_debug_add("Refused Certificate ID \"%s\" serial=%llu: %s", + key->cert->key_id, (unsigned long long)key->cert->serial, reason); + goto out; + fail_reason: - error("%s", reason); + error("%s at %s", reason, loc); auth_debug_add("%s", reason); out: free(fp); From 60b909fb110f77c1ffd15cceb5d09b8e3f79b27e Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Wed, 6 Aug 2025 11:22:53 +0000 Subject: [PATCH 175/244] upstream: Improve sentence. ok djm@ OpenBSD-Commit-ID: 9c481ddd6bad110af7e530ba90db41f6d5fe2273 --- PROTOCOL | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/PROTOCOL b/PROTOCOL index af2a813f9df8..a94b36ba6c7e 100644 --- a/PROTOCOL +++ b/PROTOCOL @@ -78,8 +78,8 @@ contains: 1.6 transport: AES-GCM OpenSSH supports the AES-GCM algorithm as specified in RFC 5647. -Because of problems with design of algorithm negotiation in this -RFC, OpenSSH (and other SSH implementation) use different rules as +Because of problems with the design of the algorithm negotiation in this +RFC, OpenSSH (and other SSH implementations) use different rules as described in: https://datatracker.ietf.org/doc/draft-miller-sshm-aes-gcm/ @@ -718,4 +718,4 @@ master instance and later clients. OpenSSH extends the usual agent protocol. These changes are documented in the PROTOCOL.agent file. -$OpenBSD: PROTOCOL,v 1.58 2025/08/05 04:00:15 djm Exp $ +$OpenBSD: PROTOCOL,v 1.59 2025/08/06 11:22:53 dtucker Exp $ From 2ebc6384258b58ace0ad2adb2593744f62749235 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Wed, 6 Aug 2025 23:44:09 +0000 Subject: [PATCH 176/244] upstream: all state related to the ssh connection should live in struct ssh or struct packet_state; one static int escaped this rule, so move it to struct packet_state now. ok millert tb OpenBSD-Commit-ID: bd6737168bf61a836ffbdc99ee4803468db90a53 --- packet.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/packet.c b/packet.c index 9dea2cfc5188..7f67f4fcd55e 100644 --- a/packet.c +++ b/packet.c @@ -1,4 +1,4 @@ -/* $OpenBSD: packet.c,v 1.318 2025/02/18 08:02:12 djm Exp $ */ +/* $OpenBSD: packet.c,v 1.319 2025/08/06 23:44:09 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -219,6 +219,12 @@ struct session_state { /* One-off warning about weak ciphers */ int cipher_warning_done; + /* + * Disconnect in progress. Used to prevent reentry in + * ssh_packet_disconnect() + */ + int disconnecting; + /* Hook for fuzzing inbound packets */ ssh_packet_hook_fn *hook_in; void *hook_in_ctx; @@ -2064,12 +2070,12 @@ ssh_packet_disconnect(struct ssh *ssh, const char *fmt,...) { char buf[1024], remote_id[512]; va_list args; - static int disconnecting = 0; int r; - if (disconnecting) /* Guard against recursive invocations. */ + /* Guard against recursive invocations. */ + if (ssh->state->disconnecting) fatal("packet_disconnect called recursively."); - disconnecting = 1; + ssh->state->disconnecting = 1; /* * Format the message. Note that the caller must make sure the From 0e1b8aa27f7c86d412c9e54ad9e2cae30d9ddab4 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Mon, 11 Aug 2025 10:55:38 +0000 Subject: [PATCH 177/244] upstream: ssh(1): add a warning when the connection negotiates a non-post quantum safe key agreement algorithm. Controlled via a new WarnWeakCrypto ssh_config option, defaulting to on. This option might grow additional weak crypto warnings in the future. More details at https://openssh.com/pq.html mostly by deraadt@ feedback dtucker@ ok deraadt@ OpenBSD-Commit-ID: 974ff243a1eccceac6a1a9d8fab3bcc89d74a2a4 --- kex-names.c | 45 ++++++++++++++++++++++++++++----------------- kex.c | 6 +++--- kex.h | 7 ++++++- readconf.c | 24 ++++++++++++++++++++++-- readconf.h | 4 +++- ssh_config.5 | 18 ++++++++++++++++-- sshconnect.c | 14 +++++++++++++- 7 files changed, 91 insertions(+), 27 deletions(-) diff --git a/kex-names.c b/kex-names.c index ec840c1f9dbc..96deb8817dbb 100644 --- a/kex-names.c +++ b/kex-names.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kex-names.c,v 1.4 2024/09/09 02:39:57 djm Exp $ */ +/* $OpenBSD: kex-names.c,v 1.5 2025/08/11 10:55:38 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * @@ -50,44 +50,45 @@ struct kexalg { u_int type; int ec_nid; int hash_alg; + int pq_alg; }; static const struct kexalg kexalgs[] = { #ifdef WITH_OPENSSL - { KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, - { KEX_DH14_SHA1, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, - { KEX_DH14_SHA256, KEX_DH_GRP14_SHA256, 0, SSH_DIGEST_SHA256 }, - { KEX_DH16_SHA512, KEX_DH_GRP16_SHA512, 0, SSH_DIGEST_SHA512 }, - { KEX_DH18_SHA512, KEX_DH_GRP18_SHA512, 0, SSH_DIGEST_SHA512 }, - { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, + { KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1, KEX_NOT_PQ }, + { KEX_DH14_SHA1, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1, KEX_NOT_PQ }, + { KEX_DH14_SHA256, KEX_DH_GRP14_SHA256, 0, SSH_DIGEST_SHA256, KEX_NOT_PQ }, + { KEX_DH16_SHA512, KEX_DH_GRP16_SHA512, 0, SSH_DIGEST_SHA512, KEX_NOT_PQ }, + { KEX_DH18_SHA512, KEX_DH_GRP18_SHA512, 0, SSH_DIGEST_SHA512, KEX_NOT_PQ }, + { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1, KEX_NOT_PQ }, #ifdef HAVE_EVP_SHA256 - { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 }, + { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256, KEX_NOT_PQ }, #endif /* HAVE_EVP_SHA256 */ #ifdef OPENSSL_HAS_ECC { KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2, - NID_X9_62_prime256v1, SSH_DIGEST_SHA256 }, + NID_X9_62_prime256v1, SSH_DIGEST_SHA256, KEX_NOT_PQ }, { KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1, - SSH_DIGEST_SHA384 }, + SSH_DIGEST_SHA384, KEX_NOT_PQ }, # ifdef OPENSSL_HAS_NISTP521 { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1, - SSH_DIGEST_SHA512 }, + SSH_DIGEST_SHA512, KEX_NOT_PQ }, # endif /* OPENSSL_HAS_NISTP521 */ #endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ #if defined(HAVE_EVP_SHA256) || !defined(WITH_OPENSSL) - { KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, - { KEX_CURVE25519_SHA256_OLD, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, + { KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256, KEX_NOT_PQ }, + { KEX_CURVE25519_SHA256_OLD, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256, KEX_NOT_PQ }, #ifdef USE_SNTRUP761X25519 { KEX_SNTRUP761X25519_SHA512, KEX_KEM_SNTRUP761X25519_SHA512, 0, - SSH_DIGEST_SHA512 }, + SSH_DIGEST_SHA512, KEX_IS_PQ }, { KEX_SNTRUP761X25519_SHA512_OLD, KEX_KEM_SNTRUP761X25519_SHA512, 0, - SSH_DIGEST_SHA512 }, + SSH_DIGEST_SHA512, KEX_IS_PQ }, #endif #ifdef USE_MLKEM768X25519 { KEX_MLKEM768X25519_SHA256, KEX_KEM_MLKEM768X25519_SHA256, 0, - SSH_DIGEST_SHA256 }, + SSH_DIGEST_SHA256, KEX_IS_PQ }, #endif #endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */ - { NULL, 0, -1, -1}, + { NULL, 0, -1, -1, 0 }, }; char * @@ -130,6 +131,16 @@ kex_name_valid(const char *name) return kex_alg_by_name(name) != NULL; } +int +kex_is_pq_from_name(const char *name) +{ + const struct kexalg *k; + + if ((k = kex_alg_by_name(name)) == NULL) + return 0; + return k->pq_alg == KEX_IS_PQ; +} + u_int kex_type_from_name(const char *name) { diff --git a/kex.c b/kex.c index 6b957e5e18f5..f8eaa8c970c6 100644 --- a/kex.c +++ b/kex.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kex.c,v 1.187 2024/08/23 04:51:00 deraadt Exp $ */ +/* $OpenBSD: kex.c,v 1.188 2025/08/11 10:55:38 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * @@ -563,8 +563,6 @@ kex_input_newkeys(int type, u_int32_t seq, struct ssh *ssh) kex->flags &= ~KEX_INITIAL; sshbuf_reset(kex->peer); kex->flags &= ~KEX_INIT_SENT; - free(kex->name); - kex->name = NULL; return 0; } @@ -620,6 +618,8 @@ kex_input_kexinit(int type, u_int32_t seq, struct ssh *ssh) error_f("no kex"); return SSH_ERR_INTERNAL_ERROR; } + free(kex->name); + kex->name = NULL; ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_protocol_error); ptr = sshpkt_ptr(ssh, &dlen); if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0) diff --git a/kex.h b/kex.h index d08988b3e141..55baa6a1e641 100644 --- a/kex.h +++ b/kex.h @@ -1,4 +1,4 @@ -/* $OpenBSD: kex.h,v 1.126 2024/09/02 12:13:56 djm Exp $ */ +/* $OpenBSD: kex.h,v 1.127 2025/08/11 10:55:38 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. @@ -115,6 +115,10 @@ enum kex_exchange { #define KEX_HAS_PING 0x0020 #define KEX_HAS_EXT_INFO_IN_AUTH 0x0040 +/* kex->pq */ +#define KEX_NOT_PQ 0 +#define KEX_IS_PQ 1 + struct sshenc { char *name; const struct sshcipher *cipher; @@ -189,6 +193,7 @@ int kex_name_valid(const char *); u_int kex_type_from_name(const char *); int kex_hash_from_name(const char *); int kex_nid_from_name(const char *); +int kex_is_pq_from_name(const char *); int kex_names_valid(const char *); char *kex_alg_list(char); char *kex_names_cat(const char *, const char *); diff --git a/readconf.c b/readconf.c index 781e5b004068..c7701d8c2633 100644 --- a/readconf.c +++ b/readconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.c,v 1.404 2025/08/05 09:08:16 job Exp $ */ +/* $OpenBSD: readconf.c,v 1.405 2025/08/11 10:55:38 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -180,7 +180,7 @@ typedef enum { oPubkeyAcceptedAlgorithms, oCASignatureAlgorithms, oProxyJump, oSecurityKeyProvider, oKnownHostsCommand, oRequiredRSASize, oEnableEscapeCommandline, oObscureKeystrokeTiming, oChannelTimeout, - oVersionAddendum, oRefuseConnection, + oVersionAddendum, oRefuseConnection, oWarnWeakCrypto, oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported } OpCodes; @@ -333,6 +333,7 @@ static struct { { "channeltimeout", oChannelTimeout }, { "versionaddendum", oVersionAddendum }, { "refuseconnection", oRefuseConnection }, + { "warnweakcrypto", oWarnWeakCrypto }, { NULL, oBadOption } }; @@ -1101,6 +1102,15 @@ static const struct multistate multistate_compression[] = { { "no", COMP_NONE }, { NULL, -1 } }; +/* XXX this will need to be replaced with a bitmask if we add more flags */ +static const struct multistate multistate_warnweakcrypto[] = { + { "true", 1 }, + { "false", 0 }, + { "yes", 1 }, + { "no", 0 }, + { "no-pq-kex", 0 }, + { NULL, -1 } +}; static int parse_multistate_value(const char *arg, const char *filename, int linenum, @@ -2427,6 +2437,11 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host, intptr = &options->required_rsa_size; goto parse_int; + case oWarnWeakCrypto: + intptr = &options->warn_weak_crypto; + multistate_ptr = multistate_warnweakcrypto; + goto parse_multistate; + case oObscureKeystrokeTiming: value = -1; while ((arg = argv_next(&ac, &av)) != NULL) { @@ -2786,6 +2801,7 @@ initialize_options(Options * options) options->pubkey_accepted_algos = NULL; options->known_hosts_command = NULL; options->required_rsa_size = -1; + options->warn_weak_crypto = -1; options->enable_escape_commandline = -1; options->obscure_keystroke_timing_interval = -1; options->tag = NULL; @@ -2989,6 +3005,8 @@ fill_default_options(Options * options) #endif if (options->required_rsa_size == -1) options->required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE; + if (options->warn_weak_crypto == -1) + options->warn_weak_crypto = 1; if (options->enable_escape_commandline == -1) options->enable_escape_commandline = 0; if (options->obscure_keystroke_timing_interval == -1) { @@ -3016,6 +3034,7 @@ fill_default_options(Options * options) goto fail; \ } \ } while (0) + options->kex_algorithms_set = options->kex_algorithms != NULL; ASSEMBLE(ciphers, def_cipher, all_cipher); ASSEMBLE(macs, def_mac, all_mac); ASSEMBLE(kex_algorithms, def_kex, all_kex); @@ -3703,6 +3722,7 @@ dump_client_config(Options *o, const char *host) dump_cfg_fmtint(oVisualHostKey, o->visual_host_key); dump_cfg_fmtint(oUpdateHostkeys, o->update_hostkeys); dump_cfg_fmtint(oEnableEscapeCommandline, o->enable_escape_commandline); + dump_cfg_fmtint(oWarnWeakCrypto, o->warn_weak_crypto); /* Integer options */ dump_cfg_int(oCanonicalizeMaxDots, o->canonicalize_max_dots); diff --git a/readconf.h b/readconf.h index 153fa62260d3..942149f9ae3f 100644 --- a/readconf.h +++ b/readconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.h,v 1.160 2025/07/31 11:23:39 job Exp $ */ +/* $OpenBSD: readconf.h,v 1.161 2025/08/11 10:55:38 djm Exp $ */ /* * Author: Tatu Ylonen @@ -67,6 +67,7 @@ typedef struct { char *macs; /* SSH2 macs in order of preference. */ char *hostkeyalgorithms; /* SSH2 server key types in order of preference. */ char *kex_algorithms; /* SSH2 kex methods in order of preference. */ + int kex_algorithms_set; /* KexAlgorithms was set by the user */ char *ca_sign_algorithms; /* Allowed CA signature algorithms */ char *hostname; /* Real host to connect. */ char *tag; /* Configuration tag name. */ @@ -180,6 +181,7 @@ typedef struct { int required_rsa_size; /* minimum size of RSA keys */ int enable_escape_commandline; /* ~C commandline */ int obscure_keystroke_timing_interval; + int warn_weak_crypto; char **channel_timeouts; /* inactivity timeout by channel type */ u_int num_channel_timeouts; diff --git a/ssh_config.5 b/ssh_config.5 index f1673e014910..4cbe98631051 100644 --- a/ssh_config.5 +++ b/ssh_config.5 @@ -33,8 +33,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh_config.5,v 1.417 2025/08/05 09:08:16 job Exp $ -.Dd $Mdocdate: August 5 2025 $ +.\" $OpenBSD: ssh_config.5,v 1.418 2025/08/11 10:55:38 djm Exp $ +.Dd $Mdocdate: August 11 2025 $ .Dt SSH_CONFIG 5 .Os .Sh NAME @@ -2229,6 +2229,20 @@ If this flag is set to (the default), no fingerprint strings are printed at login and only the fingerprint string will be printed for unknown host keys. +.It Cm WarnWeakCrypto +controls whether the user is warned when the cryptographic algorithms +negotiated for the connection are weak or otherwise recommended against. +Warnings may be disabled by turning off a specific warning or by disabling +all warnings. +Warnings that the connection is using a non-post quantum safe key exchange +may be disabled using the +.Cm no-pq-kex +flag. +.Cm no +will disable all warnings. +The default, equivalent to +.Cm yes , +is to enable all warnings. .It Cm XAuthLocation Specifies the full pathname of the .Xr xauth 1 diff --git a/sshconnect.c b/sshconnect.c index a90167fd6dae..09e937c9e64f 100644 --- a/sshconnect.c +++ b/sshconnect.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshconnect.c,v 1.371 2025/05/24 09:46:16 djm Exp $ */ +/* $OpenBSD: sshconnect.c,v 1.372 2025/08/11 10:55:38 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1580,6 +1580,14 @@ verify_host_key(char *host, struct sockaddr *hostaddr, struct sshkey *host_key, return r; } +static void +warn_nonpq_kex(void) +{ + logit("** WARNING: connection is not using a post-quantum kex exchange algorithm."); + logit("** This session may be vulnerable to \"store now, decrypt later\" attacks."); + logit("** The server may need to be upgraded. See https://openssh.com/pq.html"); +} + /* * Starts a dialog with the server, and authenticates the current user on the * server. This does not need any extra privileges. The basic connection @@ -1615,6 +1623,10 @@ ssh_login(struct ssh *ssh, Sensitive *sensitive, const char *orighost, /* authenticate user */ debug("Authenticating to %s:%d as '%s'", host, port, server_user); ssh_kex2(ssh, host, hostaddr, port, cinfo); + if (!options.kex_algorithms_set && ssh->kex != NULL && + ssh->kex->name != NULL && options.warn_weak_crypto && + !kex_is_pq_from_name(ssh->kex->name)) + warn_nonpq_kex(); ssh_userauth2(ssh, local_user, server_user, host, sensitive); free(local_user); free(host); From 8b6c1f402feb9eb6438003a312d7ffe8d5669896 Mon Sep 17 00:00:00 2001 From: "deraadt@openbsd.org" Date: Mon, 11 Aug 2025 14:37:43 +0000 Subject: [PATCH 178/244] upstream: Handle localtime_r() failure by return "UNKNOWN-TIME" which is only used in user-visible contexts. freebsd 288773 shows their localtime_r() has failed at least once for unknown reason. discussed with djm OpenBSD-Commit-ID: 68f4c92d46b2578d4594b0ed940958d597fd61ac --- misc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/misc.c b/misc.c index 838a7f788a7f..2e77eeb88de4 100644 --- a/misc.c +++ b/misc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: misc.c,v 1.201 2025/07/31 11:23:39 job Exp $ */ +/* $OpenBSD: misc.c,v 1.202 2025/08/11 14:37:43 deraadt Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2005-2020 Damien Miller. All rights reserved. @@ -2540,8 +2540,10 @@ format_absolute_time(uint64_t t, char *buf, size_t len) time_t tt = t > SSH_TIME_T_MAX ? SSH_TIME_T_MAX : t; struct tm tm; - localtime_r(&tt, &tm); - strftime(buf, len, "%Y-%m-%dT%H:%M:%S", &tm); + if (localtime_r(&tt, &tm) == NULL) + strlcpy(buf, "UNKNOWN-TIME", len); + else + strftime(buf, len, "%Y-%m-%dT%H:%M:%S", &tm); } /* From ab5074dfb614e3801fecbd376d8ed4cea613c629 Mon Sep 17 00:00:00 2001 From: "sthen@openbsd.org" Date: Tue, 12 Aug 2025 11:09:48 +0000 Subject: [PATCH 179/244] upstream: fix typo, ok markus dtucker OpenBSD-Commit-ID: 8f223da7633752162c64a659c6cf55202703d870 --- sshconnect.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sshconnect.c b/sshconnect.c index 09e937c9e64f..d2c8cf0bd8f2 100644 --- a/sshconnect.c +++ b/sshconnect.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshconnect.c,v 1.372 2025/08/11 10:55:38 djm Exp $ */ +/* $OpenBSD: sshconnect.c,v 1.373 2025/08/12 11:09:48 sthen Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1583,7 +1583,7 @@ verify_host_key(char *host, struct sockaddr *hostaddr, struct sshkey *host_key, static void warn_nonpq_kex(void) { - logit("** WARNING: connection is not using a post-quantum kex exchange algorithm."); + logit("** WARNING: connection is not using a post-quantum key exchange algorithm."); logit("** This session may be vulnerable to \"store now, decrypt later\" attacks."); logit("** The server may need to be upgraded. See https://openssh.com/pq.html"); } From fde5a4d2cd01bea700439fa6d5bbad88e65c99bd Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Thu, 14 Aug 2025 09:26:53 +0000 Subject: [PATCH 180/244] upstream: Cast serial no for %lld to prevent compiler warnings on some platforms. OpenBSD-Commit-ID: 15644234b58abc9c6da2994f0422a5aa344a9e89 --- auth2-hostbased.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/auth2-hostbased.c b/auth2-hostbased.c index e28134a1ae2c..9d8b860eb14e 100644 --- a/auth2-hostbased.c +++ b/auth2-hostbased.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-hostbased.c,v 1.54 2025/08/06 04:53:04 djm Exp $ */ +/* $OpenBSD: auth2-hostbased.c,v 1.55 2025/08/14 09:26:53 dtucker Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -217,7 +217,8 @@ hostbased_key_allowed(struct ssh *ssh, struct passwd *pw, options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) fatal_f("sshkey_fingerprint fail"); error("Refusing certificate ID \"%s\" serial=%llu signed by " - "%s CA %s: %s", key->cert->key_id, key->cert->serial, + "%s CA %s: %s", key->cert->key_id, + (unsigned long long)key->cert->serial, sshkey_type(key->cert->signature_key), fp, reason); auth_debug_add("Refused Certificate ID \"%s\" serial=%llu: %s", key->cert->key_id, (unsigned long long)key->cert->serial, From 883886c959ecab152650e231335857eb3193c662 Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Thu, 14 Aug 2025 09:44:39 +0000 Subject: [PATCH 181/244] upstream: Cast serial no for %lld to prevent compiler warnings on some platforms. OpenBSD-Commit-ID: 46c6063284d318f7e4dc922479a3e394c94b0588 --- auth2-pubkey.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/auth2-pubkey.c b/auth2-pubkey.c index 221b242f831d..d7704e5102ff 100644 --- a/auth2-pubkey.c +++ b/auth2-pubkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-pubkey.c,v 1.123 2025/08/06 04:53:04 djm Exp $ */ +/* $OpenBSD: auth2-pubkey.c,v 1.124 2025/08/14 09:44:39 dtucker Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2010 Damien Miller. All rights reserved. @@ -592,7 +592,7 @@ user_cert_trusted_ca(struct passwd *pw, struct sshkey *key, fail_reason: error("Refusing certificate ID \"%s\" serial=%llu " "signed by %s CA %s: %s", key->cert->key_id, - key->cert->serial, + (unsigned long long)key->cert->serial, sshkey_type(key->cert->signature_key), ca_fp, reason); auth_debug_add("Refused Certificate ID \"%s\" " From 32deb00b38b4ee2b3302f261ea1e68c04e020a08 Mon Sep 17 00:00:00 2001 From: "dtucker@openbsd.org" Date: Thu, 14 Aug 2025 10:03:44 +0000 Subject: [PATCH 182/244] upstream: Cast serial no for %lld to prevent compiler warnings on some platforms. OpenBSD-Commit-ID: afadd741622f16c6733d461c0d6053ed52868a57 --- auth2-pubkeyfile.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/auth2-pubkeyfile.c b/auth2-pubkeyfile.c index 531a266ac336..9d59e566658e 100644 --- a/auth2-pubkeyfile.c +++ b/auth2-pubkeyfile.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-pubkeyfile.c,v 1.5 2025/08/06 04:53:04 djm Exp $ */ +/* $OpenBSD: auth2-pubkeyfile.c,v 1.6 2025/08/14 10:03:44 dtucker Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2010 Damien Miller. All rights reserved. @@ -389,8 +389,8 @@ auth_check_authkey_line(struct passwd *pw, struct sshkey *key, cert_fail_reason: error("Refusing certificate ID \"%s\" serial=%llu " "signed by %s CA %s via %s: %s", key->cert->key_id, - key->cert->serial, sshkey_type(key->cert->signature_key), - fp, loc, reason); + (unsigned long long)key->cert->serial, + sshkey_type(key->cert->signature_key), fp, loc, reason); auth_debug_add("Refused Certificate ID \"%s\" serial=%llu: %s", key->cert->key_id, (unsigned long long)key->cert->serial, reason); goto out; From a00f5b02e171bc6d6fb130050afb7a08f5ece1d8 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Mon, 18 Aug 2025 13:44:53 +1000 Subject: [PATCH 183/244] handle futex_time64 properly in seccomp sandbox Previously we only allowed __NR_futex, but some 32-bit systems apparently support __NR_futex_time64. We had support for this in the sandbox, but because of a macro error only __NR_futex was allowlisted. ok dtucker@ --- sandbox-seccomp-filter.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sandbox-seccomp-filter.c b/sandbox-seccomp-filter.c index b31062c2b56c..827cb61ee696 100644 --- a/sandbox-seccomp-filter.c +++ b/sandbox-seccomp-filter.c @@ -180,12 +180,12 @@ /* Use this for both __NR_futex and __NR_futex_time64 */ # define SC_FUTEX(_nr) \ - SC_ALLOW_FUTEX_OP(__NR_futex, FUTEX_WAIT), \ - SC_ALLOW_FUTEX_OP(__NR_futex, FUTEX_WAIT_BITSET), \ - SC_ALLOW_FUTEX_OP(__NR_futex, FUTEX_WAKE), \ - SC_ALLOW_FUTEX_OP(__NR_futex, FUTEX_WAKE_BITSET), \ - SC_ALLOW_FUTEX_OP(__NR_futex, FUTEX_REQUEUE), \ - SC_ALLOW_FUTEX_OP(__NR_futex, FUTEX_CMP_REQUEUE) + SC_ALLOW_FUTEX_OP(_nr, FUTEX_WAIT), \ + SC_ALLOW_FUTEX_OP(_nr, FUTEX_WAIT_BITSET), \ + SC_ALLOW_FUTEX_OP(_nr, FUTEX_WAKE), \ + SC_ALLOW_FUTEX_OP(_nr, FUTEX_WAKE_BITSET), \ + SC_ALLOW_FUTEX_OP(_nr, FUTEX_REQUEUE), \ + SC_ALLOW_FUTEX_OP(_nr, FUTEX_CMP_REQUEUE) #endif /* __NR_futex || __NR_futex_time64 */ #if defined(__NR_mmap) || defined(__NR_mmap2) From 3a039108bd25ff10047d7fa64750ed7df10c717c Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Mon, 18 Aug 2025 13:46:37 +1000 Subject: [PATCH 184/244] allow some socket syscalls in seccomp sandbox Allow getsockname(2), getpeername(2) and getsockopt(2). Also allow setsockopt(2) but only IP_TOS and IPV6_TCLASS. Note that systems that use the older socketcall(2) mux syscall will not have IP_TOS and IPV6_TCLASS allowlisted. On these platforms, these calls will be soft-blocked (i.e. will fail rather than terminate the whole process with a sandbox violation). Needed for upcoming IPQoS change; ok dtucker@ --- sandbox-seccomp-filter.c | 44 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/sandbox-seccomp-filter.c b/sandbox-seccomp-filter.c index 827cb61ee696..a8f34a76c995 100644 --- a/sandbox-seccomp-filter.c +++ b/sandbox-seccomp-filter.c @@ -49,6 +49,8 @@ #include #include +#include + #include #include #include @@ -200,6 +202,32 @@ SC_ALLOW_ARG_MASK(_nr, 2, PROT_READ|PROT_WRITE|PROT_NONE) #endif /* __NR_mmap || __NR_mmap2 */ +/* Special handling for setsockopt(2) */ +#define SC_ALLOW_SETSOCKOPT(_level, _optname) \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_setsockopt, 0, 10), \ + /* load and test level, low word */ \ + BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \ + offsetof(struct seccomp_data, args[1]) + ARG_LO_OFFSET), \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, \ + ((_level) & 0xFFFFFFFF), 0, 7), \ + /* load and test level high word is zero */ \ + BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \ + offsetof(struct seccomp_data, args[1]) + ARG_HI_OFFSET), \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 5), \ + /* load and test optname, low word */ \ + BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \ + offsetof(struct seccomp_data, args[2]) + ARG_LO_OFFSET), \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, \ + ((_optname) & 0xFFFFFFFF), 0, 3), \ + /* load and test level high word is zero */ \ + BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \ + offsetof(struct seccomp_data, args[2]) + ARG_HI_OFFSET), \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 1), \ + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), \ + /* reload syscall number; all rules expect it in accumulator */ \ + BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \ + offsetof(struct seccomp_data, nr)) + /* Syscall filtering set for preauth. */ static const struct sock_filter preauth_insns[] = { /* Ensure the syscall arch convention is as expected. */ @@ -398,7 +426,23 @@ static const struct sock_filter preauth_insns[] = { #ifdef __NR_writev SC_ALLOW(__NR_writev), #endif +#ifdef __NR_getsockopt + SC_ALLOW(__NR_getsockopt), +#endif +#ifdef __NR_getsockname + SC_ALLOW(__NR_getsockname), +#endif +#ifdef __NR_getpeername + SC_ALLOW(__NR_getpeername), +#endif +#ifdef __NR_setsockopt + SC_ALLOW_SETSOCKOPT(IPPROTO_IPV6, IPV6_TCLASS), + SC_ALLOW_SETSOCKOPT(IPPROTO_IP, IP_TOS), +#endif #ifdef __NR_socketcall + SC_ALLOW_ARG(__NR_socketcall, 0, SYS_GETPEERNAME), + SC_ALLOW_ARG(__NR_socketcall, 0, SYS_GETSOCKNAME), + SC_ALLOW_ARG(__NR_socketcall, 0, SYS_GETSOCKOPT), SC_ALLOW_ARG(__NR_socketcall, 0, SYS_SHUTDOWN), SC_DENY(__NR_socketcall, EACCES), #endif From 80b5ffd22abd4093201939e31d1ea6dc8cc7913a Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Mon, 18 Aug 2025 01:59:53 +0000 Subject: [PATCH 185/244] upstream: make -E a no-op in sshd-auth. Redirecting logging to a file doesn't work in this program as logging already goes via the parent sshd-session process. ok dtucker@ OpenBSD-Commit-ID: 73325b9e69364117c18305f896c620a3abcf4f87 --- sshd-auth.c | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/sshd-auth.c b/sshd-auth.c index 5de06a5baa49..6bf596e7a5fa 100644 --- a/sshd-auth.c +++ b/sshd-auth.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd-auth.c,v 1.4 2025/05/06 05:40:56 djm Exp $ */ +/* $OpenBSD: sshd-auth.c,v 1.5 2025/08/18 01:59:53 djm Exp $ */ /* * SSH2 implementation: * Privilege Separation: @@ -445,7 +445,7 @@ main(int ac, char **av) extern int optind; int r, opt, have_key = 0; int sock_in = -1, sock_out = -1, rexeced_flag = 0; - char *line, *logfile = NULL; + char *line; u_int i; mode_t new_umask; Authctxt *authctxt; @@ -508,11 +508,7 @@ main(int ac, char **av) options.log_level++; break; case 'D': - /* ignore */ - break; case 'E': - logfile = optarg; - /* FALLTHROUGH */ case 'e': /* ignore */ break; @@ -601,19 +597,6 @@ main(int ac, char **av) OpenSSL_add_all_algorithms(); #endif - /* If requested, redirect the logs to the specified logfile. */ - if (logfile != NULL) { - char *cp, pid_s[32]; - - snprintf(pid_s, sizeof(pid_s), "%ld", (unsigned long)getpid()); - cp = percent_expand(logfile, - "p", pid_s, - "P", "sshd-auth", - (char *)NULL); - log_redirect_stderr_to(cp); - free(cp); - } - log_init(__progname, options.log_level == SYSLOG_LEVEL_NOT_SET ? SYSLOG_LEVEL_INFO : options.log_level, From 9b61679d73a8a001c25ab308db8a3162456010cf Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Mon, 18 Aug 2025 03:28:02 +0000 Subject: [PATCH 186/244] upstream: add channel_report_open() to report (to logs) open channels; ok deraadt@ (as part of bigger diff) OpenBSD-Commit-ID: 7f691e25366c5621d7ed6f7f9018d868f7511c0d --- channels.c | 17 ++++++++++++++++- channels.h | 3 ++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/channels.c b/channels.c index 0efbd8d174c7..9d56310172f3 100644 --- a/channels.c +++ b/channels.c @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.c,v 1.446 2025/06/02 14:09:34 dtucker Exp $ */ +/* $OpenBSD: channels.c,v 1.447 2025/08/18 03:28:02 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1096,6 +1096,21 @@ channel_open_message(struct ssh *ssh) return ret; } +void +channel_report_open(struct ssh *ssh, int level) +{ + char *open, *oopen, *cp, ident[256]; + + sshpkt_fmt_connection_id(ssh, ident, sizeof(ident)); + do_log2(level, "Connection: %s (pid %ld)", ident, (long)getpid()); + open = oopen = channel_open_message(ssh); + while ((cp = strsep(&open, "\r\n")) != NULL) { + if (*cp != '\0') + do_log2(level, "%s", cp); + } + free(oopen); +} + static void open_preamble(struct ssh *ssh, const char *where, Channel *c, const char *type) { diff --git a/channels.h b/channels.h index 134528d59c72..1bfade4c5c77 100644 --- a/channels.h +++ b/channels.h @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.h,v 1.158 2024/10/13 22:20:06 djm Exp $ */ +/* $OpenBSD: channels.h,v 1.159 2025/08/18 03:28:02 djm Exp $ */ /* * Author: Tatu Ylonen @@ -344,6 +344,7 @@ int channel_still_open(struct ssh *); int channel_tty_open(struct ssh *); const char *channel_format_extended_usage(const Channel *); char *channel_open_message(struct ssh *); +void channel_report_open(struct ssh *, int); int channel_find_open(struct ssh *); /* tcp forwarding */ From f807a598c96be683d97810481e954ec9db6b0027 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Mon, 18 Aug 2025 03:28:36 +0000 Subject: [PATCH 187/244] upstream: SIGINFO handler for ssh(1) to dump active channels/sessions ok deraadt@ OpenBSD-Commit-ID: 12f88a5044bca40ef5f41ff61b1755d0e25df901 --- clientloop.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/clientloop.c b/clientloop.c index 5f6577f65632..b9c050409861 100644 --- a/clientloop.c +++ b/clientloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.c,v 1.412 2025/06/17 01:20:17 djm Exp $ */ +/* $OpenBSD: clientloop.c,v 1.413 2025/08/18 03:28:36 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -147,7 +147,8 @@ extern char *forward_agent_sock_path; * because this is updated in a signal handler. */ static volatile sig_atomic_t received_window_change_signal = 0; -static volatile sig_atomic_t received_signal = 0; +static volatile sig_atomic_t siginfo_received = 0; +static volatile sig_atomic_t received_signal = 0; /* exit signals */ /* Time when backgrounded control master using ControlPersist should exit */ static time_t control_persist_exit_time = 0; @@ -224,6 +225,13 @@ window_change_handler(int sig) received_window_change_signal = 1; } +/* Signal handler for SIGINFO */ +static void +siginfo_handler(int sig) +{ + siginfo_received = 1; +} + /* * Signal handler for signals that cause the program to terminate. These * signals must be trapped to restore terminal modes. @@ -1514,6 +1522,7 @@ client_loop(struct ssh *ssh, int have_pty, int escape_char_arg, if (ssh_signal(SIGTERM, SIG_IGN) != SIG_IGN) ssh_signal(SIGTERM, signal_handler); ssh_signal(SIGWINCH, window_change_handler); + ssh_signal(SIGINFO, siginfo_handler); if (have_pty) enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE); @@ -1536,7 +1545,8 @@ client_loop(struct ssh *ssh, int have_pty, int escape_char_arg, sigaddset(&bsigset, SIGHUP) == -1 || sigaddset(&bsigset, SIGINT) == -1 || sigaddset(&bsigset, SIGQUIT) == -1 || - sigaddset(&bsigset, SIGTERM) == -1) + sigaddset(&bsigset, SIGTERM) == -1 || + sigaddset(&bsigset, SIGINFO) == -1) error_f("bsigset setup: %s", strerror(errno)); /* Main loop of the client for the interactive session mode. */ @@ -1577,6 +1587,10 @@ client_loop(struct ssh *ssh, int have_pty, int escape_char_arg, */ if (sigprocmask(SIG_BLOCK, &bsigset, &osigset) == -1) error_f("bsigset sigprocmask: %s", strerror(errno)); + if (siginfo_received) { + siginfo_received = 0; + channel_report_open(ssh, SYSLOG_LEVEL_INFO); + } if (quit_pending) break; client_wait_until_can_do_something(ssh, &pfd, &npfd_alloc, From dc5147028ff19213a32281dad07bba02e58da3fa Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Mon, 18 Aug 2025 03:29:11 +0000 Subject: [PATCH 188/244] upstream: SIGINFO handler for sshd(8) to dump active channels/sessions ok deraadt@ OpenBSD-Commit-ID: 9955cb6d157c6d7aa23a819e8ef61b1edabc8b7d --- serverloop.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/serverloop.c b/serverloop.c index 40ddfb042b49..dc96288745ea 100644 --- a/serverloop.c +++ b/serverloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: serverloop.c,v 1.241 2024/11/26 22:01:37 djm Exp $ */ +/* $OpenBSD: serverloop.c,v 1.242 2025/08/18 03:29:11 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -89,7 +89,8 @@ extern struct sshauthopt *auth_opts; static int no_more_sessions = 0; /* Disallow further sessions. */ -static volatile sig_atomic_t child_terminated = 0; /* The child has terminated. */ +static volatile sig_atomic_t child_terminated = 0; /* set on SIGCHLD */ +static volatile sig_atomic_t siginfo_received = 0; /* prototypes */ static void server_init_dispatch(struct ssh *); @@ -103,6 +104,12 @@ sigchld_handler(int sig) child_terminated = 1; } +static void +siginfo_handler(int sig) +{ + siginfo_received = 1; +} + static void client_alive_check(struct ssh *ssh) { @@ -326,9 +333,12 @@ server_loop2(struct ssh *ssh, Authctxt *authctxt) debug("Entering interactive session for SSH2."); - if (sigemptyset(&bsigset) == -1 || sigaddset(&bsigset, SIGCHLD) == -1) + if (sigemptyset(&bsigset) == -1 || + sigaddset(&bsigset, SIGCHLD) == -1 || + sigaddset(&bsigset, SIGINFO) == -1) error_f("bsigset setup: %s", strerror(errno)); ssh_signal(SIGCHLD, sigchld_handler); + ssh_signal(SIGINFO, siginfo_handler); child_terminated = 0; connection_in = ssh_packet_get_connection_in(ssh); connection_out = ssh_packet_get_connection_out(ssh); @@ -350,6 +360,10 @@ server_loop2(struct ssh *ssh, Authctxt *authctxt) if (sigprocmask(SIG_BLOCK, &bsigset, &osigset) == -1) error_f("bsigset sigprocmask: %s", strerror(errno)); collect_children(ssh); + if (siginfo_received) { + siginfo_received = 0; + channel_report_open(ssh, SYSLOG_LEVEL_INFO); + } wait_until_can_do_something(ssh, connection_in, connection_out, &pfd, &npfd_alloc, &npfd_active, &osigset, &conn_in_ready, &conn_out_ready); From 289239046b2c4b0076c14394ae9703a879e78706 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Mon, 18 Aug 2025 03:43:01 +0000 Subject: [PATCH 189/244] upstream: Make ssh(1) and sshd(8) set IP QoS (aka IP_TOS, IPV6_TCLASS) continually at runtime based on what sessions/channels are open. Previously, ssh(1) and sshd(8) would pick a QoS value when they were started and use it for the whole connection. This could produce suboptimal choices for the QoS value, e.g. for multiplexed sessions that started interactive but picked up a sftp client, or sessions that moved large amounts of data via port forwarding. Now the QoS value will change to the non-interactive IPQoS whenever a "non-interactive" channel is open; basically any channel that lacks a tty other than agent forwarding. This is important now that the default interactive IPQoS is EF (Expedited Forwarding), as many networks are configured to allow only relatively small amounts of traffic of this class and they will aggressively deprioritise the entire connection if this is exceeded. NB. because ssh(1) and sshd(8) now change IP_TOS/IPV6_TCLASS continually via setsockopt(), this commit requires a recent pledge(2) change that landed recently in the OpenBSD kernel. Please ensure you have updated to a kernel from within the last two weeks before updating OpenSSH. with job@ deraadt@ OpenBSD-Commit-ID: 325fc41717eecdf5e4b534bfa8d66817425b840f --- channels.c | 46 ++++++++++++++++++++++++++++--- channels.h | 9 ++++++- clientloop.c | 13 +++++---- misc.c | 6 ++++- mux.c | 4 ++- packet.c | 73 ++++++++++++++++++++++++++++++++++---------------- packet.h | 5 ++-- serverloop.c | 9 ++++++- session.c | 7 +---- ssh.c | 27 ++++++------------- sshd-auth.c | 4 ++- sshd-session.c | 4 ++- 12 files changed, 142 insertions(+), 65 deletions(-) diff --git a/channels.c b/channels.c index 9d56310172f3..61cc8a008bfd 100644 --- a/channels.c +++ b/channels.c @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.c,v 1.447 2025/08/18 03:28:02 djm Exp $ */ +/* $OpenBSD: channels.c,v 1.448 2025/08/18 03:43:01 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -212,6 +212,10 @@ struct ssh_channels { /* Global timeout for all OPEN channels */ int global_deadline; time_t lastused; + /* pattern-lists used to classify channels as bulk */ + char *bulk_classifier_tty, *bulk_classifier_notty; + /* Number of active bulk channels (set by channel_handler) */ + u_int nbulk; }; /* helper */ @@ -239,6 +243,8 @@ channel_init_channels(struct ssh *ssh) sc->channels_alloc = 10; sc->channels = xcalloc(sc->channels_alloc, sizeof(*sc->channels)); sc->IPv4or6 = AF_UNSPEC; + sc->bulk_classifier_tty = xstrdup(CHANNEL_BULK_TTY); + sc->bulk_classifier_notty = xstrdup(CHANNEL_BULK_NOTTY); channel_handler_init(sc); ssh->chanctxt = sc; @@ -357,6 +363,17 @@ lookup_timeout(struct ssh *ssh, const char *type) return 0; } +static void +channel_classify(struct ssh *ssh, Channel *c) +{ + struct ssh_channels *sc = ssh->chanctxt; + const char *type = c->xctype == NULL ? c->ctype : c->xctype; + const char *classifier = c->isatty ? + sc->bulk_classifier_tty : sc->bulk_classifier_notty; + + c->bulk = type != NULL && match_pattern_list(type, classifier, 0) == 1; +} + /* * Sets "extended type" of a channel; used by session layer to add additional * information about channel types (e.g. shell, login, subsystem) that can then @@ -375,6 +392,7 @@ channel_set_xtype(struct ssh *ssh, int id, const char *xctype) c->xctype = xstrdup(xctype); /* Type has changed, so look up inactivity deadline again */ c->inactive_deadline = lookup_timeout(ssh, c->xctype); + channel_classify(ssh, c); debug2_f("labeled channel %d as %s (inactive timeout %u)", id, xctype, c->inactive_deadline); } @@ -411,6 +429,13 @@ channel_get_expiry(struct ssh *ssh, Channel *c) return expiry; } +/* Returns non-zero if there is an open, non-interactive channel */ +int +channel_has_bulk(struct ssh *ssh) +{ + return ssh->chanctxt != NULL && ssh->chanctxt->nbulk != 0; +} + /* * Register filedescriptors for a channel, used when allocating a channel or * when the channel consumer/producer is ready, e.g. shell exec'd @@ -478,6 +503,7 @@ channel_register_fds(struct ssh *ssh, Channel *c, int rfd, int wfd, int efd, } /* channel might be entering a larval state, so reset global timeout */ channel_set_used_time(ssh, NULL); + channel_classify(ssh, c); } /* @@ -537,11 +563,19 @@ channel_new(struct ssh *ssh, char *ctype, int type, int rfd, int wfd, int efd, c->delayed = 1; /* prevent call to channel_post handler */ c->inactive_deadline = lookup_timeout(ssh, c->ctype); TAILQ_INIT(&c->status_confirms); + channel_classify(ssh, c); debug("channel %d: new %s [%s] (inactive timeout: %u)", found, c->ctype, remote_name, c->inactive_deadline); return c; } +void +channel_set_tty(struct ssh *ssh, Channel *c) +{ + c->isatty = 1; + channel_classify(ssh, c); +} + int channel_close_fd(struct ssh *ssh, Channel *c, int *fdp) { @@ -1019,7 +1053,7 @@ channel_format_status(const Channel *c) char *ret = NULL; xasprintf(&ret, "t%d [%s] %s%u %s%u i%u/%zu o%u/%zu e[%s]/%zu " - "fd %d/%d/%d sock %d cc %d %s%u io 0x%02x/0x%02x", + "fd %d/%d/%d sock %d cc %d %s%u io 0x%02x/0x%02x %s%s", c->type, c->xctype != NULL ? c->xctype : c->ctype, c->have_remote_id ? "r" : "nr", c->remote_id, c->mux_ctx != NULL ? "m" : "nm", c->mux_downstream_id, @@ -1028,7 +1062,8 @@ channel_format_status(const Channel *c) channel_format_extended_usage(c), sshbuf_len(c->extended), c->rfd, c->wfd, c->efd, c->sock, c->ctl_chan, c->have_ctl_child_id ? "c" : "nc", c->ctl_child_id, - c->io_want, c->io_ready); + c->io_want, c->io_ready, + c->isatty ? "T" : "", c->bulk ? "B" : "I"); return ret; } @@ -2621,10 +2656,13 @@ channel_handler(struct ssh *ssh, int table, struct timespec *timeout) time_t now; now = monotime(); - for (i = 0, oalloc = sc->channels_alloc; i < oalloc; i++) { + for (sc->nbulk = i = 0, oalloc = sc->channels_alloc; i < oalloc; i++) { c = sc->channels[i]; if (c == NULL) continue; + /* Count open channels in bulk state */ + if (c->type == SSH_CHANNEL_OPEN && c->bulk) + sc->nbulk++; /* Try to keep IO going while rekeying */ if (ssh_packet_is_rekeying(ssh) && c->type != SSH_CHANNEL_OPEN) continue; diff --git a/channels.h b/channels.h index 1bfade4c5c77..145ea2f69445 100644 --- a/channels.h +++ b/channels.h @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.h,v 1.159 2025/08/18 03:28:02 djm Exp $ */ +/* $OpenBSD: channels.h,v 1.160 2025/08/18 03:43:01 djm Exp $ */ /* * Author: Tatu Ylonen @@ -82,6 +82,10 @@ #define FORWARD_ADM 0x100 #define FORWARD_USER 0x101 +/* default pattern-lists used to classify channel types as bulk */ +#define CHANNEL_BULK_TTY "" +#define CHANNEL_BULK_NOTTY "direct-*,forwarded-*,tun-*,x11-*,session*" + struct ssh; struct Channel; typedef struct Channel Channel; @@ -180,6 +184,7 @@ struct Channel { char *ctype; /* const type - NB. not freed on channel_free */ char *xctype; /* extended type */ + int bulk; /* channel is non-interactive */ /* callback */ channel_open_fn *open_confirm; @@ -289,6 +294,7 @@ Channel *channel_new(struct ssh *, char *, int, int, int, int, u_int, u_int, int, const char *, int); void channel_set_fds(struct ssh *, int, int, int, int, int, int, int, u_int); +void channel_set_tty(struct ssh *, Channel *); void channel_free(struct ssh *, Channel *); void channel_free_all(struct ssh *); void channel_stop_listening(struct ssh *); @@ -308,6 +314,7 @@ void channel_register_status_confirm(struct ssh *, int, void channel_cancel_cleanup(struct ssh *, int); int channel_close_fd(struct ssh *, Channel *, int *); void channel_send_window_changes(struct ssh *); +int channel_has_bulk(struct ssh *); /* channel inactivity timeouts */ void channel_add_timeout(struct ssh *, const char *, int); diff --git a/clientloop.c b/clientloop.c index b9c050409861..677bf40f0233 100644 --- a/clientloop.c +++ b/clientloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.c,v 1.413 2025/08/18 03:28:36 djm Exp $ */ +/* $OpenBSD: clientloop.c,v 1.414 2025/08/18 03:43:01 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1455,7 +1455,7 @@ client_loop(struct ssh *ssh, int have_pty, int escape_char_arg, struct pollfd *pfd = NULL; u_int npfd_alloc = 0, npfd_active = 0; double start_time, total_time; - int channel_did_enqueue = 0, r; + int interactive = -1, channel_did_enqueue = 0, r; u_int64_t ibytes, obytes; int conn_in_ready, conn_out_ready; sigset_t bsigset, osigset; @@ -1621,6 +1621,12 @@ client_loop(struct ssh *ssh, int have_pty, int escape_char_arg, * sender. */ if (conn_out_ready) { + if (interactive != !channel_has_bulk(ssh)) { + interactive = !channel_has_bulk(ssh); + debug2_f("session QoS is now %s", interactive ? + "interactive" : "non-interactive"); + ssh_packet_set_interactive(ssh, interactive); + } if ((r = ssh_packet_write_poll(ssh)) != 0) { sshpkt_fatal(ssh, r, "%s: ssh_packet_write_poll", __func__); @@ -2706,9 +2712,6 @@ client_session2_setup(struct ssh *ssh, int id, int want_tty, int want_subsystem, if ((c = channel_lookup(ssh, id)) == NULL) fatal_f("channel %d: unknown channel", id); - ssh_packet_set_interactive(ssh, want_tty, - options.ip_qos_interactive, options.ip_qos_bulk); - if (want_tty) { struct winsize ws; diff --git a/misc.c b/misc.c index 2e77eeb88de4..ef77a6b7f612 100644 --- a/misc.c +++ b/misc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: misc.c,v 1.202 2025/08/11 14:37:43 deraadt Exp $ */ +/* $OpenBSD: misc.c,v 1.203 2025/08/18 03:43:01 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2005-2020 Damien Miller. All rights reserved. @@ -297,6 +297,10 @@ set_sock_tos(int fd, int tos) #ifndef IP_TOS_IS_BROKEN int af; + if (tos < 0 || tos == INT_MAX) { + debug_f("invalid TOS %d", tos); + return; + } switch ((af = get_sock_af(fd))) { case -1: /* assume not a socket */ diff --git a/mux.c b/mux.c index 1a4f357d46f0..542024e7a448 100644 --- a/mux.c +++ b/mux.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mux.c,v 1.104 2025/07/04 00:17:55 djm Exp $ */ +/* $OpenBSD: mux.c,v 1.105 2025/08/18 03:43:01 djm Exp $ */ /* * Copyright (c) 2002-2008 Damien Miller * @@ -460,6 +460,8 @@ mux_master_process_new_session(struct ssh *ssh, u_int rid, nc = channel_new(ssh, "session", SSH_CHANNEL_OPENING, new_fd[0], new_fd[1], new_fd[2], window, packetmax, CHAN_EXTENDED_WRITE, "client-session", CHANNEL_NONBLOCK_STDIO); + if (cctx->want_tty) + channel_set_tty(ssh, nc); nc->ctl_chan = c->self; /* link session -> control channel */ c->ctl_child_id = nc->self; /* link control -> session channel */ diff --git a/packet.c b/packet.c index 7f67f4fcd55e..b899fcafb57d 100644 --- a/packet.c +++ b/packet.c @@ -1,4 +1,4 @@ -/* $OpenBSD: packet.c,v 1.319 2025/08/06 23:44:09 djm Exp $ */ +/* $OpenBSD: packet.c,v 1.320 2025/08/18 03:43:01 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -210,8 +210,8 @@ struct session_state { /* Used in ssh_packet_send_mux() */ int mux; - /* Used in packet_set_interactive */ - int set_interactive_called; + /* QoS handling */ + int qos_interactive, qos_other; /* Used in packet_set_maxsize */ int set_maxsize_called; @@ -225,6 +225,9 @@ struct session_state { */ int disconnecting; + /* Nagle disabled on socket */ + int nodelay_set; + /* Hook for fuzzing inbound packets */ ssh_packet_hook_fn *hook_in; void *hook_in_ctx; @@ -253,6 +256,8 @@ ssh_alloc_session_state(void) state->connection_out = -1; state->max_packet_size = 32768; state->packet_timeout_ms = -1; + state->interactive_mode = 1; + state->qos_interactive = state->qos_other = -1; state->p_send.packets = state->p_read.packets = 0; state->initialized = 1; /* @@ -2212,37 +2217,44 @@ ssh_packet_interactive_data_to_write(struct ssh *ssh) sshbuf_len(ssh->state->output) < 256; } -void -ssh_packet_set_tos(struct ssh *ssh, int tos) +static void +apply_qos(struct ssh *ssh) { - if (!ssh_packet_connection_is_on_socket(ssh) || tos == INT_MAX) + struct session_state *state = ssh->state; + int qos = state->interactive_mode ? + state->qos_interactive : state->qos_other; + + if (!ssh_packet_connection_is_on_socket(ssh)) return; - set_sock_tos(ssh->state->connection_in, tos); + if (!state->nodelay_set) { + set_nodelay(state->connection_in); + state->nodelay_set = 1; + } + set_sock_tos(ssh->state->connection_in, qos); } -/* Informs that the current session is interactive. Sets IP flags for that. */ - +/* Informs that the current session is interactive. */ void -ssh_packet_set_interactive(struct ssh *ssh, int interactive, int qos_interactive, int qos_bulk) +ssh_packet_set_interactive(struct ssh *ssh, int interactive) { struct session_state *state = ssh->state; - if (state->set_interactive_called) - return; - state->set_interactive_called = 1; - - /* Record that we are in interactive mode. */ state->interactive_mode = interactive; + apply_qos(ssh); +} - /* Only set socket options if using a socket. */ - if (!ssh_packet_connection_is_on_socket(ssh)) - return; - set_nodelay(state->connection_in); - ssh_packet_set_tos(ssh, interactive ? qos_interactive : qos_bulk); +/* Set QoS flags to be used for interactive and non-interactive sessions */ +void +ssh_packet_set_qos(struct ssh *ssh, int qos_interactive, int qos_other) +{ + struct session_state *state = ssh->state; + + state->qos_interactive = qos_interactive; + state->qos_other = qos_other; + apply_qos(ssh); } /* Returns true if the current connection is interactive. */ - int ssh_packet_is_interactive(struct ssh *ssh) { @@ -2421,6 +2433,7 @@ ssh_packet_get_state(struct ssh *ssh, struct sshbuf *m) struct session_state *state = ssh->state; int r; +#define ENCODE_INT(v) (((v) < 0) ? 0xFFFFFFFF : (u_int)v) if ((r = kex_to_blob(m, ssh->kex)) != 0 || (r = newkeys_to_blob(m, ssh, MODE_OUT)) != 0 || (r = newkeys_to_blob(m, ssh, MODE_IN)) != 0 || @@ -2435,9 +2448,12 @@ ssh_packet_get_state(struct ssh *ssh, struct sshbuf *m) (r = sshbuf_put_u32(m, state->p_read.packets)) != 0 || (r = sshbuf_put_u64(m, state->p_read.bytes)) != 0 || (r = sshbuf_put_stringb(m, state->input)) != 0 || - (r = sshbuf_put_stringb(m, state->output)) != 0) + (r = sshbuf_put_stringb(m, state->output)) != 0 || + (r = sshbuf_put_u32(m, ENCODE_INT(state->interactive_mode))) != 0 || + (r = sshbuf_put_u32(m, ENCODE_INT(state->qos_interactive))) != 0 || + (r = sshbuf_put_u32(m, ENCODE_INT(state->qos_other))) != 0) return r; - +#undef ENCODE_INT return 0; } @@ -2556,6 +2572,7 @@ ssh_packet_set_state(struct ssh *ssh, struct sshbuf *m) const u_char *input, *output; size_t ilen, olen; int r; + u_int interactive, qos_interactive, qos_other; if ((r = kex_from_blob(m, &ssh->kex)) != 0 || (r = newkeys_from_blob(m, ssh, MODE_OUT)) != 0 || @@ -2592,6 +2609,16 @@ ssh_packet_set_state(struct ssh *ssh, struct sshbuf *m) (r = sshbuf_put(state->output, output, olen)) != 0) return r; + if ((r = sshbuf_get_u32(m, &interactive)) != 0 || + (r = sshbuf_get_u32(m, &qos_interactive)) != 0 || + (r = sshbuf_get_u32(m, &qos_other)) != 0) + return r; +#define DECODE_INT(v) ((v) > INT_MAX ? -1 : (v)) + state->interactive_mode = DECODE_INT(interactive); + state->qos_interactive = DECODE_INT(qos_interactive); + state->qos_other = DECODE_INT(qos_other); +#undef DECODE_INT + if (sshbuf_len(m)) return SSH_ERR_INVALID_FORMAT; debug3_f("done"); diff --git a/packet.h b/packet.h index 49bb87f0750b..6828476c7923 100644 --- a/packet.h +++ b/packet.h @@ -1,4 +1,4 @@ -/* $OpenBSD: packet.h,v 1.99 2024/08/15 00:51:51 djm Exp $ */ +/* $OpenBSD: packet.h,v 1.100 2025/08/18 03:43:01 djm Exp $ */ /* * Author: Tatu Ylonen @@ -111,8 +111,9 @@ int ssh_packet_check_rekey(struct ssh *); void ssh_packet_set_protocol_flags(struct ssh *, u_int); u_int ssh_packet_get_protocol_flags(struct ssh *); void ssh_packet_set_tos(struct ssh *, int); -void ssh_packet_set_interactive(struct ssh *, int, int, int); +void ssh_packet_set_interactive(struct ssh *, int); int ssh_packet_is_interactive(struct ssh *); +void ssh_packet_set_qos(struct ssh *, int, int); void ssh_packet_set_server(struct ssh *); void ssh_packet_set_authenticated(struct ssh *); void ssh_packet_set_mux(struct ssh *); diff --git a/serverloop.c b/serverloop.c index dc96288745ea..753f56388b38 100644 --- a/serverloop.c +++ b/serverloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: serverloop.c,v 1.242 2025/08/18 03:29:11 djm Exp $ */ +/* $OpenBSD: serverloop.c,v 1.243 2025/08/18 03:43:01 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -292,8 +292,15 @@ static void process_output(struct ssh *ssh, int connection_out) { int r; + static int interactive = -1; /* Send any buffered packet data to the client. */ + if (interactive != !channel_has_bulk(ssh)) { + interactive = !channel_has_bulk(ssh); + debug2_f("session QoS is now %s", interactive ? + "interactive" : "non-interactive"); + ssh_packet_set_interactive(ssh, interactive); + } if ((r = ssh_packet_write_poll(ssh)) != 0) { sshpkt_fatal(ssh, r, "%s: ssh_packet_write_poll", __func__); diff --git a/session.c b/session.c index 630e0e6a353c..7b030793ac28 100644 --- a/session.c +++ b/session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: session.c,v 1.342 2025/05/05 02:48:06 djm Exp $ */ +/* $OpenBSD: session.c,v 1.343 2025/08/18 03:43:01 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -498,9 +498,6 @@ do_exec_no_pty(struct ssh *ssh, Session *s, const char *command) #endif s->pid = pid; - /* Set interactive/non-interactive mode. */ - ssh_packet_set_interactive(ssh, s->display != NULL, - options.ip_qos_interactive, options.ip_qos_bulk); /* * Clear loginmsg, since it's the child's responsibility to display @@ -628,8 +625,6 @@ do_exec_pty(struct ssh *ssh, Session *s, const char *command) /* Enter interactive session. */ s->ptymaster = ptymaster; - ssh_packet_set_interactive(ssh, 1, - options.ip_qos_interactive, options.ip_qos_bulk); session_set_fds(ssh, s, ptyfd, fdout, -1, 1, 1); return 0; } diff --git a/ssh.c b/ssh.c index b44a943134ee..58c254b93d86 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.614 2025/06/19 05:49:05 djm Exp $ */ +/* $OpenBSD: ssh.c,v 1.615 2025/08/18 03:43:01 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -758,7 +758,6 @@ main(int ac, char **av) fatal("Couldn't allocate session state"); channel_init_channels(ssh); - /* Parse command-line arguments. */ args = argv_assemble(ac, av); /* logged later */ host = NULL; @@ -1376,6 +1375,8 @@ main(int ac, char **av) if (options.port == 0) options.port = default_ssh_port(); channel_set_af(ssh, options.address_family); + ssh_packet_set_qos(ssh, options.ip_qos_interactive, + options.ip_qos_bulk); /* Tidy and check options */ if (options.host_key_alias != NULL) @@ -2182,7 +2183,7 @@ ssh_session2_setup(struct ssh *ssh, int id, int success, void *arg) { extern char **environ; const char *display, *term; - int r, interactive = tty_flag; + int r; char *proto = NULL, *data = NULL; if (!success) @@ -2201,7 +2202,6 @@ ssh_session2_setup(struct ssh *ssh, int id, int success, void *arg) data, 1); client_expect_confirm(ssh, id, "X11 forwarding", CONFIRM_WARN); /* XXX exit_on_forward_failure */ - interactive = 1; } check_agent_present(); @@ -2212,10 +2212,6 @@ ssh_session2_setup(struct ssh *ssh, int id, int success, void *arg) fatal_fr(r, "send packet"); } - /* Tell the packet module whether this is an interactive session. */ - ssh_packet_set_interactive(ssh, interactive, - options.ip_qos_interactive, options.ip_qos_bulk); - if ((term = lookup_env_in_list("TERM", options.setenv, options.num_setenv)) == NULL || *term == '\0') term = getenv("TERM"); @@ -2252,8 +2248,9 @@ ssh_session2_open(struct ssh *ssh) "session", SSH_CHANNEL_OPENING, in, out, err, window, packetmax, CHAN_EXTENDED_WRITE, "client-session", CHANNEL_NONBLOCK_STDIO); - - debug3_f("channel_new: %d", c->self); + if (tty_flag) + channel_set_tty(ssh, c); + debug3_f("channel_new: %d%s", c->self, tty_flag ? " (tty)" : ""); channel_send_open(ssh, c->self); if (options.session_type != SESSION_TYPE_NONE) @@ -2266,7 +2263,7 @@ ssh_session2_open(struct ssh *ssh) static int ssh_session2(struct ssh *ssh, const struct ssh_conn_info *cinfo) { - int r, interactive, id = -1; + int r, id = -1; char *cp, *tun_fwd_ifname = NULL; /* XXX should be pre-session */ @@ -2322,14 +2319,6 @@ ssh_session2(struct ssh *ssh, const struct ssh_conn_info *cinfo) if (options.session_type != SESSION_TYPE_NONE) id = ssh_session2_open(ssh); - else { - interactive = options.control_master == SSHCTL_MASTER_NO; - /* ControlPersist may have clobbered ControlMaster, so check */ - if (need_controlpersist_detach) - interactive = otty_flag != 0; - ssh_packet_set_interactive(ssh, interactive, - options.ip_qos_interactive, options.ip_qos_bulk); - } /* If we don't expect to open a new session, then disallow it */ if (options.control_master == SSHCTL_MASTER_NO && diff --git a/sshd-auth.c b/sshd-auth.c index 6bf596e7a5fa..9dd086c4ce6a 100644 --- a/sshd-auth.c +++ b/sshd-auth.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd-auth.c,v 1.5 2025/08/18 01:59:53 djm Exp $ */ +/* $OpenBSD: sshd-auth.c,v 1.6 2025/08/18 03:43:01 djm Exp $ */ /* * SSH2 implementation: * Privilege Separation: @@ -652,6 +652,8 @@ main(int ac, char **av) /* Fill in default values for those options not explicitly set. */ fill_default_server_options(&options); options.timing_secret = timing_secret; /* XXX eliminate from unpriv */ + ssh_packet_set_qos(ssh, options.ip_qos_interactive, + options.ip_qos_bulk); /* Reinit logging in case config set Level, Facility or Verbose. */ log_init(__progname, options.log_level, options.log_facility, 1); diff --git a/sshd-session.c b/sshd-session.c index 60f887e92d7b..4aad8b6fe140 100644 --- a/sshd-session.c +++ b/sshd-session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd-session.c,v 1.13 2025/05/06 05:40:56 djm Exp $ */ +/* $OpenBSD: sshd-session.c,v 1.14 2025/08/18 03:43:01 djm Exp $ */ /* * SSH2 implementation: * Privilege Separation: @@ -1207,6 +1207,8 @@ main(int ac, char **av) fatal("Unable to create connection"); the_active_state = ssh; ssh_packet_set_server(ssh); + ssh_packet_set_qos(ssh, options.ip_qos_interactive, + options.ip_qos_bulk); check_ip_options(ssh); From b7ee13fbbb4ebafcf71f29685f053ecb97d1bcef Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Mon, 18 Aug 2025 14:22:18 +1000 Subject: [PATCH 190/244] wrap SIGINFO in ifdef --- clientloop.c | 11 +++++++++-- serverloop.c | 9 +++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/clientloop.c b/clientloop.c index 677bf40f0233..b9a010414ff3 100644 --- a/clientloop.c +++ b/clientloop.c @@ -225,12 +225,14 @@ window_change_handler(int sig) received_window_change_signal = 1; } +#ifdef SIGINFO /* Signal handler for SIGINFO */ static void siginfo_handler(int sig) { siginfo_received = 1; } +#endif /* * Signal handler for signals that cause the program to terminate. These @@ -1522,7 +1524,9 @@ client_loop(struct ssh *ssh, int have_pty, int escape_char_arg, if (ssh_signal(SIGTERM, SIG_IGN) != SIG_IGN) ssh_signal(SIGTERM, signal_handler); ssh_signal(SIGWINCH, window_change_handler); +#ifdef SIGINFO ssh_signal(SIGINFO, siginfo_handler); +#endif if (have_pty) enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE); @@ -1545,9 +1549,12 @@ client_loop(struct ssh *ssh, int have_pty, int escape_char_arg, sigaddset(&bsigset, SIGHUP) == -1 || sigaddset(&bsigset, SIGINT) == -1 || sigaddset(&bsigset, SIGQUIT) == -1 || - sigaddset(&bsigset, SIGTERM) == -1 || - sigaddset(&bsigset, SIGINFO) == -1) + sigaddset(&bsigset, SIGTERM) == -1) error_f("bsigset setup: %s", strerror(errno)); +#ifdef SIGINFO + if (sigaddset(&bsigset, SIGINFO) == -1) + error_f("bsigset setup: %s", strerror(errno)); +#endif /* Main loop of the client for the interactive session mode. */ while (!quit_pending) { diff --git a/serverloop.c b/serverloop.c index 753f56388b38..4beb2a390b6d 100644 --- a/serverloop.c +++ b/serverloop.c @@ -104,11 +104,13 @@ sigchld_handler(int sig) child_terminated = 1; } +#ifdef SIGINFO static void siginfo_handler(int sig) { siginfo_received = 1; } +#endif static void client_alive_check(struct ssh *ssh) @@ -341,11 +343,14 @@ server_loop2(struct ssh *ssh, Authctxt *authctxt) debug("Entering interactive session for SSH2."); if (sigemptyset(&bsigset) == -1 || - sigaddset(&bsigset, SIGCHLD) == -1 || - sigaddset(&bsigset, SIGINFO) == -1) + sigaddset(&bsigset, SIGCHLD) == -1) error_f("bsigset setup: %s", strerror(errno)); ssh_signal(SIGCHLD, sigchld_handler); +#ifdef SIGINFO + if (sigaddset(&bsigset, SIGINFO) == -1) + error_f("bsigset setup: %s", strerror(errno)); ssh_signal(SIGINFO, siginfo_handler); +#endif child_terminated = 0; connection_in = ssh_packet_get_connection_in(ssh); connection_out = ssh_packet_get_connection_out(ssh); From 056022261e6cf7eb65bbacac72afe5f4d5945f2c Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Mon, 18 Aug 2025 14:22:32 +1000 Subject: [PATCH 191/244] depend --- .depend | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.depend b/.depend index f569b603d450..6961e34dd392 100644 --- a/.depend +++ b/.depend @@ -8,8 +8,11 @@ atomicio.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-comp audit-bsm.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h audit-linux.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h audit.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h +auth-bsdauth-monitor.o: xmalloc.h sshkey.h sshbuf.h hostfile.h auth.h auth-pam.h includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h audit.h loginrec.h log.h ssherr.h auth-bsdauth.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h auth-krb5.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h ssh.h packet.h openbsd-compat/sys-queue.h dispatch.h log.h ssherr.h sshbuf.h sshkey.h misc.h servconf.h uidswap.h hostfile.h auth.h auth-pam.h audit.h loginrec.h +auth-log.o: authfile.h monitor_wrap.h channels.h +auth-log.o: xmalloc.h match.h groupaccess.h log.h ssherr.h sshbuf.h misc.h servconf.h openbsd-compat/sys-queue.h sshkey.h hostfile.h auth.h auth-pam.h includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h audit.h loginrec.h auth-options.h canohost.h packet.h dispatch.h auth-options.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/sys-queue.h xmalloc.h ssherr.h log.h sshbuf.h misc.h sshkey.h match.h ssh2.h auth-options.h auth-pam.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h auth-passwd.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h packet.h openbsd-compat/sys-queue.h dispatch.h sshbuf.h ssherr.h log.h misc.h servconf.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h auth-options.h @@ -18,17 +21,25 @@ auth-shadow.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-c auth-sia.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h auth.o: authfile.h monitor_wrap.h channels.h auth.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h match.h groupaccess.h log.h ssherr.h sshbuf.h misc.h servconf.h openbsd-compat/sys-queue.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h auth-options.h canohost.h uidswap.h packet.h dispatch.h +auth2-banner.o: atomicio.h xmalloc.h ssh2.h packet.h openbsd-compat/sys-queue.h dispatch.h log.h ssherr.h sshbuf.h misc.h servconf.h sshkey.h hostfile.h auth.h auth-pam.h includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h audit.h loginrec.h pathnames.h auth2-chall.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h ssh2.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h sshbuf.h packet.h openbsd-compat/sys-queue.h dispatch.h ssherr.h log.h misc.h servconf.h auth2-gss.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h +auth2-hostbased-monitor.o: canohost.h pathnames.h match.h +auth2-hostbased-monitor.o: xmalloc.h ssh2.h packet.h openbsd-compat/sys-queue.h dispatch.h kex.h mac.h crypto_api.h includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h sshbuf.h log.h ssherr.h misc.h servconf.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h uidswap.h auth2-hostbased.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h ssh2.h packet.h openbsd-compat/sys-queue.h dispatch.h kex.h mac.h crypto_api.h sshbuf.h log.h ssherr.h misc.h servconf.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h canohost.h auth2-hostbased.o: monitor_wrap.h pathnames.h match.h +auth2-kbdint-monitor.o: xmalloc.h packet.h openbsd-compat/sys-queue.h dispatch.h hostfile.h auth.h auth-pam.h includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h audit.h loginrec.h log.h ssherr.h misc.h servconf.h auth2-kbdint.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h packet.h openbsd-compat/sys-queue.h dispatch.h hostfile.h auth.h auth-pam.h audit.h loginrec.h log.h ssherr.h misc.h servconf.h auth2-methods.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h log.h ssherr.h misc.h servconf.h openbsd-compat/sys-queue.h xmalloc.h hostfile.h auth.h auth-pam.h audit.h loginrec.h auth2-none.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h atomicio.h xmalloc.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h packet.h openbsd-compat/sys-queue.h dispatch.h log.h ssherr.h misc.h servconf.h ssh2.h monitor_wrap.h auth2-passwd.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h packet.h openbsd-compat/sys-queue.h dispatch.h ssherr.h log.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h monitor_wrap.h misc.h servconf.h +auth2-pubkey-monitor.o: loginrec.h pathnames.h uidswap.h auth-options.h canohost.h monitor_wrap.h authfile.h match.h channels.h session.h sk-api.h +auth2-pubkey-monitor.o: xmalloc.h ssh.h ssh2.h packet.h openbsd-compat/sys-queue.h dispatch.h kex.h mac.h crypto_api.h includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h sshbuf.h log.h ssherr.h misc.h servconf.h compat.h sshkey.h hostfile.h auth.h auth-pam.h audit.h auth2-pubkey.o: audit.h loginrec.h pathnames.h uidswap.h auth-options.h canohost.h monitor_wrap.h authfile.h match.h channels.h session.h sk-api.h auth2-pubkey.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/glob.h xmalloc.h ssh.h ssh2.h packet.h openbsd-compat/sys-queue.h dispatch.h kex.h mac.h crypto_api.h sshbuf.h log.h ssherr.h misc.h servconf.h compat.h sshkey.h hostfile.h auth.h auth-pam.h auth2-pubkeyfile.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ssh.h log.h ssherr.h misc.h sshkey.h digest.h hostfile.h auth.h auth-pam.h audit.h loginrec.h auth-options.h authfile.h match.h +auth2-userauth.o: atomicio.h xmalloc.h ssh2.h packet.h openbsd-compat/sys-queue.h dispatch.h log.h ssherr.h sshbuf.h misc.h servconf.h sshkey.h hostfile.h auth.h auth-pam.h includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h audit.h loginrec.h pathnames.h monitor_wrap.h +auth2-userauth.o: digest.h auth2.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h atomicio.h xmalloc.h ssh2.h packet.h openbsd-compat/sys-queue.h dispatch.h log.h ssherr.h sshbuf.h misc.h servconf.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h pathnames.h monitor_wrap.h digest.h kex.h auth2.o: mac.h crypto_api.h authfd.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h ssh.h sshbuf.h sshkey.h authfd.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h log.h ssherr.h atomicio.h misc.h @@ -161,8 +172,14 @@ sshconnect2.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-c sshconnect2.o: sshconnect.h authfile.h dh.h authfd.h log.h ssherr.h misc.h readconf.h match.h canohost.h msg.h pathnames.h uidswap.h hostfile.h utf8.h ssh-sk.h sk-api.h sshd-auth.o: chacha.h poly1305.h cipher-aesctr.h rijndael.h digest.h sshkey.h kex.h mac.h crypto_api.h authfile.h pathnames.h atomicio.h canohost.h hostfile.h auth.h auth-pam.h audit.h loginrec.h authfd.h msg.h channels.h session.h monitor.h monitor_wrap.h auth-options.h version.h sk-api.h srclimit.h ssh-sandbox.h dh.h sshd-auth.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ./openbsd-compat/sys-tree.h openbsd-compat/sys-queue.h xmalloc.h ssh.h ssh2.h sshpty.h packet.h dispatch.h log.h ssherr.h sshbuf.h misc.h match.h servconf.h uidswap.h compat.h cipher.h cipher-chachapoly.h +sshd-monitor.o: openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h authfile.h pathnames.h atomicio.h canohost.h hostfile.h auth.h auth-pam.h audit.h loginrec.h authfd.h msg.h channels.h session.h monitor.h monitor_wrap.h auth-options.h version.h sk-api.h dh.h +sshd-monitor.o: xmalloc.h ssh.h ssh2.h sshpty.h packet.h openbsd-compat/sys-queue.h dispatch.h log.h ssherr.h sshbuf.h misc.h match.h servconf.h uidswap.h compat.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h digest.h sshkey.h kex.h mac.h crypto_api.h includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h sshd-session.o: chacha.h poly1305.h cipher-aesctr.h rijndael.h digest.h sshkey.h kex.h mac.h crypto_api.h authfile.h pathnames.h atomicio.h canohost.h hostfile.h auth.h auth-pam.h audit.h loginrec.h authfd.h msg.h channels.h session.h monitor.h monitor_wrap.h auth-options.h version.h sk-api.h srclimit.h dh.h sshd-session.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ./openbsd-compat/sys-tree.h openbsd-compat/sys-queue.h xmalloc.h ssh.h ssh2.h sshpty.h packet.h dispatch.h log.h ssherr.h sshbuf.h misc.h match.h servconf.h uidswap.h compat.h cipher.h cipher-chachapoly.h +sshd-unpriv-postauth.o: openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h authfile.h pathnames.h atomicio.h canohost.h hostfile.h auth.h auth-pam.h audit.h loginrec.h authfd.h msg.h channels.h session.h monitor.h monitor_wrap.h auth-options.h version.h sk-api.h dh.h +sshd-unpriv-postauth.o: xmalloc.h ssh.h ssh2.h sshpty.h packet.h openbsd-compat/sys-queue.h dispatch.h log.h ssherr.h sshbuf.h misc.h match.h servconf.h uidswap.h compat.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h digest.h sshkey.h kex.h mac.h crypto_api.h includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h +sshd-unpriv-preauth.o: openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h authfile.h pathnames.h atomicio.h canohost.h hostfile.h auth.h auth-pam.h audit.h loginrec.h authfd.h msg.h channels.h session.h monitor.h monitor_wrap.h auth-options.h version.h sk-api.h dh.h +sshd-unpriv-preauth.o: xmalloc.h ssh.h ssh2.h sshpty.h packet.h openbsd-compat/sys-queue.h dispatch.h log.h ssherr.h sshbuf.h misc.h match.h servconf.h uidswap.h compat.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h digest.h sshkey.h kex.h mac.h crypto_api.h includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h sshd.o: audit.h loginrec.h authfd.h msg.h version.h sk-api.h addr.h srclimit.h atomicio.h monitor_wrap.h sshd.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ./openbsd-compat/sys-tree.h openbsd-compat/sys-queue.h xmalloc.h ssh.h sshpty.h log.h ssherr.h sshbuf.h misc.h servconf.h compat.h digest.h sshkey.h authfile.h pathnames.h canohost.h hostfile.h auth.h auth-pam.h ssherr.o: ssherr.h From c2c8bae39380392449ac3297061cbfc486126ad5 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Mon, 18 Aug 2025 04:38:21 +0000 Subject: [PATCH 192/244] upstream: missing set_log_handler() call in ssh-auth.c, exposed after last commit OpenBSD-Commit-ID: 09f5c3cf33c18b8ad321edbf96c30ae3deada2b0 --- sshd-auth.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sshd-auth.c b/sshd-auth.c index 9dd086c4ce6a..6bb4aff0d726 100644 --- a/sshd-auth.c +++ b/sshd-auth.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd-auth.c,v 1.6 2025/08/18 03:43:01 djm Exp $ */ +/* $OpenBSD: sshd-auth.c,v 1.7 2025/08/18 04:38:21 djm Exp $ */ /* * SSH2 implementation: * Privilege Separation: @@ -657,6 +657,7 @@ main(int ac, char **av) /* Reinit logging in case config set Level, Facility or Verbose. */ log_init(__progname, options.log_level, options.log_facility, 1); + set_log_handler(mm_log_handler, pmonitor); debug("sshd-auth version %s, %s", SSH_VERSION, SSH_OPENSSL_VERSION); From ae44cd74f3a4ac711152f50b2712803ccf785593 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Mon, 18 Aug 2025 04:50:35 +0000 Subject: [PATCH 193/244] upstream: cast OpenBSD-Commit-ID: d69bd2328513c2dcd99f4f346b77e2bd90cf1964 --- packet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packet.c b/packet.c index b899fcafb57d..34bf91d75e52 100644 --- a/packet.c +++ b/packet.c @@ -1,4 +1,4 @@ -/* $OpenBSD: packet.c,v 1.320 2025/08/18 03:43:01 djm Exp $ */ +/* $OpenBSD: packet.c,v 1.321 2025/08/18 04:50:35 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -2613,7 +2613,7 @@ ssh_packet_set_state(struct ssh *ssh, struct sshbuf *m) (r = sshbuf_get_u32(m, &qos_interactive)) != 0 || (r = sshbuf_get_u32(m, &qos_other)) != 0) return r; -#define DECODE_INT(v) ((v) > INT_MAX ? -1 : (v)) +#define DECODE_INT(v) ((v) > INT_MAX ? -1 : (int)(v)) state->interactive_mode = DECODE_INT(interactive); state->qos_interactive = DECODE_INT(qos_interactive); state->qos_other = DECODE_INT(qos_other); From 9184fa363687fcb5dac056b093fb3b8e9d327242 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Mon, 18 Aug 2025 16:45:15 +1000 Subject: [PATCH 194/244] check for setsockopt IP_TOS in OpenBSD pledge OpenBSD has recently relaxed the pledge(2) sandbox to allow some setsockopt options to be changed without the "inet" promise. This adds compatibility for OpenBSD that predates this relaxation. --- clientloop.c | 4 ++-- configure.ac | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/clientloop.c b/clientloop.c index b9a010414ff3..577771f06963 100644 --- a/clientloop.c +++ b/clientloop.c @@ -975,11 +975,11 @@ client_repledge(void) } else if (options.forward_agent != 0) { /* agent forwarding needs to open $SSH_AUTH_SOCK at will */ debug("pledge: agent"); - if (pledge("stdio unix proc tty", NULL) == -1) + if (pledge(PLEDGE_EXTRA_INET "stdio unix proc tty", NULL) == -1) fatal_f("pledge(): %s", strerror(errno)); } else { debug("pledge: fork"); - if (pledge("stdio proc tty", NULL) == -1) + if (pledge(PLEDGE_EXTRA_INET "stdio proc tty", NULL) == -1) fatal_f("pledge(): %s", strerror(errno)); } /* XXX further things to do: diff --git a/configure.ac b/configure.ac index 460ebd3b476c..bc1900af7ad6 100644 --- a/configure.ac +++ b/configure.ac @@ -1128,6 +1128,35 @@ mips-sony-bsd|mips-sony-newsos4) AC_DEFINE([SYSLOG_R_SAFE_IN_SIGHAND], [1], [syslog_r function is safe to use in in a signal handler]) TEST_MALLOC_OPTIONS="SJRU" + AC_MSG_CHECKING([whether pledge(2) allows IP_TOS]) + need_pledge_inet="" + AC_RUN_IFELSE( + [AC_LANG_PROGRAM([[ +#include +#include +#include +#include +#include + ]], [[ +int s, one = 1; +if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) + err(1, "socket"); +if (pledge("stdio", NULL) == -1) + err(1, "pledge"); +if (setsockopt(s, IPPROTO_IP, IP_TOS, &one, sizeof(one)) == -1) + err(1, "setsockopt"); + ]])], + [ AC_MSG_RESULT([yes]) ], [ + AC_MSG_RESULT([no]) + need_pledge_inet=1 + ], + [ AC_MSG_WARN([cross compiling: cannot test]) ]) + if test -z "$need_pledge_inet" ; then + AC_DEFINE_UNQUOTED([PLEDGE_EXTRA_INET], []) + else + AC_DEFINE_UNQUOTED([PLEDGE_EXTRA_INET], ["inet "], + [need inet in pledge for setsockopt IP_TOS]) + fi ;; *-*-solaris*) if test "x$withval" != "xno" ; then From 6c84609e5f9ddd49e250d5cf190b2820dbeca178 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Mon, 18 Aug 2025 16:47:00 +1000 Subject: [PATCH 195/244] depend --- .depend | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/.depend b/.depend index 6961e34dd392..f569b603d450 100644 --- a/.depend +++ b/.depend @@ -8,11 +8,8 @@ atomicio.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-comp audit-bsm.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h audit-linux.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h audit.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h -auth-bsdauth-monitor.o: xmalloc.h sshkey.h sshbuf.h hostfile.h auth.h auth-pam.h includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h audit.h loginrec.h log.h ssherr.h auth-bsdauth.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h auth-krb5.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h ssh.h packet.h openbsd-compat/sys-queue.h dispatch.h log.h ssherr.h sshbuf.h sshkey.h misc.h servconf.h uidswap.h hostfile.h auth.h auth-pam.h audit.h loginrec.h -auth-log.o: authfile.h monitor_wrap.h channels.h -auth-log.o: xmalloc.h match.h groupaccess.h log.h ssherr.h sshbuf.h misc.h servconf.h openbsd-compat/sys-queue.h sshkey.h hostfile.h auth.h auth-pam.h includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h audit.h loginrec.h auth-options.h canohost.h packet.h dispatch.h auth-options.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/sys-queue.h xmalloc.h ssherr.h log.h sshbuf.h misc.h sshkey.h match.h ssh2.h auth-options.h auth-pam.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h auth-passwd.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h packet.h openbsd-compat/sys-queue.h dispatch.h sshbuf.h ssherr.h log.h misc.h servconf.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h auth-options.h @@ -21,25 +18,17 @@ auth-shadow.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-c auth-sia.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h auth.o: authfile.h monitor_wrap.h channels.h auth.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h match.h groupaccess.h log.h ssherr.h sshbuf.h misc.h servconf.h openbsd-compat/sys-queue.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h auth-options.h canohost.h uidswap.h packet.h dispatch.h -auth2-banner.o: atomicio.h xmalloc.h ssh2.h packet.h openbsd-compat/sys-queue.h dispatch.h log.h ssherr.h sshbuf.h misc.h servconf.h sshkey.h hostfile.h auth.h auth-pam.h includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h audit.h loginrec.h pathnames.h auth2-chall.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h ssh2.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h sshbuf.h packet.h openbsd-compat/sys-queue.h dispatch.h ssherr.h log.h misc.h servconf.h auth2-gss.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h -auth2-hostbased-monitor.o: canohost.h pathnames.h match.h -auth2-hostbased-monitor.o: xmalloc.h ssh2.h packet.h openbsd-compat/sys-queue.h dispatch.h kex.h mac.h crypto_api.h includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h sshbuf.h log.h ssherr.h misc.h servconf.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h uidswap.h auth2-hostbased.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h ssh2.h packet.h openbsd-compat/sys-queue.h dispatch.h kex.h mac.h crypto_api.h sshbuf.h log.h ssherr.h misc.h servconf.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h canohost.h auth2-hostbased.o: monitor_wrap.h pathnames.h match.h -auth2-kbdint-monitor.o: xmalloc.h packet.h openbsd-compat/sys-queue.h dispatch.h hostfile.h auth.h auth-pam.h includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h audit.h loginrec.h log.h ssherr.h misc.h servconf.h auth2-kbdint.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h packet.h openbsd-compat/sys-queue.h dispatch.h hostfile.h auth.h auth-pam.h audit.h loginrec.h log.h ssherr.h misc.h servconf.h auth2-methods.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h log.h ssherr.h misc.h servconf.h openbsd-compat/sys-queue.h xmalloc.h hostfile.h auth.h auth-pam.h audit.h loginrec.h auth2-none.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h atomicio.h xmalloc.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h packet.h openbsd-compat/sys-queue.h dispatch.h log.h ssherr.h misc.h servconf.h ssh2.h monitor_wrap.h auth2-passwd.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h packet.h openbsd-compat/sys-queue.h dispatch.h ssherr.h log.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h monitor_wrap.h misc.h servconf.h -auth2-pubkey-monitor.o: loginrec.h pathnames.h uidswap.h auth-options.h canohost.h monitor_wrap.h authfile.h match.h channels.h session.h sk-api.h -auth2-pubkey-monitor.o: xmalloc.h ssh.h ssh2.h packet.h openbsd-compat/sys-queue.h dispatch.h kex.h mac.h crypto_api.h includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h sshbuf.h log.h ssherr.h misc.h servconf.h compat.h sshkey.h hostfile.h auth.h auth-pam.h audit.h auth2-pubkey.o: audit.h loginrec.h pathnames.h uidswap.h auth-options.h canohost.h monitor_wrap.h authfile.h match.h channels.h session.h sk-api.h auth2-pubkey.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/glob.h xmalloc.h ssh.h ssh2.h packet.h openbsd-compat/sys-queue.h dispatch.h kex.h mac.h crypto_api.h sshbuf.h log.h ssherr.h misc.h servconf.h compat.h sshkey.h hostfile.h auth.h auth-pam.h auth2-pubkeyfile.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ssh.h log.h ssherr.h misc.h sshkey.h digest.h hostfile.h auth.h auth-pam.h audit.h loginrec.h auth-options.h authfile.h match.h -auth2-userauth.o: atomicio.h xmalloc.h ssh2.h packet.h openbsd-compat/sys-queue.h dispatch.h log.h ssherr.h sshbuf.h misc.h servconf.h sshkey.h hostfile.h auth.h auth-pam.h includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h audit.h loginrec.h pathnames.h monitor_wrap.h -auth2-userauth.o: digest.h auth2.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h atomicio.h xmalloc.h ssh2.h packet.h openbsd-compat/sys-queue.h dispatch.h log.h ssherr.h sshbuf.h misc.h servconf.h sshkey.h hostfile.h auth.h auth-pam.h audit.h loginrec.h pathnames.h monitor_wrap.h digest.h kex.h auth2.o: mac.h crypto_api.h authfd.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h ssh.h sshbuf.h sshkey.h authfd.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h log.h ssherr.h atomicio.h misc.h @@ -172,14 +161,8 @@ sshconnect2.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-c sshconnect2.o: sshconnect.h authfile.h dh.h authfd.h log.h ssherr.h misc.h readconf.h match.h canohost.h msg.h pathnames.h uidswap.h hostfile.h utf8.h ssh-sk.h sk-api.h sshd-auth.o: chacha.h poly1305.h cipher-aesctr.h rijndael.h digest.h sshkey.h kex.h mac.h crypto_api.h authfile.h pathnames.h atomicio.h canohost.h hostfile.h auth.h auth-pam.h audit.h loginrec.h authfd.h msg.h channels.h session.h monitor.h monitor_wrap.h auth-options.h version.h sk-api.h srclimit.h ssh-sandbox.h dh.h sshd-auth.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ./openbsd-compat/sys-tree.h openbsd-compat/sys-queue.h xmalloc.h ssh.h ssh2.h sshpty.h packet.h dispatch.h log.h ssherr.h sshbuf.h misc.h match.h servconf.h uidswap.h compat.h cipher.h cipher-chachapoly.h -sshd-monitor.o: openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h authfile.h pathnames.h atomicio.h canohost.h hostfile.h auth.h auth-pam.h audit.h loginrec.h authfd.h msg.h channels.h session.h monitor.h monitor_wrap.h auth-options.h version.h sk-api.h dh.h -sshd-monitor.o: xmalloc.h ssh.h ssh2.h sshpty.h packet.h openbsd-compat/sys-queue.h dispatch.h log.h ssherr.h sshbuf.h misc.h match.h servconf.h uidswap.h compat.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h digest.h sshkey.h kex.h mac.h crypto_api.h includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h sshd-session.o: chacha.h poly1305.h cipher-aesctr.h rijndael.h digest.h sshkey.h kex.h mac.h crypto_api.h authfile.h pathnames.h atomicio.h canohost.h hostfile.h auth.h auth-pam.h audit.h loginrec.h authfd.h msg.h channels.h session.h monitor.h monitor_wrap.h auth-options.h version.h sk-api.h srclimit.h dh.h sshd-session.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ./openbsd-compat/sys-tree.h openbsd-compat/sys-queue.h xmalloc.h ssh.h ssh2.h sshpty.h packet.h dispatch.h log.h ssherr.h sshbuf.h misc.h match.h servconf.h uidswap.h compat.h cipher.h cipher-chachapoly.h -sshd-unpriv-postauth.o: openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h authfile.h pathnames.h atomicio.h canohost.h hostfile.h auth.h auth-pam.h audit.h loginrec.h authfd.h msg.h channels.h session.h monitor.h monitor_wrap.h auth-options.h version.h sk-api.h dh.h -sshd-unpriv-postauth.o: xmalloc.h ssh.h ssh2.h sshpty.h packet.h openbsd-compat/sys-queue.h dispatch.h log.h ssherr.h sshbuf.h misc.h match.h servconf.h uidswap.h compat.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h digest.h sshkey.h kex.h mac.h crypto_api.h includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h -sshd-unpriv-preauth.o: openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h authfile.h pathnames.h atomicio.h canohost.h hostfile.h auth.h auth-pam.h audit.h loginrec.h authfd.h msg.h channels.h session.h monitor.h monitor_wrap.h auth-options.h version.h sk-api.h dh.h -sshd-unpriv-preauth.o: xmalloc.h ssh.h ssh2.h sshpty.h packet.h openbsd-compat/sys-queue.h dispatch.h log.h ssherr.h sshbuf.h misc.h match.h servconf.h uidswap.h compat.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h digest.h sshkey.h kex.h mac.h crypto_api.h includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h sshd.o: audit.h loginrec.h authfd.h msg.h version.h sk-api.h addr.h srclimit.h atomicio.h monitor_wrap.h sshd.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ./openbsd-compat/sys-tree.h openbsd-compat/sys-queue.h xmalloc.h ssh.h sshpty.h log.h ssherr.h sshbuf.h misc.h servconf.h compat.h digest.h sshkey.h authfile.h pathnames.h canohost.h hostfile.h auth.h auth-pam.h ssherr.o: ssherr.h From 5e9ca80fe65e407428dc46ed45804724d08b91b7 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Mon, 18 Aug 2025 16:47:23 +1000 Subject: [PATCH 196/244] Match version instead of groups in connect-bigconf The connect-bigconf makes a giant config file to test config passing between the sshd subprocesses. Previously it used a bunch of "Match group" lines to construct a large file. However checking group membership can be expensive (e.g. if a large groups database is present or if group lookup is remote via NSS). This could be slow enough to exceed LoginGraceTime. This switches it to "Match version" which is just a string compare and does just as well for making a giant nonsense config file. --- regress/connect-bigconf.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/regress/connect-bigconf.sh b/regress/connect-bigconf.sh index 56cf0ea649fc..ca2c11918dc0 100644 --- a/regress/connect-bigconf.sh +++ b/regress/connect-bigconf.sh @@ -4,7 +4,7 @@ tid="simple connect" for x in `jot 10000 1` ; do - echo "Match group NONEXIST" >> $OBJ/sshd_config + echo "Match version NONEXIST" >> $OBJ/sshd_config echo "ChrootDirectory /some/path/for/group/NONEXIST" >> $OBJ/sshd_config done #cat $OBJ/sshd_config From 3ef1a87d0a29eac94f32371af628e81eb2e2d817 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Mon, 18 Aug 2025 17:00:26 +1000 Subject: [PATCH 197/244] Fix pledge(2) special casing Unbreaks non-OpenBSD platforms --- configure.ac | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/configure.ac b/configure.ac index bc1900af7ad6..71766ba10e06 100644 --- a/configure.ac +++ b/configure.ac @@ -629,6 +629,9 @@ SOLARIS_PRIVS="no" # Default shared library extension SHLIBEXT=".so" +# See OpenBSD section in $host case below. +need_pledge_inet="" + # Check for some target-specific stuff case "$host" in *-*-aix*) @@ -1129,7 +1132,6 @@ mips-sony-bsd|mips-sony-newsos4) [syslog_r function is safe to use in in a signal handler]) TEST_MALLOC_OPTIONS="SJRU" AC_MSG_CHECKING([whether pledge(2) allows IP_TOS]) - need_pledge_inet="" AC_RUN_IFELSE( [AC_LANG_PROGRAM([[ #include @@ -1151,12 +1153,6 @@ if (setsockopt(s, IPPROTO_IP, IP_TOS, &one, sizeof(one)) == -1) need_pledge_inet=1 ], [ AC_MSG_WARN([cross compiling: cannot test]) ]) - if test -z "$need_pledge_inet" ; then - AC_DEFINE_UNQUOTED([PLEDGE_EXTRA_INET], []) - else - AC_DEFINE_UNQUOTED([PLEDGE_EXTRA_INET], ["inet "], - [need inet in pledge for setsockopt IP_TOS]) - fi ;; *-*-solaris*) if test "x$withval" != "xno" ; then @@ -1430,6 +1426,14 @@ AC_RUN_IFELSE([AC_LANG_PROGRAM([[ #include ]], [[ exit(0); ]])], [ AC_MSG_WARN([cross compiling: not checking compiler sanity]) ] ) +dnl Finish up special pledge(2) handling from above. +if test -z "$need_pledge_inet" ; then + AC_DEFINE_UNQUOTED([PLEDGE_EXTRA_INET], []) +else + AC_DEFINE_UNQUOTED([PLEDGE_EXTRA_INET], ["inet "], + [need inet in pledge for setsockopt IP_TOS]) +fi + dnl Checks for header files. # Checks for libraries. AC_CHECK_FUNC([setsockopt], , [AC_CHECK_LIB([socket], [setsockopt])]) From ceca966bde4ab38b2434876416da12fe16747459 Mon Sep 17 00:00:00 2001 From: "job@openbsd.org" Date: Mon, 18 Aug 2025 09:16:36 +0000 Subject: [PATCH 198/244] upstream: Delete unused accessor function OK dtucker@ OpenBSD-Commit-ID: 93b59ac088fb254e1189729ece5bb9656d6e810b --- packet.c | 9 +-------- packet.h | 3 +-- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/packet.c b/packet.c index 34bf91d75e52..6dfa7ac31a95 100644 --- a/packet.c +++ b/packet.c @@ -1,4 +1,4 @@ -/* $OpenBSD: packet.c,v 1.321 2025/08/18 04:50:35 djm Exp $ */ +/* $OpenBSD: packet.c,v 1.322 2025/08/18 09:16:36 job Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -2254,13 +2254,6 @@ ssh_packet_set_qos(struct ssh *ssh, int qos_interactive, int qos_other) apply_qos(ssh); } -/* Returns true if the current connection is interactive. */ -int -ssh_packet_is_interactive(struct ssh *ssh) -{ - return ssh->state->interactive_mode; -} - int ssh_packet_set_maxsize(struct ssh *ssh, u_int s) { diff --git a/packet.h b/packet.h index 6828476c7923..ade3c0f9df6e 100644 --- a/packet.h +++ b/packet.h @@ -1,4 +1,4 @@ -/* $OpenBSD: packet.h,v 1.100 2025/08/18 03:43:01 djm Exp $ */ +/* $OpenBSD: packet.h,v 1.101 2025/08/18 09:16:36 job Exp $ */ /* * Author: Tatu Ylonen @@ -112,7 +112,6 @@ void ssh_packet_set_protocol_flags(struct ssh *, u_int); u_int ssh_packet_get_protocol_flags(struct ssh *); void ssh_packet_set_tos(struct ssh *, int); void ssh_packet_set_interactive(struct ssh *, int); -int ssh_packet_is_interactive(struct ssh *); void ssh_packet_set_qos(struct ssh *, int, int); void ssh_packet_set_server(struct ssh *); void ssh_packet_set_authenticated(struct ssh *); From 908e9d55139bed19ed87d6fec749974eb42702c6 Mon Sep 17 00:00:00 2001 From: "caspar@openbsd.org" Date: Mon, 18 Aug 2025 18:39:33 +0000 Subject: [PATCH 199/244] upstream: ssh_config.5: say "post-quantum" instead of "post quantum safe", and rephrase the sentence to make it easier to read. Input djm@, input and OK deraadt@, OK dtucker@ OpenBSD-Commit-ID: c3ee4d1cafdcfc20cc0d2f086021efce4b19c075 --- ssh_config.5 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ssh_config.5 b/ssh_config.5 index 4cbe98631051..d24e92f73f0a 100644 --- a/ssh_config.5 +++ b/ssh_config.5 @@ -33,8 +33,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh_config.5,v 1.418 2025/08/11 10:55:38 djm Exp $ -.Dd $Mdocdate: August 11 2025 $ +.\" $OpenBSD: ssh_config.5,v 1.419 2025/08/18 18:39:33 caspar Exp $ +.Dd $Mdocdate: August 18 2025 $ .Dt SSH_CONFIG 5 .Os .Sh NAME @@ -2234,7 +2234,7 @@ controls whether the user is warned when the cryptographic algorithms negotiated for the connection are weak or otherwise recommended against. Warnings may be disabled by turning off a specific warning or by disabling all warnings. -Warnings that the connection is using a non-post quantum safe key exchange +Warnings about connections that don't use a post-quantum key exchange may be disabled using the .Cm no-pq-kex flag. From a9a3f025d76f06a6601e6e8d52b468ec467865d9 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Fri, 29 Aug 2025 03:50:38 +0000 Subject: [PATCH 200/244] upstream: remove experimental support for XMSS keys; ok deraadt markus OpenBSD-Commit-ID: 38eaf4df6189acad9e46eddf7cf32d7f6d07df35 --- .depend | 7 - Makefile.in | 12 +- PROTOCOL.agent | 13 +- authfd.c | 25 +- authfd.h | 8 +- authfile.c | 7 +- dns.c | 5 +- dns.h | 5 +- pathnames.h | 4 +- readconf.c | 3 +- servconf.c | 6 +- ssh-add.c | 73 +-- ssh-agent.c | 27 +- ssh-keygen.c | 14 +- ssh-keyscan.c | 10 +- ssh-keysign.c | 3 +- ssh-xmss.c | 389 --------------- ssh.c | 4 +- sshconnect.c | 5 +- sshd-auth.c | 5 +- sshd-session.c | 3 +- sshd.c | 3 +- sshkey-xmss.c | 1113 ------------------------------------------- sshkey-xmss.h | 56 --- sshkey.c | 153 +----- sshkey.h | 25 +- xmss_commons.c | 36 -- xmss_commons.h | 21 - xmss_fast.c | 1106 ------------------------------------------ xmss_fast.h | 111 ----- xmss_hash.c | 137 ------ xmss_hash.h | 22 - xmss_hash_address.c | 66 --- xmss_hash_address.h | 40 -- xmss_wots.c | 192 -------- xmss_wots.h | 64 --- 36 files changed, 53 insertions(+), 3720 deletions(-) delete mode 100644 ssh-xmss.c delete mode 100644 sshkey-xmss.c delete mode 100644 sshkey-xmss.h delete mode 100644 xmss_commons.c delete mode 100644 xmss_commons.h delete mode 100644 xmss_fast.c delete mode 100644 xmss_fast.h delete mode 100644 xmss_hash.c delete mode 100644 xmss_hash.h delete mode 100644 xmss_hash_address.c delete mode 100644 xmss_hash_address.h delete mode 100644 xmss_wots.c delete mode 100644 xmss_wots.h diff --git a/.depend b/.depend index f569b603d450..365db15a8cec 100644 --- a/.depend +++ b/.depend @@ -145,7 +145,6 @@ ssh-rsa.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compa ssh-sk-client.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h log.h ssherr.h sshbuf.h sshkey.h msg.h digest.h pathnames.h ssh-sk.h misc.h ssh-sk-helper.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h log.h ssherr.h sshkey.h authfd.h misc.h sshbuf.h msg.h uidswap.h ssh-sk.h ssh-pkcs11.h ssh-sk.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h -ssh-xmss.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ssh.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h openbsd-compat/openssl-compat.h openbsd-compat/sys-queue.h xmalloc.h ssh.h ssh2.h canohost.h compat.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h packet.h dispatch.h sshbuf.h channels.h ssh.o: sshkey.h authfd.h authfile.h pathnames.h clientloop.h log.h ssherr.h misc.h readconf.h sshconnect.h kex.h mac.h crypto_api.h sshpty.h match.h msg.h version.h myproposal.h utf8.h ssh_api.o: authfile.h dh.h misc.h version.h myproposal.h sshbuf.h openbsd-compat/openssl-compat.h @@ -166,7 +165,6 @@ sshd-session.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd- sshd.o: audit.h loginrec.h authfd.h msg.h version.h sk-api.h addr.h srclimit.h atomicio.h monitor_wrap.h sshd.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h ./openbsd-compat/sys-tree.h openbsd-compat/sys-queue.h xmalloc.h ssh.h sshpty.h log.h ssherr.h sshbuf.h misc.h servconf.h compat.h digest.h sshkey.h authfile.h pathnames.h canohost.h hostfile.h auth.h auth-pam.h ssherr.o: ssherr.h -sshkey-xmss.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h sshkey.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h crypto_api.h ssh2.h ssherr.h misc.h sshbuf.h cipher.h cipher-chachapoly.h chacha.h poly1305.h cipher-aesctr.h rijndael.h digest.h sshkey.h match.h ssh-sk.h ssh-pkcs11.h openbsd-compat/openssl-compat.h sshlogin.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h sshlogin.h ssherr.h loginrec.h log.h sshbuf.h misc.h servconf.h openbsd-compat/sys-queue.h sshpty.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h sshpty.h log.h ssherr.h misc.h @@ -178,8 +176,3 @@ umac.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h umac128.o: umac.c includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h umac.h misc.h rijndael.h utf8.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h utf8.h xmalloc.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h xmalloc.h log.h ssherr.h -xmss_commons.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h -xmss_fast.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h -xmss_hash.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h -xmss_hash_address.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h -xmss_wots.o: includes.h config.h defines.h platform.h openbsd-compat/openbsd-compat.h openbsd-compat/base64.h openbsd-compat/sigact.h openbsd-compat/readpassphrase.h openbsd-compat/vis.h openbsd-compat/getrrsetbyname.h openbsd-compat/sha1.h openbsd-compat/sha2.h openbsd-compat/md5.h openbsd-compat/blf.h openbsd-compat/fnmatch.h openbsd-compat/getopt.h openbsd-compat/bsd-signal.h openbsd-compat/bsd-misc.h openbsd-compat/bsd-setres_id.h openbsd-compat/bsd-statvfs.h openbsd-compat/bsd-waitpid.h openbsd-compat/bsd-poll.h openbsd-compat/fake-rfc2553.h openbsd-compat/bsd-cygwin_util.h openbsd-compat/port-aix.h openbsd-compat/port-irix.h openbsd-compat/port-linux.h openbsd-compat/port-solaris.h openbsd-compat/port-net.h openbsd-compat/port-uw.h openbsd-compat/bsd-nextstep.h entropy.h diff --git a/Makefile.in b/Makefile.in index 9e45d522088b..19a9e4dcf1df 100644 --- a/Makefile.in +++ b/Makefile.in @@ -76,15 +76,6 @@ MKDIR_P=@MKDIR_P@ TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) sshd-session$(EXEEXT) sshd-auth$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-sk-helper$(EXEEXT) $(SK_STANDALONE) -XMSS_OBJS=\ - ssh-xmss.o \ - sshkey-xmss.o \ - xmss_commons.o \ - xmss_fast.o \ - xmss_hash.o \ - xmss_hash_address.o \ - xmss_wots.o - LIBOPENSSH_OBJS=\ ssh_api.o \ ssherr.o \ @@ -94,8 +85,7 @@ LIBOPENSSH_OBJS=\ sshbuf-misc.o \ sshbuf-getput-crypto.o \ krl.o \ - bitmap.o \ - ${XMSS_OBJS} + bitmap.o LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ authfd.o authfile.o \ diff --git a/PROTOCOL.agent b/PROTOCOL.agent index b6e14262d0f6..2af749b30b7b 100644 --- a/PROTOCOL.agent +++ b/PROTOCOL.agent @@ -73,17 +73,6 @@ identities and, in particular, signature requests will check the key constraints against the session-bind@openssh.com bindings recorded for the agent connection over which they were received. -3. SSH_AGENT_CONSTRAIN_MAXSIGN key constraint - -This key constraint allows communication to an agent of the maximum -number of signatures that may be made with an XMSS key. The format of -the constraint is: - - byte SSH_AGENT_CONSTRAIN_MAXSIGN (0x03) - uint32 max_signatures - -This option is only valid for XMSS keys. - 3. associated-certs-v00@openssh.com key constraint extension The key constraint extension allows certificates to be associated @@ -115,4 +104,4 @@ A SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED will return SSH_AGENT_SUCCESS if any key (plain private or certificate) was successfully loaded, or SSH_AGENT_FAILURE if no key was loaded. -$OpenBSD: PROTOCOL.agent,v 1.24 2024/11/27 13:27:34 djm Exp $ +$OpenBSD: PROTOCOL.agent,v 1.25 2025/08/29 03:50:38 djm Exp $ diff --git a/authfd.c b/authfd.c index 66797880af84..2bbe646e304a 100644 --- a/authfd.c +++ b/authfd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: authfd.c,v 1.135 2025/05/06 05:40:56 djm Exp $ */ +/* $OpenBSD: authfd.c,v 1.136 2025/08/29 03:50:38 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -505,7 +505,7 @@ encode_dest_constraint(struct sshbuf *m, const struct dest_constraint *dc) static int encode_constraints(struct sshbuf *m, u_int life, u_int confirm, - u_int maxsign, const char *provider, + const char *provider, struct dest_constraint **dest_constraints, size_t ndest_constraints, int cert_only, struct sshkey **certs, size_t ncerts) { @@ -522,11 +522,6 @@ encode_constraints(struct sshbuf *m, u_int life, u_int confirm, if ((r = sshbuf_put_u8(m, SSH_AGENT_CONSTRAIN_CONFIRM)) != 0) goto out; } - if (maxsign != 0) { - if ((r = sshbuf_put_u8(m, SSH_AGENT_CONSTRAIN_MAXSIGN)) != 0 || - (r = sshbuf_put_u32(m, maxsign)) != 0) - goto out; - } if (provider != NULL) { if ((r = sshbuf_put_u8(m, SSH_AGENT_CONSTRAIN_EXTENSION)) != 0 || @@ -585,13 +580,12 @@ encode_constraints(struct sshbuf *m, u_int life, u_int confirm, */ int ssh_add_identity_constrained(int sock, struct sshkey *key, - const char *comment, u_int life, u_int confirm, u_int maxsign, + const char *comment, u_int life, u_int confirm, const char *provider, struct dest_constraint **dest_constraints, size_t ndest_constraints) { struct sshbuf *msg; - int r, constrained = (life || confirm || maxsign || - provider || dest_constraints); + int r, constrained = (life || confirm || provider || dest_constraints); u_char type; if ((msg = sshbuf_new()) == NULL) @@ -610,14 +604,11 @@ ssh_add_identity_constrained(int sock, struct sshkey *key, case KEY_ED25519_CERT: case KEY_ED25519_SK: case KEY_ED25519_SK_CERT: - case KEY_XMSS: - case KEY_XMSS_CERT: type = constrained ? SSH2_AGENTC_ADD_ID_CONSTRAINED : SSH2_AGENTC_ADD_IDENTITY; if ((r = sshbuf_put_u8(msg, type)) != 0 || - (r = sshkey_private_serialize_maxsign(key, msg, maxsign, - 0)) != 0 || + (r = sshkey_private_serialize(key, msg)) != 0 || (r = sshbuf_put_cstring(msg, comment)) != 0) goto out; break; @@ -626,8 +617,8 @@ ssh_add_identity_constrained(int sock, struct sshkey *key, goto out; } if (constrained && - (r = encode_constraints(msg, life, confirm, maxsign, - provider, dest_constraints, ndest_constraints, 0, NULL, 0)) != 0) + (r = encode_constraints(msg, life, confirm, provider, + dest_constraints, ndest_constraints, 0, NULL, 0)) != 0) goto out; if ((r = ssh_request_reply_decode(sock, msg)) != 0) goto out; @@ -703,7 +694,7 @@ ssh_update_card(int sock, int add, const char *reader_id, const char *pin, (r = sshbuf_put_cstring(msg, pin)) != 0) goto out; if (constrained && - (r = encode_constraints(msg, life, confirm, 0, NULL, + (r = encode_constraints(msg, life, confirm, NULL, dest_constraints, ndest_constraints, cert_only, certs, ncerts)) != 0) goto out; diff --git a/authfd.h b/authfd.h index c1e4b405ce29..958d480de6c7 100644 --- a/authfd.h +++ b/authfd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: authfd.h,v 1.52 2023/12/18 14:46:56 djm Exp $ */ +/* $OpenBSD: authfd.h,v 1.53 2025/08/29 03:50:38 djm Exp $ */ /* * Author: Tatu Ylonen @@ -48,9 +48,8 @@ int ssh_lock_agent(int sock, int lock, const char *password); int ssh_fetch_identitylist(int sock, struct ssh_identitylist **idlp); void ssh_free_identitylist(struct ssh_identitylist *idl); int ssh_add_identity_constrained(int sock, struct sshkey *key, - const char *comment, u_int life, u_int confirm, u_int maxsign, - const char *provider, struct dest_constraint **dest_constraints, - size_t ndest_constraints); + const char *comment, u_int life, u_int confirm, const char *provider, + struct dest_constraint **dest_constraints, size_t ndest_constraints); int ssh_agent_has_key(int sock, const struct sshkey *key); int ssh_remove_identity(int sock, const struct sshkey *key); int ssh_update_card(int sock, int add, const char *reader_id, @@ -106,7 +105,6 @@ int ssh_agent_bind_hostkey(int sock, const struct sshkey *key, #define SSH_AGENT_CONSTRAIN_LIFETIME 1 #define SSH_AGENT_CONSTRAIN_CONFIRM 2 -#define SSH_AGENT_CONSTRAIN_MAXSIGN 3 #define SSH_AGENT_CONSTRAIN_EXTENSION 255 /* extended failure messages */ diff --git a/authfile.c b/authfile.c index bf485baf237a..16e02d9d0580 100644 --- a/authfile.c +++ b/authfile.c @@ -1,4 +1,4 @@ -/* $OpenBSD: authfile.c,v 1.146 2025/05/06 05:40:56 djm Exp $ */ +/* $OpenBSD: authfile.c,v 1.147 2025/08/29 03:50:38 djm Exp $ */ /* * Copyright (c) 2000, 2013 Markus Friedl. All rights reserved. * @@ -131,8 +131,6 @@ sshkey_load_private_type(int type, const char *filename, const char *passphrase, goto out; r = sshkey_load_private_type_fd(fd, type, passphrase, keyp, commentp); - if (r == 0 && keyp && *keyp) - r = sshkey_set_filename(*keyp, filename); out: close(fd); return r; @@ -184,8 +182,6 @@ sshkey_load_pubkey_from_private(const char *filename, struct sshkey **pubkeyp) (r = sshkey_parse_pubkey_from_private_fileblob_type(buffer, KEY_UNSPEC, &pubkey)) != 0) goto out; - if ((r = sshkey_set_filename(pubkey, filename)) != 0) - goto out; /* success */ if (pubkeyp != NULL) { *pubkeyp = pubkey; @@ -331,7 +327,6 @@ sshkey_load_private_cert(int type, const char *filename, const char *passphrase, case KEY_ECDSA: #endif /* WITH_OPENSSL */ case KEY_ED25519: - case KEY_XMSS: case KEY_UNSPEC: break; default: diff --git a/dns.c b/dns.c index c01c7bebee18..e8693cee8313 100644 --- a/dns.c +++ b/dns.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dns.c,v 1.45 2025/05/06 05:40:56 djm Exp $ */ +/* $OpenBSD: dns.c,v 1.46 2025/08/29 03:50:38 djm Exp $ */ /* * Copyright (c) 2003 Wesley Griffin. All rights reserved. @@ -94,9 +94,6 @@ dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type, case KEY_ED25519: *algorithm = SSHFP_KEY_ED25519; break; - case KEY_XMSS: - *algorithm = SSHFP_KEY_XMSS; - break; default: *algorithm = SSHFP_KEY_RESERVED; /* 0 */ } diff --git a/dns.h b/dns.h index 864ab7d00ac7..ab2df061e987 100644 --- a/dns.h +++ b/dns.h @@ -1,4 +1,4 @@ -/* $OpenBSD: dns.h,v 1.20 2023/02/10 04:56:30 djm Exp $ */ +/* $OpenBSD: dns.h,v 1.21 2025/08/29 03:50:38 djm Exp $ */ /* * Copyright (c) 2003 Wesley Griffin. All rights reserved. @@ -33,8 +33,7 @@ enum sshfp_types { SSHFP_KEY_RSA = 1, SSHFP_KEY_DSA = 2, SSHFP_KEY_ECDSA = 3, - SSHFP_KEY_ED25519 = 4, - SSHFP_KEY_XMSS = 5 + SSHFP_KEY_ED25519 = 4 }; enum sshfp_hashes { diff --git a/pathnames.h b/pathnames.h index 9e76dbba841f..0dcc4955241f 100644 --- a/pathnames.h +++ b/pathnames.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pathnames.h,v 1.35 2025/05/06 05:40:56 djm Exp $ */ +/* $OpenBSD: pathnames.h,v 1.36 2025/08/29 03:50:38 djm Exp $ */ /* * Author: Tatu Ylonen @@ -38,7 +38,6 @@ #define _PATH_HOST_CONFIG_FILE SSHDIR "/ssh_config" #define _PATH_HOST_ECDSA_KEY_FILE SSHDIR "/ssh_host_ecdsa_key" #define _PATH_HOST_ED25519_KEY_FILE SSHDIR "/ssh_host_ed25519_key" -#define _PATH_HOST_XMSS_KEY_FILE SSHDIR "/ssh_host_xmss_key" #define _PATH_HOST_RSA_KEY_FILE SSHDIR "/ssh_host_rsa_key" #define _PATH_DH_MODULI SSHDIR "/moduli" @@ -89,7 +88,6 @@ #define _PATH_SSH_CLIENT_ID_ECDSA _PATH_SSH_USER_DIR "/id_ecdsa" #define _PATH_SSH_CLIENT_ID_RSA _PATH_SSH_USER_DIR "/id_rsa" #define _PATH_SSH_CLIENT_ID_ED25519 _PATH_SSH_USER_DIR "/id_ed25519" -#define _PATH_SSH_CLIENT_ID_XMSS _PATH_SSH_USER_DIR "/id_xmss" #define _PATH_SSH_CLIENT_ID_ECDSA_SK _PATH_SSH_USER_DIR "/id_ecdsa_sk" #define _PATH_SSH_CLIENT_ID_ED25519_SK _PATH_SSH_USER_DIR "/id_ed25519_sk" diff --git a/readconf.c b/readconf.c index c7701d8c2633..ba25ba881047 100644 --- a/readconf.c +++ b/readconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.c,v 1.405 2025/08/11 10:55:38 djm Exp $ */ +/* $OpenBSD: readconf.c,v 1.406 2025/08/29 03:50:38 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -2911,7 +2911,6 @@ fill_default_options(Options * options) _PATH_SSH_CLIENT_ID_ED25519, 0); add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_ED25519_SK, 0); - add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_XMSS, 0); } if (options->escape_char == -1) options->escape_char = '~'; diff --git a/servconf.c b/servconf.c index 92f924e6015c..3175f0df8fce 100644 --- a/servconf.c +++ b/servconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.c,v 1.430 2025/08/05 09:08:16 job Exp $ */ +/* $OpenBSD: servconf.c,v 1.431 2025/08/29 03:50:38 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -314,10 +314,6 @@ fill_default_server_options(ServerOptions *options) #endif servconf_add_hostkey("[default]", 0, options, _PATH_HOST_ED25519_KEY_FILE, 0); -#ifdef WITH_XMSS - servconf_add_hostkey("[default]", 0, options, - _PATH_HOST_XMSS_KEY_FILE, 0); -#endif /* WITH_XMSS */ } /* No certificates by default */ if (options->num_ports == 0) diff --git a/ssh-add.c b/ssh-add.c index 18897a0a834d..2e41bc26a363 100644 --- a/ssh-add.c +++ b/ssh-add.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-add.c,v 1.174 2025/05/06 05:40:56 djm Exp $ */ +/* $OpenBSD: ssh-add.c,v 1.175 2025/08/29 03:50:38 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -84,7 +84,6 @@ static char *default_files[] = { #endif /* WITH_OPENSSL */ _PATH_SSH_CLIENT_ID_ED25519, _PATH_SSH_CLIENT_ID_ED25519_SK, - _PATH_SSH_CLIENT_ID_XMSS, NULL }; @@ -96,10 +95,6 @@ static int lifetime = 0; /* User has to confirm key use */ static int confirm = 0; -/* Maximum number of signatures (XMSS) */ -static u_int maxsign = 0; -static u_int minleft = 0; - /* we keep a cache of one passphrase */ static char *pass = NULL; static void @@ -249,10 +244,7 @@ add_file(int agent_fd, const char *filename, int key_only, int cert_only, char *comment = NULL; char msg[1024], *certpath = NULL; int r, fd, ret = -1; - size_t i; - u_int32_t left; struct sshbuf *keyblob; - struct ssh_identitylist *idlist; if (strcmp(filename, "-") == 0) { fd = STDIN_FILENO; @@ -328,38 +320,6 @@ add_file(int agent_fd, const char *filename, int key_only, int cert_only, comment = xstrdup(filename); sshbuf_free(keyblob); - /* For XMSS */ - if ((r = sshkey_set_filename(private, filename)) != 0) { - fprintf(stderr, "Could not add filename to private key: %s (%s)\n", - filename, comment); - goto out; - } - if (maxsign && minleft && - (r = ssh_fetch_identitylist(agent_fd, &idlist)) == 0) { - for (i = 0; i < idlist->nkeys; i++) { - if (!sshkey_equal_public(idlist->keys[i], private)) - continue; - left = sshkey_signatures_left(idlist->keys[i]); - if (left < minleft) { - fprintf(stderr, - "Only %d signatures left.\n", left); - break; - } - fprintf(stderr, "Skipping update: "); - if (left == minleft) { - fprintf(stderr, - "required signatures left (%d).\n", left); - } else { - fprintf(stderr, - "more signatures left (%d) than" - " required (%d).\n", left, minleft); - } - ssh_free_identitylist(idlist); - goto out; - } - ssh_free_identitylist(idlist); - } - if (sshkey_is_sk(private)) { if (skprovider == NULL) { fprintf(stderr, "Cannot load FIDO key %s " @@ -373,7 +333,7 @@ add_file(int agent_fd, const char *filename, int key_only, int cert_only, if (!cert_only && (r = ssh_add_identity_constrained(agent_fd, private, comment, - lifetime, confirm, maxsign, skprovider, + lifetime, confirm, skprovider, dest_constraints, ndest_constraints)) == 0) { ret = 0; if (!qflag) { @@ -427,7 +387,7 @@ add_file(int agent_fd, const char *filename, int key_only, int cert_only, sshkey_free(cert); if ((r = ssh_add_identity_constrained(agent_fd, private, comment, - lifetime, confirm, maxsign, skprovider, + lifetime, confirm, skprovider, dest_constraints, ndest_constraints)) != 0) { error_r(r, "Certificate %s (%s) add failed", certpath, private->cert->key_id); @@ -531,7 +491,6 @@ list_identities(int agent_fd, int do_fp) char *fp; int r; struct ssh_identitylist *idlist; - u_int32_t left; size_t i; if ((r = ssh_fetch_identitylist(agent_fd, &idlist)) != 0) { @@ -556,12 +515,7 @@ list_identities(int agent_fd, int do_fp) ssh_err(r)); continue; } - fprintf(stdout, " %s", idlist->comments[i]); - left = sshkey_signatures_left(idlist->keys[i]); - if (left > 0) - fprintf(stdout, - " [signatures left %d]", left); - fprintf(stdout, "\n"); + fprintf(stdout, " %s\n", idlist->comments[i]); } } ssh_free_identitylist(idlist); @@ -620,7 +574,7 @@ load_resident_keys(int agent_fd, const char *skprovider, int qflag, fingerprint_hash, SSH_FP_DEFAULT)) == NULL) fatal_f("sshkey_fingerprint failed"); if ((r = ssh_add_identity_constrained(agent_fd, key, "", - lifetime, confirm, maxsign, skprovider, + lifetime, confirm, skprovider, dest_constraints, ndest_constraints)) != 0) { error("Unable to add key %s %s", sshkey_type(key), fp); @@ -791,9 +745,6 @@ usage(void) fprintf(stderr, "usage: ssh-add [-CcDdKkLlqvXx] [-E fingerprint_hash] [-H hostkey_file]\n" " [-h destination_constraint] [-S provider] [-t life]\n" -#ifdef WITH_XMSS -" [-M maxsign] [-m minleft]\n" -#endif " [file ...]\n" " ssh-add -s pkcs11 [-Cv] [certificate ...]\n" " ssh-add -e pkcs11\n" @@ -887,20 +838,8 @@ main(int argc, char **argv) confirm = 1; break; case 'm': - minleft = (u_int)strtonum(optarg, 1, UINT_MAX, NULL); - if (minleft == 0) { - usage(); - ret = 1; - goto done; - } - break; case 'M': - maxsign = (u_int)strtonum(optarg, 1, UINT_MAX, NULL); - if (maxsign == 0) { - usage(); - ret = 1; - goto done; - } + /* deprecated */ break; case 'd': deleting = 1; diff --git a/ssh-agent.c b/ssh-agent.c index d82b351d04b6..2c7b94be55f2 100644 --- a/ssh-agent.c +++ b/ssh-agent.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-agent.c,v 1.312 2025/05/05 02:48:06 djm Exp $ */ +/* $OpenBSD: ssh-agent.c,v 1.313 2025/08/29 03:50:38 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -644,8 +644,7 @@ process_request_identities(SocketEntry *e) /* identity not visible, don't include in response */ if (identity_permitted(id, e, NULL, NULL, NULL) != 0) continue; - if ((r = sshkey_puts_opts(id->key, keys, - SSHKEY_SERIALIZE_INFO)) != 0 || + if ((r = sshkey_puts(id->key, keys)) != 0 || (r = sshbuf_put_cstring(keys, id->comment)) != 0) { error_fr(r, "compose key/comment"); continue; @@ -1292,7 +1291,7 @@ parse_key_constraints(struct sshbuf *m, struct sshkey *k, time_t *deathp, { u_char ctype; int r; - u_int seconds, maxsign = 0; + u_int seconds; while (sshbuf_len(m)) { if ((r = sshbuf_get_u8(m, &ctype)) != 0) { @@ -1321,26 +1320,6 @@ parse_key_constraints(struct sshbuf *m, struct sshkey *k, time_t *deathp, } *confirmp = 1; break; - case SSH_AGENT_CONSTRAIN_MAXSIGN: - if (k == NULL) { - error_f("maxsign not valid here"); - r = SSH_ERR_INVALID_FORMAT; - goto out; - } - if (maxsign != 0) { - error_f("maxsign already set"); - r = SSH_ERR_INVALID_FORMAT; - goto out; - } - if ((r = sshbuf_get_u32(m, &maxsign)) != 0) { - error_fr(r, "parse maxsign constraint"); - goto out; - } - if ((r = sshkey_enable_maxsign(k, maxsign)) != 0) { - error_fr(r, "enable maxsign"); - goto out; - } - break; case SSH_AGENT_CONSTRAIN_EXTENSION: if ((r = parse_key_constraint_extension(m, sk_providerp, dcsp, ndcsp, diff --git a/ssh-keygen.c b/ssh-keygen.c index 867fbd1ca014..6e62886378c7 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keygen.c,v 1.481 2025/05/24 03:37:40 dtucker Exp $ */ +/* $OpenBSD: ssh-keygen.c,v 1.482 2025/08/29 03:50:38 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1994 Tatu Ylonen , Espoo, Finland @@ -273,10 +273,6 @@ ask_filename(struct passwd *pw, const char *prompt) case KEY_ED25519_SK_CERT: name = _PATH_SSH_CLIENT_ID_ED25519_SK; break; - case KEY_XMSS: - case KEY_XMSS_CERT: - name = _PATH_SSH_CLIENT_ID_XMSS; - break; default: fatal("bad key type"); } @@ -1024,9 +1020,6 @@ do_gen_all_hostkeys(struct passwd *pw) #endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ { "ed25519", "ED25519",_PATH_HOST_ED25519_KEY_FILE }, -#ifdef WITH_XMSS - { "xmss", "XMSS",_PATH_HOST_XMSS_KEY_FILE }, -#endif /* WITH_XMSS */ { NULL, NULL, NULL } }; @@ -1521,7 +1514,7 @@ do_change_comment(struct passwd *pw, const char *identity_comment) } } - if (private->type != KEY_ED25519 && private->type != KEY_XMSS && + if (private->type != KEY_ED25519 && private_key_format != SSHKEY_PRIVATE_OPENSSH) { error("Comments are only supported for keys stored in " "the new format (-o)."); @@ -3727,9 +3720,6 @@ main(int argc, char **argv) n += do_print_resource_record(pw, _PATH_HOST_ED25519_KEY_FILE, rr_hostname, print_generic, opts, nopts); - n += do_print_resource_record(pw, - _PATH_HOST_XMSS_KEY_FILE, rr_hostname, - print_generic, opts, nopts); if (n == 0) fatal("no keys found."); exit(0); diff --git a/ssh-keyscan.c b/ssh-keyscan.c index 7b1e0ca86500..914de1244dd4 100644 --- a/ssh-keyscan.c +++ b/ssh-keyscan.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keyscan.c,v 1.166 2025/05/06 05:40:56 djm Exp $ */ +/* $OpenBSD: ssh-keyscan.c,v 1.167 2025/08/29 03:50:38 djm Exp $ */ /* * Copyright 1995, 1996 by David Mazieres . * @@ -65,7 +65,6 @@ int ssh_port = SSH_DEFAULT_PORT; #define KT_RSA (1) #define KT_ECDSA (1<<1) #define KT_ED25519 (1<<2) -#define KT_XMSS (1<<3) #define KT_ECDSA_SK (1<<4) #define KT_ED25519_SK (1<<5) @@ -252,10 +251,6 @@ keygrab_ssh2(con *c) myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ? "ssh-ed25519-cert-v01@openssh.com" : "ssh-ed25519"; break; - case KT_XMSS: - myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ? - "ssh-xmss-cert-v01@openssh.com" : "ssh-xmss@openssh.com"; - break; case KT_ECDSA: myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ? "ecdsa-sha2-nistp256-cert-v01@openssh.com," @@ -747,9 +742,6 @@ main(int argc, char **argv) case KEY_ED25519: get_keytypes |= KT_ED25519; break; - case KEY_XMSS: - get_keytypes |= KT_XMSS; - break; case KEY_ED25519_SK: get_keytypes |= KT_ED25519_SK; break; diff --git a/ssh-keysign.c b/ssh-keysign.c index 4d65dd1d33a0..2410c6cd1b7b 100644 --- a/ssh-keysign.c +++ b/ssh-keysign.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keysign.c,v 1.76 2025/05/06 05:40:56 djm Exp $ */ +/* $OpenBSD: ssh-keysign.c,v 1.77 2025/08/29 03:50:38 djm Exp $ */ /* * Copyright (c) 2002 Markus Friedl. All rights reserved. * @@ -202,7 +202,6 @@ main(int argc, char **argv) /* XXX This really needs to read sshd_config for the paths */ key_fd[i++] = open(_PATH_HOST_ECDSA_KEY_FILE, O_RDONLY); key_fd[i++] = open(_PATH_HOST_ED25519_KEY_FILE, O_RDONLY); - key_fd[i++] = open(_PATH_HOST_XMSS_KEY_FILE, O_RDONLY); key_fd[i++] = open(_PATH_HOST_RSA_KEY_FILE, O_RDONLY); if ((pw = getpwuid(getuid())) == NULL) diff --git a/ssh-xmss.c b/ssh-xmss.c deleted file mode 100644 index b6d0561b1411..000000000000 --- a/ssh-xmss.c +++ /dev/null @@ -1,389 +0,0 @@ -/* $OpenBSD: ssh-xmss.c,v 1.14 2022/10/28 00:44:44 djm Exp $*/ -/* - * Copyright (c) 2017 Stefan-Lukas Gazdag. - * Copyright (c) 2017 Markus Friedl. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#include "includes.h" -#ifdef WITH_XMSS - -#define SSHKEY_INTERNAL -#include -#include - -#include -#include -#include -#ifdef HAVE_STDINT_H -# include -#endif -#include - -#include "log.h" -#include "sshbuf.h" -#include "sshkey.h" -#include "sshkey-xmss.h" -#include "ssherr.h" -#include "ssh.h" - -#include "xmss_fast.h" - -static void -ssh_xmss_cleanup(struct sshkey *k) -{ - freezero(k->xmss_pk, sshkey_xmss_pklen(k)); - freezero(k->xmss_sk, sshkey_xmss_sklen(k)); - sshkey_xmss_free_state(k); - free(k->xmss_name); - free(k->xmss_filename); - k->xmss_pk = NULL; - k->xmss_sk = NULL; - k->xmss_name = NULL; - k->xmss_filename = NULL; -} - -static int -ssh_xmss_equal(const struct sshkey *a, const struct sshkey *b) -{ - if (a->xmss_pk == NULL || b->xmss_pk == NULL) - return 0; - if (sshkey_xmss_pklen(a) != sshkey_xmss_pklen(b)) - return 0; - if (memcmp(a->xmss_pk, b->xmss_pk, sshkey_xmss_pklen(a)) != 0) - return 0; - return 1; -} - -static int -ssh_xmss_serialize_public(const struct sshkey *key, struct sshbuf *b, - enum sshkey_serialize_rep opts) -{ - int r; - - if (key->xmss_name == NULL || key->xmss_pk == NULL || - sshkey_xmss_pklen(key) == 0) - return SSH_ERR_INVALID_ARGUMENT; - if ((r = sshbuf_put_cstring(b, key->xmss_name)) != 0 || - (r = sshbuf_put_string(b, key->xmss_pk, - sshkey_xmss_pklen(key))) != 0 || - (r = sshkey_xmss_serialize_pk_info(key, b, opts)) != 0) - return r; - - return 0; -} - -static int -ssh_xmss_serialize_private(const struct sshkey *key, struct sshbuf *b, - enum sshkey_serialize_rep opts) -{ - int r; - - if (key->xmss_name == NULL) - return SSH_ERR_INVALID_ARGUMENT; - /* Note: can't reuse ssh_xmss_serialize_public because of sk order */ - if ((r = sshbuf_put_cstring(b, key->xmss_name)) != 0 || - (r = sshbuf_put_string(b, key->xmss_pk, - sshkey_xmss_pklen(key))) != 0 || - (r = sshbuf_put_string(b, key->xmss_sk, - sshkey_xmss_sklen(key))) != 0 || - (r = sshkey_xmss_serialize_state_opt(key, b, opts)) != 0) - return r; - - return 0; -} - -static int -ssh_xmss_copy_public(const struct sshkey *from, struct sshkey *to) -{ - int r = SSH_ERR_INTERNAL_ERROR; - u_int32_t left; - size_t pklen; - - if ((r = sshkey_xmss_init(to, from->xmss_name)) != 0) - return r; - if (from->xmss_pk == NULL) - return 0; /* XXX SSH_ERR_INTERNAL_ERROR ? */ - - if ((pklen = sshkey_xmss_pklen(from)) == 0 || - sshkey_xmss_pklen(to) != pklen) - return SSH_ERR_INTERNAL_ERROR; - if ((to->xmss_pk = malloc(pklen)) == NULL) - return SSH_ERR_ALLOC_FAIL; - memcpy(to->xmss_pk, from->xmss_pk, pklen); - /* simulate number of signatures left on pubkey */ - left = sshkey_xmss_signatures_left(from); - if (left) - sshkey_xmss_enable_maxsign(to, left); - return 0; -} - -static int -ssh_xmss_deserialize_public(const char *ktype, struct sshbuf *b, - struct sshkey *key) -{ - size_t len = 0; - char *xmss_name = NULL; - u_char *pk = NULL; - int ret = SSH_ERR_INTERNAL_ERROR; - - if ((ret = sshbuf_get_cstring(b, &xmss_name, NULL)) != 0) - goto out; - if ((ret = sshkey_xmss_init(key, xmss_name)) != 0) - goto out; - if ((ret = sshbuf_get_string(b, &pk, &len)) != 0) - goto out; - if (len == 0 || len != sshkey_xmss_pklen(key)) { - ret = SSH_ERR_INVALID_FORMAT; - goto out; - } - key->xmss_pk = pk; - pk = NULL; - if (!sshkey_is_cert(key) && - (ret = sshkey_xmss_deserialize_pk_info(key, b)) != 0) - goto out; - /* success */ - ret = 0; - out: - free(xmss_name); - freezero(pk, len); - return ret; -} - -static int -ssh_xmss_deserialize_private(const char *ktype, struct sshbuf *b, - struct sshkey *key) -{ - int r; - char *xmss_name = NULL; - size_t pklen = 0, sklen = 0; - u_char *xmss_pk = NULL, *xmss_sk = NULL; - - /* Note: can't reuse ssh_xmss_deserialize_public because of sk order */ - if ((r = sshbuf_get_cstring(b, &xmss_name, NULL)) != 0 || - (r = sshbuf_get_string(b, &xmss_pk, &pklen)) != 0 || - (r = sshbuf_get_string(b, &xmss_sk, &sklen)) != 0) - goto out; - if (!sshkey_is_cert(key) && - (r = sshkey_xmss_init(key, xmss_name)) != 0) - goto out; - if (pklen != sshkey_xmss_pklen(key) || - sklen != sshkey_xmss_sklen(key)) { - r = SSH_ERR_INVALID_FORMAT; - goto out; - } - key->xmss_pk = xmss_pk; - key->xmss_sk = xmss_sk; - xmss_pk = xmss_sk = NULL; - /* optional internal state */ - if ((r = sshkey_xmss_deserialize_state_opt(key, b)) != 0) - goto out; - /* success */ - r = 0; - out: - free(xmss_name); - freezero(xmss_pk, pklen); - freezero(xmss_sk, sklen); - return r; -} - -static int -ssh_xmss_sign(struct sshkey *key, - u_char **sigp, size_t *lenp, - const u_char *data, size_t datalen, - const char *alg, const char *sk_provider, const char *sk_pin, u_int compat) -{ - u_char *sig = NULL; - size_t slen = 0, len = 0, required_siglen; - unsigned long long smlen; - int r, ret; - struct sshbuf *b = NULL; - - if (lenp != NULL) - *lenp = 0; - if (sigp != NULL) - *sigp = NULL; - - if (key == NULL || - sshkey_type_plain(key->type) != KEY_XMSS || - key->xmss_sk == NULL || - sshkey_xmss_params(key) == NULL) - return SSH_ERR_INVALID_ARGUMENT; - if ((r = sshkey_xmss_siglen(key, &required_siglen)) != 0) - return r; - if (datalen >= INT_MAX - required_siglen) - return SSH_ERR_INVALID_ARGUMENT; - smlen = slen = datalen + required_siglen; - if ((sig = malloc(slen)) == NULL) - return SSH_ERR_ALLOC_FAIL; - if ((r = sshkey_xmss_get_state(key, 1)) != 0) - goto out; - if ((ret = xmss_sign(key->xmss_sk, sshkey_xmss_bds_state(key), sig, &smlen, - data, datalen, sshkey_xmss_params(key))) != 0 || smlen <= datalen) { - r = SSH_ERR_INVALID_ARGUMENT; /* XXX better error? */ - goto out; - } - /* encode signature */ - if ((b = sshbuf_new()) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto out; - } - if ((r = sshbuf_put_cstring(b, "ssh-xmss@openssh.com")) != 0 || - (r = sshbuf_put_string(b, sig, smlen - datalen)) != 0) - goto out; - len = sshbuf_len(b); - if (sigp != NULL) { - if ((*sigp = malloc(len)) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto out; - } - memcpy(*sigp, sshbuf_ptr(b), len); - } - if (lenp != NULL) - *lenp = len; - /* success */ - r = 0; - out: - if ((ret = sshkey_xmss_update_state(key, 1)) != 0) { - /* discard signature since we cannot update the state */ - if (r == 0 && sigp != NULL && *sigp != NULL) { - explicit_bzero(*sigp, len); - free(*sigp); - } - if (sigp != NULL) - *sigp = NULL; - if (lenp != NULL) - *lenp = 0; - r = ret; - } - sshbuf_free(b); - if (sig != NULL) - freezero(sig, slen); - - return r; -} - -static int -ssh_xmss_verify(const struct sshkey *key, - const u_char *sig, size_t siglen, - const u_char *data, size_t dlen, const char *alg, u_int compat, - struct sshkey_sig_details **detailsp) -{ - struct sshbuf *b = NULL; - char *ktype = NULL; - const u_char *sigblob; - u_char *sm = NULL, *m = NULL; - size_t len, required_siglen; - unsigned long long smlen = 0, mlen = 0; - int r, ret; - - if (key == NULL || - sshkey_type_plain(key->type) != KEY_XMSS || - key->xmss_pk == NULL || - sshkey_xmss_params(key) == NULL || - sig == NULL || siglen == 0) - return SSH_ERR_INVALID_ARGUMENT; - if ((r = sshkey_xmss_siglen(key, &required_siglen)) != 0) - return r; - if (dlen >= INT_MAX - required_siglen) - return SSH_ERR_INVALID_ARGUMENT; - - if ((b = sshbuf_from(sig, siglen)) == NULL) - return SSH_ERR_ALLOC_FAIL; - if ((r = sshbuf_get_cstring(b, &ktype, NULL)) != 0 || - (r = sshbuf_get_string_direct(b, &sigblob, &len)) != 0) - goto out; - if (strcmp("ssh-xmss@openssh.com", ktype) != 0) { - r = SSH_ERR_KEY_TYPE_MISMATCH; - goto out; - } - if (sshbuf_len(b) != 0) { - r = SSH_ERR_UNEXPECTED_TRAILING_DATA; - goto out; - } - if (len != required_siglen) { - r = SSH_ERR_INVALID_FORMAT; - goto out; - } - if (dlen >= SIZE_MAX - len) { - r = SSH_ERR_INVALID_ARGUMENT; - goto out; - } - smlen = len + dlen; - mlen = smlen; - if ((sm = malloc(smlen)) == NULL || (m = malloc(mlen)) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto out; - } - memcpy(sm, sigblob, len); - memcpy(sm+len, data, dlen); - if ((ret = xmss_sign_open(m, &mlen, sm, smlen, - key->xmss_pk, sshkey_xmss_params(key))) != 0) { - debug2_f("xmss_sign_open failed: %d", ret); - } - if (ret != 0 || mlen != dlen) { - r = SSH_ERR_SIGNATURE_INVALID; - goto out; - } - /* XXX compare 'm' and 'data' ? */ - /* success */ - r = 0; - out: - if (sm != NULL) - freezero(sm, smlen); - if (m != NULL) - freezero(m, smlen); - sshbuf_free(b); - free(ktype); - return r; -} - -static const struct sshkey_impl_funcs sshkey_xmss_funcs = { - /* .size = */ NULL, - /* .alloc = */ NULL, - /* .cleanup = */ ssh_xmss_cleanup, - /* .equal = */ ssh_xmss_equal, - /* .ssh_serialize_public = */ ssh_xmss_serialize_public, - /* .ssh_deserialize_public = */ ssh_xmss_deserialize_public, - /* .ssh_serialize_private = */ ssh_xmss_serialize_private, - /* .ssh_deserialize_private = */ ssh_xmss_deserialize_private, - /* .generate = */ sshkey_xmss_generate_private_key, - /* .copy_public = */ ssh_xmss_copy_public, - /* .sign = */ ssh_xmss_sign, - /* .verify = */ ssh_xmss_verify, -}; - -const struct sshkey_impl sshkey_xmss_impl = { - /* .name = */ "ssh-xmss@openssh.com", - /* .shortname = */ "XMSS", - /* .sigalg = */ NULL, - /* .type = */ KEY_XMSS, - /* .nid = */ 0, - /* .cert = */ 0, - /* .sigonly = */ 0, - /* .keybits = */ 256, - /* .funcs = */ &sshkey_xmss_funcs, -}; - -const struct sshkey_impl sshkey_xmss_cert_impl = { - /* .name = */ "ssh-xmss-cert-v01@openssh.com", - /* .shortname = */ "XMSS-CERT", - /* .sigalg = */ NULL, - /* .type = */ KEY_XMSS_CERT, - /* .nid = */ 0, - /* .cert = */ 1, - /* .sigonly = */ 0, - /* .keybits = */ 256, - /* .funcs = */ &sshkey_xmss_funcs, -}; -#endif /* WITH_XMSS */ diff --git a/ssh.c b/ssh.c index 58c254b93d86..1eaa5986ed47 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.615 2025/08/18 03:43:01 djm Exp $ */ +/* $OpenBSD: ssh.c,v 1.616 2025/08/29 03:50:38 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1762,8 +1762,6 @@ main(int ac, char **av) L_PUBKEY(_PATH_HOST_ECDSA_KEY_FILE, 4); L_PUBKEY(_PATH_HOST_ED25519_KEY_FILE, 5); L_PUBKEY(_PATH_HOST_RSA_KEY_FILE, 6); - L_CERT(_PATH_HOST_XMSS_KEY_FILE, 8); - L_PUBKEY(_PATH_HOST_XMSS_KEY_FILE, 9); if (loaded == 0) debug("HostbasedAuthentication enabled but no " "local public host keys could be loaded."); diff --git a/sshconnect.c b/sshconnect.c index d2c8cf0bd8f2..8ddc531da571 100644 --- a/sshconnect.c +++ b/sshconnect.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshconnect.c,v 1.373 2025/08/12 11:09:48 sthen Exp $ */ +/* $OpenBSD: sshconnect.c,v 1.374 2025/08/29 03:50:38 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1640,7 +1640,6 @@ show_other_keys(struct hostkeys *hostkeys, struct sshkey *key) KEY_RSA, KEY_ECDSA, KEY_ED25519, - KEY_XMSS, -1 }; int i, ret = 0; @@ -1763,7 +1762,7 @@ maybe_add_key_to_agent(const char *authfile, struct sshkey *private, if ((r = ssh_add_identity_constrained(auth_sock, private, comment == NULL ? authfile : comment, options.add_keys_to_agent_lifespan, - (options.add_keys_to_agent == 3), 0, skprovider, NULL, 0)) == 0) + (options.add_keys_to_agent == 3), skprovider, NULL, 0)) == 0) debug("identity added to agent: %s", authfile); else debug("could not add identity to agent: %s (%d)", authfile, r); diff --git a/sshd-auth.c b/sshd-auth.c index 6bb4aff0d726..95520608c433 100644 --- a/sshd-auth.c +++ b/sshd-auth.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd-auth.c,v 1.7 2025/08/18 04:38:21 djm Exp $ */ +/* $OpenBSD: sshd-auth.c,v 1.8 2025/08/29 03:50:38 djm Exp $ */ /* * SSH2 implementation: * Privilege Separation: @@ -254,7 +254,6 @@ list_hostkey_types(void) case KEY_ED25519: case KEY_ECDSA_SK: case KEY_ED25519_SK: - case KEY_XMSS: append_hostkey_type(b, sshkey_ssh_name(key)); break; } @@ -274,7 +273,6 @@ list_hostkey_types(void) case KEY_ED25519_CERT: case KEY_ECDSA_SK_CERT: case KEY_ED25519_SK_CERT: - case KEY_XMSS_CERT: append_hostkey_type(b, sshkey_ssh_name(key)); break; } @@ -299,7 +297,6 @@ get_hostkey_public_by_type(int type, int nid, struct ssh *ssh) case KEY_ED25519_CERT: case KEY_ECDSA_SK_CERT: case KEY_ED25519_SK_CERT: - case KEY_XMSS_CERT: key = host_certificates[i]; break; default: diff --git a/sshd-session.c b/sshd-session.c index 4aad8b6fe140..5c007563061c 100644 --- a/sshd-session.c +++ b/sshd-session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd-session.c,v 1.14 2025/08/18 03:43:01 djm Exp $ */ +/* $OpenBSD: sshd-session.c,v 1.15 2025/08/29 03:50:38 djm Exp $ */ /* * SSH2 implementation: * Privilege Separation: @@ -489,7 +489,6 @@ get_hostkey_by_type(int type, int nid, int need_private, struct ssh *ssh) case KEY_ED25519_CERT: case KEY_ECDSA_SK_CERT: case KEY_ED25519_SK_CERT: - case KEY_XMSS_CERT: key = sensitive_data.host_certificates[i]; break; default: diff --git a/sshd.c b/sshd.c index 6960193816f5..f77a4a2ec141 100644 --- a/sshd.c +++ b/sshd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd.c,v 1.621 2025/07/04 09:51:01 djm Exp $ */ +/* $OpenBSD: sshd.c,v 1.622 2025/08/29 03:50:38 djm Exp $ */ /* * Copyright (c) 2000, 2001, 2002 Markus Friedl. All rights reserved. * Copyright (c) 2002 Niels Provos. All rights reserved. @@ -1672,7 +1672,6 @@ main(int ac, char **av) case KEY_ED25519: case KEY_ECDSA_SK: case KEY_ED25519_SK: - case KEY_XMSS: if (have_agent || key != NULL) sensitive_data.have_ssh2_key = 1; break; diff --git a/sshkey-xmss.c b/sshkey-xmss.c deleted file mode 100644 index 818aba9059df..000000000000 --- a/sshkey-xmss.c +++ /dev/null @@ -1,1113 +0,0 @@ -/* $OpenBSD: sshkey-xmss.c,v 1.12 2022/10/28 00:39:29 djm Exp $ */ -/* - * Copyright (c) 2017 Markus Friedl. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "includes.h" -#ifdef WITH_XMSS - -#include -#include - -#include -#include -#include -#include -#include -#ifdef HAVE_SYS_FILE_H -# include -#endif - -#include "ssh2.h" -#include "ssherr.h" -#include "sshbuf.h" -#include "cipher.h" -#include "sshkey.h" -#include "sshkey-xmss.h" -#include "atomicio.h" -#include "log.h" - -#include "xmss_fast.h" - -/* opaque internal XMSS state */ -#define XMSS_MAGIC "xmss-state-v1" -#define XMSS_CIPHERNAME "aes256-gcm@openssh.com" -struct ssh_xmss_state { - xmss_params params; - u_int32_t n, w, h, k; - - bds_state bds; - u_char *stack; - u_int32_t stackoffset; - u_char *stacklevels; - u_char *auth; - u_char *keep; - u_char *th_nodes; - u_char *retain; - treehash_inst *treehash; - - u_int32_t idx; /* state read from file */ - u_int32_t maxidx; /* restricted # of signatures */ - int have_state; /* .state file exists */ - int lockfd; /* locked in sshkey_xmss_get_state() */ - u_char allow_update; /* allow sshkey_xmss_update_state() */ - char *enc_ciphername;/* encrypt state with cipher */ - u_char *enc_keyiv; /* encrypt state with key */ - u_int32_t enc_keyiv_len; /* length of enc_keyiv */ -}; - -int sshkey_xmss_init_bds_state(struct sshkey *); -int sshkey_xmss_init_enc_key(struct sshkey *, const char *); -void sshkey_xmss_free_bds(struct sshkey *); -int sshkey_xmss_get_state_from_file(struct sshkey *, const char *, - int *, int); -int sshkey_xmss_encrypt_state(const struct sshkey *, struct sshbuf *, - struct sshbuf **); -int sshkey_xmss_decrypt_state(const struct sshkey *, struct sshbuf *, - struct sshbuf **); -int sshkey_xmss_serialize_enc_key(const struct sshkey *, struct sshbuf *); -int sshkey_xmss_deserialize_enc_key(struct sshkey *, struct sshbuf *); - -#define PRINT(...) do { if (printerror) sshlog(__FILE__, __func__, __LINE__, \ - 0, SYSLOG_LEVEL_ERROR, NULL, __VA_ARGS__); } while (0) - -int -sshkey_xmss_init(struct sshkey *key, const char *name) -{ - struct ssh_xmss_state *state; - - if (key->xmss_state != NULL) - return SSH_ERR_INVALID_FORMAT; - if (name == NULL) - return SSH_ERR_INVALID_FORMAT; - state = calloc(sizeof(struct ssh_xmss_state), 1); - if (state == NULL) - return SSH_ERR_ALLOC_FAIL; - if (strcmp(name, XMSS_SHA2_256_W16_H10_NAME) == 0) { - state->n = 32; - state->w = 16; - state->h = 10; - } else if (strcmp(name, XMSS_SHA2_256_W16_H16_NAME) == 0) { - state->n = 32; - state->w = 16; - state->h = 16; - } else if (strcmp(name, XMSS_SHA2_256_W16_H20_NAME) == 0) { - state->n = 32; - state->w = 16; - state->h = 20; - } else { - free(state); - return SSH_ERR_KEY_TYPE_UNKNOWN; - } - if ((key->xmss_name = strdup(name)) == NULL) { - free(state); - return SSH_ERR_ALLOC_FAIL; - } - state->k = 2; /* XXX hardcoded */ - state->lockfd = -1; - if (xmss_set_params(&state->params, state->n, state->h, state->w, - state->k) != 0) { - free(state); - return SSH_ERR_INVALID_FORMAT; - } - key->xmss_state = state; - return 0; -} - -void -sshkey_xmss_free_state(struct sshkey *key) -{ - struct ssh_xmss_state *state = key->xmss_state; - - sshkey_xmss_free_bds(key); - if (state) { - if (state->enc_keyiv) { - explicit_bzero(state->enc_keyiv, state->enc_keyiv_len); - free(state->enc_keyiv); - } - free(state->enc_ciphername); - free(state); - } - key->xmss_state = NULL; -} - -#define SSH_XMSS_K2_MAGIC "k=2" -#define num_stack(x) ((x->h+1)*(x->n)) -#define num_stacklevels(x) (x->h+1) -#define num_auth(x) ((x->h)*(x->n)) -#define num_keep(x) ((x->h >> 1)*(x->n)) -#define num_th_nodes(x) ((x->h - x->k)*(x->n)) -#define num_retain(x) (((1ULL << x->k) - x->k - 1) * (x->n)) -#define num_treehash(x) ((x->h) - (x->k)) - -int -sshkey_xmss_init_bds_state(struct sshkey *key) -{ - struct ssh_xmss_state *state = key->xmss_state; - u_int32_t i; - - state->stackoffset = 0; - if ((state->stack = calloc(num_stack(state), 1)) == NULL || - (state->stacklevels = calloc(num_stacklevels(state), 1))== NULL || - (state->auth = calloc(num_auth(state), 1)) == NULL || - (state->keep = calloc(num_keep(state), 1)) == NULL || - (state->th_nodes = calloc(num_th_nodes(state), 1)) == NULL || - (state->retain = calloc(num_retain(state), 1)) == NULL || - (state->treehash = calloc(num_treehash(state), - sizeof(treehash_inst))) == NULL) { - sshkey_xmss_free_bds(key); - return SSH_ERR_ALLOC_FAIL; - } - for (i = 0; i < state->h - state->k; i++) - state->treehash[i].node = &state->th_nodes[state->n*i]; - xmss_set_bds_state(&state->bds, state->stack, state->stackoffset, - state->stacklevels, state->auth, state->keep, state->treehash, - state->retain, 0); - return 0; -} - -void -sshkey_xmss_free_bds(struct sshkey *key) -{ - struct ssh_xmss_state *state = key->xmss_state; - - if (state == NULL) - return; - free(state->stack); - free(state->stacklevels); - free(state->auth); - free(state->keep); - free(state->th_nodes); - free(state->retain); - free(state->treehash); - state->stack = NULL; - state->stacklevels = NULL; - state->auth = NULL; - state->keep = NULL; - state->th_nodes = NULL; - state->retain = NULL; - state->treehash = NULL; -} - -void * -sshkey_xmss_params(const struct sshkey *key) -{ - struct ssh_xmss_state *state = key->xmss_state; - - if (state == NULL) - return NULL; - return &state->params; -} - -void * -sshkey_xmss_bds_state(const struct sshkey *key) -{ - struct ssh_xmss_state *state = key->xmss_state; - - if (state == NULL) - return NULL; - return &state->bds; -} - -int -sshkey_xmss_siglen(const struct sshkey *key, size_t *lenp) -{ - struct ssh_xmss_state *state = key->xmss_state; - - if (lenp == NULL) - return SSH_ERR_INVALID_ARGUMENT; - if (state == NULL) - return SSH_ERR_INVALID_FORMAT; - *lenp = 4 + state->n + - state->params.wots_par.keysize + - state->h * state->n; - return 0; -} - -size_t -sshkey_xmss_pklen(const struct sshkey *key) -{ - struct ssh_xmss_state *state = key->xmss_state; - - if (state == NULL) - return 0; - return state->n * 2; -} - -size_t -sshkey_xmss_sklen(const struct sshkey *key) -{ - struct ssh_xmss_state *state = key->xmss_state; - - if (state == NULL) - return 0; - return state->n * 4 + 4; -} - -int -sshkey_xmss_init_enc_key(struct sshkey *k, const char *ciphername) -{ - struct ssh_xmss_state *state = k->xmss_state; - const struct sshcipher *cipher; - size_t keylen = 0, ivlen = 0; - - if (state == NULL) - return SSH_ERR_INVALID_ARGUMENT; - if ((cipher = cipher_by_name(ciphername)) == NULL) - return SSH_ERR_INTERNAL_ERROR; - if ((state->enc_ciphername = strdup(ciphername)) == NULL) - return SSH_ERR_ALLOC_FAIL; - keylen = cipher_keylen(cipher); - ivlen = cipher_ivlen(cipher); - state->enc_keyiv_len = keylen + ivlen; - if ((state->enc_keyiv = calloc(state->enc_keyiv_len, 1)) == NULL) { - free(state->enc_ciphername); - state->enc_ciphername = NULL; - return SSH_ERR_ALLOC_FAIL; - } - arc4random_buf(state->enc_keyiv, state->enc_keyiv_len); - return 0; -} - -int -sshkey_xmss_serialize_enc_key(const struct sshkey *k, struct sshbuf *b) -{ - struct ssh_xmss_state *state = k->xmss_state; - int r; - - if (state == NULL || state->enc_keyiv == NULL || - state->enc_ciphername == NULL) - return SSH_ERR_INVALID_ARGUMENT; - if ((r = sshbuf_put_cstring(b, state->enc_ciphername)) != 0 || - (r = sshbuf_put_string(b, state->enc_keyiv, - state->enc_keyiv_len)) != 0) - return r; - return 0; -} - -int -sshkey_xmss_deserialize_enc_key(struct sshkey *k, struct sshbuf *b) -{ - struct ssh_xmss_state *state = k->xmss_state; - size_t len; - int r; - - if (state == NULL) - return SSH_ERR_INVALID_ARGUMENT; - if ((r = sshbuf_get_cstring(b, &state->enc_ciphername, NULL)) != 0 || - (r = sshbuf_get_string(b, &state->enc_keyiv, &len)) != 0) - return r; - state->enc_keyiv_len = len; - return 0; -} - -int -sshkey_xmss_serialize_pk_info(const struct sshkey *k, struct sshbuf *b, - enum sshkey_serialize_rep opts) -{ - struct ssh_xmss_state *state = k->xmss_state; - u_char have_info = 1; - u_int32_t idx; - int r; - - if (state == NULL) - return SSH_ERR_INVALID_ARGUMENT; - if (opts != SSHKEY_SERIALIZE_INFO) - return 0; - idx = k->xmss_sk ? PEEK_U32(k->xmss_sk) : state->idx; - if ((r = sshbuf_put_u8(b, have_info)) != 0 || - (r = sshbuf_put_u32(b, idx)) != 0 || - (r = sshbuf_put_u32(b, state->maxidx)) != 0) - return r; - return 0; -} - -int -sshkey_xmss_deserialize_pk_info(struct sshkey *k, struct sshbuf *b) -{ - struct ssh_xmss_state *state = k->xmss_state; - u_char have_info; - int r; - - if (state == NULL) - return SSH_ERR_INVALID_ARGUMENT; - /* optional */ - if (sshbuf_len(b) == 0) - return 0; - if ((r = sshbuf_get_u8(b, &have_info)) != 0) - return r; - if (have_info != 1) - return SSH_ERR_INVALID_ARGUMENT; - if ((r = sshbuf_get_u32(b, &state->idx)) != 0 || - (r = sshbuf_get_u32(b, &state->maxidx)) != 0) - return r; - return 0; -} - -int -sshkey_xmss_generate_private_key(struct sshkey *k, int bits) -{ - int r; - const char *name; - - if (bits == 10) { - name = XMSS_SHA2_256_W16_H10_NAME; - } else if (bits == 16) { - name = XMSS_SHA2_256_W16_H16_NAME; - } else if (bits == 20) { - name = XMSS_SHA2_256_W16_H20_NAME; - } else { - name = XMSS_DEFAULT_NAME; - } - if ((r = sshkey_xmss_init(k, name)) != 0 || - (r = sshkey_xmss_init_bds_state(k)) != 0 || - (r = sshkey_xmss_init_enc_key(k, XMSS_CIPHERNAME)) != 0) - return r; - if ((k->xmss_pk = malloc(sshkey_xmss_pklen(k))) == NULL || - (k->xmss_sk = malloc(sshkey_xmss_sklen(k))) == NULL) { - return SSH_ERR_ALLOC_FAIL; - } - xmss_keypair(k->xmss_pk, k->xmss_sk, sshkey_xmss_bds_state(k), - sshkey_xmss_params(k)); - return 0; -} - -int -sshkey_xmss_get_state_from_file(struct sshkey *k, const char *filename, - int *have_file, int printerror) -{ - struct sshbuf *b = NULL, *enc = NULL; - int ret = SSH_ERR_SYSTEM_ERROR, r, fd = -1; - u_int32_t len; - unsigned char buf[4], *data = NULL; - - *have_file = 0; - if ((fd = open(filename, O_RDONLY)) >= 0) { - *have_file = 1; - if (atomicio(read, fd, buf, sizeof(buf)) != sizeof(buf)) { - PRINT("corrupt state file: %s", filename); - goto done; - } - len = PEEK_U32(buf); - if ((data = calloc(len, 1)) == NULL) { - ret = SSH_ERR_ALLOC_FAIL; - goto done; - } - if (atomicio(read, fd, data, len) != len) { - PRINT("cannot read blob: %s", filename); - goto done; - } - if ((enc = sshbuf_from(data, len)) == NULL) { - ret = SSH_ERR_ALLOC_FAIL; - goto done; - } - sshkey_xmss_free_bds(k); - if ((r = sshkey_xmss_decrypt_state(k, enc, &b)) != 0) { - ret = r; - goto done; - } - if ((r = sshkey_xmss_deserialize_state(k, b)) != 0) { - ret = r; - goto done; - } - ret = 0; - } -done: - if (fd != -1) - close(fd); - free(data); - sshbuf_free(enc); - sshbuf_free(b); - return ret; -} - -int -sshkey_xmss_get_state(const struct sshkey *k, int printerror) -{ - struct ssh_xmss_state *state = k->xmss_state; - u_int32_t idx = 0; - char *filename = NULL; - char *statefile = NULL, *ostatefile = NULL, *lockfile = NULL; - int lockfd = -1, have_state = 0, have_ostate, tries = 0; - int ret = SSH_ERR_INVALID_ARGUMENT, r; - - if (state == NULL) - goto done; - /* - * If maxidx is set, then we are allowed a limited number - * of signatures, but don't need to access the disk. - * Otherwise we need to deal with the on-disk state. - */ - if (state->maxidx) { - /* xmss_sk always contains the current state */ - idx = PEEK_U32(k->xmss_sk); - if (idx < state->maxidx) { - state->allow_update = 1; - return 0; - } - return SSH_ERR_INVALID_ARGUMENT; - } - if ((filename = k->xmss_filename) == NULL) - goto done; - if (asprintf(&lockfile, "%s.lock", filename) == -1 || - asprintf(&statefile, "%s.state", filename) == -1 || - asprintf(&ostatefile, "%s.ostate", filename) == -1) { - ret = SSH_ERR_ALLOC_FAIL; - goto done; - } - if ((lockfd = open(lockfile, O_CREAT|O_RDONLY, 0600)) == -1) { - ret = SSH_ERR_SYSTEM_ERROR; - PRINT("cannot open/create: %s", lockfile); - goto done; - } - while (flock(lockfd, LOCK_EX|LOCK_NB) == -1) { - if (errno != EWOULDBLOCK) { - ret = SSH_ERR_SYSTEM_ERROR; - PRINT("cannot lock: %s", lockfile); - goto done; - } - if (++tries > 10) { - ret = SSH_ERR_SYSTEM_ERROR; - PRINT("giving up on: %s", lockfile); - goto done; - } - usleep(1000*100*tries); - } - /* XXX no longer const */ - if ((r = sshkey_xmss_get_state_from_file((struct sshkey *)k, - statefile, &have_state, printerror)) != 0) { - if ((r = sshkey_xmss_get_state_from_file((struct sshkey *)k, - ostatefile, &have_ostate, printerror)) == 0) { - state->allow_update = 1; - r = sshkey_xmss_forward_state(k, 1); - state->idx = PEEK_U32(k->xmss_sk); - state->allow_update = 0; - } - } - if (!have_state && !have_ostate) { - /* check that bds state is initialized */ - if (state->bds.auth == NULL) - goto done; - PRINT("start from scratch idx 0: %u", state->idx); - } else if (r != 0) { - ret = r; - goto done; - } - if (state->idx + 1 < state->idx) { - PRINT("state wrap: %u", state->idx); - goto done; - } - state->have_state = have_state; - state->lockfd = lockfd; - state->allow_update = 1; - lockfd = -1; - ret = 0; -done: - if (lockfd != -1) - close(lockfd); - free(lockfile); - free(statefile); - free(ostatefile); - return ret; -} - -int -sshkey_xmss_forward_state(const struct sshkey *k, u_int32_t reserve) -{ - struct ssh_xmss_state *state = k->xmss_state; - u_char *sig = NULL; - size_t required_siglen; - unsigned long long smlen; - u_char data; - int ret, r; - - if (state == NULL || !state->allow_update) - return SSH_ERR_INVALID_ARGUMENT; - if (reserve == 0) - return SSH_ERR_INVALID_ARGUMENT; - if (state->idx + reserve <= state->idx) - return SSH_ERR_INVALID_ARGUMENT; - if ((r = sshkey_xmss_siglen(k, &required_siglen)) != 0) - return r; - if ((sig = malloc(required_siglen)) == NULL) - return SSH_ERR_ALLOC_FAIL; - while (reserve-- > 0) { - state->idx = PEEK_U32(k->xmss_sk); - smlen = required_siglen; - if ((ret = xmss_sign(k->xmss_sk, sshkey_xmss_bds_state(k), - sig, &smlen, &data, 0, sshkey_xmss_params(k))) != 0) { - r = SSH_ERR_INVALID_ARGUMENT; - break; - } - } - free(sig); - return r; -} - -int -sshkey_xmss_update_state(const struct sshkey *k, int printerror) -{ - struct ssh_xmss_state *state = k->xmss_state; - struct sshbuf *b = NULL, *enc = NULL; - u_int32_t idx = 0; - unsigned char buf[4]; - char *filename = NULL; - char *statefile = NULL, *ostatefile = NULL, *nstatefile = NULL; - int fd = -1; - int ret = SSH_ERR_INVALID_ARGUMENT; - - if (state == NULL || !state->allow_update) - return ret; - if (state->maxidx) { - /* no update since the number of signatures is limited */ - ret = 0; - goto done; - } - idx = PEEK_U32(k->xmss_sk); - if (idx == state->idx) { - /* no signature happened, no need to update */ - ret = 0; - goto done; - } else if (idx != state->idx + 1) { - PRINT("more than one signature happened: idx %u state %u", - idx, state->idx); - goto done; - } - state->idx = idx; - if ((filename = k->xmss_filename) == NULL) - goto done; - if (asprintf(&statefile, "%s.state", filename) == -1 || - asprintf(&ostatefile, "%s.ostate", filename) == -1 || - asprintf(&nstatefile, "%s.nstate", filename) == -1) { - ret = SSH_ERR_ALLOC_FAIL; - goto done; - } - unlink(nstatefile); - if ((b = sshbuf_new()) == NULL) { - ret = SSH_ERR_ALLOC_FAIL; - goto done; - } - if ((ret = sshkey_xmss_serialize_state(k, b)) != 0) { - PRINT("SERLIALIZE FAILED: %d", ret); - goto done; - } - if ((ret = sshkey_xmss_encrypt_state(k, b, &enc)) != 0) { - PRINT("ENCRYPT FAILED: %d", ret); - goto done; - } - if ((fd = open(nstatefile, O_CREAT|O_WRONLY|O_EXCL, 0600)) == -1) { - ret = SSH_ERR_SYSTEM_ERROR; - PRINT("open new state file: %s", nstatefile); - goto done; - } - POKE_U32(buf, sshbuf_len(enc)); - if (atomicio(vwrite, fd, buf, sizeof(buf)) != sizeof(buf)) { - ret = SSH_ERR_SYSTEM_ERROR; - PRINT("write new state file hdr: %s", nstatefile); - close(fd); - goto done; - } - if (atomicio(vwrite, fd, sshbuf_mutable_ptr(enc), sshbuf_len(enc)) != - sshbuf_len(enc)) { - ret = SSH_ERR_SYSTEM_ERROR; - PRINT("write new state file data: %s", nstatefile); - close(fd); - goto done; - } - if (fsync(fd) == -1) { - ret = SSH_ERR_SYSTEM_ERROR; - PRINT("sync new state file: %s", nstatefile); - close(fd); - goto done; - } - if (close(fd) == -1) { - ret = SSH_ERR_SYSTEM_ERROR; - PRINT("close new state file: %s", nstatefile); - goto done; - } - if (state->have_state) { - unlink(ostatefile); - if (link(statefile, ostatefile)) { - ret = SSH_ERR_SYSTEM_ERROR; - PRINT("backup state %s to %s", statefile, ostatefile); - goto done; - } - } - if (rename(nstatefile, statefile) == -1) { - ret = SSH_ERR_SYSTEM_ERROR; - PRINT("rename %s to %s", nstatefile, statefile); - goto done; - } - ret = 0; -done: - if (state->lockfd != -1) { - close(state->lockfd); - state->lockfd = -1; - } - if (nstatefile) - unlink(nstatefile); - free(statefile); - free(ostatefile); - free(nstatefile); - sshbuf_free(b); - sshbuf_free(enc); - return ret; -} - -int -sshkey_xmss_serialize_state(const struct sshkey *k, struct sshbuf *b) -{ - struct ssh_xmss_state *state = k->xmss_state; - treehash_inst *th; - u_int32_t i, node; - int r; - - if (state == NULL) - return SSH_ERR_INVALID_ARGUMENT; - if (state->stack == NULL) - return SSH_ERR_INVALID_ARGUMENT; - state->stackoffset = state->bds.stackoffset; /* copy back */ - if ((r = sshbuf_put_cstring(b, SSH_XMSS_K2_MAGIC)) != 0 || - (r = sshbuf_put_u32(b, state->idx)) != 0 || - (r = sshbuf_put_string(b, state->stack, num_stack(state))) != 0 || - (r = sshbuf_put_u32(b, state->stackoffset)) != 0 || - (r = sshbuf_put_string(b, state->stacklevels, num_stacklevels(state))) != 0 || - (r = sshbuf_put_string(b, state->auth, num_auth(state))) != 0 || - (r = sshbuf_put_string(b, state->keep, num_keep(state))) != 0 || - (r = sshbuf_put_string(b, state->th_nodes, num_th_nodes(state))) != 0 || - (r = sshbuf_put_string(b, state->retain, num_retain(state))) != 0 || - (r = sshbuf_put_u32(b, num_treehash(state))) != 0) - return r; - for (i = 0; i < num_treehash(state); i++) { - th = &state->treehash[i]; - node = th->node - state->th_nodes; - if ((r = sshbuf_put_u32(b, th->h)) != 0 || - (r = sshbuf_put_u32(b, th->next_idx)) != 0 || - (r = sshbuf_put_u32(b, th->stackusage)) != 0 || - (r = sshbuf_put_u8(b, th->completed)) != 0 || - (r = sshbuf_put_u32(b, node)) != 0) - return r; - } - return 0; -} - -int -sshkey_xmss_serialize_state_opt(const struct sshkey *k, struct sshbuf *b, - enum sshkey_serialize_rep opts) -{ - struct ssh_xmss_state *state = k->xmss_state; - int r = SSH_ERR_INVALID_ARGUMENT; - u_char have_stack, have_filename, have_enc; - - if (state == NULL) - return SSH_ERR_INVALID_ARGUMENT; - if ((r = sshbuf_put_u8(b, opts)) != 0) - return r; - switch (opts) { - case SSHKEY_SERIALIZE_STATE: - r = sshkey_xmss_serialize_state(k, b); - break; - case SSHKEY_SERIALIZE_FULL: - if ((r = sshkey_xmss_serialize_enc_key(k, b)) != 0) - return r; - r = sshkey_xmss_serialize_state(k, b); - break; - case SSHKEY_SERIALIZE_SHIELD: - /* all of stack/filename/enc are optional */ - have_stack = state->stack != NULL; - if ((r = sshbuf_put_u8(b, have_stack)) != 0) - return r; - if (have_stack) { - state->idx = PEEK_U32(k->xmss_sk); /* update */ - if ((r = sshkey_xmss_serialize_state(k, b)) != 0) - return r; - } - have_filename = k->xmss_filename != NULL; - if ((r = sshbuf_put_u8(b, have_filename)) != 0) - return r; - if (have_filename && - (r = sshbuf_put_cstring(b, k->xmss_filename)) != 0) - return r; - have_enc = state->enc_keyiv != NULL; - if ((r = sshbuf_put_u8(b, have_enc)) != 0) - return r; - if (have_enc && - (r = sshkey_xmss_serialize_enc_key(k, b)) != 0) - return r; - if ((r = sshbuf_put_u32(b, state->maxidx)) != 0 || - (r = sshbuf_put_u8(b, state->allow_update)) != 0) - return r; - break; - case SSHKEY_SERIALIZE_DEFAULT: - r = 0; - break; - default: - r = SSH_ERR_INVALID_ARGUMENT; - break; - } - return r; -} - -int -sshkey_xmss_deserialize_state(struct sshkey *k, struct sshbuf *b) -{ - struct ssh_xmss_state *state = k->xmss_state; - treehash_inst *th; - u_int32_t i, lh, node; - size_t ls, lsl, la, lk, ln, lr; - char *magic; - int r = SSH_ERR_INTERNAL_ERROR; - - if (state == NULL) - return SSH_ERR_INVALID_ARGUMENT; - if (k->xmss_sk == NULL) - return SSH_ERR_INVALID_ARGUMENT; - if ((state->treehash = calloc(num_treehash(state), - sizeof(treehash_inst))) == NULL) - return SSH_ERR_ALLOC_FAIL; - if ((r = sshbuf_get_cstring(b, &magic, NULL)) != 0 || - (r = sshbuf_get_u32(b, &state->idx)) != 0 || - (r = sshbuf_get_string(b, &state->stack, &ls)) != 0 || - (r = sshbuf_get_u32(b, &state->stackoffset)) != 0 || - (r = sshbuf_get_string(b, &state->stacklevels, &lsl)) != 0 || - (r = sshbuf_get_string(b, &state->auth, &la)) != 0 || - (r = sshbuf_get_string(b, &state->keep, &lk)) != 0 || - (r = sshbuf_get_string(b, &state->th_nodes, &ln)) != 0 || - (r = sshbuf_get_string(b, &state->retain, &lr)) != 0 || - (r = sshbuf_get_u32(b, &lh)) != 0) - goto out; - if (strcmp(magic, SSH_XMSS_K2_MAGIC) != 0) { - r = SSH_ERR_INVALID_ARGUMENT; - goto out; - } - /* XXX check stackoffset */ - if (ls != num_stack(state) || - lsl != num_stacklevels(state) || - la != num_auth(state) || - lk != num_keep(state) || - ln != num_th_nodes(state) || - lr != num_retain(state) || - lh != num_treehash(state)) { - r = SSH_ERR_INVALID_ARGUMENT; - goto out; - } - for (i = 0; i < num_treehash(state); i++) { - th = &state->treehash[i]; - if ((r = sshbuf_get_u32(b, &th->h)) != 0 || - (r = sshbuf_get_u32(b, &th->next_idx)) != 0 || - (r = sshbuf_get_u32(b, &th->stackusage)) != 0 || - (r = sshbuf_get_u8(b, &th->completed)) != 0 || - (r = sshbuf_get_u32(b, &node)) != 0) - goto out; - if (node < num_th_nodes(state)) - th->node = &state->th_nodes[node]; - } - POKE_U32(k->xmss_sk, state->idx); - xmss_set_bds_state(&state->bds, state->stack, state->stackoffset, - state->stacklevels, state->auth, state->keep, state->treehash, - state->retain, 0); - /* success */ - r = 0; - out: - free(magic); - return r; -} - -int -sshkey_xmss_deserialize_state_opt(struct sshkey *k, struct sshbuf *b) -{ - struct ssh_xmss_state *state = k->xmss_state; - enum sshkey_serialize_rep opts; - u_char have_state, have_stack, have_filename, have_enc; - int r; - - if ((r = sshbuf_get_u8(b, &have_state)) != 0) - return r; - - opts = have_state; - switch (opts) { - case SSHKEY_SERIALIZE_DEFAULT: - r = 0; - break; - case SSHKEY_SERIALIZE_SHIELD: - if ((r = sshbuf_get_u8(b, &have_stack)) != 0) - return r; - if (have_stack && - (r = sshkey_xmss_deserialize_state(k, b)) != 0) - return r; - if ((r = sshbuf_get_u8(b, &have_filename)) != 0) - return r; - if (have_filename && - (r = sshbuf_get_cstring(b, &k->xmss_filename, NULL)) != 0) - return r; - if ((r = sshbuf_get_u8(b, &have_enc)) != 0) - return r; - if (have_enc && - (r = sshkey_xmss_deserialize_enc_key(k, b)) != 0) - return r; - if ((r = sshbuf_get_u32(b, &state->maxidx)) != 0 || - (r = sshbuf_get_u8(b, &state->allow_update)) != 0) - return r; - break; - case SSHKEY_SERIALIZE_STATE: - if ((r = sshkey_xmss_deserialize_state(k, b)) != 0) - return r; - break; - case SSHKEY_SERIALIZE_FULL: - if ((r = sshkey_xmss_deserialize_enc_key(k, b)) != 0 || - (r = sshkey_xmss_deserialize_state(k, b)) != 0) - return r; - break; - default: - r = SSH_ERR_INVALID_FORMAT; - break; - } - return r; -} - -int -sshkey_xmss_encrypt_state(const struct sshkey *k, struct sshbuf *b, - struct sshbuf **retp) -{ - struct ssh_xmss_state *state = k->xmss_state; - struct sshbuf *encrypted = NULL, *encoded = NULL, *padded = NULL; - struct sshcipher_ctx *ciphercontext = NULL; - const struct sshcipher *cipher; - u_char *cp, *key, *iv = NULL; - size_t i, keylen, ivlen, blocksize, authlen, encrypted_len, aadlen; - int r = SSH_ERR_INTERNAL_ERROR; - - if (retp != NULL) - *retp = NULL; - if (state == NULL || - state->enc_keyiv == NULL || - state->enc_ciphername == NULL) - return SSH_ERR_INTERNAL_ERROR; - if ((cipher = cipher_by_name(state->enc_ciphername)) == NULL) { - r = SSH_ERR_INTERNAL_ERROR; - goto out; - } - blocksize = cipher_blocksize(cipher); - keylen = cipher_keylen(cipher); - ivlen = cipher_ivlen(cipher); - authlen = cipher_authlen(cipher); - if (state->enc_keyiv_len != keylen + ivlen) { - r = SSH_ERR_INVALID_FORMAT; - goto out; - } - key = state->enc_keyiv; - if ((encrypted = sshbuf_new()) == NULL || - (encoded = sshbuf_new()) == NULL || - (padded = sshbuf_new()) == NULL || - (iv = malloc(ivlen)) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto out; - } - - /* replace first 4 bytes of IV with index to ensure uniqueness */ - memcpy(iv, key + keylen, ivlen); - POKE_U32(iv, state->idx); - - if ((r = sshbuf_put(encoded, XMSS_MAGIC, sizeof(XMSS_MAGIC))) != 0 || - (r = sshbuf_put_u32(encoded, state->idx)) != 0) - goto out; - - /* padded state will be encrypted */ - if ((r = sshbuf_putb(padded, b)) != 0) - goto out; - i = 0; - while (sshbuf_len(padded) % blocksize) { - if ((r = sshbuf_put_u8(padded, ++i & 0xff)) != 0) - goto out; - } - encrypted_len = sshbuf_len(padded); - - /* header including the length of state is used as AAD */ - if ((r = sshbuf_put_u32(encoded, encrypted_len)) != 0) - goto out; - aadlen = sshbuf_len(encoded); - - /* concat header and state */ - if ((r = sshbuf_putb(encoded, padded)) != 0) - goto out; - - /* reserve space for encryption of encoded data plus auth tag */ - /* encrypt at offset addlen */ - if ((r = sshbuf_reserve(encrypted, - encrypted_len + aadlen + authlen, &cp)) != 0 || - (r = cipher_init(&ciphercontext, cipher, key, keylen, - iv, ivlen, 1)) != 0 || - (r = cipher_crypt(ciphercontext, 0, cp, sshbuf_ptr(encoded), - encrypted_len, aadlen, authlen)) != 0) - goto out; - - /* success */ - r = 0; - out: - if (retp != NULL) { - *retp = encrypted; - encrypted = NULL; - } - sshbuf_free(padded); - sshbuf_free(encoded); - sshbuf_free(encrypted); - cipher_free(ciphercontext); - free(iv); - return r; -} - -int -sshkey_xmss_decrypt_state(const struct sshkey *k, struct sshbuf *encoded, - struct sshbuf **retp) -{ - struct ssh_xmss_state *state = k->xmss_state; - struct sshbuf *copy = NULL, *decrypted = NULL; - struct sshcipher_ctx *ciphercontext = NULL; - const struct sshcipher *cipher = NULL; - u_char *key, *iv = NULL, *dp; - size_t keylen, ivlen, authlen, aadlen; - u_int blocksize, encrypted_len, index; - int r = SSH_ERR_INTERNAL_ERROR; - - if (retp != NULL) - *retp = NULL; - if (state == NULL || - state->enc_keyiv == NULL || - state->enc_ciphername == NULL) - return SSH_ERR_INTERNAL_ERROR; - if ((cipher = cipher_by_name(state->enc_ciphername)) == NULL) { - r = SSH_ERR_INVALID_FORMAT; - goto out; - } - blocksize = cipher_blocksize(cipher); - keylen = cipher_keylen(cipher); - ivlen = cipher_ivlen(cipher); - authlen = cipher_authlen(cipher); - if (state->enc_keyiv_len != keylen + ivlen) { - r = SSH_ERR_INTERNAL_ERROR; - goto out; - } - key = state->enc_keyiv; - - if ((copy = sshbuf_fromb(encoded)) == NULL || - (decrypted = sshbuf_new()) == NULL || - (iv = malloc(ivlen)) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto out; - } - - /* check magic */ - if (sshbuf_len(encoded) < sizeof(XMSS_MAGIC) || - memcmp(sshbuf_ptr(encoded), XMSS_MAGIC, sizeof(XMSS_MAGIC))) { - r = SSH_ERR_INVALID_FORMAT; - goto out; - } - /* parse public portion */ - if ((r = sshbuf_consume(encoded, sizeof(XMSS_MAGIC))) != 0 || - (r = sshbuf_get_u32(encoded, &index)) != 0 || - (r = sshbuf_get_u32(encoded, &encrypted_len)) != 0) - goto out; - - /* check size of encrypted key blob */ - if (encrypted_len < blocksize || (encrypted_len % blocksize) != 0) { - r = SSH_ERR_INVALID_FORMAT; - goto out; - } - /* check that an appropriate amount of auth data is present */ - if (sshbuf_len(encoded) < authlen || - sshbuf_len(encoded) - authlen < encrypted_len) { - r = SSH_ERR_INVALID_FORMAT; - goto out; - } - - aadlen = sshbuf_len(copy) - sshbuf_len(encoded); - - /* replace first 4 bytes of IV with index to ensure uniqueness */ - memcpy(iv, key + keylen, ivlen); - POKE_U32(iv, index); - - /* decrypt private state of key */ - if ((r = sshbuf_reserve(decrypted, aadlen + encrypted_len, &dp)) != 0 || - (r = cipher_init(&ciphercontext, cipher, key, keylen, - iv, ivlen, 0)) != 0 || - (r = cipher_crypt(ciphercontext, 0, dp, sshbuf_ptr(copy), - encrypted_len, aadlen, authlen)) != 0) - goto out; - - /* there should be no trailing data */ - if ((r = sshbuf_consume(encoded, encrypted_len + authlen)) != 0) - goto out; - if (sshbuf_len(encoded) != 0) { - r = SSH_ERR_INVALID_FORMAT; - goto out; - } - - /* remove AAD */ - if ((r = sshbuf_consume(decrypted, aadlen)) != 0) - goto out; - /* XXX encrypted includes unchecked padding */ - - /* success */ - r = 0; - if (retp != NULL) { - *retp = decrypted; - decrypted = NULL; - } - out: - cipher_free(ciphercontext); - sshbuf_free(copy); - sshbuf_free(decrypted); - free(iv); - return r; -} - -u_int32_t -sshkey_xmss_signatures_left(const struct sshkey *k) -{ - struct ssh_xmss_state *state = k->xmss_state; - u_int32_t idx; - - if (sshkey_type_plain(k->type) == KEY_XMSS && state && - state->maxidx) { - idx = k->xmss_sk ? PEEK_U32(k->xmss_sk) : state->idx; - if (idx < state->maxidx) - return state->maxidx - idx; - } - return 0; -} - -int -sshkey_xmss_enable_maxsign(struct sshkey *k, u_int32_t maxsign) -{ - struct ssh_xmss_state *state = k->xmss_state; - - if (sshkey_type_plain(k->type) != KEY_XMSS) - return SSH_ERR_INVALID_ARGUMENT; - if (maxsign == 0) - return 0; - if (state->idx + maxsign < state->idx) - return SSH_ERR_INVALID_ARGUMENT; - state->maxidx = state->idx + maxsign; - return 0; -} -#endif /* WITH_XMSS */ diff --git a/sshkey-xmss.h b/sshkey-xmss.h deleted file mode 100644 index ab8b9c905a96..000000000000 --- a/sshkey-xmss.h +++ /dev/null @@ -1,56 +0,0 @@ -/* $OpenBSD: sshkey-xmss.h,v 1.4 2022/10/28 00:39:29 djm Exp $ */ -/* - * Copyright (c) 2017 Markus Friedl. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef SSHKEY_XMSS_H -#define SSHKEY_XMSS_H - -#define XMSS_SHA2_256_W16_H10_NAME "XMSS_SHA2-256_W16_H10" -#define XMSS_SHA2_256_W16_H16_NAME "XMSS_SHA2-256_W16_H16" -#define XMSS_SHA2_256_W16_H20_NAME "XMSS_SHA2-256_W16_H20" -#define XMSS_DEFAULT_NAME XMSS_SHA2_256_W16_H10_NAME - -size_t sshkey_xmss_pklen(const struct sshkey *); -size_t sshkey_xmss_sklen(const struct sshkey *); -int sshkey_xmss_init(struct sshkey *, const char *); -void sshkey_xmss_free_state(struct sshkey *); -int sshkey_xmss_generate_private_key(struct sshkey *, int); -int sshkey_xmss_serialize_state(const struct sshkey *, struct sshbuf *); -int sshkey_xmss_serialize_state_opt(const struct sshkey *, struct sshbuf *, - enum sshkey_serialize_rep); -int sshkey_xmss_serialize_pk_info(const struct sshkey *, struct sshbuf *, - enum sshkey_serialize_rep); -int sshkey_xmss_deserialize_state(struct sshkey *, struct sshbuf *); -int sshkey_xmss_deserialize_state_opt(struct sshkey *, struct sshbuf *); -int sshkey_xmss_deserialize_pk_info(struct sshkey *, struct sshbuf *); - -int sshkey_xmss_siglen(const struct sshkey *, size_t *); -void *sshkey_xmss_params(const struct sshkey *); -void *sshkey_xmss_bds_state(const struct sshkey *); -int sshkey_xmss_get_state(const struct sshkey *, int); -int sshkey_xmss_enable_maxsign(struct sshkey *, u_int32_t); -int sshkey_xmss_forward_state(const struct sshkey *, u_int32_t); -int sshkey_xmss_update_state(const struct sshkey *, int); -u_int32_t sshkey_xmss_signatures_left(const struct sshkey *); - -#endif /* SSHKEY_XMSS_H */ diff --git a/sshkey.c b/sshkey.c index 3b1335d99725..6b3e24ec44e1 100644 --- a/sshkey.c +++ b/sshkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshkey.c,v 1.151 2025/07/24 05:44:55 djm Exp $ */ +/* $OpenBSD: sshkey.c,v 1.152 2025/08/29 03:50:38 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * Copyright (c) 2008 Alexander von Gernler. All rights reserved. @@ -62,11 +62,6 @@ #include "ssh-sk.h" #include "ssh-pkcs11.h" -#ifdef WITH_XMSS -#include "sshkey-xmss.h" -#include "xmss_fast.h" -#endif - #include "openbsd-compat/openssl-compat.h" /* openssh private key file format */ @@ -88,8 +83,6 @@ #define SSHKEY_SHIELD_CIPHER "aes256-ctr" /* XXX want AES-EME* */ #define SSHKEY_SHIELD_PREKEY_HASH SSH_DIGEST_SHA512 -int sshkey_private_serialize_opt(struct sshkey *key, - struct sshbuf *buf, enum sshkey_serialize_rep); static int sshkey_from_blob_internal(struct sshbuf *buf, struct sshkey **keyp, int allow_cert); @@ -121,10 +114,6 @@ extern const struct sshkey_impl sshkey_rsa_sha256_cert_impl; extern const struct sshkey_impl sshkey_rsa_sha512_impl; extern const struct sshkey_impl sshkey_rsa_sha512_cert_impl; #endif /* WITH_OPENSSL */ -#ifdef WITH_XMSS -extern const struct sshkey_impl sshkey_xmss_impl; -extern const struct sshkey_impl sshkey_xmss_cert_impl; -#endif const struct sshkey_impl * const keyimpls[] = { &sshkey_ed25519_impl, @@ -156,10 +145,6 @@ const struct sshkey_impl * const keyimpls[] = { &sshkey_rsa_sha512_impl, &sshkey_rsa_sha512_cert_impl, #endif /* WITH_OPENSSL */ -#ifdef WITH_XMSS - &sshkey_xmss_impl, - &sshkey_xmss_cert_impl, -#endif NULL }; @@ -452,8 +437,6 @@ sshkey_type_plain(int type) return KEY_ED25519; case KEY_ED25519_SK_CERT: return KEY_ED25519_SK; - case KEY_XMSS_CERT: - return KEY_XMSS; default: return type; } @@ -474,8 +457,6 @@ sshkey_type_certified(int type) return KEY_ED25519_CERT; case KEY_ED25519_SK: return KEY_ED25519_SK_CERT; - case KEY_XMSS: - return KEY_XMSS_CERT; default: return -1; } @@ -919,17 +900,10 @@ sshkey_puts_opts_internal(const struct sshkey *key, struct sshbuf *b, return r; } -int -sshkey_puts_opts(const struct sshkey *key, struct sshbuf *b, - enum sshkey_serialize_rep opts) -{ - return sshkey_puts_opts_internal(key, b, opts, 0); -} - int sshkey_puts(const struct sshkey *key, struct sshbuf *b) { - return sshkey_puts_opts(key, b, SSHKEY_SERIALIZE_DEFAULT); + return sshkey_puts_opts_internal(key, b, SSHKEY_SERIALIZE_DEFAULT, 0); } int @@ -1691,8 +1665,7 @@ sshkey_shield_private(struct sshkey *k) } if (sshkey_is_shielded(k) && (r = sshkey_unshield_private(k)) != 0) goto out; - if ((r = sshkey_private_serialize_opt(k, prvbuf, - SSHKEY_SERIALIZE_SHIELD)) != 0) + if ((r = sshkey_private_serialize(k, prvbuf)) != 0) goto out; /* pad to cipher blocksize */ i = 0; @@ -2550,7 +2523,7 @@ sshkey_serialize_private_sk(const struct sshkey *key, struct sshbuf *b) return 0; } -int +static int sshkey_private_serialize_opt(struct sshkey *key, struct sshbuf *buf, enum sshkey_serialize_rep opts) { @@ -2601,6 +2574,7 @@ sshkey_private_serialize(struct sshkey *key, struct sshbuf *b) SSHKEY_SERIALIZE_DEFAULT); } + /* Shared deserialization of FIDO private key components */ int sshkey_private_deserialize_sk(struct sshbuf *buf, struct sshkey *k) @@ -2660,7 +2634,6 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp) expect_ed25519_pk = k->ed25519_pk; k->sk_application = NULL; k->ed25519_pk = NULL; - /* XXX xmss too or refactor */ } else { if ((k = sshkey_new(type)) == NULL) { r = SSH_ERR_ALLOC_FAIL; @@ -2674,7 +2647,6 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp) if ((r = impl->funcs->deserialize_private(tname, buf, k)) != 0) goto out; - /* XXX xmss too or refactor */ if ((expect_sk_application != NULL && (k->sk_application == NULL || strcmp(expect_sk_application, k->sk_application) != 0)) || (expect_ed25519_pk != NULL && (k->ed25519_pk == NULL || @@ -2919,8 +2891,7 @@ sshkey_private_to_blob2(struct sshkey *prv, struct sshbuf *blob, goto out; /* append private key and comment*/ - if ((r = sshkey_private_serialize_opt(prv, encrypted, - SSHKEY_SERIALIZE_FULL)) != 0 || + if ((r = sshkey_private_serialize(prv, encrypted)) != 0 || (r = sshbuf_put_cstring(encrypted, comment)) != 0) goto out; @@ -3400,9 +3371,6 @@ sshkey_private_to_fileblob(struct sshkey *key, struct sshbuf *blob, #endif /* WITH_OPENSSL */ case KEY_ED25519: case KEY_ED25519_SK: -#ifdef WITH_XMSS - case KEY_XMSS: -#endif /* WITH_XMSS */ #ifdef WITH_OPENSSL case KEY_ECDSA_SK: #endif /* WITH_OPENSSL */ @@ -3664,24 +3632,16 @@ sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type, if (commentp != NULL) *commentp = NULL; - switch (type) { - case KEY_XMSS: - /* No fallback for new-format-only keys */ - return sshkey_parse_private2(blob, type, passphrase, - keyp, commentp); - default: - r = sshkey_parse_private2(blob, type, passphrase, keyp, - commentp); - /* Only fallback to PEM parser if a format error occurred. */ - if (r != SSH_ERR_INVALID_FORMAT) - return r; + r = sshkey_parse_private2(blob, type, passphrase, keyp, commentp); + /* Only fallback to PEM parser if a format error occurred. */ + if (r != SSH_ERR_INVALID_FORMAT) + return r; #ifdef WITH_OPENSSL - return sshkey_parse_private_pem_fileblob(blob, type, - passphrase, keyp); + return sshkey_parse_private_pem_fileblob(blob, type, + passphrase, keyp); #else - return SSH_ERR_INVALID_FORMAT; + return SSH_ERR_INVALID_FORMAT; #endif /* WITH_OPENSSL */ - } } int @@ -3716,90 +3676,3 @@ sshkey_parse_pubkey_from_private_fileblob_type(struct sshbuf *blob, int type, return r; return 0; } - -#ifdef WITH_XMSS -/* - * serialize the key with the current state and forward the state - * maxsign times. - */ -int -sshkey_private_serialize_maxsign(struct sshkey *k, struct sshbuf *b, - u_int32_t maxsign, int printerror) -{ - int r, rupdate; - - if (maxsign == 0 || - sshkey_type_plain(k->type) != KEY_XMSS) - return sshkey_private_serialize_opt(k, b, - SSHKEY_SERIALIZE_DEFAULT); - if ((r = sshkey_xmss_get_state(k, printerror)) != 0 || - (r = sshkey_private_serialize_opt(k, b, - SSHKEY_SERIALIZE_STATE)) != 0 || - (r = sshkey_xmss_forward_state(k, maxsign)) != 0) - goto out; - r = 0; -out: - if ((rupdate = sshkey_xmss_update_state(k, printerror)) != 0) { - if (r == 0) - r = rupdate; - } - return r; -} - -u_int32_t -sshkey_signatures_left(const struct sshkey *k) -{ - if (sshkey_type_plain(k->type) == KEY_XMSS) - return sshkey_xmss_signatures_left(k); - return 0; -} - -int -sshkey_enable_maxsign(struct sshkey *k, u_int32_t maxsign) -{ - if (sshkey_type_plain(k->type) != KEY_XMSS) - return SSH_ERR_INVALID_ARGUMENT; - return sshkey_xmss_enable_maxsign(k, maxsign); -} - -int -sshkey_set_filename(struct sshkey *k, const char *filename) -{ - if (k == NULL) - return SSH_ERR_INVALID_ARGUMENT; - if (sshkey_type_plain(k->type) != KEY_XMSS) - return 0; - if (filename == NULL) - return SSH_ERR_INVALID_ARGUMENT; - if ((k->xmss_filename = strdup(filename)) == NULL) - return SSH_ERR_ALLOC_FAIL; - return 0; -} -#else -int -sshkey_private_serialize_maxsign(struct sshkey *k, struct sshbuf *b, - u_int32_t maxsign, int printerror) -{ - return sshkey_private_serialize_opt(k, b, SSHKEY_SERIALIZE_DEFAULT); -} - -u_int32_t -sshkey_signatures_left(const struct sshkey *k) -{ - return 0; -} - -int -sshkey_enable_maxsign(struct sshkey *k, u_int32_t maxsign) -{ - return SSH_ERR_INVALID_ARGUMENT; -} - -int -sshkey_set_filename(struct sshkey *k, const char *filename) -{ - if (k == NULL) - return SSH_ERR_INVALID_ARGUMENT; - return 0; -} -#endif /* WITH_XMSS */ diff --git a/sshkey.h b/sshkey.h index 77253bc4e12a..c3262b896f06 100644 --- a/sshkey.h +++ b/sshkey.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sshkey.h,v 1.69 2025/07/24 06:12:08 djm Exp $ */ +/* $OpenBSD: sshkey.h,v 1.70 2025/08/29 03:50:38 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. @@ -63,8 +63,6 @@ enum sshkey_types { KEY_RSA_CERT, KEY_ECDSA_CERT, KEY_ED25519_CERT, - KEY_XMSS, - KEY_XMSS_CERT, KEY_ECDSA_SK, KEY_ECDSA_SK_CERT, KEY_ED25519_SK, @@ -87,10 +85,6 @@ enum sshkey_fp_rep { /* Private key serialisation formats, used on the wire */ enum sshkey_serialize_rep { SSHKEY_SERIALIZE_DEFAULT = 0, - SSHKEY_SERIALIZE_STATE = 1, /* only state is serialized */ - SSHKEY_SERIALIZE_FULL = 2, /* include keys for saving to disk */ - SSHKEY_SERIALIZE_SHIELD = 3, /* everything, for encrypting in ram */ - SSHKEY_SERIALIZE_INFO = 254, /* minimal information */ }; /* Private key disk formats */ @@ -130,12 +124,6 @@ struct sshkey { /* KEY_ED25519 and KEY_ED25519_SK */ u_char *ed25519_sk; u_char *ed25519_pk; - /* KEY_XMSS */ - char *xmss_name; - char *xmss_filename; /* for state file updates */ - void *xmss_state; /* depends on xmss_name, opaque */ - u_char *xmss_sk; - u_char *xmss_pk; /* KEY_ECDSA_SK and KEY_ED25519_SK */ char *sk_application; uint8_t sk_flags; @@ -271,8 +259,6 @@ int sshkey_to_blob(const struct sshkey *, u_char **, size_t *); int sshkey_to_base64(const struct sshkey *, char **); int sshkey_putb(const struct sshkey *, struct sshbuf *); int sshkey_puts(const struct sshkey *, struct sshbuf *); -int sshkey_puts_opts(const struct sshkey *, struct sshbuf *, - enum sshkey_serialize_rep); int sshkey_plain_to_blob(const struct sshkey *, u_char **, size_t *); int sshkey_putb_plain(const struct sshkey *, struct sshbuf *); int sshkey_puts_plain(const struct sshkey *, struct sshbuf *); @@ -297,8 +283,6 @@ void sshkey_dump_ec_key(const EC_KEY *); /* private key parsing and serialisation */ int sshkey_private_serialize(struct sshkey *key, struct sshbuf *buf); -int sshkey_private_serialize_opt(struct sshkey *key, struct sshbuf *buf, - enum sshkey_serialize_rep); int sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **keyp); /* private key file format parsing and serialisation */ @@ -325,13 +309,6 @@ int ssh_ed25519_encode_store_sig(const u_char *, size_t, int ssh_rsa_complete_crt_parameters(const BIGNUM *, const BIGNUM *, const BIGNUM *, const BIGNUM *, BIGNUM **, BIGNUM **); -/* stateful keys (e.g. XMSS) */ -int sshkey_set_filename(struct sshkey *, const char *); -int sshkey_enable_maxsign(struct sshkey *, u_int32_t); -u_int32_t sshkey_signatures_left(const struct sshkey *); -int sshkey_private_serialize_maxsign(struct sshkey *key, - struct sshbuf *buf, u_int32_t maxsign, int); - void sshkey_sig_details_free(struct sshkey_sig_details *); #ifdef WITH_OPENSSL diff --git a/xmss_commons.c b/xmss_commons.c deleted file mode 100644 index 8d6b80b6eb79..000000000000 --- a/xmss_commons.c +++ /dev/null @@ -1,36 +0,0 @@ -/* $OpenBSD: xmss_commons.c,v 1.2 2018/02/26 03:56:44 dtucker Exp $ */ -/* -xmss_commons.c 20160722 -Andreas Hülsing -Joost Rijneveld -Public domain. -*/ - -#include "includes.h" -#ifdef WITH_XMSS - -#include "xmss_commons.h" -#include -#include -#ifdef HAVE_STDINT_H -# include -#endif - -void to_byte(unsigned char *out, unsigned long long in, uint32_t bytes) -{ - int32_t i; - for (i = bytes-1; i >= 0; i--) { - out[i] = in & 0xff; - in = in >> 8; - } -} - -#if 0 -void hexdump(const unsigned char *a, size_t len) -{ - size_t i; - for (i = 0; i < len; i++) - printf("%02x", a[i]); -} -#endif -#endif /* WITH_XMSS */ diff --git a/xmss_commons.h b/xmss_commons.h deleted file mode 100644 index a98e4799c425..000000000000 --- a/xmss_commons.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifdef WITH_XMSS -/* $OpenBSD: xmss_commons.h,v 1.3 2018/02/26 03:56:44 dtucker Exp $ */ -/* -xmss_commons.h 20160722 -Andreas Hülsing -Joost Rijneveld -Public domain. -*/ -#ifndef XMSS_COMMONS_H -#define XMSS_COMMONS_H - -#include -#ifdef HAVE_STDINT_H -#include -#endif -#endif -void to_byte(unsigned char *output, unsigned long long in, uint32_t bytes); -#if 0 -void hexdump(const unsigned char *a, size_t len); -#endif -#endif /* WITH_XMSS */ diff --git a/xmss_fast.c b/xmss_fast.c deleted file mode 100644 index 421b39a37a9e..000000000000 --- a/xmss_fast.c +++ /dev/null @@ -1,1106 +0,0 @@ -/* $OpenBSD: xmss_fast.c,v 1.3 2018/03/22 07:06:11 markus Exp $ */ -/* -xmss_fast.c version 20160722 -Andreas Hülsing -Joost Rijneveld -Public domain. -*/ - -#include "includes.h" -#ifdef WITH_XMSS - -#include -#include -#ifdef HAVE_STDINT_H -# include -#endif - -#include "xmss_fast.h" -#include "crypto_api.h" -#include "xmss_wots.h" -#include "xmss_hash.h" - -#include "xmss_commons.h" -#include "xmss_hash_address.h" -// For testing -#include "stdio.h" - - - -/** - * Used for pseudorandom keygeneration, - * generates the seed for the WOTS keypair at address addr - * - * takes n byte sk_seed and returns n byte seed using 32 byte address addr. - */ -static void get_seed(unsigned char *seed, const unsigned char *sk_seed, int n, uint32_t addr[8]) -{ - unsigned char bytes[32]; - // Make sure that chain addr, hash addr, and key bit are 0! - setChainADRS(addr,0); - setHashADRS(addr,0); - setKeyAndMask(addr,0); - // Generate pseudorandom value - addr_to_byte(bytes, addr); - prf(seed, bytes, sk_seed, n); -} - -/** - * Initialize xmss params struct - * parameter names are the same as in the draft - * parameter k is K as used in the BDS algorithm - */ -int xmss_set_params(xmss_params *params, int n, int h, int w, int k) -{ - if (k >= h || k < 2 || (h - k) % 2) { - fprintf(stderr, "For BDS traversal, H - K must be even, with H > K >= 2!\n"); - return 1; - } - params->h = h; - params->n = n; - params->k = k; - wots_params wots_par; - wots_set_params(&wots_par, n, w); - params->wots_par = wots_par; - return 0; -} - -/** - * Initialize BDS state struct - * parameter names are the same as used in the description of the BDS traversal - */ -void xmss_set_bds_state(bds_state *state, unsigned char *stack, int stackoffset, unsigned char *stacklevels, unsigned char *auth, unsigned char *keep, treehash_inst *treehash, unsigned char *retain, int next_leaf) -{ - state->stack = stack; - state->stackoffset = stackoffset; - state->stacklevels = stacklevels; - state->auth = auth; - state->keep = keep; - state->treehash = treehash; - state->retain = retain; - state->next_leaf = next_leaf; -} - -/** - * Initialize xmssmt_params struct - * parameter names are the same as in the draft - * - * Especially h is the total tree height, i.e. the XMSS trees have height h/d - */ -int xmssmt_set_params(xmssmt_params *params, int n, int h, int d, int w, int k) -{ - if (h % d) { - fprintf(stderr, "d must divide h without remainder!\n"); - return 1; - } - params->h = h; - params->d = d; - params->n = n; - params->index_len = (h + 7) / 8; - xmss_params xmss_par; - if (xmss_set_params(&xmss_par, n, (h/d), w, k)) { - return 1; - } - params->xmss_par = xmss_par; - return 0; -} - -/** - * Computes a leaf from a WOTS public key using an L-tree. - */ -static void l_tree(unsigned char *leaf, unsigned char *wots_pk, const xmss_params *params, const unsigned char *pub_seed, uint32_t addr[8]) -{ - unsigned int l = params->wots_par.len; - unsigned int n = params->n; - uint32_t i = 0; - uint32_t height = 0; - uint32_t bound; - - //ADRS.setTreeHeight(0); - setTreeHeight(addr, height); - - while (l > 1) { - bound = l >> 1; //floor(l / 2); - for (i = 0; i < bound; i++) { - //ADRS.setTreeIndex(i); - setTreeIndex(addr, i); - //wots_pk[i] = RAND_HASH(pk[2i], pk[2i + 1], SEED, ADRS); - hash_h(wots_pk+i*n, wots_pk+i*2*n, pub_seed, addr, n); - } - //if ( l % 2 == 1 ) { - if (l & 1) { - //pk[floor(l / 2) + 1] = pk[l]; - memcpy(wots_pk+(l>>1)*n, wots_pk+(l-1)*n, n); - //l = ceil(l / 2); - l=(l>>1)+1; - } - else { - //l = ceil(l / 2); - l=(l>>1); - } - //ADRS.setTreeHeight(ADRS.getTreeHeight() + 1); - height++; - setTreeHeight(addr, height); - } - //return pk[0]; - memcpy(leaf, wots_pk, n); -} - -/** - * Computes the leaf at a given address. First generates the WOTS key pair, then computes leaf using l_tree. As this happens position independent, we only require that addr encodes the right ltree-address. - */ -static void gen_leaf_wots(unsigned char *leaf, const unsigned char *sk_seed, const xmss_params *params, const unsigned char *pub_seed, uint32_t ltree_addr[8], uint32_t ots_addr[8]) -{ - unsigned char seed[params->n]; - unsigned char pk[params->wots_par.keysize]; - - get_seed(seed, sk_seed, params->n, ots_addr); - wots_pkgen(pk, seed, &(params->wots_par), pub_seed, ots_addr); - - l_tree(leaf, pk, params, pub_seed, ltree_addr); -} - -static int treehash_minheight_on_stack(bds_state* state, const xmss_params *params, const treehash_inst *treehash) { - unsigned int r = params->h, i; - for (i = 0; i < treehash->stackusage; i++) { - if (state->stacklevels[state->stackoffset - i - 1] < r) { - r = state->stacklevels[state->stackoffset - i - 1]; - } - } - return r; -} - -/** - * Merkle's TreeHash algorithm. The address only needs to initialize the first 78 bits of addr. Everything else will be set by treehash. - * Currently only used for key generation. - * - */ -static void treehash_setup(unsigned char *node, int height, int index, bds_state *state, const unsigned char *sk_seed, const xmss_params *params, const unsigned char *pub_seed, const uint32_t addr[8]) -{ - unsigned int idx = index; - unsigned int n = params->n; - unsigned int h = params->h; - unsigned int k = params->k; - // use three different addresses because at this point we use all three formats in parallel - uint32_t ots_addr[8]; - uint32_t ltree_addr[8]; - uint32_t node_addr[8]; - // only copy layer and tree address parts - memcpy(ots_addr, addr, 12); - // type = ots - setType(ots_addr, 0); - memcpy(ltree_addr, addr, 12); - setType(ltree_addr, 1); - memcpy(node_addr, addr, 12); - setType(node_addr, 2); - - uint32_t lastnode, i; - unsigned char stack[(height+1)*n]; - unsigned int stacklevels[height+1]; - unsigned int stackoffset=0; - unsigned int nodeh; - - lastnode = idx+(1<treehash[i].h = i; - state->treehash[i].completed = 1; - state->treehash[i].stackusage = 0; - } - - i = 0; - for (; idx < lastnode; idx++) { - setLtreeADRS(ltree_addr, idx); - setOTSADRS(ots_addr, idx); - gen_leaf_wots(stack+stackoffset*n, sk_seed, params, pub_seed, ltree_addr, ots_addr); - stacklevels[stackoffset] = 0; - stackoffset++; - if (h - k > 0 && i == 3) { - memcpy(state->treehash[0].node, stack+stackoffset*n, n); - } - while (stackoffset>1 && stacklevels[stackoffset-1] == stacklevels[stackoffset-2]) - { - nodeh = stacklevels[stackoffset-1]; - if (i >> nodeh == 1) { - memcpy(state->auth + nodeh*n, stack+(stackoffset-1)*n, n); - } - else { - if (nodeh < h - k && i >> nodeh == 3) { - memcpy(state->treehash[nodeh].node, stack+(stackoffset-1)*n, n); - } - else if (nodeh >= h - k) { - memcpy(state->retain + ((1 << (h - 1 - nodeh)) + nodeh - h + (((i >> nodeh) - 3) >> 1)) * n, stack+(stackoffset-1)*n, n); - } - } - setTreeHeight(node_addr, stacklevels[stackoffset-1]); - setTreeIndex(node_addr, (idx >> (stacklevels[stackoffset-1]+1))); - hash_h(stack+(stackoffset-2)*n, stack+(stackoffset-2)*n, pub_seed, - node_addr, n); - stacklevels[stackoffset-2]++; - stackoffset--; - } - i++; - } - - for (i = 0; i < n; i++) - node[i] = stack[i]; -} - -static void treehash_update(treehash_inst *treehash, bds_state *state, const unsigned char *sk_seed, const xmss_params *params, const unsigned char *pub_seed, const uint32_t addr[8]) { - int n = params->n; - - uint32_t ots_addr[8]; - uint32_t ltree_addr[8]; - uint32_t node_addr[8]; - // only copy layer and tree address parts - memcpy(ots_addr, addr, 12); - // type = ots - setType(ots_addr, 0); - memcpy(ltree_addr, addr, 12); - setType(ltree_addr, 1); - memcpy(node_addr, addr, 12); - setType(node_addr, 2); - - setLtreeADRS(ltree_addr, treehash->next_idx); - setOTSADRS(ots_addr, treehash->next_idx); - - unsigned char nodebuffer[2 * n]; - unsigned int nodeheight = 0; - gen_leaf_wots(nodebuffer, sk_seed, params, pub_seed, ltree_addr, ots_addr); - while (treehash->stackusage > 0 && state->stacklevels[state->stackoffset-1] == nodeheight) { - memcpy(nodebuffer + n, nodebuffer, n); - memcpy(nodebuffer, state->stack + (state->stackoffset-1)*n, n); - setTreeHeight(node_addr, nodeheight); - setTreeIndex(node_addr, (treehash->next_idx >> (nodeheight+1))); - hash_h(nodebuffer, nodebuffer, pub_seed, node_addr, n); - nodeheight++; - treehash->stackusage--; - state->stackoffset--; - } - if (nodeheight == treehash->h) { // this also implies stackusage == 0 - memcpy(treehash->node, nodebuffer, n); - treehash->completed = 1; - } - else { - memcpy(state->stack + state->stackoffset*n, nodebuffer, n); - treehash->stackusage++; - state->stacklevels[state->stackoffset] = nodeheight; - state->stackoffset++; - treehash->next_idx++; - } -} - -/** - * Computes a root node given a leaf and an authapth - */ -static void validate_authpath(unsigned char *root, const unsigned char *leaf, unsigned long leafidx, const unsigned char *authpath, const xmss_params *params, const unsigned char *pub_seed, uint32_t addr[8]) -{ - unsigned int n = params->n; - - uint32_t i, j; - unsigned char buffer[2*n]; - - // If leafidx is odd (last bit = 1), current path element is a right child and authpath has to go to the left. - // Otherwise, it is the other way around - if (leafidx & 1) { - for (j = 0; j < n; j++) - buffer[n+j] = leaf[j]; - for (j = 0; j < n; j++) - buffer[j] = authpath[j]; - } - else { - for (j = 0; j < n; j++) - buffer[j] = leaf[j]; - for (j = 0; j < n; j++) - buffer[n+j] = authpath[j]; - } - authpath += n; - - for (i=0; i < params->h-1; i++) { - setTreeHeight(addr, i); - leafidx >>= 1; - setTreeIndex(addr, leafidx); - if (leafidx&1) { - hash_h(buffer+n, buffer, pub_seed, addr, n); - for (j = 0; j < n; j++) - buffer[j] = authpath[j]; - } - else { - hash_h(buffer, buffer, pub_seed, addr, n); - for (j = 0; j < n; j++) - buffer[j+n] = authpath[j]; - } - authpath += n; - } - setTreeHeight(addr, (params->h-1)); - leafidx >>= 1; - setTreeIndex(addr, leafidx); - hash_h(root, buffer, pub_seed, addr, n); -} - -/** - * Performs one treehash update on the instance that needs it the most. - * Returns 1 if such an instance was not found - **/ -static char bds_treehash_update(bds_state *state, unsigned int updates, const unsigned char *sk_seed, const xmss_params *params, unsigned char *pub_seed, const uint32_t addr[8]) { - uint32_t i, j; - unsigned int level, l_min, low; - unsigned int h = params->h; - unsigned int k = params->k; - unsigned int used = 0; - - for (j = 0; j < updates; j++) { - l_min = h; - level = h - k; - for (i = 0; i < h - k; i++) { - if (state->treehash[i].completed) { - low = h; - } - else if (state->treehash[i].stackusage == 0) { - low = i; - } - else { - low = treehash_minheight_on_stack(state, params, &(state->treehash[i])); - } - if (low < l_min) { - level = i; - l_min = low; - } - } - if (level == h - k) { - break; - } - treehash_update(&(state->treehash[level]), state, sk_seed, params, pub_seed, addr); - used++; - } - return updates - used; -} - -/** - * Updates the state (typically NEXT_i) by adding a leaf and updating the stack - * Returns 1 if all leaf nodes have already been processed - **/ -static char bds_state_update(bds_state *state, const unsigned char *sk_seed, const xmss_params *params, unsigned char *pub_seed, const uint32_t addr[8]) { - uint32_t ltree_addr[8]; - uint32_t node_addr[8]; - uint32_t ots_addr[8]; - - int n = params->n; - int h = params->h; - int k = params->k; - - int nodeh; - int idx = state->next_leaf; - if (idx == 1 << h) { - return 1; - } - - // only copy layer and tree address parts - memcpy(ots_addr, addr, 12); - // type = ots - setType(ots_addr, 0); - memcpy(ltree_addr, addr, 12); - setType(ltree_addr, 1); - memcpy(node_addr, addr, 12); - setType(node_addr, 2); - - setOTSADRS(ots_addr, idx); - setLtreeADRS(ltree_addr, idx); - - gen_leaf_wots(state->stack+state->stackoffset*n, sk_seed, params, pub_seed, ltree_addr, ots_addr); - - state->stacklevels[state->stackoffset] = 0; - state->stackoffset++; - if (h - k > 0 && idx == 3) { - memcpy(state->treehash[0].node, state->stack+state->stackoffset*n, n); - } - while (state->stackoffset>1 && state->stacklevels[state->stackoffset-1] == state->stacklevels[state->stackoffset-2]) { - nodeh = state->stacklevels[state->stackoffset-1]; - if (idx >> nodeh == 1) { - memcpy(state->auth + nodeh*n, state->stack+(state->stackoffset-1)*n, n); - } - else { - if (nodeh < h - k && idx >> nodeh == 3) { - memcpy(state->treehash[nodeh].node, state->stack+(state->stackoffset-1)*n, n); - } - else if (nodeh >= h - k) { - memcpy(state->retain + ((1 << (h - 1 - nodeh)) + nodeh - h + (((idx >> nodeh) - 3) >> 1)) * n, state->stack+(state->stackoffset-1)*n, n); - } - } - setTreeHeight(node_addr, state->stacklevels[state->stackoffset-1]); - setTreeIndex(node_addr, (idx >> (state->stacklevels[state->stackoffset-1]+1))); - hash_h(state->stack+(state->stackoffset-2)*n, state->stack+(state->stackoffset-2)*n, pub_seed, node_addr, n); - - state->stacklevels[state->stackoffset-2]++; - state->stackoffset--; - } - state->next_leaf++; - return 0; -} - -/** - * Returns the auth path for node leaf_idx and computes the auth path for the - * next leaf node, using the algorithm described by Buchmann, Dahmen and Szydlo - * in "Post Quantum Cryptography", Springer 2009. - */ -static void bds_round(bds_state *state, const unsigned long leaf_idx, const unsigned char *sk_seed, const xmss_params *params, unsigned char *pub_seed, uint32_t addr[8]) -{ - unsigned int i; - unsigned int n = params->n; - unsigned int h = params->h; - unsigned int k = params->k; - - unsigned int tau = h; - unsigned int startidx; - unsigned int offset, rowidx; - unsigned char buf[2 * n]; - - uint32_t ots_addr[8]; - uint32_t ltree_addr[8]; - uint32_t node_addr[8]; - // only copy layer and tree address parts - memcpy(ots_addr, addr, 12); - // type = ots - setType(ots_addr, 0); - memcpy(ltree_addr, addr, 12); - setType(ltree_addr, 1); - memcpy(node_addr, addr, 12); - setType(node_addr, 2); - - for (i = 0; i < h; i++) { - if (! ((leaf_idx >> i) & 1)) { - tau = i; - break; - } - } - - if (tau > 0) { - memcpy(buf, state->auth + (tau-1) * n, n); - // we need to do this before refreshing state->keep to prevent overwriting - memcpy(buf + n, state->keep + ((tau-1) >> 1) * n, n); - } - if (!((leaf_idx >> (tau + 1)) & 1) && (tau < h - 1)) { - memcpy(state->keep + (tau >> 1)*n, state->auth + tau*n, n); - } - if (tau == 0) { - setLtreeADRS(ltree_addr, leaf_idx); - setOTSADRS(ots_addr, leaf_idx); - gen_leaf_wots(state->auth, sk_seed, params, pub_seed, ltree_addr, ots_addr); - } - else { - setTreeHeight(node_addr, (tau-1)); - setTreeIndex(node_addr, leaf_idx >> tau); - hash_h(state->auth + tau * n, buf, pub_seed, node_addr, n); - for (i = 0; i < tau; i++) { - if (i < h - k) { - memcpy(state->auth + i * n, state->treehash[i].node, n); - } - else { - offset = (1 << (h - 1 - i)) + i - h; - rowidx = ((leaf_idx >> i) - 1) >> 1; - memcpy(state->auth + i * n, state->retain + (offset + rowidx) * n, n); - } - } - - for (i = 0; i < ((tau < h - k) ? tau : (h - k)); i++) { - startidx = leaf_idx + 1 + 3 * (1 << i); - if (startidx < 1U << h) { - state->treehash[i].h = i; - state->treehash[i].next_idx = startidx; - state->treehash[i].completed = 0; - state->treehash[i].stackusage = 0; - } - } - } -} - -/* - * Generates a XMSS key pair for a given parameter set. - * Format sk: [(32bit) idx || SK_SEED || SK_PRF || PUB_SEED || root] - * Format pk: [root || PUB_SEED] omitting algo oid. - */ -int xmss_keypair(unsigned char *pk, unsigned char *sk, bds_state *state, xmss_params *params) -{ - unsigned int n = params->n; - // Set idx = 0 - sk[0] = 0; - sk[1] = 0; - sk[2] = 0; - sk[3] = 0; - // Init SK_SEED (n byte), SK_PRF (n byte), and PUB_SEED (n byte) - randombytes(sk+4, 3*n); - // Copy PUB_SEED to public key - memcpy(pk+n, sk+4+2*n, n); - - uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - - // Compute root - treehash_setup(pk, params->h, 0, state, sk+4, params, sk+4+2*n, addr); - // copy root to sk - memcpy(sk+4+3*n, pk, n); - return 0; -} - -/** - * Signs a message. - * Returns - * 1. an array containing the signature followed by the message AND - * 2. an updated secret key! - * - */ -int xmss_sign(unsigned char *sk, bds_state *state, unsigned char *sig_msg, unsigned long long *sig_msg_len, const unsigned char *msg, unsigned long long msglen, const xmss_params *params) -{ - unsigned int h = params->h; - unsigned int n = params->n; - unsigned int k = params->k; - uint16_t i = 0; - - // Extract SK - unsigned long idx = ((unsigned long)sk[0] << 24) | ((unsigned long)sk[1] << 16) | ((unsigned long)sk[2] << 8) | sk[3]; - unsigned char sk_seed[n]; - memcpy(sk_seed, sk+4, n); - unsigned char sk_prf[n]; - memcpy(sk_prf, sk+4+n, n); - unsigned char pub_seed[n]; - memcpy(pub_seed, sk+4+2*n, n); - - // index as 32 bytes string - unsigned char idx_bytes_32[32]; - to_byte(idx_bytes_32, idx, 32); - - unsigned char hash_key[3*n]; - - // Update SK - sk[0] = ((idx + 1) >> 24) & 255; - sk[1] = ((idx + 1) >> 16) & 255; - sk[2] = ((idx + 1) >> 8) & 255; - sk[3] = (idx + 1) & 255; - // -- Secret key for this non-forward-secure version is now updated. - // -- A productive implementation should use a file handle instead and write the updated secret key at this point! - - // Init working params - unsigned char R[n]; - unsigned char msg_h[n]; - unsigned char ots_seed[n]; - uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - - // --------------------------------- - // Message Hashing - // --------------------------------- - - // Message Hash: - // First compute pseudorandom value - prf(R, idx_bytes_32, sk_prf, n); - // Generate hash key (R || root || idx) - memcpy(hash_key, R, n); - memcpy(hash_key+n, sk+4+3*n, n); - to_byte(hash_key+2*n, idx, n); - // Then use it for message digest - h_msg(msg_h, msg, msglen, hash_key, 3*n, n); - - // Start collecting signature - *sig_msg_len = 0; - - // Copy index to signature - sig_msg[0] = (idx >> 24) & 255; - sig_msg[1] = (idx >> 16) & 255; - sig_msg[2] = (idx >> 8) & 255; - sig_msg[3] = idx & 255; - - sig_msg += 4; - *sig_msg_len += 4; - - // Copy R to signature - for (i = 0; i < n; i++) - sig_msg[i] = R[i]; - - sig_msg += n; - *sig_msg_len += n; - - // ---------------------------------- - // Now we start to "really sign" - // ---------------------------------- - - // Prepare Address - setType(ots_addr, 0); - setOTSADRS(ots_addr, idx); - - // Compute seed for OTS key pair - get_seed(ots_seed, sk_seed, n, ots_addr); - - // Compute WOTS signature - wots_sign(sig_msg, msg_h, ots_seed, &(params->wots_par), pub_seed, ots_addr); - - sig_msg += params->wots_par.keysize; - *sig_msg_len += params->wots_par.keysize; - - // the auth path was already computed during the previous round - memcpy(sig_msg, state->auth, h*n); - - if (idx < (1U << h) - 1) { - bds_round(state, idx, sk_seed, params, pub_seed, ots_addr); - bds_treehash_update(state, (h - k) >> 1, sk_seed, params, pub_seed, ots_addr); - } - -/* TODO: save key/bds state here! */ - - sig_msg += params->h*n; - *sig_msg_len += params->h*n; - - //Whipe secret elements? - //zerobytes(tsk, CRYPTO_SECRETKEYBYTES); - - - memcpy(sig_msg, msg, msglen); - *sig_msg_len += msglen; - - return 0; -} - -/** - * Verifies a given message signature pair under a given public key. - */ -int xmss_sign_open(unsigned char *msg, unsigned long long *msglen, const unsigned char *sig_msg, unsigned long long sig_msg_len, const unsigned char *pk, const xmss_params *params) -{ - unsigned int n = params->n; - - unsigned long long i, m_len; - unsigned long idx=0; - unsigned char wots_pk[params->wots_par.keysize]; - unsigned char pkhash[n]; - unsigned char root[n]; - unsigned char msg_h[n]; - unsigned char hash_key[3*n]; - - unsigned char pub_seed[n]; - memcpy(pub_seed, pk+n, n); - - // Init addresses - uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - uint32_t ltree_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - uint32_t node_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - - setType(ots_addr, 0); - setType(ltree_addr, 1); - setType(node_addr, 2); - - // Extract index - idx = ((unsigned long)sig_msg[0] << 24) | ((unsigned long)sig_msg[1] << 16) | ((unsigned long)sig_msg[2] << 8) | sig_msg[3]; - printf("verify:: idx = %lu\n", idx); - - // Generate hash key (R || root || idx) - memcpy(hash_key, sig_msg+4,n); - memcpy(hash_key+n, pk, n); - to_byte(hash_key+2*n, idx, n); - - sig_msg += (n+4); - sig_msg_len -= (n+4); - - // hash message - unsigned long long tmp_sig_len = params->wots_par.keysize+params->h*n; - m_len = sig_msg_len - tmp_sig_len; - h_msg(msg_h, sig_msg + tmp_sig_len, m_len, hash_key, 3*n, n); - - //----------------------- - // Verify signature - //----------------------- - - // Prepare Address - setOTSADRS(ots_addr, idx); - // Check WOTS signature - wots_pkFromSig(wots_pk, sig_msg, msg_h, &(params->wots_par), pub_seed, ots_addr); - - sig_msg += params->wots_par.keysize; - sig_msg_len -= params->wots_par.keysize; - - // Compute Ltree - setLtreeADRS(ltree_addr, idx); - l_tree(pkhash, wots_pk, params, pub_seed, ltree_addr); - - // Compute root - validate_authpath(root, pkhash, idx, sig_msg, params, pub_seed, node_addr); - - sig_msg += params->h*n; - sig_msg_len -= params->h*n; - - for (i = 0; i < n; i++) - if (root[i] != pk[i]) - goto fail; - - *msglen = sig_msg_len; - for (i = 0; i < *msglen; i++) - msg[i] = sig_msg[i]; - - return 0; - - -fail: - *msglen = sig_msg_len; - for (i = 0; i < *msglen; i++) - msg[i] = 0; - *msglen = -1; - return -1; -} - -/* - * Generates a XMSSMT key pair for a given parameter set. - * Format sk: [(ceil(h/8) bit) idx || SK_SEED || SK_PRF || PUB_SEED || root] - * Format pk: [root || PUB_SEED] omitting algo oid. - */ -int xmssmt_keypair(unsigned char *pk, unsigned char *sk, bds_state *states, unsigned char *wots_sigs, xmssmt_params *params) -{ - unsigned int n = params->n; - unsigned int i; - unsigned char ots_seed[params->n]; - // Set idx = 0 - for (i = 0; i < params->index_len; i++) { - sk[i] = 0; - } - // Init SK_SEED (n byte), SK_PRF (n byte), and PUB_SEED (n byte) - randombytes(sk+params->index_len, 3*n); - // Copy PUB_SEED to public key - memcpy(pk+n, sk+params->index_len+2*n, n); - - // Set address to point on the single tree on layer d-1 - uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - setLayerADRS(addr, (params->d-1)); - // Set up state and compute wots signatures for all but topmost tree root - for (i = 0; i < params->d - 1; i++) { - // Compute seed for OTS key pair - treehash_setup(pk, params->xmss_par.h, 0, states + i, sk+params->index_len, &(params->xmss_par), pk+n, addr); - setLayerADRS(addr, (i+1)); - get_seed(ots_seed, sk+params->index_len, n, addr); - wots_sign(wots_sigs + i*params->xmss_par.wots_par.keysize, pk, ots_seed, &(params->xmss_par.wots_par), pk+n, addr); - } - treehash_setup(pk, params->xmss_par.h, 0, states + i, sk+params->index_len, &(params->xmss_par), pk+n, addr); - memcpy(sk+params->index_len+3*n, pk, n); - return 0; -} - -/** - * Signs a message. - * Returns - * 1. an array containing the signature followed by the message AND - * 2. an updated secret key! - * - */ -int xmssmt_sign(unsigned char *sk, bds_state *states, unsigned char *wots_sigs, unsigned char *sig_msg, unsigned long long *sig_msg_len, const unsigned char *msg, unsigned long long msglen, const xmssmt_params *params) -{ - unsigned int n = params->n; - - unsigned int tree_h = params->xmss_par.h; - unsigned int h = params->h; - unsigned int k = params->xmss_par.k; - unsigned int idx_len = params->index_len; - uint64_t idx_tree; - uint32_t idx_leaf; - uint64_t i, j; - int needswap_upto = -1; - unsigned int updates; - - unsigned char sk_seed[n]; - unsigned char sk_prf[n]; - unsigned char pub_seed[n]; - // Init working params - unsigned char R[n]; - unsigned char msg_h[n]; - unsigned char hash_key[3*n]; - unsigned char ots_seed[n]; - uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - unsigned char idx_bytes_32[32]; - bds_state tmp; - - // Extract SK - unsigned long long idx = 0; - for (i = 0; i < idx_len; i++) { - idx |= ((unsigned long long)sk[i]) << 8*(idx_len - 1 - i); - } - - memcpy(sk_seed, sk+idx_len, n); - memcpy(sk_prf, sk+idx_len+n, n); - memcpy(pub_seed, sk+idx_len+2*n, n); - - // Update SK - for (i = 0; i < idx_len; i++) { - sk[i] = ((idx + 1) >> 8*(idx_len - 1 - i)) & 255; - } - // -- Secret key for this non-forward-secure version is now updated. - // -- A productive implementation should use a file handle instead and write the updated secret key at this point! - - - // --------------------------------- - // Message Hashing - // --------------------------------- - - // Message Hash: - // First compute pseudorandom value - to_byte(idx_bytes_32, idx, 32); - prf(R, idx_bytes_32, sk_prf, n); - // Generate hash key (R || root || idx) - memcpy(hash_key, R, n); - memcpy(hash_key+n, sk+idx_len+3*n, n); - to_byte(hash_key+2*n, idx, n); - - // Then use it for message digest - h_msg(msg_h, msg, msglen, hash_key, 3*n, n); - - // Start collecting signature - *sig_msg_len = 0; - - // Copy index to signature - for (i = 0; i < idx_len; i++) { - sig_msg[i] = (idx >> 8*(idx_len - 1 - i)) & 255; - } - - sig_msg += idx_len; - *sig_msg_len += idx_len; - - // Copy R to signature - for (i = 0; i < n; i++) - sig_msg[i] = R[i]; - - sig_msg += n; - *sig_msg_len += n; - - // ---------------------------------- - // Now we start to "really sign" - // ---------------------------------- - - // Handle lowest layer separately as it is slightly different... - - // Prepare Address - setType(ots_addr, 0); - idx_tree = idx >> tree_h; - idx_leaf = (idx & ((1 << tree_h)-1)); - setLayerADRS(ots_addr, 0); - setTreeADRS(ots_addr, idx_tree); - setOTSADRS(ots_addr, idx_leaf); - - // Compute seed for OTS key pair - get_seed(ots_seed, sk_seed, n, ots_addr); - - // Compute WOTS signature - wots_sign(sig_msg, msg_h, ots_seed, &(params->xmss_par.wots_par), pub_seed, ots_addr); - - sig_msg += params->xmss_par.wots_par.keysize; - *sig_msg_len += params->xmss_par.wots_par.keysize; - - memcpy(sig_msg, states[0].auth, tree_h*n); - sig_msg += tree_h*n; - *sig_msg_len += tree_h*n; - - // prepare signature of remaining layers - for (i = 1; i < params->d; i++) { - // put WOTS signature in place - memcpy(sig_msg, wots_sigs + (i-1)*params->xmss_par.wots_par.keysize, params->xmss_par.wots_par.keysize); - - sig_msg += params->xmss_par.wots_par.keysize; - *sig_msg_len += params->xmss_par.wots_par.keysize; - - // put AUTH nodes in place - memcpy(sig_msg, states[i].auth, tree_h*n); - sig_msg += tree_h*n; - *sig_msg_len += tree_h*n; - } - - updates = (tree_h - k) >> 1; - - setTreeADRS(addr, (idx_tree + 1)); - // mandatory update for NEXT_0 (does not count towards h-k/2) if NEXT_0 exists - if ((1 + idx_tree) * (1 << tree_h) + idx_leaf < (1ULL << h)) { - bds_state_update(&states[params->d], sk_seed, &(params->xmss_par), pub_seed, addr); - } - - for (i = 0; i < params->d; i++) { - // check if we're not at the end of a tree - if (! (((idx + 1) & ((1ULL << ((i+1)*tree_h)) - 1)) == 0)) { - idx_leaf = (idx >> (tree_h * i)) & ((1 << tree_h)-1); - idx_tree = (idx >> (tree_h * (i+1))); - setLayerADRS(addr, i); - setTreeADRS(addr, idx_tree); - if (i == (unsigned int) (needswap_upto + 1)) { - bds_round(&states[i], idx_leaf, sk_seed, &(params->xmss_par), pub_seed, addr); - } - updates = bds_treehash_update(&states[i], updates, sk_seed, &(params->xmss_par), pub_seed, addr); - setTreeADRS(addr, (idx_tree + 1)); - // if a NEXT-tree exists for this level; - if ((1 + idx_tree) * (1 << tree_h) + idx_leaf < (1ULL << (h - tree_h * i))) { - if (i > 0 && updates > 0 && states[params->d + i].next_leaf < (1ULL << h)) { - bds_state_update(&states[params->d + i], sk_seed, &(params->xmss_par), pub_seed, addr); - updates--; - } - } - } - else if (idx < (1ULL << h) - 1) { - memcpy(&tmp, states+params->d + i, sizeof(bds_state)); - memcpy(states+params->d + i, states + i, sizeof(bds_state)); - memcpy(states + i, &tmp, sizeof(bds_state)); - - setLayerADRS(ots_addr, (i+1)); - setTreeADRS(ots_addr, ((idx + 1) >> ((i+2) * tree_h))); - setOTSADRS(ots_addr, (((idx >> ((i+1) * tree_h)) + 1) & ((1 << tree_h)-1))); - - get_seed(ots_seed, sk+params->index_len, n, ots_addr); - wots_sign(wots_sigs + i*params->xmss_par.wots_par.keysize, states[i].stack, ots_seed, &(params->xmss_par.wots_par), pub_seed, ots_addr); - - states[params->d + i].stackoffset = 0; - states[params->d + i].next_leaf = 0; - - updates--; // WOTS-signing counts as one update - needswap_upto = i; - for (j = 0; j < tree_h-k; j++) { - states[i].treehash[j].completed = 1; - } - } - } - - //Whipe secret elements? - //zerobytes(tsk, CRYPTO_SECRETKEYBYTES); - - memcpy(sig_msg, msg, msglen); - *sig_msg_len += msglen; - - return 0; -} - -/** - * Verifies a given message signature pair under a given public key. - */ -int xmssmt_sign_open(unsigned char *msg, unsigned long long *msglen, const unsigned char *sig_msg, unsigned long long sig_msg_len, const unsigned char *pk, const xmssmt_params *params) -{ - unsigned int n = params->n; - - unsigned int tree_h = params->xmss_par.h; - unsigned int idx_len = params->index_len; - uint64_t idx_tree; - uint32_t idx_leaf; - - unsigned long long i, m_len; - unsigned long long idx=0; - unsigned char wots_pk[params->xmss_par.wots_par.keysize]; - unsigned char pkhash[n]; - unsigned char root[n]; - unsigned char msg_h[n]; - unsigned char hash_key[3*n]; - - unsigned char pub_seed[n]; - memcpy(pub_seed, pk+n, n); - - // Init addresses - uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - uint32_t ltree_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - uint32_t node_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - - // Extract index - for (i = 0; i < idx_len; i++) { - idx |= ((unsigned long long)sig_msg[i]) << (8*(idx_len - 1 - i)); - } - printf("verify:: idx = %llu\n", idx); - sig_msg += idx_len; - sig_msg_len -= idx_len; - - // Generate hash key (R || root || idx) - memcpy(hash_key, sig_msg,n); - memcpy(hash_key+n, pk, n); - to_byte(hash_key+2*n, idx, n); - - sig_msg += n; - sig_msg_len -= n; - - - // hash message (recall, R is now on pole position at sig_msg - unsigned long long tmp_sig_len = (params->d * params->xmss_par.wots_par.keysize) + (params->h * n); - m_len = sig_msg_len - tmp_sig_len; - h_msg(msg_h, sig_msg + tmp_sig_len, m_len, hash_key, 3*n, n); - - - //----------------------- - // Verify signature - //----------------------- - - // Prepare Address - idx_tree = idx >> tree_h; - idx_leaf = (idx & ((1 << tree_h)-1)); - setLayerADRS(ots_addr, 0); - setTreeADRS(ots_addr, idx_tree); - setType(ots_addr, 0); - - memcpy(ltree_addr, ots_addr, 12); - setType(ltree_addr, 1); - - memcpy(node_addr, ltree_addr, 12); - setType(node_addr, 2); - - setOTSADRS(ots_addr, idx_leaf); - - // Check WOTS signature - wots_pkFromSig(wots_pk, sig_msg, msg_h, &(params->xmss_par.wots_par), pub_seed, ots_addr); - - sig_msg += params->xmss_par.wots_par.keysize; - sig_msg_len -= params->xmss_par.wots_par.keysize; - - // Compute Ltree - setLtreeADRS(ltree_addr, idx_leaf); - l_tree(pkhash, wots_pk, &(params->xmss_par), pub_seed, ltree_addr); - - // Compute root - validate_authpath(root, pkhash, idx_leaf, sig_msg, &(params->xmss_par), pub_seed, node_addr); - - sig_msg += tree_h*n; - sig_msg_len -= tree_h*n; - - for (i = 1; i < params->d; i++) { - // Prepare Address - idx_leaf = (idx_tree & ((1 << tree_h)-1)); - idx_tree = idx_tree >> tree_h; - - setLayerADRS(ots_addr, i); - setTreeADRS(ots_addr, idx_tree); - setType(ots_addr, 0); - - memcpy(ltree_addr, ots_addr, 12); - setType(ltree_addr, 1); - - memcpy(node_addr, ltree_addr, 12); - setType(node_addr, 2); - - setOTSADRS(ots_addr, idx_leaf); - - // Check WOTS signature - wots_pkFromSig(wots_pk, sig_msg, root, &(params->xmss_par.wots_par), pub_seed, ots_addr); - - sig_msg += params->xmss_par.wots_par.keysize; - sig_msg_len -= params->xmss_par.wots_par.keysize; - - // Compute Ltree - setLtreeADRS(ltree_addr, idx_leaf); - l_tree(pkhash, wots_pk, &(params->xmss_par), pub_seed, ltree_addr); - - // Compute root - validate_authpath(root, pkhash, idx_leaf, sig_msg, &(params->xmss_par), pub_seed, node_addr); - - sig_msg += tree_h*n; - sig_msg_len -= tree_h*n; - - } - - for (i = 0; i < n; i++) - if (root[i] != pk[i]) - goto fail; - - *msglen = sig_msg_len; - for (i = 0; i < *msglen; i++) - msg[i] = sig_msg[i]; - - return 0; - - -fail: - *msglen = sig_msg_len; - for (i = 0; i < *msglen; i++) - msg[i] = 0; - *msglen = -1; - return -1; -} -#endif /* WITH_XMSS */ diff --git a/xmss_fast.h b/xmss_fast.h deleted file mode 100644 index 2ffba7057baf..000000000000 --- a/xmss_fast.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifdef WITH_XMSS -/* $OpenBSD: xmss_fast.h,v 1.2 2018/02/26 03:56:44 dtucker Exp $ */ -/* -xmss_fast.h version 20160722 -Andreas Hülsing -Joost Rijneveld -Public domain. -*/ - -#include "xmss_wots.h" - -#ifndef XMSS_H -#define XMSS_H -typedef struct{ - unsigned int level; - unsigned long long subtree; - unsigned int subleaf; -} leafaddr; - -typedef struct{ - wots_params wots_par; - unsigned int n; - unsigned int h; - unsigned int k; -} xmss_params; - -typedef struct{ - xmss_params xmss_par; - unsigned int n; - unsigned int h; - unsigned int d; - unsigned int index_len; -} xmssmt_params; - -typedef struct{ - unsigned int h; - unsigned int next_idx; - unsigned int stackusage; - unsigned char completed; - unsigned char *node; -} treehash_inst; - -typedef struct { - unsigned char *stack; - unsigned int stackoffset; - unsigned char *stacklevels; - unsigned char *auth; - unsigned char *keep; - treehash_inst *treehash; - unsigned char *retain; - unsigned int next_leaf; -} bds_state; - -/** - * Initialize BDS state struct - * parameter names are the same as used in the description of the BDS traversal - */ -void xmss_set_bds_state(bds_state *state, unsigned char *stack, int stackoffset, unsigned char *stacklevels, unsigned char *auth, unsigned char *keep, treehash_inst *treehash, unsigned char *retain, int next_leaf); -/** - * Initializes parameter set. - * Needed, for any of the other methods. - */ -int xmss_set_params(xmss_params *params, int n, int h, int w, int k); -/** - * Initialize xmssmt_params struct - * parameter names are the same as in the draft - * - * Especially h is the total tree height, i.e. the XMSS trees have height h/d - */ -int xmssmt_set_params(xmssmt_params *params, int n, int h, int d, int w, int k); -/** - * Generates a XMSS key pair for a given parameter set. - * Format sk: [(32bit) idx || SK_SEED || SK_PRF || PUB_SEED || root] - * Format pk: [root || PUB_SEED] omitting algo oid. - */ -int xmss_keypair(unsigned char *pk, unsigned char *sk, bds_state *state, xmss_params *params); -/** - * Signs a message. - * Returns - * 1. an array containing the signature followed by the message AND - * 2. an updated secret key! - * - */ -int xmss_sign(unsigned char *sk, bds_state *state, unsigned char *sig_msg, unsigned long long *sig_msg_len, const unsigned char *msg,unsigned long long msglen, const xmss_params *params); -/** - * Verifies a given message signature pair under a given public key. - * - * Note: msg and msglen are pure outputs which carry the message in case verification succeeds. The (input) message is assumed to be within sig_msg which has the form (sig||msg). - */ -int xmss_sign_open(unsigned char *msg,unsigned long long *msglen, const unsigned char *sig_msg,unsigned long long sig_msg_len, const unsigned char *pk, const xmss_params *params); - -/* - * Generates a XMSSMT key pair for a given parameter set. - * Format sk: [(ceil(h/8) bit) idx || SK_SEED || SK_PRF || PUB_SEED || root] - * Format pk: [root || PUB_SEED] omitting algo oid. - */ -int xmssmt_keypair(unsigned char *pk, unsigned char *sk, bds_state *states, unsigned char *wots_sigs, xmssmt_params *params); -/** - * Signs a message. - * Returns - * 1. an array containing the signature followed by the message AND - * 2. an updated secret key! - * - */ -int xmssmt_sign(unsigned char *sk, bds_state *state, unsigned char *wots_sigs, unsigned char *sig_msg, unsigned long long *sig_msg_len, const unsigned char *msg, unsigned long long msglen, const xmssmt_params *params); -/** - * Verifies a given message signature pair under a given public key. - */ -int xmssmt_sign_open(unsigned char *msg, unsigned long long *msglen, const unsigned char *sig_msg, unsigned long long sig_msg_len, const unsigned char *pk, const xmssmt_params *params); -#endif -#endif /* WITH_XMSS */ diff --git a/xmss_hash.c b/xmss_hash.c deleted file mode 100644 index 70c126ae25a3..000000000000 --- a/xmss_hash.c +++ /dev/null @@ -1,137 +0,0 @@ -/* $OpenBSD: xmss_hash.c,v 1.4 2023/12/20 00:06:25 jsg Exp $ */ -/* -hash.c version 20160722 -Andreas Hülsing -Joost Rijneveld -Public domain. -*/ - -#include "includes.h" -#ifdef WITH_XMSS - -#include "xmss_hash_address.h" -#include "xmss_commons.h" -#include "xmss_hash.h" - -#include -#ifdef HAVE_STDINT_H -# include -#endif -#include -#include - -int core_hash_SHA2(unsigned char *, const unsigned int, const unsigned char *, - unsigned int, const unsigned char *, unsigned long long, unsigned int); - -unsigned char* addr_to_byte(unsigned char *bytes, const uint32_t addr[8]){ -#if IS_LITTLE_ENDIAN==1 - int i = 0; - for(i=0;i<8;i++) - to_byte(bytes+i*4, addr[i],4); - return bytes; -#else - memcpy(bytes, addr, 32); - return bytes; -#endif -} - -int core_hash_SHA2(unsigned char *out, const unsigned int type, const unsigned char *key, unsigned int keylen, const unsigned char *in, unsigned long long inlen, unsigned int n){ - unsigned long long i = 0; - unsigned char buf[inlen + n + keylen]; - - // Input is (toByte(X, 32) || KEY || M) - - // set toByte - to_byte(buf, type, n); - - for (i=0; i < keylen; i++) { - buf[i+n] = key[i]; - } - - for (i=0; i < inlen; i++) { - buf[keylen + n + i] = in[i]; - } - - if (n == 32) { - SHA256(buf, inlen + keylen + n, out); - return 0; - } - else { - if (n == 64) { - SHA512(buf, inlen + keylen + n, out); - return 0; - } - } - return 1; -} - -/** - * Implements PRF - */ -int prf(unsigned char *out, const unsigned char *in, const unsigned char *key, unsigned int keylen) -{ - return core_hash_SHA2(out, 3, key, keylen, in, 32, keylen); -} - -/* - * Implements H_msg - */ -int h_msg(unsigned char *out, const unsigned char *in, unsigned long long inlen, const unsigned char *key, const unsigned int keylen, const unsigned int n) -{ - if (keylen != 3*n){ - // H_msg takes 3n-bit keys, but n does not match the keylength of keylen - return -1; - } - return core_hash_SHA2(out, 2, key, keylen, in, inlen, n); -} - -/** - * We assume the left half is in in[0]...in[n-1] - */ -int hash_h(unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8], const unsigned int n) -{ - - unsigned char buf[2*n]; - unsigned char key[n]; - unsigned char bitmask[2*n]; - unsigned char byte_addr[32]; - unsigned int i; - - setKeyAndMask(addr, 0); - addr_to_byte(byte_addr, addr); - prf(key, byte_addr, pub_seed, n); - // Use MSB order - setKeyAndMask(addr, 1); - addr_to_byte(byte_addr, addr); - prf(bitmask, byte_addr, pub_seed, n); - setKeyAndMask(addr, 2); - addr_to_byte(byte_addr, addr); - prf(bitmask+n, byte_addr, pub_seed, n); - for (i = 0; i < 2*n; i++) { - buf[i] = in[i] ^ bitmask[i]; - } - return core_hash_SHA2(out, 1, key, n, buf, 2*n, n); -} - -int hash_f(unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8], const unsigned int n) -{ - unsigned char buf[n]; - unsigned char key[n]; - unsigned char bitmask[n]; - unsigned char byte_addr[32]; - unsigned int i; - - setKeyAndMask(addr, 0); - addr_to_byte(byte_addr, addr); - prf(key, byte_addr, pub_seed, n); - - setKeyAndMask(addr, 1); - addr_to_byte(byte_addr, addr); - prf(bitmask, byte_addr, pub_seed, n); - - for (i = 0; i < n; i++) { - buf[i] = in[i] ^ bitmask[i]; - } - return core_hash_SHA2(out, 0, key, n, buf, n, n); -} -#endif /* WITH_XMSS */ diff --git a/xmss_hash.h b/xmss_hash.h deleted file mode 100644 index d19c62152add..000000000000 --- a/xmss_hash.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifdef WITH_XMSS -/* $OpenBSD: xmss_hash.h,v 1.2 2018/02/26 03:56:44 dtucker Exp $ */ -/* -hash.h version 20160722 -Andreas Hülsing -Joost Rijneveld -Public domain. -*/ - -#ifndef HASH_H -#define HASH_H - -#define IS_LITTLE_ENDIAN 1 - -unsigned char* addr_to_byte(unsigned char *bytes, const uint32_t addr[8]); -int prf(unsigned char *out, const unsigned char *in, const unsigned char *key, unsigned int keylen); -int h_msg(unsigned char *out,const unsigned char *in,unsigned long long inlen, const unsigned char *key, const unsigned int keylen, const unsigned int n); -int hash_h(unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8], const unsigned int n); -int hash_f(unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8], const unsigned int n); - -#endif -#endif /* WITH_XMSS */ diff --git a/xmss_hash_address.c b/xmss_hash_address.c deleted file mode 100644 index 2702c4562bfc..000000000000 --- a/xmss_hash_address.c +++ /dev/null @@ -1,66 +0,0 @@ -/* $OpenBSD: xmss_hash_address.c,v 1.2 2018/02/26 03:56:44 dtucker Exp $ */ -/* -hash_address.c version 20160722 -Andreas Hülsing -Joost Rijneveld -Public domain. -*/ -#include "includes.h" -#ifdef WITH_XMSS - -#ifdef HAVE_STDINT_H -# include -#endif -#include "xmss_hash_address.h" /* prototypes */ - -void setLayerADRS(uint32_t adrs[8], uint32_t layer){ - adrs[0] = layer; -} - -void setTreeADRS(uint32_t adrs[8], uint64_t tree){ - adrs[1] = (uint32_t) (tree >> 32); - adrs[2] = (uint32_t) tree; -} - -void setType(uint32_t adrs[8], uint32_t type){ - adrs[3] = type; - int i; - for(i = 4; i < 8; i++){ - adrs[i] = 0; - } -} - -void setKeyAndMask(uint32_t adrs[8], uint32_t keyAndMask){ - adrs[7] = keyAndMask; -} - -// OTS - -void setOTSADRS(uint32_t adrs[8], uint32_t ots){ - adrs[4] = ots; -} - -void setChainADRS(uint32_t adrs[8], uint32_t chain){ - adrs[5] = chain; -} - -void setHashADRS(uint32_t adrs[8], uint32_t hash){ - adrs[6] = hash; -} - -// L-tree - -void setLtreeADRS(uint32_t adrs[8], uint32_t ltree){ - adrs[4] = ltree; -} - -// Hash Tree & L-tree - -void setTreeHeight(uint32_t adrs[8], uint32_t treeHeight){ - adrs[5] = treeHeight; -} - -void setTreeIndex(uint32_t adrs[8], uint32_t treeIndex){ - adrs[6] = treeIndex; -} -#endif /* WITH_XMSS */ diff --git a/xmss_hash_address.h b/xmss_hash_address.h deleted file mode 100644 index 66bb4cc4d5fa..000000000000 --- a/xmss_hash_address.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifdef WITH_XMSS -/* $OpenBSD: xmss_hash_address.h,v 1.2 2018/02/26 03:56:44 dtucker Exp $ */ -/* -hash_address.h version 20160722 -Andreas Hülsing -Joost Rijneveld -Public domain. -*/ - -#ifdef HAVE_STDINT_H -#include -#endif - -void setLayerADRS(uint32_t adrs[8], uint32_t layer); - -void setTreeADRS(uint32_t adrs[8], uint64_t tree); - -void setType(uint32_t adrs[8], uint32_t type); - -void setKeyAndMask(uint32_t adrs[8], uint32_t keyAndMask); - -// OTS - -void setOTSADRS(uint32_t adrs[8], uint32_t ots); - -void setChainADRS(uint32_t adrs[8], uint32_t chain); - -void setHashADRS(uint32_t adrs[8], uint32_t hash); - -// L-tree - -void setLtreeADRS(uint32_t adrs[8], uint32_t ltree); - -// Hash Tree & L-tree - -void setTreeHeight(uint32_t adrs[8], uint32_t treeHeight); - -void setTreeIndex(uint32_t adrs[8], uint32_t treeIndex); - -#endif /* WITH_XMSS */ diff --git a/xmss_wots.c b/xmss_wots.c deleted file mode 100644 index 993e661f6707..000000000000 --- a/xmss_wots.c +++ /dev/null @@ -1,192 +0,0 @@ -/* $OpenBSD: xmss_wots.c,v 1.3 2018/04/10 00:10:49 djm Exp $ */ -/* -wots.c version 20160722 -Andreas Hülsing -Joost Rijneveld -Public domain. -*/ - -#include "includes.h" -#ifdef WITH_XMSS - -#include -#ifdef HAVE_STDINT_H -# include -#endif -#include -#include "xmss_commons.h" -#include "xmss_hash.h" -#include "xmss_wots.h" -#include "xmss_hash_address.h" - - -/* libm-free version of log2() for wots */ -static inline int -wots_log2(uint32_t v) -{ - int b; - - for (b = sizeof (v) * CHAR_BIT - 1; b >= 0; b--) { - if ((1U << b) & v) { - return b; - } - } - return 0; -} - -void -wots_set_params(wots_params *params, int n, int w) -{ - params->n = n; - params->w = w; - params->log_w = wots_log2(params->w); - params->len_1 = (CHAR_BIT * n) / params->log_w; - params->len_2 = (wots_log2(params->len_1 * (w - 1)) / params->log_w) + 1; - params->len = params->len_1 + params->len_2; - params->keysize = params->len * params->n; -} - -/** - * Helper method for pseudorandom key generation - * Expands an n-byte array into a len*n byte array - * this is done using PRF - */ -static void expand_seed(unsigned char *outseeds, const unsigned char *inseed, const wots_params *params) -{ - uint32_t i = 0; - unsigned char ctr[32]; - for(i = 0; i < params->len; i++){ - to_byte(ctr, i, 32); - prf((outseeds + (i*params->n)), ctr, inseed, params->n); - } -} - -/** - * Computes the chaining function. - * out and in have to be n-byte arrays - * - * interprets in as start-th value of the chain - * addr has to contain the address of the chain - */ -static void gen_chain(unsigned char *out, const unsigned char *in, unsigned int start, unsigned int steps, const wots_params *params, const unsigned char *pub_seed, uint32_t addr[8]) -{ - uint32_t i, j; - for (j = 0; j < params->n; j++) - out[j] = in[j]; - - for (i = start; i < (start+steps) && i < params->w; i++) { - setHashADRS(addr, i); - hash_f(out, out, pub_seed, addr, params->n); - } -} - -/** - * base_w algorithm as described in draft. - * - * - */ -static void base_w(int *output, const int out_len, const unsigned char *input, const wots_params *params) -{ - int in = 0; - int out = 0; - uint32_t total = 0; - int bits = 0; - int consumed = 0; - - for (consumed = 0; consumed < out_len; consumed++) { - if (bits == 0) { - total = input[in]; - in++; - bits += 8; - } - bits -= params->log_w; - output[out] = (total >> bits) & (params->w - 1); - out++; - } -} - -void wots_pkgen(unsigned char *pk, const unsigned char *sk, const wots_params *params, const unsigned char *pub_seed, uint32_t addr[8]) -{ - uint32_t i; - expand_seed(pk, sk, params); - for (i=0; i < params->len; i++) { - setChainADRS(addr, i); - gen_chain(pk+i*params->n, pk+i*params->n, 0, params->w-1, params, pub_seed, addr); - } -} - - -int wots_sign(unsigned char *sig, const unsigned char *msg, const unsigned char *sk, const wots_params *params, const unsigned char *pub_seed, uint32_t addr[8]) -{ - //int basew[params->len]; - int csum = 0; - uint32_t i = 0; - int *basew = calloc(params->len, sizeof(int)); - if (basew == NULL) - return -1; - - base_w(basew, params->len_1, msg, params); - - for (i=0; i < params->len_1; i++) { - csum += params->w - 1 - basew[i]; - } - - csum = csum << (8 - ((params->len_2 * params->log_w) % 8)); - - int len_2_bytes = ((params->len_2 * params->log_w) + 7) / 8; - - unsigned char csum_bytes[len_2_bytes]; - to_byte(csum_bytes, csum, len_2_bytes); - - int csum_basew[params->len_2]; - base_w(csum_basew, params->len_2, csum_bytes, params); - - for (i = 0; i < params->len_2; i++) { - basew[params->len_1 + i] = csum_basew[i]; - } - - expand_seed(sig, sk, params); - - for (i = 0; i < params->len; i++) { - setChainADRS(addr, i); - gen_chain(sig+i*params->n, sig+i*params->n, 0, basew[i], params, pub_seed, addr); - } - free(basew); - return 0; -} - -int wots_pkFromSig(unsigned char *pk, const unsigned char *sig, const unsigned char *msg, const wots_params *params, const unsigned char *pub_seed, uint32_t addr[8]) -{ - int csum = 0; - uint32_t i = 0; - int *basew = calloc(params->len, sizeof(int)); - if (basew == NULL) - return -1; - - base_w(basew, params->len_1, msg, params); - - for (i=0; i < params->len_1; i++) { - csum += params->w - 1 - basew[i]; - } - - csum = csum << (8 - ((params->len_2 * params->log_w) % 8)); - - int len_2_bytes = ((params->len_2 * params->log_w) + 7) / 8; - - unsigned char csum_bytes[len_2_bytes]; - to_byte(csum_bytes, csum, len_2_bytes); - - int csum_basew[params->len_2]; - base_w(csum_basew, params->len_2, csum_bytes, params); - - for (i = 0; i < params->len_2; i++) { - basew[params->len_1 + i] = csum_basew[i]; - } - for (i=0; i < params->len; i++) { - setChainADRS(addr, i); - gen_chain(pk+i*params->n, sig+i*params->n, basew[i], params->w-1-basew[i], params, pub_seed, addr); - } - free(basew); - return 0; -} -#endif /* WITH_XMSS */ diff --git a/xmss_wots.h b/xmss_wots.h deleted file mode 100644 index 1eebf3b215df..000000000000 --- a/xmss_wots.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifdef WITH_XMSS -/* $OpenBSD: xmss_wots.h,v 1.3 2018/02/26 12:14:53 dtucker Exp $ */ -/* -wots.h version 20160722 -Andreas Hülsing -Joost Rijneveld -Public domain. -*/ - -#ifndef WOTS_H -#define WOTS_H - -#ifdef HAVE_STDINT_H -#include "stdint.h" -#endif - -/** - * WOTS parameter set - * - * Meaning as defined in draft-irtf-cfrg-xmss-hash-based-signatures-02 - */ -typedef struct { - uint32_t len_1; - uint32_t len_2; - uint32_t len; - uint32_t n; - uint32_t w; - uint32_t log_w; - uint32_t keysize; -} wots_params; - -/** - * Set the WOTS parameters, - * only m, n, w are required as inputs, - * len, len_1, and len_2 are computed from those. - * - * Assumes w is a power of 2 - */ -void wots_set_params(wots_params *params, int n, int w); - -/** - * WOTS key generation. Takes a 32byte seed for the secret key, expands it to a full WOTS secret key and computes the corresponding public key. - * For this it takes the seed pub_seed which is used to generate bitmasks and hash keys and the address of this WOTS key pair addr - * - * params, must have been initialized before using wots_set params for params ! This is not done in this function - * - * Places the computed public key at address pk. - */ -void wots_pkgen(unsigned char *pk, const unsigned char *sk, const wots_params *params, const unsigned char *pub_seed, uint32_t addr[8]); - -/** - * Takes a m-byte message and the 32-byte seed for the secret key to compute a signature that is placed at "sig". - * - */ -int wots_sign(unsigned char *sig, const unsigned char *msg, const unsigned char *sk, const wots_params *params, const unsigned char *pub_seed, uint32_t addr[8]); - -/** - * Takes a WOTS signature, a m-byte message and computes a WOTS public key that it places at pk. - * - */ -int wots_pkFromSig(unsigned char *pk, const unsigned char *sig, const unsigned char *msg, const wots_params *params, const unsigned char *pub_seed, uint32_t addr[8]); - -#endif -#endif /* WITH_XMSS */ From d41503a5762680e43a8d31e4ec2b9b684028f378 Mon Sep 17 00:00:00 2001 From: User Date: Fri, 9 Jan 2026 11:51:41 -0800 Subject: [PATCH 201/244] add GitHub Copilot files --- .github/agents/merge-upstream.agent.md | 399 ++++++++++++++ .github/instructions/build.instructions.md | 300 +++++++++++ .../getting-started.instructions.md | 28 + .../merge/merge-details.instructions.md | 504 ++++++++++++++++++ .../merge-process-overview.instructions.md | 280 ++++++++++ .../merge/research.instructions.md | 106 ++++ .../repository-overview.instructions.md | 131 +++++ .github/instructions/setup.instructions.md | 86 +++ .github/instructions/testing.instructions.md | 248 +++++++++ .github/tools/Build-OpenSSH.ps1 | 254 +++++++++ .github/tools/Get-CommitGroups.ps1 | 402 ++++++++++++++ .github/tools/Start-OpenSSHBuild.ps1 | 195 +++++++ .github/tools/Test-OpenSSHBuild.ps1 | 262 +++++++++ .github/tools/Test-OpenSSHFunctionality.ps1 | 447 ++++++++++++++++ 14 files changed, 3642 insertions(+) create mode 100644 .github/agents/merge-upstream.agent.md create mode 100644 .github/instructions/build.instructions.md create mode 100644 .github/instructions/getting-started.instructions.md create mode 100644 .github/instructions/merge/merge-details.instructions.md create mode 100644 .github/instructions/merge/merge-process-overview.instructions.md create mode 100644 .github/instructions/merge/research.instructions.md create mode 100644 .github/instructions/repository-overview.instructions.md create mode 100644 .github/instructions/setup.instructions.md create mode 100644 .github/instructions/testing.instructions.md create mode 100644 .github/tools/Build-OpenSSH.ps1 create mode 100644 .github/tools/Get-CommitGroups.ps1 create mode 100644 .github/tools/Start-OpenSSHBuild.ps1 create mode 100644 .github/tools/Test-OpenSSHBuild.ps1 create mode 100644 .github/tools/Test-OpenSSHFunctionality.ps1 diff --git a/.github/agents/merge-upstream.agent.md b/.github/agents/merge-upstream.agent.md new file mode 100644 index 000000000000..a5565b25b883 --- /dev/null +++ b/.github/agents/merge-upstream.agent.md @@ -0,0 +1,399 @@ +--- +name: merge-upstream +description: Assist with merging upstream OpenSSH commits into the PowerShell fork. +tools: + ['vscode', 'execute', 'read', 'edit', 'search', 'web', 'test-server/*', 'agent', 'todo'] +--- +# OpenSSH Upstream Merge Agent + +## Agent Purpose +This agent assists with merging upstream OpenSSH commits into the PowerShell fork (PowerShell/openssh-portable). It handles the complete workflow from environment verification through pull request submission. + +**Note:** This agent has access to specialized MCP (Model Context Protocol) tools that automate commit analysis and CI status checking. When available, use the MCP tools instead of running scripts manually. + +## Agent Capabilities + +### Core Functions +- **Environment verification and setup** +- **Commit group analysis** using Get-CommitGroups MCP tool +- **Incremental cherry-picking** with conflict resolution +- **Windows-specific build system updates** +- **Compilation and testing** +- **Documentation and PR preparation** + +### Key Tools Available + +1. **Get-CommitGroups MCP Tool** - Groups commits by CI presence or success + - **Access**: Available via MCP server (preferred method) + - **MCP Tool Name**: `mcp_pwsh-mcp-server_Get_CommitGroups` + - **Direct Script**: `.github/tools/Get-CommitGroups.ps1` (fallback) + - **Parameters**: + - `GitHubTag` (string, optional): GitHub tag to start from (e.g., "V_10_0_P2") + - `StartCommit` (string, optional): Commit SHA to start from + - `FirstChunkOnly` (boolean, optional): Stop after finding first chunk + - `GroupByCIPresence` (boolean, optional): Group by CI presence instead of CI success + - **Recommended Usage**: Always use `-FirstChunkOnly -GroupByCIPresence` for incremental merging + - **Usage via MCP**: Use the MCP tool function directly - it handles all GitHub API calls + - **Manual Usage**: `Get-Help .\Get-CommitGroups.ps1` for direct script execution + +2. **OpenSSHBuildHelper Module** - Build automation + - Location: `contrib\win32\openssh\OpenSSHBuildHelper.psm1` + - Key cmdlet: `Start-OpenSSHBuild -Configuration Release -NativeHostArch x64` + +3. **Git** - Version control operations + - Cherry-pick: `git cherry-pick start_commit^..end_commit` (inclusive) + - Status: `git status` + - Remotes: `origin`, `upstream-pwsh`, `upstream` + +## Workflow Phases + +### Phase 0: Research and Planning +**Objective:** Understand the merge scope, requirements, and context + +**Steps:** +1. **Read all merge instructions** from `.github/instructions/merge/` folder: + - `merge-process-overview.instructions.md` - Primary merge workflow and process overview + - `research.instructions.md` - Research methodology and analysis requirements + - `merge-details.instructions.md` - Detailed conflict resolution strategies and patterns + +2. **Analyze upstream changes:** + - Review release notes for target version + - Identify breaking changes and new features + - Note security fixes and critical updates + - Assess Windows-specific impact + +3. **Review historical context:** + - Examine previous merge PRs for patterns + - Identify recurring conflict areas + - Note Windows-specific workarounds from past merges + - Document lessons learned from previous merges + +**Success Criteria:** +- All merge instructions read and understood +- Upstream changes analyzed and documented +- Ready to proceed with environment setup + +### Phase 1: Pre-Merge Setup +**Objective:** Verify environment and establish baseline + +**Steps:** +1. Verify Git, PowerShell, Visual Studio are available +2. Confirm repository remotes are configured +3. Identify upstream version/tag to merge +4. Create merge branch: `merge-v-` +5. Perform baseline build on `latestw_all` branch +6. Use Get-CommitGroups with `-FirstChunkOnly -GroupByCIPresence` to get first commit batch + +**Success Criteria:** +- Base branch builds successfully +- First commit group identified (ending with any CI run) +- Merge branch created + +### Phase 2: Incremental Merge +**Objective:** Cherry-pick commits in a single batch ending with a CI run + +**Steps:** +1. **Get first commit batch** using Get-CommitGroups with `-FirstChunkOnly -GroupByCIPresence`: + ```pwsh + # For first batch - start from last merged tag + .github\tools\Get-CommitGroups.ps1 -GitHubTag "V_10_0_P2" -FirstChunkOnly -GroupByCIPresence + + # For subsequent batches - start from last batch's end commit + .github\tools\Get-CommitGroups.ps1 -StartCommit "" -FirstChunkOnly -GroupByCIPresence + + # The tool returns structured data: + # { + # "ChunkNumber": 1, + # "StartCommit": "609fe2c", + # "EndCommit": "6fb728d", + # "StartCommitFull": "609fe2cae2459d721ac11d23cd27b8a94397ef3c", + # "EndCommitFull": "6fb728df50c1afd338cb0223a84ce24579577eff", + # "CommitCount": 12, + # "StartMessage": "upstream: rework the text for -3 to make it clearer", + # "EndMessage": "Run all tests on Cygwin again." + # } + ``` + +2. **Display batch information for verification:** + ```pwsh + Write-Host "Processing Batch $($result.ChunkNumber)" -ForegroundColor Cyan + Write-Host "Commit Range: $($result.StartCommit)..$($result.EndCommit)" -ForegroundColor Gray + Write-Host "Start: [$($result.StartCommit)] $($result.StartMessage)" -ForegroundColor White + Write-Host "End: [$($result.EndCommit)] $($result.EndMessage)" -ForegroundColor Green + Write-Host "Total commits: $($result.CommitCount)" -ForegroundColor Yellow + ``` + +3. **Cherry-pick the batch:** + ```pwsh + git cherry-pick $($result.StartCommitFull)^..$($result.EndCommitFull) + ``` + +4. **Resolve conflicts** following Windows preservation patterns (if conflicts occur) +5. **Stage and continue:** `git add .` then `git cherry-pick --continue` +6. **Repeat steps 4-5** until all commits in batch are applied + +**Conflict Resolution Patterns:** +- **Windows-specific code:** Preserve with `#ifdef WINDOWS` +- **Removed featureand Validation +**Objective:** Build successfully and validate if CI was successful + +**MANDATORY:** Build after each commit batch before proceeding to next batch. + +**Steps:** +1. **Build the merged code:** + ```pwsh + .github\tools\Build-OpenSSH.ps1 -Configuration Release -Architecture x64 + ``` + +2. **If build fails, fix compilation errors:** + - Document all compilation errors from build output + - Fix source code issues (add Windows compatibility defines, update function signatures, add platform guards) + - Update Visual Studio project files (add/remove source files, create projects for new binaries) + - Rebuild until successful + - Commit build fixes with detailed description + +3. **Check if batch ended with successful CI:** + - Inspect the chunk's end commit CI status from Get-CommitGroups output + - Look for commits ending with `CIStatus: "success"` in the detailed output + +4. **If CI was successful, run validation tests:** + ```pwsh + .github\tools\Test-OpenSSHFunctionality.ps1 + ``` + - This test installs service, creates test user, validates SSH connectivity + - If tests fail, fix issues and commit fixes + - **Do not proceed** to next batch until tests pass + +5. **If CI was not successful (or no CI), skip validation:** + - Build success is sufficient to proceed + - Validation will be performed at next successful CI checkpoint + +**Common Build Fixes:** +- Missing source files in .vcxproj files +- Removed files still referenced in projects +- Missing function implementations (add to win32compat) + +**Success Criteria:** +- Clean build with no errors +- All expected binaries generated +- If batch had successful CI: validation tests pass +- If batch had no/failed CI: build success is sufficient + +### Phase 4: Summary and Approval +**Objective:** Summarize changes and get approval before proceeding + +**MANDATORY:** Before proceeding to the next commit batch, provide summary and wait for user approval. + +**Steps:** +1. **Generate batch summary:** + ```markdown + ## Batch Completion Summary + + **Batch:** [StartCommit]..[EndCommit] ( commits) + **End Commit CI Status:** + + ### Changes in this Batch: + - + - + - + + ### Conflicts Resolved: + - : + - : + + ### Build Status: + - Build: ✅ Success / ❌ Failed + - Build fixes applied: + + ### Validation Status: + - Validation tests: ✅ Passed / ⏭️ Skipped (no successful CI) / ❌ Failed + - Test fixes applied: + + ### Next Steps: + - Next batch will start from commit: + - Estimated remaining batches: + + **Ready to proceed to next batch?** + ``` + +2. **Wait for user response:** + - User responds "yes" / "continue" / "proceed" → Continue to Phase 5 + - User responds "no" / "stop" / "wait" → Pause and await further instructions + - User provides feedback → Address concerns and re-summarize + +**Success Criteria:** +- Summary provided with all required information +- User approval received to proceed + +### Phase 5: Iteration +**Objective:** Process remaining commit groups until merge is complete + +**Steps:** +1. **Return to Phase 2** with `-StartCommit` set to previous batch's end commit +2. **Repeat Phases 2-4** for each batch: + - Get next batch with Get-CommitGroups + - Cherry-pick commits + - Build (mandatory) + - Validate (if batch ends with successful CI) + - Summarize and get approval +3. **Continue** until all target commits are merged or HEAD is reached +4. **Perform final comprehensive validation:** + ```pwsh + .github\tools\Test-OpenSSHFunctionality.ps1 + ``` + +**Success Criteria:** +- All commit batches processed +- Build remains stable after each batch +- All successful CI checkpoints validated +- Final validation passes +1. Use Get-CommitGroups MCP tool with `-StartCommit` parameter set to previous batch end commit +2. Repeat Phase 2-4 for next batch +3. Continue until all target commits merged +4. Perform final comprehensive test + +**Success Criteria:** +- All commit groups processed +- Build remains stable after each batch +- Tests pass after each batch + +### Phase 6: Documentation and PR +**Objective:** Document changes and submit for review + +**Steps:** +1. Review all merge commits for clarity +2. Document major conflict resolutions +3. Note any Windows-specific changes +4. Push branch: `git push origin merge-v-` +5. Create PR with comprehensive description +6. Add labels and request reviewers + +**PR Description Template:** +```markdown +## Merge OpenSSH + +This PR merges upstream OpenSSH commits from through . + +### Commit Groups +- Batch 1: to ( commits) +- Batch 2: to ( commits) +... + +### Major Changes +- [List significant upstream changes] + +### Windows-Specific Resolutions +- [List Windows compatibility fixes] +- [List build system updates] + +### Testing +- [x] Builds successfully (x64) +- [x] Service starts and runs +- [x] SSH connections work +- [x] Basic operations verified + +### Known Issues +- [List any known limitations or issues] +``` + +**Success Criteria:** +- PR created with complete description +- All CI checks passing +- Reviewers assigned + +## Decision Points + +### When to Use Commit Groups +- **High complexity merge:** >100 commits, significant changes +- **Medium complexity merge:** 50-100 commits, moderate changes +- **Low complexity merge:** <50 commits, minor changes → single merge OK + +### Conflict Resolution Strategy +**Always preserve:** +- Windows-specific functionality in `#ifdef WINDOWS` blocks +- Security fixes from upstream +- Build system integrity + +**Accept upstream for:** +- Removed deprecated features (e.g., DSA) +- Algorithm updates +- API modernization + +**Combine when:** +- Both sides add different functionality +- Windows needs additional compatibility code +- Upstream changes affect Windows-specific code + +## Key Files to Monitor + +### Frequently Modified +- `config.h` / `config.h.vs` - Configuration defines +- `*.vcxproj` - Visual Studio project files +- `contrib/win32/win32compat/*` - Windows compatibility layer + +### Conflict Hotspots +- Authentication code (`auth*.c`) +- Platform-specific code (`platform*.c`) + +## Recovery Procedures + +### Abort Cherry-Pick +```bash +git cherry-pick --abort +git clean -fd +git reset --hard +``` + +### Restart from Checkpoint +```bash +git checkout merge-v- +git log --oneline -5 # Verify last successful commit +# Continue from there +``` + +### Build Failure Recovery +1. Check build log: `contrib\win32\openssh\OpenSSHReleasex64.log` +2. Search for "error C" or "error LNK" +3. Fix errors in order (compilation before linking) +4. Commit fixes separately for clarity + +## Best Practices + +### Commit Organization +- One logical fix per commit +- Clear commit messages explaining Windows-specific changes +- Reference upstream commit SHAs when applicable + +### Testing Between Batches +- Build after each batch +- Quick smoke test (service start, simple connection) +- Full test only after all batches complete + +### Documentation +- Comment complex conflict resolutions in code +- Note Windows-specific workarounds +- Link to upstream issues/PRs when relevant + +## Success Metrics +- ✅ All commits from target range merged +- ✅ Clean build with no warnings +- ✅ All tests passing +- ✅ SSH service functional +- ✅ PR approved and merged +- ✅ No regressions reported in first 48 hours + +## Reference Links + +### Repository Links +- [Upstream OpenSSH](https://github.com/openssh/openssh-portable) +- [PowerShell Fork](https://github.com/PowerShell/openssh-portable) + +### Instruction Documents (Phase 0 Required Reading) +- [Merge Process Overview](../instructions/merge/merge-process-overview.instructions.md) +- [Research Instructions](../instructions/merge/research.instructions.md) +- [Merge Details Instructions](../instructions/merge/merge-details.instructions.md) + +### Additional Instructions +- [Build Instructions](../instructions/build.instructions.md) +- [Setup Instructions](../instructions/setup.instructions.md) +- [Testing Instructions](../instructions/testing.instructions.md) diff --git a/.github/instructions/build.instructions.md b/.github/instructions/build.instructions.md new file mode 100644 index 000000000000..82f267f30cd9 --- /dev/null +++ b/.github/instructions/build.instructions.md @@ -0,0 +1,300 @@ +--- +applyTo: "**/*" +--- + +# Build Instructions for AI Agents + +## Overview +This document provides comprehensive build instructions for OpenSSH-Portable on Windows, specifically tailored for AI agents performing upstream merges. + +## Prerequisites Verification + +### Check Required Tools +```pwsh +# Verify PowerShell version +$PSVersionTable.PSVersion + +# Verify Visual Studio installation +Get-ChildItem "C:\Program Files*\Microsoft Visual Studio\*\*\MSBuild\Current\Bin\msbuild.exe" + +# Verify Windows SDK +Get-ChildItem "C:\Program Files*\Windows Kits\10\bin" -Directory + +# Verify Git +git --version +``` + +## Build Process + +### Using MCP Build Tools (Recommended) + +The repository includes MCP tools that automate the build, verification, and error analysis process. + +#### Option 1: Build & Verify (Recommended) +```pwsh +# Complete build and verification in one step +.\.github\tools\Build-OpenSSH.ps1 -Configuration Release -Architecture x64 + +# Clean build +.\.github\tools\Build-OpenSSH.ps1 -Configuration Release -Architecture x64 -Clean + +# Debug build +.\.github\tools\Build-OpenSSH.ps1 -Configuration Debug -Architecture x64 +``` + +**Output includes:** +- Build success/failure status +- All 14 expected artifacts verification +- Parsed compilation errors with file/line/code/message +- Build warnings summary +- Build log location + +#### Option 2: Build Only +```pwsh +# Incremental build +.\.github\tools\Start-OpenSSHBuild.ps1 -Configuration Release -Architecture x64 + +# Clean build +.\.github\tools\Start-OpenSSHBuild.ps1 -Configuration Release -Architecture x64 -Clean +``` + +#### Option 3: Test Existing Build +```pwsh +# Test artifacts and parse errors from previous build +.\.github\tools\Test-OpenSSHBuild.ps1 -Configuration Release -Architecture x64 +``` + +### Using PowerShell Module Directly (Alternative) + +If you need direct access to the build module functions: + +#### Step 1: Environment Setup +```pwsh +# Navigate to repository root +cd + +# Import build helper module +Import-Module .\contrib\win32\openssh\OpenSSHBuildHelper.psm1 -Force + +# Verify module loaded +Get-Command -Module OpenSSHBuildHelper +``` + +#### Step 2: Initial Build +```pwsh +Start-OpenSSHBuild -Configuration Release -NativeHostArch x64 +``` + +## Compilation Error Resolution + +### Common Error Categories + +#### 1. Missing Preprocessor Definitions +**Symptoms:** +``` +error C2065: 'SOME_DEFINE': undeclared identifier +``` + +**Resolution:** +```pwsh +# Edit config.h.vs file +notepad .\contrib\win32\openssh\config.h.vs + +# Add missing definitions (example) +#define SOME_DEFINE 1 +``` + +#### 2. Missing Windows Equivalents +**Symptoms:** +``` +error C3861: 'fork': identifier not found +error C3861: 'signal': identifier not found +``` + +**Resolution Pattern:** +```c +// In source file, add Windows compatibility +#ifdef WINDOWS + // Use Windows equivalent or win32compat function + HANDLE process = CreateProcess(...); +#else + // Original Unix code + pid_t pid = fork(); +#endif +``` + +#### 3. Build System Inconsistencies +**Symptoms:** +``` +error MSB3073: The command exited with code 1 +fatal error C1083: Cannot open source file: 'newfile.c' +``` + +**AI Agent Resolution Process:** +1. **Check Makefile changes:** + ```bash + git diff upstream-pwsh/latestw_all upstream/ -- Makefile.in + ``` + +2. **Identify new/removed source files:** + ```bash + # Look for patterns like: + # ssh_SOURCES = ssh.c readconf.c clientloop.c sshtty.c \ + # sshconnect.c sshconnect2.c mux.c newfile.c + ``` + +3. **Update Visual Studio projects:** + ```xml + + + ``` + +4. **Update solution if new binaries added:** + ``` + # Check for new programs in Makefile: + # bin_PROGRAMS = ssh sshd ssh-add ssh-keygen ssh-keyscan ssh-copy-id scp sftp sftp-server ssh-pkcs11-helper ssh-sk-helper ssh-agent new-binary + ``` + +### Step-by-Step Error Resolution + +#### AI Agent Workflow: +1. **Attempt initial build using MCP tool** + ```pwsh + .\.github\tools\Build-OpenSSH.ps1 -Configuration Release -Architecture x64 + ``` +2. **Review structured error output** from Build-OpenSSH tool +3. **Categorize error types** (preprocessor, Windows compatibility, build system) +4. **Apply appropriate resolution strategy** (see error categories above) +5. **Rebuild and verify** using Build-OpenSSH tool again +6. **Commit fixes with detailed message** + +#### Manual Error Analysis Commands (if needed): +```pwsh +# Parse errors manually from log file +.\.github\tools\Test-OpenSSHBuild.ps1 -Configuration Release -Architecture x64 + +# Direct MSBuild with detailed logging +& "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\MSBuild.exe" .\contrib\win32\openssh\Win32-OpenSSH.sln /p:Configuration=Release /p:Platform=x64 /v:detailed +``` + +## Project File Management + +### Understanding the Project Structure +``` +contrib\win32\openssh\ +├── Win32-OpenSSH.sln # Main solution file +├── libssh.vcxproj # Core SSH library +├── ssh.vcxproj # SSH client +├── sshd.vcxproj # SSH server listener handling +├── sshd-auth.vcxproj # SSH server authentication handling +├── sshd-session.vcxproj # SSH server session handling +├── ssh-add.vcxproj # Key agent utility +├── ssh-agent.vcxproj # Authentication agent +├── ssh-keygen.vcxproj # Key generation utility +├── ssh-keyscan.vcxproj # Key scanning utility +└── ssh-pkcs11-helper.vcxproj # SSH PKCS11 helper +└── ssh-shell-host.vcxproj # SSH shell host +└── ssh-sk-helper.vcxproj # SSH SK helper +├── scp.vcxproj # Secure copy +├── sftp.vcxproj # Secure file transfer client +└── sftp-server.vcxproj # Secure file transfer server +``` + +### Adding New Projects (AI Agent Process) +1. **Identify new binary in Makefile:** + ```bash + grep "bin_PROGRAMS\|sbin_PROGRAMS" Makefile.in + ``` + +2. **Check Windows applicability:** + ```bash + # Skip Unix-only binaries like ssh-keysign + # Include utilities that work on Windows + ``` + +3. **Create new project file:** + ```pwsh + # Copy existing similar project + Copy-Item ssh.vcxproj ssh-newutil.vcxproj + ``` + +4. **Update project references:** + ```xml + + + ssh-newutil + ssh-newutil + + ``` + +5. **Add to solution:** + ``` + # Edit Win32-OpenSSH.sln to include new project + ``` + +## Validation and Testing + +### Build Verification Using MCP Tools +```pwsh +# Recommended: Use Build-OpenSSH which includes testing +.\.github\tools\Build-OpenSSH.ps1 -Configuration Release -Architecture x64 + +# Or test an existing build +.\.github\tools\Test-OpenSSHBuild.ps1 -Configuration Release -Architecture x64 +``` + +**Expected Output:** +- Success/failure status +- 14 of 14 artifacts found +- Parsed errors and warnings +- Build log location + +**Expected Artifacts (14 executables):** +- ssh.exe, sshd.exe, sshd-auth.exe, sshd-session.exe +- ssh-agent.exe, ssh-add.exe, ssh-keygen.exe, ssh-keyscan.exe +- scp.exe, sftp.exe, sftp-server.exe +- ssh-pkcs11-helper.exe, ssh-shellhost.exe, ssh-sk-helper.exe + +### Manual Verification (Alternative) +```pwsh +# Check that all expected binaries were built +$buildPath = ".\contrib\win32\openssh\x64\Release" +Get-ChildItem $buildPath -Filter "*.exe" | Select-Object Name + +# Expected outputs: +# a binary for each vcxproj file, e.g. +# ssh.vcxproj -> ssh.exe +``` + +### Quick Functionality Test +```pwsh +# Verify version reporting +& ".\contrib\win32\openssh\x64\Release\ssh.exe" -V +``` + +## Troubleshooting Guide + +### Build Helper Module Issues +```pwsh +# Force reload module +Remove-Module OpenSSHBuildHelper -Force -ErrorAction SilentlyContinue +Import-Module .\contrib\win32\openssh\OpenSSHBuildHelper.psm1 -Force +``` + +### Path and Environment Issues +```pwsh +# Verify Visual Studio environment +& "${env:ProgramFiles}\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\VsDevCmd.bat" + +# Check MSBuild path +where.exe msbuild +``` + +### Permission Issues +```pwsh +# Ensure running as Administrator if needed +if (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) +{ + Write-Warning "Build may require Administrator privileges" +} +``` diff --git a/.github/instructions/getting-started.instructions.md b/.github/instructions/getting-started.instructions.md new file mode 100644 index 000000000000..d4f064517e42 --- /dev/null +++ b/.github/instructions/getting-started.instructions.md @@ -0,0 +1,28 @@ +### 🔧 General Repository Instructions +These instructions apply to any task involving the OpenSSH-Portable repository: + +- **[repository-overview.instructions.md](./repository-overview.instructions.md)** - Repository structure and Windows compatibility layer overview +- **[setup.instructions.md](./setup.instructions.md)** - Repository setup and environment configuration +- **[build.instructions.md](./build.instructions.md)** - Compilation procedures and error resolution +- **[testing.instructions.md](./testing.instructions.md)** - Validation and testing procedures + +### 🔀 Upstream Merge Task Instructions +These instructions are specific to performing upstream merges from openssh/openssh-portable: + +- **[merge/merge-process-overview.instructions.md](./merge/merge-process-overview.instructions.md)** - Primary merge workflow and process overview +- **[merge/merge-details.instructions.md](./merge/merge-details.instructions.md)** - Detailed conflict resolution strategies and patterns +- **[merge/research.instructions.md](./merge/research.instructions.md)** - Intelligence gathering and analysis procedures + +## Quick Start Guide + +### For Human Developers +1. Read [merge/merge-process-overview.instructions.md](./merge/merge-process-overview.instructions.md) for complete merge workflow overview +2. Follow phase-by-phase process +3. Reference general repository instructions ([setup](./setup.instructions.md), [build](./build.instructions.md), [testing](./testing.instructions.md)) as needed + +### For AI Agents +1. **Start here:** [merge/merge-process-overview.instructions.md](./merge/merge-process-overview.instructions.md) +2. **Understand the repository:** Review general instructions for setup, build, and testing procedures +3. **Follow systematic approach:** Check off each merge item before proceeding +4. **Use automation:** Leverage provided scripts in `tools/` directory +5. **Escalate if needed:** Document blockers and seek human guidance when complexity exceeds capabilities diff --git a/.github/instructions/merge/merge-details.instructions.md b/.github/instructions/merge/merge-details.instructions.md new file mode 100644 index 000000000000..b2214858543c --- /dev/null +++ b/.github/instructions/merge/merge-details.instructions.md @@ -0,0 +1,504 @@ +--- +applyTo: "**/*" +--- + +# Merge Instructions for AI Agents + +## Overview +This AI-specific documentation provides comprehensive instructions and algorithmic frameworks that AI agents can use to systematically approach the OpenSSH merge process with minimal human intervention while maintaining high quality and consistency. It combines conflict resolution strategies with automated decision-making processes. + +**Key Approach: Chunked Merging** +Instead of merging entire upstream versions at once, this framework implements a chunked approach that: +- Processes commits in small batches ending with commits that have any CI run (successful or not) +- Groups commits by CI presence rather than CI success for more frequent checkpoints +- Builds after each batch (mandatory) +- Validates functionality only at successful CI checkpoints +- Requires user approval before proceeding to next batch +- Allows for incremental progress and easier rollback +- Reduces complexity of conflict resolution +- Enables better testing and validation at each step + +## Decision Framework for AI Agents + +### Pre-Merge Analysis Algorithm +```pseudocode +FUNCTION analyze_upstream_changes(target_version): + // Step 1: Find last merged commit and determine range + last_upstream_commit = find_last_upstream_commit_in_fork() + commit_range = get_commit_range(last_upstream_commit, target_version) + + // Step 2: Fetch and analyze release notes + release_notes = fetch_release_notes(target_version) + risk_factors = [] + + FOR EACH change IN release_notes: + IF change.contains(["signal", "fork", "pipe", "process", "daemon", "service"]): + risk_factors.append({type: "PROCESS_MANAGEMENT", change: change}) + IF change.contains(["auth", "pam", "kerberos", "gssapi"]): + risk_factors.append({type: "AUTHENTICATION", change: change}) + IF change.contains(["build", "makefile", "configure", "autotools"]): + risk_factors.append({type: "BUILD_SYSTEM", change: change}) + IF change.contains(["security", "cve", "vulnerability"]): + risk_factors.append({type: "SECURITY", change: change, priority: "HIGH"}) +``` + +### Conflict Resolution Decision Tree +```pseudocode +FUNCTION resolve_conflict(file_path, conflict_content): + conflict_type = analyze_conflict_type(conflict_content) + + SWITCH conflict_type: + CASE "SECURITY_FIX": + // Always accept upstream security fixes + RETURN accept_upstream(conflict_content) + + CASE "BUILD_SYSTEM_CHANGE": + // Need to update Visual Studio projects + upstream_changes = extract_upstream_changes(conflict_content) + RETURN combine_with_windows_build_system(upstream_changes) + + CASE "PROCESS_MANAGEMENT": + // Unix fork/exec vs Windows CreateProcess + IF contains_fork_or_exec(conflict_content): + RETURN wrap_with_platform_ifdef(conflict_content) + ELSE: + RETURN analyze_compatibility(conflict_content) + + CASE "AUTHENTICATION": + // PAM/Kerberos vs Windows auth + RETURN preserve_windows_auth_with_upstream_features(conflict_content) + + CASE "CONFIGURATION": + // config.h vs config.h.vs changes + new_defines = extract_new_defines(conflict_content) + RETURN update_config_h_vs(new_defines) + + DEFAULT: + // Use historical pattern matching + similar_resolutions = find_similar_conflicts(file_path, conflict_content) + RETURN apply_similar_resolution_pattern(similar_resolutions[0]) +``` + +## Information Sources and Analysis + +### Primary References +- [Upstream release notes](https://www.openssh.com/releasenotes.html) - Pay special attention when merging new versions +- [Previous merge PRs](./research.instructions.md) - Review conflict resolution patterns +- Commit history and messages - Use `git log --oneline upstream/` to understand changes +- Local repository file comparison - Use 3-way diff tools + +### Analysis Commands +```pwsh +# View commit details for understanding changes +git show + +# Compare files between branches +git diff upstream-pwsh/latestw_all upstream/ -- +``` + +## Conflict Resolution Strategies + +### 1. Taking Upstream Changes +**When to use:** Security fixes, bug fixes, feature improvements that don't conflict with Windows functionality. + +```c +// Example: Accept upstream security patch +<<<<<<< HEAD +// Windows-specific code +======= +// New upstream security fix +>>>>>>> upstream/V_X_Y_PZ +``` +**Resolution:** Take the upstream change completely. + +### 2. Combining Changes with Preprocessor Directives +**When to use:** Upstream changes that conflict with Windows-specific functionality but both are needed. + +```c +// Example: Combining platform-specific implementations +#ifdef WINDOWS + // Windows-specific implementation + return windows_specific_function(); +#else + // Upstream Unix implementation + return unix_specific_function(); +#endif /* WINDOWS */ +``` + +### 3. Excluding Changes with #ifndef WINDOWS +**When to use:** Upstream changes are not applicable to Windows or would break Windows functionality. + +```c +// Example: Excluding Unix-only functionality +#ifndef WINDOWS + // Unix-only code that doesn't apply to Windows + setup_unix_specific_feature(); +#endif /* !WINDOWS */ +``` + +## Automated Conflict Resolution Patterns + +### Pattern 1: Platform-Specific Code Wrapping +```c +// Input conflict: +<<<<<<< HEAD +void windows_specific_function() { + // Windows implementation +} +======= +void unix_specific_function() { + // New upstream Unix implementation +} +>>>>>>> upstream/version + +// AI Resolution: +#ifdef WINDOWS +void windows_specific_function() { + // Windows implementation +} +#else +void unix_specific_function() { + // New upstream Unix implementation +} +#endif /* WINDOWS */ +``` + +### Pattern 2: Configuration File Updates +```pseudocode +FUNCTION update_config_h_vs(upstream_config_changes): + config_vs_path = "./contrib/win32/openssh/config.h.vs" + current_config = read_file(config_vs_path) + + FOR EACH define IN upstream_config_changes: + IF define.is_windows_compatible(): + IF define NOT IN current_config: + add_define_to_config_vs(define, determine_windows_value(define)) + ELSE: + // Add comment explaining why it's not included + add_comment_to_config_vs(f"// {define.name} - Unix only, not applicable to Windows") + + write_file(config_vs_path, current_config) +``` + +### Pattern 3: Build System Synchronization +```pseudocode +FUNCTION sync_build_system(): + makefile_changes = get_makefile_changes() + + FOR EACH binary IN makefile_changes.new_binaries: + IF binary.is_windows_applicable(): + create_visual_studio_project(binary) + add_to_solution_file(binary) + ELSE: + log(f"Skipping {binary} - Unix only") + + FOR EACH binary IN makefile_changes.removed_binaries: + remove_visual_studio_project(binary) + remove_from_solution_file(binary) + + FOR EACH source_file IN makefile_changes.new_source_files: + target_project = determine_target_project(source_file) + add_source_to_project(target_project, source_file) +``` + +## Common Conflict Patterns + +### File System Operations +- **Fork/exec calls** → Use Windows process creation APIs +- **Signal handling** → Use Windows event mechanisms +- **File permissions** → Adapt to Windows ACL model + +### Build System Changes +- **Makefile additions** → Update Visual Studio project files +- **New dependencies** → Check Windows compatibility +- **Compiler flags** → Translate to MSVC equivalents + +### Configuration Changes +- **New config options** → Add to `./contrib/win32/openssh/config.h.vs` +- **Feature detection** → Verify Windows support +- **Default values** → Adjust for Windows environment + +## Resolution Workflow + +### For Each Conflict: +1. **Analyze the change** + ```bash + git show upstream/ -- + ``` + +2. **Check previous resolutions** + - Search previous merge PRs for similar conflicts + - Look for patterns in Windows-specific handling + +3. **Choose resolution strategy** + - Upstream change: Complete replacement + - Combined: Add preprocessor directives + - Excluded: Use `#ifndef WINDOWS` + +4. **Test the resolution** + - Ensure code compiles + - Verify simple ssh connection to local host works + - Check that upstream functionality is preserved where applicable + +5. **Document the decision** + - Add comments explaining the Windows-specific handling + - Note in commit message why this approach was chosen + +## Build Validation Automation + +### Iterative Build and Fix Process +```pseudocode +FUNCTION automated_build_fix(): + MAX_ITERATIONS = 10 + iteration = 0 + + WHILE iteration < MAX_ITERATIONS: + build_result = attempt_build() + + IF build_result.success: + RETURN SUCCESS + + errors = parse_build_errors(build_result.output) + fixes_applied = [] + + FOR EACH error IN errors: + fix = determine_fix_strategy(error) + IF fix: + apply_fix(fix) + fixes_applied.append(fix) + + IF fixes_applied.empty(): + RETURN MANUAL_INTERVENTION_REQUIRED + + commit_build_fixes(fixes_applied, f"Build fixes iteration {iteration + 1}") + iteration += 1 + + RETURN MAX_ITERATIONS_EXCEEDED + +FUNCTION determine_fix_strategy(error): + SWITCH error.type: + CASE "MISSING_INCLUDE": + RETURN add_windows_include(error.missing_header) + CASE "UNDEFINED_FUNCTION": + RETURN add_windows_equivalent(error.function_name) + CASE "MISSING_DEFINE": + RETURN add_to_config_h_vs(error.define_name) + CASE "MISSING_SOURCE_FILE": + RETURN add_source_to_project(error.file_name) + DEFAULT: + RETURN null +``` + +## Testing Automation Framework + +### Automated Test Execution +```pseudocode +FUNCTION execute_test_suite(): + test_results = {} + + // Phase 1: Build verification + test_results["build"] = verify_build_artifacts() + IF NOT test_results["build"].success: + RETURN test_results + + // Phase 2: Service setup + test_results["service_setup"] = setup_ssh_service() + IF NOT test_results["service_setup"].success: + RETURN test_results + + // Phase 3: Basic connectivity + test_results["connectivity"] = test_basic_ssh_connection() + + // Cleanup + cleanup_test_environment() + + RETURN test_results + +FUNCTION generate_test_report(test_results): + report = "# Automated Test Results\n\n" + + FOR EACH category, result IN test_results: + status = result.success ? "✅ PASS" : "❌ FAIL" + report += f"## {category}: {status}\n" + + IF NOT result.success: + report += f"Error: {result.error}\n" + report += f"Suggested Fix: {result.suggested_fix}\n" + + RETURN report +``` + +## Error Recovery Strategies + +### Automatic Rollback Points +```pseudocode +FUNCTION create_checkpoint(phase_name): + current_commit = get_current_commit_hash() + checkpoints[phase_name] = current_commit + tag_commit(f"checkpoint-{phase_name}", current_commit) + +FUNCTION rollback_to_checkpoint(phase_name): + IF phase_name IN checkpoints: + reset_to_commit(checkpoints[phase_name]) + RETURN SUCCESS + ELSE: + RETURN CHECKPOINT_NOT_FOUND + +// Usage in main workflow +create_checkpoint("pre-merge") +execute_merge() + +IF merge_conflicts_too_complex(): + rollback_to_checkpoint("pre-merge") + request_manual_intervention() +``` + +### Conflict Complexity Assessment +```pseudocode +FUNCTION assess_conflict_complexity(conflicts): + complexity_score = 0 + + FOR EACH conflict IN conflicts: + // File-based scoring + IF conflict.file.ends_with(".c", ".h"): + complexity_score += 2 + IF conflict.file.contains("auth", "pam", "kerberos"): + complexity_score += 5 + IF conflict.file == "config.h": + complexity_score += 3 + + // Content-based scoring + lines_in_conflict = conflict.content.split('\n').length + complexity_score += lines_in_conflict * 0.1 + + // Pattern-based scoring + IF conflict.content.contains("fork", "exec", "signal"): + complexity_score += 10 + IF conflict.content.contains("WIN32", "WINDOWS", "#ifdef"): + complexity_score -= 2 // Already has platform guards + + IF complexity_score > 50: + RETURN "HIGH_COMPLEXITY" + ELIF complexity_score > 20: + RETURN "MEDIUM_COMPLEXITY" + ELSE: + RETURN "LOW_COMPLEXITY" +``` + +## Anti-Patterns to Avoid + +### ❌ Don't Remove Upstream Code +```c +// WRONG: This will cause future merge conflicts +// Completely removing upstream additions +``` + +### ❌ Don't Modify Upstream Logic Without Guards +```c +// WRONG: Modifying upstream code without preprocessor protection +upstream_function_with_windows_modifications(); +``` + +### ✅ Do Use Preprocessor Guards +```c +// CORRECT: Preserve upstream code with conditional compilation +#ifdef WINDOWS + windows_alternative(); +#else + upstream_function(); +#endif +``` + +## Progress Tracking and Reporting + +### Automated Progress Updates +```pseudocode +FUNCTION update_progress(phase, status, details): + progress_entry = { + timestamp: current_timestamp(), + phase: phase, + status: status, // SUCCESS, FAILURE, IN_PROGRESS + details: details, + commit_hash: get_current_commit_hash() + } + + append_to_progress_log(progress_entry) + + IF status == "FAILURE": + generate_failure_report(phase, details) + suggest_recovery_actions(phase, details) + +FUNCTION generate_merge_summary(): + summary = { + total_conflicts: count_resolved_conflicts(), + build_iterations: count_build_fix_iterations(), + test_results: get_final_test_results(), + time_elapsed: calculate_total_time(), + commits_created: count_commits_since_start(), + complexity_rating: assess_overall_complexity() + } + + RETURN format_summary_report(summary) +``` + +## Integration with Development Workflow + +### Pull Request Preparation +```pseudocode +FUNCTION prepare_pull_request(): + // Generate comprehensive commit history + commit_history = get_commits_since_branch_creation() + + // Create PR description + pr_description = f""" +# Merge OpenSSH {target_version} to Windows Fork + +## Summary +{generate_merge_summary()} + +## Conflict Resolutions +{generate_conflict_resolution_summary()} + +## Testing Results +{generate_test_report(final_test_results)} + +## Files Modified +{list_modified_files()} + +## Breaking Changes +{identify_breaking_changes()} +""" + + RETURN { + title: f"Merge upstream OpenSSH {target_version}", + description: pr_description, + labels: ["upstream-merge", determine_complexity_label()], + assignees: get_default_reviewers() + } +``` + +## Commit Message Template + +``` +Resolve merge conflicts for + +Major conflict resolutions: +- : Combined upstream with Windows using #ifdef +- : Excluded upstream with #ifndef WINDOWS due to +- : Accepted upstream completely + +Reasoning: +``` + +## Troubleshooting + +### If Unsure About a Conflict: +1. Check if the upstream change addresses a CVE or security issue (prioritize) +2. Look for similar code patterns elsewhere in the Windows codebase +3. Consult the OpenSSH-portable issue tracker for context +4. When in doubt, use conditional compilation to preserve both approaches + +### Testing Your Resolution: +- Build the project after each major conflict resolution +- Run ssh connection to local host to ensure basic functionality +- Check that removed functionality wasn't critical to Windows operation \ No newline at end of file diff --git a/.github/instructions/merge/merge-process-overview.instructions.md b/.github/instructions/merge/merge-process-overview.instructions.md new file mode 100644 index 000000000000..34f4b413a6b5 --- /dev/null +++ b/.github/instructions/merge/merge-process-overview.instructions.md @@ -0,0 +1,280 @@ +--- +applyTo: "**/*" +--- + +# OpenSSH-Portable: Merge From Upstream Instructions + +## Overview +This documentation provides comprehensive instructions for merging OpenBSD's OpenSSH-Portable changes into the PowerShell team's Windows-compatible fork. It is designed to be used by both human developers and AI agents to complete a full merge process that results in a ready-to-merge Pull Request. + +## Prerequisites +Ensure the following tools are installed and configured before proceeding: +- **Git** +- **PowerShell** +- **Visual Studio** with: + - Latest C/C++ development tools + - Latest Windows 10/11 SDK + +## Process Overview +The merge process uses a **chunked approach** to reduce complexity and improve success rates. Instead of merging entire upstream versions at once, commits are processed in small batches ending with commits that have CI runs. Each batch is built and optionally validated before proceeding to the next. + +The process consists of several interconnected phases: + +1. **[Setup Phase](#setup-phase)** - Repository configuration and preparation +2. **[Research Phase](#research-phase)** - Understanding changes and conflicts +3. **[Merge Phase](#merge-phase)** - Performing chunked commit merging +4. **[Build Phase](#build-phase)** - Resolving compilation issues +5. **[Testing Phase](#testing-phase)** - Validating functionality +6. **[Submission Phase](#submission-phase)** - Creating the Pull Request + +## Setup Phase + +**📖 Detailed Instructions:** [Setup Instructions](../setup.instructions.md) + +**Quick Overview:** +1. Clone your fork of the openssh-portable repository +2. Configure upstream remotes (PowerShell team fork + original OpenSSH) +3. Fetch latest changes + +## Research Phase + +**📖 Detailed Instructions:** [Research Instructions](./research.instructions.md) + +**Key Resources:** +- **Upstream Release Notes:** [OpenSSH Release Notes](https://www.openssh.com/releasenotes.html) +- **Previous Merge PRs:** such as https://github.com/PowerShell/openssh-portable/pull/737 + +## Merge Phase + +### Initial Preparation +1. **Checkout base branch:** + ```pwsh + git checkout upstream-pwsh/latestw_all + ``` + +2. **Verify baseline build** + **(📖 Detailed Instructions:** [Build Instructions](../build.instructions.md)): + ```pwsh + Import-Module .\contrib\win32\openssh\OpenSSHBuildHelper.psm1 -Force + Start-OpenSSHBuild -Configuration Release -NativeHostArch x64 + ``` + +3. **Configure git:** + ```pwsh + git config core.editor true + ``` + +3. **Create merge branch:** + ```pwsh + git checkout -b merge-v- + # Example: merge-v9.8-20241010 + ``` + +### Perform Merge with Grouped Commits +4. **Identify merge range and group commits:** + Use .\tools\Get-CommitGroups.ps1 with `-FirstChunkOnly -GroupByCIPresence` + ```pwsh + # Find the last upstream tag in the fork (this is the starting point for the next merge) + # Call .\tools\Get-CommitGroups.ps1 -GitHubTag -FirstChunkOnly -GroupByCIPresence + # This gets commits ending with any commit that has CI runs (not just successful CI) + # Example output: + # { + # "ChunkNumber": 1, + # "StartCommit": "609fe2c", + # "EndCommit": "6fb728d", + # "StartCommitFull": "609fe2cae2459d721ac11d23cd27b8a94397ef3c", + # "EndCommitFull": "6fb728df50c1afd338cb0223a84ce24579577eff", + # "CommitCount": 57, + # "StartMessage": "upstream: rework the text for -3 to make it clearer what default", + # "EndMessage": "Run all tests on Cygwin again." + # } + + # Print the commit batch details for verification + Write-Host "Processing batch: $($result.StartCommit)..$($result.EndCommit)" + Write-Host "Start: $($result.StartMessage)" + Write-Host "End: $($result.EndMessage)" + Write-Host "End Commit CI Status: $($result.EndCommit has CI runs)" + + # After completing steps below, get next batch: + # Call .\tools\Get-CommitGroups.ps1 -StartCommit -FirstChunkOnly -GroupByCIPresence + # Continue this process untiland + # follow the below steps to completion until the upstream's HEAD has been successfully merged + ``` + +5. **Execute chunked merge (commit-by-commit within the chunk):** + + **Important:** Even though commits are *grouped* into chunks for planning/CI boundaries, **cherry-pick each commit individually** within the chunk and **build after each commit**. This catches Windows-specific build breaks early and makes it clear which upstream commit introduced a regression. + + ```pwsh + # For each chunk (start..end), enumerate and cherry-pick commits one at a time. + # Then build after EACH commit. + # + # Example for a single chunk: + $chunkStart = $result.StartCommitFull + $chunkEnd = $result.EndCommitFull + $commits = git rev-list --reverse "$chunkStart^..$chunkEnd" + + foreach ($commit in $commits) { + Write-Host "Cherry-picking commit: $commit" + git cherry-pick $commit + + # Build after every commit so we can attribute failures precisely. + # Prefer the MCP build helper if available; otherwise use Start-OpenSSHBuild. + .\.github\tools\Build-OpenSSH.ps1 -Configuration Release -Architecture x64 + } + ``` + +7. **Resolve merge conflicts (per commit):** + **📖 Detailed Instructions** ([Merge Details](./merge-details.instructions.md)): + + - Resolve conflicts for the current commit only + - Use three-way comparison tools + - Follow established Windows compatibility patterns + - Reference previous merge PRs for similar conflicts + +8. **Continue cherry-picking after resolution:** + ```pwsh + # After resolving conflicts for current commit + git add . + git cherry-pick --continue + + # Then continue with remaining commits in batch + # Repeat process for next batch if needed + ``` + +9. **Build after completing the batch:** + ```pwsh + .\.github\tools\Build-OpenSSH.ps1 -Configuration Release -Architecture x64 + + # If build fails, fix issues and rebuild + # Commit any build fixes separately + ``` + +10. **Validate if batch ended with successful CI:** + ```pwsh + # Check the end commit's CI status from Get-CommitGroups output + # If CI was successful, run validation: + .\.github\tools\Test-OpenSSHFunctionality.ps1 + + # If no CI or failed CI, skip validation (build success is sufficient) + ``` + +11. **Provide summary and get approval:** + - Summarize batch changes, conflicts resolved, build status, validation status + - Wait for user approval before proceeding to next batch + - Document next steps (starting commit for next batch) +--- + +## Build Phase + +**📖 Detailed Instructions:** [Build Instructions](../build.instructions.md) + +7. **Initial build attempt:** + ```pwsh + Start-OpenSSHBuild -Configuration Release -NativeHostArch x64 + ``` + +8. **Resolve compilation errors (iterative process):** + + **Common Areas to Check:** + - **config.h.vs updates:** New preprocessor definitions + - **Function signatures:** Windows equivalents for Unix functions + - **Build system changes:** Makefile vs Visual Studio projects + - **New dependencies:** Windows compatibility verification + +9. **Update Visual Studio projects:** + - Check Makefile for added/removed binaries + - Create/update .vcxproj files as needed + - Update Win32-OpenSSH.sln solution file + - Ensure Windows-applicable binaries only + +10. **Commit build fixes:** + ```pwsh + git commit -m "Fix compilation errors for + + Changes: + - Updated config.h.vs with + - Added Windows equivalent for + - Updated project files for " + ``` + +--- + +## Testing Phase + +**📖 Detailed Instructions:** [Testing Instructions](../testing.instructions.md) + +11. **Basic functionality test:** + ```pwsh + # Set up SSH service (see testing.instructions.md) + ssh.exe @localhost + ``` + +12. **Troubleshoot connection issues:** + - Enable verbose logging + - Check service configuration + - Use debugger if necessary + - Verify certificate/key handling + +13. **Commit any test fixes:** + ```pwsh + git commit -m "Fix runtime issues for + + Issues resolved: + - " + ``` + +--- + +## Submission Phase + +### Creating the Pull Request +14. **Push to fork:** + ```pwsh + git push origin merge-v- + ``` + +15. **Create Pull Request:** + - Target: `PowerShell/openssh-portable:latestw_all` + - Title: `Merge upstream OpenSSH ` + - Include comprehensive description of changes and resolutions + +16. **Address CI/test failures:** + - Monitor automated tests + - Fix any Windows-specific test failures + - Ensure all checks pass + +17. **Request review:** + - Tag appropriate PowerShell team reviewers + - Provide context for complex conflict resolutions + +--- + +## Success Criteria + +**The merge is complete when:** +- [ ] All merge conflicts resolved with documented reasoning +- [ ] Solution builds successfully on Windows +- [ ] Basic SSH connection test passes +- [ ] All CI tests pass +- [ ] PR approved and ready for merge + +--- + +## AI Agent Resources + +AI agents should utilize these additional resources: + +- **[Reference Analysis](./research.instructions.md)** - Intelligence gathering protocols +- **[Merge Details](./merge-details.instructions.md)** - Comprehensive merge process, conflict resolution, and automation algorithms +- **[Testing Instructions](../testing.instructions.md)** - Detailed validation procedures + +**For AI Agents:** +1. **Start with this overview** - Follow the phases and track progress commit-by-commit +2. **Follow decision trees** - Refer to AI agent instructions for algorithmic guidance +3. **Document everything** - Maintain detailed commit messages and resolution rationale +4. **Use automated testing** - Leverage provided test scripts for validation +5. **Escalate when needed** - If complexity exceeds capabilities, document and request human intervention + +**Success Criteria Check:** +The merge process is successful when an AI agent can complete all phases independently and produce a Pull Request that meets all quality standards without human intervention. diff --git a/.github/instructions/merge/research.instructions.md b/.github/instructions/merge/research.instructions.md new file mode 100644 index 000000000000..f8b8c5032d5c --- /dev/null +++ b/.github/instructions/merge/research.instructions.md @@ -0,0 +1,106 @@ +--- +applyTo: "**/*" +--- + +# References for AI Agents + +## AI Agent Instructions +This file provides reference materials and links that AI agents should review before and during the merge process. Each section contains specific guidance on what to look for and how to use the information. + +## Upstream Release Notes +**URL:** https://www.openssh.com/releasenotes.html + +**AI Agent Task:** +1. Navigate to the release notes page +2. Focus ONLY on the latest release section (at the top of the page) +3. Look for these specific types of changes that require Windows compatibility work: + - Signal handling modifications + - File handling changes + - Inter-process communication (IPC) updates + - New system calls or POSIX-specific functionality + - Changes to build system or dependencies + - Security fixes that might affect Windows implementations + +**Example Analysis:** +``` +If release notes mention "Added support for new signal handling in sshd", +the AI should flag this as requiring Windows event mechanism adaptation. +``` + +## Previous Merge Pull Requests + +**AI Agent Task:** Review these PRs in order of recency for conflict resolution patterns: + +1. **Most Recent:** https://github.com/PowerShell/openssh-portable/pull/737 +2. https://github.com/PowerShell/openssh-portable/pull/703 +3. https://github.com/PowerShell/openssh-portable/pull/684 +4. https://github.com/PowerShell/openssh-portable/pull/657 +5. https://github.com/PowerShell/openssh-portable/pull/626 +6. https://github.com/PowerShell/openssh-portable/pull/577 +7. https://github.com/PowerShell/openssh-portable/pull/504 +8. https://github.com/PowerShell/openssh-portable/pull/351 + +**What to Extract from Each PR:** +1. **Commit Messages:** Look for commits added AFTER the initial merge commit +2. **File Patterns:** Note which files commonly have conflicts +3. **Resolution Strategies:** Document how specific types of conflicts were resolved +4. **Build Fixes:** Note compilation issues and their solutions +5. **Test Failures:** Understand common CI/test failures and fixes + +**Key Contributors to Follow:** +- Regular PowerShell/OpenSSH-Portable contributors +- Their commit patterns and resolution strategies +- Comments and review feedback + +## Upstream Repository Analysis + +**Commands for AI Agent:** +```pwsh +# Get commit history for target version +git log --oneline upstream/ --since="" + +# Analyze specific commits +git show + +# Compare branches +git diff upstream-pwsh/latestw_all upstream/ +``` + +## Windows-Specific Knowledge Base + +### Common Conflict Areas +1. **Process Management:** fork() vs CreateProcess() +2. **Signal Handling:** Unix signals vs Windows events +3. **File Permissions:** POSIX permissions vs Windows ACLs +4. **Path Handling:** Unix paths vs Windows paths +5. **Build System:** Makefile vs Visual Studio projects + +### Resolution Pattern Library +```c +// Pattern 1: Platform-specific implementation +#ifdef WINDOWS + // Windows implementation +#else + // Unix implementation +#endif + +// Pattern 2: Exclude Unix-only features +#ifndef WINDOWS + // Unix-only code +#endif + +// Pattern 3: Windows compatibility layer +#ifdef WINDOWS + #include "win32compat.h" +#endif +``` + +## Decision Matrix for AI Agents + +| Conflict Type | Resolution Strategy | Example | +|---------------|-------------------|---------| +| Security Fix | Accept upstream completely | CVE patches | +| Build System | Update VS project files | New source files | +| System Calls | Add Windows equivalent | fork() → CreateProcess() | +| Configuration | Update config.h.vs | New preprocessor defines | +| Test Code | Platform-specific guards | Unix-only tests | diff --git a/.github/instructions/repository-overview.instructions.md b/.github/instructions/repository-overview.instructions.md new file mode 100644 index 000000000000..aa343214f394 --- /dev/null +++ b/.github/instructions/repository-overview.instructions.md @@ -0,0 +1,131 @@ +--- +applyTo: "**/*" +--- + +# Repository Structure and Windows Compatibility Layer + +## Overview + +This repository is a **downstream fork** of [openssh/openssh-portable](https://github.com/openssh/openssh-portable) maintained by the PowerShell team to provide Windows compatibility for OpenSSH. + +## Repository Organization + +### Upstream Code (Base Directory) +The root of the repository contains the upstream OpenSSH code: +- Core SSH implementation files (`.c`, `.h`) +- Unix/POSIX-focused codebase +- Maintained to stay close to upstream for easier merging + +### Windows Compatibility Layer + +#### Primary Windows Code Locations + +**1. `.\contrib\win32\openssh\`** +- Visual Studio project files (`.vcxproj`, `.sln`) +- Windows-specific build configuration +- Project organization for Windows builds + +**2. `.\contrib\win32\win32compat\`** +- Windows compatibility implementation layer +- Provides Windows equivalents for POSIX functions +- Contains platform abstraction code + +#### Compatibility Strategy + +The Windows port follows a **separation of concerns** approach to minimize divergence from upstream: + +1. **Preferred: Compatibility Layer** + - Windows-specific implementations prefixed with `w32_` + - Example: `w32_mkdir()`, `w32_stat()`, `w32_open()` + - Macro redefinition in headers to redirect POSIX calls + - Located in `contrib\win32\win32compat\` + +2. **When Necessary: Conditional Compilation** + - Use `#ifdef WINDOWS` blocks in upstream files + - Keep Windows-specific code minimal and well-documented + - Only when compatibility layer approach is insufficient + +**Example Pattern:** +```c +// In win32compat header (e.g., sys/stat.h) +int w32_mkdir(const char *pathname, unsigned short mode); +#undef mkdir // Clear any existing definition +#define mkdir w32_mkdir // Redirect to Windows implementation + +// In upstream code - no changes needed +mkdir(path, 0700); // Automatically uses w32_mkdir on Windows +``` + +## Special Case: SSH-Agent + +### Important: Separate Windows Implementation + +The **ssh-agent** is a special case that **does not follow** the standard compatibility layer pattern: + +- **Windows ssh-agent location**: `.\contrib\win32\win32compat\ssh-agent\` +- Built from **completely separate code** from the upstream ssh-agent +- Uses Windows-native APIs and service architecture + +### Implications for Upstream Merges + +When merging changes to `ssh-agent.c` or related agent files from upstream: + +1. **Simple changes** (bug fixes, small improvements): + - Manually port functionality to `contrib\win32\win32compat\ssh-agent\` + - Adapt logic to Windows implementation + +2. **Complex changes** (architectural changes, new features): + - Document as TODO in merge commit + - Flag for Windows team review + - May require significant redesign work + +3. **Do NOT**: + - Directly apply upstream ssh-agent patches to Windows version + - Assume one-to-one code correspondence + - Merge without understanding Windows implementation differences + +### Other Binaries + +All other OpenSSH binaries (ssh, sshd, scp, sftp, etc.) follow the standard compatibility layer approach and can be merged more directly from upstream with appropriate Windows compatibility adjustments. + +## Best Practices for Merging + +### 1. Minimize Direct Modifications +- Prefer extending compatibility layer over adding `#ifdef WINDOWS` blocks +- Keep upstream code as clean as possible + +### 2. Document Windows-Specific Changes +- Clear comments explaining why Windows needs different approach +- Reference related compatibility layer functions + +### 3. Test on Windows +- Always build and test on Windows after merging +- Use provided automation tools in `.github\tools\` +- Verify both functionality and build process + +### 4. Upstream Alignment +- Track which upstream commits have been merged +- Maintain clear merge history +- Document any deviations from upstream behavior + +## Key Files to Know + +### Build System +- `contrib\win32\openssh\Win32-OpenSSH.sln` - Main Visual Studio solution +- `contrib\win32\openssh\*.vcxproj` - Individual project files +- `contrib\win32\openssh\OpenSSHBuildHelper.psm1` - Build helper module + +### Compatibility Headers +- `contrib\win32\win32compat\inc\sys\*` - POSIX header replacements +- `contrib\win32\win32compat\inc\*.h` - Windows compatibility declarations +- `contrib\win32\win32compat\inc\crtheaders.h` - CRT header mappings + +### Compatibility Implementation +- `contrib\win32\win32compat\*.c` - Windows function implementations +- `contrib\win32\win32compat\ssh-agent\*` - Separate Windows ssh-agent + +## Getting Help + +- **Build issues**: See [build.instructions.md](./build.instructions.md) +- **Merge conflicts**: See [merge/merge-details.instructions.md](./merge/merge-details.instructions.md) +- **Testing**: See [testing.instructions.md](./testing.instructions.md) diff --git a/.github/instructions/setup.instructions.md b/.github/instructions/setup.instructions.md new file mode 100644 index 000000000000..3081ae3cfdd2 --- /dev/null +++ b/.github/instructions/setup.instructions.md @@ -0,0 +1,86 @@ +--- +applyTo: "**/*" +--- + +# Repository Setup Instructions for AI Agents + +## Initial Repository Setup + +### Step 1: Clone Your Fork +```pwsh +# Replace 'your-username' with actual GitHub username +git clone https://github.com/your-username/openssh-portable.git +cd openssh-portable +``` + +### Step 2: Add Upstream Repositories +```pwsh +# Add PowerShell team's fork as upstream-pwsh +git remote add upstream-pwsh https://github.com/PowerShell/openssh-portable.git + +# Add original OpenSSH repository as upstream +git remote add upstream https://github.com/openssh/openssh-portable.git +``` + +### Step 3: Verify Remote Configuration +```pwsh +git remote -v +# Expected output: +# origin https://github.com/your-username/openssh-portable.git (fetch) +# origin https://github.com/your-username/openssh-portable.git (push) +# upstream https://github.com/openssh/openssh-portable.git (fetch) +# upstream https://github.com/openssh/openssh-portable.git (push) +# upstream-pwsh https://github.com/PowerShell/openssh-portable.git (fetch) +# upstream-pwsh https://github.com/PowerShell/openssh-portable.git (push) +``` + +### Step 4: Initial Fetch +```pwsh +git fetch --all +``` + +## Branch Strategy + +### Understanding the Branch Structure +- **upstream-pwsh/latestw_all**: Main Windows-compatible branch (base for merges) +- **upstream/master**: Latest upstream OpenSSH development +- **upstream/V_X_Y_PZ**: Tagged releases (merge targets) + +### Verification Commands +```pwsh +# List all branches +git branch -r + +# Check current branch +git branch +``` + +### Step 5: Clone VCPkg Repository +```pwsh +# In the same parent directory as openssh-portable +git clone https://github.com/Microsoft/vcpkg.git +``` + +### Step 6: Setup VCPkg Integration with MSBuild +```pwsh +cd vcpkg +.\bootstrap-vcpkg.bat +.\vcpkg.exe integrate install +``` + +## AI Agent Checklist + +Before proceeding to merge: +- [ ] Repository cloned successfully +- [ ] All three remotes configured (origin, upstream, upstream-pwsh) +- [ ] Can fetch from all remotes without errors +- [ ] Can see upstream-pwsh/latestw_all branch +- [ ] Can see upstream target version/branch +- [ ] Working directory is clean (`git status` shows no uncommitted changes) + +## Troubleshooting + +### Common Issues +1. **Authentication errors**: Ensure GitHub credentials are configured +2. **Network issues**: Check proxy settings if behind corporate firewall +3. **Branch not found**: Verify branch/tag names are correct diff --git a/.github/instructions/testing.instructions.md b/.github/instructions/testing.instructions.md new file mode 100644 index 000000000000..7aa715edeab2 --- /dev/null +++ b/.github/instructions/testing.instructions.md @@ -0,0 +1,248 @@ +--- +applyTo: "**/*" +--- + +# Testing Instructions for AI Agents + +## Overview +This document provides comprehensive testing procedures for validating OpenSSH-Portable merges on Windows. Testing should be performed after successful compilation to ensure functionality is preserved. + +## Automated Testing with MCP Tools (Recommended) + +### Using Test-OpenSSHFunctionality Tool + +The repository includes an MCP tool that automates end-to-end functional testing of OpenSSH on Windows. + +```pwsh +# Run automated functional test (requires Administrator privileges) +.\.github\tools\Test-OpenSSHFunctionality.ps1 + +# Test with specific configuration +.\.github\tools\Test-OpenSSHFunctionality.ps1 -Configuration Debug -Architecture x64 + +# Skip firewall configuration if rules already exist +.\.github\tools\Test-OpenSSHFunctionality.ps1 -SkipFirewall +``` + +**What the tool does:** +1. Verifies Administrator privileges +2. Creates a temporary test user with random password +3. Installs and starts the SSH service +4. Configures Windows Firewall (unless -SkipFirewall is used) +5. Tests SSH connection with password authentication +6. Executes "echo hello world" command via SSH +7. Cleans up all resources (user, service, firewall rule) + +**Expected output on success:** +``` +=== OpenSSH Functionality Test === +[1/6] Checking Administrator privileges... +✓ Running with Administrator privileges +[2/6] Creating temporary test user... +✓ Created test user: openssh_test_1234 +[3/6] Installing SSH service... +✓ SSH service installed successfully +[4/6] Starting SSH service... +✓ SSH service started successfully +[5/6] Configuring Windows Firewall... +✓ Firewall rule created +[6/6] Testing SSH connection... +✓ SSH connection successful + Command output: hello world + +=== Cleanup === +✓ SSH service uninstalled +✓ Firewall rule removed +✓ Test user removed + +=== Test Summary === +Status: PASSED +``` + +**The tool returns a structured result object with:** +- `Success`: Boolean indicating overall test success +- `ServiceInstalled`: Whether service installation succeeded +- `ServiceStarted`: Whether service started successfully +- `ConnectionSuccessful`: Whether SSH connection test passed +- `CommandOutput`: Output from the test command +- `TestUser`: Name of the temporary test user created +- `Errors`: Array of any errors encountered +- `Message`: Summary message + +## Manual Testing Procedures + +If you need to perform manual testing or troubleshoot specific issues, follow these procedures: + +### Prerequisites Check +```pwsh +# Verify Windows version compatibility +Get-ComputerInfo | Select-Object WindowsProductName, WindowsVersion + +# Check if running as Administrator - REQUIRED for service installation +if (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) +{ + Write-Error "Administrative privileges are REQUIRED for service installation and testing." + Write-Host "Please restart PowerShell or VS Code as Administrator and try again." -ForegroundColor Yellow + Write-Host "To elevate: Right-click PowerShell/VS Code -> 'Run as Administrator'" -ForegroundColor Yellow + exit 1 +} + +Write-Host "✓ Running with Administrator privileges" -ForegroundColor Green + +# Verify build artifacts exist +$buildPath = ".\contrib\win32\openssh\x64\Release" +if (-not (Test-Path "$buildPath\sshd.exe") -or -not (Test-Path "$buildPath\ssh.exe")) { + Write-Error "Build artifacts not found. Please build the project first." + exit 1 +} + +Write-Host "✓ Build artifacts verified" -ForegroundColor Green +``` + +### Test Environment Setup + +### Service Installation and Configuration + +#### Step 1: Install SSH Service +```pwsh +# Navigate to build directory +cd .\contrib\win32\openssh\x64\Release + +# Install SSH server service with PowerShell script +.\install-sshd.ps1 + +# Verify service installation +Get-Service sshd -ErrorAction SilentlyContinue | Select-Object Name, Status, StartType +``` + +#### Step 2: Configure SSH Service +```pwsh +# Start SSH service +Start-Service sshd + +# Verify service is running +Get-Service sshd | Select-Object Name, Status +``` + +#### Step 3: Configure Windows Firewall (if needed) +```pwsh +# Allow SSH through Windows Firewall +New-NetFirewallRule -DisplayName "SSH Server (sshd)" -Direction Inbound -Port 22 -Protocol TCP -Action Allow -ErrorAction SilentlyContinue +``` + +## Basic Functionality Tests + +### Test 1: SSH Client Connection +```pwsh +# Test local connection (most basic test) +$username = $env:USERNAME +$hostname = "localhost" + +Write-Host "Testing SSH connection: ssh $username@$hostname" + +# Basic connection test +.\ssh.exe $username@$hostname "echo 'SSH connection successful'" +``` + +**Expected Output:** +``` +SSH connection successful +``` + +## Error Diagnosis and Troubleshooting + +### Run SSH Server in Debug Mode +```pwsh +# Enable SSH daemon debug logging +Stop-Service sshd +.\sshd.exe -ddd + +# In another terminal, test connection with verbose client logging +.\ssh.exe -vvv $username@$hostname +``` + +### Common Issues and Solutions + +#### Issue 1: Service Won't Start +**Symptoms:** +- Service fails to start +- Event log shows service errors + +**Diagnosis:** +```pwsh +# Check event logs +Get-WinEvent -LogName System | Where-Object {$_.ProviderName -eq "Service Control Manager" -and $_.Id -eq 7034} | Select-Object -First 5 + +# Check sshd configuration +.\sshd.exe -T +``` + +**Common Solutions:** +- Verify configuration file syntax + +#### Issue 2: Connection Timeouts +**Symptoms:** +- SSH client hangs +- Connection timeout errors + +**Diagnosis:** +```pwsh +# Check network connectivity +Test-NetConnection -ComputerName localhost -Port 22 + +# Check Windows Firewall rules +Get-NetFirewallRule | Where-Object {$_.DisplayName -like "*SSH*"} +``` + +## Success Criteria + +**Testing is successful when:** +- [ ] All expected executables are present after build (verified by Test-OpenSSHBuild.ps1) +- [ ] SSH service installs and starts without errors +- [ ] SSH connection with password authentication succeeds +- [ ] Test command executes successfully via SSH connection +- [ ] All resources cleaned up properly after testing + + +## AI Agent Guidelines + +1. **Use automated testing tools** whenever possible - prefer Test-OpenSSHFunctionality.ps1 over manual procedures +2. **Run tests incrementally** during the merge process, not just at the end +3. **Document any test failures** and their resolutions in commit messages +4. **Pay special attention to Windows-specific functionality** that might be affected by upstream changes +5. **Always verify cleanup** - ensure test users, services, and firewall rules are removed +6. **Report any new functionality** that needs additional testing procedures + +### Recommended Testing Workflow for AI Agents + +1. **After successful build**, run the automated functionality test: + ```pwsh + .\.github\tools\Test-OpenSSHFunctionality.ps1 + ``` + +2. **If test passes**, the merge is validated for basic SSH functionality + +3. **If test fails**, use manual procedures and debug mode to diagnose issues + +4. **Document results** in commit message or merge documentation + +## Manual Test Environment Cleanup + +If you ran manual tests instead of using the automated tool: + +```pwsh +# Clean up test environment +Stop-Service sshd -ErrorAction SilentlyContinue +cd .\contrib\win32\openssh\x64\Release +.\uninstall-sshd.ps1 + +# Remove firewall rule +Remove-NetFirewallRule -DisplayName "SSH Server (sshd)" -ErrorAction SilentlyContinue + +# Remove any test users manually created +Remove-LocalUser -Name "test_username" -ErrorAction SilentlyContinue + +Write-Host "Test environment cleaned up" +``` + +**Note:** The automated Test-OpenSSHFunctionality.ps1 tool handles all cleanup automatically, even on failure. diff --git a/.github/tools/Build-OpenSSH.ps1 b/.github/tools/Build-OpenSSH.ps1 new file mode 100644 index 000000000000..692559066f0e --- /dev/null +++ b/.github/tools/Build-OpenSSH.ps1 @@ -0,0 +1,254 @@ +<# +.SYNOPSIS + MCP wrapper tool that builds and verifies OpenSSH in a single operation. + +.DESCRIPTION + This script combines Start-OpenSSHBuild and Test-OpenSSHBuild into a single + convenient operation. It first builds OpenSSH using the specified configuration + and architecture, then tests that all expected artifacts were produced and + parses the build log for errors. + + This is the recommended tool for most build operations as it provides + comprehensive feedback in one step. + +.PARAMETER Configuration + Build configuration type. Valid values: 'Debug', 'Release' + Default: 'Release' + +.PARAMETER Architecture + Target architecture for the build. Valid values: 'x64', 'x86', 'ARM', 'ARM64' + Default: 'x64' + +.PARAMETER Clean + When specified, performs a clean build by deleting existing build artifacts first. + Default: false (incremental build) + +.PARAMETER NoOpenSSL + Build without OpenSSL support. + Default: false + +.PARAMETER OneCore + Build for Windows OneCore API subset. + Default: false + +.OUTPUTS + Returns a consolidated hashtable with: + - BuildSuccess: Boolean indicating if build succeeded + - TestSuccess: Boolean indicating if test passed + - OverallSuccess: Boolean indicating both build and test succeeded + - BuildExitCode: MSBuild exit code + - BuildMessage: Build status message + - TotalArtifacts: Count of artifacts found + - ExpectedArtifacts: Count of artifacts expected (14) + - ArtifactsMissing: Array of missing artifacts + - Errors: Array of parsed error objects + - Warnings: Array of parsed warning objects + - LogFile: Path to build log file + - BuildPath: Path to build output directory + - Message: Overall summary message + +.EXAMPLE + .\Build-OpenSSH.ps1 -Configuration Release -Architecture x64 + + Performs an incremental release build for x64 and tests artifacts. + +.EXAMPLE + .\Build-OpenSSH.ps1 -Configuration Debug -Architecture x64 -Clean + + Performs a clean debug build for x64 and tests artifacts. + +.EXAMPLE + .\Build-OpenSSH.ps1 -Architecture ARM64 -OneCore + + Performs an incremental OneCore release build for ARM64 and tests artifacts. + +.NOTES + - This tool calls Start-OpenSSHBuild.ps1 and Test-OpenSSHBuild.ps1 + - Requires Visual Studio 2019 or later with C++ tools + - Requires Windows SDK 10.0.17763.0 or later + - Build artifacts output to: contrib\win32\openssh\{Architecture}\{Configuration}\ + - Build log written to: OpenSSH{Configuration}{Architecture}.log +#> + +param( + [Parameter(Mandatory=$false)] + [ValidateSet('Debug', 'Release')] + [string]$Configuration = 'Release', + + [Parameter(Mandatory=$false)] + [ValidateSet('x64', 'x86', 'ARM', 'ARM64')] + [string]$Architecture = 'x64', + + [Parameter(Mandatory=$false)] + [switch]$Clean, + + [Parameter(Mandatory=$false)] + [switch]$NoOpenSSL, + + [Parameter(Mandatory=$false)] + [switch]$OneCore +) + +$scriptRoot = $PSScriptRoot + +try { + Write-Host "========================================" -ForegroundColor Cyan + Write-Host "OpenSSH Build & Test Tool (MCP)" -ForegroundColor Cyan + Write-Host "========================================" -ForegroundColor Cyan + Write-Host "Configuration: $Configuration" -ForegroundColor White + Write-Host "Architecture: $Architecture" -ForegroundColor White + Write-Host "Clean Build: $Clean" -ForegroundColor White + Write-Host "No OpenSSL: $NoOpenSSL" -ForegroundColor White + Write-Host "OneCore: $OneCore" -ForegroundColor White + Write-Host "========================================`n" -ForegroundColor Cyan + + # Step 1: Build + Write-Host "STEP 1: Building OpenSSH..." -ForegroundColor Cyan + Write-Host "----------------------------------------`n" -ForegroundColor Cyan + + $buildParams = @{ + Configuration = $Configuration + Architecture = $Architecture + } + + if ($Clean) { + $buildParams['Clean'] = $true + } + + if ($NoOpenSSL) { + $buildParams['NoOpenSSL'] = $true + } + + if ($OneCore) { + $buildParams['OneCore'] = $true + } + + $buildScriptPath = Join-Path $scriptRoot "Start-OpenSSHBuild.ps1" + $buildResult = & $buildScriptPath @buildParams + + if (-not $buildResult.Success) { + Write-Host "`n⚠ Build failed, skipping test" -ForegroundColor Yellow + + # Return build result with test skipped + $result = @{ + BuildSuccess = $false + TestSuccess = $false + OverallSuccess = $false + BuildExitCode = $buildResult.ExitCode + BuildMessage = $buildResult.Message + TotalArtifacts = 0 + ExpectedArtifacts = 14 + ArtifactsMissing = @() + Errors = @() + Warnings = @() + LogFile = $buildResult.LogFile + BuildPath = $buildResult.BuildPath + Message = "Build failed: $($buildResult.Message)" + } + + return $result + } + + # Step 2: Test + Write-Host "`nSTEP 2: Testing Build Artifacts..." -ForegroundColor Cyan + Write-Host "----------------------------------------`n" -ForegroundColor Cyan + + $testParams = @{ + Configuration = $Configuration + Architecture = $Architecture + LogFile = $buildResult.LogFile + } + + $testScriptPath = Join-Path $scriptRoot "Test-OpenSSHBuild.ps1" + $testResult = & $testScriptPath @testParams + + # Step 3: Consolidate results + $overallSuccess = $buildResult.Success -and $testResult.Success + + Write-Host "`n========================================" -ForegroundColor $(if ($overallSuccess) { "Green" } else { "Red" }) + Write-Host "OVERALL RESULT: $(if ($overallSuccess) { 'SUCCESS' } else { 'FAILED' })" -ForegroundColor $(if ($overallSuccess) { "Green" } else { "Red" }) + Write-Host "========================================" -ForegroundColor $(if ($overallSuccess) { "Green" } else { "Red" }) + + if ($overallSuccess) { + Write-Host "✓ Build succeeded" -ForegroundColor Green + Write-Host "✓ All $($testResult.ExpectedArtifacts) artifacts tested" -ForegroundColor Green + Write-Host "✓ No errors found" -ForegroundColor Green + } else { + if (-not $buildResult.Success) { + Write-Host "✗ Build failed with exit code $($buildResult.ExitCode)" -ForegroundColor Red + } + if ($testResult.ArtifactsMissing.Count -gt 0) { + Write-Host "✗ $($testResult.ArtifactsMissing.Count) artifacts missing" -ForegroundColor Red + } + if ($testResult.Errors.Count -gt 0) { + Write-Host "✗ $($testResult.Errors.Count) error(s) found" -ForegroundColor Red + } + } + + Write-Host "`nBuild artifacts: $($buildResult.BuildPath)" -ForegroundColor White + Write-Host "Build log: $($buildResult.LogFile)" -ForegroundColor White + + # Build consolidated message + $messageParts = @() + if ($buildResult.Success) { + $messageParts += "Build succeeded" + } else { + $messageParts += "Build failed" + } + + if ($testResult.Success) { + $messageParts += "all artifacts tested" + } else { + if ($testResult.ArtifactsMissing.Count -gt 0) { + $messageParts += "$($testResult.ArtifactsMissing.Count) artifacts missing" + } + if ($testResult.Errors.Count -gt 0) { + $messageParts += "$($testResult.Errors.Count) errors" + } + } + + $consolidatedMessage = $messageParts -join ", " + + $result = @{ + BuildSuccess = $buildResult.Success + TestSuccess = $testResult.Success + OverallSuccess = $overallSuccess + BuildExitCode = $buildResult.ExitCode + BuildMessage = $buildResult.Message + TotalArtifacts = $testResult.TotalArtifacts + ExpectedArtifacts = $testResult.ExpectedArtifacts + ArtifactsMissing = $testResult.ArtifactsMissing + Errors = $testResult.Errors + Warnings = $testResult.Warnings + LogFile = $buildResult.LogFile + BuildPath = $buildResult.BuildPath + Message = $consolidatedMessage + } + + return $result + +} catch { + Write-Host "`n========================================" -ForegroundColor Red + Write-Host "ERROR" -ForegroundColor Red + Write-Host "========================================" -ForegroundColor Red + Write-Host $_.Exception.Message -ForegroundColor Red + Write-Host $_.ScriptStackTrace -ForegroundColor Gray + + $result = @{ + BuildSuccess = $false + TestSuccess = $false + OverallSuccess = $false + BuildExitCode = -1 + BuildMessage = "Tool error: $($_.Exception.Message)" + TotalArtifacts = 0 + ExpectedArtifacts = 14 + ArtifactsMissing = @() + Errors = @() + Warnings = @() + LogFile = "" + BuildPath = "" + Message = "Build & test tool error: $($_.Exception.Message)" + } + + return $result +} diff --git a/.github/tools/Get-CommitGroups.ps1 b/.github/tools/Get-CommitGroups.ps1 new file mode 100644 index 000000000000..be7677800325 --- /dev/null +++ b/.github/tools/Get-CommitGroups.ps1 @@ -0,0 +1,402 @@ +<# +.SYNOPSIS + Groups upstream OpenSSH commits into batches based on CI success status or CI presence. + +.DESCRIPTION + This script fetches commits from the openssh/openssh-portable repository on GitHub + and groups them into batches (chunks) based on CI test results. By default, each chunk + ends with a commit that has all CI tests passing (success or skipped). Alternatively, + when using -GroupByCIPresence, each chunk ends with any commit that has CI runs, + regardless of success or failure. + + The script is designed to help with incremental merging of upstream commits by + identifying safe stopping points where all tests pass (or where CI exists). + + When the total number of commits exceeds 250 (GitHub API limit), the script + automatically adjusts to fetch the first 250 commits in chronological order. + +.PARAMETER GitHubTag + The GitHub tag to start from (e.g., "V_10_0_P2"). Cannot be used with -StartCommit. + The script will find commits after this tag up to HEAD. + +.PARAMETER StartCommit + The commit SHA to start from (e.g., "6fb728df50c1afd338cb0223a84ce24579577eff"). + Cannot be used with -GitHubTag. The script will find commits after this commit up to HEAD. + This is typically used when continuing from a previously merged commit. + +.PARAMETER FirstChunkOnly + When specified, the script stops after finding the first chunk with a successful CI commit + (or first chunk with any CI when using -GroupByCIPresence). + This is useful for incremental processing where you want to merge one batch at a time. + +.PARAMETER GroupByCIPresence + When specified, groups commits by CI presence (any CI run exists) rather than CI success. + Each chunk ends with a commit that has any CI runs, regardless of pass/fail status. + Default behavior (without this flag) groups by CI success only. + +.OUTPUTS + Returns an array of chunk objects, each containing: + - ChunkNumber: Sequential number of the chunk + - StartIndex/EndIndex: Array indices for the chunk range + - StartCommit/EndCommit: Short SHA (7 chars) of first and last commits + - StartCommitFull/EndCommitFull: Full SHA of first and last commits + - CommitCount: Number of commits in the chunk + - StartMessage/EndMessage: Commit messages for first and last commits + +.EXAMPLE + .\Get-CommitGroups.ps1 -GitHubTag "V_10_0_P2" -FirstChunkOnly + + Finds the first batch of commits after the V_10_0_P2 tag that ends with passing CI. + +.EXAMPLE + .\Get-CommitGroups.ps1 -StartCommit "6fb728df50c1afd338cb0223a84ce24579577eff" -FirstChunkOnly + + Finds the first batch of commits after the specified commit that ends with passing CI. + Useful for continuing from where a previous merge left off. + +.EXAMPLE + .\Get-CommitGroups.ps1 -StartCommit "6fb728df50c1afd338cb0223a84ce24579577eff" + + Finds all batches of commits after the specified commit, grouping by CI success. + Each batch ends with a commit that has passing CI tests. + +.EXAMPLE + .\Get-CommitGroups.ps1 -GitHubTag "V_10_0_P2" -GroupByCIPresence -FirstChunkOnly + + Finds the first batch of commits after the V_10_0_P2 tag that ends with any commit + that has CI runs (regardless of success or failure). + +.NOTES + - Requires internet access to query GitHub API + - Set GITHUB_TOKEN environment variable for authenticated API access (5,000 requests/hour) + - Without token: rate limited with 200ms delay between commits (60 requests/hour) + - Maximum 250 commits per API call (automatically handled) + - CI status is checked via GitHub check-runs API with pagination support + - Default mode: Commits with "success" or "skipped" CI conclusions are considered passing + - GroupByCIPresence mode: Any commit with CI runs (regardless of result) ends a chunk + +.LINK + https://github.com/openssh/openssh-portable +#> + +param( + [Parameter(Mandatory=$false)] + [string]$GitHubTag, + + [Parameter(Mandatory=$false)] + [string]$StartCommit, + + [Parameter(Mandatory=$false)] + [switch]$FirstChunkOnly, + + [Parameter(Mandatory=$false)] + [switch]$GroupByCIPresence +) + +# Validate parameters +if (-not $GitHubTag -and -not $StartCommit) { + Write-Error "Either -GitHubTag or -StartCommit must be provided" + exit 1 +} + +if ($GitHubTag -and $StartCommit) { + Write-Error "Cannot specify both -GitHubTag and -StartCommit. Please provide only one." + exit 1 +} + +# Configuration +$repo = "openssh/openssh-portable" +$apiBase = "https://api.github.com/repos/$repo" + +# Check for GitHub token for authenticated API access +$script:githubToken = $env:GITHUB_TOKEN +if ($script:githubToken) { + Write-Host "Using authenticated GitHub API (higher rate limits)" -ForegroundColor Green +} else { + Write-Host "Using unauthenticated GitHub API (rate limited - consider setting GITHUB_TOKEN)" -ForegroundColor Yellow +} + +if ($GitHubTag) { + Write-Host "Fetching commits starting from tag: $GitHubTag" -ForegroundColor Cyan +} else { + Write-Host "Fetching commits starting from commit: $StartCommit" -ForegroundColor Cyan +} + +# Function to get GitHub API headers with optional authentication +function Get-GitHubHeaders { + $headers = @{ + "User-Agent" = "PowerShell" + "Accept" = "application/vnd.github+json" + } + + if ($script:githubToken) { + $headers["Authorization"] = "Bearer $script:githubToken" + } + + return $headers +} + +# Get the starting commit SHA +try { + if ($GitHubTag) { + $tagInfo = Invoke-RestMethod -Uri "$apiBase/git/refs/tags/$GitHubTag" -Headers (Get-GitHubHeaders) + $startCommitSha = $tagInfo.object.sha + + # If it's an annotated tag, we need to get the actual commit + if ($tagInfo.object.type -eq "tag") { + $tagObject = Invoke-RestMethod -Uri $tagInfo.object.url -Headers (Get-GitHubHeaders) + $startCommitSha = $tagObject.object.sha + } + + Write-Host "Tag $GitHubTag points to commit: $startCommitSha" -ForegroundColor Green + } else { + # Validate the commit exists + $commitInfo = Invoke-RestMethod -Uri "$apiBase/commits/$StartCommit" -Headers (Get-GitHubHeaders) + $startCommitSha = $commitInfo.sha + Write-Host "Starting from commit: $startCommitSha" -ForegroundColor Green + } +} catch { + Write-Error "Failed to retrieve starting commit information: $_" + exit 1 +} + +# Function to check CI status for a commit +function Get-CommitCIStatus { + param( + [string]$sha, + [bool]$checkPresenceOnly = $false + ) + + try { + $allCheckRuns = @() + $page = 1 + $perPage = 100 + + # Fetch all pages of check runs + do { + $checkRunsUrl = "$apiBase/commits/$sha/check-runs?per_page=$perPage&page=$page" + $response = Invoke-RestMethod -Uri $checkRunsUrl -Headers (Get-GitHubHeaders) + + $allCheckRuns += $response.check_runs + $page++ + + } while ($response.check_runs.Count -eq $perPage) + + # Check if there are any check runs + if ($allCheckRuns.Count -eq 0) { + return "no_ci" + } + + # If only checking for presence, return has_ci + if ($checkPresenceOnly) { + return "has_ci" + } + + # Check if all check runs are successful or skipped + $allSuccessful = $true + foreach ($checkRun in $allCheckRuns) { + # Accept "success" or "skipped" as valid conclusions + if ($checkRun.conclusion -ne "success" -and $checkRun.conclusion -ne "skipped") { + $allSuccessful = $false + break + } + } + + if ($allSuccessful) { + return "success" + } else { + return "failure" + } + } catch { + Write-Warning "Could not get CI status for commit $sha : $_" + return "unknown" + } +} + +# Function to get commit details +function Get-CommitDetails { + param([string]$sha) + + try { + $commitUrl = "$apiBase/commits/$sha" + $commit = Invoke-RestMethod -Uri $commitUrl -Headers (Get-GitHubHeaders) + return @{ + Sha = $commit.sha.Substring(0, 7) + FullSha = $commit.sha + Message = $commit.commit.message.Split("`n")[0] + Author = $commit.commit.author.name + Date = $commit.commit.author.date + } + } catch { + Write-Warning "Could not get commit details for $sha" + return $null + } +} + +# Fetch commits starting from the tag using compare API +Write-Host "`nFetching commits from the repository..." -ForegroundColor Cyan + +try { + # Get commits after the starting commit (excluding the start commit itself) + $allCommits = @() + $page = 1 + $perPage = 250 # Compare API returns max 250 commits per page + + Write-Host "Fetching commits from $startCommitSha...HEAD" -ForegroundColor Gray + + # The Compare API doesn't support pagination, so we need to use commits API instead + # to get commits in the correct range with proper pagination + $compareUrl = "$apiBase/compare/${startCommitSha}...HEAD" + $comparison = Invoke-RestMethod -Uri $compareUrl -Headers (Get-GitHubHeaders) + + # The Compare API returns commits - need to verify order + # According to GitHub API docs, commits are in chronological order (oldest first) + $allCommits = @($comparison.commits) + + # If we hit the 250 commit limit, we need to get the actual first 250 commits + # by using the oldest commit from this batch as the end point + if ($comparison.total_commits -gt 250) { + Write-Host "Warning: Total commits ($($comparison.total_commits)) exceeds API limit (250)." -ForegroundColor Yellow + Write-Host "Fetching first 250 commits by using oldest commit as endpoint..." -ForegroundColor Cyan + + # Get the oldest commit SHA from the initial batch (first in chronological order) + $oldestCommitSha = $allCommits[0].sha + + # Now compare from start to this oldest commit to get the actual first 250 + $limitedCompareUrl = "$apiBase/compare/${startCommitSha}...${oldestCommitSha}" + Write-Host "Comparing $startCommitSha...$oldestCommitSha" -ForegroundColor Gray + $limitedComparison = Invoke-RestMethod -Uri $limitedCompareUrl -Headers (Get-GitHubHeaders) + + $allCommits = @($limitedComparison.commits) + Write-Host "Fetched $($allCommits.Count) commits in the corrected range" -ForegroundColor Green + } + + $startRef = if ($GitHubTag) { "tag $GitHubTag" } else { "commit $StartCommit" } + Write-Host "Found $($allCommits.Count) commits from $startRef" -ForegroundColor Green +} catch { + Write-Error "Failed to fetch commits: $_" + exit 1 +} + +# Process commits and check CI status +$statusCheckMessage = if ($GroupByCIPresence) { "Checking CI presence for each commit..." } else { "Checking CI status for each commit..." } +Write-Host "\n$statusCheckMessage" -ForegroundColor Cyan + +$commitsWithStatus = @() +$chunks = @() +$commitCount = 0 +$chunkStart = 0 + +foreach ($commit in $allCommits) { + $commitCount++ + Write-Host "Processing commit $commitCount of $($allCommits.Count): $($commit.sha.Substring(0,7))" -ForegroundColor Gray + + $status = Get-CommitCIStatus -sha $commit.sha -checkPresenceOnly $GroupByCIPresence + $details = Get-CommitDetails -sha $commit.sha + + if ($details) { + $commitsWithStatus += [PSCustomObject]@{ + Index = $commitCount - 1 + Sha = $details.Sha + FullSha = $details.FullSha + Message = $details.Message + Author = $details.Author + Date = $details.Date + CIStatus = $status + } + + # Check if this commit completes a chunk (based on grouping mode) + $targetStatus = if ($GroupByCIPresence) { "has_ci" } else { "success" } + if ($status -eq $targetStatus) { + $chunkEnd = $commitsWithStatus.Count - 1 + + $chunks += [PSCustomObject]@{ + ChunkNumber = $chunks.Count + 1 + StartIndex = $chunkStart + EndIndex = $chunkEnd + StartCommit = $commitsWithStatus[$chunkStart].Sha + EndCommit = $commitsWithStatus[$chunkEnd].Sha + StartCommitFull = $commitsWithStatus[$chunkStart].FullSha + EndCommitFull = $commitsWithStatus[$chunkEnd].FullSha + CommitCount = $chunkEnd - $chunkStart + 1 + StartMessage = $commitsWithStatus[$chunkStart].Message + EndMessage = $commitsWithStatus[$chunkEnd].Message + } + + $chunkStart = $commitsWithStatus.Count + + # If FirstChunkOnly is specified, stop after finding the first chunk + if ($FirstChunkOnly) { + $chunkFoundMessage = if ($GroupByCIPresence) { "Found first chunk with CI, stopping..." } else { "Found first successful chunk, stopping..." } + Write-Host $chunkFoundMessage -ForegroundColor Green + break + } + } + } + + # Rate limiting - only needed for unauthenticated requests + if (-not $script:githubToken) { + Start-Sleep -Milliseconds 200 + } +} + +# Handle remaining commits that don't end with success (only if not FirstChunkOnly or no chunk found) +if (-not $FirstChunkOnly -and $chunkStart -lt $commitsWithStatus.Count) { + $chunkEnd = $commitsWithStatus.Count - 1 + $chunks += [PSCustomObject]@{ + ChunkNumber = $chunks.Count + 1 + StartIndex = $chunkStart + EndIndex = $chunkEnd + StartCommit = $commitsWithStatus[$chunkStart].Sha + EndCommit = $commitsWithStatus[$chunkEnd].Sha + StartCommitFull = $commitsWithStatus[$chunkStart].FullSha + EndCommitFull = $commitsWithStatus[$chunkEnd].FullSha + CommitCount = $chunkEnd - $chunkStart + 1 + StartMessage = $commitsWithStatus[$chunkStart].Message + EndMessage = $commitsWithStatus[$chunkEnd].Message + } +} + +Write-Host "`nGrouping complete." -ForegroundColor Cyan + +# Display results +$groupingMode = if ($GroupByCIPresence) { "CI Presence" } else { "CI Success" } +Write-Host "\n========================================" -ForegroundColor Cyan +Write-Host "COMMIT CHUNKS (Grouped by $groupingMode)" -ForegroundColor Cyan +Write-Host "========================================`n" -ForegroundColor Cyan + +foreach ($chunk in $chunks) { + Write-Host "Chunk $($chunk.ChunkNumber): $($chunk.CommitCount) commits" -ForegroundColor Yellow + Write-Host " Start: $($chunk.StartCommit) - $($chunk.StartMessage)" -ForegroundColor White + Write-Host " End: $($chunk.EndCommit) - $($chunk.EndMessage)" -ForegroundColor Green + Write-Host " Commit Pair: ($($chunk.StartCommitFull), $($chunk.EndCommitFull))" -ForegroundColor Magenta + Write-Host "" +} + +Write-Host "`nTotal Chunks: $($chunks.Count)" -ForegroundColor Cyan +Write-Host "Total Commits: $($commitsWithStatus.Count)" -ForegroundColor Cyan + +# Output detailed commit list +Write-Host "`n========================================" -ForegroundColor Cyan +Write-Host "DETAILED COMMIT LIST" -ForegroundColor Cyan +Write-Host "========================================`n" -ForegroundColor Cyan + +# Only show commits that are part of returned chunks +$maxIndex = if ($chunks.Count -gt 0) { $chunks[-1].EndIndex } else { -1 } +foreach ($commit in $commitsWithStatus) { + if ($commit.Index -le $maxIndex) { + $statusColor = switch ($commit.CIStatus) { + "success" { "Green" } + "has_ci" { "Green" } + "failure" { "Red" } + "no_ci" { "Yellow" } + "pending" { "Yellow" } + default { "Gray" } + } + + Write-Host "$($commit.Sha) | $($commit.CIStatus.PadRight(10)) | $($commit.Message.Substring(0, [Math]::Min(60, $commit.Message.Length)))" -ForegroundColor $statusColor + } +} + +# Return the chunks for potential further processing +return $chunks diff --git a/.github/tools/Start-OpenSSHBuild.ps1 b/.github/tools/Start-OpenSSHBuild.ps1 new file mode 100644 index 000000000000..c175b29c6394 --- /dev/null +++ b/.github/tools/Start-OpenSSHBuild.ps1 @@ -0,0 +1,195 @@ +<# +.SYNOPSIS + MCP tool to build OpenSSH on Windows using Visual Studio. + +.DESCRIPTION + This script wraps the Start-OpenSSHBuild function from OpenSSHBuildHelper.psm1 + to provide a standardized MCP interface for building OpenSSH. It supports + incremental and clean builds, multiple architectures, and various build configurations. + + The tool invokes MSBuild on the Win32-OpenSSH.sln solution and captures + all build output to a log file. + +.PARAMETER Configuration + Build configuration type. Valid values: 'Debug', 'Release' + Default: 'Release' + +.PARAMETER Architecture + Target architecture for the build. Valid values: 'x64', 'x86', 'ARM', 'ARM64' + Default: 'x64' + +.PARAMETER Clean + When specified, performs a clean build by deleting existing build artifacts first. + Default: false (incremental build) + +.PARAMETER NoOpenSSL + Build without OpenSSL support. + Default: false + +.PARAMETER OneCore + Build for Windows OneCore API subset. + Default: false + +.OUTPUTS + Returns a hashtable with: + - Success: Boolean indicating build success + - ExitCode: MSBuild exit code + - LogFile: Path to build log file + - BuildPath: Path to build output directory + - Message: Status message + +.EXAMPLE + .\Start-OpenSSHBuild.ps1 -Configuration Release -Architecture x64 + + Performs an incremental release build for x64 architecture. + +.EXAMPLE + .\Start-OpenSSHBuild.ps1 -Configuration Debug -Architecture x64 -Clean + + Performs a clean debug build for x64 architecture. + +.EXAMPLE + .\Start-OpenSSHBuild.ps1 -Architecture ARM64 -OneCore + + Performs an incremental OneCore release build for ARM64. + +.NOTES + - Requires Visual Studio 2019 or later with C++ tools + - Requires Windows SDK 10.0.17763.0 or later + - Build artifacts output to: contrib\win32\openssh\{Architecture}\{Configuration}\ + - Build log written to: OpenSSH{Configuration}{Architecture}.log +#> + +param( + [Parameter(Mandatory=$false)] + [ValidateSet('Debug', 'Release')] + [string]$Configuration = 'Release', + + [Parameter(Mandatory=$false)] + [ValidateSet('x64', 'x86', 'ARM', 'ARM64')] + [string]$Architecture = 'x64', + + [Parameter(Mandatory=$false)] + [switch]$Clean, + + [Parameter(Mandatory=$false)] + [switch]$NoOpenSSL, + + [Parameter(Mandatory=$false)] + [switch]$OneCore +) + +# Determine repository root (go up from .github\tools to repo root) +$scriptRoot = $PSScriptRoot +$repoRoot = Split-Path -Parent (Split-Path -Parent $scriptRoot) + +# Navigate to repository root +Push-Location $repoRoot + +try { + Write-Host "========================================" -ForegroundColor Cyan + Write-Host "OpenSSH Build Tool (MCP)" -ForegroundColor Cyan + Write-Host "========================================" -ForegroundColor Cyan + Write-Host "Configuration: $Configuration" -ForegroundColor White + Write-Host "Architecture: $Architecture" -ForegroundColor White + Write-Host "Clean Build: $Clean" -ForegroundColor White + Write-Host "No OpenSSL: $NoOpenSSL" -ForegroundColor White + Write-Host "OneCore: $OneCore" -ForegroundColor White + Write-Host "========================================`n" -ForegroundColor Cyan + + # Import OpenSSH build helper module + $buildHelperPath = Join-Path $repoRoot "contrib\win32\openssh\OpenSSHBuildHelper.psm1" + if (-not (Test-Path $buildHelperPath)) { + throw "OpenSSHBuildHelper.psm1 not found at: $buildHelperPath" + } + + Import-Module $buildHelperPath -Force -ErrorAction Stop + Write-Host "✓ Loaded OpenSSHBuildHelper module" -ForegroundColor Green + + # Define build output path + $buildPath = Join-Path $repoRoot "contrib\win32\openssh\$Architecture\$Configuration" + + # Perform clean if requested + if ($Clean -and (Test-Path $buildPath)) { + Write-Host "`nCleaning previous build artifacts..." -ForegroundColor Yellow + Remove-Item $buildPath -Recurse -Force -ErrorAction Stop + Write-Host "✓ Cleaned: $buildPath" -ForegroundColor Green + } + + # Build log file path + $logFile = Join-Path $repoRoot "OpenSSH$Configuration$Architecture.log" + Write-Host "`nBuild log: $logFile" -ForegroundColor Gray + + # Prepare parameters for Start-OpenSSHBuild + $buildParams = @{ + Configuration = $Configuration + NativeHostArch = $Architecture + } + + if ($NoOpenSSL) { + $buildParams['NoOpenSSL'] = $true + } + + if ($OneCore) { + $buildParams['OneCore'] = $true + } + + # Execute build + Write-Host "`nStarting build..." -ForegroundColor Cyan + Write-Host "Command: Start-OpenSSHBuild -Configuration $Configuration -NativeHostArch $Architecture$(if($NoOpenSSL){' -NoOpenSSL'})$(if($OneCore){' -OneCore'})" -ForegroundColor Gray + + $buildResult = Start-OpenSSHBuild @buildParams + + # Check build result + if ($buildResult -eq 0) { + Write-Host "`n========================================" -ForegroundColor Green + Write-Host "BUILD SUCCEEDED" -ForegroundColor Green + Write-Host "========================================" -ForegroundColor Green + Write-Host "Build artifacts: $buildPath" -ForegroundColor White + + $result = @{ + Success = $true + ExitCode = 0 + LogFile = $logFile + BuildPath = $buildPath + Message = "Build completed successfully" + } + } else { + Write-Host "`n========================================" -ForegroundColor Red + Write-Host "BUILD FAILED" -ForegroundColor Red + Write-Host "========================================" -ForegroundColor Red + Write-Host "Exit code: $buildResult" -ForegroundColor Red + Write-Host "Check log file: $logFile" -ForegroundColor Yellow + + $result = @{ + Success = $false + ExitCode = $buildResult + LogFile = $logFile + BuildPath = $buildPath + Message = "Build failed with exit code $buildResult. Check log file for details." + } + } + + # Output result as JSON for MCP consumption + return $result + +} catch { + Write-Host "`n========================================" -ForegroundColor Red + Write-Host "ERROR" -ForegroundColor Red + Write-Host "========================================" -ForegroundColor Red + Write-Host $_.Exception.Message -ForegroundColor Red + Write-Host $_.ScriptStackTrace -ForegroundColor Gray + + $result = @{ + Success = $false + ExitCode = -1 + LogFile = $logFile + BuildPath = $buildPath + Message = "Build tool error: $($_.Exception.Message)" + } + + return $result + +} finally { + Pop-Location +} diff --git a/.github/tools/Test-OpenSSHBuild.ps1 b/.github/tools/Test-OpenSSHBuild.ps1 new file mode 100644 index 000000000000..25aa95f4571c --- /dev/null +++ b/.github/tools/Test-OpenSSHBuild.ps1 @@ -0,0 +1,262 @@ +<# +.SYNOPSIS + MCP tool to test OpenSSH build artifacts and parse build errors. + +.DESCRIPTION + This script tests that all expected OpenSSH executables were built successfully + and parses the build log file for any compilation or linker errors using regex patterns. + + Expected artifacts (14 executables): + - ssh.exe, sshd.exe, sshd-auth.exe, sshd-session.exe + - ssh-agent.exe, ssh-add.exe, ssh-keygen.exe, ssh-keyscan.exe + - scp.exe, sftp.exe, sftp-server.exe + - ssh-pkcs11-helper.exe, ssh-shellhost.exe, ssh-sk-helper.exe + +.PARAMETER Configuration + Build configuration type that was used. Valid values: 'Debug', 'Release' + Default: 'Release' + +.PARAMETER Architecture + Target architecture that was built. Valid values: 'x64', 'x86', 'ARM', 'ARM64' + Default: 'x64' + +.PARAMETER LogFile + Optional path to the build log file. If not specified, uses default pattern: + OpenSSH{Configuration}{Architecture}.log in repository root. + +.OUTPUTS + Returns a hashtable with: + - Success: Boolean indicating if all artifacts present and no errors + - ArtifactsFound: Array of executables that exist + - ArtifactsMissing: Array of expected executables that are missing + - TotalArtifacts: Count of artifacts found + - ExpectedArtifacts: Count of artifacts expected (14) + - Errors: Array of parsed error objects with file, line, code, message + - Warnings: Array of parsed warning objects + - LogFile: Path to log file analyzed + - Message: Summary message + +.EXAMPLE + .\Test-OpenSSHBuild.ps1 -Configuration Release -Architecture x64 + + Tests release build artifacts for x64 architecture. + +.EXAMPLE + .\Test-OpenSSHBuild.ps1 -Configuration Debug -Architecture x86 -LogFile "C:\build\custom.log" + + Tests debug build artifacts for x86 using a custom log file location. + +.NOTES + - Expected build artifact location: contrib\win32\openssh\{Architecture}\{Configuration}\ + - Error parsing regex: ^(?.*?)\((?\d+)[,)].*?error (?(C|LNK)\d+): (?.*)$ + - Warning parsing regex: ^(?.*?)\((?\d+)[,)].*?warning (?(C|LNK)\d+): (?.*)$ +#> + +param( + [Parameter(Mandatory=$false)] + [ValidateSet('Debug', 'Release')] + [string]$Configuration = 'Release', + + [Parameter(Mandatory=$false)] + [ValidateSet('x64', 'x86', 'ARM', 'ARM64')] + [string]$Architecture = 'x64', + + [Parameter(Mandatory=$false)] + [string]$LogFile +) + +# Determine repository root (go up from .github\tools to repo root) +$scriptRoot = $PSScriptRoot +$repoRoot = Split-Path -Parent (Split-Path -Parent $scriptRoot) + +# Define expected artifacts (14 executables) +$expectedArtifacts = @( + "ssh.exe", + "sshd.exe", + "sshd-auth.exe", + "sshd-session.exe", + "ssh-agent.exe", + "ssh-add.exe", + "ssh-keygen.exe", + "ssh-keyscan.exe", + "scp.exe", + "sftp.exe", + "sftp-server.exe", + "ssh-pkcs11-helper.exe", + "ssh-shellhost.exe", + "ssh-sk-helper.exe" +) + +try { + Write-Host "========================================" -ForegroundColor Cyan + Write-Host "OpenSSH Build Test Tool (MCP)" -ForegroundColor Cyan + Write-Host "========================================" -ForegroundColor Cyan + Write-Host "Configuration: $Configuration" -ForegroundColor White + Write-Host "Architecture: $Architecture" -ForegroundColor White + Write-Host "========================================`n" -ForegroundColor Cyan + + # Define build output path + $buildPath = Join-Path $repoRoot "contrib\win32\openssh\$Architecture\$Configuration" + + if (-not (Test-Path $buildPath)) { + Write-Host "Build path does not exist: $buildPath" -ForegroundColor Red + + $result = @{ + Success = $false + ArtifactsFound = @() + ArtifactsMissing = $expectedArtifacts + TotalArtifacts = 0 + ExpectedArtifacts = $expectedArtifacts.Count + Errors = @() + Warnings = @() + LogFile = $LogFile + Message = "Build path does not exist: $buildPath" + } + + return $result + } + + Write-Host "Build path: $buildPath" -ForegroundColor Gray + + # Check for artifacts + Write-Host "`nChecking for expected artifacts..." -ForegroundColor Cyan + + $artifactsFound = @() + $artifactsMissing = @() + + foreach ($artifact in $expectedArtifacts) { + $artifactPath = Join-Path $buildPath $artifact + if (Test-Path $artifactPath) { + $artifactsFound += $artifact + Write-Host " ✓ $artifact" -ForegroundColor Green + } else { + $artifactsMissing += $artifact + Write-Host " ✗ $artifact (MISSING)" -ForegroundColor Red + } + } + + Write-Host "`nArtifacts: $($artifactsFound.Count) of $($expectedArtifacts.Count) found" -ForegroundColor $(if ($artifactsMissing.Count -eq 0) { "Green" } else { "Yellow" }) + + # Parse build log if available + $errors = @() + $warnings = @() + + if (-not $LogFile) { + $LogFile = Join-Path $repoRoot "OpenSSH$Configuration$Architecture.log" + } + + if (Test-Path $LogFile) { + Write-Host "`nParsing build log: $LogFile" -ForegroundColor Cyan + + $logContent = Get-Content $LogFile -ErrorAction SilentlyContinue + + if ($logContent) { + # Error regex: file(line) : error CODE: message + # Example: c:\path\file.c(123): error C2065: 'identifier' : undeclared identifier + $errorRegex = '^(?.*?)\((?\d+)[,)].*?error (?(C|LNK)\d+): (?.*)$' + + # Warning regex: similar pattern for warnings + $warningRegex = '^(?.*?)\((?\d+)[,)].*?warning (?(C|LNK)\d+): (?.*)$' + + foreach ($line in $logContent) { + # Check for errors + if ($line -match $errorRegex) { + $errors += [PSCustomObject]@{ + File = $matches['file'] + Line = [int]$matches['line'] + Code = $matches['code'] + Message = $matches['message'] + RawLine = $line + } + } + # Check for warnings + elseif ($line -match $warningRegex) { + $warnings += [PSCustomObject]@{ + File = $matches['file'] + Line = [int]$matches['line'] + Code = $matches['code'] + Message = $matches['message'] + RawLine = $line + } + } + } + + if ($errors.Count -gt 0) { + Write-Host "`nFound $($errors.Count) error(s) in build log:" -ForegroundColor Red + foreach ($e in $errors) { + Write-Host " $($e.File)($($e.Line)): error $($e.Code): $($e.Message)" -ForegroundColor Red + } + } else { + Write-Host "`n✓ No errors found in build log" -ForegroundColor Green + } + + if ($warnings.Count -gt 0) { + Write-Host "`nFound $($warnings.Count) warning(s) in build log:" -ForegroundColor Yellow + foreach ($warning in $warnings | Select-Object -First 10) { + Write-Host " $($warning.File)($($warning.Line)): warning $($warning.Code): $($warning.Message)" -ForegroundColor Yellow + } + if ($warnings.Count -gt 10) { + Write-Host " ... and $($warnings.Count - 10) more warnings" -ForegroundColor Gray + } + } + } else { + Write-Host "Log file is empty or could not be read" -ForegroundColor Yellow + } + } else { + Write-Host "`nBuild log not found: $LogFile" -ForegroundColor Yellow + } + + # Determine overall success + $success = ($artifactsMissing.Count -eq 0) -and ($errors.Count -eq 0) + + # Build summary message + if ($success) { + $message = "All $($expectedArtifacts.Count) artifacts built successfully with no errors" + } elseif ($artifactsMissing.Count -gt 0 -and $errors.Count -gt 0) { + $message = "$($artifactsMissing.Count) artifacts missing and $($errors.Count) error(s) found" + } elseif ($artifactsMissing.Count -gt 0) { + $message = "$($artifactsMissing.Count) artifacts missing" + } else { + $message = "$($errors.Count) error(s) found in build log" + } + + Write-Host "`n========================================" -ForegroundColor $(if ($success) { "Green" } else { "Red" }) + Write-Host $(if ($success) { "TEST PASSED" } else { "TEST FAILED" }) -ForegroundColor $(if ($success) { "Green" } else { "Red" }) + Write-Host "========================================" -ForegroundColor $(if ($success) { "Green" } else { "Red" }) + Write-Host $message -ForegroundColor White + + $result = @{ + Success = $success + ArtifactsFound = $artifactsFound + ArtifactsMissing = $artifactsMissing + TotalArtifacts = $artifactsFound.Count + ExpectedArtifacts = $expectedArtifacts.Count + Errors = $errors + Warnings = $warnings + LogFile = $LogFile + Message = $message + } + + return $result + +} catch { + Write-Host "`n========================================" -ForegroundColor Red + Write-Host "ERROR" -ForegroundColor Red + Write-Host "========================================" -ForegroundColor Red + Write-Host $_.Exception.Message -ForegroundColor Red + Write-Host $_.ScriptStackTrace -ForegroundColor Gray + + $result = @{ + Success = $false + ArtifactsFound = @() + ArtifactsMissing = $expectedArtifacts + TotalArtifacts = 0 + ExpectedArtifacts = $expectedArtifacts.Count + Errors = @() + Warnings = @() + LogFile = $LogFile + Message = "Test tool error: $($_.Exception.Message)" + } + + return $result +} diff --git a/.github/tools/Test-OpenSSHFunctionality.ps1 b/.github/tools/Test-OpenSSHFunctionality.ps1 new file mode 100644 index 000000000000..9e1b0f7c8907 --- /dev/null +++ b/.github/tools/Test-OpenSSHFunctionality.ps1 @@ -0,0 +1,447 @@ +<# +.SYNOPSIS + Tests OpenSSH functionality by installing the SSH service, creating a test user, + and attempting a password-authenticated SSH connection. + +.DESCRIPTION + This script performs end-to-end functional testing of OpenSSH on Windows by: + 1. Verifying Administrator privileges + 2. Creating a temporary local user with a random password + 3. Installing the SSH service using install-sshd.ps1 + 4. Starting the SSH service + 5. Configuring Windows Firewall (optional) + 6. Testing SSH connection with password authentication + 7. Cleaning up all resources (user, service, firewall rule) + + The test is successful if an SSH connection can execute "echo hello world" successfully. + +.PARAMETER Configuration + Build configuration type. Valid values: 'Debug', 'Release' + Default: 'Release' + +.PARAMETER Architecture + Target architecture. Valid values: 'x64', 'x86', 'ARM', 'ARM64' + Default: 'x64' + +.PARAMETER SkipFirewall + Skip Windows Firewall configuration. Use this if firewall rules already exist + or if testing on a system without firewall enabled. + +.PARAMETER NoCleanup + Skip cleanup of created resources (test user, firewall rule, temp files). + Useful when debugging failures. + +.EXAMPLE + .\Test-OpenSSHFunctionality.ps1 + Tests using default Release x64 build with firewall configuration + +.EXAMPLE + .\Test-OpenSSHFunctionality.ps1 -Configuration Debug -Architecture x64 + Tests using Debug x64 build + +.EXAMPLE + .\Test-OpenSSHFunctionality.ps1 -SkipFirewall + Tests without modifying firewall rules + +.NOTES + Requires Administrator privileges. + Creates temporary user with prefix "openssh_test_" which is removed after testing. +#> + +[CmdletBinding()] +param( + [Parameter()] + [ValidateSet('Debug', 'Release')] + [string]$Configuration = 'Release', + + [Parameter()] + [ValidateSet('x64', 'x86', 'ARM', 'ARM64')] + [string]$Architecture = 'x64', + + [Parameter()] + [switch]$SkipFirewall, + + [Parameter()] + [switch]$NoCleanup +) + +# Helper function to generate a random password +function New-RandomPassword { + [CmdletBinding()] + param( + [Parameter()] + [int]$Length = 20 + ) + + # Character sets for password complexity + $lowercase = 'abcdefghijklmnopqrstuvwxyz' + $uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + $numbers = '0123456789' + $special = '!@#$%^&*()_+-=[]{}|;:,.<>?' + + # Ensure at least one character from each set + $password = @( + $lowercase[(Get-Random -Maximum $lowercase.Length)] + $uppercase[(Get-Random -Maximum $uppercase.Length)] + $numbers[(Get-Random -Maximum $numbers.Length)] + $special[(Get-Random -Maximum $special.Length)] + ) + + # Fill the rest with random characters from all sets + $allChars = $lowercase + $uppercase + $numbers + $special + for ($i = $password.Count; $i -lt $Length; $i++) { + $password += $allChars[(Get-Random -Maximum $allChars.Length)] + } + + # Shuffle the password + $shuffled = $password | Sort-Object {Get-Random} + + return -join $shuffled +} + +# Initialize result object +$result = [PSCustomObject]@{ + Success = $false + ServiceInstalled = $false + ServiceStarted = $false + ConnectionSuccessful = $false + CommandOutput = $null + TestUser = $null + Errors = @() + Message = "" +} + +# Variables for cleanup tracking +$testUser = $null +$serviceWasInstalled = $false +$firewallRuleCreated = $false + +try { + Write-Host "=== OpenSSH Functionality Test ===" -ForegroundColor Cyan + Write-Host "Configuration: $Configuration" -ForegroundColor Gray + Write-Host "Architecture: $Architecture" -ForegroundColor Gray + Write-Host "" + + # Step 1: Verify Administrator privileges + Write-Host "[1/6] Checking Administrator privileges..." -ForegroundColor Yellow + $isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") + + if (-not $isAdmin) { + $result.Errors += "Administrator privileges required" + $result.Message = "FAILED: This script must be run as Administrator for service installation and user management." + Write-Host "✗ Administrator privileges required" -ForegroundColor Red + Write-Host " Please restart PowerShell or VS Code as Administrator" -ForegroundColor Yellow + return $result + } + Write-Host "✓ Running with Administrator privileges" -ForegroundColor Green + + # Step 2: Locate build artifacts and scripts + $scriptRoot = Split-Path -Parent $PSCommandPath + $repoRoot = Split-Path -Parent (Split-Path -Parent $scriptRoot) + $buildPath = Join-Path $repoRoot "bin\$Architecture\$Configuration" + $askPassExe = Join-Path $repoRoot "regress\pesterTests\utilities\askpass_util\askpass_util.exe" + + # Verify build artifacts exist + $sshdExe = Join-Path $buildPath "sshd.exe" + $sshExe = Join-Path $buildPath "ssh.exe" + $installScript = Join-Path $buildPath "install-sshd.ps1" + + if (-not (Test-Path $sshdExe) -or -not (Test-Path $sshExe)) { + $result.Errors += "Build artifacts not found at $buildPath" + $result.Message = "FAILED: Build artifacts not found. Please build the project first." + Write-Host "✗ Build artifacts not found at $buildPath" -ForegroundColor Red + return $result + } + + if (-not (Test-Path $installScript)) { + $result.Errors += "install-sshd.ps1 not found at $buildPath" + $result.Message = "FAILED: install-sshd.ps1 script not found." + Write-Host "✗ install-sshd.ps1 not found at $buildPath" -ForegroundColor Red + return $result + } + + # Step 3: Create temporary test user + Write-Host "`n[2/6] Creating temporary test user..." -ForegroundColor Yellow + $testUsername = "openssh_test_" + (Get-Random -Minimum 1000 -Maximum 9999) + $testPassword = New-RandomPassword -Length 24 + $securePassword = ConvertTo-SecureString $testPassword -AsPlainText -Force + + try { + Import-Module Microsoft.PowerShell.LocalAccounts -UseWindowsPowerShell + New-LocalUser -Name $testUsername -Password $securePassword -Description "Temporary user for OpenSSH testing" -ErrorAction Stop | Out-Null + $testUser = $testUsername + $result.TestUser = $testUsername + $env:ASKPASS_PASSWORD = $testPassword + $env:SSH_ASKPASS_REQUIRE = "force" + if (-not (Test-Path $askPassExe)) { + throw "SSH_ASKPASS helper not found at '$askPassExe'" + } + $env:SSH_ASKPASS = $askPassExe + Write-Host "✓ Created test user: $testUsername" -ForegroundColor Green + } + catch { + $result.Errors += "Failed to create test user: $_" + $result.Message = "FAILED: Could not create temporary test user." + Write-Host "✗ Failed to create test user: $_" -ForegroundColor Red + return $result + } + + # Step 4: Install SSH service + Write-Host "`n[3/6] Installing SSH service..." -ForegroundColor Yellow + Push-Location $buildPath + try { + # Check if service already exists + $existingService = Get-Service sshd -ErrorAction SilentlyContinue + if ($existingService) { + Write-Host " SSH service already exists, uninstalling first..." -ForegroundColor Gray + $uninstallScript = Join-Path $buildPath "uninstall-sshd.ps1" + if (Test-Path $uninstallScript) { + & $uninstallScript 2>&1 | Out-Null + Start-Sleep -Seconds 2 + } + } + + # Install the service + & $installScript 2>&1 | Out-Null + $serviceWasInstalled = $true + + # Verify installation + $service = Get-Service sshd -ErrorAction SilentlyContinue + if ($service) { + $result.ServiceInstalled = $true + Write-Host "✓ SSH service installed successfully" -ForegroundColor Green + } + else { + throw "Service installation completed but service not found" + } + } + catch { + $result.Errors += "Failed to install SSH service: $_" + $result.Message = "FAILED: SSH service installation failed." + Write-Host "✗ Failed to install SSH service: $_" -ForegroundColor Red + return $result + } + finally { + Pop-Location + } + + # Step 5: Start SSH service + Write-Host "`n[4/6] Starting SSH service..." -ForegroundColor Yellow + try { + Start-Service sshd -ErrorAction Stop + Start-Sleep -Seconds 2 + + $service = Get-Service sshd + if ($service.Status -eq 'Running') { + $result.ServiceStarted = $true + Write-Host "✓ SSH service started successfully" -ForegroundColor Green + } + else { + throw "Service status is $($service.Status), expected Running" + } + } + catch { + $result.Errors += "Failed to start SSH service: $_" + $result.Message = "FAILED: Could not start SSH service." + Write-Host "✗ Failed to start SSH service: $_" -ForegroundColor Red + return $result + } + + # Step 6: Configure Windows Firewall (if not skipped) + if (-not $SkipFirewall) { + Write-Host "`n[5/6] Configuring Windows Firewall..." -ForegroundColor Yellow + try { + # Check if rule already exists + $existingRule = Get-NetFirewallRule -DisplayName "SSH Server (sshd) - Test" -ErrorAction SilentlyContinue + if ($existingRule) { + Remove-NetFirewallRule -DisplayName "SSH Server (sshd) - Test" -ErrorAction SilentlyContinue + } + + New-NetFirewallRule -DisplayName "SSH Server (sshd) - Test" -Direction Inbound -Port 22 -Protocol TCP -Action Allow -ErrorAction Stop | Out-Null + $firewallRuleCreated = $true + Write-Host "✓ Firewall rule created" -ForegroundColor Green + } + catch { + # Non-critical error, continue with test + Write-Host "⚠ Firewall configuration failed (non-critical): $_" -ForegroundColor Yellow + } + } + else { + Write-Host "`n[5/6] Skipping firewall configuration (as requested)" -ForegroundColor Gray + } + + # Step 7: Test SSH connection + Write-Host "`n[6/6] Testing SSH connection..." -ForegroundColor Yellow + + # Prepare connection test + $sshClientPath = Join-Path $buildPath "ssh.exe" + $hostname = "localhost" + $testCommand = "echo hello world" + + # Create temporary files for password input and output capture + $tempPasswordFile = [System.IO.Path]::GetTempFileName() + $tempOutputFile = [System.IO.Path]::GetTempFileName() + $tempErrorFile = [System.IO.Path]::GetTempFileName() + + try { + # Write password to temp file (for potential use, though we'll use environment variable) + Set-Content -Path $tempPasswordFile -Value $testPassword -NoNewline + + # Build SSH command with password authentication forced + # Note: Windows SSH doesn't support stdin password directly, so we rely on interactive prompt handling + # For automated testing, we'll use SSH with key-based auth disabled and capture output + + $processInfo = New-Object System.Diagnostics.ProcessStartInfo + $processInfo.FileName = $sshClientPath + $processInfo.Arguments = "-o StrictHostKeyChecking=no -o UserKnownHostsFile=NUL -o PubkeyAuthentication=no -o PasswordAuthentication=yes $testUsername@$hostname `"$testCommand`"" + $processInfo.RedirectStandardInput = $true + $processInfo.RedirectStandardOutput = $true + $processInfo.RedirectStandardError = $true + $processInfo.UseShellExecute = $false + $processInfo.CreateNoWindow = $true + + $process = New-Object System.Diagnostics.Process + $process.StartInfo = $processInfo + + Write-Host " Attempting SSH connection to $testUsername@$hostname..." -ForegroundColor Gray + + $process.Start() | Out-Null + + # Wait for completion (with timeout) + $completed = $process.WaitForExit(15000) # 15 second timeout + + if (-not $completed) { + $process.Kill() + throw "SSH connection timed out after 15 seconds" + } + + $stdout = $process.StandardOutput.ReadToEnd() + $stderr = $process.StandardError.ReadToEnd() + $exitCode = $process.ExitCode + + # Check result + if ($exitCode -eq 0 -and $stdout -match "hello world") { + $result.ConnectionSuccessful = $true + $result.CommandOutput = $stdout.Trim() + $result.Success = $true + $result.Message = "SUCCESS: SSH connection test passed. Command executed successfully." + Write-Host "✓ SSH connection successful" -ForegroundColor Green + Write-Host " Command output: $($stdout.Trim())" -ForegroundColor Gray + } + else { + $result.Errors += "SSH connection failed with exit code $exitCode" + if ($stderr) { + $result.Errors += "SSH error: $stderr" + } + $result.Message = "FAILED: SSH connection test failed." + Write-Host "✗ SSH connection failed (exit code: $exitCode)" -ForegroundColor Red + if ($stderr) { + Write-Host " Error: $stderr" -ForegroundColor Red + } + } + } + catch { + $result.Errors += "SSH connection test error: $_" + $result.Message = "FAILED: SSH connection test encountered an error." + Write-Host "✗ SSH connection test error: $_" -ForegroundColor Red + } + finally { + # Clean up temp files + if (Test-Path $tempPasswordFile) { Remove-Item $tempPasswordFile -Force -ErrorAction SilentlyContinue } + if (Test-Path $tempOutputFile) { Remove-Item $tempOutputFile -Force -ErrorAction SilentlyContinue } + if (Test-Path $tempErrorFile) { Remove-Item $tempErrorFile -Force -ErrorAction SilentlyContinue } + } +} +finally { + # Cleanup: Always attempt to clean up resources + Write-Host "`n=== Cleanup ===" -ForegroundColor Cyan + + if ($NoCleanup) { + Write-Host "⚠ NoCleanup specified - leaving resources in place for investigation." -ForegroundColor Yellow + if ($testUser) { + Write-Host " Test user: $testUser" -ForegroundColor Yellow + } + if ($serviceWasInstalled) { + Write-Host " SSH service may still be installed/running (sshd)." -ForegroundColor Yellow + } + if ($firewallRuleCreated) { + Write-Host " Firewall rule: SSH Server (sshd) - Test" -ForegroundColor Yellow + } + Write-Host ""; + } else { + # Stop and uninstall SSH service + if ($serviceWasInstalled) { + Write-Host "Stopping SSH service..." -ForegroundColor Gray + try { + Stop-Service sshd -Force -ErrorAction SilentlyContinue + Start-Sleep -Seconds 1 + } + catch { + Write-Host "⚠ Warning: Failed to stop service: $_" -ForegroundColor Yellow + } + + Write-Host "Uninstalling SSH service..." -ForegroundColor Gray + $uninstallScript = Join-Path $buildPath "uninstall-sshd.ps1" + if (Test-Path $uninstallScript) { + Push-Location $buildPath + try { + & $uninstallScript 2>&1 | Out-Null + Write-Host "✓ SSH service uninstalled" -ForegroundColor Green + } + catch { + Write-Host "⚠ Warning: Failed to uninstall service: $_" -ForegroundColor Yellow + } + finally { + Pop-Location + } + } + } + + # Remove firewall rule + if ($firewallRuleCreated) { + Write-Host "Removing firewall rule..." -ForegroundColor Gray + try { + Remove-NetFirewallRule -DisplayName "SSH Server (sshd) - Test" -ErrorAction SilentlyContinue + Write-Host "✓ Firewall rule removed" -ForegroundColor Green + } + catch { + Write-Host "⚠ Warning: Failed to remove firewall rule: $_" -ForegroundColor Yellow + } + } + + # Remove test user + if ($testUser) { + Write-Host "Removing test user..." -ForegroundColor Gray + try { + Remove-LocalUser -Name $testUser -ErrorAction Stop + Write-Host "✓ Test user removed" -ForegroundColor Green + } + catch { + Write-Host "⚠ Warning: Failed to remove test user: $_" -ForegroundColor Yellow + Write-Host " You may need to manually remove user: $testUser" -ForegroundColor Yellow + } + } + + Write-Host "" + } +} + +# Output summary +Write-Host "=== Test Summary ===" -ForegroundColor Cyan +Write-Host "Status: $(if ($result.Success) { 'PASSED' } else { 'FAILED' })" -ForegroundColor $(if ($result.Success) { 'Green' } else { 'Red' }) +Write-Host "Service Installed: $($result.ServiceInstalled)" -ForegroundColor Gray +Write-Host "Service Started: $($result.ServiceStarted)" -ForegroundColor Gray +Write-Host "Connection Successful: $($result.ConnectionSuccessful)" -ForegroundColor Gray +if ($result.CommandOutput) { + Write-Host "Command Output: $($result.CommandOutput)" -ForegroundColor Gray +} +if ($result.Errors.Count -gt 0) { + Write-Host "Errors:" -ForegroundColor Red + foreach ($e in $result.Errors) { + Write-Host " - $e" -ForegroundColor Red + } +} +Write-Host "" + +# Return result object +return $result From 1053ed352101d114f969bce07efb9d8c1329a642 Mon Sep 17 00:00:00 2001 From: User Date: Fri, 9 Jan 2026 12:10:08 -0800 Subject: [PATCH 202/244] update instructions to branch off of current branch instead of latestw_all --- .github/agents/merge-upstream.agent.md | 2 +- .../merge/merge-details.instructions.md | 2 +- .../merge/merge-process-overview.instructions.md | 13 ++++--------- .github/instructions/merge/research.instructions.md | 2 +- .github/instructions/setup.instructions.md | 3 +-- 5 files changed, 8 insertions(+), 14 deletions(-) diff --git a/.github/agents/merge-upstream.agent.md b/.github/agents/merge-upstream.agent.md index a5565b25b883..240b1b956458 100644 --- a/.github/agents/merge-upstream.agent.md +++ b/.github/agents/merge-upstream.agent.md @@ -81,7 +81,7 @@ This agent assists with merging upstream OpenSSH commits into the PowerShell for 2. Confirm repository remotes are configured 3. Identify upstream version/tag to merge 4. Create merge branch: `merge-v-` -5. Perform baseline build on `latestw_all` branch +5. Perform baseline build from current branch 6. Use Get-CommitGroups with `-FirstChunkOnly -GroupByCIPresence` to get first commit batch **Success Criteria:** diff --git a/.github/instructions/merge/merge-details.instructions.md b/.github/instructions/merge/merge-details.instructions.md index b2214858543c..5c6f20d909d4 100644 --- a/.github/instructions/merge/merge-details.instructions.md +++ b/.github/instructions/merge/merge-details.instructions.md @@ -93,7 +93,7 @@ FUNCTION resolve_conflict(file_path, conflict_content): git show # Compare files between branches -git diff upstream-pwsh/latestw_all upstream/ -- +git diff HEAD upstream/ -- ``` ## Conflict Resolution Strategies diff --git a/.github/instructions/merge/merge-process-overview.instructions.md b/.github/instructions/merge/merge-process-overview.instructions.md index 34f4b413a6b5..fd8cce4b2620 100644 --- a/.github/instructions/merge/merge-process-overview.instructions.md +++ b/.github/instructions/merge/merge-process-overview.instructions.md @@ -47,24 +47,19 @@ The process consists of several interconnected phases: ## Merge Phase ### Initial Preparation -1. **Checkout base branch:** - ```pwsh - git checkout upstream-pwsh/latestw_all - ``` - -2. **Verify baseline build** +1. **Verify baseline build** **(📖 Detailed Instructions:** [Build Instructions](../build.instructions.md)): ```pwsh Import-Module .\contrib\win32\openssh\OpenSSHBuildHelper.psm1 -Force Start-OpenSSHBuild -Configuration Release -NativeHostArch x64 ``` -3. **Configure git:** +2. **Configure git:** ```pwsh git config core.editor true ``` -3. **Create merge branch:** +3. **Create merge branch from current branch:** ```pwsh git checkout -b merge-v- # Example: merge-v9.8-20241010 @@ -235,7 +230,7 @@ The process consists of several interconnected phases: ``` 15. **Create Pull Request:** - - Target: `PowerShell/openssh-portable:latestw_all` + - Target: `PowerShell/openssh-portable:` (typically the branch you started from, e.g., latestw_all) - Title: `Merge upstream OpenSSH ` - Include comprehensive description of changes and resolutions diff --git a/.github/instructions/merge/research.instructions.md b/.github/instructions/merge/research.instructions.md index f8b8c5032d5c..49b6b56a4226 100644 --- a/.github/instructions/merge/research.instructions.md +++ b/.github/instructions/merge/research.instructions.md @@ -63,7 +63,7 @@ git log --oneline upstream/ --since="" git show # Compare branches -git diff upstream-pwsh/latestw_all upstream/ +git diff HEAD upstream/ ``` ## Windows-Specific Knowledge Base diff --git a/.github/instructions/setup.instructions.md b/.github/instructions/setup.instructions.md index 3081ae3cfdd2..5ec3962af00f 100644 --- a/.github/instructions/setup.instructions.md +++ b/.github/instructions/setup.instructions.md @@ -42,7 +42,7 @@ git fetch --all ## Branch Strategy ### Understanding the Branch Structure -- **upstream-pwsh/latestw_all**: Main Windows-compatible branch (base for merges) +- **upstream-pwsh/latestw_all**: Main Windows-compatible branch - **upstream/master**: Latest upstream OpenSSH development - **upstream/V_X_Y_PZ**: Tagged releases (merge targets) @@ -74,7 +74,6 @@ Before proceeding to merge: - [ ] Repository cloned successfully - [ ] All three remotes configured (origin, upstream, upstream-pwsh) - [ ] Can fetch from all remotes without errors -- [ ] Can see upstream-pwsh/latestw_all branch - [ ] Can see upstream target version/branch - [ ] Working directory is clean (`git status` shows no uncommitted changes) From 2955382ceb21b7c65455cc373d5a312758a47414 Mon Sep 17 00:00:00 2001 From: User Date: Fri, 9 Jan 2026 12:17:50 -0800 Subject: [PATCH 203/244] remove direct references to scripts for mcp tools --- .github/agents/merge-upstream.agent.md | 21 +++++++----- .github/instructions/build.instructions.md | 32 ------------------- .../merge-process-overview.instructions.md | 1 - 3 files changed, 13 insertions(+), 41 deletions(-) diff --git a/.github/agents/merge-upstream.agent.md b/.github/agents/merge-upstream.agent.md index 240b1b956458..9014f07e45e5 100644 --- a/.github/agents/merge-upstream.agent.md +++ b/.github/agents/merge-upstream.agent.md @@ -24,23 +24,28 @@ This agent assists with merging upstream OpenSSH commits into the PowerShell for ### Key Tools Available 1. **Get-CommitGroups MCP Tool** - Groups commits by CI presence or success - - **Access**: Available via MCP server (preferred method) + - **Access**: Available via MCP server - **MCP Tool Name**: `mcp_pwsh-mcp-server_Get_CommitGroups` - - **Direct Script**: `.github/tools/Get-CommitGroups.ps1` (fallback) - **Parameters**: - `GitHubTag` (string, optional): GitHub tag to start from (e.g., "V_10_0_P2") - `StartCommit` (string, optional): Commit SHA to start from - `FirstChunkOnly` (boolean, optional): Stop after finding first chunk - `GroupByCIPresence` (boolean, optional): Group by CI presence instead of CI success - **Recommended Usage**: Always use `-FirstChunkOnly -GroupByCIPresence` for incremental merging - - **Usage via MCP**: Use the MCP tool function directly - it handles all GitHub API calls - - **Manual Usage**: `Get-Help .\Get-CommitGroups.ps1` for direct script execution + - **Usage**: Use the MCP tool function directly - it handles all GitHub API calls + - **If tool unavailable**: ERROR - This tool is required for the merge workflow -2. **OpenSSHBuildHelper Module** - Build automation - - Location: `contrib\win32\openssh\OpenSSHBuildHelper.psm1` - - Key cmdlet: `Start-OpenSSHBuild -Configuration Release -NativeHostArch x64` +2. **Build-OpenSSH MCP Tool** - Build automation and verification + - **Access**: Available via `.github/tools/Build-OpenSSH.ps1` + - **Usage**: `.github/tools/Build-OpenSSH.ps1 -Configuration Release -Architecture x64` + - **If tool unavailable**: ERROR - This tool is required for the merge workflow -3. **Git** - Version control operations +3. **Test-OpenSSHFunctionality MCP Tool** - Functional testing + - **Access**: Available via `.github/tools/Test-OpenSSHFunctionality.ps1` + - **Usage**: `.github/tools/Test-OpenSSHFunctionality.ps1` + - **If tool unavailable**: ERROR - This tool is required for the merge workflow + +4. **Git** - Version control operations - Cherry-pick: `git cherry-pick start_commit^..end_commit` (inclusive) - Status: `git status` - Remotes: `origin`, `upstream-pwsh`, `upstream` diff --git a/.github/instructions/build.instructions.md b/.github/instructions/build.instructions.md index 82f267f30cd9..fdd4549f207b 100644 --- a/.github/instructions/build.instructions.md +++ b/.github/instructions/build.instructions.md @@ -64,27 +64,6 @@ The repository includes MCP tools that automate the build, verification, and err .\.github\tools\Test-OpenSSHBuild.ps1 -Configuration Release -Architecture x64 ``` -### Using PowerShell Module Directly (Alternative) - -If you need direct access to the build module functions: - -#### Step 1: Environment Setup -```pwsh -# Navigate to repository root -cd - -# Import build helper module -Import-Module .\contrib\win32\openssh\OpenSSHBuildHelper.psm1 -Force - -# Verify module loaded -Get-Command -Module OpenSSHBuildHelper -``` - -#### Step 2: Initial Build -```pwsh -Start-OpenSSHBuild -Configuration Release -NativeHostArch x64 -``` - ## Compilation Error Resolution ### Common Error Categories @@ -255,17 +234,6 @@ contrib\win32\openssh\ - scp.exe, sftp.exe, sftp-server.exe - ssh-pkcs11-helper.exe, ssh-shellhost.exe, ssh-sk-helper.exe -### Manual Verification (Alternative) -```pwsh -# Check that all expected binaries were built -$buildPath = ".\contrib\win32\openssh\x64\Release" -Get-ChildItem $buildPath -Filter "*.exe" | Select-Object Name - -# Expected outputs: -# a binary for each vcxproj file, e.g. -# ssh.vcxproj -> ssh.exe -``` - ### Quick Functionality Test ```pwsh # Verify version reporting diff --git a/.github/instructions/merge/merge-process-overview.instructions.md b/.github/instructions/merge/merge-process-overview.instructions.md index fd8cce4b2620..d06bda0f986b 100644 --- a/.github/instructions/merge/merge-process-overview.instructions.md +++ b/.github/instructions/merge/merge-process-overview.instructions.md @@ -114,7 +114,6 @@ The process consists of several interconnected phases: git cherry-pick $commit # Build after every commit so we can attribute failures precisely. - # Prefer the MCP build helper if available; otherwise use Start-OpenSSHBuild. .\.github\tools\Build-OpenSSH.ps1 -Configuration Release -Architecture x64 } ``` From 36c482653550d3d42c46e82e2fe7c7cf8fba088b Mon Sep 17 00:00:00 2001 From: User Date: Fri, 9 Jan 2026 12:22:56 -0800 Subject: [PATCH 204/244] fix default log location in tool --- .github/tools/Test-OpenSSHBuild.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/tools/Test-OpenSSHBuild.ps1 b/.github/tools/Test-OpenSSHBuild.ps1 index 25aa95f4571c..afb978b778bc 100644 --- a/.github/tools/Test-OpenSSHBuild.ps1 +++ b/.github/tools/Test-OpenSSHBuild.ps1 @@ -142,7 +142,7 @@ try { $warnings = @() if (-not $LogFile) { - $LogFile = Join-Path $repoRoot "OpenSSH$Configuration$Architecture.log" + $LogFile = Join-Path $repoRoot "contrib\win32\openssh\OpenSSH$Configuration$Architecture.log" } if (Test-Path $LogFile) { From 2ffcb0e3aedfef3b088b44889c87cabd74f5e9b8 Mon Sep 17 00:00:00 2001 From: User Date: Fri, 9 Jan 2026 12:30:14 -0800 Subject: [PATCH 205/244] create tool for merge process prerequisites --- .github/agents/merge-upstream.agent.md | 34 +- .../merge-process-overview.instructions.md | 20 +- .github/tools/Test-MergePrerequisites.ps1 | 332 ++++++++++++++++++ 3 files changed, 374 insertions(+), 12 deletions(-) create mode 100644 .github/tools/Test-MergePrerequisites.ps1 diff --git a/.github/agents/merge-upstream.agent.md b/.github/agents/merge-upstream.agent.md index 9014f07e45e5..e5cca4d7b48e 100644 --- a/.github/agents/merge-upstream.agent.md +++ b/.github/agents/merge-upstream.agent.md @@ -82,17 +82,35 @@ This agent assists with merging upstream OpenSSH commits into the PowerShell for **Objective:** Verify environment and establish baseline **Steps:** -1. Verify Git, PowerShell, Visual Studio are available -2. Confirm repository remotes are configured -3. Identify upstream version/tag to merge -4. Create merge branch: `merge-v-` -5. Perform baseline build from current branch -6. Use Get-CommitGroups with `-FirstChunkOnly -GroupByCIPresence` to get first commit batch +1. **Run prerequisite verification via MCP tool:** + - **MCP Tool Name**: `mcp_test-server_Test_MergePrerequisites` + - **Parameters**: + - `TargetVersion` (string, required): Upstream version/tag to merge (e.g., "V_10_0_P2") + - `SkipBaselineBuild` (boolean, optional): Skip baseline build check (default: false) + + This single tool verifies: + - Git, PowerShell, Visual Studio are available + - Repository remotes are configured (origin, upstream, upstream-pwsh) + - Target version/tag exists in upstream + - Working directory is clean (no uncommitted changes) + - Baseline build passes from current branch + - First commit batch is identified + +2. **Proceed only if tool reports success:** + - Tool must return `Success: true` + - Tool must display "ALL PREREQUISITES MET" + - If tool fails, fix reported issues before continuing + +3. **Create merge branch:** + ```pwsh + git checkout -b merge-v- + # Example: git checkout -b merge-v10.0P2-20260109 + ``` **Success Criteria:** -- Base branch builds successfully -- First commit group identified (ending with any CI run) +- Prerequisite tool reports all checks passed - Merge branch created +- Ready to begin Phase 2 (cherry-picking first batch) ### Phase 2: Incremental Merge **Objective:** Cherry-pick commits in a single batch ending with a CI run diff --git a/.github/instructions/merge/merge-process-overview.instructions.md b/.github/instructions/merge/merge-process-overview.instructions.md index d06bda0f986b..491d36b3dd15 100644 --- a/.github/instructions/merge/merge-process-overview.instructions.md +++ b/.github/instructions/merge/merge-process-overview.instructions.md @@ -47,11 +47,23 @@ The process consists of several interconnected phases: ## Merge Phase ### Initial Preparation -1. **Verify baseline build** - **(📖 Detailed Instructions:** [Build Instructions](../build.instructions.md)): +1. **Verify prerequisites and baseline** + Use the Test-MergePrerequisites MCP tool: ```pwsh - Import-Module .\contrib\win32\openssh\OpenSSHBuildHelper.psm1 -Force - Start-OpenSSHBuild -Configuration Release -NativeHostArch x64 + # Run prerequisite check via MCP tool + # MCP Tool Name: mcp_test-server_Test_MergePrerequisites + # Parameters: TargetVersion (required), SkipBaselineBuild (optional) + + # Example invocation (replace with target like "V_10_0_P2"): + # The MCP tool will verify: + # - Git, PowerShell, Visual Studio installed + # - Repository remotes configured (origin, upstream, upstream-pwsh) + # - Target version exists in upstream + # - Working directory is clean + # - Baseline build passes (unless SkipBaselineBuild is true) + # - First commit batch identified + + # Proceed only if tool reports "ALL PREREQUISITES MET" ``` 2. **Configure git:** diff --git a/.github/tools/Test-MergePrerequisites.ps1 b/.github/tools/Test-MergePrerequisites.ps1 new file mode 100644 index 000000000000..c27c9bdb6dd5 --- /dev/null +++ b/.github/tools/Test-MergePrerequisites.ps1 @@ -0,0 +1,332 @@ +<# +.SYNOPSIS + MCP tool that verifies all prerequisites for starting an OpenSSH upstream merge. + +.DESCRIPTION + This script performs comprehensive pre-merge setup verification for the OpenSSH + upstream merge workflow. It checks: + - Required tools (Git, PowerShell, Visual Studio) + - Repository configuration (remotes, branch state) + - Baseline build capability + - Target version identification + + This tool should be run before starting Phase 1 of the merge workflow to ensure + all prerequisites are met. It prevents wasted effort by catching configuration + issues early. + +.PARAMETER TargetVersion + The upstream version/tag to merge (e.g., "V_10_0_P2", "V_9_9_P1") + This can be a tag name or branch name from the upstream repository. + +.PARAMETER SkipBaselineBuild + Skip the baseline build verification step. Use this if you've already + verified the base branch builds successfully. + Default: false (baseline build is performed) + +.OUTPUTS + Returns a hashtable with: + - Success: Boolean indicating all prerequisites passed + - GitInstalled: Boolean - Git is available + - PowerShellVersion: String - PowerShell version + - VSInstalled: Boolean - Visual Studio is available + - RemotesConfigured: Boolean - All required remotes configured + - TargetExists: Boolean - Target version/tag exists in upstream + - WorkingDirClean: Boolean - No uncommitted changes + - BaselineBuildPassed: Boolean - Base branch builds successfully (if not skipped) + - FirstChunkIdentified: Boolean - First commit batch identified + - FirstChunk: Object - First commit batch details from Get-CommitGroups + - Issues: Array - List of any issues found + - Message: String - Summary message + +.EXAMPLE + .\Test-MergePrerequisites.ps1 -TargetVersion "V_10_0_P2" + + Verifies all prerequisites for merging upstream V_10_0_P2. + +.EXAMPLE + .\Test-MergePrerequisites.ps1 -TargetVersion "V_10_0_P2" -SkipBaselineBuild + + Verifies prerequisites but skips the baseline build check. + +.NOTES + - This is a Phase 1 Pre-Merge Setup verification tool + - Should be run before creating the merge branch + - Requires approximately 2-5 minutes to complete (depending on baseline build) + - Part of the OpenSSH upstream merge workflow automation +#> + +param( + [Parameter(Mandatory=$true)] + [string]$TargetVersion, + + [Parameter(Mandatory=$false)] + [switch]$SkipBaselineBuild +) + +$scriptRoot = $PSScriptRoot +$repoRoot = (Get-Item $scriptRoot).Parent.Parent.FullName + +$result = @{ + Success = $false + GitInstalled = $false + PowerShellVersion = $PSVersionTable.PSVersion.ToString() + VSInstalled = $false + RemotesConfigured = $false + TargetExists = $false + WorkingDirClean = $false + BaselineBuildPassed = $null # null if skipped + FirstChunkIdentified = $false + FirstChunk = $null + Issues = @() + Message = "" +} + +try { + Write-Host "========================================" -ForegroundColor Cyan + Write-Host "OpenSSH Merge Prerequisites Check" -ForegroundColor Cyan + Write-Host "========================================" -ForegroundColor Cyan + Write-Host "Target Version: $TargetVersion" -ForegroundColor White + Write-Host "Skip Baseline: $SkipBaselineBuild" -ForegroundColor White + Write-Host "========================================`n" -ForegroundColor Cyan + + # Change to repository root + Push-Location $repoRoot + + # Step 1: Verify Git + Write-Host "[1/8] Checking Git installation..." -ForegroundColor Cyan + try { + $gitVersion = git --version 2>&1 + if ($LASTEXITCODE -eq 0) { + $result.GitInstalled = $true + Write-Host " ✓ Git installed: $gitVersion" -ForegroundColor Green + } else { + $result.Issues += "Git is not installed or not in PATH" + Write-Host " ✗ Git not found" -ForegroundColor Red + } + } catch { + $result.Issues += "Git is not installed or not in PATH" + Write-Host " ✗ Git not found" -ForegroundColor Red + } + + # Step 2: Verify PowerShell version + Write-Host "`n[2/8] Checking PowerShell version..." -ForegroundColor Cyan + $psVersion = $PSVersionTable.PSVersion + if ($psVersion.Major -ge 5) { + Write-Host " ✓ PowerShell $($psVersion.ToString()) (>= 5.0)" -ForegroundColor Green + } else { + $result.Issues += "PowerShell version $($psVersion.ToString()) is too old (need >= 5.0)" + Write-Host " ✗ PowerShell $($psVersion.ToString()) is too old (need >= 5.0)" -ForegroundColor Red + } + + # Step 3: Verify Visual Studio + Write-Host "`n[3/8] Checking Visual Studio installation..." -ForegroundColor Cyan + $msBuildPaths = @( + "${env:ProgramFiles}\Microsoft Visual Studio\2022\*\MSBuild\Current\Bin\MSBuild.exe", + "${env:ProgramFiles}\Microsoft Visual Studio\2019\*\MSBuild\Current\Bin\MSBuild.exe", + "${env:ProgramFiles(x86)}\Microsoft Visual Studio\2022\*\MSBuild\Current\Bin\MSBuild.exe", + "${env:ProgramFiles(x86)}\Microsoft Visual Studio\2019\*\MSBuild\Current\Bin\MSBuild.exe" + ) + + $msBuildFound = $false + foreach ($path in $msBuildPaths) { + $resolved = Resolve-Path $path -ErrorAction SilentlyContinue + if ($resolved) { + $msBuildFound = $true + $result.VSInstalled = $true + Write-Host " ✓ Visual Studio found: $($resolved.Path)" -ForegroundColor Green + break + } + } + + if (-not $msBuildFound) { + $result.Issues += "Visual Studio 2019 or later not found" + Write-Host " ✗ Visual Studio 2019 or later not found" -ForegroundColor Red + } + + # Step 4: Verify repository remotes + Write-Host "`n[4/8] Checking repository remotes..." -ForegroundColor Cyan + if ($result.GitInstalled) { + $remotes = git remote 2>&1 + $expectedRemotes = @('origin', 'upstream', 'upstream-pwsh') + $missingRemotes = @() + + foreach ($remote in $expectedRemotes) { + if ($remotes -contains $remote) { + $remoteUrl = git remote get-url $remote 2>&1 + Write-Host " ✓ $remote configured: $remoteUrl" -ForegroundColor Green + } else { + $missingRemotes += $remote + Write-Host " ✗ $remote not configured" -ForegroundColor Red + } + } + + if ($missingRemotes.Count -eq 0) { + $result.RemotesConfigured = $true + } else { + $result.Issues += "Missing remotes: $($missingRemotes -join ', ')" + } + } else { + Write-Host " ⊘ Skipped (Git not available)" -ForegroundColor Yellow + } + + # Step 5: Verify target version exists + Write-Host "`n[5/8] Checking target version exists..." -ForegroundColor Cyan + if ($result.GitInstalled -and $result.RemotesConfigured) { + Write-Host " Fetching from upstream..." -ForegroundColor Gray + git fetch upstream 2>&1 | Out-Null + + $tagExists = git rev-parse "upstream/$TargetVersion" 2>&1 + if ($LASTEXITCODE -eq 0) { + $result.TargetExists = $true + Write-Host " ✓ Target exists: upstream/$TargetVersion" -ForegroundColor Green + } else { + $result.Issues += "Target version/tag 'upstream/$TargetVersion' not found" + Write-Host " ✗ Target 'upstream/$TargetVersion' not found" -ForegroundColor Red + } + } else { + Write-Host " ⊘ Skipped (prerequisites not met)" -ForegroundColor Yellow + } + + # Step 6: Verify working directory is clean + Write-Host "`n[6/8] Checking working directory state..." -ForegroundColor Cyan + if ($result.GitInstalled) { + $status = git status --porcelain 2>&1 + if ([string]::IsNullOrWhiteSpace($status)) { + $result.WorkingDirClean = $true + Write-Host " ✓ Working directory is clean" -ForegroundColor Green + } else { + $result.Issues += "Working directory has uncommitted changes" + Write-Host " ✗ Working directory has uncommitted changes" -ForegroundColor Red + Write-Host " Run 'git status' to see changes" -ForegroundColor Yellow + } + } else { + Write-Host " ⊘ Skipped (Git not available)" -ForegroundColor Yellow + } + + # Step 7: Baseline build verification + Write-Host "`n[7/8] Verifying baseline build..." -ForegroundColor Cyan + if ($SkipBaselineBuild) { + Write-Host " ⊘ Skipped (SkipBaselineBuild flag set)" -ForegroundColor Yellow + } else { + $currentBranch = git rev-parse --abbrev-ref HEAD 2>&1 + Write-Host " Current branch: $currentBranch" -ForegroundColor Gray + Write-Host " Starting baseline build..." -ForegroundColor Gray + + $buildScriptPath = Join-Path $scriptRoot "Build-OpenSSH.ps1" + $buildResult = & $buildScriptPath -Configuration Release -Architecture x64 + + if ($buildResult.OverallSuccess) { + $result.BaselineBuildPassed = $true + Write-Host " ✓ Baseline build passed" -ForegroundColor Green + Write-Host " All $($buildResult.ExpectedArtifacts) artifacts built successfully" -ForegroundColor Gray + } else { + $result.BaselineBuildPassed = $false + $result.Issues += "Baseline build failed: $($buildResult.Message)" + Write-Host " ✗ Baseline build failed" -ForegroundColor Red + Write-Host " $($buildResult.Message)" -ForegroundColor Yellow + Write-Host " Check build log: $($buildResult.LogFile)" -ForegroundColor Yellow + } + } + + # Step 8: Identify first commit batch + Write-Host "`n[8/8] Identifying first commit batch..." -ForegroundColor Cyan + if ($result.GitInstalled -and $result.TargetExists) { + $commitGroupsScript = Join-Path $scriptRoot "Get-CommitGroups.ps1" + + Write-Host " Finding last merged tag..." -ForegroundColor Gray + # Find the last upstream tag in current branch + $lastTag = git describe --tags --match "V_*" --abbrev=0 2>&1 + + if ($LASTEXITCODE -eq 0) { + Write-Host " Last merged tag: $lastTag" -ForegroundColor Gray + Write-Host " Finding commits from $lastTag to $TargetVersion..." -ForegroundColor Gray + + try { + $firstChunk = & $commitGroupsScript -GitHubTag $lastTag -FirstChunkOnly -GroupByCIPresence + + if ($firstChunk -and $firstChunk.CommitCount -gt 0) { + $result.FirstChunkIdentified = $true + $result.FirstChunk = $firstChunk + Write-Host " ✓ First batch identified" -ForegroundColor Green + Write-Host " Range: $($firstChunk.StartCommit)..$($firstChunk.EndCommit)" -ForegroundColor Gray + Write-Host " Commits: $($firstChunk.CommitCount)" -ForegroundColor Gray + Write-Host " Start: $($firstChunk.StartMessage)" -ForegroundColor Gray + Write-Host " End: $($firstChunk.EndMessage)" -ForegroundColor Gray + } else { + $result.Issues += "No commits found between $lastTag and $TargetVersion" + Write-Host " ⚠ No new commits found (may already be up to date)" -ForegroundColor Yellow + } + } catch { + $result.Issues += "Failed to get commit groups: $($_.Exception.Message)" + Write-Host " ✗ Failed to get commit groups" -ForegroundColor Red + Write-Host " $($_.Exception.Message)" -ForegroundColor Yellow + } + } else { + $result.Issues += "Could not find last merged tag (no V_* tags in current branch)" + Write-Host " ✗ Could not find last merged tag" -ForegroundColor Red + } + } else { + Write-Host " ⊘ Skipped (prerequisites not met)" -ForegroundColor Yellow + } + + # Final evaluation + Write-Host "`n========================================" -ForegroundColor Cyan + Write-Host "PREREQUISITE CHECK SUMMARY" -ForegroundColor Cyan + Write-Host "========================================" -ForegroundColor Cyan + + $criticalChecks = @( + $result.GitInstalled, + $result.VSInstalled, + $result.RemotesConfigured, + $result.TargetExists, + $result.WorkingDirClean + ) + + # Baseline build is critical unless skipped + if (-not $SkipBaselineBuild) { + $criticalChecks += $result.BaselineBuildPassed + } + + # First chunk identification is informational, not critical + $result.Success = ($criticalChecks | Where-Object { $_ -eq $false }).Count -eq 0 + + if ($result.Success) { + Write-Host "✓ ALL PREREQUISITES MET" -ForegroundColor Green + Write-Host "`nYou are ready to begin the merge process:" -ForegroundColor White + Write-Host " 1. Create merge branch: git checkout -b merge-v$TargetVersion-$(Get-Date -Format 'yyyyMMdd')" -ForegroundColor Gray + Write-Host " 2. Begin cherry-picking commits from first batch" -ForegroundColor Gray + + if ($result.FirstChunkIdentified) { + Write-Host "`nFirst batch to merge:" -ForegroundColor White + Write-Host " git cherry-pick $($result.FirstChunk.StartCommitFull)^..$($result.FirstChunk.EndCommitFull)" -ForegroundColor Gray + } + + $result.Message = "All prerequisites met. Ready to start merge." + } else { + Write-Host "✗ PREREQUISITES NOT MET" -ForegroundColor Red + Write-Host "`nIssues found:" -ForegroundColor Yellow + foreach ($issue in $result.Issues) { + Write-Host " • $issue" -ForegroundColor Red + } + $result.Message = "$($result.Issues.Count) issue(s) found. Fix issues before starting merge." + } + + Write-Host "" + + return $result + +} catch { + Write-Host "`n========================================" -ForegroundColor Red + Write-Host "ERROR" -ForegroundColor Red + Write-Host "========================================" -ForegroundColor Red + Write-Host $_.Exception.Message -ForegroundColor Red + Write-Host $_.ScriptStackTrace -ForegroundColor Gray + + $result.Success = $false + $result.Issues += "Tool error: $($_.Exception.Message)" + $result.Message = "Prerequisite check failed with error: $($_.Exception.Message)" + + return $result +} finally { + Pop-Location +} From 4984b21ecd7e1b4bb41f0142483593cadcd37313 Mon Sep 17 00:00:00 2001 From: User Date: Fri, 9 Jan 2026 12:44:19 -0800 Subject: [PATCH 206/244] replace more direct scripts references to mcp tool references --- .github/agents/merge-upstream.agent.md | 76 +++++++++-------- .github/instructions/build.instructions.md | 71 ++++++++-------- .../merge-process-overview.instructions.md | 85 ++++++++++--------- .github/instructions/testing.instructions.md | 62 ++++++++++---- 4 files changed, 167 insertions(+), 127 deletions(-) diff --git a/.github/agents/merge-upstream.agent.md b/.github/agents/merge-upstream.agent.md index e5cca4d7b48e..da1c415110ce 100644 --- a/.github/agents/merge-upstream.agent.md +++ b/.github/agents/merge-upstream.agent.md @@ -25,7 +25,7 @@ This agent assists with merging upstream OpenSSH commits into the PowerShell for 1. **Get-CommitGroups MCP Tool** - Groups commits by CI presence or success - **Access**: Available via MCP server - - **MCP Tool Name**: `mcp_pwsh-mcp-server_Get_CommitGroups` + - **MCP Tool Name**: `mcp_openssh-server_Get_CommitGroups` - **Parameters**: - `GitHubTag` (string, optional): GitHub tag to start from (e.g., "V_10_0_P2") - `StartCommit` (string, optional): Commit SHA to start from @@ -36,13 +36,20 @@ This agent assists with merging upstream OpenSSH commits into the PowerShell for - **If tool unavailable**: ERROR - This tool is required for the merge workflow 2. **Build-OpenSSH MCP Tool** - Build automation and verification - - **Access**: Available via `.github/tools/Build-OpenSSH.ps1` - - **Usage**: `.github/tools/Build-OpenSSH.ps1 -Configuration Release -Architecture x64` + - **MCP Tool Name**: `mcp_openssh-serve_Build_OpenSSH` + - **Parameters**: + - `Configuration` (string, optional): Build configuration - "Debug" or "Release" (default: "Release") + - `Architecture` (string, optional): Target architecture - "x64", "x86", "ARM", "ARM64" (default: "x64") + - `Clean` (boolean, optional): Perform clean build (default: false) - **If tool unavailable**: ERROR - This tool is required for the merge workflow 3. **Test-OpenSSHFunctionality MCP Tool** - Functional testing - - **Access**: Available via `.github/tools/Test-OpenSSHFunctionality.ps1` - - **Usage**: `.github/tools/Test-OpenSSHFunctionality.ps1` + - **MCP Tool Name**: `mcp_openssh-serve_Test_OpenSSHFunctionality` + - **Parameters**: + - `Configuration` (string, optional): Build configuration - "Debug" or "Release" (default: "Release") + - `Architecture` (string, optional): Target architecture - "x64", "x86", "ARM", "ARM64" (default: "x64") + - `SkipFirewall` (boolean, optional): Skip firewall configuration (default: false) + - `NoCleanup` (boolean, optional): Skip cleanup for debugging (default: false) - **If tool unavailable**: ERROR - This tool is required for the merge workflow 4. **Git** - Version control operations @@ -83,7 +90,7 @@ This agent assists with merging upstream OpenSSH commits into the PowerShell for **Steps:** 1. **Run prerequisite verification via MCP tool:** - - **MCP Tool Name**: `mcp_test-server_Test_MergePrerequisites` + - **MCP Tool Name**: `mcp_openssh-server_Test_MergePrerequisites` - **Parameters**: - `TargetVersion` (string, required): Upstream version/tag to merge (e.g., "V_10_0_P2") - `SkipBaselineBuild` (boolean, optional): Skip baseline build check (default: false) @@ -116,25 +123,24 @@ This agent assists with merging upstream OpenSSH commits into the PowerShell for **Objective:** Cherry-pick commits in a single batch ending with a CI run **Steps:** -1. **Get first commit batch** using Get-CommitGroups with `-FirstChunkOnly -GroupByCIPresence`: - ```pwsh - # For first batch - start from last merged tag - .github\tools\Get-CommitGroups.ps1 -GitHubTag "V_10_0_P2" -FirstChunkOnly -GroupByCIPresence - - # For subsequent batches - start from last batch's end commit - .github\tools\Get-CommitGroups.ps1 -StartCommit "" -FirstChunkOnly -GroupByCIPresence +1. **Get first commit batch** using Get-CommitGroups MCP tool: + - **MCP Tool Name**: `mcp_openssh-serve_Get_CommitGroups` + - **Parameters**: + - For first batch: `GitHubTag="V_10_0_P2"`, `FirstChunkOnly=true`, `GroupByCIPresence=true` + - For subsequent batches: `StartCommit=""`, `FirstChunkOnly=true`, `GroupByCIPresence=true` - # The tool returns structured data: - # { - # "ChunkNumber": 1, - # "StartCommit": "609fe2c", - # "EndCommit": "6fb728d", - # "StartCommitFull": "609fe2cae2459d721ac11d23cd27b8a94397ef3c", - # "EndCommitFull": "6fb728df50c1afd338cb0223a84ce24579577eff", - # "CommitCount": 12, - # "StartMessage": "upstream: rework the text for -3 to make it clearer", - # "EndMessage": "Run all tests on Cygwin again." - # } + **The tool returns structured data:** + ```json + { + "ChunkNumber": 1, + "StartCommit": "609fe2c", + "EndCommit": "6fb728d", + "StartCommitFull": "609fe2cae2459d721ac11d23cd27b8a94397ef3c", + "EndCommitFull": "6fb728df50c1afd338cb0223a84ce24579577eff", + "CommitCount": 12, + "StartMessage": "upstream: rework the text for -3 to make it clearer", + "EndMessage": "Run all tests on Cygwin again." + } ``` 2. **Display batch information for verification:** @@ -164,9 +170,8 @@ This agent assists with merging upstream OpenSSH commits into the PowerShell for **Steps:** 1. **Build the merged code:** - ```pwsh - .github\tools\Build-OpenSSH.ps1 -Configuration Release -Architecture x64 - ``` + - **MCP Tool Name**: `mcp_openssh-serve_Build_OpenSSH` + - **Parameters**: `Configuration="Release"`, `Architecture="x64"` 2. **If build fails, fix compilation errors:** - Document all compilation errors from build output @@ -180,12 +185,12 @@ This agent assists with merging upstream OpenSSH commits into the PowerShell for - Look for commits ending with `CIStatus: "success"` in the detailed output 4. **If CI was successful, run validation tests:** - ```pwsh - .github\tools\Test-OpenSSHFunctionality.ps1 - ``` - - This test installs service, creates test user, validates SSH connectivity - - If tests fail, fix issues and commit fixes - - **Do not proceed** to next batch until tests pass + - **MCP Tool Name**: `mcp_openssh-serve_Test_OpenSSHFunctionality` + - **Parameters**: (use defaults for Release/x64) + + This test installs service, creates test user, validates SSH connectivity. + If tests fail, fix issues and commit fixes. + **Do not proceed** to next batch until tests pass. 5. **If CI was not successful (or no CI), skip validation:** - Build success is sufficient to proceed @@ -261,9 +266,8 @@ This agent assists with merging upstream OpenSSH commits into the PowerShell for - Summarize and get approval 3. **Continue** until all target commits are merged or HEAD is reached 4. **Perform final comprehensive validation:** - ```pwsh - .github\tools\Test-OpenSSHFunctionality.ps1 - ``` + - **MCP Tool Name**: `mcp_openssh-serve_Test_OpenSSHFunctionality` + - **Parameters**: (use defaults for Release/x64) **Success Criteria:** - All commit batches processed diff --git a/.github/instructions/build.instructions.md b/.github/instructions/build.instructions.md index fdd4549f207b..84b10974f4c0 100644 --- a/.github/instructions/build.instructions.md +++ b/.github/instructions/build.instructions.md @@ -31,16 +31,17 @@ git --version The repository includes MCP tools that automate the build, verification, and error analysis process. #### Option 1: Build & Verify (Recommended) -```pwsh -# Complete build and verification in one step -.\.github\tools\Build-OpenSSH.ps1 -Configuration Release -Architecture x64 - -# Clean build -.\.github\tools\Build-OpenSSH.ps1 -Configuration Release -Architecture x64 -Clean - -# Debug build -.\.github\tools\Build-OpenSSH.ps1 -Configuration Debug -Architecture x64 -``` +Use the Build-OpenSSH MCP tool: +- **MCP Tool Name**: `mcp_openssh-serve_Build_OpenSSH` +- **Parameters**: + - `Configuration` (optional): "Debug" or "Release" (default: "Release") + - `Architecture` (optional): "x64", "x86", "ARM", "ARM64" (default: "x64") + - `Clean` (optional): Perform clean build (default: false) + +**Examples:** +- Complete build and verification: `Configuration="Release"`, `Architecture="x64"` +- Clean build: `Configuration="Release"`, `Architecture="x64"`, `Clean=true` +- Debug build: `Configuration="Debug"`, `Architecture="x64"` **Output includes:** - Build success/failure status @@ -50,19 +51,21 @@ The repository includes MCP tools that automate the build, verification, and err - Build log location #### Option 2: Build Only -```pwsh -# Incremental build -.\.github\tools\Start-OpenSSHBuild.ps1 -Configuration Release -Architecture x64 +Use the Start-OpenSSHBuild MCP tool: +- **MCP Tool Name**: `mcp_openssh-serve_Start_OpenSSHBuild` +- **Parameters**: + - `Configuration` (optional): "Debug" or "Release" (default: "Release") + - `Architecture` (optional): "x64", "x86", "ARM", "ARM64" (default: "x64") + - `Clean` (optional): Perform clean build (default: false) -# Clean build -.\.github\tools\Start-OpenSSHBuild.ps1 -Configuration Release -Architecture x64 -Clean -``` +**Examples:** +- Incremental build: `Configuration="Release"`, `Architecture="x64"` +- Clean build: `Configuration="Release"`, `Architecture="x64"`, `Clean=true` #### Option 3: Test Existing Build -```pwsh -# Test artifacts and parse errors from previous build -.\.github\tools\Test-OpenSSHBuild.ps1 -Configuration Release -Architecture x64 -``` +Use the Test-OpenSSHBuild MCP tool: +- **MCP Tool Name**: `mcp_openssh-serve_Test_OpenSSHBuild` +- **Parameters**: `Configuration="Release"`, `Architecture="x64"` ## Compilation Error Resolution @@ -138,21 +141,21 @@ fatal error C1083: Cannot open source file: 'newfile.c' #### AI Agent Workflow: 1. **Attempt initial build using MCP tool** - ```pwsh - .\.github\tools\Build-OpenSSH.ps1 -Configuration Release -Architecture x64 - ``` + - **MCP Tool Name**: `mcp_openssh-serve_Build_OpenSSH` + - **Parameters**: `Configuration="Release"`, `Architecture="x64"` 2. **Review structured error output** from Build-OpenSSH tool 3. **Categorize error types** (preprocessor, Windows compatibility, build system) 4. **Apply appropriate resolution strategy** (see error categories above) -5. **Rebuild and verify** using Build-OpenSSH tool again +5. **Rebuild and verify** using Build-OpenSSH MCP tool again 6. **Commit fixes with detailed message** #### Manual Error Analysis Commands (if needed): -```pwsh -# Parse errors manually from log file -.\.github\tools\Test-OpenSSHBuild.ps1 -Configuration Release -Architecture x64 +Parse errors manually from log file using the Test-OpenSSHBuild MCP tool: +- **MCP Tool Name**: `mcp_openssh-serve_Test_OpenSSHBuild` +- **Parameters**: `Configuration="Release"`, `Architecture="x64"` -# Direct MSBuild with detailed logging +Or use direct MSBuild with detailed logging: +```pwsh & "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\MSBuild.exe" .\contrib\win32\openssh\Win32-OpenSSH.sln /p:Configuration=Release /p:Platform=x64 /v:detailed ``` @@ -215,13 +218,13 @@ contrib\win32\openssh\ ### Build Verification Using MCP Tools ```pwsh -# Recommended: Use Build-OpenSSH which includes testing -.\.github\tools\Build-OpenSSH.ps1 -Configuration Release -Architecture x64 - -# Or test an existing build -.\.github\tools\Test-OpenSSHBuild.ps1 -Configuration Release -Architecture x64 -``` +Use the Build-OpenSSH MCP tool (recommended): +- **MCP Tool Name**: `mcp_openssh-serve_Build_OpenSSH` +- **Parameters**: `Configuration="Release"`, `Architecture="x64"` +Or test an existing build: +- **MCP Tool Name**: `mcp_openssh-serve_Test_OpenSSHBuild` +- **Parameters**: `Configuration="Release"`, `Architecture="x64" **Expected Output:** - Success/failure status - 14 of 14 artifacts found diff --git a/.github/instructions/merge/merge-process-overview.instructions.md b/.github/instructions/merge/merge-process-overview.instructions.md index 491d36b3dd15..69083761a9fd 100644 --- a/.github/instructions/merge/merge-process-overview.instructions.md +++ b/.github/instructions/merge/merge-process-overview.instructions.md @@ -51,7 +51,7 @@ The process consists of several interconnected phases: Use the Test-MergePrerequisites MCP tool: ```pwsh # Run prerequisite check via MCP tool - # MCP Tool Name: mcp_test-server_Test_MergePrerequisites + # MCP Tool Name: mcp_openssh-server_Test_MergePrerequisites # Parameters: TargetVersion (required), SkipBaselineBuild (optional) # Example invocation (replace with target like "V_10_0_P2"): @@ -79,35 +79,41 @@ The process consists of several interconnected phases: ### Perform Merge with Grouped Commits 4. **Identify merge range and group commits:** - Use .\tools\Get-CommitGroups.ps1 with `-FirstChunkOnly -GroupByCIPresence` - ```pwsh - # Find the last upstream tag in the fork (this is the starting point for the next merge) - # Call .\tools\Get-CommitGroups.ps1 -GitHubTag -FirstChunkOnly -GroupByCIPresence - # This gets commits ending with any commit that has CI runs (not just successful CI) - # Example output: - # { - # "ChunkNumber": 1, - # "StartCommit": "609fe2c", - # "EndCommit": "6fb728d", - # "StartCommitFull": "609fe2cae2459d721ac11d23cd27b8a94397ef3c", - # "EndCommitFull": "6fb728df50c1afd338cb0223a84ce24579577eff", - # "CommitCount": 57, - # "StartMessage": "upstream: rework the text for -3 to make it clearer what default", - # "EndMessage": "Run all tests on Cygwin again." - # } - - # Print the commit batch details for verification - Write-Host "Processing batch: $($result.StartCommit)..$($result.EndCommit)" - Write-Host "Start: $($result.StartMessage)" - Write-Host "End: $($result.EndMessage)" - Write-Host "End Commit CI Status: $($result.EndCommit has CI runs)" - - # After completing steps below, get next batch: - # Call .\tools\Get-CommitGroups.ps1 -StartCommit -FirstChunkOnly -GroupByCIPresence - # Continue this process untiland - # follow the below steps to completion until the upstream's HEAD has been successfully merged + Use the Get-CommitGroups MCP tool with `-FirstChunkOnly -GroupByCIPresence` + + **MCP Tool Name**: `mcp_openssh-serve_Get_CommitGroups` + + **Parameters**: + - `GitHubTag` (string, optional): Start from last merged tag (e.g., "V_10_0_P2") + - `StartCommit` (string, optional): Start from specific commit SHA + - `FirstChunkOnly` (boolean): Set to `true` + - `GroupByCIPresence` (boolean): Set to `true` + + **Example for first batch**: + - Find the last upstream tag in the fork + - Call tool with `GitHubTag=`, `FirstChunkOnly=true`, `GroupByCIPresence=true` + - This gets commits ending with any commit that has CI runs (not just successful CI) + + **Example output:** + ```json + { + "ChunkNumber": 1, + "StartCommit": "609fe2c", + "EndCommit": "6fb728d", + "StartCommitFull": "609fe2cae2459d721ac11d23cd27b8a94397ef3c", + "EndCommitFull": "6fb728df50c1afd338cb0223a84ce24579577eff", + "CommitCount": 57, + "StartMessage": "upstream: rework the text for -3 to make it clearer what default", + "EndMessage": "Run all tests on Cygwin again." + } ``` + Display batch details for verification, then proceed with cherry-picking. + + **After completing steps below, get next batch**: + - Call tool with `StartCommit=`, `FirstChunkOnly=true`, `GroupByCIPresence=true` + - Continue this process until the upstream's HEAD has been successfully merged + 5. **Execute chunked merge (commit-by-commit within the chunk):** **Important:** Even though commits are *grouped* into chunks for planning/CI boundaries, **cherry-pick each commit individually** within the chunk and **build after each commit**. This catches Windows-specific build breaks early and makes it clear which upstream commit introduced a regression. @@ -126,7 +132,8 @@ The process consists of several interconnected phases: git cherry-pick $commit # Build after every commit so we can attribute failures precisely. - .\.github\tools\Build-OpenSSH.ps1 -Configuration Release -Architecture x64 + # Use MCP Tool: mcp_openssh-serve_Build_OpenSSH + # Parameters: Configuration="Release", Architecture="x64" } ``` @@ -149,21 +156,19 @@ The process consists of several interconnected phases: ``` 9. **Build after completing the batch:** - ```pwsh - .\.github\tools\Build-OpenSSH.ps1 -Configuration Release -Architecture x64 + Use the Build-OpenSSH MCP tool: + - **MCP Tool Name**: `mcp_openssh-serve_Build_OpenSSH` + - **Parameters**: `Configuration="Release"`, `Architecture="x64"` - # If build fails, fix issues and rebuild - # Commit any build fixes separately - ``` + If build fails, fix issues and rebuild. Commit any build fixes separately. 10. **Validate if batch ended with successful CI:** - ```pwsh - # Check the end commit's CI status from Get-CommitGroups output - # If CI was successful, run validation: - .\.github\tools\Test-OpenSSHFunctionality.ps1 + Check the end commit's CI status from Get-CommitGroups output. + If CI was successful, run validation: + - **MCP Tool Name**: `mcp_openssh-serve_Test_OpenSSHFunctionality` + - **Parameters**: (use defaults for Release/x64) - # If no CI or failed CI, skip validation (build success is sufficient) - ``` + If no CI or failed CI, skip validation (build success is sufficient). 11. **Provide summary and get approval:** - Summarize batch changes, conflicts resolved, build status, validation status diff --git a/.github/instructions/testing.instructions.md b/.github/instructions/testing.instructions.md index 7aa715edeab2..00a60db8fc4d 100644 --- a/.github/instructions/testing.instructions.md +++ b/.github/instructions/testing.instructions.md @@ -13,16 +13,18 @@ This document provides comprehensive testing procedures for validating OpenSSH-P The repository includes an MCP tool that automates end-to-end functional testing of OpenSSH on Windows. -```pwsh -# Run automated functional test (requires Administrator privileges) -.\.github\tools\Test-OpenSSHFunctionality.ps1 - -# Test with specific configuration -.\.github\tools\Test-OpenSSHFunctionality.ps1 -Configuration Debug -Architecture x64 - -# Skip firewall configuration if rules already exist -.\.github\tools\Test-OpenSSHFunctionality.ps1 -SkipFirewall -``` +Use the Test-OpenSSHFunctionality MCP tool: +- **MCP Tool Name**: `mcp_openssh-serve_Test_OpenSSHFunctionality` +- **Parameters**: + - `Configuration` (optional): "Debug" or "Release" (default: "Release") + - `Architecture` (optional): "x64", "x86", "ARM", "ARM64" (default: "x64") + - `SkipFirewall` (optional): Skip firewall configuration (default: false) + - `NoCleanup` (optional): Skip cleanup for debugging (default: false) + +**Examples:** +- Run with defaults: (no parameters needed) +- Test with specific configuration: `Configuration="Debug"`, `Architecture="x64"` +- Skip firewall configuration: `SkipFirewall=true` **What the tool does:** 1. Verifies Administrator privileges @@ -69,9 +71,36 @@ Status: PASSED - `Errors`: Array of any errors encountered - `Message`: Summary message -## Manual Testing Procedures +## Primary Testing Approach + +**Use the automated Test-OpenSSHFunctionality MCP tool for all testing.** + +The MCP tool performs comprehensive end-to-end testing including: +- Administrator privilege verification +- Temporary test user creation +- SSH service installation and startup +- Windows Firewall configuration +- SSH connection testing with password authentication +- Command execution verification +- Complete cleanup of all test resources + +**MCP Tool Name**: `mcp_openssh-serve_Test_OpenSSHFunctionality` + +**Parameters**: +- `Configuration` (optional): "Debug" or "Release" (default: "Release") +- `Architecture` (optional): "x64", "x86", "ARM", "ARM64" (default: "x64") +- `SkipFirewall` (optional): Skip firewall configuration (default: false) +- `NoCleanup` (optional): Skip cleanup for debugging (default: false) + +**When to use**: +- After successful build to validate functionality +- During merge process at CI checkpoints +- Before creating pull requests +- When debugging SSH connectivity issues + +## Manual Testing Procedures (For Troubleshooting Only) -If you need to perform manual testing or troubleshoot specific issues, follow these procedures: +If the automated MCP tool fails and you need to troubleshoot specific issues manually, follow these procedures: ### Prerequisites Check ```pwsh @@ -197,7 +226,7 @@ Get-NetFirewallRule | Where-Object {$_.DisplayName -like "*SSH*"} ## Success Criteria **Testing is successful when:** -- [ ] All expected executables are present after build (verified by Test-OpenSSHBuild.ps1) +- [ ] All expected executables are present after build (verified by Test-OpenSSHBuild MCP tool) - [ ] SSH service installs and starts without errors - [ ] SSH connection with password authentication succeeds - [ ] Test command executes successfully via SSH connection @@ -206,7 +235,7 @@ Get-NetFirewallRule | Where-Object {$_.DisplayName -like "*SSH*"} ## AI Agent Guidelines -1. **Use automated testing tools** whenever possible - prefer Test-OpenSSHFunctionality.ps1 over manual procedures +1. **Use automated testing tools** whenever possible - use the Test-OpenSSHFunctionality MCP tool over manual procedures 2. **Run tests incrementally** during the merge process, not just at the end 3. **Document any test failures** and their resolutions in commit messages 4. **Pay special attention to Windows-specific functionality** that might be affected by upstream changes @@ -216,9 +245,8 @@ Get-NetFirewallRule | Where-Object {$_.DisplayName -like "*SSH*"} ### Recommended Testing Workflow for AI Agents 1. **After successful build**, run the automated functionality test: - ```pwsh - .\.github\tools\Test-OpenSSHFunctionality.ps1 - ``` + - **MCP Tool Name**: `mcp_openssh-serve_Test_OpenSSHFunctionality` + - **Parameters**: (use defaults) 2. **If test passes**, the merge is validated for basic SSH functionality From 63ac1acf50e0457881163d966c84cd86530e493e Mon Sep 17 00:00:00 2001 From: User Date: Fri, 9 Jan 2026 13:00:53 -0800 Subject: [PATCH 207/244] update mcp server name --- .github/agents/merge-upstream.agent.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/agents/merge-upstream.agent.md b/.github/agents/merge-upstream.agent.md index da1c415110ce..a45f950eb2cf 100644 --- a/.github/agents/merge-upstream.agent.md +++ b/.github/agents/merge-upstream.agent.md @@ -2,7 +2,7 @@ name: merge-upstream description: Assist with merging upstream OpenSSH commits into the PowerShell fork. tools: - ['vscode', 'execute', 'read', 'edit', 'search', 'web', 'test-server/*', 'agent', 'todo'] + ['vscode', 'execute', 'read', 'edit', 'search', 'web', 'openssh-server/*', 'agent', 'todo'] --- # OpenSSH Upstream Merge Agent From 644bbf55b5659aa86da2ad48200832a69dfbb036 Mon Sep 17 00:00:00 2001 From: User Date: Fri, 9 Jan 2026 13:05:38 -0800 Subject: [PATCH 208/244] fix merge prereq tool --- .github/tools/Test-MergePrerequisites.ps1 | 78 ++++++----------------- 1 file changed, 19 insertions(+), 59 deletions(-) diff --git a/.github/tools/Test-MergePrerequisites.ps1 b/.github/tools/Test-MergePrerequisites.ps1 index c27c9bdb6dd5..cb7877791d58 100644 --- a/.github/tools/Test-MergePrerequisites.ps1 +++ b/.github/tools/Test-MergePrerequisites.ps1 @@ -75,8 +75,6 @@ $result = @{ TargetExists = $false WorkingDirClean = $false BaselineBuildPassed = $null # null if skipped - FirstChunkIdentified = $false - FirstChunk = $null Issues = @() Message = "" } @@ -170,25 +168,33 @@ try { } # Step 5: Verify target version exists - Write-Host "`n[5/8] Checking target version exists..." -ForegroundColor Cyan + Write-Host "`n[5/7] Checking target version exists..." -ForegroundColor Cyan if ($result.GitInstalled -and $result.RemotesConfigured) { Write-Host " Fetching from upstream..." -ForegroundColor Gray - git fetch upstream 2>&1 | Out-Null + git fetch upstream --tags 2>&1 | Out-Null - $tagExists = git rev-parse "upstream/$TargetVersion" 2>&1 + # Check if it's a tag first, then try as a branch + $tagExists = git rev-parse "$TargetVersion" 2>&1 if ($LASTEXITCODE -eq 0) { $result.TargetExists = $true - Write-Host " ✓ Target exists: upstream/$TargetVersion" -ForegroundColor Green + Write-Host " ✓ Target tag exists: $TargetVersion" -ForegroundColor Green } else { - $result.Issues += "Target version/tag 'upstream/$TargetVersion' not found" - Write-Host " ✗ Target 'upstream/$TargetVersion' not found" -ForegroundColor Red + # Try as a branch + $branchExists = git rev-parse "upstream/$TargetVersion" 2>&1 + if ($LASTEXITCODE -eq 0) { + $result.TargetExists = $true + Write-Host " ✓ Target branch exists: upstream/$TargetVersion" -ForegroundColor Green + } else { + $result.Issues += "Target version/tag '$TargetVersion' not found in upstream" + Write-Host " ✗ Target '$TargetVersion' not found" -ForegroundColor Red + } } } else { Write-Host " ⊘ Skipped (prerequisites not met)" -ForegroundColor Yellow } # Step 6: Verify working directory is clean - Write-Host "`n[6/8] Checking working directory state..." -ForegroundColor Cyan + Write-Host "`n[6/7] Checking working directory state..." -ForegroundColor Cyan if ($result.GitInstalled) { $status = git status --porcelain 2>&1 if ([string]::IsNullOrWhiteSpace($status)) { @@ -204,7 +210,7 @@ try { } # Step 7: Baseline build verification - Write-Host "`n[7/8] Verifying baseline build..." -ForegroundColor Cyan + Write-Host "`n[7/7] Verifying baseline build..." -ForegroundColor Cyan if ($SkipBaselineBuild) { Write-Host " ⊘ Skipped (SkipBaselineBuild flag set)" -ForegroundColor Yellow } else { @@ -228,47 +234,6 @@ try { } } - # Step 8: Identify first commit batch - Write-Host "`n[8/8] Identifying first commit batch..." -ForegroundColor Cyan - if ($result.GitInstalled -and $result.TargetExists) { - $commitGroupsScript = Join-Path $scriptRoot "Get-CommitGroups.ps1" - - Write-Host " Finding last merged tag..." -ForegroundColor Gray - # Find the last upstream tag in current branch - $lastTag = git describe --tags --match "V_*" --abbrev=0 2>&1 - - if ($LASTEXITCODE -eq 0) { - Write-Host " Last merged tag: $lastTag" -ForegroundColor Gray - Write-Host " Finding commits from $lastTag to $TargetVersion..." -ForegroundColor Gray - - try { - $firstChunk = & $commitGroupsScript -GitHubTag $lastTag -FirstChunkOnly -GroupByCIPresence - - if ($firstChunk -and $firstChunk.CommitCount -gt 0) { - $result.FirstChunkIdentified = $true - $result.FirstChunk = $firstChunk - Write-Host " ✓ First batch identified" -ForegroundColor Green - Write-Host " Range: $($firstChunk.StartCommit)..$($firstChunk.EndCommit)" -ForegroundColor Gray - Write-Host " Commits: $($firstChunk.CommitCount)" -ForegroundColor Gray - Write-Host " Start: $($firstChunk.StartMessage)" -ForegroundColor Gray - Write-Host " End: $($firstChunk.EndMessage)" -ForegroundColor Gray - } else { - $result.Issues += "No commits found between $lastTag and $TargetVersion" - Write-Host " ⚠ No new commits found (may already be up to date)" -ForegroundColor Yellow - } - } catch { - $result.Issues += "Failed to get commit groups: $($_.Exception.Message)" - Write-Host " ✗ Failed to get commit groups" -ForegroundColor Red - Write-Host " $($_.Exception.Message)" -ForegroundColor Yellow - } - } else { - $result.Issues += "Could not find last merged tag (no V_* tags in current branch)" - Write-Host " ✗ Could not find last merged tag" -ForegroundColor Red - } - } else { - Write-Host " ⊘ Skipped (prerequisites not met)" -ForegroundColor Yellow - } - # Final evaluation Write-Host "`n========================================" -ForegroundColor Cyan Write-Host "PREREQUISITE CHECK SUMMARY" -ForegroundColor Cyan @@ -287,19 +252,14 @@ try { $criticalChecks += $result.BaselineBuildPassed } - # First chunk identification is informational, not critical $result.Success = ($criticalChecks | Where-Object { $_ -eq $false }).Count -eq 0 if ($result.Success) { Write-Host "✓ ALL PREREQUISITES MET" -ForegroundColor Green Write-Host "`nYou are ready to begin the merge process:" -ForegroundColor White - Write-Host " 1. Create merge branch: git checkout -b merge-v$TargetVersion-$(Get-Date -Format 'yyyyMMdd')" -ForegroundColor Gray - Write-Host " 2. Begin cherry-picking commits from first batch" -ForegroundColor Gray - - if ($result.FirstChunkIdentified) { - Write-Host "`nFirst batch to merge:" -ForegroundColor White - Write-Host " git cherry-pick $($result.FirstChunk.StartCommitFull)^..$($result.FirstChunk.EndCommitFull)" -ForegroundColor Gray - } + Write-Host " 1. Create merge branch: git checkout -b merge-$TargetVersion-$(Get-Date -Format 'yyyyMMdd')" -ForegroundColor Gray + Write-Host " 2. Use Get-CommitGroups tool to identify first batch of commits" -ForegroundColor Gray + Write-Host " 3. Begin cherry-picking commits from first batch" -ForegroundColor Gray $result.Message = "All prerequisites met. Ready to start merge." } else { From 1d8b2015110e8f44cfc5f3c373e42f1a5b8625f8 Mon Sep 17 00:00:00 2001 From: User Date: Fri, 9 Jan 2026 13:16:40 -0800 Subject: [PATCH 209/244] update merge prereq tool --- .github/tools/Test-MergePrerequisites.ps1 | 70 +++++------------------ 1 file changed, 13 insertions(+), 57 deletions(-) diff --git a/.github/tools/Test-MergePrerequisites.ps1 b/.github/tools/Test-MergePrerequisites.ps1 index cb7877791d58..8ae3b1f3f3da 100644 --- a/.github/tools/Test-MergePrerequisites.ps1 +++ b/.github/tools/Test-MergePrerequisites.ps1 @@ -7,22 +7,19 @@ upstream merge workflow. It checks: - Required tools (Git, PowerShell, Visual Studio) - Repository configuration (remotes, branch state) - - Baseline build capability - Target version identification This tool should be run before starting Phase 1 of the merge workflow to ensure all prerequisites are met. It prevents wasted effort by catching configuration issues early. + + To verify baseline build capability, use the Test-OpenSSHBuild MCP tool: + mcp_openssh-serve_Test_OpenSSHBuild .PARAMETER TargetVersion The upstream version/tag to merge (e.g., "V_10_0_P2", "V_9_9_P1") This can be a tag name or branch name from the upstream repository. -.PARAMETER SkipBaselineBuild - Skip the baseline build verification step. Use this if you've already - verified the base branch builds successfully. - Default: false (baseline build is performed) - .OUTPUTS Returns a hashtable with: - Success: Boolean indicating all prerequisites passed @@ -32,9 +29,6 @@ - RemotesConfigured: Boolean - All required remotes configured - TargetExists: Boolean - Target version/tag exists in upstream - WorkingDirClean: Boolean - No uncommitted changes - - BaselineBuildPassed: Boolean - Base branch builds successfully (if not skipped) - - FirstChunkIdentified: Boolean - First commit batch identified - - FirstChunk: Object - First commit batch details from Get-CommitGroups - Issues: Array - List of any issues found - Message: String - Summary message @@ -42,25 +36,18 @@ .\Test-MergePrerequisites.ps1 -TargetVersion "V_10_0_P2" Verifies all prerequisites for merging upstream V_10_0_P2. - -.EXAMPLE - .\Test-MergePrerequisites.ps1 -TargetVersion "V_10_0_P2" -SkipBaselineBuild - - Verifies prerequisites but skips the baseline build check. + For baseline build verification, use Test-OpenSSHBuild MCP tool separately. .NOTES - This is a Phase 1 Pre-Merge Setup verification tool - Should be run before creating the merge branch - - Requires approximately 2-5 minutes to complete (depending on baseline build) + - For baseline build verification, use: mcp_openssh-serve_Test_OpenSSHBuild - Part of the OpenSSH upstream merge workflow automation #> param( [Parameter(Mandatory=$true)] - [string]$TargetVersion, - - [Parameter(Mandatory=$false)] - [switch]$SkipBaselineBuild + [string]$TargetVersion ) $scriptRoot = $PSScriptRoot @@ -74,7 +61,6 @@ $result = @{ RemotesConfigured = $false TargetExists = $false WorkingDirClean = $false - BaselineBuildPassed = $null # null if skipped Issues = @() Message = "" } @@ -84,14 +70,13 @@ try { Write-Host "OpenSSH Merge Prerequisites Check" -ForegroundColor Cyan Write-Host "========================================" -ForegroundColor Cyan Write-Host "Target Version: $TargetVersion" -ForegroundColor White - Write-Host "Skip Baseline: $SkipBaselineBuild" -ForegroundColor White Write-Host "========================================`n" -ForegroundColor Cyan # Change to repository root Push-Location $repoRoot # Step 1: Verify Git - Write-Host "[1/8] Checking Git installation..." -ForegroundColor Cyan + Write-Host "[1/6] Checking Git installation..." -ForegroundColor Cyan try { $gitVersion = git --version 2>&1 if ($LASTEXITCODE -eq 0) { @@ -107,7 +92,7 @@ try { } # Step 2: Verify PowerShell version - Write-Host "`n[2/8] Checking PowerShell version..." -ForegroundColor Cyan + Write-Host "`n[2/6] Checking PowerShell version..." -ForegroundColor Cyan $psVersion = $PSVersionTable.PSVersion if ($psVersion.Major -ge 5) { Write-Host " ✓ PowerShell $($psVersion.ToString()) (>= 5.0)" -ForegroundColor Green @@ -117,7 +102,7 @@ try { } # Step 3: Verify Visual Studio - Write-Host "`n[3/8] Checking Visual Studio installation..." -ForegroundColor Cyan + Write-Host "`n[3/6] Checking Visual Studio installation..." -ForegroundColor Cyan $msBuildPaths = @( "${env:ProgramFiles}\Microsoft Visual Studio\2022\*\MSBuild\Current\Bin\MSBuild.exe", "${env:ProgramFiles}\Microsoft Visual Studio\2019\*\MSBuild\Current\Bin\MSBuild.exe", @@ -142,7 +127,7 @@ try { } # Step 4: Verify repository remotes - Write-Host "`n[4/8] Checking repository remotes..." -ForegroundColor Cyan + Write-Host "`n[4/6] Checking repository remotes..." -ForegroundColor Cyan if ($result.GitInstalled) { $remotes = git remote 2>&1 $expectedRemotes = @('origin', 'upstream', 'upstream-pwsh') @@ -168,7 +153,7 @@ try { } # Step 5: Verify target version exists - Write-Host "`n[5/7] Checking target version exists..." -ForegroundColor Cyan + Write-Host "`n[5/6] Checking target version exists..." -ForegroundColor Cyan if ($result.GitInstalled -and $result.RemotesConfigured) { Write-Host " Fetching from upstream..." -ForegroundColor Gray git fetch upstream --tags 2>&1 | Out-Null @@ -194,7 +179,7 @@ try { } # Step 6: Verify working directory is clean - Write-Host "`n[6/7] Checking working directory state..." -ForegroundColor Cyan + Write-Host "`n[6/6] Checking working directory state..." -ForegroundColor Cyan if ($result.GitInstalled) { $status = git status --porcelain 2>&1 if ([string]::IsNullOrWhiteSpace($status)) { @@ -209,31 +194,6 @@ try { Write-Host " ⊘ Skipped (Git not available)" -ForegroundColor Yellow } - # Step 7: Baseline build verification - Write-Host "`n[7/7] Verifying baseline build..." -ForegroundColor Cyan - if ($SkipBaselineBuild) { - Write-Host " ⊘ Skipped (SkipBaselineBuild flag set)" -ForegroundColor Yellow - } else { - $currentBranch = git rev-parse --abbrev-ref HEAD 2>&1 - Write-Host " Current branch: $currentBranch" -ForegroundColor Gray - Write-Host " Starting baseline build..." -ForegroundColor Gray - - $buildScriptPath = Join-Path $scriptRoot "Build-OpenSSH.ps1" - $buildResult = & $buildScriptPath -Configuration Release -Architecture x64 - - if ($buildResult.OverallSuccess) { - $result.BaselineBuildPassed = $true - Write-Host " ✓ Baseline build passed" -ForegroundColor Green - Write-Host " All $($buildResult.ExpectedArtifacts) artifacts built successfully" -ForegroundColor Gray - } else { - $result.BaselineBuildPassed = $false - $result.Issues += "Baseline build failed: $($buildResult.Message)" - Write-Host " ✗ Baseline build failed" -ForegroundColor Red - Write-Host " $($buildResult.Message)" -ForegroundColor Yellow - Write-Host " Check build log: $($buildResult.LogFile)" -ForegroundColor Yellow - } - } - # Final evaluation Write-Host "`n========================================" -ForegroundColor Cyan Write-Host "PREREQUISITE CHECK SUMMARY" -ForegroundColor Cyan @@ -247,16 +207,12 @@ try { $result.WorkingDirClean ) - # Baseline build is critical unless skipped - if (-not $SkipBaselineBuild) { - $criticalChecks += $result.BaselineBuildPassed - } - $result.Success = ($criticalChecks | Where-Object { $_ -eq $false }).Count -eq 0 if ($result.Success) { Write-Host "✓ ALL PREREQUISITES MET" -ForegroundColor Green Write-Host "`nYou are ready to begin the merge process:" -ForegroundColor White + Write-Host " 0. (Optional) Verify baseline build: mcp_openssh-serve_Test_OpenSSHBuild" -ForegroundColor Gray Write-Host " 1. Create merge branch: git checkout -b merge-$TargetVersion-$(Get-Date -Format 'yyyyMMdd')" -ForegroundColor Gray Write-Host " 2. Use Get-CommitGroups tool to identify first batch of commits" -ForegroundColor Gray Write-Host " 3. Begin cherry-picking commits from first batch" -ForegroundColor Gray From aa02282770b2209298ce5911b9871e3f27819f08 Mon Sep 17 00:00:00 2001 From: User Date: Fri, 9 Jan 2026 13:17:45 -0800 Subject: [PATCH 210/244] update instructions --- .github/tools/Test-MergePrerequisites.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/tools/Test-MergePrerequisites.ps1 b/.github/tools/Test-MergePrerequisites.ps1 index 8ae3b1f3f3da..aeae000c83a9 100644 --- a/.github/tools/Test-MergePrerequisites.ps1 +++ b/.github/tools/Test-MergePrerequisites.ps1 @@ -212,7 +212,7 @@ try { if ($result.Success) { Write-Host "✓ ALL PREREQUISITES MET" -ForegroundColor Green Write-Host "`nYou are ready to begin the merge process:" -ForegroundColor White - Write-Host " 0. (Optional) Verify baseline build: mcp_openssh-serve_Test_OpenSSHBuild" -ForegroundColor Gray + Write-Host " 0. (Optional) Verify baseline build: mcp_openssh-server_Test_OpenSSHBuild" -ForegroundColor Gray Write-Host " 1. Create merge branch: git checkout -b merge-$TargetVersion-$(Get-Date -Format 'yyyyMMdd')" -ForegroundColor Gray Write-Host " 2. Use Get-CommitGroups tool to identify first batch of commits" -ForegroundColor Gray Write-Host " 3. Begin cherry-picking commits from first batch" -ForegroundColor Gray From 2bbb98e9c8e45a0af662e25c8ae2fabe5267205c Mon Sep 17 00:00:00 2001 From: User Date: Fri, 9 Jan 2026 13:21:27 -0800 Subject: [PATCH 211/244] update instructions --- .../instructions/merge/merge-process-overview.instructions.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/instructions/merge/merge-process-overview.instructions.md b/.github/instructions/merge/merge-process-overview.instructions.md index 69083761a9fd..f9899a1cd993 100644 --- a/.github/instructions/merge/merge-process-overview.instructions.md +++ b/.github/instructions/merge/merge-process-overview.instructions.md @@ -60,8 +60,6 @@ The process consists of several interconnected phases: # - Repository remotes configured (origin, upstream, upstream-pwsh) # - Target version exists in upstream # - Working directory is clean - # - Baseline build passes (unless SkipBaselineBuild is true) - # - First commit batch identified # Proceed only if tool reports "ALL PREREQUISITES MET" ``` From 123f8e24b05b7a8d00ed0313272f39d730094e53 Mon Sep 17 00:00:00 2001 From: User Date: Thu, 15 Jan 2026 08:06:30 -0800 Subject: [PATCH 212/244] refactor tool to workaround io/buffer issues when invoked via MCP --- .github/tools/Test-MergePrerequisites.ps1 | 120 ++++++++++++---------- 1 file changed, 63 insertions(+), 57 deletions(-) diff --git a/.github/tools/Test-MergePrerequisites.ps1 b/.github/tools/Test-MergePrerequisites.ps1 index aeae000c83a9..879ef45dc424 100644 --- a/.github/tools/Test-MergePrerequisites.ps1 +++ b/.github/tools/Test-MergePrerequisites.ps1 @@ -51,6 +51,9 @@ param( ) $scriptRoot = $PSScriptRoot +if ([string]::IsNullOrEmpty($scriptRoot)) { + $scriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path +} $repoRoot = (Get-Item $scriptRoot).Parent.Parent.FullName $result = @{ @@ -70,18 +73,21 @@ try { Write-Host "OpenSSH Merge Prerequisites Check" -ForegroundColor Cyan Write-Host "========================================" -ForegroundColor Cyan Write-Host "Target Version: $TargetVersion" -ForegroundColor White + Write-Host "Repository Root: $repoRoot" -ForegroundColor Gray Write-Host "========================================`n" -ForegroundColor Cyan # Change to repository root Push-Location $repoRoot + Write-Host "Working Directory: $(Get-Location)" -ForegroundColor Gray + Write-Host "" # Step 1: Verify Git - Write-Host "[1/6] Checking Git installation..." -ForegroundColor Cyan + Write-Host "[1/5] Checking Git installation..." -ForegroundColor Cyan try { - $gitVersion = git --version 2>&1 - if ($LASTEXITCODE -eq 0) { + $gitPath = Get-Command git -ErrorAction SilentlyContinue + if ($gitPath) { $result.GitInstalled = $true - Write-Host " ✓ Git installed: $gitVersion" -ForegroundColor Green + Write-Host " ✓ Git found: $($gitPath.Source)" -ForegroundColor Green } else { $result.Issues += "Git is not installed or not in PATH" Write-Host " ✗ Git not found" -ForegroundColor Red @@ -92,7 +98,7 @@ try { } # Step 2: Verify PowerShell version - Write-Host "`n[2/6] Checking PowerShell version..." -ForegroundColor Cyan + Write-Host "`n[2/5] Checking PowerShell version..." -ForegroundColor Cyan $psVersion = $PSVersionTable.PSVersion if ($psVersion.Major -ge 5) { Write-Host " ✓ PowerShell $($psVersion.ToString()) (>= 5.0)" -ForegroundColor Green @@ -102,7 +108,7 @@ try { } # Step 3: Verify Visual Studio - Write-Host "`n[3/6] Checking Visual Studio installation..." -ForegroundColor Cyan + Write-Host "`n[3/5] Checking Visual Studio installation..." -ForegroundColor Cyan $msBuildPaths = @( "${env:ProgramFiles}\Microsoft Visual Studio\2022\*\MSBuild\Current\Bin\MSBuild.exe", "${env:ProgramFiles}\Microsoft Visual Studio\2019\*\MSBuild\Current\Bin\MSBuild.exe", @@ -127,73 +133,68 @@ try { } # Step 4: Verify repository remotes - Write-Host "`n[4/6] Checking repository remotes..." -ForegroundColor Cyan + Write-Host "`n[4/5] Checking repository remotes..." -ForegroundColor Cyan if ($result.GitInstalled) { - $remotes = git remote 2>&1 - $expectedRemotes = @('origin', 'upstream', 'upstream-pwsh') - $missingRemotes = @() - - foreach ($remote in $expectedRemotes) { - if ($remotes -contains $remote) { - $remoteUrl = git remote get-url $remote 2>&1 - Write-Host " ✓ $remote configured: $remoteUrl" -ForegroundColor Green + try { + $gitConfigPath = Join-Path $repoRoot ".git\config" + if (Test-Path $gitConfigPath) { + $gitConfig = Get-Content $gitConfigPath -Raw + $expectedRemotes = @('origin', 'upstream', 'upstream-pwsh') + $missingRemotes = @() + + foreach ($remote in $expectedRemotes) { + if ($gitConfig -match "\[remote `"$remote`"\]") { + Write-Host " ✓ $remote configured" -ForegroundColor Green + } else { + $missingRemotes += $remote + Write-Host " ✗ $remote not configured" -ForegroundColor Red + } + } + + if ($missingRemotes.Count -eq 0) { + $result.RemotesConfigured = $true + } else { + $result.Issues += "Missing remotes: $($missingRemotes -join ', ')" + } } else { - $missingRemotes += $remote - Write-Host " ✗ $remote not configured" -ForegroundColor Red + $result.Issues += "Not a git repository" + Write-Host " ✗ Not a git repository" -ForegroundColor Red } - } - - if ($missingRemotes.Count -eq 0) { - $result.RemotesConfigured = $true - } else { - $result.Issues += "Missing remotes: $($missingRemotes -join ', ')" + } catch { + $result.Issues += "Error checking remotes: $($_.Exception.Message)" + Write-Host " ✗ Error checking remotes" -ForegroundColor Red } } else { Write-Host " ⊘ Skipped (Git not available)" -ForegroundColor Yellow } # Step 5: Verify target version exists - Write-Host "`n[5/6] Checking target version exists..." -ForegroundColor Cyan + Write-Host "`n[5/5] Checking target version exists..." -ForegroundColor Cyan if ($result.GitInstalled -and $result.RemotesConfigured) { - Write-Host " Fetching from upstream..." -ForegroundColor Gray - git fetch upstream --tags 2>&1 | Out-Null - - # Check if it's a tag first, then try as a branch - $tagExists = git rev-parse "$TargetVersion" 2>&1 - if ($LASTEXITCODE -eq 0) { - $result.TargetExists = $true - Write-Host " ✓ Target tag exists: $TargetVersion" -ForegroundColor Green - } else { - # Try as a branch - $branchExists = git rev-parse "upstream/$TargetVersion" 2>&1 - if ($LASTEXITCODE -eq 0) { + try { + # Check if tag/branch ref exists in .git directory + $tagPath = Join-Path $repoRoot ".git\refs\tags\$TargetVersion" + $upstreamBranchPath = Join-Path $repoRoot ".git\refs\remotes\upstream\$TargetVersion" + + if (Test-Path $tagPath) { + $result.TargetExists = $true + Write-Host " ✓ Target tag exists locally: $TargetVersion" -ForegroundColor Green + } elseif (Test-Path $upstreamBranchPath) { $result.TargetExists = $true Write-Host " ✓ Target branch exists: upstream/$TargetVersion" -ForegroundColor Green } else { - $result.Issues += "Target version/tag '$TargetVersion' not found in upstream" - Write-Host " ✗ Target '$TargetVersion' not found" -ForegroundColor Red + $result.Issues += "Target version/tag '$TargetVersion' not found locally. Run 'git fetch upstream --tags' to update." + Write-Host " ✗ Target '$TargetVersion' not found locally" -ForegroundColor Red + Write-Host " Hint: Run 'git fetch upstream --tags' to fetch latest tags" -ForegroundColor Yellow } + } catch { + $result.Issues += "Error checking target version: $($_.Exception.Message)" + Write-Host " ✗ Error checking target version" -ForegroundColor Red } } else { Write-Host " ⊘ Skipped (prerequisites not met)" -ForegroundColor Yellow } - # Step 6: Verify working directory is clean - Write-Host "`n[6/6] Checking working directory state..." -ForegroundColor Cyan - if ($result.GitInstalled) { - $status = git status --porcelain 2>&1 - if ([string]::IsNullOrWhiteSpace($status)) { - $result.WorkingDirClean = $true - Write-Host " ✓ Working directory is clean" -ForegroundColor Green - } else { - $result.Issues += "Working directory has uncommitted changes" - Write-Host " ✗ Working directory has uncommitted changes" -ForegroundColor Red - Write-Host " Run 'git status' to see changes" -ForegroundColor Yellow - } - } else { - Write-Host " ⊘ Skipped (Git not available)" -ForegroundColor Yellow - } - # Final evaluation Write-Host "`n========================================" -ForegroundColor Cyan Write-Host "PREREQUISITE CHECK SUMMARY" -ForegroundColor Cyan @@ -203,8 +204,7 @@ try { $result.GitInstalled, $result.VSInstalled, $result.RemotesConfigured, - $result.TargetExists, - $result.WorkingDirClean + $result.TargetExists ) $result.Success = ($criticalChecks | Where-Object { $_ -eq $false }).Count -eq 0 @@ -229,6 +229,7 @@ try { Write-Host "" + # Return result return $result } catch { @@ -242,7 +243,12 @@ try { $result.Issues += "Tool error: $($_.Exception.Message)" $result.Message = "Prerequisite check failed with error: $($_.Exception.Message)" + # Return result return $result } finally { - Pop-Location + try { + Pop-Location + } catch { + # Ignore Pop-Location errors in MCP context + } } From 09f0fd65a737bb86fa6e203eb84decbf37e44f66 Mon Sep 17 00:00:00 2001 From: User Date: Thu, 15 Jan 2026 08:14:26 -0800 Subject: [PATCH 213/244] update instructions to use mcp tool to read build logs --- .github/instructions/build.instructions.md | 16 +++++++++++++--- .../merge/merge-process-overview.instructions.md | 9 ++++++++- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/.github/instructions/build.instructions.md b/.github/instructions/build.instructions.md index 84b10974f4c0..52621f426530 100644 --- a/.github/instructions/build.instructions.md +++ b/.github/instructions/build.instructions.md @@ -149,12 +149,22 @@ fatal error C1083: Cannot open source file: 'newfile.c' 5. **Rebuild and verify** using Build-OpenSSH MCP tool again 6. **Commit fixes with detailed message** -#### Manual Error Analysis Commands (if needed): -Parse errors manually from log file using the Test-OpenSSHBuild MCP tool: +#### Reading Build Logs and Errors: +**ALWAYS use the Test-OpenSSHBuild MCP tool to read build logs and parse errors:** - **MCP Tool Name**: `mcp_openssh-serve_Test_OpenSSHBuild` - **Parameters**: `Configuration="Release"`, `Architecture="x64"` -Or use direct MSBuild with detailed logging: +**Why use this tool:** +- Automatically locates and parses the build log file +- Provides structured error output with file paths, line numbers, error codes, and messages +- Groups errors and warnings for easier analysis +- Works reliably in MCP context where direct file reading may not be available + +**DO NOT** attempt to read log files directly with `Get-Content` or similar commands. +**DO NOT** try to locate log files manually. + +#### Alternative: Direct MSBuild (Terminal Only) +Only use this when running directly in a terminal (not via MCP): ```pwsh & "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\MSBuild.exe" .\contrib\win32\openssh\Win32-OpenSSH.sln /p:Configuration=Release /p:Platform=x64 /v:detailed ``` diff --git a/.github/instructions/merge/merge-process-overview.instructions.md b/.github/instructions/merge/merge-process-overview.instructions.md index f9899a1cd993..07bbf4d42adb 100644 --- a/.github/instructions/merge/merge-process-overview.instructions.md +++ b/.github/instructions/merge/merge-process-overview.instructions.md @@ -158,7 +158,14 @@ The process consists of several interconnected phases: - **MCP Tool Name**: `mcp_openssh-serve_Build_OpenSSH` - **Parameters**: `Configuration="Release"`, `Architecture="x64"` - If build fails, fix issues and rebuild. Commit any build fixes separately. + If build fails: + - **Use Test-OpenSSHBuild MCP tool to read the build log and parse errors**: + - **MCP Tool Name**: `mcp_openssh-serve_Test_OpenSSHBuild` + - **Parameters**: `Configuration="Release"`, `Architecture="x64"` + - **DO NOT** try to read log files directly with `Get-Content` or locate them manually + - Fix issues based on parsed error output + - Rebuild and verify + - Commit any build fixes separately with descriptive messages 10. **Validate if batch ended with successful CI:** Check the end commit's CI status from Get-CommitGroups output. From 59178e8144589dffc9d8a92c22aef18cb146895a Mon Sep 17 00:00:00 2001 From: User Date: Thu, 15 Jan 2026 08:38:26 -0800 Subject: [PATCH 214/244] update build verfication script to check correct location for artifacts --- .github/tools/Test-OpenSSHBuild.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/tools/Test-OpenSSHBuild.ps1 b/.github/tools/Test-OpenSSHBuild.ps1 index afb978b778bc..a1a8c3389682 100644 --- a/.github/tools/Test-OpenSSHBuild.ps1 +++ b/.github/tools/Test-OpenSSHBuild.ps1 @@ -47,7 +47,7 @@ Tests debug build artifacts for x86 using a custom log file location. .NOTES - - Expected build artifact location: contrib\win32\openssh\{Architecture}\{Configuration}\ + - Expected build artifact location: bin\{Architecture}\{Configuration}\ - Error parsing regex: ^(?.*?)\((?\d+)[,)].*?error (?(C|LNK)\d+): (?.*)$ - Warning parsing regex: ^(?.*?)\((?\d+)[,)].*?warning (?(C|LNK)\d+): (?.*)$ #> @@ -96,7 +96,7 @@ try { Write-Host "========================================`n" -ForegroundColor Cyan # Define build output path - $buildPath = Join-Path $repoRoot "contrib\win32\openssh\$Architecture\$Configuration" + $buildPath = Join-Path $repoRoot "bin\$Architecture\$Configuration" if (-not (Test-Path $buildPath)) { Write-Host "Build path does not exist: $buildPath" -ForegroundColor Red From 298557951af0388caafaebf87e1e742383c27479 Mon Sep 17 00:00:00 2001 From: User Date: Thu, 15 Jan 2026 09:04:29 -0800 Subject: [PATCH 215/244] fix typo --- .github/tools/Get-CommitGroups.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/tools/Get-CommitGroups.ps1 b/.github/tools/Get-CommitGroups.ps1 index be7677800325..0c5411dcedb3 100644 --- a/.github/tools/Get-CommitGroups.ps1 +++ b/.github/tools/Get-CommitGroups.ps1 @@ -280,7 +280,7 @@ try { # Process commits and check CI status $statusCheckMessage = if ($GroupByCIPresence) { "Checking CI presence for each commit..." } else { "Checking CI status for each commit..." } -Write-Host "\n$statusCheckMessage" -ForegroundColor Cyan +Write-Host "`n$statusCheckMessage" -ForegroundColor Cyan $commitsWithStatus = @() $chunks = @() From 76775b2b9c68618868c37af644393f3cc1d81f06 Mon Sep 17 00:00:00 2001 From: Tess Gauthier Date: Fri, 23 Jan 2026 12:27:46 -0500 Subject: [PATCH 216/244] fix tool to parse build log for success/failure and update instructions --- .github/agents/merge-upstream.agent.md | 44 +-- .github/instructions/build.instructions.md | 80 +++--- .../merge/merge-details.instructions.md | 12 +- .../merge-process-overview.instructions.md | 48 ++-- .github/instructions/testing.instructions.md | 6 +- .github/tools/Build-OpenSSH.ps1 | 254 ------------------ .github/tools/Start-OpenSSHBuild.ps1 | 31 ++- .github/tools/Test-MergePrerequisites.ps1 | 12 +- .github/tools/Test-OpenSSHBuild.ps1 | 86 +++++- 9 files changed, 194 insertions(+), 379 deletions(-) delete mode 100644 .github/tools/Build-OpenSSH.ps1 diff --git a/.github/agents/merge-upstream.agent.md b/.github/agents/merge-upstream.agent.md index a45f950eb2cf..36b8695b4809 100644 --- a/.github/agents/merge-upstream.agent.md +++ b/.github/agents/merge-upstream.agent.md @@ -35,16 +35,16 @@ This agent assists with merging upstream OpenSSH commits into the PowerShell for - **Usage**: Use the MCP tool function directly - it handles all GitHub API calls - **If tool unavailable**: ERROR - This tool is required for the merge workflow -2. **Build-OpenSSH MCP Tool** - Build automation and verification - - **MCP Tool Name**: `mcp_openssh-serve_Build_OpenSSH` - - **Parameters**: - - `Configuration` (string, optional): Build configuration - "Debug" or "Release" (default: "Release") - - `Architecture` (string, optional): Target architecture - "x64", "x86", "ARM", "ARM64" (default: "x64") - - `Clean` (boolean, optional): Perform clean build (default: false) - - **If tool unavailable**: ERROR - This tool is required for the merge workflow +2. **Start-OpenSSHBuild MCP Tool** - Build automation + - **MCP Tool Name**: `mcp_openssh-server_Start_OpenSSHBuild` + - **Parameters**: + - `Configuration` (string, optional): Build configuration - "Debug" or "Release" (default: "Release") + - `Architecture` (string, optional): Target architecture - "x64", "x86", "ARM", "ARM64" (default: "x64") + - `Clean` (boolean, optional): Perform clean build (default: false) + - **If tool unavailable**: ERROR - This tool is required for the merge workflow 3. **Test-OpenSSHFunctionality MCP Tool** - Functional testing - - **MCP Tool Name**: `mcp_openssh-serve_Test_OpenSSHFunctionality` + - **MCP Tool Name**: `mcp_openssh-server_Test_OpenSSHFunctionality` - **Parameters**: - `Configuration` (string, optional): Build configuration - "Debug" or "Release" (default: "Release") - `Architecture` (string, optional): Target architecture - "x64", "x86", "ARM", "ARM64" (default: "x64") @@ -94,7 +94,7 @@ This agent assists with merging upstream OpenSSH commits into the PowerShell for - **Parameters**: - `TargetVersion` (string, required): Upstream version/tag to merge (e.g., "V_10_0_P2") - `SkipBaselineBuild` (boolean, optional): Skip baseline build check (default: false) - + This single tool verifies: - Git, PowerShell, Visual Studio are available - Repository remotes are configured (origin, upstream, upstream-pwsh) @@ -124,11 +124,11 @@ This agent assists with merging upstream OpenSSH commits into the PowerShell for **Steps:** 1. **Get first commit batch** using Get-CommitGroups MCP tool: - - **MCP Tool Name**: `mcp_openssh-serve_Get_CommitGroups` + - **MCP Tool Name**: `mcp_openssh-server_Get_CommitGroups` - **Parameters**: - For first batch: `GitHubTag="V_10_0_P2"`, `FirstChunkOnly=true`, `GroupByCIPresence=true` - For subsequent batches: `StartCommit=""`, `FirstChunkOnly=true`, `GroupByCIPresence=true` - + **The tool returns structured data:** ```json { @@ -170,7 +170,7 @@ This agent assists with merging upstream OpenSSH commits into the PowerShell for **Steps:** 1. **Build the merged code:** - - **MCP Tool Name**: `mcp_openssh-serve_Build_OpenSSH` + - **MCP Tool Name**: `mcp_openssh-server_Start_OpenSSHBuild` - **Parameters**: `Configuration="Release"`, `Architecture="x64"` 2. **If build fails, fix compilation errors:** @@ -185,9 +185,9 @@ This agent assists with merging upstream OpenSSH commits into the PowerShell for - Look for commits ending with `CIStatus: "success"` in the detailed output 4. **If CI was successful, run validation tests:** - - **MCP Tool Name**: `mcp_openssh-serve_Test_OpenSSHFunctionality` + - **MCP Tool Name**: `mcp_openssh-server_Test_OpenSSHFunctionality` - **Parameters**: (use defaults for Release/x64) - + This test installs service, creates test user, validates SSH connectivity. If tests fail, fix issues and commit fixes. **Do not proceed** to next batch until tests pass. @@ -216,31 +216,31 @@ This agent assists with merging upstream OpenSSH commits into the PowerShell for 1. **Generate batch summary:** ```markdown ## Batch Completion Summary - + **Batch:** [StartCommit]..[EndCommit] ( commits) **End Commit CI Status:** - + ### Changes in this Batch: - - - - + ### Conflicts Resolved: - : - : - + ### Build Status: - Build: ✅ Success / ❌ Failed - Build fixes applied: - + ### Validation Status: - Validation tests: ✅ Passed / ⏭️ Skipped (no successful CI) / ❌ Failed - Test fixes applied: - + ### Next Steps: - Next batch will start from commit: - Estimated remaining batches: - + **Ready to proceed to next batch?** ``` @@ -266,7 +266,7 @@ This agent assists with merging upstream OpenSSH commits into the PowerShell for - Summarize and get approval 3. **Continue** until all target commits are merged or HEAD is reached 4. **Perform final comprehensive validation:** - - **MCP Tool Name**: `mcp_openssh-serve_Test_OpenSSHFunctionality` + - **MCP Tool Name**: `mcp_openssh-server_Test_OpenSSHFunctionality` - **Parameters**: (use defaults for Release/x64) **Success Criteria:** diff --git a/.github/instructions/build.instructions.md b/.github/instructions/build.instructions.md index 52621f426530..0dca61bd3fb9 100644 --- a/.github/instructions/build.instructions.md +++ b/.github/instructions/build.instructions.md @@ -28,31 +28,11 @@ git --version ### Using MCP Build Tools (Recommended) -The repository includes MCP tools that automate the build, verification, and error analysis process. +The repository includes MCP tools that automate the build and error analysis process. -#### Option 1: Build & Verify (Recommended) -Use the Build-OpenSSH MCP tool: -- **MCP Tool Name**: `mcp_openssh-serve_Build_OpenSSH` -- **Parameters**: - - `Configuration` (optional): "Debug" or "Release" (default: "Release") - - `Architecture` (optional): "x64", "x86", "ARM", "ARM64" (default: "x64") - - `Clean` (optional): Perform clean build (default: false) - -**Examples:** -- Complete build and verification: `Configuration="Release"`, `Architecture="x64"` -- Clean build: `Configuration="Release"`, `Architecture="x64"`, `Clean=true` -- Debug build: `Configuration="Debug"`, `Architecture="x64"` - -**Output includes:** -- Build success/failure status -- All 14 expected artifacts verification -- Parsed compilation errors with file/line/code/message -- Build warnings summary -- Build log location - -#### Option 2: Build Only +#### Build Use the Start-OpenSSHBuild MCP tool: -- **MCP Tool Name**: `mcp_openssh-serve_Start_OpenSSHBuild` +- **MCP Tool Name**: `mcp_openssh-server_Start_OpenSSHBuild` - **Parameters**: - `Configuration` (optional): "Debug" or "Release" (default: "Release") - `Architecture` (optional): "x64", "x86", "ARM", "ARM64" (default: "x64") @@ -62,9 +42,9 @@ Use the Start-OpenSSHBuild MCP tool: - Incremental build: `Configuration="Release"`, `Architecture="x64"` - Clean build: `Configuration="Release"`, `Architecture="x64"`, `Clean=true` -#### Option 3: Test Existing Build -Use the Test-OpenSSHBuild MCP tool: -- **MCP Tool Name**: `mcp_openssh-serve_Test_OpenSSHBuild` +#### Test Existing Build (on failure only) +Use the Test-OpenSSHBuild MCP tool when a build fails: +- **MCP Tool Name**: `mcp_openssh-server_Test_OpenSSHBuild` - **Parameters**: `Configuration="Release"`, `Architecture="x64"` ## Compilation Error Resolution @@ -140,29 +120,34 @@ fatal error C1083: Cannot open source file: 'newfile.c' ### Step-by-Step Error Resolution #### AI Agent Workflow: -1. **Attempt initial build using MCP tool** - - **MCP Tool Name**: `mcp_openssh-serve_Build_OpenSSH` - - **Parameters**: `Configuration="Release"`, `Architecture="x64"` -2. **Review structured error output** from Build-OpenSSH tool -3. **Categorize error types** (preprocessor, Windows compatibility, build system) -4. **Apply appropriate resolution strategy** (see error categories above) -5. **Rebuild and verify** using Build-OpenSSH MCP tool again -6. **Commit fixes with detailed message** - -#### Reading Build Logs and Errors: -**ALWAYS use the Test-OpenSSHBuild MCP tool to read build logs and parse errors:** -- **MCP Tool Name**: `mcp_openssh-serve_Test_OpenSSHBuild` +1. **Run the build** + - Use: **Start-OpenSSHBuild** — `mcp_openssh-server_Start_OpenSSHBuild` with `Configuration` and `Architecture`. +2. **If build succeeded**, skip log parsing and proceed. +3. **If build failed**, **parse errors** using **Test-OpenSSHBuild** — `mcp_openssh-server_Test_OpenSSHBuild`. +4. **Categorize error types** (preprocessor, Windows compatibility, build system). +5. **Apply appropriate resolution strategy** (see error categories above) and **rebuild** with Start-OpenSSHBuild. +6. **Commit fixes with detailed message**. + +#### Reading Build Logs and Errors (on failure only) +Use the **Test-OpenSSHBuild** MCP tool to read build logs and parse errors **only when the build fails**: +- **MCP Tool Name**: `mcp_openssh-server_Test_OpenSSHBuild` - **Parameters**: `Configuration="Release"`, `Architecture="x64"` **Why use this tool:** - Automatically locates and parses the build log file -- Provides structured error output with file paths, line numbers, error codes, and messages +- Provides structured error output with file paths, codes, and messages - Groups errors and warnings for easier analysis - Works reliably in MCP context where direct file reading may not be available **DO NOT** attempt to read log files directly with `Get-Content` or similar commands. **DO NOT** try to locate log files manually. +### Build Tools Invocation Policy + +- Use `Start-OpenSSHBuild.ps1` to run the build for each chunk/batch. +- Only if `Start-OpenSSHBuild.ps1` reports the build failed, invoke `Test-OpenSSHBuild.ps1` to parse errors and warnings from the build log. +- Skip `Test-OpenSSHBuild.ps1` when the build succeeded to avoid unnecessary log parsing. + #### Alternative: Direct MSBuild (Terminal Only) Only use this when running directly in a terminal (not via MCP): ```pwsh @@ -228,19 +213,18 @@ contrib\win32\openssh\ ### Build Verification Using MCP Tools ```pwsh -Use the Build-OpenSSH MCP tool (recommended): -- **MCP Tool Name**: `mcp_openssh-serve_Build_OpenSSH` +Use the Start-OpenSSHBuild MCP tool (recommended): +- **MCP Tool Name**: `mcp_openssh-server_Start_OpenSSHBuild` - **Parameters**: `Configuration="Release"`, `Architecture="x64"` -Or test an existing build: -- **MCP Tool Name**: `mcp_openssh-serve_Test_OpenSSHBuild` -- **Parameters**: `Configuration="Release"`, `Architecture="x64" -**Expected Output:** -- Success/failure status -- 14 of 14 artifacts found +If the build fails, parse errors with: +- **MCP Tool Name**: `mcp_openssh-server_Test_OpenSSHBuild` +- **Parameters**: `Configuration="Release"`, `Architecture="x64"` +**Expected Output (on failure):** +- Build failure status - Parsed errors and warnings - Build log location - +``` **Expected Artifacts (14 executables):** - ssh.exe, sshd.exe, sshd-auth.exe, sshd-session.exe - ssh-agent.exe, ssh-add.exe, ssh-keygen.exe, ssh-keyscan.exe diff --git a/.github/instructions/merge/merge-details.instructions.md b/.github/instructions/merge/merge-details.instructions.md index 5c6f20d909d4..a2358a04cb2b 100644 --- a/.github/instructions/merge/merge-details.instructions.md +++ b/.github/instructions/merge/merge-details.instructions.md @@ -253,12 +253,14 @@ FUNCTION automated_build_fix(): iteration = 0 WHILE iteration < MAX_ITERATIONS: - build_result = attempt_build() + // Always start with Start-OpenSSHBuild.ps1 + build_result = start_openssh_build(Configuration="Release", Architecture="x64") IF build_result.success: RETURN SUCCESS - errors = parse_build_errors(build_result.output) + // Only invoke Test-OpenSSHBuild.ps1 when build failed + errors = test_openssh_build(Configuration="Release", Architecture="x64", LogFile=build_result.log) fixes_applied = [] FOR EACH error IN errors: @@ -289,6 +291,12 @@ FUNCTION determine_fix_strategy(error): RETURN null ``` +### Build Tools Invocation Policy + +- Use `Start-OpenSSHBuild.ps1` to run the build for each chunk/batch. +- Only if `Start-OpenSSHBuild.ps1` reports the build failed, invoke `Test-OpenSSHBuild.ps1` to parse errors and warnings from the build log. +- Skip `Test-OpenSSHBuild.ps1` when the build succeeded to avoid unnecessary log parsing. + ## Testing Automation Framework ### Automated Test Execution diff --git a/.github/instructions/merge/merge-process-overview.instructions.md b/.github/instructions/merge/merge-process-overview.instructions.md index 07bbf4d42adb..857ffcc7aa3f 100644 --- a/.github/instructions/merge/merge-process-overview.instructions.md +++ b/.github/instructions/merge/merge-process-overview.instructions.md @@ -53,14 +53,14 @@ The process consists of several interconnected phases: # Run prerequisite check via MCP tool # MCP Tool Name: mcp_openssh-server_Test_MergePrerequisites # Parameters: TargetVersion (required), SkipBaselineBuild (optional) - + # Example invocation (replace with target like "V_10_0_P2"): # The MCP tool will verify: # - Git, PowerShell, Visual Studio installed # - Repository remotes configured (origin, upstream, upstream-pwsh) # - Target version exists in upstream # - Working directory is clean - + # Proceed only if tool reports "ALL PREREQUISITES MET" ``` @@ -68,7 +68,7 @@ The process consists of several interconnected phases: ```pwsh git config core.editor true ``` - + 3. **Create merge branch from current branch:** ```pwsh git checkout -b merge-v- @@ -78,20 +78,20 @@ The process consists of several interconnected phases: ### Perform Merge with Grouped Commits 4. **Identify merge range and group commits:** Use the Get-CommitGroups MCP tool with `-FirstChunkOnly -GroupByCIPresence` - - **MCP Tool Name**: `mcp_openssh-serve_Get_CommitGroups` - + + **MCP Tool Name**: `mcp_openssh-server_Get_CommitGroups` + **Parameters**: - `GitHubTag` (string, optional): Start from last merged tag (e.g., "V_10_0_P2") - `StartCommit` (string, optional): Start from specific commit SHA - `FirstChunkOnly` (boolean): Set to `true` - `GroupByCIPresence` (boolean): Set to `true` - + **Example for first batch**: - Find the last upstream tag in the fork - Call tool with `GitHubTag=`, `FirstChunkOnly=true`, `GroupByCIPresence=true` - This gets commits ending with any commit that has CI runs (not just successful CI) - + **Example output:** ```json { @@ -129,9 +129,9 @@ The process consists of several interconnected phases: Write-Host "Cherry-picking commit: $commit" git cherry-pick $commit - # Build after every commit so we can attribute failures precisely. - # Use MCP Tool: mcp_openssh-serve_Build_OpenSSH - # Parameters: Configuration="Release", Architecture="x64" + # Build after every commit to attribute failures precisely. + # Use MCP Tool: mcp_openssh-server_Start_OpenSSHBuild + # Parameters: Configuration="Release", Architecture="x64" } ``` @@ -154,25 +154,25 @@ The process consists of several interconnected phases: ``` 9. **Build after completing the batch:** - Use the Build-OpenSSH MCP tool: - - **MCP Tool Name**: `mcp_openssh-serve_Build_OpenSSH` - - **Parameters**: `Configuration="Release"`, `Architecture="x64"` - - If build fails: - - **Use Test-OpenSSHBuild MCP tool to read the build log and parse errors**: - - **MCP Tool Name**: `mcp_openssh-serve_Test_OpenSSHBuild` + Use the Start-OpenSSHBuild MCP tool: + - **MCP Tool Name**: `mcp_openssh-server_Start_OpenSSHBuild` - **Parameters**: `Configuration="Release"`, `Architecture="x64"` - - **DO NOT** try to read log files directly with `Get-Content` or locate them manually - - Fix issues based on parsed error output - - Rebuild and verify - - Commit any build fixes separately with descriptive messages + + If build fails: + - **Use Test-OpenSSHBuild MCP tool to read the build log and parse errors**: + - **MCP Tool Name**: `mcp_openssh-server_Test_OpenSSHBuild` + - **Parameters**: `Configuration="Release"`, `Architecture="x64"` + - **DO NOT** try to read log files directly with `Get-Content` or locate them manually + - Fix issues based on parsed error output + - Rebuild and verify + - Commit any build fixes separately with descriptive messages 10. **Validate if batch ended with successful CI:** Check the end commit's CI status from Get-CommitGroups output. If CI was successful, run validation: - - **MCP Tool Name**: `mcp_openssh-serve_Test_OpenSSHFunctionality` + - **MCP Tool Name**: `mcp_openssh-server_Test_OpenSSHFunctionality` - **Parameters**: (use defaults for Release/x64) - + If no CI or failed CI, skip validation (build success is sufficient). 11. **Provide summary and get approval:** diff --git a/.github/instructions/testing.instructions.md b/.github/instructions/testing.instructions.md index 00a60db8fc4d..c4f675b3a83c 100644 --- a/.github/instructions/testing.instructions.md +++ b/.github/instructions/testing.instructions.md @@ -14,7 +14,7 @@ This document provides comprehensive testing procedures for validating OpenSSH-P The repository includes an MCP tool that automates end-to-end functional testing of OpenSSH on Windows. Use the Test-OpenSSHFunctionality MCP tool: -- **MCP Tool Name**: `mcp_openssh-serve_Test_OpenSSHFunctionality` +- **MCP Tool Name**: `mcp_openssh-server_Test_OpenSSHFunctionality` - **Parameters**: - `Configuration` (optional): "Debug" or "Release" (default: "Release") - `Architecture` (optional): "x64", "x86", "ARM", "ARM64" (default: "x64") @@ -84,7 +84,7 @@ The MCP tool performs comprehensive end-to-end testing including: - Command execution verification - Complete cleanup of all test resources -**MCP Tool Name**: `mcp_openssh-serve_Test_OpenSSHFunctionality` +**MCP Tool Name**: `mcp_openssh-server_Test_OpenSSHFunctionality` **Parameters**: - `Configuration` (optional): "Debug" or "Release" (default: "Release") @@ -245,7 +245,7 @@ Get-NetFirewallRule | Where-Object {$_.DisplayName -like "*SSH*"} ### Recommended Testing Workflow for AI Agents 1. **After successful build**, run the automated functionality test: - - **MCP Tool Name**: `mcp_openssh-serve_Test_OpenSSHFunctionality` + - **MCP Tool Name**: `mcp_openssh-server_Test_OpenSSHFunctionality` - **Parameters**: (use defaults) 2. **If test passes**, the merge is validated for basic SSH functionality diff --git a/.github/tools/Build-OpenSSH.ps1 b/.github/tools/Build-OpenSSH.ps1 deleted file mode 100644 index 692559066f0e..000000000000 --- a/.github/tools/Build-OpenSSH.ps1 +++ /dev/null @@ -1,254 +0,0 @@ -<# -.SYNOPSIS - MCP wrapper tool that builds and verifies OpenSSH in a single operation. - -.DESCRIPTION - This script combines Start-OpenSSHBuild and Test-OpenSSHBuild into a single - convenient operation. It first builds OpenSSH using the specified configuration - and architecture, then tests that all expected artifacts were produced and - parses the build log for errors. - - This is the recommended tool for most build operations as it provides - comprehensive feedback in one step. - -.PARAMETER Configuration - Build configuration type. Valid values: 'Debug', 'Release' - Default: 'Release' - -.PARAMETER Architecture - Target architecture for the build. Valid values: 'x64', 'x86', 'ARM', 'ARM64' - Default: 'x64' - -.PARAMETER Clean - When specified, performs a clean build by deleting existing build artifacts first. - Default: false (incremental build) - -.PARAMETER NoOpenSSL - Build without OpenSSL support. - Default: false - -.PARAMETER OneCore - Build for Windows OneCore API subset. - Default: false - -.OUTPUTS - Returns a consolidated hashtable with: - - BuildSuccess: Boolean indicating if build succeeded - - TestSuccess: Boolean indicating if test passed - - OverallSuccess: Boolean indicating both build and test succeeded - - BuildExitCode: MSBuild exit code - - BuildMessage: Build status message - - TotalArtifacts: Count of artifacts found - - ExpectedArtifacts: Count of artifacts expected (14) - - ArtifactsMissing: Array of missing artifacts - - Errors: Array of parsed error objects - - Warnings: Array of parsed warning objects - - LogFile: Path to build log file - - BuildPath: Path to build output directory - - Message: Overall summary message - -.EXAMPLE - .\Build-OpenSSH.ps1 -Configuration Release -Architecture x64 - - Performs an incremental release build for x64 and tests artifacts. - -.EXAMPLE - .\Build-OpenSSH.ps1 -Configuration Debug -Architecture x64 -Clean - - Performs a clean debug build for x64 and tests artifacts. - -.EXAMPLE - .\Build-OpenSSH.ps1 -Architecture ARM64 -OneCore - - Performs an incremental OneCore release build for ARM64 and tests artifacts. - -.NOTES - - This tool calls Start-OpenSSHBuild.ps1 and Test-OpenSSHBuild.ps1 - - Requires Visual Studio 2019 or later with C++ tools - - Requires Windows SDK 10.0.17763.0 or later - - Build artifacts output to: contrib\win32\openssh\{Architecture}\{Configuration}\ - - Build log written to: OpenSSH{Configuration}{Architecture}.log -#> - -param( - [Parameter(Mandatory=$false)] - [ValidateSet('Debug', 'Release')] - [string]$Configuration = 'Release', - - [Parameter(Mandatory=$false)] - [ValidateSet('x64', 'x86', 'ARM', 'ARM64')] - [string]$Architecture = 'x64', - - [Parameter(Mandatory=$false)] - [switch]$Clean, - - [Parameter(Mandatory=$false)] - [switch]$NoOpenSSL, - - [Parameter(Mandatory=$false)] - [switch]$OneCore -) - -$scriptRoot = $PSScriptRoot - -try { - Write-Host "========================================" -ForegroundColor Cyan - Write-Host "OpenSSH Build & Test Tool (MCP)" -ForegroundColor Cyan - Write-Host "========================================" -ForegroundColor Cyan - Write-Host "Configuration: $Configuration" -ForegroundColor White - Write-Host "Architecture: $Architecture" -ForegroundColor White - Write-Host "Clean Build: $Clean" -ForegroundColor White - Write-Host "No OpenSSL: $NoOpenSSL" -ForegroundColor White - Write-Host "OneCore: $OneCore" -ForegroundColor White - Write-Host "========================================`n" -ForegroundColor Cyan - - # Step 1: Build - Write-Host "STEP 1: Building OpenSSH..." -ForegroundColor Cyan - Write-Host "----------------------------------------`n" -ForegroundColor Cyan - - $buildParams = @{ - Configuration = $Configuration - Architecture = $Architecture - } - - if ($Clean) { - $buildParams['Clean'] = $true - } - - if ($NoOpenSSL) { - $buildParams['NoOpenSSL'] = $true - } - - if ($OneCore) { - $buildParams['OneCore'] = $true - } - - $buildScriptPath = Join-Path $scriptRoot "Start-OpenSSHBuild.ps1" - $buildResult = & $buildScriptPath @buildParams - - if (-not $buildResult.Success) { - Write-Host "`n⚠ Build failed, skipping test" -ForegroundColor Yellow - - # Return build result with test skipped - $result = @{ - BuildSuccess = $false - TestSuccess = $false - OverallSuccess = $false - BuildExitCode = $buildResult.ExitCode - BuildMessage = $buildResult.Message - TotalArtifacts = 0 - ExpectedArtifacts = 14 - ArtifactsMissing = @() - Errors = @() - Warnings = @() - LogFile = $buildResult.LogFile - BuildPath = $buildResult.BuildPath - Message = "Build failed: $($buildResult.Message)" - } - - return $result - } - - # Step 2: Test - Write-Host "`nSTEP 2: Testing Build Artifacts..." -ForegroundColor Cyan - Write-Host "----------------------------------------`n" -ForegroundColor Cyan - - $testParams = @{ - Configuration = $Configuration - Architecture = $Architecture - LogFile = $buildResult.LogFile - } - - $testScriptPath = Join-Path $scriptRoot "Test-OpenSSHBuild.ps1" - $testResult = & $testScriptPath @testParams - - # Step 3: Consolidate results - $overallSuccess = $buildResult.Success -and $testResult.Success - - Write-Host "`n========================================" -ForegroundColor $(if ($overallSuccess) { "Green" } else { "Red" }) - Write-Host "OVERALL RESULT: $(if ($overallSuccess) { 'SUCCESS' } else { 'FAILED' })" -ForegroundColor $(if ($overallSuccess) { "Green" } else { "Red" }) - Write-Host "========================================" -ForegroundColor $(if ($overallSuccess) { "Green" } else { "Red" }) - - if ($overallSuccess) { - Write-Host "✓ Build succeeded" -ForegroundColor Green - Write-Host "✓ All $($testResult.ExpectedArtifacts) artifacts tested" -ForegroundColor Green - Write-Host "✓ No errors found" -ForegroundColor Green - } else { - if (-not $buildResult.Success) { - Write-Host "✗ Build failed with exit code $($buildResult.ExitCode)" -ForegroundColor Red - } - if ($testResult.ArtifactsMissing.Count -gt 0) { - Write-Host "✗ $($testResult.ArtifactsMissing.Count) artifacts missing" -ForegroundColor Red - } - if ($testResult.Errors.Count -gt 0) { - Write-Host "✗ $($testResult.Errors.Count) error(s) found" -ForegroundColor Red - } - } - - Write-Host "`nBuild artifacts: $($buildResult.BuildPath)" -ForegroundColor White - Write-Host "Build log: $($buildResult.LogFile)" -ForegroundColor White - - # Build consolidated message - $messageParts = @() - if ($buildResult.Success) { - $messageParts += "Build succeeded" - } else { - $messageParts += "Build failed" - } - - if ($testResult.Success) { - $messageParts += "all artifacts tested" - } else { - if ($testResult.ArtifactsMissing.Count -gt 0) { - $messageParts += "$($testResult.ArtifactsMissing.Count) artifacts missing" - } - if ($testResult.Errors.Count -gt 0) { - $messageParts += "$($testResult.Errors.Count) errors" - } - } - - $consolidatedMessage = $messageParts -join ", " - - $result = @{ - BuildSuccess = $buildResult.Success - TestSuccess = $testResult.Success - OverallSuccess = $overallSuccess - BuildExitCode = $buildResult.ExitCode - BuildMessage = $buildResult.Message - TotalArtifacts = $testResult.TotalArtifacts - ExpectedArtifacts = $testResult.ExpectedArtifacts - ArtifactsMissing = $testResult.ArtifactsMissing - Errors = $testResult.Errors - Warnings = $testResult.Warnings - LogFile = $buildResult.LogFile - BuildPath = $buildResult.BuildPath - Message = $consolidatedMessage - } - - return $result - -} catch { - Write-Host "`n========================================" -ForegroundColor Red - Write-Host "ERROR" -ForegroundColor Red - Write-Host "========================================" -ForegroundColor Red - Write-Host $_.Exception.Message -ForegroundColor Red - Write-Host $_.ScriptStackTrace -ForegroundColor Gray - - $result = @{ - BuildSuccess = $false - TestSuccess = $false - OverallSuccess = $false - BuildExitCode = -1 - BuildMessage = "Tool error: $($_.Exception.Message)" - TotalArtifacts = 0 - ExpectedArtifacts = 14 - ArtifactsMissing = @() - Errors = @() - Warnings = @() - LogFile = "" - BuildPath = "" - Message = "Build & test tool error: $($_.Exception.Message)" - } - - return $result -} diff --git a/.github/tools/Start-OpenSSHBuild.ps1 b/.github/tools/Start-OpenSSHBuild.ps1 index c175b29c6394..b6b0c6e2c3d0 100644 --- a/.github/tools/Start-OpenSSHBuild.ps1 +++ b/.github/tools/Start-OpenSSHBuild.ps1 @@ -116,8 +116,8 @@ try { Write-Host "✓ Cleaned: $buildPath" -ForegroundColor Green } - # Build log file path - $logFile = Join-Path $repoRoot "OpenSSH$Configuration$Architecture.log" + # Build log file path (align with other tools under contrib\win32\openssh) + $logFile = Join-Path $repoRoot "contrib\win32\openssh\OpenSSH$Configuration$Architecture.log" Write-Host "`nBuild log: $logFile" -ForegroundColor Gray # Prepare parameters for Start-OpenSSHBuild @@ -140,8 +140,25 @@ try { $buildResult = Start-OpenSSHBuild @buildParams - # Check build result - if ($buildResult -eq 0) { + # Determine build success primarily via log markers, not exit code + $successByLog = $null + $buildLogTime = $null + if (Test-Path $logFile) { + $buildLogTime = (Get-Item $logFile -ErrorAction SilentlyContinue).LastWriteTime + $logLines = Get-Content $logFile -ErrorAction SilentlyContinue + if ($logLines) { + $lastMarker = $null + foreach ($line in $logLines) { + if ($line -match '(?i)Build\s+(FAILED|Failed)') { $lastMarker = 'FAILED' } + elseif ($line -match '(?i)Build\s+(SUCCEEDED|Succeeded)') { $lastMarker = 'SUCCEEDED' } + } + if ($lastMarker) { $successByLog = ($lastMarker -eq 'SUCCEEDED') } + } + } + + $derivedSuccess = if ($successByLog -ne $null) { $successByLog } else { $buildResult -eq 0 } + + if ($derivedSuccess) { Write-Host "`n========================================" -ForegroundColor Green Write-Host "BUILD SUCCEEDED" -ForegroundColor Green Write-Host "========================================" -ForegroundColor Green @@ -149,9 +166,10 @@ try { $result = @{ Success = $true - ExitCode = 0 + ExitCode = $buildResult LogFile = $logFile BuildPath = $buildPath + BuildLogTimestamp = $buildLogTime Message = "Build completed successfully" } } else { @@ -166,7 +184,8 @@ try { ExitCode = $buildResult LogFile = $logFile BuildPath = $buildPath - Message = "Build failed with exit code $buildResult. Check log file for details." + BuildLogTimestamp = $buildLogTime + Message = "Build failed (determined from log markers or exit code). Check log file for details." } } diff --git a/.github/tools/Test-MergePrerequisites.ps1 b/.github/tools/Test-MergePrerequisites.ps1 index 879ef45dc424..bd807746fa40 100644 --- a/.github/tools/Test-MergePrerequisites.ps1 +++ b/.github/tools/Test-MergePrerequisites.ps1 @@ -8,13 +8,13 @@ - Required tools (Git, PowerShell, Visual Studio) - Repository configuration (remotes, branch state) - Target version identification - + This tool should be run before starting Phase 1 of the merge workflow to ensure all prerequisites are met. It prevents wasted effort by catching configuration issues early. - + To verify baseline build capability, use the Test-OpenSSHBuild MCP tool: - mcp_openssh-serve_Test_OpenSSHBuild + mcp_openssh-server_Test_OpenSSHBuild .PARAMETER TargetVersion The upstream version/tag to merge (e.g., "V_10_0_P2", "V_9_9_P1") @@ -41,7 +41,7 @@ .NOTES - This is a Phase 1 Pre-Merge Setup verification tool - Should be run before creating the merge branch - - For baseline build verification, use: mcp_openssh-serve_Test_OpenSSHBuild + - For baseline build verification, use: mcp_openssh-server_Test_OpenSSHBuild - Part of the OpenSSH upstream merge workflow automation #> @@ -175,7 +175,7 @@ try { # Check if tag/branch ref exists in .git directory $tagPath = Join-Path $repoRoot ".git\refs\tags\$TargetVersion" $upstreamBranchPath = Join-Path $repoRoot ".git\refs\remotes\upstream\$TargetVersion" - + if (Test-Path $tagPath) { $result.TargetExists = $true Write-Host " ✓ Target tag exists locally: $TargetVersion" -ForegroundColor Green @@ -216,7 +216,7 @@ try { Write-Host " 1. Create merge branch: git checkout -b merge-$TargetVersion-$(Get-Date -Format 'yyyyMMdd')" -ForegroundColor Gray Write-Host " 2. Use Get-CommitGroups tool to identify first batch of commits" -ForegroundColor Gray Write-Host " 3. Begin cherry-picking commits from first batch" -ForegroundColor Gray - + $result.Message = "All prerequisites met. Ready to start merge." } else { Write-Host "✗ PREREQUISITES NOT MET" -ForegroundColor Red diff --git a/.github/tools/Test-OpenSSHBuild.ps1 b/.github/tools/Test-OpenSSHBuild.ps1 index a1a8c3389682..db50930c7d2b 100644 --- a/.github/tools/Test-OpenSSHBuild.ps1 +++ b/.github/tools/Test-OpenSSHBuild.ps1 @@ -48,8 +48,10 @@ .NOTES - Expected build artifact location: bin\{Architecture}\{Configuration}\ - - Error parsing regex: ^(?.*?)\((?\d+)[,)].*?error (?(C|LNK)\d+): (?.*)$ - - Warning parsing regex: ^(?.*?)\((?\d+)[,)].*?warning (?(C|LNK)\d+): (?.*)$ + - Error parsing regex (file/line form): ^(?.+?)\((?\d+)[,)].*?\s(?fatal error|error)\s+(?(?:C|LNK|MSB)\d+)\s*:\s*(?.+)$ + - Error parsing regex (generic/no line): ^(?:.*?:\s*)?(?fatal error|error)\s+(?(?:C|LNK|MSB)\d+)\s*:\s*(?.+)$ + - Warning parsing regex (file/line form): ^(?.+?)\((?\d+)[,)].*?\swarning\s+(?(?:C|LNK|MSB)\d+)\s*:\s*(?.+)$ + - Warning parsing regex (generic/no line): ^(?:.*?:\s*)?warning\s+(?(?:C|LNK|MSB)\d+)\s*:\s*(?.+)$ #> param( @@ -149,18 +151,38 @@ try { Write-Host "`nParsing build log: $LogFile" -ForegroundColor Cyan $logContent = Get-Content $LogFile -ErrorAction SilentlyContinue + $logTime = (Get-Item $LogFile -ErrorAction SilentlyContinue).LastWriteTime if ($logContent) { - # Error regex: file(line) : error CODE: message - # Example: c:\path\file.c(123): error C2065: 'identifier' : undeclared identifier - $errorRegex = '^(?.*?)\((?\d+)[,)].*?error (?(C|LNK)\d+): (?.*)$' + # Find the first build status marker and, if failed, only scan lines after it + $buildStatusIndex = $null + $buildFailed = $false + for ($i = 0; $i -lt $logContent.Count; $i++) { + $line = $logContent[$i] + if ($line -match 'Build\s+(FAILED|Failed)') { + $buildStatusIndex = $i + $buildFailed = $true + break + } elseif ($line -match 'Build\s+(SUCCEEDED|Succeeded)') { + $buildStatusIndex = $i + break + } + } - # Warning regex: similar pattern for warnings - $warningRegex = '^(?.*?)\((?\d+)[,)].*?warning (?(C|LNK)\d+): (?.*)$' + $linesToScan = $logContent + if ($buildFailed -and $buildStatusIndex -ne $null -and $buildStatusIndex + 1 -lt $logContent.Count) { + $linesToScan = $logContent[($buildStatusIndex + 1)..($logContent.Count - 1)] + } - foreach ($line in $logContent) { - # Check for errors - if ($line -match $errorRegex) { + # Broadened regex patterns to support linker/MSBuild messages without line numbers + $errorWithFileRegex = '^(?.+?)\((?\d+)[,)].*?\s(?fatal error|error)\s+(?(?:C|LNK|MSB)\d+)\s*:\s*(?.+)$' + $genericErrorRegex = '^(?:.*?:\s*)?(?fatal error|error)\s+(?(?:C|LNK|MSB)\d+)\s*:\s*(?.+)$' + $warningWithFileRegex = '^(?.+?)\((?\d+)[,)].*?\swarning\s+(?(?:C|LNK|MSB)\d+)\s*:\s*(?.+)$' + $genericWarningRegex = '^(?:.*?:\s*)?warning\s+(?(?:C|LNK|MSB)\d+)\s*:\s*(?.+)$' + + foreach ($line in $linesToScan) { + # Errors with file/line + if ($line -match $errorWithFileRegex) { $errors += [PSCustomObject]@{ File = $matches['file'] Line = [int]$matches['line'] @@ -168,9 +190,21 @@ try { Message = $matches['message'] RawLine = $line } + continue + } + # Generic errors (e.g., LINK/MSBuild without line numbers) + if ($line -match $genericErrorRegex) { + $errors += [PSCustomObject]@{ + File = '' + Line = $null + Code = $matches['code'] + Message = $matches['message'] + RawLine = $line + } + continue } - # Check for warnings - elseif ($line -match $warningRegex) { + # Warnings with file/line + if ($line -match $warningWithFileRegex) { $warnings += [PSCustomObject]@{ File = $matches['file'] Line = [int]$matches['line'] @@ -178,13 +212,29 @@ try { Message = $matches['message'] RawLine = $line } + continue + } + # Generic warnings + if ($line -match $genericWarningRegex) { + $warnings += [PSCustomObject]@{ + File = '' + Line = $null + Code = $matches['code'] + Message = $matches['message'] + RawLine = $line + } } } if ($errors.Count -gt 0) { Write-Host "`nFound $($errors.Count) error(s) in build log:" -ForegroundColor Red foreach ($e in $errors) { - Write-Host " $($e.File)($($e.Line)): error $($e.Code): $($e.Message)" -ForegroundColor Red + if ([string]::IsNullOrEmpty($e.File)) { + Write-Host " error $($e.Code): $($e.Message)" -ForegroundColor Red + } else { + $lineSuffix = if ($e.Line -ne $null) { "(" + $e.Line + ")" } else { "" } + Write-Host (" {0}{1}: error {2}: {3}" -f $e.File, $lineSuffix, $e.Code, $e.Message) -ForegroundColor Red + } } } else { Write-Host "`n✓ No errors found in build log" -ForegroundColor Green @@ -193,7 +243,12 @@ try { if ($warnings.Count -gt 0) { Write-Host "`nFound $($warnings.Count) warning(s) in build log:" -ForegroundColor Yellow foreach ($warning in $warnings | Select-Object -First 10) { - Write-Host " $($warning.File)($($warning.Line)): warning $($warning.Code): $($warning.Message)" -ForegroundColor Yellow + if ([string]::IsNullOrEmpty($warning.File)) { + Write-Host " warning $($warning.Code): $($warning.Message)" -ForegroundColor Yellow + } else { + $lineSuffix = if ($warning.Line -ne $null) { "(" + $warning.Line + ")" } else { "" } + Write-Host (" {0}{1}: warning {2}: {3}" -f $warning.File, $lineSuffix, $warning.Code, $warning.Message) -ForegroundColor Yellow + } } if ($warnings.Count -gt 10) { Write-Host " ... and $($warnings.Count - 10) more warnings" -ForegroundColor Gray @@ -202,6 +257,8 @@ try { } else { Write-Host "Log file is empty or could not be read" -ForegroundColor Yellow } + + # Timestamp freshness checks removed; rely on build log parsing instead } else { Write-Host "`nBuild log not found: $LogFile" -ForegroundColor Yellow } @@ -234,6 +291,7 @@ try { Errors = $errors Warnings = $warnings LogFile = $LogFile + # BuildLogTimestamp and stale artifact checks removed Message = $message } From e379310b0920b58b917f56337b07516529c47606 Mon Sep 17 00:00:00 2001 From: Tess Gauthier Date: Fri, 23 Jan 2026 12:47:40 -0500 Subject: [PATCH 217/244] add merge prompt file --- .github/prompt/merge.prompt.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 .github/prompt/merge.prompt.md diff --git a/.github/prompt/merge.prompt.md b/.github/prompt/merge.prompt.md new file mode 100644 index 000000000000..d64421f7ef5c --- /dev/null +++ b/.github/prompt/merge.prompt.md @@ -0,0 +1,29 @@ +# Merge Upstream Prompt + +Assist with merging the commits from upstream into this branch starting from the provided GitHub tag or commit. + +Provide the following when you invoke this prompt: +- Start ref (tag or commit) — REQUIRED (e.g., `upstream/V_9_8_P1` or a commit SHA) +- Upstream remote — optional (default: `upstream`) +- Windows fork remote — optional (default: `upstream-pwsh`) +- Target branch — optional (default: current branch) + +Operating guidance: +- Use and follow merge-upstream.agent.md. Treat it as the primary operating guide. +- Rely on the provided for repository overview, setup, build, merge strategy, and testing. Do not re-fetch or re-search them; assume they are already attached in context. +- Perform chunked merges ending at commits with CI runs; build after each batch. Only parse build logs if the build fails. +- Build using the MCP tools: `mcp_openssh-server_Start_OpenSSHBuild` (Release/x64 by default). If the build fails, analyze with `mcp_openssh-server_Test_OpenSSHBuild`. +- Apply Windows compatibility strategies as documented (prefer win32compat layer; guard with `#ifdef WINDOWS` when necessary; update VS projects for build system changes). +- Summarize a plan, request approval between batches, and clearly list conflict resolutions and rationale. + +Expected outputs per batch: +- Planned commit range and rationale for the batch boundary +- Conflict resolutions (what, why, how), especially Windows-specific handling +- Build result summary and, on failure, parsed errors with applied fixes +- Next-step proposal and explicit ask to proceed + +Quick start examples: +- "Merge from tag `upstream/V_9_8_P1` into my current branch." +- "Merge starting at commit `3a1b2c3`, upstream remote `upstream`, target current branch." + +If the Start ref is not provided, ask for it before proceeding. From 5b55ec2ceb8519b4aba8eb0c21fce5fbb7f82bc4 Mon Sep 17 00:00:00 2001 From: User Date: Fri, 23 Jan 2026 09:49:55 -0800 Subject: [PATCH 218/244] update tools --- .github/agents/merge-upstream.agent.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/agents/merge-upstream.agent.md b/.github/agents/merge-upstream.agent.md index 36b8695b4809..e5b0e8f2b5dd 100644 --- a/.github/agents/merge-upstream.agent.md +++ b/.github/agents/merge-upstream.agent.md @@ -2,7 +2,7 @@ name: merge-upstream description: Assist with merging upstream OpenSSH commits into the PowerShell fork. tools: - ['vscode', 'execute', 'read', 'edit', 'search', 'web', 'openssh-server/*', 'agent', 'todo'] + ['vscode', 'execute', 'read', 'agent', 'edit', 'search', 'web', 'openssh-server/*', 'todo'] --- # OpenSSH Upstream Merge Agent From 950bb1beae304ef8da15efa6bd8bb65de65967fe Mon Sep 17 00:00:00 2001 From: User Date: Fri, 23 Jan 2026 12:21:13 -0800 Subject: [PATCH 219/244] update instructions to build only after batch of commits with a CI run --- .../merge-process-overview.instructions.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/.github/instructions/merge/merge-process-overview.instructions.md b/.github/instructions/merge/merge-process-overview.instructions.md index 857ffcc7aa3f..f8b26c6847cc 100644 --- a/.github/instructions/merge/merge-process-overview.instructions.md +++ b/.github/instructions/merge/merge-process-overview.instructions.md @@ -112,14 +112,12 @@ The process consists of several interconnected phases: - Call tool with `StartCommit=`, `FirstChunkOnly=true`, `GroupByCIPresence=true` - Continue this process until the upstream's HEAD has been successfully merged -5. **Execute chunked merge (commit-by-commit within the chunk):** +5. **Execute chunked merge (batch cherry-pick all commits in chunk):** - **Important:** Even though commits are *grouped* into chunks for planning/CI boundaries, **cherry-pick each commit individually** within the chunk and **build after each commit**. This catches Windows-specific build breaks early and makes it clear which upstream commit introduced a regression. + **Important:** Cherry-pick **all commits in the batch** before building. This is more efficient than building after each individual commit. If the build fails, you can identify the problematic commit(s) through git bisect or by examining the build errors. ```pwsh - # For each chunk (start..end), enumerate and cherry-pick commits one at a time. - # Then build after EACH commit. - # + # For each chunk (start..end), cherry-pick all commits in the batch # Example for a single chunk: $chunkStart = $result.StartCommitFull $chunkEnd = $result.EndCommitFull @@ -128,11 +126,12 @@ The process consists of several interconnected phases: foreach ($commit in $commits) { Write-Host "Cherry-picking commit: $commit" git cherry-pick $commit - - # Build after every commit to attribute failures precisely. - # Use MCP Tool: mcp_openssh-server_Start_OpenSSHBuild - # Parameters: Configuration="Release", Architecture="x64" + + # If conflicts occur, resolve them before continuing to next commit + # (see step 7 below for conflict resolution) } + + # After all commits in batch are cherry-picked, proceed to build (step 9) ``` 7. **Resolve merge conflicts (per commit):** From ead71d7b3fbdcede7049a0e7a0e0c5c69e8fca37 Mon Sep 17 00:00:00 2001 From: User Date: Fri, 23 Jan 2026 12:26:15 -0800 Subject: [PATCH 220/244] update prereq tool to use start-job with git cmd --- .github/tools/Test-MergePrerequisites.ps1 | 51 ++++++++++++++++++++--- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/.github/tools/Test-MergePrerequisites.ps1 b/.github/tools/Test-MergePrerequisites.ps1 index bd807746fa40..dfd4c9c85972 100644 --- a/.github/tools/Test-MergePrerequisites.ps1 +++ b/.github/tools/Test-MergePrerequisites.ps1 @@ -82,7 +82,7 @@ try { Write-Host "" # Step 1: Verify Git - Write-Host "[1/5] Checking Git installation..." -ForegroundColor Cyan + Write-Host "[1/6] Checking Git installation..." -ForegroundColor Cyan try { $gitPath = Get-Command git -ErrorAction SilentlyContinue if ($gitPath) { @@ -98,7 +98,7 @@ try { } # Step 2: Verify PowerShell version - Write-Host "`n[2/5] Checking PowerShell version..." -ForegroundColor Cyan + Write-Host "`n[2/6] Checking PowerShell version..." -ForegroundColor Cyan $psVersion = $PSVersionTable.PSVersion if ($psVersion.Major -ge 5) { Write-Host " ✓ PowerShell $($psVersion.ToString()) (>= 5.0)" -ForegroundColor Green @@ -108,7 +108,7 @@ try { } # Step 3: Verify Visual Studio - Write-Host "`n[3/5] Checking Visual Studio installation..." -ForegroundColor Cyan + Write-Host "`n[3/6] Checking Visual Studio installation..." -ForegroundColor Cyan $msBuildPaths = @( "${env:ProgramFiles}\Microsoft Visual Studio\2022\*\MSBuild\Current\Bin\MSBuild.exe", "${env:ProgramFiles}\Microsoft Visual Studio\2019\*\MSBuild\Current\Bin\MSBuild.exe", @@ -133,7 +133,7 @@ try { } # Step 4: Verify repository remotes - Write-Host "`n[4/5] Checking repository remotes..." -ForegroundColor Cyan + Write-Host "`n[4/6] Checking repository remotes..." -ForegroundColor Cyan if ($result.GitInstalled) { try { $gitConfigPath = Join-Path $repoRoot ".git\config" @@ -169,7 +169,7 @@ try { } # Step 5: Verify target version exists - Write-Host "`n[5/5] Checking target version exists..." -ForegroundColor Cyan + Write-Host "`n[5/6] Checking target version exists..." -ForegroundColor Cyan if ($result.GitInstalled -and $result.RemotesConfigured) { try { # Check if tag/branch ref exists in .git directory @@ -195,6 +195,44 @@ try { Write-Host " ⊘ Skipped (prerequisites not met)" -ForegroundColor Yellow } + # Step 6: Verify working directory is clean + Write-Host "`n[6/6] Checking working directory status..." -ForegroundColor Cyan + if ($result.GitInstalled) { + try { + # Use Start-Job to run git status --porcelain + $job = Start-Job -ScriptBlock { + param($repoPath) + Set-Location $repoPath + git status --porcelain + } -ArgumentList $repoRoot + + $jobResult = Wait-Job $job -Timeout 10 + if ($jobResult) { + $statusOutput = Receive-Job $job + Remove-Job $job -Force + + if ([string]::IsNullOrWhiteSpace($statusOutput)) { + $result.WorkingDirClean = $true + Write-Host " ✓ Working directory is clean" -ForegroundColor Green + } else { + $result.Issues += "Working directory has uncommitted changes" + Write-Host " ✗ Working directory has uncommitted changes:" -ForegroundColor Red + $statusOutput | ForEach-Object { Write-Host " $_" -ForegroundColor Yellow } + Write-Host " Hint: Commit or stash changes before starting merge" -ForegroundColor Yellow + } + } else { + Remove-Job $job -Force + $result.Issues += "Git status check timed out" + Write-Host " ✗ Git status check timed out" -ForegroundColor Red + } + } catch { + $result.Issues += "Error checking working directory: $($_.Exception.Message)" + Write-Host " ✗ Error checking working directory status" -ForegroundColor Red + } + } else { + Write-Host " ⊘ Skipped (Git not available)" -ForegroundColor Yellow + } + # Final evaluation Write-Host "`n========================================" -ForegroundColor Cyan Write-Host "PREREQUISITE CHECK SUMMARY" -ForegroundColor Cyan @@ -204,7 +242,8 @@ try { $result.GitInstalled, $result.VSInstalled, $result.RemotesConfigured, - $result.TargetExists + $result.TargetExists, + $result.WorkingDirClean ) $result.Success = ($criticalChecks | Where-Object { $_ -eq $false }).Count -eq 0 From 071bfba1e3fa2e5116e40770018ddb5fff92c87c Mon Sep 17 00:00:00 2001 From: User Date: Fri, 23 Jan 2026 12:32:01 -0800 Subject: [PATCH 221/244] update build instructions with paths.targets info --- .github/instructions/build.instructions.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/.github/instructions/build.instructions.md b/.github/instructions/build.instructions.md index 0dca61bd3fb9..435a3ede52e1 100644 --- a/.github/instructions/build.instructions.md +++ b/.github/instructions/build.instructions.md @@ -154,6 +154,28 @@ Only use this when running directly in a terminal (not via MCP): & "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\MSBuild.exe" .\contrib\win32\openssh\Win32-OpenSSH.sln /p:Configuration=Release /p:Platform=x64 /v:detailed ``` +### Important Note: paths.targets File Modification + +**The build process automatically modifies `.\contrib\win32\openssh\paths.targets`** to update SDK version paths based on the currently installed Windows SDK. This is normal and expected behavior. + +**Before committing any changes:** +```pwsh +# Check if paths.targets was modified by the build +git status .\contrib\win32\openssh\paths.targets + +# If it shows as modified, restore it to a clean state +git checkout .\contrib\win32\openssh\paths.targets +``` + +**Why this happens:** +- MSBuild automatically updates SDK paths to match your local environment +- These changes are environment-specific and should not be committed +- The file will be modified on every build + +**AI Agent Workflow:** +- After completing all build fixes and before final commit, restore paths.targets +- Only commit actual code changes, not build-generated path updates + ## Project File Management ### Understanding the Project Structure From 332176b17ec2a2e14819dc1de4adf90689d72f8b Mon Sep 17 00:00:00 2001 From: User Date: Fri, 23 Jan 2026 12:46:11 -0800 Subject: [PATCH 222/244] refine instructions --- .github/instructions/build.instructions.md | 17 +++++++++++++---- .../merge-process-overview.instructions.md | 16 ++++++++++++++-- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/.github/instructions/build.instructions.md b/.github/instructions/build.instructions.md index 435a3ede52e1..92c2ca11d842 100644 --- a/.github/instructions/build.instructions.md +++ b/.github/instructions/build.instructions.md @@ -126,7 +126,11 @@ fatal error C1083: Cannot open source file: 'newfile.c' 3. **If build failed**, **parse errors** using **Test-OpenSSHBuild** — `mcp_openssh-server_Test_OpenSSHBuild`. 4. **Categorize error types** (preprocessor, Windows compatibility, build system). 5. **Apply appropriate resolution strategy** (see error categories above) and **rebuild** with Start-OpenSSHBuild. -6. **Commit fixes with detailed message**. +6. **CRITICAL: Before committing, restore paths.targets**: + ```pwsh + git checkout .\contrib\win32\openssh\paths.targets + ``` +7. **Commit fixes with detailed message** (only actual code changes, not paths.targets). #### Reading Build Logs and Errors (on failure only) Use the **Test-OpenSSHBuild** MCP tool to read build logs and parse errors **only when the build fails**: @@ -172,9 +176,14 @@ git checkout .\contrib\win32\openssh\paths.targets - These changes are environment-specific and should not be committed - The file will be modified on every build -**AI Agent Workflow:** -- After completing all build fixes and before final commit, restore paths.targets -- Only commit actual code changes, not build-generated path updates +**AI Agent Workflow (CRITICAL):** +1. **ALWAYS restore paths.targets before committing**: + ```pwsh + # This MUST be done before every commit + git checkout .\contrib\win32\openssh\paths.targets + ``` +2. Only commit actual code changes, not build-generated path updates +3. Verify with `git status` that paths.targets is not staged before committing ## Project File Management diff --git a/.github/instructions/merge/merge-process-overview.instructions.md b/.github/instructions/merge/merge-process-overview.instructions.md index f8b26c6847cc..7b590a22a145 100644 --- a/.github/instructions/merge/merge-process-overview.instructions.md +++ b/.github/instructions/merge/merge-process-overview.instructions.md @@ -69,11 +69,19 @@ The process consists of several interconnected phases: git config core.editor true ``` -3. **Create merge branch from current branch:** +3. **Create merge branch (if not already created):** ```pwsh + # Check if branch already exists + git rev-parse --verify merge-v- 2>$null + + # If it doesn't exist, create it git checkout -b merge-v- # Example: merge-v9.8-20241010 + + # If it already exists, switch to it + git checkout merge-v- ``` + **Note:** The Test-MergePrerequisites tool will suggest the branch name. Create it once and reuse it throughout the merge process. ### Perform Merge with Grouped Commits 4. **Identify merge range and group commits:** @@ -164,7 +172,11 @@ The process consists of several interconnected phases: - **DO NOT** try to read log files directly with `Get-Content` or locate them manually - Fix issues based on parsed error output - Rebuild and verify - - Commit any build fixes separately with descriptive messages + - **CRITICAL: Before committing, restore paths.targets**: + ```pwsh + git checkout .\contrib\win32\openssh\paths.targets + ``` + - Commit any build fixes separately with descriptive messages (only actual code changes) 10. **Validate if batch ended with successful CI:** Check the end commit's CI status from Get-CommitGroups output. From 0bb51cd47730f5fdc0a7fbfb14000b88bf0471db Mon Sep 17 00:00:00 2001 From: User Date: Fri, 23 Jan 2026 12:49:00 -0800 Subject: [PATCH 223/244] tweak instructions --- .../merge/merge-process-overview.instructions.md | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/.github/instructions/merge/merge-process-overview.instructions.md b/.github/instructions/merge/merge-process-overview.instructions.md index 7b590a22a145..f50a9eb03ec1 100644 --- a/.github/instructions/merge/merge-process-overview.instructions.md +++ b/.github/instructions/merge/merge-process-overview.instructions.md @@ -69,20 +69,6 @@ The process consists of several interconnected phases: git config core.editor true ``` -3. **Create merge branch (if not already created):** - ```pwsh - # Check if branch already exists - git rev-parse --verify merge-v- 2>$null - - # If it doesn't exist, create it - git checkout -b merge-v- - # Example: merge-v9.8-20241010 - - # If it already exists, switch to it - git checkout merge-v- - ``` - **Note:** The Test-MergePrerequisites tool will suggest the branch name. Create it once and reuse it throughout the merge process. - ### Perform Merge with Grouped Commits 4. **Identify merge range and group commits:** Use the Get-CommitGroups MCP tool with `-FirstChunkOnly -GroupByCIPresence` From 29ad1162babdcd2aacbe3e7ef1f2fcec5f6eca72 Mon Sep 17 00:00:00 2001 From: User Date: Fri, 23 Jan 2026 12:50:53 -0800 Subject: [PATCH 224/244] update tool --- .github/tools/Test-MergePrerequisites.ps1 | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/tools/Test-MergePrerequisites.ps1 b/.github/tools/Test-MergePrerequisites.ps1 index dfd4c9c85972..3cd75bd87657 100644 --- a/.github/tools/Test-MergePrerequisites.ps1 +++ b/.github/tools/Test-MergePrerequisites.ps1 @@ -251,11 +251,6 @@ try { if ($result.Success) { Write-Host "✓ ALL PREREQUISITES MET" -ForegroundColor Green Write-Host "`nYou are ready to begin the merge process:" -ForegroundColor White - Write-Host " 0. (Optional) Verify baseline build: mcp_openssh-server_Test_OpenSSHBuild" -ForegroundColor Gray - Write-Host " 1. Create merge branch: git checkout -b merge-$TargetVersion-$(Get-Date -Format 'yyyyMMdd')" -ForegroundColor Gray - Write-Host " 2. Use Get-CommitGroups tool to identify first batch of commits" -ForegroundColor Gray - Write-Host " 3. Begin cherry-picking commits from first batch" -ForegroundColor Gray - $result.Message = "All prerequisites met. Ready to start merge." } else { Write-Host "✗ PREREQUISITES NOT MET" -ForegroundColor Red From a1072a6099dad797252db312c3b1b8ad12bf8773 Mon Sep 17 00:00:00 2001 From: User Date: Fri, 30 Jan 2026 10:30:24 -0800 Subject: [PATCH 225/244] fix bug in tool --- .github/tools/Get-CommitGroups.ps1 | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/.github/tools/Get-CommitGroups.ps1 b/.github/tools/Get-CommitGroups.ps1 index 0c5411dcedb3..ef83730f31b2 100644 --- a/.github/tools/Get-CommitGroups.ps1 +++ b/.github/tools/Get-CommitGroups.ps1 @@ -254,21 +254,22 @@ try { $allCommits = @($comparison.commits) # If we hit the 250 commit limit, we need to get the actual first 250 commits - # by using the oldest commit from this batch as the end point - if ($comparison.total_commits -gt 250) { + # by iteratively narrowing the range until we get 250 or fewer commits + while ($comparison.total_commits -gt 250) { Write-Host "Warning: Total commits ($($comparison.total_commits)) exceeds API limit (250)." -ForegroundColor Yellow - Write-Host "Fetching first 250 commits by using oldest commit as endpoint..." -ForegroundColor Cyan + Write-Host "Fetching first 250 commits by narrowing the range..." -ForegroundColor Cyan - # Get the oldest commit SHA from the initial batch (first in chronological order) + # Get the oldest commit SHA from the current batch (first in chronological order) + # Since the batch is limited to 250, this is approximately the 250th commit from start $oldestCommitSha = $allCommits[0].sha - # Now compare from start to this oldest commit to get the actual first 250 + # Now compare from start to this oldest commit to narrow down the range $limitedCompareUrl = "$apiBase/compare/${startCommitSha}...${oldestCommitSha}" Write-Host "Comparing $startCommitSha...$oldestCommitSha" -ForegroundColor Gray - $limitedComparison = Invoke-RestMethod -Uri $limitedCompareUrl -Headers (Get-GitHubHeaders) + $comparison = Invoke-RestMethod -Uri $limitedCompareUrl -Headers (Get-GitHubHeaders) - $allCommits = @($limitedComparison.commits) - Write-Host "Fetched $($allCommits.Count) commits in the corrected range" -ForegroundColor Green + $allCommits = @($comparison.commits) + Write-Host "Narrowed to $($comparison.total_commits) total commits ($($allCommits.Count) returned)" -ForegroundColor Green } $startRef = if ($GitHubTag) { "tag $GitHubTag" } else { "commit $StartCommit" } From c19ad3f0af2d298bddf6c458d5cb6b480d698c47 Mon Sep 17 00:00:00 2001 From: User Date: Fri, 30 Jan 2026 11:34:05 -0800 Subject: [PATCH 226/244] update instructions --- .github/instructions/build.instructions.md | 9 +++++++++ .../instructions/merge/merge-details.instructions.md | 11 ++++++++++- .../instructions/repository-overview.instructions.md | 7 ++++++- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/.github/instructions/build.instructions.md b/.github/instructions/build.instructions.md index 92c2ca11d842..bcf6a3f8bc9f 100644 --- a/.github/instructions/build.instructions.md +++ b/.github/instructions/build.instructions.md @@ -110,6 +110,8 @@ fatal error C1083: Cannot open source file: 'newfile.c' ``` + + **Important:** Visual Studio project files (`.vcxproj`) use Windows-style line endings (`\r\n`). When programmatically adding lines to these files, ensure you use `\r\n` instead of just `\n` to maintain consistency with the existing file format. This prevents Git from showing the entire file as changed. 4. **Update solution if new binaries added:** ``` @@ -240,6 +242,13 @@ contrib\win32\openssh\ # Edit Win32-OpenSSH.sln to include new project ``` +**Important Note on Line Endings:** +Both `.vcxproj` and `.sln` files use Windows-style line endings (`\r\n`). When programmatically modifying these files: +- Use `\r\n` instead of `\n` when inserting new lines +- Maintain consistent line endings to avoid Git showing spurious changes +- Example in PowerShell: `$newLine = "`r`n"` +- Example in Python: `new_line = "\r\n"` + ## Validation and Testing ### Build Verification Using MCP Tools diff --git a/.github/instructions/merge/merge-details.instructions.md b/.github/instructions/merge/merge-details.instructions.md index a2358a04cb2b..3f1df5e4e98b 100644 --- a/.github/instructions/merge/merge-details.instructions.md +++ b/.github/instructions/merge/merge-details.instructions.md @@ -199,6 +199,14 @@ FUNCTION sync_build_system(): FOR EACH source_file IN makefile_changes.new_source_files: target_project = determine_target_project(source_file) add_source_to_project(target_project, source_file) + +// CRITICAL: When modifying .vcxproj or .sln files programmatically, +// ALWAYS use Windows line endings (\r\n) instead of Unix (\n). +// This prevents Git from showing the entire file as modified. +FUNCTION add_source_to_project(project_file, source_file): + // Example: Use \r\n for line endings + new_line = f" \r\n" + insert_into_project_file(project_file, new_line) ``` ## Common Conflict Patterns @@ -209,9 +217,10 @@ FUNCTION sync_build_system(): - **File permissions** → Adapt to Windows ACL model ### Build System Changes -- **Makefile additions** → Update Visual Studio project files +- **Makefile additions** → Update Visual Studio project files (use `\r\n` line endings) - **New dependencies** → Check Windows compatibility - **Compiler flags** → Translate to MSVC equivalents +- **Project file edits** → Maintain Windows line endings (`\r\n`) to avoid Git diffs ### Configuration Changes - **New config options** → Add to `./contrib/win32/openssh/config.h.vs` diff --git a/.github/instructions/repository-overview.instructions.md b/.github/instructions/repository-overview.instructions.md index aa343214f394..3fe4c9d6c2b8 100644 --- a/.github/instructions/repository-overview.instructions.md +++ b/.github/instructions/repository-overview.instructions.md @@ -79,7 +79,12 @@ When merging changes to `ssh-agent.c` or related agent files from upstream: - Flag for Windows team review - May require significant redesign work -3. **Do NOT**: +3. **New files** (additional agent-related source files): + - **Not all new upstream files need to be ported** to the Windows ssh-agent + - Evaluate whether the functionality is relevant to the Windows implementation + - If not applicable, document the decision and skip porting + +4. **Do NOT**: - Directly apply upstream ssh-agent patches to Windows version - Assume one-to-one code correspondence - Merge without understanding Windows implementation differences From 2d2368cd04fdff490a4272bef306b38e52386606 Mon Sep 17 00:00:00 2001 From: User Date: Fri, 20 Feb 2026 11:15:50 -0800 Subject: [PATCH 227/244] add instructions for communication expectations and examples --- .../agent-communication.instructions.md | 139 ++++++++ .../agent-communication-merge.instructions.md | 335 ++++++++++++++++++ 2 files changed, 474 insertions(+) create mode 100644 .github/instructions/agent-communication.instructions.md create mode 100644 .github/instructions/merge/agent-communication-merge.instructions.md diff --git a/.github/instructions/agent-communication.instructions.md b/.github/instructions/agent-communication.instructions.md new file mode 100644 index 000000000000..eb5242163023 --- /dev/null +++ b/.github/instructions/agent-communication.instructions.md @@ -0,0 +1,139 @@ +--- +applyTo: "**/*" +--- + +# AI Agent Communication Guidelines + +## Overview +This document establishes how AI agents should communicate with users throughout their interactions. These guidelines apply to **all agent operations** in this workspace. For merge-specific communication templates, see [agent-communication-merge.instructions.md](./merge/agent-communication-merge.instructions.md). + +## Core Principle: Tool Output vs Agent Communication + +### Distinction + +**1. MCP Tool Execution (Write-Host is acceptable):** +- When MCP tools execute PowerShell scripts, those scripts may use `Write-Host` for output +- This is normal and expected behavior for the tool itself +- The agent receives this output and can parse it +- Example: `Test-OpenSSHFunctionality.ps1` uses `Write-Host` to display test progress + +**2. Agent-to-User Communication (Use chat messages ONLY):** +- AI agents **MUST** communicate with users through chat messages, not `Write-Host` +- **DO NOT** invoke `Write-Host` or other console output commands from the agent +- Instead, present information conversationally in your responses +- Parse tool output and summarize it in chat messages + +## Communication Standards + +### ❌ INCORRECT: Agent Using Write-Host +```pwsh +Write-Host "Starting merge process..." +Write-Host "Build succeeded!" -ForegroundColor Green +Write-Host "Found 3 conflicts in auth.c" +``` + +### ✅ CORRECT: Agent Using Chat Messages +``` +Starting the merge process. I'll cherry-pick the commits in this batch and then build. + +The build succeeded! All 14 executables were created successfully. + +Found 3 conflicts in auth.c. Analyzing the conflict types to determine the resolution strategy. +``` + +## Pseudocode Implementation Guidance + +When you see pseudocode functions in instruction files like: +- `update_progress()` +- `generate_test_report()` +- `log()` +- `append_to_progress_log()` + +These represent **conceptual operations**. Implement them by: +1. Generating the information/report internally +2. Communicating the results to the user via chat messages +3. **NOT** by executing `Write-Host` or similar PowerShell output commands + +### Example: Pseudocode to Implementation + +**Pseudocode:** +```pseudocode +FUNCTION update_progress(phase, status, details): + log(f"Phase {phase}: {status}") + IF status == "FAILURE": + generate_failure_report(details) +``` + +**Correct Agent Implementation:** +``` +[Agent analyzes the phase and status] +[Agent sends chat message]: "Phase 1: Conflict Resolution - Completed successfully. Resolved 5 conflicts across 3 files." +``` + +**Incorrect Agent Implementation:** +```pwsh +Write-Host "Phase 1: Conflict Resolution - Completed successfully" +``` + +## Best Practices + +### 1. Be Conversational +- Write naturally, as if speaking to a colleague +- Avoid overly formal or robotic language +- Use active voice + +### 2. Provide Context +- Explain what you're doing and why +- Help users understand the current state +- Highlight important information + +### 3. Use Structured Formatting When Helpful +- Use markdown formatting for clarity +- Use bullet points for lists +- Use code blocks for commands or file paths +- Use file links when referencing specific files + +### 4. Progressive Disclosure +- Start with high-level summaries +- Provide details when relevant +- Don't overwhelm with unnecessary information + +### 5. Clear Status Indicators +Use clear language for status: +- ✅ "succeeded", "completed successfully", "passed" +- ❌ "failed", "encountered errors", "did not pass" +- ⚠️ "warning", "requires attention", "partial success" + +## Examples + +### Good: Progress Update +``` +Analyzing the upstream changes between the last merge commit and V_10_0_P2. Found 127 commits with 8 security fixes and 3 build system changes that will require Visual Studio project updates. +``` + +### Good: Error Report +``` +The build failed with 4 compilation errors: +- auth.c: Missing include for Windows compatibility header +- sshd.c: Undefined reference to fork() - needs Windows equivalent +- config.h.vs: Missing preprocessor definition for HAVE_SETRESUID + +I'll add the Windows compatibility fixes now. +``` + +### Good: Success Report +``` +Testing completed successfully! The SSH service installed, started, and accepted connections. The test command executed correctly with expected output. +``` + +## Merge-Specific Guidelines + +For detailed merge workflow communication templates, including exact formats for tool output summaries and commit batch summaries, see: +- [Merge-Specific Agent Communication Guidelines](./merge/agent-communication-merge.instructions.md) + +## Summary + +- **Tools can use Write-Host** - MCP tools and PowerShell scripts may output to console +- **Agents use chat only** - All agent communication must be via chat messages +- **Parse, don't echo** - Parse tool output and present summaries conversationally +- **Be clear and helpful** - Provide context, use formatting, and communicate status clearly diff --git a/.github/instructions/merge/agent-communication-merge.instructions.md b/.github/instructions/merge/agent-communication-merge.instructions.md new file mode 100644 index 000000000000..049cf62a09e0 --- /dev/null +++ b/.github/instructions/merge/agent-communication-merge.instructions.md @@ -0,0 +1,335 @@ +--- +applyTo: ".github/instructions/merge/**" +--- + +# Merge-Specific Agent Communication Guidelines + +## Overview +This document provides specific communication templates and guidelines for AI agents performing upstream merge operations. These guidelines **supplement** the high-level agent communication principles defined in [agent-communication.instructions.md](../agent-communication.instructions.md). + +**Key Points:** +- The high-level communication guidelines apply to ALL merge interactions +- This document adds merge-specific templates and formats +- Tool output templates are **MUST use** (exact format required) +- Batch summary templates are **SHOULD include** (flexible adaptation allowed) + +## MCP Tool Output Templates + +These templates define the **exact format** agents MUST use when communicating tool results to users. + +### 1. Start-OpenSSHBuild Tool Output + +**MUST use this format when reporting build results.** + +#### Success Scenario: +``` +Build completed successfully. All 14 executables were created: +- ssh.exe, sshd.exe, sshd-auth.exe, sshd-session.exe +- ssh-agent.exe, ssh-add.exe, ssh-keygen.exe, ssh-keyscan.exe +- scp.exe, sftp.exe, sftp-server.exe +- ssh-pkcs11-helper.exe, ssh-shellhost.exe, ssh-sk-helper.exe + +Configuration: Release | Architecture: x64 +``` + +#### Failure Scenario: +``` +Build failed with compilation errors. Analyzing the build log to identify issues. + +[After running Test-OpenSSHBuild] +Found X compilation errors: +- [file.c]: [brief error description] +- [file.c]: [brief error description] + +I'll resolve these errors now. +``` + +### 2. Test-OpenSSHBuild Tool Output + +**MUST use this format when reporting build error analysis.** + +#### When Build Failed: +``` +Build error analysis complete: + +Compilation Errors (X): +- [filename.c] (Line Y): [Error code] - [Brief description] +- [filename.c] (Line Y): [Error code] - [Brief description] + +Warnings (X): +- [filename.c] (Line Y): [Warning description] + +Error Categories: +- Missing preprocessor definitions: X +- Windows compatibility issues: X +- Build system inconsistencies: X +``` + +#### When Build Succeeded: +``` +No need to analyze build errors - the build completed successfully. +``` + +**Note:** Only invoke Test-OpenSSHBuild when Start-OpenSSHBuild reports failure. + +### 3. Test-OpenSSHFunctionality Tool Output + +**MUST use this format when reporting functionality test results.** + +#### Success Scenario: +``` +Functionality testing completed successfully! + +Test Results: +✅ Administrator privileges verified +✅ Test user created: [username] +✅ SSH service installed successfully +✅ SSH service started successfully +✅ Firewall rule configured +✅ SSH connection test passed +✅ Command execution verified: "echo hello world" returned expected output + +All test resources cleaned up. +``` + +#### Failure Scenario: +``` +Functionality testing failed. + +Test Progress: +✅ Administrator privileges verified +✅ Test user created: [username] +❌ SSH service installation failed + +Error: [Error message from tool] + +The test environment has been cleaned up. I'll investigate the service installation issue. +``` + +#### Partial Success Scenario: +``` +Functionality testing completed with warnings. + +Test Results: +✅ Administrator privileges verified +✅ Test user created: [username] +✅ SSH service installed successfully +✅ SSH service started successfully +⚠️ Firewall rule configuration skipped (SkipFirewall=true) +✅ SSH connection test passed +✅ Command execution verified + +Note: Firewall was not configured as requested. Ensure firewall rules exist if testing remote connections. +``` + +## Commit Batch Summary Template + +**SHOULD include these elements** when summarizing a commit batch. Adapt the format and detail level based on context. + +### Template Structure: + +``` +Processing batch [N] ([X] commits from [start_hash] to [end_hash]) + +Key Changes: +- [Category 1]: [Brief description] +- [Category 2]: [Brief description] +- [Category 3]: [Brief description] + +Files Modified: [X] files +Conflicts: [X] conflicts ([resolved/pending]) + +[Additional context if needed] +``` + +### Example - Simple Batch: +``` +Processing batch 1 (8 commits from a1b2c3d to e4f5a6b) + +Key Changes: +- Security fixes: Updated bounds checking in buffer handling +- Bug fixes: Corrected memory leak in session cleanup +- Documentation: Updated protocol specification comments + +Files Modified: 12 files +Conflicts: 2 conflicts (resolved) +``` + +### Example - Complex Batch: +``` +Processing batch 3 (15 commits from 7h8i9j0 to k1l2m3n) + +Key Changes: +- Build system: Added new source files for MLKEM support +- Authentication: Enhanced certificate validation logic +- Process management: Modified daemon initialization (requires Windows adaptation) +- Configuration: Added 3 new preprocessor definitions + +Files Modified: 28 files +Conflicts: 7 conflicts (5 resolved, 2 require manual review) + +Note: The daemon initialization changes use fork() which needs Windows CreateProcess() equivalent. +``` + +### Example - Minimal Batch: +``` +Processing batch 5 (3 commits from x7y8z9 to a0b1c2) + +Key Changes: +- Minor documentation updates +- Code formatting corrections + +Files Modified: 4 files +Conflicts: None +``` + +## Progress Update Templates + +**SHOULD include these elements** when communicating progress at different workflow phases. Adapt wording to context. + +### Pre-Merge Analysis Phase: +``` +Analyzing upstream changes from [last_merge_tag] to [target_version]... + +Found [X] commits to merge: +- [X] security fixes (HIGH PRIORITY) +- [X] bug fixes +- [X] feature additions +- [X] build system changes + +Grouping commits into batches for incremental merging. +``` + +### Conflict Resolution Phase: +``` +Resolving [X] conflicts in [filename]: + +- Conflict 1: [Brief description] → [Resolution strategy] +- Conflict 2: [Brief description] → [Resolution strategy] + +[X] conflicts resolved, [Y] remaining. +``` + +### Build Fixes Phase: +``` +Applying build fixes for iteration [N]: + +- Added Windows compatibility header to [file.c] +- Updated config.h.vs with [X] new definitions +- Added [source_file.c] to [project.vcxproj] + +Rebuilding... +``` + +### Testing Phase: +``` +Running functionality tests to validate the merge... + +[Use Test-OpenSSHFunctionality template from above] +``` + +### Cleanup Phase: +``` +Finalizing the merge: + +✅ Restored paths.targets to clean state +✅ Verified [X] commits applied successfully +✅ All builds passing +✅ Functionality tests passing + +Ready to commit and push. +``` + +## Special Scenarios + +### When Seeking User Approval: +``` +Batch [N] is ready for review: + +Summary: +- [X] commits merged successfully +- Build: ✅ Passed +- Tests: ✅ Passed +- Conflicts: [X] resolved + +Changes include: [brief list] + +May I proceed with the next batch? +``` + +### When Requesting Manual Intervention: +``` +I've encountered a complex conflict that requires manual review: + +File: [filename] +Issue: [Description of the conflict complexity] +Context: [Why automated resolution isn't appropriate] + +Recommendation: [Suggested approach] + +Please advise on how to proceed. +``` + +### When Reporting Critical Issues: +``` +⚠️ CRITICAL: [Issue type detected] + +Details: +- [Specific problem] +- [Impact assessment] +- [Affected components] + +This requires immediate attention before proceeding with the merge. +``` + +## Integration with Pseudocode + +When implementing pseudocode patterns from merge-details.instructions.md, use these communication approaches: + +### update_progress() → Chat Message +```pseudocode +# Pseudocode: +update_progress("Build Fixes", "IN_PROGRESS", "Applied 3 fixes") + +# Agent Implementation (via chat): +"Applying build fixes (iteration 2): Added 3 Windows compatibility changes. Rebuilding now..." +``` + +### generate_test_report() → Structured Chat Message +```pseudocode +# Pseudocode: +report = generate_test_report(test_results) + +# Agent Implementation (via chat): +[Use Test-OpenSSHFunctionality template from above] +``` + +### log() → Contextual Chat Message +```pseudocode +# Pseudocode: +log(f"Skipping {binary} - Unix only") + +# Agent Implementation (via chat): +"Skipping ssh-keysign.exe - Unix-only binary not applicable to Windows build." +``` + +## Best Practices for Merge Communication + +1. **Always include commit hashes** when referencing specific commits (first 7 characters) +2. **Use file links** when referencing specific files: [filename](path/to/filename) +3. **Categorize changes** by type (security, bug fix, feature, build system, etc.) +4. **Highlight Windows-specific considerations** that required special handling +5. **Provide commit counts** to show progress and scope +6. **Be specific about conflict types** and resolution strategies used +7. **Report before and after** major operations (build, test, etc.) +8. **Update after each batch** to maintain transparency +9. **Use consistent terminology** aligned with the instruction files +10. **Mark critical items** with appropriate indicators (⚠️, ✅, ❌) + +## Summary + +- **Tool templates are REQUIRED** - Use exact formats for MCP tool output summaries +- **Batch templates are RECOMMENDED** - Include suggested elements but adapt to context +- **Supplement high-level guidelines** - All general communication principles still apply +- **Maintain transparency** - Keep users informed throughout the merge process +- **Be consistent** - Use standard terminology and formatting patterns From 179d41ef8bfac06cbc56df428e67e8d76846cfca Mon Sep 17 00:00:00 2001 From: User Date: Fri, 20 Feb 2026 11:26:19 -0800 Subject: [PATCH 228/244] update instructions and tools to clarify end commit expectations --- .github/agents/merge-upstream.agent.md | 15 +++++++------ .../merge-process-overview.instructions.md | 8 ++++--- .github/prompt/merge.prompt.md | 3 +++ .github/tools/Get-CommitGroups.ps1 | 21 ++++++++++++++++--- 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/.github/agents/merge-upstream.agent.md b/.github/agents/merge-upstream.agent.md index e5b0e8f2b5dd..3909a0b7138e 100644 --- a/.github/agents/merge-upstream.agent.md +++ b/.github/agents/merge-upstream.agent.md @@ -29,6 +29,7 @@ This agent assists with merging upstream OpenSSH commits into the PowerShell for - **Parameters**: - `GitHubTag` (string, optional): GitHub tag to start from (e.g., "V_10_0_P2") - `StartCommit` (string, optional): Commit SHA to start from + - `EndCommit` (string, optional): Commit SHA to end at (default: HEAD - most recent upstream commit) - `FirstChunkOnly` (boolean, optional): Stop after finding first chunk - `GroupByCIPresence` (boolean, optional): Group by CI presence instead of CI success - **Recommended Usage**: Always use `-FirstChunkOnly -GroupByCIPresence` for incremental merging @@ -92,7 +93,8 @@ This agent assists with merging upstream OpenSSH commits into the PowerShell for 1. **Run prerequisite verification via MCP tool:** - **MCP Tool Name**: `mcp_openssh-server_Test_MergePrerequisites` - **Parameters**: - - `TargetVersion` (string, required): Upstream version/tag to merge (e.g., "V_10_0_P2") + - `TargetVersion` (string, required): Upstream version/tag to start from (e.g., "V_10_0_P2") + - `EndCommit` (string, optional): Commit SHA to end at (default: HEAD - most recent upstream commit) - `SkipBaselineBuild` (boolean, optional): Skip baseline build check (default: false) This single tool verifies: @@ -126,8 +128,9 @@ This agent assists with merging upstream OpenSSH commits into the PowerShell for 1. **Get first commit batch** using Get-CommitGroups MCP tool: - **MCP Tool Name**: `mcp_openssh-server_Get_CommitGroups` - **Parameters**: - - For first batch: `GitHubTag="V_10_0_P2"`, `FirstChunkOnly=true`, `GroupByCIPresence=true` - - For subsequent batches: `StartCommit=""`, `FirstChunkOnly=true`, `GroupByCIPresence=true` + - For first batch: `GitHubTag="V_10_0_P2"`, `EndCommit=""`, `FirstChunkOnly=true`, `GroupByCIPresence=true` + - For subsequent batches: `StartCommit=""`, `EndCommit=""`, `FirstChunkOnly=true`, `GroupByCIPresence=true` + - **Note**: If `EndCommit` is not specified, the tool will merge up to the most recent upstream commit (HEAD) **The tool returns structured data:** ```json @@ -257,14 +260,14 @@ This agent assists with merging upstream OpenSSH commits into the PowerShell for **Objective:** Process remaining commit groups until merge is complete **Steps:** -1. **Return to Phase 2** with `-StartCommit` set to previous batch's end commit +1. **Return to Phase 2** with `-StartCommit` set to previous batch's end commit and `-EndCommit` set to target end commit 2. **Repeat Phases 2-4** for each batch: - - Get next batch with Get-CommitGroups + - Get next batch with Get-CommitGroups (passing both StartCommit and EndCommit) - Cherry-pick commits - Build (mandatory) - Validate (if batch ends with successful CI) - Summarize and get approval -3. **Continue** until all target commits are merged or HEAD is reached +3. **Continue** until the target end commit is reached (or HEAD if no end commit was specified) 4. **Perform final comprehensive validation:** - **MCP Tool Name**: `mcp_openssh-server_Test_OpenSSHFunctionality` - **Parameters**: (use defaults for Release/x64) diff --git a/.github/instructions/merge/merge-process-overview.instructions.md b/.github/instructions/merge/merge-process-overview.instructions.md index f50a9eb03ec1..87d273eafea2 100644 --- a/.github/instructions/merge/merge-process-overview.instructions.md +++ b/.github/instructions/merge/merge-process-overview.instructions.md @@ -78,12 +78,14 @@ The process consists of several interconnected phases: **Parameters**: - `GitHubTag` (string, optional): Start from last merged tag (e.g., "V_10_0_P2") - `StartCommit` (string, optional): Start from specific commit SHA + - `EndCommit` (string, optional): End at specific commit SHA (default: HEAD - most recent upstream commit) - `FirstChunkOnly` (boolean): Set to `true` - `GroupByCIPresence` (boolean): Set to `true` **Example for first batch**: - Find the last upstream tag in the fork - - Call tool with `GitHubTag=`, `FirstChunkOnly=true`, `GroupByCIPresence=true` + - Call tool with `GitHubTag=`, `EndCommit=`, `FirstChunkOnly=true`, `GroupByCIPresence=true` + - Omit `EndCommit` to merge all commits up to HEAD (most recent upstream commit) - This gets commits ending with any commit that has CI runs (not just successful CI) **Example output:** @@ -103,8 +105,8 @@ The process consists of several interconnected phases: Display batch details for verification, then proceed with cherry-picking. **After completing steps below, get next batch**: - - Call tool with `StartCommit=`, `FirstChunkOnly=true`, `GroupByCIPresence=true` - - Continue this process until the upstream's HEAD has been successfully merged + - Call tool with `StartCommit=`, `EndCommit=`, `FirstChunkOnly=true`, `GroupByCIPresence=true` + - Continue this process until the target end commit is reached (or HEAD if no end commit specified) 5. **Execute chunked merge (batch cherry-pick all commits in chunk):** diff --git a/.github/prompt/merge.prompt.md b/.github/prompt/merge.prompt.md index d64421f7ef5c..a75572557e79 100644 --- a/.github/prompt/merge.prompt.md +++ b/.github/prompt/merge.prompt.md @@ -4,6 +4,7 @@ Assist with merging the commits from upstream into this branch starting from the Provide the following when you invoke this prompt: - Start ref (tag or commit) — REQUIRED (e.g., `upstream/V_9_8_P1` or a commit SHA) +- End ref (commit) — OPTIONAL (default: HEAD - most recent upstream commit) - Upstream remote — optional (default: `upstream`) - Windows fork remote — optional (default: `upstream-pwsh`) - Target branch — optional (default: current branch) @@ -24,6 +25,8 @@ Expected outputs per batch: Quick start examples: - "Merge from tag `upstream/V_9_8_P1` into my current branch." +- "Merge from tag `upstream/V_9_8_P1` to commit `a1b2c3d` into my current branch." - "Merge starting at commit `3a1b2c3`, upstream remote `upstream`, target current branch." If the Start ref is not provided, ask for it before proceeding. +If the End ref is not provided, merging will continue to HEAD (most recent upstream commit). diff --git a/.github/tools/Get-CommitGroups.ps1 b/.github/tools/Get-CommitGroups.ps1 index ef83730f31b2..c2e2b18049d8 100644 --- a/.github/tools/Get-CommitGroups.ps1 +++ b/.github/tools/Get-CommitGroups.ps1 @@ -21,9 +21,14 @@ .PARAMETER StartCommit The commit SHA to start from (e.g., "6fb728df50c1afd338cb0223a84ce24579577eff"). - Cannot be used with -GitHubTag. The script will find commits after this commit up to HEAD. + Cannot be used with -GitHubTag. The script will find commits after this commit up to EndCommit (or HEAD if not specified). This is typically used when continuing from a previously merged commit. +.PARAMETER EndCommit + The commit SHA to end at (e.g., "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0"). + If not specified, defaults to HEAD (most recent upstream commit). + This allows merging up to a specific commit rather than always merging to HEAD. + .PARAMETER FirstChunkOnly When specified, the script stops after finding the first chunk with a successful CI commit (or first chunk with any CI when using -GroupByCIPresence). @@ -66,6 +71,12 @@ Finds the first batch of commits after the V_10_0_P2 tag that ends with any commit that has CI runs (regardless of success or failure). +.EXAMPLE + .\Get-CommitGroups.ps1 -StartCommit "6fb728df50c1afd338cb0223a84ce24579577eff" -EndCommit "a1b2c3d4e5f6" -FirstChunkOnly + + Finds the first batch of commits between the specified start and end commits. + Useful for merging a specific range rather than all commits up to HEAD. + .NOTES - Requires internet access to query GitHub API - Set GITHUB_TOKEN environment variable for authenticated API access (5,000 requests/hour) @@ -86,6 +97,9 @@ param( [Parameter(Mandatory=$false)] [string]$StartCommit, + [Parameter(Mandatory=$false)] + [string]$EndCommit, + [Parameter(Mandatory=$false)] [switch]$FirstChunkOnly, @@ -242,11 +256,12 @@ try { $page = 1 $perPage = 250 # Compare API returns max 250 commits per page - Write-Host "Fetching commits from $startCommitSha...HEAD" -ForegroundColor Gray + $endRef = if ($EndCommit) { $EndCommit } else { "HEAD" } + Write-Host "Fetching commits from $startCommitSha...$endRef" -ForegroundColor Gray # The Compare API doesn't support pagination, so we need to use commits API instead # to get commits in the correct range with proper pagination - $compareUrl = "$apiBase/compare/${startCommitSha}...HEAD" + $compareUrl = "$apiBase/compare/${startCommitSha}...$endRef" $comparison = Invoke-RestMethod -Uri $compareUrl -Headers (Get-GitHubHeaders) # The Compare API returns commits - need to verify order From 7e1ea03f1344edfa48b2964fcdf36bb2056caeb5 Mon Sep 17 00:00:00 2001 From: User Date: Fri, 20 Feb 2026 11:33:49 -0800 Subject: [PATCH 229/244] add instructions around addressing compiler warnings --- .github/agents/merge-upstream.agent.md | 10 ++- .github/instructions/build.instructions.md | 57 +++++++++++++++- .../agent-communication-merge.instructions.md | 67 ++++++++++++++++++- .../merge/merge-details.instructions.md | 21 ++++-- .../merge-process-overview.instructions.md | 26 +++++-- 5 files changed, 164 insertions(+), 17 deletions(-) diff --git a/.github/agents/merge-upstream.agent.md b/.github/agents/merge-upstream.agent.md index 3909a0b7138e..bb67a39cefbb 100644 --- a/.github/agents/merge-upstream.agent.md +++ b/.github/agents/merge-upstream.agent.md @@ -110,7 +110,14 @@ This agent assists with merging upstream OpenSSH commits into the PowerShell for - Tool must display "ALL PREREQUISITES MET" - If tool fails, fix reported issues before continuing -3. **Create merge branch:** +3. **Establish baseline warning count:** + - **MCP Tool Name**: `mcp_openssh-server_Test_OpenSSHBuild` + - **Parameters**: `Configuration="Release"`, `Architecture="x64"` + - Parse and document the current warning count and categories + - This baseline will be used to detect new warnings introduced during merge + - Store baseline for comparison after each build + +4. **Create merge branch:** ```pwsh git checkout -b merge-v- # Example: git checkout -b merge-v10.0P2-20260109 @@ -118,6 +125,7 @@ This agent assists with merging upstream OpenSSH commits into the PowerShell for **Success Criteria:** - Prerequisite tool reports all checks passed +- Baseline warning count established and documented - Merge branch created - Ready to begin Phase 2 (cherry-picking first batch) diff --git a/.github/instructions/build.instructions.md b/.github/instructions/build.instructions.md index bcf6a3f8bc9f..23724ae0d8f8 100644 --- a/.github/instructions/build.instructions.md +++ b/.github/instructions/build.instructions.md @@ -47,6 +47,55 @@ Use the Test-OpenSSHBuild MCP tool when a build fails: - **MCP Tool Name**: `mcp_openssh-server_Test_OpenSSHBuild` - **Parameters**: `Configuration="Release"`, `Architecture="x64"` +## Compiler Warning Policy + +### Overview +All new compiler warnings introduced during the merge process must be reported to users and require approval before proceeding. This ensures code quality is maintained and potential issues are not overlooked. + +### Baseline Establishment +1. **Before starting the merge**, establish a baseline warning count: + - Run Test-OpenSSHBuild on the current branch (before any merge commits) + - Document the total warning count and warning categories + - Store this as the baseline for comparison + +2. **After each build during merge**, compare warnings against baseline: + - Run Test-OpenSSHBuild after every successful build (not just failures) + - Compare current warning count to baseline + - Identify any new warnings introduced + +### Warning Categorization +Attempt to categorize warnings to help users make informed decisions: + +**Common Warning Categories:** +- **Deprecated APIs**: Use of functions/APIs marked as deprecated +- **Type Conversions**: Implicit type conversions that may lose data +- **Unused Variables/Functions**: Declared but unused code elements +- **Potential Bugs**: Logic issues that may cause runtime problems +- **Security-Related**: Potential security vulnerabilities (buffer overruns, etc.) +- **Platform-Specific**: Windows-specific compatibility warnings + +**Note:** Categorization helps users make decisions, but **all new warnings require user approval regardless of predicted severity**. + +### User Approval Requirement +**Critical Rule**: No threshold - every new warning requires user input. + +1. **When new warnings are detected:** + - Report warning count delta (baseline vs current) + - List each new warning with: + - File and line number + - Warning code and message + - Attempted category classification + - Request user decision: fix warnings or proceed as-is + +2. **User must explicitly approve:** + - Fixing warnings before continuing + - Proceeding with warnings (acknowledging they will remain) + - Do NOT automatically proceed if new warnings appear + +3. **Update baseline if user approves proceeding:** + - If user approves proceeding with new warnings, update baseline + - This prevents re-reporting the same warnings in subsequent batches + ## Compilation Error Resolution ### Common Error Categories @@ -151,8 +200,12 @@ Use the **Test-OpenSSHBuild** MCP tool to read build logs and parse errors **onl ### Build Tools Invocation Policy - Use `Start-OpenSSHBuild.ps1` to run the build for each chunk/batch. -- Only if `Start-OpenSSHBuild.ps1` reports the build failed, invoke `Test-OpenSSHBuild.ps1` to parse errors and warnings from the build log. -- Skip `Test-OpenSSHBuild.ps1` when the build succeeded to avoid unnecessary log parsing. +- **ALWAYS invoke `Test-OpenSSHBuild.ps1` after every build** (success or failure): + - On build failure: Parse errors and warnings to fix issues + - On build success: Parse warnings to compare against baseline +- Compare warning count against established baseline +- If new warnings detected, report to user and request approval before proceeding +- Do NOT skip `Test-OpenSSHBuild.ps1` even when build succeeds - warning checks are mandatory. #### Alternative: Direct MSBuild (Terminal Only) Only use this when running directly in a terminal (not via MCP): diff --git a/.github/instructions/merge/agent-communication-merge.instructions.md b/.github/instructions/merge/agent-communication-merge.instructions.md index 049cf62a09e0..27c49018c943 100644 --- a/.github/instructions/merge/agent-communication-merge.instructions.md +++ b/.github/instructions/merge/agent-communication-merge.instructions.md @@ -44,6 +44,35 @@ Found X compilation errors: I'll resolve these errors now. ``` +#### Success with New Warnings Scenario: +**MUST use this format when build succeeds but new warnings are detected.** + +``` +Build completed successfully. All 14 executables were created. + +However, new compiler warnings have been introduced: + +Baseline: X warnings → Current: Y warnings (ΔZ new warnings) + +New Warnings Detected: + +**Deprecated APIs (2):** +- [auth.c] (Line 145): C4996 - 'strcpy': This function may be unsafe. Consider using strcpy_s instead. +- [sshd.c] (Line 302): C4996 - 'GetVersion': was declared deprecated + +**Type Conversions (1):** +- [channels.c] (Line 89): C4244 - Conversion from 'size_t' to 'int', possible loss of data + +**Analysis:** +These warnings appear to be introduced by upstream changes. The deprecated API warnings may require Windows-specific alternatives, and the type conversion should be reviewed for potential data loss. + +How would you like to proceed? +1. Fix these warnings before continuing +2. Proceed with warnings (will update baseline) + +Please advise. +``` + ### 2. Test-OpenSSHBuild Tool Output **MUST use this format when reporting build error analysis.** @@ -65,12 +94,44 @@ Error Categories: - Build system inconsistencies: X ``` -#### When Build Succeeded: +#### When Build Succeeded with No New Warnings: ``` -No need to analyze build errors - the build completed successfully. +Build analysis complete: + +Compilation Errors: 0 +Warnings: X (no change from baseline) + +No new warnings introduced. Build is clean. +``` + +#### When Build Succeeded with New Warnings: +``` +Build analysis complete: + +Compilation Errors: 0 + +Warnings Comparison: +- Baseline: X warnings +- Current: Y warnings +- New warnings: Z + +New Warnings by Category: + +**Deprecated APIs (2):** +- [auth.c] (Line 145): C4996 - 'strcpy': This function may be unsafe +- [sshd.c] (Line 302): C4996 - 'GetVersion': was declared deprecated + +**Type Conversions (1):** +- [channels.c] (Line 89): C4244 - Conversion from 'size_t' to 'int' + +**Potential Bugs (0)** +**Security-Related (0)** +**Platform-Specific (0)** + +These new warnings require user approval before proceeding. ``` -**Note:** Only invoke Test-OpenSSHBuild when Start-OpenSSHBuild reports failure. +**Note:** ALWAYS invoke Test-OpenSSHBuild after every build to check for warnings, not just on failure. ### 3. Test-OpenSSHFunctionality Tool Output diff --git a/.github/instructions/merge/merge-details.instructions.md b/.github/instructions/merge/merge-details.instructions.md index 3f1df5e4e98b..d69e2cf67b09 100644 --- a/.github/instructions/merge/merge-details.instructions.md +++ b/.github/instructions/merge/merge-details.instructions.md @@ -265,11 +265,20 @@ FUNCTION automated_build_fix(): // Always start with Start-OpenSSHBuild.ps1 build_result = start_openssh_build(Configuration="Release", Architecture="x64") + // ALWAYS invoke Test-OpenSSHBuild.ps1 to check warnings (success or failure) + test_result = test_openssh_build(Configuration="Release", Architecture="x64", LogFile=build_result.log) + IF build_result.success: + // Check for new warnings against baseline + new_warnings = compare_warnings_to_baseline(test_result.warnings, baseline_warnings) + IF new_warnings.count > 0: + categorized_warnings = categorize_warnings(new_warnings) + request_user_approval(categorized_warnings) + // Wait for user decision: fix warnings or proceed RETURN SUCCESS - // Only invoke Test-OpenSSHBuild.ps1 when build failed - errors = test_openssh_build(Configuration="Release", Architecture="x64", LogFile=build_result.log) + // Build failed - parse errors + errors = test_result.errors fixes_applied = [] FOR EACH error IN errors: @@ -303,8 +312,12 @@ FUNCTION determine_fix_strategy(error): ### Build Tools Invocation Policy - Use `Start-OpenSSHBuild.ps1` to run the build for each chunk/batch. -- Only if `Start-OpenSSHBuild.ps1` reports the build failed, invoke `Test-OpenSSHBuild.ps1` to parse errors and warnings from the build log. -- Skip `Test-OpenSSHBuild.ps1` when the build succeeded to avoid unnecessary log parsing. +- **ALWAYS invoke `Test-OpenSSHBuild.ps1` after every build** (success or failure): + - On build failure: Parse errors and warnings to fix issues + - On build success: Parse warnings to compare against baseline +- Compare warning count against established baseline +- If new warnings detected, report to user with categorization and request approval before proceeding +- Do NOT skip `Test-OpenSSHBuild.ps1` even when build succeeds - warning checks are mandatory. ## Testing Automation Framework diff --git a/.github/instructions/merge/merge-process-overview.instructions.md b/.github/instructions/merge/merge-process-overview.instructions.md index 87d273eafea2..a50405864a80 100644 --- a/.github/instructions/merge/merge-process-overview.instructions.md +++ b/.github/instructions/merge/merge-process-overview.instructions.md @@ -153,18 +153,30 @@ The process consists of several interconnected phases: - **MCP Tool Name**: `mcp_openssh-server_Start_OpenSSHBuild` - **Parameters**: `Configuration="Release"`, `Architecture="x64"` - If build fails: - - **Use Test-OpenSSHBuild MCP tool to read the build log and parse errors**: + **ALWAYS check warnings after build (success or failure):** + - **Use Test-OpenSSHBuild MCP tool to parse errors and warnings**: - **MCP Tool Name**: `mcp_openssh-server_Test_OpenSSHBuild` - **Parameters**: `Configuration="Release"`, `Architecture="x64"` - **DO NOT** try to read log files directly with `Get-Content` or locate them manually + + If build failed: - Fix issues based on parsed error output - Rebuild and verify - - **CRITICAL: Before committing, restore paths.targets**: - ```pwsh - git checkout .\contrib\win32\openssh\paths.targets - ``` - - Commit any build fixes separately with descriptive messages (only actual code changes) + + If build succeeded: + - Compare warnings against baseline established in Phase 1 + - If new warnings detected: + - Categorize warnings (deprecated APIs, type conversions, potential bugs, etc.) + - Report to user with warning details and categories + - Request user decision: fix warnings or proceed + - Wait for user approval before continuing + - If user approves proceeding, update baseline to include new warnings + + **CRITICAL: Before committing, restore paths.targets**: + ```pwsh + git checkout .\contrib\win32\openssh\paths.targets + ``` + Commit any build fixes separately with descriptive messages (only actual code changes) 10. **Validate if batch ended with successful CI:** Check the end commit's CI status from Get-CommitGroups output. From c19afda80e1f663baae9a378cfe4af7d8dec47d3 Mon Sep 17 00:00:00 2001 From: User Date: Fri, 6 Mar 2026 09:38:13 -0800 Subject: [PATCH 230/244] add tool to wrap GH commands to check exit code --- .github/instructions/build.instructions.md | 26 +- .../merge/merge-details.instructions.md | 17 +- .../merge-process-overview.instructions.md | 62 ++- .../merge/research.instructions.md | 17 +- .github/instructions/setup.instructions.md | 8 +- .github/tools/Invoke-Git.ps1 | 406 ++++++++++++++++++ .github/tools/Test-OpenSSHFunctionality.ps1 | 14 +- 7 files changed, 495 insertions(+), 55 deletions(-) create mode 100644 .github/tools/Invoke-Git.ps1 diff --git a/.github/instructions/build.instructions.md b/.github/instructions/build.instructions.md index 23724ae0d8f8..fd2a73856920 100644 --- a/.github/instructions/build.instructions.md +++ b/.github/instructions/build.instructions.md @@ -143,8 +143,9 @@ fatal error C1083: Cannot open source file: 'newfile.c' **AI Agent Resolution Process:** 1. **Check Makefile changes:** - ```bash - git diff upstream-pwsh/latestw_all upstream/ -- Makefile.in + ```pwsh + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="Diff", Range="upstream-pwsh/latestw_all..upstream/", Path="Makefile.in" ``` 2. **Identify new/removed source files:** @@ -179,7 +180,8 @@ fatal error C1083: Cannot open source file: 'newfile.c' 5. **Apply appropriate resolution strategy** (see error categories above) and **rebuild** with Start-OpenSSHBuild. 6. **CRITICAL: Before committing, restore paths.targets**: ```pwsh - git checkout .\contrib\win32\openssh\paths.targets + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="Checkout", Target=".\contrib\win32\openssh\paths.targets" ``` 7. **Commit fixes with detailed message** (only actual code changes, not paths.targets). @@ -219,11 +221,14 @@ Only use this when running directly in a terminal (not via MCP): **Before committing any changes:** ```pwsh -# Check if paths.targets was modified by the build -git status .\contrib\win32\openssh\paths.targets - -# If it shows as modified, restore it to a clean state -git checkout .\contrib\win32\openssh\paths.targets +# Check if paths.targets was modified by the build: +# MCP Tool: mcp_openssh-server_Invoke_Git +# Operation="Status" +# Check if paths.targets appears in result.ModifiedFiles + +# If it shows as modified, restore it to a clean state: +# MCP Tool: mcp_openssh-server_Invoke_Git +# Operation="Checkout", Target=".\contrib\win32\openssh\paths.targets" ``` **Why this happens:** @@ -235,10 +240,11 @@ git checkout .\contrib\win32\openssh\paths.targets 1. **ALWAYS restore paths.targets before committing**: ```pwsh # This MUST be done before every commit - git checkout .\contrib\win32\openssh\paths.targets + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="Checkout", Target=".\contrib\win32\openssh\paths.targets" ``` 2. Only commit actual code changes, not build-generated path updates -3. Verify with `git status` that paths.targets is not staged before committing +3. Verify with Invoke-Git `Operation="Status"` that paths.targets is not in `ModifiedFiles` before committing ## Project File Management diff --git a/.github/instructions/merge/merge-details.instructions.md b/.github/instructions/merge/merge-details.instructions.md index d69e2cf67b09..875171e54b27 100644 --- a/.github/instructions/merge/merge-details.instructions.md +++ b/.github/instructions/merge/merge-details.instructions.md @@ -84,16 +84,18 @@ FUNCTION resolve_conflict(file_path, conflict_content): ### Primary References - [Upstream release notes](https://www.openssh.com/releasenotes.html) - Pay special attention when merging new versions - [Previous merge PRs](./research.instructions.md) - Review conflict resolution patterns -- Commit history and messages - Use `git log --oneline upstream/` to understand changes +- Commit history and messages - Use Invoke-Git `Operation="Log"`, `Range="..upstream/"` to understand changes - Local repository file comparison - Use 3-way diff tools ### Analysis Commands ```pwsh -# View commit details for understanding changes -git show +# View commit details for understanding changes: +# MCP Tool: mcp_openssh-server_Invoke_Git +# Operation="Show", CommitHash="" -# Compare files between branches -git diff HEAD upstream/ -- +# Compare files between branches: +# MCP Tool: mcp_openssh-server_Invoke_Git +# Operation="Diff", Range="HEAD..upstream/", Path="" ``` ## Conflict Resolution Strategies @@ -231,8 +233,9 @@ FUNCTION add_source_to_project(project_file, source_file): ### For Each Conflict: 1. **Analyze the change** - ```bash - git show upstream/ -- + ```pwsh + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="Show", CommitHash="upstream/", Path="" ``` 2. **Check previous resolutions** diff --git a/.github/instructions/merge/merge-process-overview.instructions.md b/.github/instructions/merge/merge-process-overview.instructions.md index a50405864a80..4f64bf99b092 100644 --- a/.github/instructions/merge/merge-process-overview.instructions.md +++ b/.github/instructions/merge/merge-process-overview.instructions.md @@ -66,7 +66,8 @@ The process consists of several interconnected phases: 2. **Configure git:** ```pwsh - git config core.editor true + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="Config", Key="core.editor", Value="true" ``` ### Perform Merge with Grouped Commits @@ -117,11 +118,16 @@ The process consists of several interconnected phases: # Example for a single chunk: $chunkStart = $result.StartCommitFull $chunkEnd = $result.EndCommitFull - $commits = git rev-list --reverse "$chunkStart^..$chunkEnd" - foreach ($commit in $commits) { - Write-Host "Cherry-picking commit: $commit" - git cherry-pick $commit + # Get commits in oldest-first order using Invoke-Git MCP tool: + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="Log", Range="$chunkStart^..$chunkEnd", ShasOnly=true + # result.Commits contains [{Hash, Message}] in oldest-first order + + foreach ($commit in $result.Commits) { + # Cherry-pick each commit using Invoke-Git MCP tool: + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="CherryPick", CommitHash=$commit.Hash # If conflicts occur, resolve them before continuing to next commit # (see step 7 below for conflict resolution) @@ -141,8 +147,14 @@ The process consists of several interconnected phases: 8. **Continue cherry-picking after resolution:** ```pwsh # After resolving conflicts for current commit - git add . - git cherry-pick --continue + + # Stage all resolved files using Invoke-Git MCP tool: + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="Add", Path="." + + # Continue cherry-pick using Invoke-Git MCP tool: + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="CherryPickContinue" # Then continue with remaining commits in batch # Repeat process for next batch if needed @@ -174,7 +186,8 @@ The process consists of several interconnected phases: **CRITICAL: Before committing, restore paths.targets**: ```pwsh - git checkout .\contrib\win32\openssh\paths.targets + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="Checkout", Target=".\contrib\win32\openssh\paths.targets" ``` Commit any build fixes separately with descriptive messages (only actual code changes) @@ -197,9 +210,9 @@ The process consists of several interconnected phases: **📖 Detailed Instructions:** [Build Instructions](../build.instructions.md) 7. **Initial build attempt:** - ```pwsh - Start-OpenSSHBuild -Configuration Release -NativeHostArch x64 - ``` + Use the Start-OpenSSHBuild MCP tool: + - **MCP Tool Name**: `mcp_openssh-server_Start_OpenSSHBuild` + - **Parameters**: `Configuration="Release"`, `Architecture="x64"` 8. **Resolve compilation errors (iterative process):** @@ -217,12 +230,14 @@ The process consists of several interconnected phases: 10. **Commit build fixes:** ```pwsh - git commit -m "Fix compilation errors for - - Changes: - - Updated config.h.vs with - - Added Windows equivalent for - - Updated project files for " + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="Commit" + # Message="Fix compilation errors for + # + # Changes: + # - Updated config.h.vs with + # - Added Windows equivalent for + # - Updated project files for " ``` --- @@ -245,10 +260,12 @@ The process consists of several interconnected phases: 13. **Commit any test fixes:** ```pwsh - git commit -m "Fix runtime issues for - - Issues resolved: - - " + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="Commit" + # Message="Fix runtime issues for + # + # Issues resolved: + # - " ``` --- @@ -258,7 +275,8 @@ The process consists of several interconnected phases: ### Creating the Pull Request 14. **Push to fork:** ```pwsh - git push origin merge-v- + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="Push", Remote="origin", Branch="merge-v-" ``` 15. **Create Pull Request:** diff --git a/.github/instructions/merge/research.instructions.md b/.github/instructions/merge/research.instructions.md index 49b6b56a4226..3259ac577037 100644 --- a/.github/instructions/merge/research.instructions.md +++ b/.github/instructions/merge/research.instructions.md @@ -54,16 +54,19 @@ the AI should flag this as requiring Windows event mechanism adaptation. ## Upstream Repository Analysis -**Commands for AI Agent:** +**Commands for AI Agent (use Invoke-Git MCP tool):** ```pwsh -# Get commit history for target version -git log --oneline upstream/ --since="" +# Get commit history for target version: +# MCP Tool: mcp_openssh-server_Invoke_Git +# Operation="Log", Range="..upstream/" -# Analyze specific commits -git show +# Analyze specific commits: +# MCP Tool: mcp_openssh-server_Invoke_Git +# Operation="Show", CommitHash="" -# Compare branches -git diff HEAD upstream/ +# Compare branches: +# MCP Tool: mcp_openssh-server_Invoke_Git +# Operation="Diff", Range="HEAD..upstream/" ``` ## Windows-Specific Knowledge Base diff --git a/.github/instructions/setup.instructions.md b/.github/instructions/setup.instructions.md index 5ec3962af00f..00bb5b88746f 100644 --- a/.github/instructions/setup.instructions.md +++ b/.github/instructions/setup.instructions.md @@ -35,9 +35,9 @@ git remote -v ``` ### Step 4: Initial Fetch -```pwsh -git fetch --all -``` +Use the Invoke-Git MCP tool to fetch from all remotes: +- **MCP Tool**: `mcp_openssh-server_Invoke_Git` +- **Operation**: `Fetch`, **Remote**: `all` ## Branch Strategy @@ -75,7 +75,7 @@ Before proceeding to merge: - [ ] All three remotes configured (origin, upstream, upstream-pwsh) - [ ] Can fetch from all remotes without errors - [ ] Can see upstream target version/branch -- [ ] Working directory is clean (`git status` shows no uncommitted changes) +- [ ] Working directory is clean (use Invoke-Git `Operation="Status"` — `ModifiedFiles` and `ConflictedFiles` should both be empty) ## Troubleshooting diff --git a/.github/tools/Invoke-Git.ps1 b/.github/tools/Invoke-Git.ps1 new file mode 100644 index 000000000000..f091e32b016c --- /dev/null +++ b/.github/tools/Invoke-Git.ps1 @@ -0,0 +1,406 @@ +<# +.SYNOPSIS + Executes a git operation and returns a structured result with exit code. + +.DESCRIPTION + MCP-compatible tool that runs git commands via System.Diagnostics.Process for + reliable exit code capture without interfering with the MCP server's stdio + transport. Async stream reads are started before WaitForExit to prevent deadlocks + when git output exceeds the stream buffer size. + + Returns a structured hashtable with Success, ExitCode, Output, Error, and + operation-specific fields so agents can make programmatic decisions without + text parsing. + +.PARAMETER Operation + The git operation to perform. One of: + CherryPick, CherryPickContinue, CherryPickAbort, + Add, Checkout, CreateBranch, + Commit, Push, Fetch, + Config, Reset, Clean, + Status, Log, Diff, Show + +.PARAMETER CommitHash + A commit SHA or any git ref (branch name, tag, etc.). + Used by: CherryPick, Show. + +.PARAMETER Range + A git range expression (e.g. "abc123^..def456" or "HEAD..upstream/V_10_0_P2"). + Used by: Log (and Log with ShasOnly), Diff. + +.PARAMETER Message + Commit message text. + Used by: Commit. + +.PARAMETER Path + File path or directory to operate on. Defaults to '.'. + Used by: Add, Checkout (file restore), Diff, Show. + +.PARAMETER Remote + Remote name. Defaults to 'origin'. + Used by: Fetch, Push. + +.PARAMETER Branch + Branch name to create or push. + Used by: CreateBranch, Push. + +.PARAMETER StartPoint + Git ref (branch, tag, or commit) to base the new branch on. + Used by: CreateBranch. + +.PARAMETER Target + Branch, tag, commit ref, or file path to check out or reset to. + Used by: Checkout, Reset. + +.PARAMETER Key + Git config key (e.g. "core.editor"). + Used by: Config. + +.PARAMETER Value + Git config value to set. + Used by: Config. + +.PARAMETER Mode + Reset mode: 'soft', 'mixed' (default), or 'hard'. + Used by: Reset. + +.PARAMETER ShasOnly + When specified alongside Operation=Log, uses git rev-list --reverse instead of + git log --oneline. Returns commit SHAs in oldest-first order suitable for building + a cherry-pick loop. result.Commits will contain [{Hash: "", Message: ""}]. + +.OUTPUTS + Hashtable with: + Success [bool] Whether the command exited with code 0 + ExitCode [int] Raw process exit code + Output [string] Stdout from git + Error [string] Stderr from git + Message [string] Human-readable summary + Plus operation-specific fields: + CherryPick (on failure): ConflictedFiles [string[]] + Log / ShasOnly: Commits [{Hash, Message}] + Status: ConflictedFiles [string[]], ModifiedFiles [string[]] + Commit (on success): CommitHash [string] + +.EXAMPLE + # Cherry-pick a single commit + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="CherryPick", CommitHash="abc1234" + +.EXAMPLE + # Get ordered commit SHAs in a batch range for a cherry-pick loop + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="Log", Range="abc123^..def456", ShasOnly=true + +.EXAMPLE + # Stage all changes after conflict resolution (Path defaults to '.') + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="Add" + +.EXAMPLE + # Continue cherry-pick after resolving conflicts + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="CherryPickContinue" + +.EXAMPLE + # Abort an in-progress cherry-pick + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="CherryPickAbort" + +.EXAMPLE + # Restore paths.targets after a build modifies it + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="Checkout", Target=".\contrib\win32\openssh\paths.targets" + +.EXAMPLE + # Create and check out a new merge branch + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="CreateBranch", Branch="merge-v10.0P2-20260306" + +.EXAMPLE + # Commit staged changes + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="Commit", Message="Fix compilation errors for V_10_0_P2" + +.EXAMPLE + # Push a branch to origin + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="Push", Remote="origin", Branch="merge-v10.0P2-20260306" + +.EXAMPLE + # Set a git config value + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="Config", Key="core.editor", Value="true" + +.EXAMPLE + # Show differences between two refs for a specific file + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="Diff", Range="upstream-pwsh/latestw_all..upstream/V_10_0_P2", Path="Makefile.in" + +.EXAMPLE + # Inspect a specific commit + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="Show", CommitHash="abc1234" + +.EXAMPLE + # Check working directory status for conflicts and modifications + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="Status" + +.EXAMPLE + # Hard-reset to HEAD (recovery) + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="Reset", Target="HEAD", Mode="hard" + +.EXAMPLE + # Remove untracked files (recovery) + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="Clean" +#> + +param( + [Parameter(Mandatory)] + [ValidateSet( + 'CherryPick', 'CherryPickContinue', 'CherryPickAbort', + 'Add', 'Checkout', 'CreateBranch', + 'Commit', 'Push', 'Fetch', + 'Config', 'Reset', 'Clean', + 'Status', 'Log', 'Diff', 'Show' + )] + [string]$Operation, + + # CherryPick, Show — accepts any git ref: commit SHA, branch name, tag, etc. + [string]$CommitHash = '', + + # Log (plain or ShasOnly), Diff — git range expression e.g. "abc123^..def456" + [string]$Range = '', + + # Commit — commit message text + [string]$Message = '', + + # Add, Checkout (file restore), Diff, Show — file/directory path + [string]$Path = '.', + + # Fetch, Push — remote name + [string]$Remote = 'origin', + + # CreateBranch, Push — branch name + [string]$Branch = '', + + # CreateBranch — starting ref for the new branch + [string]$StartPoint = '', + + # Checkout, Reset — target ref or file path + [string]$Target = '', + + # Config — key (e.g. "core.editor") + [string]$Key = '', + + # Config — value to set + [string]$Value = '', + + # Reset — reset mode + [ValidateSet('soft', 'mixed', 'hard')] + [string]$Mode = 'mixed', + + # Log — use git rev-list --reverse (SHAs only, oldest first) instead of git log --oneline + [switch]$ShasOnly +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +# --------------------------------------------------------------------------- +# Private helper — runs git via System.Diagnostics.Process. +# +# IMPORTANT: We use ProcessStartInfo rather than Start-Process because +# Start-Process with -RedirectStandardOutput/-RedirectStandardError conflicts +# with the MCP server's stdio transport, causing the process to hang. +# +# Async stream reads MUST be started BEFORE WaitForExit to prevent deadlocks: +# if git output exceeds the internal stream buffer, git blocks waiting for the +# buffer to drain while WaitForExit blocks waiting for git to exit. +# --------------------------------------------------------------------------- +function Invoke-GitCommand { + param([string[]]$Arguments) + + $processInfo = [System.Diagnostics.ProcessStartInfo]::new() + $processInfo.FileName = 'git' + $processInfo.Arguments = ($Arguments | ForEach-Object { + if ($_ -match '\s') { "`"$_`"" } else { $_ } + }) -join ' ' + $processInfo.UseShellExecute = $false + $processInfo.CreateNoWindow = $true + $processInfo.RedirectStandardInput = $true # Prevent git inheriting the MCP stdio pipe + $processInfo.RedirectStandardOutput = $true + $processInfo.RedirectStandardError = $true + + $process = [System.Diagnostics.Process]::new() + $process.StartInfo = $processInfo + $process.Start() | Out-Null + $process.StandardInput.Close() # Immediately close stdin so git never blocks on input + + # Begin async reads BEFORE blocking on WaitForExit + $stdoutTask = $process.StandardOutput.ReadToEndAsync() + $stderrTask = $process.StandardError.ReadToEndAsync() + + $completed = $process.WaitForExit(30000) # 30-second timeout + + if (-not $completed) { + $process.Kill() + return @{ + ExitCode = -1 + Success = $false + Output = '' + Error = "git $($Arguments -join ' ') timed out after 30 seconds" + } + } + + return @{ + ExitCode = $process.ExitCode + Success = ($process.ExitCode -eq 0) + Output = $stdoutTask.GetAwaiter().GetResult().TrimEnd() + Error = $stderrTask.GetAwaiter().GetResult().TrimEnd() + } +} + +# --------------------------------------------------------------------------- +# Operation dispatcher +# --------------------------------------------------------------------------- +$result = switch ($Operation) { + + 'CherryPick' { + if (-not $CommitHash) { throw 'CommitHash is required for CherryPick' } + $r = Invoke-GitCommand -Arguments @('cherry-pick', $CommitHash) + if (-not $r.Success) { + # Enrich failure result with list of conflicted files for agent reporting + $statusResult = Invoke-GitCommand -Arguments @('status', '--porcelain') + $r['ConflictedFiles'] = ($statusResult.Output -split "`n") | + Where-Object { $_ -match '^(UU|AA|DD|AU|UA|DU|UD)\s' } | + ForEach-Object { $_.Substring(3).Trim() } + } + $r + } + + 'CherryPickContinue' { + Invoke-GitCommand -Arguments @('cherry-pick', '--continue') + } + + 'CherryPickAbort' { + Invoke-GitCommand -Arguments @('cherry-pick', '--abort') + } + + 'Add' { + Invoke-GitCommand -Arguments @('add', $Path) + } + + 'Checkout' { + if (-not $Target) { throw 'Target is required for Checkout (branch name, tag, or file path)' } + Invoke-GitCommand -Arguments @('checkout', $Target) + } + + 'CreateBranch' { + if (-not $Branch) { throw 'Branch is required for CreateBranch' } + $args = @('checkout', '-b', $Branch) + if ($StartPoint) { $args += $StartPoint } + Invoke-GitCommand -Arguments $args + } + + 'Commit' { + if (-not $Message) { throw 'Message is required for Commit' } + $r = Invoke-GitCommand -Arguments @('commit', '-m', $Message) + if ($r.Success -and $r.Output -match '\[[\w/]+ ([0-9a-f]{7,})\]') { + $r['CommitHash'] = $Matches[1] + } + $r + } + + 'Push' { + $args = @('push', $Remote) + if ($Branch) { $args += $Branch } + Invoke-GitCommand -Arguments $args + } + + 'Fetch' { + $args = if ($Remote -eq 'all') { @('fetch', '--all') } else { @('fetch', $Remote) } + Invoke-GitCommand -Arguments $args + } + + 'Config' { + if (-not $Key) { throw 'Key is required for Config' } + $args = @('config', $Key) + if ($Value) { $args += $Value } + Invoke-GitCommand -Arguments $args + } + + 'Reset' { + if (-not $Target) { throw 'Target is required for Reset' } + Invoke-GitCommand -Arguments @('reset', "--$Mode", $Target) + } + + 'Clean' { + # -f (force) -d (include untracked directories) — standard recovery clean + Invoke-GitCommand -Arguments @('clean', '-fd') + } + + 'Status' { + $r = Invoke-GitCommand -Arguments @('status', '--porcelain') + $lines = if ($r.Output) { $r.Output -split "`n" } else { @() } + $r['ConflictedFiles'] = $lines | + Where-Object { $_ -match '^(UU|AA|DD|AU|UA|DU|UD)\s' } | + ForEach-Object { $_.Substring(3).Trim() } + $r['ModifiedFiles'] = $lines | + Where-Object { $_ -notmatch '^(UU|AA|DD|AU|UA|DU|UD)\s' -and $_ -match '^\S' } | + ForEach-Object { ($_ -replace '^\S+\s+', '').Trim() } + $r + } + + 'Log' { + if (-not $Range) { throw 'Range is required for Log (e.g. "abc123^..def456" or "HEAD..upstream/V_10_0_P2")' } + if ($ShasOnly) { + # Use rev-list --reverse to get SHAs in oldest-first (cherry-pick) order + $r = Invoke-GitCommand -Arguments @('rev-list', '--reverse', $Range) + $r['Commits'] = if ($r.Success -and $r.Output) { + ($r.Output -split "`n") | + Where-Object { $_ -match '^[0-9a-f]{7,}$' } | + ForEach-Object { @{ Hash = $_; Message = '' } } + } else { @() } + } else { + $logArgs = @('log', '--oneline', $Range) + if ($Path -and $Path -ne '.') { $logArgs += '--'; $logArgs += $Path } + $r = Invoke-GitCommand -Arguments $logArgs + $r['Commits'] = if ($r.Success -and $r.Output) { + ($r.Output -split "`n") | + Where-Object { $_ -match '^[0-9a-f]' } | + ForEach-Object { + if ($_ -match '^([0-9a-f]+)\s+(.+)$') { + @{ Hash = $Matches[1]; Message = $Matches[2] } + } + } + } else { @() } + } + $r + } + + 'Diff' { + $args = @('diff') + if ($Range) { $args += $Range } + if ($Path -and $Path -ne '.') { $args += '--'; $args += $Path } + Invoke-GitCommand -Arguments $args + } + + 'Show' { + $args = @('show') + if ($CommitHash) { $args += $CommitHash } + if ($Path -and $Path -ne '.') { $args += '--'; $args += $Path } + Invoke-GitCommand -Arguments $args + } +} + +$result['Message'] = if ($result.Success) { + "git $Operation completed successfully" +} else { + "git $Operation failed with exit code $($result.ExitCode): $($result.Error)" +} + +return $result diff --git a/.github/tools/Test-OpenSSHFunctionality.ps1 b/.github/tools/Test-OpenSSHFunctionality.ps1 index 9e1b0f7c8907..7a1186dc98a2 100644 --- a/.github/tools/Test-OpenSSHFunctionality.ps1 +++ b/.github/tools/Test-OpenSSHFunctionality.ps1 @@ -307,16 +307,20 @@ try { $process.Start() | Out-Null - # Wait for completion (with timeout) - $completed = $process.WaitForExit(15000) # 15 second timeout + # Begin async reads BEFORE blocking on WaitForExit — prevents deadlock when + # SSH output exceeds the internal stream buffer size (same issue as MCP stdio). + $stdoutTask = $process.StandardOutput.ReadToEndAsync() + $stderrTask = $process.StandardError.ReadToEndAsync() + + $completed = $process.WaitForExit(30000) # 30-second timeout if (-not $completed) { $process.Kill() - throw "SSH connection timed out after 15 seconds" + throw "SSH connection timed out after 30 seconds" } - $stdout = $process.StandardOutput.ReadToEnd() - $stderr = $process.StandardError.ReadToEnd() + $stdout = $stdoutTask.GetAwaiter().GetResult() + $stderr = $stderrTask.GetAwaiter().GetResult() $exitCode = $process.ExitCode # Check result From 8a16638903648b486037009322f613575fbb9f4e Mon Sep 17 00:00:00 2001 From: User Date: Fri, 6 Mar 2026 09:59:33 -0800 Subject: [PATCH 231/244] add tool to get context during complex conflicts --- .github/agents/merge-upstream.agent.md | 19 +- .../merge/merge-details.instructions.md | 38 ++ .github/tools/Get-ConflictContext.ps1 | 489 ++++++++++++++++++ 3 files changed, 544 insertions(+), 2 deletions(-) create mode 100644 .github/tools/Get-ConflictContext.ps1 diff --git a/.github/agents/merge-upstream.agent.md b/.github/agents/merge-upstream.agent.md index bb67a39cefbb..559261dfac96 100644 --- a/.github/agents/merge-upstream.agent.md +++ b/.github/agents/merge-upstream.agent.md @@ -2,7 +2,7 @@ name: merge-upstream description: Assist with merging upstream OpenSSH commits into the PowerShell fork. tools: - ['vscode', 'execute', 'read', 'agent', 'edit', 'search', 'web', 'openssh-server/*', 'todo'] + ['vscode', 'execute', 'read', 'edit', 'search', 'web', 'agent', 'openssh-server/*', 'todo'] --- # OpenSSH Upstream Merge Agent @@ -53,7 +53,22 @@ This agent assists with merging upstream OpenSSH commits into the PowerShell for - `NoCleanup` (boolean, optional): Skip cleanup for debugging (default: false) - **If tool unavailable**: ERROR - This tool is required for the merge workflow -4. **Git** - Version control operations +4. **Get-ConflictContext MCP Tool** - Three-way conflict context for high-complexity conflicts + - **MCP Tool Name**: `mcp_openssh-server_Get_ConflictContext` + - **When to use**: ONLY when `assess_conflict_complexity()` returns `HIGH_COMPLEXITY` + - **Parameters**: + - `FilePath` (string, required): Path to the conflicted file relative to the repository root + - `CommitHash` (string, required): The upstream commit SHA being cherry-picked that caused the conflict + - `ContextLines` (integer, optional): Lines of context above/below each hunk match (default: 40) + - `MaxTotalLines` (integer, optional): Maximum total lines across all three versions and all hunks (default: 150 — ~50 per version). Increase if broader context is needed. + - **What it returns**: For each hunk in the upstream diff — excerpts from three versions: + - `UpstreamBefore`: The file as it existed in upstream *before* this commit + - `UpstreamAfter`: The file in upstream *after* this commit + - `OurFork`: The corresponding region in our fork (located by content-anchor matching, not line numbers) + - **Budget**: `max(10, floor(MaxTotalLines / 3 / hunkCount))` lines per version per hunk; a warning is added to `Message` if the 10-line minimum floor is applied + - **If tool unavailable**: Fall back to reading the conflicted file directly and using `Invoke_Git Operation="Show"` and `Operation="Diff"` to gather context manually + +5. **Git** - Version control operations - Cherry-pick: `git cherry-pick start_commit^..end_commit` (inclusive) - Status: `git status` - Remotes: `origin`, `upstream-pwsh`, `upstream` diff --git a/.github/instructions/merge/merge-details.instructions.md b/.github/instructions/merge/merge-details.instructions.md index 875171e54b27..aaeab4fc3bb2 100644 --- a/.github/instructions/merge/merge-details.instructions.md +++ b/.github/instructions/merge/merge-details.instructions.md @@ -418,6 +418,44 @@ FUNCTION assess_conflict_complexity(conflicts): RETURN "LOW_COMPLEXITY" ``` +### Using Get-ConflictContext for High-Complexity Conflicts + +When `assess_conflict_complexity()` returns `HIGH_COMPLEXITY`, invoke the `Get-ConflictContext` MCP tool **before** attempting to edit the file. It provides three-way context anchored to the actual changed regions, accounting for the fact that our fork's line numbers differ from upstream. + +```pseudocode +FUNCTION resolve_conflict(file_path, conflict_content, cherry_pick_commit): + complexity = assess_conflict_complexity([{file: file_path, content: conflict_content}]) + + IF complexity == "HIGH_COMPLEXITY": + // Fetch three-way context before editing + // MCP Tool: mcp_openssh-server_Get_ConflictContext + // FilePath=file_path, CommitHash=cherry_pick_commit + // + // If the default MaxTotalLines=150 is insufficient (e.g., many hunks or + // a large function), re-invoke with a higher value such as MaxTotalLines=300. + context = get_conflict_context(file_path, cherry_pick_commit) + + FOR EACH hunk IN context.Hunks: + // Use all three excerpts to understand: + // hunk.UpstreamBefore — what the upstream code looked like before the commit + // hunk.UpstreamAfter — what the upstream commit changed it to + // hunk.OurFork — what our fork has in the corresponding region + // (Note field explains how the region was located) + determine_resolution_strategy(hunk) + + // Check Message for budget warnings and increase MaxTotalLines if needed + IF context.Message contains "minimum floor": + re_invoke_with_larger_budget(file_path, cherry_pick_commit) + + RETURN apply_resolution_strategy(file_path, conflict_content) +``` + +**Key behaviours of the tool:** +- **Binary files**: Returns `IsBinary=true` and no excerpts — resolve manually. +- **Unavailable versions**: A version returns `Lines=null` with a `Note` explaining why (e.g. file newly added by this commit). +- **Fork region location**: Uses sliding-window content matching against the diff's unchanged context lines. Falls back to the function name from the `@@` hunk header if the anchor score is too low. The `Note` field on each `OurFork` excerpt describes which strategy was used. +- **Budget warning**: If `MaxTotalLines` is too small to give each hunk 10 lines per version, a warning appears in `Message` — increase `MaxTotalLines` and re-invoke. + ## Anti-Patterns to Avoid ### ❌ Don't Remove Upstream Code diff --git a/.github/tools/Get-ConflictContext.ps1 b/.github/tools/Get-ConflictContext.ps1 new file mode 100644 index 000000000000..e83d6a4c4fd3 --- /dev/null +++ b/.github/tools/Get-ConflictContext.ps1 @@ -0,0 +1,489 @@ +<# +.SYNOPSIS + Retrieves three-way context for a conflicted file to aid complex conflict resolution. + +.DESCRIPTION + MCP-compatible tool that fetches three versions of a file involved in a cherry-pick + conflict — the upstream file before the commit, the upstream file after the commit, + and our fork's version (via MERGE_HEAD) — and extracts focused, line-numbered excerpts + centered on each changed hunk. + + For each hunk in the upstream diff, the tool locates the corresponding region in our + fork using two-tier content matching: + Tier 1: Sliding-window overlap score against unchanged context lines from the diff. + Tier 2: Fallback to searching for the function name from the @@ hunk header. + + This handles line-number divergence between upstream and our fork by finding the + region by content rather than by position. + + Use this tool ONLY when conflict complexity assessment returns HIGH_COMPLEXITY. + +.PARAMETER FilePath + Path to the conflicted file, relative to the repository root. + +.PARAMETER CommitHash + The upstream commit SHA being cherry-picked that caused the conflict. + +.PARAMETER ContextLines + Number of lines of context above and below each hunk match to include in excerpts. + Default: 40 + +.PARAMETER MaxTotalLines + Maximum total lines returned across all three versions combined (across all hunks). + Budget per version per hunk = max(10, floor(MaxTotalLines / 3 / hunkCount)). + The minimum floor of 10 lines per version per hunk is always enforced. + If the floor overrides the calculated budget, a warning is included in Message. + Default: 150 (approximately 50 lines per version) + +.OUTPUTS + Hashtable with: + Success [bool] Whether the operation completed without errors + Message [string] Human-readable summary (includes warnings about budget) + CommitMessage [string] The commit message of CommitHash + UpstreamDiff [string] Raw unified diff for the file from this commit + HunkCount [int] Number of hunks found in the upstream diff + IsBinary [bool] True if the file is binary (no excerpts returned) + Hunks [array] One entry per hunk: + HunkIndex [int] 1-based hunk number + HunkHeader [string] The @@ header line + FunctionName [string] Function name extracted from @@ header (may be empty) + UpstreamBefore [object] { Lines, StartLine, EndLine, Note } + UpstreamAfter [object] { Lines, StartLine, EndLine, Note } + OurFork [object] { Lines, StartLine, EndLine, Note } + + Each excerpt object: + Lines [string[]] The extracted lines (null if version unavailable) + StartLine [int] 1-based line number of first line in the excerpt + EndLine [int] 1-based line number of last line in the excerpt + Note [string] Explanation if unavailable or how region was located + +.EXAMPLE + # Get conflict context for a high-complexity conflict + # MCP Tool: mcp_openssh-server_Get_ConflictContext + # FilePath="auth.c", CommitHash="abc1234" + +.EXAMPLE + # Get context with increased budget for a file with many hunks + # MCP Tool: mcp_openssh-server_Get_ConflictContext + # FilePath="channels.c", CommitHash="abc1234", MaxTotalLines=300 +#> + +param( + [Parameter(Mandatory)] + [string]$FilePath, + + [Parameter(Mandatory)] + [string]$CommitHash, + + [int]$ContextLines = 40, + + [int]$MaxTotalLines = 150 +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +# ── Git process helper (same pattern as Invoke-Git.ps1) ────────────────────── + +function Invoke-GitCommand { + param([string[]]$Arguments) + + $processInfo = [System.Diagnostics.ProcessStartInfo]::new() + $processInfo.FileName = 'git' + $processInfo.Arguments = ($Arguments | ForEach-Object { + if ($_ -match '\s') { "`"$_`"" } else { $_ } + }) -join ' ' + $processInfo.UseShellExecute = $false + $processInfo.CreateNoWindow = $true + $processInfo.RedirectStandardInput = $true + $processInfo.RedirectStandardOutput = $true + $processInfo.RedirectStandardError = $true + + $process = [System.Diagnostics.Process]::new() + $process.StartInfo = $processInfo + $process.Start() | Out-Null + $process.StandardInput.Close() + + $stdoutTask = $process.StandardOutput.ReadToEndAsync() + $stderrTask = $process.StandardError.ReadToEndAsync() + + $completed = $process.WaitForExit(30000) + + if (-not $completed) { + $process.Kill() + return @{ + ExitCode = -1 + Success = $false + Output = '' + Error = "git $($Arguments -join ' ') timed out after 30 seconds" + } + } + + return @{ + ExitCode = $process.ExitCode + Success = ($process.ExitCode -eq 0) + Output = $stdoutTask.GetAwaiter().GetResult() + Error = $stderrTask.GetAwaiter().GetResult().TrimEnd() + } +} + +# ── Helper: fetch a file at a git ref ──────────────────────────────────────── + +function Get-FileAtRef { + param([string]$Ref, [string]$File) + + $r = Invoke-GitCommand -Arguments @('show', "${Ref}:${File}") + if (-not $r.Success) { + return @{ Lines = $null; Note = "File not available at ref '${Ref}': $($r.Error.Trim())" } + } + $lines = $r.Output -split "`n" + # Remove trailing empty element produced by split on a newline-terminated string + if ($lines.Count -gt 0 -and $lines[-1] -eq '') { + $lines = $lines[0..($lines.Count - 2)] + } + return @{ Lines = $lines; Note = $null } +} + +# ── Helper: slice a line-numbered excerpt centred on a 1-based line ────────── + +function Get-Excerpt { + param( + [string[]]$Lines, + [int]$CenterLine, # 1-based + [int]$Budget # max lines to return + ) + + if (-not $Lines) { return $null } + $half = [Math]::Floor($Budget / 2) + $start = [Math]::Max(0, $CenterLine - 1 - $half) + $end = [Math]::Min($Lines.Count - 1, $CenterLine - 1 + $half) + + # Expand toward the opposite edge if we hit a boundary before using the full budget + if (($end - $start + 1) -lt $Budget) { + if ($start -eq 0) { + $end = [Math]::Min($Lines.Count - 1, $Budget - 1) + } else { + $start = [Math]::Max(0, $end - $Budget + 1) + } + } + + return @{ + Lines = $Lines[$start..$end] + StartLine = $start + 1 + EndLine = $end + 1 + Note = $null + } +} + +# ── Helper: sliding-window content-anchor match ─────────────────────────────── +# Returns the 1-based centre line in $FileLines that best overlaps $AnchorLines. + +function Find-AnchorMatch { + param( + [string[]]$FileLines, + [string[]]$AnchorLines, + [int]$ExpectedCenter # 1-based fallback if no match found + ) + + $anchorSet = @{} + foreach ($a in $AnchorLines) { + $t = $a.Trim() + if ($t) { $anchorSet[$t] = $true } + } + + $windowSize = [Math]::Max($AnchorLines.Count, 5) + $bestScore = -1 + $bestCenter = $ExpectedCenter + + for ($i = 0; $i -le ($FileLines.Count - $windowSize); $i++) { + $score = 0 + for ($j = $i; $j -lt ($i + $windowSize) -and $j -lt $FileLines.Count; $j++) { + $trimmed = $FileLines[$j].Trim() + if ($trimmed -and $anchorSet.ContainsKey($trimmed)) { $score++ } + } + if ($score -gt $bestScore) { + $bestScore = $score + $bestCenter = $i + [Math]::Floor($windowSize / 2) + 1 # convert to 1-based + } + } + + return @{ + Center = $bestCenter + Score = $bestScore + MaxPossible = $anchorSet.Count + } +} + +# ── Helper: find the first line in $FileLines containing $FunctionName ─────── + +function Find-FunctionMatch { + param( + [string[]]$FileLines, + [string]$FunctionName + ) + + $pattern = "\b$([regex]::Escape($FunctionName))\b" + for ($i = 0; $i -lt $FileLines.Count; $i++) { + if ($FileLines[$i] -match $pattern) { + return $i + 1 # 1-based + } + } + return -1 +} + +# ── Helper: parse all @@ hunks from unified diff text ──────────────────────── + +function Parse-DiffHunks { + param([string]$DiffText) + + $hunks = @() + $lines = $DiffText -split "`n" + $currentHunk = $null + $contextAccum = @() + $inHunk = $false + + foreach ($line in $lines) { + if ($line -match '^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@(.*)$') { + + # Flush the previous hunk before starting a new one + if ($null -ne $currentHunk) { + $currentHunk['ContextLines'] = $contextAccum + $hunks += $currentHunk + } + + $upstreamStart = [int]$Matches[1] + $upstreamCount = if ($Matches[2]) { [int]$Matches[2] } else { 1 } + $afterStart = [int]$Matches[3] + $afterCount = if ($Matches[4]) { [int]$Matches[4] } else { 1 } + $funcTrailer = $Matches[5].Trim() + + # Extract function name from the optional trailer after @@ + $funcName = '' + if ($funcTrailer -match '(\w[\w_]*)\s*\(') { + $funcName = $Matches[1] + } elseif ($funcTrailer -match '(\w[\w_]+)') { + $funcName = $Matches[1] + } + + $currentHunk = @{ + Header = $line.Trim() + FunctionName = $funcName + UpstreamStart = $upstreamStart + UpstreamCount = $upstreamCount + AfterStart = $afterStart + AfterCount = $afterCount + } + $contextAccum = @() + $inHunk = $true + + } elseif ($inHunk) { + # Collect unchanged context lines (lines starting with a space) + if ($line -match '^ (.*)$') { + $contextAccum += $Matches[1] + } + } + } + + # Flush the last hunk + if ($null -ne $currentHunk) { + $currentHunk['ContextLines'] = $contextAccum + $hunks += $currentHunk + } + + return $hunks +} + +# ── Main ────────────────────────────────────────────────────────────────────── + +$warnings = @() + +# 1. Get the upstream diff for this file at this commit +$diffResult = Invoke-GitCommand -Arguments @('diff', "${CommitHash}^..${CommitHash}", '--', $FilePath) +if (-not $diffResult.Success -and $diffResult.ExitCode -ne 1) { + return @{ + Success = $false + Message = "Failed to get diff for '${FilePath}' at commit ${CommitHash}: $($diffResult.Error)" + CommitMessage = '' + UpstreamDiff = '' + HunkCount = 0 + IsBinary = $false + Hunks = @() + } +} + +$upstreamDiff = $diffResult.Output + +# 2. Binary file — return early with a note, no excerpts +if ($upstreamDiff -match 'Binary files .* differ') { + return @{ + Success = $true + Message = "Binary file — context not available for '${FilePath}'." + CommitMessage = '' + UpstreamDiff = $upstreamDiff + HunkCount = 0 + IsBinary = $true + Hunks = @() + } +} + +# 3. File not touched by this commit +if ([string]::IsNullOrWhiteSpace($upstreamDiff)) { + return @{ + Success = $true + Message = "File '${FilePath}' was not modified by commit ${CommitHash}." + CommitMessage = '' + UpstreamDiff = '' + HunkCount = 0 + IsBinary = $false + Hunks = @() + } +} + +# 4. Get the commit message +$commitMsgResult = Invoke-GitCommand -Arguments @('log', '-1', '--pretty=format:%s%n%n%b', $CommitHash) +$commitMessage = if ($commitMsgResult.Success) { $commitMsgResult.Output.Trim() } else { '' } + +# 5. Fetch the three file versions +# MERGE_HEAD is populated by git during an in-progress cherry-pick conflict +# and points to the commit being cherry-picked (our fork's working state before merge) +$upstreamBefore = Get-FileAtRef -Ref "${CommitHash}^" -File $FilePath +$upstreamAfter = Get-FileAtRef -Ref "${CommitHash}" -File $FilePath +$ourFork = Get-FileAtRef -Ref 'MERGE_HEAD' -File $FilePath + +# 6. Parse hunks from the diff +$hunks = Parse-DiffHunks -DiffText $upstreamDiff +$hunkCount = $hunks.Count + +if ($hunkCount -eq 0) { + return @{ + Success = $true + Message = "No hunks found in diff for '${FilePath}' at commit ${CommitHash}." + CommitMessage = $commitMessage + UpstreamDiff = $upstreamDiff + HunkCount = 0 + IsBinary = $false + Hunks = @() + } +} + +# 7. Compute per-hunk line budget +# MaxTotalLines is split evenly across 3 versions and all hunks. +# Minimum floor of 10 lines per version per hunk is always enforced. +$MIN_LINES_PER_HUNK = 10 +$budgetPerHunk = [Math]::Floor($MaxTotalLines / 3 / $hunkCount) + +if ($budgetPerHunk -lt $MIN_LINES_PER_HUNK) { + $warnings += "MaxTotalLines=${MaxTotalLines} is too small for ${hunkCount} hunk(s) across 3 versions; " + + "minimum floor of ${MIN_LINES_PER_HUNK} lines applied — consider increasing MaxTotalLines." + $budgetPerHunk = $MIN_LINES_PER_HUNK +} + +# Never exceed the caller's ContextLines preference +$budgetPerHunk = [Math]::Min($budgetPerHunk, $ContextLines) + +# 8. Build per-hunk results +$ANCHOR_SCORE_THRESHOLD = 2 +$resultHunks = @() + +for ($h = 0; $h -lt $hunkCount; $h++) { + + $hunk = $hunks[$h] + $anchorLines = $hunk['ContextLines'] + + # ── upstream-before: line numbers are known from the diff header ────────── + $uBefore = @{ Lines = $null; StartLine = $null; EndLine = $null; Note = $upstreamBefore.Note } + if ($upstreamBefore.Lines) { + $center = $hunk['UpstreamStart'] + [Math]::Floor($hunk['UpstreamCount'] / 2) + $excerpt = Get-Excerpt -Lines $upstreamBefore.Lines -CenterLine $center -Budget $budgetPerHunk + if ($excerpt) { $uBefore = $excerpt } + } + + # ── upstream-after: line numbers are known from the diff header ─────────── + $uAfter = @{ Lines = $null; StartLine = $null; EndLine = $null; Note = $upstreamAfter.Note } + if ($upstreamAfter.Lines) { + $center = $hunk['AfterStart'] + [Math]::Floor($hunk['AfterCount'] / 2) + $excerpt = Get-Excerpt -Lines $upstreamAfter.Lines -CenterLine $center -Budget $budgetPerHunk + if ($excerpt) { $uAfter = $excerpt } + } + + # ── our fork: line numbers diverge — locate by content matching ────────── + $forkExcerpt = @{ Lines = $null; StartLine = $null; EndLine = $null; Note = $ourFork.Note } + + if ($ourFork.Lines) { + $forkCenter = $hunk['UpstreamStart'] # fallback: use upstream line number as estimate + $matchNote = $null + + if ($anchorLines.Count -ge 2) { + # Tier 1: sliding-window content match against unchanged context lines + $match = Find-AnchorMatch -FileLines $ourFork.Lines ` + -AnchorLines $anchorLines ` + -ExpectedCenter $forkCenter + + if ($match.Score -ge $ANCHOR_SCORE_THRESHOLD) { + $forkCenter = $match.Center + $matchNote = "Located via content-anchor match (score $($match.Score)/$($match.MaxPossible))." + } elseif ($hunk['FunctionName']) { + # Tier 2: anchor score too low — fall back to function name search + $fnLine = Find-FunctionMatch -FileLines $ourFork.Lines -FunctionName $hunk['FunctionName'] + if ($fnLine -gt 0) { + $forkCenter = $fnLine + $matchNote = "Located via function-name fallback ('$($hunk['FunctionName'])')." + } else { + $matchNote = "Could not locate region — anchor score too low and function " + + "'$($hunk['FunctionName'])' not found. Using upstream line number as estimate." + } + } else { + $matchNote = "Could not locate region — anchor score too low and no function name " + + "available. Using upstream line number as estimate." + } + + } elseif ($hunk['FunctionName']) { + # Too few anchor lines for sliding window — go straight to function-name search + $fnLine = Find-FunctionMatch -FileLines $ourFork.Lines -FunctionName $hunk['FunctionName'] + if ($fnLine -gt 0) { + $forkCenter = $fnLine + $matchNote = "Located via function-name fallback ('$($hunk['FunctionName'])') — " + + "insufficient anchor lines for content match." + } else { + $matchNote = "Insufficient anchor lines and function '$($hunk['FunctionName'])' not found. " + + "Using upstream line number as estimate." + } + } else { + $matchNote = "Insufficient anchor lines and no function name available. " + + "Using upstream line number as estimate." + } + + $excerpt = Get-Excerpt -Lines $ourFork.Lines -CenterLine $forkCenter -Budget $budgetPerHunk + if ($excerpt) { + $excerpt['Note'] = $matchNote + $forkExcerpt = $excerpt + } + } + + $resultHunks += @{ + HunkIndex = $h + 1 + HunkHeader = $hunk['Header'] + FunctionName = $hunk['FunctionName'] + UpstreamBefore = $uBefore + UpstreamAfter = $uAfter + OurFork = $forkExcerpt + } +} + +# 9. Return final result +$message = if ($warnings.Count -gt 0) { + "Context retrieved for ${hunkCount} hunk(s) in '${FilePath}' (commit ${CommitHash}). " + + "Warnings: $($warnings -join ' | ')" +} else { + "Context retrieved for ${hunkCount} hunk(s) in '${FilePath}' (commit ${CommitHash})." +} + +return @{ + Success = $true + Message = $message + CommitMessage = $commitMessage + UpstreamDiff = $upstreamDiff + HunkCount = $hunkCount + IsBinary = $false + Hunks = $resultHunks +} From 5f24965d20ff8e4bd89fff3fd744ca2c6390ecda Mon Sep 17 00:00:00 2001 From: Tess Gauthier Date: Tue, 17 Mar 2026 16:57:03 -0400 Subject: [PATCH 232/244] add scratch branch instructions --- .github/agents/merge-upstream.agent.md | 206 ++++++++++++++---- .../agent-communication-merge.instructions.md | 29 +++ .../merge/merge-details.instructions.md | 38 +++- .../merge-process-overview.instructions.md | 121 ++++++---- .github/prompt/merge.prompt.md | 2 +- .github/tools/Get-ConflictContext.ps1 | 17 +- .github/tools/Invoke-Git.ps1 | 47 +++- .github/tools/Replay-MergeResolutions.ps1 | 201 +++++++++++++++++ .github/tools/Save-MergeResolution.ps1 | 160 ++++++++++++++ 9 files changed, 716 insertions(+), 105 deletions(-) create mode 100644 .github/tools/Replay-MergeResolutions.ps1 create mode 100644 .github/tools/Save-MergeResolution.ps1 diff --git a/.github/agents/merge-upstream.agent.md b/.github/agents/merge-upstream.agent.md index 559261dfac96..5bfcdd7deea4 100644 --- a/.github/agents/merge-upstream.agent.md +++ b/.github/agents/merge-upstream.agent.md @@ -16,7 +16,7 @@ This agent assists with merging upstream OpenSSH commits into the PowerShell for ### Core Functions - **Environment verification and setup** - **Commit group analysis** using Get-CommitGroups MCP tool -- **Incremental cherry-picking** with conflict resolution +- **Two-phase merge**: scratch branch (incremental merge + resolution recording) then real branch (single merge + replay) - **Windows-specific build system updates** - **Compilation and testing** - **Documentation and PR preparation** @@ -68,8 +68,30 @@ This agent assists with merging upstream OpenSSH commits into the PowerShell for - **Budget**: `max(10, floor(MaxTotalLines / 3 / hunkCount))` lines per version per hunk; a warning is added to `Message` if the 10-line minimum floor is applied - **If tool unavailable**: Fall back to reading the conflicted file directly and using `Invoke_Git Operation="Show"` and `Operation="Diff"` to gather context manually -5. **Git** - Version control operations - - Cherry-pick: `git cherry-pick start_commit^..end_commit` (inclusive) +5. **Save-MergeResolution MCP Tool** - Records conflict resolution decisions + - **MCP Tool Name**: `mcp_openssh-server_Save_MergeResolution` + - **When to use**: After resolving each conflicted file during the scratch-branch phase + - **Parameters**: + - `FilePath` (string, required): Resolved file path relative to repo root + - `Strategy` (string, required): One of `accept_upstream`, `ifdef_windows`, `ifndef_windows`, `combine`, `manual` + - `Rationale` (string, required): Why this strategy was chosen + - `BatchNumber` (int, required): Current batch number + - `UpstreamCommits` (string, optional): Comma-separated SHAs of upstream commits touching this file + - `MergeTarget` (string, optional): Final upstream ref (only needed on first call to initialise the log) + - **If tool unavailable**: Agent should manually track resolutions in session memory + +6. **Replay-MergeResolutions MCP Tool** - Replays saved resolutions onto merge conflicts + - **MCP Tool Name**: `mcp_openssh-server_Replay_MergeResolutions` + - **When to use**: During the real-branch phase after `git merge` produces conflicts + - **Parameters**: + - `DryRun` (boolean, optional): Preview without modifying files (default: false) + - **Returns**: `ResolvedFiles[]`, `UnmatchedFiles[]`, `FailedFiles[]` + - **If tool unavailable**: Agent should manually re-resolve using strategies from session memory + +7. **Git** - Version control operations + - Merge: `Invoke-Git Operation="Merge" CommitHash=""` (uses `--no-ff`) + - MergeContinue / MergeAbort for conflict flow + - Cherry-pick operations remain available for other use cases - Status: `git status` - Remotes: `origin`, `upstream-pwsh`, `upstream` @@ -132,20 +154,36 @@ This agent assists with merging upstream OpenSSH commits into the PowerShell for - This baseline will be used to detect new warnings introduced during merge - Store baseline for comparison after each build -4. **Create merge branch:** +4. **Enable git rerere** (records conflict resolutions for automatic replay): + ```pwsh + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="Config", Key="rerere.enabled", Value="true" + ``` + +5. **Create merge branch and scratch branch:** ```pwsh - git checkout -b merge-v- - # Example: git checkout -b merge-v10.0P2-20260109 + # Create the real merge branch (will receive the final single merge) + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="CreateBranch", Branch="merge-v-" + # Example: Branch="merge-v10.0P2-20260109" + + # Create the scratch branch from the same point (for incremental merges) + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="CreateBranch", Branch="scratch-merge-v-" ``` **Success Criteria:** - Prerequisite tool reports all checks passed - Baseline warning count established and documented -- Merge branch created -- Ready to begin Phase 2 (cherry-picking first batch) +- `rerere.enabled` set to `true` +- Both merge branch and scratch branch created +- Currently on the scratch branch +- Ready to begin Phase 2 (scratch-branch incremental merge) -### Phase 2: Incremental Merge -**Objective:** Cherry-pick commits in a single batch ending with a CI run +### Phase 2: Scratch Branch — Incremental Merge +**Objective:** Merge commits in batches on the scratch branch, recording every conflict resolution for later replay. + +The scratch branch uses `git merge` (not cherry-pick) at each batch boundary. This ensures conflict markers match the final single merge, maximising `git rerere` hit rate. **Steps:** 1. **Get first commit batch** using Get-CommitGroups MCP tool: @@ -169,24 +207,35 @@ This agent assists with merging upstream OpenSSH commits into the PowerShell for } ``` -2. **Display batch information for verification:** +2. **Display batch information** for verification. + +3. **Merge the batch endpoint:** ```pwsh - Write-Host "Processing Batch $($result.ChunkNumber)" -ForegroundColor Cyan - Write-Host "Commit Range: $($result.StartCommit)..$($result.EndCommit)" -ForegroundColor Gray - Write-Host "Start: [$($result.StartCommit)] $($result.StartMessage)" -ForegroundColor White - Write-Host "End: [$($result.EndCommit)] $($result.EndMessage)" -ForegroundColor Green - Write-Host "Total commits: $($result.CommitCount)" -ForegroundColor Yellow + # Merge all commits up to the batch endpoint + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="Merge", CommitHash=$result.EndCommitFull ``` - -3. **Cherry-pick the batch:** + This brings in all commits from the previous merge point through `EndCommitFull` in a single merge. The `--no-ff` flag ensures a merge commit is always created. + +4. **If conflicts occur, resolve and record each one:** + - For each conflicted file reported in the merge result's `ConflictedFiles`: + a. Resolve the conflict following Windows preservation patterns + b. **Record the resolution** using Save-MergeResolution: + ```pwsh + # MCP Tool: mcp_openssh-server_Save_MergeResolution + # FilePath="", Strategy="", Rationale="", + # BatchNumber=, UpstreamCommits="" + # (On first call, also set MergeTarget="upstream/") + ``` + c. Stage the resolved file: `Invoke-Git Operation="Add" Path=""` + - `git rerere` will also automatically record the resolution. + +5. **Complete the merge:** ```pwsh - git cherry-pick $($result.StartCommitFull)^..$($result.EndCommitFull) + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="MergeContinue" ``` -4. **Resolve conflicts** following Windows preservation patterns (if conflicts occur) -5. **Stage and continue:** `git add .` then `git cherry-pick --continue` -6. **Repeat steps 4-5** until all commits in batch are applied - **Conflict Resolution Patterns:** - **Windows-specific code:** Preserve with `#ifdef WINDOWS` - **Removed featureand Validation @@ -279,38 +328,98 @@ This agent assists with merging upstream OpenSSH commits into the PowerShell for - Summary provided with all required information - User approval received to proceed -### Phase 5: Iteration -**Objective:** Process remaining commit groups until merge is complete +### Phase 5: Scratch Branch Iteration +**Objective:** Process remaining commit batches on the scratch branch until all upstream commits are merged. **Steps:** 1. **Return to Phase 2** with `-StartCommit` set to previous batch's end commit and `-EndCommit` set to target end commit 2. **Repeat Phases 2-4** for each batch: - Get next batch with Get-CommitGroups (passing both StartCommit and EndCommit) - - Cherry-pick commits + - Merge batch endpoint (`Invoke-Git Merge`) + - Resolve conflicts and record with Save-MergeResolution - Build (mandatory) - Validate (if batch ends with successful CI) - Summarize and get approval 3. **Continue** until the target end commit is reached (or HEAD if no end commit was specified) -4. **Perform final comprehensive validation:** +4. **Final scratch-branch validation:** - **MCP Tool Name**: `mcp_openssh-server_Test_OpenSSHFunctionality` - **Parameters**: (use defaults for Release/x64) **Success Criteria:** -- All commit batches processed +- All commit batches processed on scratch branch - Build remains stable after each batch - All successful CI checkpoints validated -- Final validation passes -1. Use Get-CommitGroups MCP tool with `-StartCommit` parameter set to previous batch end commit -2. Repeat Phase 2-4 for next batch -3. Continue until all target commits merged -4. Perform final comprehensive test +- Resolution log (`.git/merge-resolution-log.json`) contains all conflict resolutions +- Ready to proceed to real-branch single merge + +### Phase 6: Real Branch — Single Merge +**Objective:** Produce clean history on the real merge branch with a single merge commit preserving all upstream SHAs. + +**Steps:** +1. **Switch to the real merge branch:** + ```pwsh + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="Checkout", Target="merge-v-" + ``` + +2. **Perform a single merge** of the final upstream target: + ```pwsh + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="Merge", CommitHash="" + ``` + This creates one merge commit. `git rerere` will automatically apply resolutions it recorded during the scratch phase. + +3. **Replay remaining resolutions** from the log: + ```pwsh + # MCP Tool: mcp_openssh-server_Replay_MergeResolutions + # (no parameters needed — reads from .git/merge-resolution-log.json) + ``` + The tool reports: + - `ResolvedFiles`: Files auto-resolved from the log + - `UnmatchedFiles`: Conflicted files not in the log (resolve manually) + - `FailedFiles`: Files where replay failed (resolve manually) + +4. **Resolve any remaining unmatched conflicts:** + - Use the resolution log's strategies and rationale as guidance + - These are typically files where the merge produced different conflict regions than the scratch-branch merge + +5. **Complete the merge:** + ```pwsh + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="MergeContinue" + ``` + +6. **Apply build fixes** as separate commits after the merge commit: + - Review build fixes from the scratch branch + - Apply the same fixes (config.h.vs updates, .vcxproj changes, etc.) + - Commit with descriptive messages + - **CRITICAL: Restore paths.targets before committing:** + ```pwsh + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="Checkout", Target=".\contrib\win32\openssh\paths.targets" + ``` + +7. **Build and validate on the real branch:** + - Build: `mcp_openssh-server_Start_OpenSSHBuild` (Release/x64) + - Check warnings: `mcp_openssh-server_Test_OpenSSHBuild` + - Validate: `mcp_openssh-server_Test_OpenSSHFunctionality` + +8. **Clean up scratch branch:** + ```pwsh + # The scratch branch is no longer needed + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="Checkout", Target="merge-v-" + # Then delete scratch: git branch -D scratch-merge-v- + ``` **Success Criteria:** -- All commit groups processed -- Build remains stable after each batch -- Tests pass after each batch +- Real branch has exactly one merge commit (plus build fix commits) +- All upstream commits appear in the DAG with original SHAs +- `git log --first-parent` shows a clean merge history +- Build succeeds and functionality tests pass +- Scratch branch deleted -### Phase 6: Documentation and PR +### Phase 7: Documentation and PR **Objective:** Document changes and submit for review **Steps:** @@ -390,18 +499,35 @@ This PR merges upstream OpenSSH commits from through . ## Recovery Procedures -### Abort Cherry-Pick +### Abort Merge +```bash +git merge --abort +git clean -fd +git reset --hard +``` + +### Abort Cherry-Pick (if used outside merge workflow) ```bash git cherry-pick --abort git clean -fd git reset --hard ``` +### Restart Scratch Branch +```bash +# Delete the scratch branch and recreate from the merge branch +git checkout merge-v- +git branch -D scratch-merge-v- +git checkout -b scratch-merge-v- +# Re-enable rerere if needed +git config rerere.enabled true +``` + ### Restart from Checkpoint ```bash git checkout merge-v- -git log --oneline -5 # Verify last successful commit -# Continue from there +git log --oneline -5 # Verify last successful state +# Continue from there (or recreate scratch branch) ``` ### Build Failure Recovery diff --git a/.github/instructions/merge/agent-communication-merge.instructions.md b/.github/instructions/merge/agent-communication-merge.instructions.md index 27c49018c943..80aa273e2ab9 100644 --- a/.github/instructions/merge/agent-communication-merge.instructions.md +++ b/.github/instructions/merge/agent-communication-merge.instructions.md @@ -301,6 +301,35 @@ Finalizing the merge: Ready to commit and push. ``` +### Scratch-to-Real Branch Transition: +``` +Scratch branch phase complete! + +Summary: +- Processed [N] batches on scratch branch +- Resolved [X] total conflicts across [Y] files +- All [N] batches built successfully +- Resolution log saved with [X] entries + +Switching to the real merge branch for the single final merge. +Recorded resolutions will be replayed automatically via git rerere and the resolution log. +``` + +### Real Branch Replay Report: +``` +Single merge completed on real branch. Resolution replay results: + +- Auto-resolved by git rerere: [X] files +- Replayed from resolution log: [Y] files +- Unmatched (manual resolution needed): [Z] files + - [file1]: [brief reason] + - [file2]: [brief reason] +- Failed replays: [W] files + +[If unmatched > 0]: Resolving the remaining [Z] files using strategies from the scratch phase... +[If all resolved]: All conflicts resolved. Applying build fixes as separate commits. +``` + ## Special Scenarios ### When Seeking User Approval: diff --git a/.github/instructions/merge/merge-details.instructions.md b/.github/instructions/merge/merge-details.instructions.md index aaeab4fc3bb2..a01f5cd605b4 100644 --- a/.github/instructions/merge/merge-details.instructions.md +++ b/.github/instructions/merge/merge-details.instructions.md @@ -7,16 +7,20 @@ applyTo: "**/*" ## Overview This AI-specific documentation provides comprehensive instructions and algorithmic frameworks that AI agents can use to systematically approach the OpenSSH merge process with minimal human intervention while maintaining high quality and consistency. It combines conflict resolution strategies with automated decision-making processes. -**Key Approach: Chunked Merging** -Instead of merging entire upstream versions at once, this framework implements a chunked approach that: -- Processes commits in small batches ending with commits that have any CI run (successful or not) -- Groups commits by CI presence rather than CI success for more frequent checkpoints -- Builds after each batch (mandatory) +**Key Approach: Two-Phase Merge with Scratch Branch** +Instead of cherry-picking commits (which rewrites history), this framework implements a two-phase approach: + +1. **Scratch branch** — Incremental `git merge` at batch boundaries (grouped by CI presence). Build and test after each batch. Every conflict resolution is recorded via `git rerere` and the Save-MergeResolution MCP tool. +2. **Real branch** — A single `git merge` of the final upstream target. Recorded resolutions replay automatically via `git rerere` and Replay-MergeResolutions. This produces one merge commit with all upstream SHAs intact. + +Benefits: +- Preserves upstream commit history exactly (original SHAs, authors, timestamps) +- Uses incremental merge on scratch branch so conflict markers match the final merge (maximising `rerere` replay) +- Builds after each batch on scratch branch (mandatory) for early error detection - Validates functionality only at successful CI checkpoints - Requires user approval before proceeding to next batch - Allows for incremental progress and easier rollback - Reduces complexity of conflict resolution -- Enables better testing and validation at each step ## Decision Framework for AI Agents @@ -270,7 +274,7 @@ FUNCTION automated_build_fix(): // ALWAYS invoke Test-OpenSSHBuild.ps1 to check warnings (success or failure) test_result = test_openssh_build(Configuration="Release", Architecture="x64", LogFile=build_result.log) - + IF build_result.success: // Check for new warnings against baseline new_warnings = compare_warnings_to_baseline(test_result.warnings, baseline_warnings) @@ -321,6 +325,8 @@ FUNCTION determine_fix_strategy(error): - Compare warning count against established baseline - If new warnings detected, report to user with categorization and request approval before proceeding - Do NOT skip `Test-OpenSSHBuild.ps1` even when build succeeds - warning checks are mandatory. +- On the scratch branch, commit build fixes after each batch merge commit. +- On the real branch, apply the same build fixes as separate commits after the single merge commit. ## Testing Automation Framework @@ -423,17 +429,17 @@ FUNCTION assess_conflict_complexity(conflicts): When `assess_conflict_complexity()` returns `HIGH_COMPLEXITY`, invoke the `Get-ConflictContext` MCP tool **before** attempting to edit the file. It provides three-way context anchored to the actual changed regions, accounting for the fact that our fork's line numbers differ from upstream. ```pseudocode -FUNCTION resolve_conflict(file_path, conflict_content, cherry_pick_commit): +FUNCTION resolve_conflict(file_path, conflict_content, merge_batch_commit): complexity = assess_conflict_complexity([{file: file_path, content: conflict_content}]) IF complexity == "HIGH_COMPLEXITY": // Fetch three-way context before editing // MCP Tool: mcp_openssh-server_Get_ConflictContext - // FilePath=file_path, CommitHash=cherry_pick_commit + // FilePath=file_path, CommitHash=merge_batch_commit // // If the default MaxTotalLines=150 is insufficient (e.g., many hunks or // a large function), re-invoke with a higher value such as MaxTotalLines=300. - context = get_conflict_context(file_path, cherry_pick_commit) + context = get_conflict_context(file_path, merge_batch_commit) FOR EACH hunk IN context.Hunks: // Use all three excerpts to understand: @@ -445,9 +451,17 @@ FUNCTION resolve_conflict(file_path, conflict_content, cherry_pick_commit): // Check Message for budget warnings and increase MaxTotalLines if needed IF context.Message contains "minimum floor": - re_invoke_with_larger_budget(file_path, cherry_pick_commit) + re_invoke_with_larger_budget(file_path, merge_batch_commit) + + resolved = apply_resolution_strategy(file_path, conflict_content) + + // Record the resolution for replay on the real branch + // MCP Tool: mcp_openssh-server_Save_MergeResolution + // FilePath=file_path, Strategy=, Rationale=, + // BatchNumber=, UpstreamCommits= + save_merge_resolution(file_path, strategy, rationale, batch_number) - RETURN apply_resolution_strategy(file_path, conflict_content) + RETURN resolved ``` **Key behaviours of the tool:** diff --git a/.github/instructions/merge/merge-process-overview.instructions.md b/.github/instructions/merge/merge-process-overview.instructions.md index 4f64bf99b092..43b6eb1606d9 100644 --- a/.github/instructions/merge/merge-process-overview.instructions.md +++ b/.github/instructions/merge/merge-process-overview.instructions.md @@ -16,16 +16,20 @@ Ensure the following tools are installed and configured before proceeding: - Latest Windows 10/11 SDK ## Process Overview -The merge process uses a **chunked approach** to reduce complexity and improve success rates. Instead of merging entire upstream versions at once, commits are processed in small batches ending with commits that have CI runs. Each batch is built and optionally validated before proceeding to the next. +The merge process uses a **two-phase approach** to preserve upstream commit history while keeping conflict resolution manageable: + +1. **Scratch branch** — Incremental `git merge` at batch boundaries. Build and test after each batch. Every conflict resolution is recorded via `git rerere` and a resolution log. +2. **Real branch** — A single `git merge` of the final upstream target. Recorded resolutions are replayed automatically. This produces one merge commit with all upstream SHAs intact. The process consists of several interconnected phases: 1. **[Setup Phase](#setup-phase)** - Repository configuration and preparation 2. **[Research Phase](#research-phase)** - Understanding changes and conflicts -3. **[Merge Phase](#merge-phase)** - Performing chunked commit merging -4. **[Build Phase](#build-phase)** - Resolving compilation issues -5. **[Testing Phase](#testing-phase)** - Validating functionality -6. **[Submission Phase](#submission-phase)** - Creating the Pull Request +3. **[Scratch Branch Phase](#scratch-branch-phase)** - Incremental merging with resolution recording +4. **[Real Branch Phase](#real-branch-phase)** - Single merge with resolution replay +5. **[Build Phase](#build-phase)** - Resolving compilation issues +6. **[Testing Phase](#testing-phase)** - Validating functionality +7. **[Submission Phase](#submission-phase)** - Creating the Pull Request ## Setup Phase @@ -68,9 +72,24 @@ The process consists of several interconnected phases: ```pwsh # MCP Tool: mcp_openssh-server_Invoke_Git # Operation="Config", Key="core.editor", Value="true" + + # Enable rerere for automatic resolution recording + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="Config", Key="rerere.enabled", Value="true" + ``` + +3. **Create branches:** + ```pwsh + # Create the real merge branch (receives the final single merge) + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="CreateBranch", Branch="merge-v-" + + # Create the scratch branch from the same point (for incremental merges) + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="CreateBranch", Branch="scratch-merge-v-" ``` -### Perform Merge with Grouped Commits +### Scratch Branch Phase 4. **Identify merge range and group commits:** Use the Get-CommitGroups MCP tool with `-FirstChunkOnly -GroupByCIPresence` @@ -103,61 +122,47 @@ The process consists of several interconnected phases: } ``` - Display batch details for verification, then proceed with cherry-picking. + Display batch details for verification, then proceed with merging. **After completing steps below, get next batch**: - Call tool with `StartCommit=`, `EndCommit=`, `FirstChunkOnly=true`, `GroupByCIPresence=true` - Continue this process until the target end commit is reached (or HEAD if no end commit specified) -5. **Execute chunked merge (batch cherry-pick all commits in chunk):** +5. **Execute batch merge on scratch branch:** - **Important:** Cherry-pick **all commits in the batch** before building. This is more efficient than building after each individual commit. If the build fails, you can identify the problematic commit(s) through git bisect or by examining the build errors. + Merge the batch's end commit to bring in all commits in the range at once: ```pwsh - # For each chunk (start..end), cherry-pick all commits in the batch - # Example for a single chunk: - $chunkStart = $result.StartCommitFull - $chunkEnd = $result.EndCommitFull - - # Get commits in oldest-first order using Invoke-Git MCP tool: + # Merge all commits up to the batch endpoint # MCP Tool: mcp_openssh-server_Invoke_Git - # Operation="Log", Range="$chunkStart^..$chunkEnd", ShasOnly=true - # result.Commits contains [{Hash, Message}] in oldest-first order - - foreach ($commit in $result.Commits) { - # Cherry-pick each commit using Invoke-Git MCP tool: - # MCP Tool: mcp_openssh-server_Invoke_Git - # Operation="CherryPick", CommitHash=$commit.Hash - - # If conflicts occur, resolve them before continuing to next commit - # (see step 7 below for conflict resolution) - } - - # After all commits in batch are cherry-picked, proceed to build (step 9) + # Operation="Merge", CommitHash=$result.EndCommitFull ``` -7. **Resolve merge conflicts (per commit):** + This uses `--no-ff` to always create a merge commit checkpoint. + +7. **Resolve merge conflicts and record resolutions:** **📖 Detailed Instructions** ([Merge Details](./merge-details.instructions.md)): - - Resolve conflicts for the current commit only - - Use three-way comparison tools + - Resolve conflicts for all conflicted files + - **Record each resolution** using the Save-MergeResolution MCP tool: + ```pwsh + # MCP Tool: mcp_openssh-server_Save_MergeResolution + # FilePath="", Strategy="", Rationale="", + # BatchNumber=, UpstreamCommits="" + ``` + - `git rerere` also automatically records resolutions - Follow established Windows compatibility patterns - Reference previous merge PRs for similar conflicts -8. **Continue cherry-picking after resolution:** +8. **Complete the merge after resolution:** ```pwsh - # After resolving conflicts for current commit - # Stage all resolved files using Invoke-Git MCP tool: # MCP Tool: mcp_openssh-server_Invoke_Git # Operation="Add", Path="." - # Continue cherry-pick using Invoke-Git MCP tool: + # Continue merge using Invoke-Git MCP tool: # MCP Tool: mcp_openssh-server_Invoke_Git - # Operation="CherryPickContinue" - - # Then continue with remaining commits in batch - # Repeat process for next batch if needed + # Operation="MergeContinue" ``` 9. **Build after completing the batch:** @@ -170,11 +175,11 @@ The process consists of several interconnected phases: - **MCP Tool Name**: `mcp_openssh-server_Test_OpenSSHBuild` - **Parameters**: `Configuration="Release"`, `Architecture="x64"` - **DO NOT** try to read log files directly with `Get-Content` or locate them manually - + If build failed: - Fix issues based on parsed error output - Rebuild and verify - + If build succeeded: - Compare warnings against baseline established in Phase 1 - If new warnings detected: @@ -183,7 +188,7 @@ The process consists of several interconnected phases: - Request user decision: fix warnings or proceed - Wait for user approval before continuing - If user approves proceeding, update baseline to include new warnings - + **CRITICAL: Before committing, restore paths.targets**: ```pwsh # MCP Tool: mcp_openssh-server_Invoke_Git @@ -203,6 +208,38 @@ The process consists of several interconnected phases: - Summarize batch changes, conflicts resolved, build status, validation status - Wait for user approval before proceeding to next batch - Document next steps (starting commit for next batch) + - After all batches complete on the scratch branch, proceed to the Real Branch Phase + +### Real Branch Phase +12. **Switch to the real merge branch:** + ```pwsh + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="Checkout", Target="merge-v-" + ``` + +13. **Perform a single merge** of the final upstream target: + ```pwsh + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="Merge", CommitHash="" + ``` + `git rerere` will automatically apply resolutions recorded during the scratch phase. + +14. **Replay remaining resolutions** from the log: + ```pwsh + # MCP Tool: mcp_openssh-server_Replay_MergeResolutions + # (reads from .git/merge-resolution-log.json) + ``` + Resolve any unmatched files manually using the log's strategy and rationale as guidance. + +15. **Complete the merge and apply build fixes:** + ```pwsh + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="MergeContinue" + ``` + Apply build fixes (config.h.vs, .vcxproj changes, etc.) as separate commits after the merge commit. + +16. **Final build and validation** on the real branch. + --- ## Build Phase diff --git a/.github/prompt/merge.prompt.md b/.github/prompt/merge.prompt.md index a75572557e79..0089b1bcbbba 100644 --- a/.github/prompt/merge.prompt.md +++ b/.github/prompt/merge.prompt.md @@ -12,7 +12,7 @@ Provide the following when you invoke this prompt: Operating guidance: - Use and follow merge-upstream.agent.md. Treat it as the primary operating guide. - Rely on the provided for repository overview, setup, build, merge strategy, and testing. Do not re-fetch or re-search them; assume they are already attached in context. -- Perform chunked merges ending at commits with CI runs; build after each batch. Only parse build logs if the build fails. +- Use the two-phase merge workflow: (1) incremental `git merge` on a scratch branch with resolution recording via `git rerere` and Save-MergeResolution, then (2) a single `git merge` on the real branch with resolution replay via `git rerere` and Replay-MergeResolutions. This preserves upstream commit history. - Build using the MCP tools: `mcp_openssh-server_Start_OpenSSHBuild` (Release/x64 by default). If the build fails, analyze with `mcp_openssh-server_Test_OpenSSHBuild`. - Apply Windows compatibility strategies as documented (prefer win32compat layer; guard with `#ifdef WINDOWS` when necessary; update VS projects for build system changes). - Summarize a plan, request approval between batches, and clearly list conflict resolutions and rationale. diff --git a/.github/tools/Get-ConflictContext.ps1 b/.github/tools/Get-ConflictContext.ps1 index e83d6a4c4fd3..46bab7be45b1 100644 --- a/.github/tools/Get-ConflictContext.ps1 +++ b/.github/tools/Get-ConflictContext.ps1 @@ -3,10 +3,10 @@ Retrieves three-way context for a conflicted file to aid complex conflict resolution. .DESCRIPTION - MCP-compatible tool that fetches three versions of a file involved in a cherry-pick - conflict — the upstream file before the commit, the upstream file after the commit, - and our fork's version (via MERGE_HEAD) — and extracts focused, line-numbered excerpts - centered on each changed hunk. + MCP-compatible tool that fetches three versions of a file involved in a merge or + cherry-pick conflict — the upstream file before the commit, the upstream file after + the commit, and our fork's version (via HEAD) — and extracts focused, line-numbered + excerpts centered on each changed hunk. For each hunk in the upstream diff, the tool locates the corresponding region in our fork using two-tier content matching: @@ -22,7 +22,8 @@ Path to the conflicted file, relative to the repository root. .PARAMETER CommitHash - The upstream commit SHA being cherry-picked that caused the conflict. + The upstream commit SHA that caused the conflict. During the scratch-branch merge + workflow, this is typically the batch endpoint commit passed to git merge. .PARAMETER ContextLines Number of lines of context above and below each hunk match to include in excerpts. @@ -344,11 +345,11 @@ $commitMsgResult = Invoke-GitCommand -Arguments @('log', '-1', '--pretty=format: $commitMessage = if ($commitMsgResult.Success) { $commitMsgResult.Output.Trim() } else { '' } # 5. Fetch the three file versions -# MERGE_HEAD is populated by git during an in-progress cherry-pick conflict -# and points to the commit being cherry-picked (our fork's working state before merge) +# HEAD is our fork's version of the file during both merge and cherry-pick conflicts. +# CommitHash^ is the upstream state before the commit; CommitHash is after. $upstreamBefore = Get-FileAtRef -Ref "${CommitHash}^" -File $FilePath $upstreamAfter = Get-FileAtRef -Ref "${CommitHash}" -File $FilePath -$ourFork = Get-FileAtRef -Ref 'MERGE_HEAD' -File $FilePath +$ourFork = Get-FileAtRef -Ref 'HEAD' -File $FilePath # 6. Parse hunks from the diff $hunks = Parse-DiffHunks -DiffText $upstreamDiff diff --git a/.github/tools/Invoke-Git.ps1 b/.github/tools/Invoke-Git.ps1 index f091e32b016c..3a30a1f53ade 100644 --- a/.github/tools/Invoke-Git.ps1 +++ b/.github/tools/Invoke-Git.ps1 @@ -15,6 +15,7 @@ .PARAMETER Operation The git operation to perform. One of: CherryPick, CherryPickContinue, CherryPickAbort, + Merge, MergeContinue, MergeAbort, Add, Checkout, CreateBranch, Commit, Push, Fetch, Config, Reset, Clean, @@ -22,7 +23,7 @@ .PARAMETER CommitHash A commit SHA or any git ref (branch name, tag, etc.). - Used by: CherryPick, Show. + Used by: CherryPick, Merge, Show. .PARAMETER Range A git range expression (e.g. "abc123^..def456" or "HEAD..upstream/V_10_0_P2"). @@ -78,6 +79,7 @@ Message [string] Human-readable summary Plus operation-specific fields: CherryPick (on failure): ConflictedFiles [string[]] + Merge (on failure): ConflictedFiles [string[]] Log / ShasOnly: Commits [{Hash, Message}] Status: ConflictedFiles [string[]], ModifiedFiles [string[]] Commit (on success): CommitHash [string] @@ -152,6 +154,26 @@ # MCP Tool: mcp_openssh-server_Invoke_Git # Operation="Reset", Target="HEAD", Mode="hard" +.EXAMPLE + # Merge an upstream batch endpoint into the current branch + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="Merge", CommitHash="6fb728df50c1afd338cb0223a84ce24579577eff" + +.EXAMPLE + # Continue a merge after resolving conflicts + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="MergeContinue" + +.EXAMPLE + # Abort an in-progress merge + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="MergeAbort" + +.EXAMPLE + # Enable rerere for merge resolution recording + # MCP Tool: mcp_openssh-server_Invoke_Git + # Operation="Config", Key="rerere.enabled", Value="true" + .EXAMPLE # Remove untracked files (recovery) # MCP Tool: mcp_openssh-server_Invoke_Git @@ -162,6 +184,7 @@ param( [Parameter(Mandatory)] [ValidateSet( 'CherryPick', 'CherryPickContinue', 'CherryPickAbort', + 'Merge', 'MergeContinue', 'MergeAbort', 'Add', 'Checkout', 'CreateBranch', 'Commit', 'Push', 'Fetch', 'Config', 'Reset', 'Clean', @@ -169,7 +192,7 @@ param( )] [string]$Operation, - # CherryPick, Show — accepts any git ref: commit SHA, branch name, tag, etc. + # CherryPick, Merge, Show — accepts any git ref: commit SHA, branch name, tag, etc. [string]$CommitHash = '', # Log (plain or ShasOnly), Diff — git range expression e.g. "abc123^..def456" @@ -290,6 +313,26 @@ $result = switch ($Operation) { Invoke-GitCommand -Arguments @('cherry-pick', '--abort') } + 'Merge' { + if (-not $CommitHash) { throw 'CommitHash is required for Merge (target ref to merge)' } + $r = Invoke-GitCommand -Arguments @('merge', '--no-ff', $CommitHash) + if (-not $r.Success) { + $statusResult = Invoke-GitCommand -Arguments @('status', '--porcelain') + $r['ConflictedFiles'] = ($statusResult.Output -split "`n") | + Where-Object { $_ -match '^(UU|AA|DD|AU|UA|DU|UD)\s' } | + ForEach-Object { $_.Substring(3).Trim() } + } + $r + } + + 'MergeContinue' { + Invoke-GitCommand -Arguments @('merge', '--continue') + } + + 'MergeAbort' { + Invoke-GitCommand -Arguments @('merge', '--abort') + } + 'Add' { Invoke-GitCommand -Arguments @('add', $Path) } diff --git a/.github/tools/Replay-MergeResolutions.ps1 b/.github/tools/Replay-MergeResolutions.ps1 new file mode 100644 index 000000000000..7006c44de9a9 --- /dev/null +++ b/.github/tools/Replay-MergeResolutions.ps1 @@ -0,0 +1,201 @@ +<# +.SYNOPSIS + Replays saved conflict resolutions from the merge resolution log onto + currently conflicted files. + +.DESCRIPTION + MCP-compatible tool for the real-branch phase of the scratch-branch merge + workflow. Reads .git/merge-resolution-log.json (populated during the scratch + phase by Save-MergeResolution.ps1) and attempts to apply saved resolutions + to files that are currently in a conflicted state (UU/AA/etc. in git status). + + For each conflicted file that has a matching entry in the log, the tool writes + the saved resolved content and stages the file with git add. + + Files not found in the log are reported as unmatched so the agent can resolve + them manually. + +.PARAMETER DryRun + When specified, reports what would be applied without modifying any files. + +.OUTPUTS + Hashtable with: + Success [bool] Whether the operation completed without errors + Message [string] Human-readable summary + ResolvedFiles [string[]] Files successfully resolved from the log + UnmatchedFiles [string[]] Conflicted files with no log entry + FailedFiles [string[]] Files where replay was attempted but failed + LogPath [string] Absolute path to the resolution log + +.EXAMPLE + # Replay all saved resolutions onto current merge conflicts + # MCP Tool: mcp_openssh-server_Replay_MergeResolutions + +.EXAMPLE + # Preview what would be replayed without modifying files + # MCP Tool: mcp_openssh-server_Replay_MergeResolutions + # DryRun=true +#> + +param( + [switch]$DryRun +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +# ── Git process helper (same pattern as Invoke-Git.ps1) ────────────────────── + +function Invoke-GitCommand { + param([string[]]$Arguments) + + $processInfo = [System.Diagnostics.ProcessStartInfo]::new() + $processInfo.FileName = 'git' + $processInfo.Arguments = ($Arguments | ForEach-Object { + if ($_ -match '\s') { "`"$_`"" } else { $_ } + }) -join ' ' + $processInfo.UseShellExecute = $false + $processInfo.CreateNoWindow = $true + $processInfo.RedirectStandardInput = $true + $processInfo.RedirectStandardOutput = $true + $processInfo.RedirectStandardError = $true + + $process = [System.Diagnostics.Process]::new() + $process.StartInfo = $processInfo + $process.Start() | Out-Null + $process.StandardInput.Close() + + $stdoutTask = $process.StandardOutput.ReadToEndAsync() + $stderrTask = $process.StandardError.ReadToEndAsync() + + $completed = $process.WaitForExit(30000) + + if (-not $completed) { + $process.Kill() + return @{ + ExitCode = -1 + Success = $false + Output = '' + Error = "git $($Arguments -join ' ') timed out after 30 seconds" + } + } + + return @{ + ExitCode = $process.ExitCode + Success = ($process.ExitCode -eq 0) + Output = $stdoutTask.GetAwaiter().GetResult().TrimEnd() + Error = $stderrTask.GetAwaiter().GetResult().TrimEnd() + } +} + +# ── Locate and read the resolution log ─────────────────────────────────────── + +$gitDir = Join-Path (Get-Location) '.git' +$logPath = Join-Path $gitDir 'merge-resolution-log.json' + +if (-not (Test-Path $logPath)) { + return @{ + Success = $false + Message = 'No resolution log found at .git/merge-resolution-log.json. Run the scratch-branch phase first.' + ResolvedFiles = @() + UnmatchedFiles = @() + FailedFiles = @() + LogPath = $logPath + } +} + +$log = Get-Content -Raw $logPath | ConvertFrom-Json + +if (-not $log.resolutions -or $log.resolutions.Count -eq 0) { + return @{ + Success = $true + Message = 'Resolution log is empty — no saved resolutions to replay.' + ResolvedFiles = @() + UnmatchedFiles = @() + FailedFiles = @() + LogPath = $logPath + } +} + +# ── Build a lookup of saved resolutions keyed by file path ─────────────────── +# If multiple entries exist for the same file (across batches), use the latest one. + +$resolutionMap = @{} +foreach ($entry in $log.resolutions) { + $resolutionMap[$entry.file] = $entry +} + +# ── Get currently conflicted files from git status ─────────────────────────── + +$statusResult = Invoke-GitCommand -Arguments @('status', '--porcelain') +$conflictedFiles = @() +if ($statusResult.Output) { + $conflictedFiles = ($statusResult.Output -split "`n") | + Where-Object { $_ -match '^(UU|AA|DD|AU|UA|DU|UD)\s' } | + ForEach-Object { $_.Substring(3).Trim() } +} + +if ($conflictedFiles.Count -eq 0) { + return @{ + Success = $true + Message = 'No conflicted files found — nothing to replay.' + ResolvedFiles = @() + UnmatchedFiles = @() + FailedFiles = @() + LogPath = $logPath + } +} + +# ── Replay resolutions ────────────────────────────────────────────────────── + +$resolvedFiles = [System.Collections.Generic.List[string]]::new() +$unmatchedFiles = [System.Collections.Generic.List[string]]::new() +$failedFiles = [System.Collections.Generic.List[string]]::new() + +foreach ($file in $conflictedFiles) { + if (-not $resolutionMap.ContainsKey($file)) { + $unmatchedFiles.Add($file) + continue + } + + $entry = $resolutionMap[$file] + + if ($DryRun) { + $resolvedFiles.Add($file) + continue + } + + try { + # Decode the saved resolved content and write it to the file + $contentBytes = [System.Convert]::FromBase64String($entry.resolved_content_base64) + $fullFilePath = Join-Path (Get-Location) $file + [System.IO.File]::WriteAllBytes($fullFilePath, $contentBytes) + + # Stage the resolved file + $addResult = Invoke-GitCommand -Arguments @('add', $file) + if (-not $addResult.Success) { + $failedFiles.Add($file) + continue + } + + $resolvedFiles.Add($file) + } catch { + $failedFiles.Add($file) + } +} + +# ── Return result ──────────────────────────────────────────────────────────── + +$dryRunNote = if ($DryRun) { ' (DRY RUN — no files modified)' } else { '' } +$message = "Replay complete${dryRunNote}: $($resolvedFiles.Count) resolved, " + + "$($unmatchedFiles.Count) unmatched, $($failedFiles.Count) failed " + + "(out of $($conflictedFiles.Count) conflicted files)." + +return @{ + Success = ($failedFiles.Count -eq 0) + Message = $message + ResolvedFiles = $resolvedFiles.ToArray() + UnmatchedFiles = $unmatchedFiles.ToArray() + FailedFiles = $failedFiles.ToArray() + LogPath = $logPath +} diff --git a/.github/tools/Save-MergeResolution.ps1 b/.github/tools/Save-MergeResolution.ps1 new file mode 100644 index 000000000000..049d0e739172 --- /dev/null +++ b/.github/tools/Save-MergeResolution.ps1 @@ -0,0 +1,160 @@ +<# +.SYNOPSIS + Records a conflict resolution entry to the merge resolution log. + +.DESCRIPTION + MCP-compatible tool that saves details about how a conflicted file was resolved + during the scratch-branch phase of the merge workflow. The resolution — including + the resolved file content, strategy, and rationale — is appended to a JSON log + at .git/merge-resolution-log.json. + + This log is consumed by Replay-MergeResolutions.ps1 during the real-branch + single-merge phase to automatically re-apply known resolutions. + +.PARAMETER FilePath + Path to the resolved file, relative to the repository root. + +.PARAMETER Strategy + The resolution strategy used. One of: + accept_upstream — Took the upstream change completely + ifdef_windows — Wrapped with #ifdef WINDOWS / #else / #endif + ifndef_windows — Excluded with #ifndef WINDOWS + combine — Combined upstream and Windows changes + manual — Custom resolution not fitting other categories + +.PARAMETER Rationale + Free-text explanation of why this resolution strategy was chosen. + +.PARAMETER BatchNumber + The batch number (from Get-CommitGroups) that this resolution belongs to. + +.PARAMETER UpstreamCommits + Comma-separated list of upstream commit SHAs that touched this file in this batch. + +.PARAMETER MergeTarget + The final upstream ref being merged (e.g. "upstream/V_10_1_P1"). Only needed on + the first invocation to initialise the log header. Ignored if log already exists. + +.OUTPUTS + Hashtable with: + Success [bool] Whether the entry was saved + Message [string] Human-readable summary + LogPath [string] Absolute path to the resolution log file + +.EXAMPLE + # Record a resolution after resolving auth.c + # MCP Tool: mcp_openssh-server_Save_MergeResolution + # FilePath="auth.c", Strategy="ifdef_windows", Rationale="Wrapped PAM code", + # BatchNumber=1, UpstreamCommits="abc1234,def5678" + +.EXAMPLE + # Record the first resolution (initialises log with MergeTarget) + # MCP Tool: mcp_openssh-server_Save_MergeResolution + # FilePath="channels.c", Strategy="accept_upstream", Rationale="Security fix", + # BatchNumber=1, UpstreamCommits="abc1234", MergeTarget="upstream/V_10_1_P1" +#> + +param( + [Parameter(Mandatory)] + [string]$FilePath, + + [Parameter(Mandatory)] + [ValidateSet('accept_upstream', 'ifdef_windows', 'ifndef_windows', 'combine', 'manual')] + [string]$Strategy, + + [Parameter(Mandatory)] + [string]$Rationale, + + [Parameter(Mandatory)] + [int]$BatchNumber, + + [string]$UpstreamCommits = '', + + [string]$MergeTarget = '' +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +# ── Locate the log file inside .git ────────────────────────────────────────── + +$gitDir = Join-Path (Get-Location) '.git' +if (-not (Test-Path $gitDir)) { + return @{ + Success = $false + Message = 'Not inside a git repository — .git directory not found.' + LogPath = '' + } +} + +$logPath = Join-Path $gitDir 'merge-resolution-log.json' + +# ── Read or initialise the log ─────────────────────────────────────────────── + +if (Test-Path $logPath) { + $log = Get-Content -Raw $logPath | ConvertFrom-Json +} else { + $log = [PSCustomObject]@{ + merge_target = if ($MergeTarget) { $MergeTarget } else { 'unknown' } + created_at = (Get-Date -Format 'o') + resolutions = @() + } +} + +# ── Read the resolved file and compute hash ────────────────────────────────── + +$fullFilePath = Join-Path (Get-Location) $FilePath +if (-not (Test-Path $fullFilePath)) { + return @{ + Success = $false + Message = "Resolved file not found: ${FilePath}" + LogPath = $logPath + } +} + +$fileBytes = [System.IO.File]::ReadAllBytes($fullFilePath) +$sha256 = [System.Security.Cryptography.SHA256]::Create() +$hashBytes = $sha256.ComputeHash($fileBytes) +$hashString = ($hashBytes | ForEach-Object { $_.ToString('x2') }) -join '' +$contentB64 = [System.Convert]::ToBase64String($fileBytes) + +# ── Parse upstream commits ─────────────────────────────────────────────────── + +$commitList = if ($UpstreamCommits) { + ($UpstreamCommits -split ',') | ForEach-Object { $_.Trim() } | Where-Object { $_ } +} else { + @() +} + +# ── Build the entry ────────────────────────────────────────────────────────── + +$entry = [PSCustomObject]@{ + file = $FilePath + batch_number = $BatchNumber + upstream_commits = $commitList + strategy = $Strategy + rationale = $Rationale + resolved_content_sha256 = $hashString + resolved_content_base64 = $contentB64 + recorded_at = (Get-Date -Format 'o') +} + +# ── Append and save ────────────────────────────────────────────────────────── + +# ConvertFrom-Json returns a fixed-size array; convert to a list so we can add +$existingResolutions = [System.Collections.Generic.List[object]]::new() +if ($log.resolutions) { + foreach ($r in $log.resolutions) { + $existingResolutions.Add($r) + } +} +$existingResolutions.Add($entry) +$log.resolutions = $existingResolutions.ToArray() + +$log | ConvertTo-Json -Depth 10 | Set-Content -Path $logPath -Encoding utf8 + +return @{ + Success = $true + Message = "Resolution recorded for '${FilePath}' (batch ${BatchNumber}, strategy: ${Strategy}). Log has $($log.resolutions.Count) entries." + LogPath = $logPath +} From 232775da6515f4855370907d970a65e6f39bb44a Mon Sep 17 00:00:00 2001 From: Tess Gauthier Date: Wed, 15 Apr 2026 12:21:42 -0400 Subject: [PATCH 233/244] refine instructions --- .github/agents/merge-upstream.agent.md | 5 +++ .../merge/merge-details.instructions.md | 37 +++++++++++++++++++ .../merge-process-overview.instructions.md | 10 ++++- .github/instructions/testing.instructions.md | 36 +++++++++++++++++- .github/prompt/merge.prompt.md | 3 ++ 5 files changed, 88 insertions(+), 3 deletions(-) diff --git a/.github/agents/merge-upstream.agent.md b/.github/agents/merge-upstream.agent.md index 5bfcdd7deea4..775b9fa3b9c3 100644 --- a/.github/agents/merge-upstream.agent.md +++ b/.github/agents/merge-upstream.agent.md @@ -53,6 +53,11 @@ This agent assists with merging upstream OpenSSH commits into the PowerShell for - `NoCleanup` (boolean, optional): Skip cleanup for debugging (default: false) - **If tool unavailable**: ERROR - This tool is required for the merge workflow + **Validation scenario override:** + - If prompt input declares `Validation scenario=entra-id-debug-localhost`, do not use temporary local-user/password validation. + - Instead, run `sshd -ddd` in one terminal and validate with `ssh localhost` from a second terminal. + - Use this only on machines where the Entra-ID admin account already has key-based auth configured. + 4. **Get-ConflictContext MCP Tool** - Three-way conflict context for high-complexity conflicts - **MCP Tool Name**: `mcp_openssh-server_Get_ConflictContext` - **When to use**: ONLY when `assess_conflict_complexity()` returns `HIGH_COMPLEXITY` diff --git a/.github/instructions/merge/merge-details.instructions.md b/.github/instructions/merge/merge-details.instructions.md index a01f5cd605b4..27db390e5b1b 100644 --- a/.github/instructions/merge/merge-details.instructions.md +++ b/.github/instructions/merge/merge-details.instructions.md @@ -215,6 +215,20 @@ FUNCTION add_source_to_project(project_file, source_file): insert_into_project_file(project_file, new_line) ``` +### Pattern 4: OpenSSH 10.3 Split-sshd State Ordering (Windows) + +When upstream changes split pre-auth work between `sshd-session` and `sshd-auth`, preserve the state/message ordering exactly. + +- `sshd-session` (listener/monitor side) should not perform banner exchange that upstream moved to `sshd-auth`. +- For Windows `FORK_NOT_SUPPORTED` post-auth child (`sshd-session -z`), monitor message order matters: + - Receive identification-exchange state first. + - Then receive authenticated user context. + +If this ordering is wrong, common symptoms are: +- pre-auth failures such as banner parsing or signature mismatches +- post-auth `Invalid user` with empty username +- monitor keystate errors like `incomplete message` + ## Common Conflict Patterns ### File System Operations @@ -222,6 +236,11 @@ FUNCTION add_source_to_project(project_file, source_file): - **Signal handling** → Use Windows event mechanisms - **File permissions** → Adapt to Windows ACL model +### Privsep and Monitor State Transitions (Windows) +- For split `sshd-session` / `sshd-auth` flows, keep sender/receiver message ordering identical across monitor channels. +- Do not add ad-hoc state shuttling unless both sender and receiver are updated in lockstep. +- When debugging, verify the first protocol failure point (banner exchange vs KEX vs post-auth keystate) before changing multiple stages at once. + ### Build System Changes - **Makefile additions** → Update Visual Studio project files (use `\r\n` line endings) - **New dependencies** → Check Windows compatibility @@ -560,8 +579,26 @@ FUNCTION prepare_pull_request(): labels: ["upstream-merge", determine_complexity_label()], assignees: get_default_reviewers() } + +FUNCTION normalize_fork_workflow_triggers(): + workflow_files = list_files(".github/workflows/*.yml") + + FOR EACH wf IN workflow_files: + // Policy for PowerShell Windows fork: dispatch-only upstream workflows + ensure_trigger_enabled(wf, "workflow_dispatch") + disable_trigger(wf, "push") + disable_trigger(wf, "pull_request") + disable_trigger(wf, "schedule") + + RETURN "workflow triggers normalized for fork policy" ``` +### Workflow Trigger Policy (Windows Fork) +- Upstream workflow files merged into this fork should default to manual invocation only. +- Keep `workflow_dispatch` active. +- Disable automatic triggers (`push`, `pull_request`, `schedule`) unless the Windows fork explicitly depends on them. +- During final merge review, verify `.github/workflows/*.yml` trigger blocks are policy-compliant. + ## Commit Message Template ``` diff --git a/.github/instructions/merge/merge-process-overview.instructions.md b/.github/instructions/merge/merge-process-overview.instructions.md index 43b6eb1606d9..8cfa7b8de472 100644 --- a/.github/instructions/merge/merge-process-overview.instructions.md +++ b/.github/instructions/merge/merge-process-overview.instructions.md @@ -321,12 +321,17 @@ The process consists of several interconnected phases: - Title: `Merge upstream OpenSSH ` - Include comprehensive description of changes and resolutions -16. **Address CI/test failures:** +16. **Normalize upstream workflow triggers for Windows fork:** + - Ensure merged upstream workflow files under `.github/workflows/*.yml` are dispatch-only in this fork. + - Keep `workflow_dispatch` enabled and disable automatic triggers (`push`, `pull_request`, `schedule`) unless explicitly required for this fork. + - Preserve trigger blocks as commented context where practical so future re-syncs are straightforward. + +17. **Address CI/test failures:** - Monitor automated tests - Fix any Windows-specific test failures - Ensure all checks pass -17. **Request review:** +18. **Request review:** - Tag appropriate PowerShell team reviewers - Provide context for complex conflict resolutions @@ -339,6 +344,7 @@ The process consists of several interconnected phases: - [ ] Solution builds successfully on Windows - [ ] Basic SSH connection test passes - [ ] All CI tests pass +- [ ] Upstream workflow triggers normalized to dispatch-only for this fork - [ ] PR approved and ready for merge --- diff --git a/.github/instructions/testing.instructions.md b/.github/instructions/testing.instructions.md index c4f675b3a83c..f4544d8b5877 100644 --- a/.github/instructions/testing.instructions.md +++ b/.github/instructions/testing.instructions.md @@ -98,6 +98,35 @@ The MCP tool performs comprehensive end-to-end testing including: - Before creating pull requests - When debugging SSH connectivity issues +## Validation Scenario Override: Entra-ID Debug Localhost + +Use this scenario when the prompt explicitly declares `Validation scenario=entra-id-debug-localhost`. + +In this scenario, do not create a temporary local user and random password. Instead, validate using an existing Entra-ID administrator account with key-based auth already configured. + +### Steps +1. Open terminal A in the build output directory and run sshd in foreground debug mode: +```pwsh +cd .\bin\x64\Release +.\sshd.exe -ddd +``` + +2. Open terminal B and attempt local key-based connection: +```pwsh +.\ssh.exe localhost +``` + +3. Confirm validation success by checking both sides: +- Client side: successful login on `ssh localhost` using existing key-based auth +- Server side (terminal A): no fatal errors during authentication/session setup + +### Notes +- This mode is intended for machines that already have admin key-based auth configured. +- Keep `sshd -ddd` running only for validation and stop it after the test. +- Use this scenario instead of `Test-OpenSSHFunctionality` when declared in the prompt. +- Use the rebuilt client and server from the same output directory (`.\bin\x64\Release`) to avoid version-mismatch handshake artifacts. +- Do not run extra port probes (for example `Test-NetConnection localhost -Port 22`) between starting `sshd -ddd` and the first `ssh` attempt; probes can consume the one foreground debug session and produce misleading connection-reset/refused behavior. + ## Manual Testing Procedures (For Troubleshooting Only) If the automated MCP tool fails and you need to troubleshoot specific issues manually, follow these procedures: @@ -228,7 +257,7 @@ Get-NetFirewallRule | Where-Object {$_.DisplayName -like "*SSH*"} **Testing is successful when:** - [ ] All expected executables are present after build (verified by Test-OpenSSHBuild MCP tool) - [ ] SSH service installs and starts without errors -- [ ] SSH connection with password authentication succeeds +- [ ] SSH validation succeeds via either password authentication (standard) or `ssh localhost` key-based auth (entra-id-debug-localhost) - [ ] Test command executes successfully via SSH connection - [ ] All resources cleaned up properly after testing @@ -248,6 +277,11 @@ Get-NetFirewallRule | Where-Object {$_.DisplayName -like "*SSH*"} - **MCP Tool Name**: `mcp_openssh-server_Test_OpenSSHFunctionality` - **Parameters**: (use defaults) + If the prompt declares `Validation scenario=entra-id-debug-localhost`, use the Entra-ID debug localhost flow instead: + - Run `.\sshd.exe -ddd` in one terminal from `.\bin\x64\Release` + - Run `.\ssh.exe localhost` in another terminal from `.\bin\x64\Release` + - Report outcome from both client connection behavior and server debug logs + 2. **If test passes**, the merge is validated for basic SSH functionality 3. **If test fails**, use manual procedures and debug mode to diagnose issues diff --git a/.github/prompt/merge.prompt.md b/.github/prompt/merge.prompt.md index 0089b1bcbbba..d5bd78140b6d 100644 --- a/.github/prompt/merge.prompt.md +++ b/.github/prompt/merge.prompt.md @@ -8,12 +8,14 @@ Provide the following when you invoke this prompt: - Upstream remote — optional (default: `upstream`) - Windows fork remote — optional (default: `upstream-pwsh`) - Target branch — optional (default: current branch) +- Validation scenario — optional (default: `standard`); set to `entra-id-debug-localhost` when the machine uses an Entra-ID admin account with existing key-based auth Operating guidance: - Use and follow merge-upstream.agent.md. Treat it as the primary operating guide. - Rely on the provided for repository overview, setup, build, merge strategy, and testing. Do not re-fetch or re-search them; assume they are already attached in context. - Use the two-phase merge workflow: (1) incremental `git merge` on a scratch branch with resolution recording via `git rerere` and Save-MergeResolution, then (2) a single `git merge` on the real branch with resolution replay via `git rerere` and Replay-MergeResolutions. This preserves upstream commit history. - Build using the MCP tools: `mcp_openssh-server_Start_OpenSSHBuild` (Release/x64 by default). If the build fails, analyze with `mcp_openssh-server_Test_OpenSSHBuild`. +- For validation, default to `mcp_openssh-server_Test_OpenSSHFunctionality`. If `Validation scenario=entra-id-debug-localhost` is declared, skip temporary local-user/password validation and instead run sshd in debug mode (`sshd -ddd`) and validate from a second terminal using `ssh localhost`. - Apply Windows compatibility strategies as documented (prefer win32compat layer; guard with `#ifdef WINDOWS` when necessary; update VS projects for build system changes). - Summarize a plan, request approval between batches, and clearly list conflict resolutions and rationale. @@ -27,6 +29,7 @@ Quick start examples: - "Merge from tag `upstream/V_9_8_P1` into my current branch." - "Merge from tag `upstream/V_9_8_P1` to commit `a1b2c3d` into my current branch." - "Merge starting at commit `3a1b2c3`, upstream remote `upstream`, target current branch." +- "Merge from tag `upstream/V_10_0_P2` to `upstream/V_10_3_P1`, validation scenario `entra-id-debug-localhost`." If the Start ref is not provided, ask for it before proceeding. If the End ref is not provided, merging will continue to HEAD (most recent upstream commit). From f06d9c80957e8a47b2f65f06daa87ed40ddcca6f Mon Sep 17 00:00:00 2001 From: Tess Gauthier Date: Thu, 16 Apr 2026 11:33:25 -0400 Subject: [PATCH 234/244] add tool to invoke E2E CI --- .../merge/merge-details.instructions.md | 14 +- .../merge-process-overview.instructions.md | 19 +- .github/instructions/testing.instructions.md | 94 ++++- .github/tools/Invoke-OpenSSHTests.ps1 | 338 ++++++++++++++++++ 4 files changed, 454 insertions(+), 11 deletions(-) create mode 100644 .github/tools/Invoke-OpenSSHTests.ps1 diff --git a/.github/instructions/merge/merge-details.instructions.md b/.github/instructions/merge/merge-details.instructions.md index 27db390e5b1b..495f5ab7b0f3 100644 --- a/.github/instructions/merge/merge-details.instructions.md +++ b/.github/instructions/merge/merge-details.instructions.md @@ -10,14 +10,14 @@ This AI-specific documentation provides comprehensive instructions and algorithm **Key Approach: Two-Phase Merge with Scratch Branch** Instead of cherry-picking commits (which rewrites history), this framework implements a two-phase approach: -1. **Scratch branch** — Incremental `git merge` at batch boundaries (grouped by CI presence). Build and test after each batch. Every conflict resolution is recorded via `git rerere` and the Save-MergeResolution MCP tool. +1. **Scratch branch** — Incremental `git merge` at batch boundaries (grouped by CI presence). Build and run the full CI test suite after each batch. Every conflict resolution is recorded via `git rerere` and the Save-MergeResolution MCP tool. 2. **Real branch** — A single `git merge` of the final upstream target. Recorded resolutions replay automatically via `git rerere` and Replay-MergeResolutions. This produces one merge commit with all upstream SHAs intact. Benefits: - Preserves upstream commit history exactly (original SHAs, authors, timestamps) - Uses incremental merge on scratch branch so conflict markers match the final merge (maximising `rerere` replay) - Builds after each batch on scratch branch (mandatory) for early error detection -- Validates functionality only at successful CI checkpoints +- Runs the full CI test suite after each batch (mandatory), independent of upstream CI status - Requires user approval before proceeding to next batch - Allows for incremental progress and easier rollback - Reduces complexity of conflict resolution @@ -347,6 +347,16 @@ FUNCTION determine_fix_strategy(error): - On the scratch branch, commit build fixes after each batch merge commit. - On the real branch, apply the same build fixes as separate commits after the single merge commit. +### Batch Test Invocation Policy (Scratch Branch) + +- After each batch merge is completed and builds cleanly, run the full CI test suite: + - **MCP Tool Name**: `mcp_openssh-server_Invoke_OpenSSHTests` + - **Parameters**: `Configuration="Release"`, `Architecture="x64"`, `TestSuite="All"` +- This is mandatory for every batch, regardless of whether the upstream endpoint commit had successful CI. +- If any suite fails, re-run only the failing suite while fixing (`TestSuite="Unit"`, `TestSuite="Bash"`, `TestSuite="E2E"`). +- For bash triage, run a single failing test with `BashTestFilePath`. +- Do not proceed to the next batch until the full suite passes (or user explicitly approves an exception). + ## Testing Automation Framework ### Automated Test Execution diff --git a/.github/instructions/merge/merge-process-overview.instructions.md b/.github/instructions/merge/merge-process-overview.instructions.md index 8cfa7b8de472..e2787a0edaa9 100644 --- a/.github/instructions/merge/merge-process-overview.instructions.md +++ b/.github/instructions/merge/merge-process-overview.instructions.md @@ -18,7 +18,7 @@ Ensure the following tools are installed and configured before proceeding: ## Process Overview The merge process uses a **two-phase approach** to preserve upstream commit history while keeping conflict resolution manageable: -1. **Scratch branch** — Incremental `git merge` at batch boundaries. Build and test after each batch. Every conflict resolution is recorded via `git rerere` and a resolution log. +1. **Scratch branch** — Incremental `git merge` at batch boundaries. Build and run the full CI test suite after each batch. Every conflict resolution is recorded via `git rerere` and a resolution log. 2. **Real branch** — A single `git merge` of the final upstream target. Recorded resolutions are replayed automatically. This produces one merge commit with all upstream SHAs intact. The process consists of several interconnected phases: @@ -196,16 +196,19 @@ The process consists of several interconnected phases: ``` Commit any build fixes separately with descriptive messages (only actual code changes) -10. **Validate if batch ended with successful CI:** - Check the end commit's CI status from Get-CommitGroups output. - If CI was successful, run validation: - - **MCP Tool Name**: `mcp_openssh-server_Test_OpenSSHFunctionality` - - **Parameters**: (use defaults for Release/x64) +10. **Run full CI validation after every batch (mandatory):** + Run the full OpenSSH CI suite regardless of upstream CI status for the batch endpoint. + - **MCP Tool Name**: `mcp_openssh-server_Invoke_OpenSSHTests` + - **Parameters**: `Configuration="Release"`, `Architecture="x64"`, `TestSuite="All"` - If no CI or failed CI, skip validation (build success is sufficient). + If any suite fails: + - Capture failing suite details from tool output + - Re-run only the failing suite to iterate faster (`TestSuite="Unit"`, `TestSuite="Bash"`, or `TestSuite="E2E"`) + - For a single failing bash case, use `TestSuite="Bash"` and `BashTestFilePath=""` + - Fix issues and re-run full suite before proceeding to the next batch 11. **Provide summary and get approval:** - - Summarize batch changes, conflicts resolved, build status, validation status + - Summarize batch changes, conflicts resolved, build status, and full CI suite status (Unit/Bash/E2E) - Wait for user approval before proceeding to next batch - Document next steps (starting commit for next batch) - After all batches complete on the scratch branch, proceed to the Real Branch Phase diff --git a/.github/instructions/testing.instructions.md b/.github/instructions/testing.instructions.md index f4544d8b5877..5ad56413cc40 100644 --- a/.github/instructions/testing.instructions.md +++ b/.github/instructions/testing.instructions.md @@ -98,6 +98,92 @@ The MCP tool performs comprehensive end-to-end testing including: - Before creating pull requests - When debugging SSH connectivity issues +## Full CI Test Suite + +For thorough validation (e.g., before submitting a PR or after a significant merge), run the complete CI test suite: unit tests, bash regression tests, and Pester E2E tests. + +Reference: https://github.com/PowerShell/Win32-OpenSSH/wiki/Run-OpenSSH-Pester-Tests + +### Using the Invoke-OpenSSHTests MCP Tool (Recommended) + +Use the Invoke-OpenSSHTests MCP tool: +- **MCP Tool Name**: `mcp_openssh-server_Invoke_OpenSSHTests` +- **Parameters**: + - `Configuration` (optional): "Debug" or "Release" (default: "Release") + - `Architecture` (optional): "x64", "x86", "ARM", "ARM64" (default: "x64") + - `TestSuite` (optional): "All", "Unit", "Bash", "E2E" — one or more values (default: "All") + - `BashTestFilePath` (optional): Absolute path to a single `.sh` test file for targeted bash testing (e.g., `C:\repos\openssh-portable\regress\banner.sh`) + - `BashShellPath` (optional): Path to `sh.exe` — auto-detected from common Cygwin locations if omitted + - `NoCleanup` (optional): Skip `Clear-OpenSSHTestEnvironment` after the run (default: false) + - `SkipSetup` (optional): Skip `Set-OpenSSHTestEnvironment` when environment is already configured (default: false) + +**The tool returns a structured result with:** +- `Success`: Overall pass/fail +- `UnitTestsPassed`, `BashTestsPassed`, `E2ETestsPassed`: Per-suite results (`$true`/`$false`/`$null` if not run) +- `UnitTestOutput`, `BashTestOutput`, `E2ETestOutput`: Captured output for each suite +- `Errors`: Array of failure messages +- `Warnings`: Known gotchas and environment notes +- `Message`: Summary + +**Examples:** +- Run full suite: (no parameters needed) +- Run only E2E tests: `TestSuite="E2E"` +- Run a single bash test: `TestSuite="Bash"`, `BashTestFilePath="C:\repos\openssh-portable\regress\banner.sh"` + +### Manually Running the Full CI Suite + +Binaries are expected at `C:\repos\openssh-portable\bin\{Architecture}\{Configuration}`. + +```pwsh +# 1. Import the test helper module +Import-Module C:\repos\openssh-portable\contrib\win32\openssh\OpenSSHTestHelper.psm1 -Force + +# 2. Configure the test environment (installs test accounts, sshd test service, etc.) +# This modifies known_hosts and ssh_config; run Clear-OpenSSHTestEnvironment to undo. +Set-OpenSSHTestEnvironment -OpenSSHBinPath "C:\repos\openssh-portable\bin\x64\Release" -Confirm:$false + +# 3. Run unit tests (unittest-*.exe binaries in the bin folder) +Invoke-OpenSSHUnitTest + +# 4. Run bash regression tests (requires Cygwin sh.exe) +Invoke-OpenSSHBashTests + +# 5. Run Pester E2E tests +Invoke-OpenSSHE2ETest + +# 6. Clean up test accounts, service, and ssh config changes +Clear-OpenSSHTestEnvironment +``` + +### Running a Single Bash Test + +Use `bash_tests_iterator.ps1` to run one bash test file in isolation: + +```pwsh +.\contrib\win32\openssh\bash_tests_iterator.ps1 ` + -OpenSSHBinPath "C:\repos\openssh-portable\bin\x64\Release" ` + -BashTestsPath "C:\repos\openssh-portable\regress" ` + -ShellPath "C:\cygwin64\bin\sh.exe" ` + -TestFilePath "C:\repos\openssh-portable\regress\banner.sh" +``` + +### Known CI Test Gotchas + +**`cfginclude.sh` — wrong PowerShell executable:** +The test calls `powershell.exe` directly. When running under `pwsh.exe`, the test will fail unless the file is edited to replace `powershell.exe` with `pwsh.exe`. +See: https://github.com/PowerShell/PowerShell/issues/18530#issuecomment-1325691850 + +**WSMan / Port Forwarding tests — disabled on some VMs:** +The WSMan and port-forwarding Pester tests may fail on VMs where these Windows features are disabled by default. Options: +- Enable the features: turn on "Windows Remote Management" and ensure port-forward firewall rules are allowed. +- Skip the affected test files (e.g., `PortForwarding.Tests.ps1`) when running `Invoke-OpenSSHE2ETest` for routine validation. + +**Pester version requirement:** +The E2E tests require **Pester version < 5**. The helper module will attempt to install Pester 3.4.6 via chocolatey if a compatible version is not found. + +**Cygwin required for bash tests:** +`Invoke-OpenSSHBashTests` auto-detects `sh.exe` at `%SystemDrive%\cygwin64\bin\sh.exe`, `%SystemDrive%\cygwin\bin\sh.exe`, or `%SystemDrive%\tools\cygwin\bin\sh.exe`. If none is found it installs Cygwin via chocolatey. Provide `-BashShellPath` to the MCP tool to override. + ## Validation Scenario Override: Entra-ID Debug Localhost Use this scenario when the prompt explicitly declares `Validation scenario=entra-id-debug-localhost`. @@ -286,7 +372,13 @@ Get-NetFirewallRule | Where-Object {$_.DisplayName -like "*SSH*"} 3. **If test fails**, use manual procedures and debug mode to diagnose issues -4. **Document results** in commit message or merge documentation +4. **For full CI validation** (e.g., before creating a PR), run the complete test suite: + - **MCP Tool Name**: `mcp_openssh-server_Invoke_OpenSSHTests` + - **Parameters**: (use defaults to run all suites) + - If a specific suite fails, re-run it in isolation using `TestSuite="Unit"`, `TestSuite="Bash"`, or `TestSuite="E2E"` + - For a single failing bash test: `TestSuite="Bash"`, `BashTestFilePath=""` + +5. **Document results** in commit message or merge documentation ## Manual Test Environment Cleanup diff --git a/.github/tools/Invoke-OpenSSHTests.ps1 b/.github/tools/Invoke-OpenSSHTests.ps1 new file mode 100644 index 000000000000..bcb3be929b30 --- /dev/null +++ b/.github/tools/Invoke-OpenSSHTests.ps1 @@ -0,0 +1,338 @@ +<# +.SYNOPSIS + Runs the OpenSSH full CI test suite (unit tests, bash tests, and E2E/Pester tests). + +.DESCRIPTION + This script automates the full OpenSSH CI test workflow on Windows using the + OpenSSHTestHelper module. It supports running all test suites together or + individual suites, with optional single-test targeting for bash tests. + + Test suites: + - Unit: Runs unittest-*.exe binaries found under the binary path + - Bash: Runs upstream bash regression tests via Cygwin sh.exe + - E2E: Runs Windows Pester-based end-to-end tests (requires Pester < 5) + + The workflow is: + 1. Import OpenSSHTestHelper module + 2. Set-OpenSSHTestEnvironment (installs test accounts, sshd test service, etc.) + 3. Run selected test suites + 4. Clear-OpenSSHTestEnvironment (unless -NoCleanup) + + Reference: https://github.com/PowerShell/Win32-OpenSSH/wiki/Run-OpenSSH-Pester-Tests + +.PARAMETER Configuration + Build configuration. Valid values: 'Debug', 'Release'. Default: 'Release'. + +.PARAMETER Architecture + Target architecture. Valid values: 'x64', 'x86', 'ARM', 'ARM64'. Default: 'x64'. + +.PARAMETER TestSuite + Which test suites to run. Valid values: 'All', 'Unit', 'Bash', 'E2E'. + Default: 'All'. Multiple values allowed. + +.PARAMETER BashTestFilePath + Run a single bash test file instead of the full bash suite. + Must be an absolute path to a .sh file under the regress folder. + Example: C:\repos\openssh-portable\regress\banner.sh + Only applies when TestSuite includes 'Bash'. + +.PARAMETER BashShellPath + Path to sh.exe (Cygwin or WSL). Auto-detected from common Cygwin locations + if not specified. Example: C:\cygwin64\bin\sh.exe + +.PARAMETER NoCleanup + Skip Clear-OpenSSHTestEnvironment at the end. Useful for debugging failures. + +.PARAMETER SkipSetup + Skip Set-OpenSSHTestEnvironment. Use when environment is already configured. + +.EXAMPLE + .\Invoke-OpenSSHTests.ps1 + Runs all test suites with Release x64 binaries. + +.EXAMPLE + .\Invoke-OpenSSHTests.ps1 -TestSuite Unit + Runs only unit tests. + +.EXAMPLE + .\Invoke-OpenSSHTests.ps1 -TestSuite E2E -Configuration Debug + Runs only Pester E2E tests using Debug binaries. + +.EXAMPLE + .\Invoke-OpenSSHTests.ps1 -TestSuite Bash -BashTestFilePath C:\repos\openssh-portable\regress\banner.sh + Runs a single bash test. + +.NOTES + Requires Administrator privileges. + Pester < 5 required for E2E tests (the helper will install via chocolatey if needed). + Cygwin (sh.exe) required for bash tests. + + Known gotchas: + - cfginclude.sh calls powershell.exe; if running under pwsh.exe, edit the test to use pwsh.exe. + See https://github.com/PowerShell/PowerShell/issues/18530#issuecomment-1325691850 + - WSMan and Port Forwarding tests may be disallowed on some VMs by default. + Enable the features or skip the affected tests. +#> + +[CmdletBinding()] +param( + [Parameter()] + [ValidateSet('Debug', 'Release')] + [string]$Configuration = 'Release', + + [Parameter()] + [ValidateSet('x64', 'x86', 'ARM', 'ARM64')] + [string]$Architecture = 'x64', + + [Parameter()] + [ValidateSet('All', 'Unit', 'Bash', 'E2E')] + [string[]]$TestSuite = @('All'), + + [Parameter()] + [string]$BashTestFilePath = '', + + [Parameter()] + [string]$BashShellPath = '', + + [Parameter()] + [switch]$NoCleanup, + + [Parameter()] + [switch]$SkipSetup +) + +# ────────────────────────────────────────────────────────────────────────────── +# Resolve paths +# ────────────────────────────────────────────────────────────────────────────── +$scriptRoot = Split-Path -Parent $PSCommandPath +$repoRoot = Split-Path -Parent (Split-Path -Parent $scriptRoot) +$binPath = Join-Path $repoRoot "bin\$Architecture\$Configuration" +$helperModule = Join-Path $repoRoot "contrib\win32\openssh\OpenSSHTestHelper.psm1" +$bashIterator = Join-Path $repoRoot "contrib\win32\openssh\bash_tests_iterator.ps1" +$regressPath = Join-Path $repoRoot "regress" + +# ────────────────────────────────────────────────────────────────────────────── +# Result object +# ────────────────────────────────────────────────────────────────────────────── +$result = [PSCustomObject]@{ + Success = $false + UnitTestsPassed = $null # $true/$false/$null (not run) + BashTestsPassed = $null + E2ETestsPassed = $null + UnitTestOutput = $null + BashTestOutput = $null + E2ETestOutput = $null + Errors = @() + Warnings = @() + Message = '' +} + +$moduleImported = $false +$setupCompleted = $false + +function Write-StepHeader([string]$msg) { + Write-Host "" + Write-Host "=== $msg ===" -ForegroundColor Cyan +} + +$runUnit = $TestSuite -contains 'All' -or $TestSuite -contains 'Unit' +$runBash = $TestSuite -contains 'All' -or $TestSuite -contains 'Bash' +$runE2E = $TestSuite -contains 'All' -or $TestSuite -contains 'E2E' + +try { + # ── Admin check ────────────────────────────────────────────────────────── + $isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole( + [Security.Principal.WindowsBuiltInRole]"Administrator") + if (-not $isAdmin) { + $result.Errors += "Administrator privileges required." + $result.Message = "FAILED: Must be run as Administrator." + Write-Host "✗ Administrator privileges required." -ForegroundColor Red + return $result + } + + # ── Verify binaries ────────────────────────────────────────────────────── + if (-not (Test-Path (Join-Path $binPath "ssh.exe"))) { + $result.Errors += "Binaries not found at $binPath. Build the project first." + $result.Message = "FAILED: Build artifacts not found at $binPath." + Write-Host "✗ Binaries not found at $binPath" -ForegroundColor Red + return $result + } + Write-Host "✓ Binaries found at $binPath" -ForegroundColor Green + + # ── Import helper module ───────────────────────────────────────────────── + Write-StepHeader "Importing OpenSSHTestHelper" + if (-not (Test-Path $helperModule)) { + $result.Errors += "OpenSSHTestHelper.psm1 not found at $helperModule" + $result.Message = "FAILED: OpenSSHTestHelper module not found." + Write-Host "✗ Module not found: $helperModule" -ForegroundColor Red + return $result + } + Import-Module $helperModule -Force + $moduleImported = $true + Write-Host "✓ Module imported" -ForegroundColor Green + + # ── Set-OpenSSHTestEnvironment ─────────────────────────────────────────── + if (-not $SkipSetup) { + Write-StepHeader "Setting Up Test Environment" + Write-Host " OpenSSHBinPath: $binPath" + Set-OpenSSHTestEnvironment -OpenSSHBinPath $binPath -Confirm:$false + $setupCompleted = $true + Write-Host "✓ Test environment configured" -ForegroundColor Green + } else { + Write-Host "⚠ Skipping Set-OpenSSHTestEnvironment (-SkipSetup specified)" -ForegroundColor Yellow + $result.Warnings += "Setup skipped — environment must already be configured." + } + + # ── Unit Tests ─────────────────────────────────────────────────────────── + if ($runUnit) { + Write-StepHeader "Running Unit Tests" + try { + # Force unit test discovery to the selected build output path. + $unitOutput = Invoke-OpenSSHUnitTest -UnitTestDirectory $binPath *>&1 | Tee-Object -Variable unitCapture + $unitText = $unitCapture | Out-String + $result.UnitTestOutput = $unitText + + # Detect failure: unit test runner writes "failed" to output or exits non-zero + if ($unitText -match 'failed') { + $result.UnitTestsPassed = $false + $result.Errors += "Unit tests reported failures. See UnitTestOutput for details." + Write-Host "✗ Unit tests: FAILED" -ForegroundColor Red + } else { + $result.UnitTestsPassed = $true + Write-Host "✓ Unit tests: PASSED" -ForegroundColor Green + } + } catch { + $result.UnitTestsPassed = $false + $result.Errors += "Unit test exception: $_" + Write-Host "✗ Unit tests threw an exception: $_" -ForegroundColor Red + } + } + + # ── Bash Tests ─────────────────────────────────────────────────────────── + if ($runBash) { + Write-StepHeader "Running Bash Tests" + $result.Warnings += "cfginclude.sh gotcha: calls powershell.exe; if running under pwsh, edit the test to use pwsh.exe (see https://github.com/PowerShell/PowerShell/issues/18530#issuecomment-1325691850)." + + try { + if (-not [string]::IsNullOrEmpty($BashTestFilePath)) { + # Single bash test via iterator. + $resolvedShellPath = $BashShellPath + if ([string]::IsNullOrEmpty($resolvedShellPath) -or -not (Test-Path $resolvedShellPath)) { + throw "BashShellPath is required for single-test mode." + } + + Write-Host " Shell: $resolvedShellPath" + Write-Host " Running single test: $BashTestFilePath" + $bashOutput = & $bashIterator ` + -OpenSSHBinPath $binPath ` + -BashTestsPath $regressPath ` + -ShellPath $resolvedShellPath ` + -TestFilePath $BashTestFilePath ` + *>&1 | Tee-Object -Variable bashCapture + } else { + # Full bash suite via helper (helper handles Cygwin install/detection). + Write-Host " Running full bash test suite..." + $bashOutput = Invoke-OpenSSHBashTests *>&1 | Tee-Object -Variable bashCapture + } + + $bashText = $bashCapture | Out-String + $result.BashTestOutput = $bashText + + if ($bashText -match 'FAILED|not ok') { + $result.BashTestsPassed = $false + $result.Errors += "Bash tests reported failures. See BashTestOutput for details." + Write-Host "✗ Bash tests: FAILED" -ForegroundColor Red + } else { + $result.BashTestsPassed = $true + Write-Host "✓ Bash tests: PASSED" -ForegroundColor Green + } + } catch { + $result.BashTestsPassed = $false + $result.Errors += "Bash test exception: $_" + Write-Host "✗ Bash tests threw an exception: $_" -ForegroundColor Red + } + } + + # ── E2E / Pester Tests ─────────────────────────────────────────────────── + if ($runE2E) { + Write-StepHeader "Running E2E Pester Tests" + $result.Warnings += "WSMan and Port Forwarding tests may fail on some VMs where those features are disabled. Enable them in Windows Features or skip those test files." + Write-Host " ⚠ Note: WSMan/Port Forwarding may need to be enabled on this machine." -ForegroundColor Yellow + + try { + $e2eOutput = Invoke-OpenSSHE2ETest *>&1 | Tee-Object -Variable e2eCapture + $e2eText = $e2eCapture | Out-String + $result.E2ETestOutput = $e2eText + + if ($e2eText -match 'Failed\s*:\s*[1-9]|Tests failed') { + $result.E2ETestsPassed = $false + $result.Errors += "E2E tests reported failures. See E2ETestOutput for details." + Write-Host "✗ E2E Pester tests: FAILED" -ForegroundColor Red + } else { + $result.E2ETestsPassed = $true + Write-Host "✓ E2E Pester tests: PASSED" -ForegroundColor Green + } + } catch { + $result.E2ETestsPassed = $false + $result.Errors += "E2E test exception: $_" + Write-Host "✗ E2E tests threw an exception: $_" -ForegroundColor Red + } + } + + # ── Overall result ─────────────────────────────────────────────────────── + $anyFailed = ($result.UnitTestsPassed -eq $false) -or + ($result.BashTestsPassed -eq $false) -or + ($result.E2ETestsPassed -eq $false) + + $result.Success = -not $anyFailed + $result.Message = if ($result.Success) { "All selected test suites passed." } ` + else { "One or more test suites failed. See Errors for details." } + +} catch { + $result.Errors += "Unexpected error: $_" + $result.Message = "FAILED: Unexpected error — $_" + Write-Host "✗ Unexpected error: $_" -ForegroundColor Red +} finally { + # ── Cleanup ────────────────────────────────────────────────────────────── + if (-not $NoCleanup -and -not $SkipSetup -and $moduleImported -and $setupCompleted) { + Write-StepHeader "Cleaning Up Test Environment" + try { + Clear-OpenSSHTestEnvironment + Write-Host "✓ Test environment cleaned up" -ForegroundColor Green + } catch { + $result.Warnings += "Cleanup warning: $_" + Write-Host "⚠ Cleanup encountered an issue: $_" -ForegroundColor Yellow + } + } elseif (-not $NoCleanup -and -not $SkipSetup -and (-not $moduleImported -or -not $setupCompleted)) { + $result.Warnings += "Cleanup skipped because setup did not complete." + Write-Host "⚠ Cleanup skipped because setup did not complete." -ForegroundColor Yellow + } elseif ($NoCleanup) { + Write-Host "⚠ Skipping cleanup (-NoCleanup specified). Run Clear-OpenSSHTestEnvironment manually." -ForegroundColor Yellow + } +} + +# ── Summary ─────────────────────────────────────────────────────────────────── +Write-Host "" +Write-Host "=== Test Summary ===" -ForegroundColor Cyan +Write-Host "Overall: $(if ($result.Success) { '✓ PASSED' } else { '✗ FAILED' })" -ForegroundColor $(if ($result.Success) { 'Green' } else { 'Red' }) +if ($null -ne $result.UnitTestsPassed) { + Write-Host "Unit Tests: $(if ($result.UnitTestsPassed) { '✓ PASSED' } else { '✗ FAILED' })" -ForegroundColor $(if ($result.UnitTestsPassed) { 'Green' } else { 'Red' }) +} +if ($null -ne $result.BashTestsPassed) { + Write-Host "Bash Tests: $(if ($result.BashTestsPassed) { '✓ PASSED' } else { '✗ FAILED' })" -ForegroundColor $(if ($result.BashTestsPassed) { 'Green' } else { 'Red' }) +} +if ($null -ne $result.E2ETestsPassed) { + Write-Host "E2E Tests: $(if ($result.E2ETestsPassed) { '✓ PASSED' } else { '✗ FAILED' })" -ForegroundColor $(if ($result.E2ETestsPassed) { 'Green' } else { 'Red' }) +} +if ($result.Warnings.Count -gt 0) { + Write-Host "" + Write-Host "Warnings:" -ForegroundColor Yellow + $result.Warnings | ForEach-Object { Write-Host " ⚠ $_" -ForegroundColor Yellow } +} +if ($result.Errors.Count -gt 0) { + Write-Host "" + Write-Host "Errors:" -ForegroundColor Red + $result.Errors | ForEach-Object { Write-Host " ✗ $_" -ForegroundColor Red } +} + +return $result From ff950b70fc6d3f9d907256b3f7270f55aa4e1996 Mon Sep 17 00:00:00 2001 From: Tess Gauthier Date: Mon, 20 Apr 2026 16:54:44 -0400 Subject: [PATCH 235/244] Fix unittest benchmark compatibility after batch 1 merge - Resolve leftover conflict markers in test_helper.c - Add CLOCK_REALTIME fallback define for Windows unit tests - Add benchmarks() entry point in win32compat unit tests to satisfy benchmark harness linking --- regress/unittests/test_helper/test_helper.c | 7 ++++--- regress/unittests/win32compat/tests.c | 6 ++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/regress/unittests/test_helper/test_helper.c b/regress/unittests/test_helper/test_helper.c index fcdf0de65bd1..097fd1033065 100644 --- a/regress/unittests/test_helper/test_helper.c +++ b/regress/unittests/test_helper/test_helper.c @@ -60,6 +60,10 @@ #define BENCH_COLUMN_WIDTH 40 #define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) + +#ifndef CLOCK_REALTIME +# define CLOCK_REALTIME 0 +#endif #define TEST_CHECK_INT(r, pred) do { \ switch (pred) { \ @@ -450,7 +454,6 @@ assert_string(const char *file, int line, const char *a1, const char *a2, test_die(); } -<<<<<<< HEAD static char * tohex(const void *_s, size_t l) { @@ -468,8 +471,6 @@ tohex(const void *_s, size_t l) return r; } -======= ->>>>>>> f3d465530e75cb6c02e2cde1d15e6c4bb51ebfd9 void assert_mem(const char *file, int line, const char *a1, const char *a2, const void *aa1, const void *aa2, size_t l, enum test_predicate pred) diff --git a/regress/unittests/win32compat/tests.c b/regress/unittests/win32compat/tests.c index ae27730dc757..756d6b8b394c 100644 --- a/regress/unittests/win32compat/tests.c +++ b/regress/unittests/win32compat/tests.c @@ -27,6 +27,12 @@ tests() miscellaneous_tests(); } +void +benchmarks(void) +{ + tests(); +} + char * dup_str(char *inStr) { From 9640f12204e693b88f40a902cf5487da70ffda93 Mon Sep 17 00:00:00 2001 From: Tess Gauthier Date: Mon, 4 May 2026 13:05:16 -0400 Subject: [PATCH 236/244] Build fixes for batch 9 (V_10_3_P1 merge): misc-agent.c on Windows Upstream commit 80162f9d7 (Move agent listener sockets to ~/.ssh/agent) split agent listener code from session.c and ssh-agent.c into a new file misc-agent.c. Windows fixes: - misc-agent.c: Added include includes.h to pull in win32compat shims. - misc-agent.c: Wrapped socket_is_stale and agent_cleanup_stale in ifndef WINDOWS since they use Unix-only APIs (DT_SOCK, DT_UNKNOWN, dirent.d_type, dirfd, fstatat, unlinkat, st_mtim, timespeccmp, timespecsub, CLOCK_REALTIME) and are only called from upstream ssh-agent.c, which is not built on Windows (Windows uses a separate ssh-agent implementation under contrib/win32/win32compat/ssh-agent). - sshd-auth.vcxproj, sshd-session.vcxproj: Added misc-agent.c so that agent_listener (called from session.c) is linked. Resolves LNK2001 unresolved external symbol agent_listener. agent_listener and its helpers remain available because session.c (built on Windows) calls them; the underlying AF_UNIX socket APIs are supported via win32compat. --- contrib/win32/openssh/sshd-auth.vcxproj | 1 + contrib/win32/openssh/sshd-session.vcxproj | 1 + misc-agent.c | 4 +++- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/contrib/win32/openssh/sshd-auth.vcxproj b/contrib/win32/openssh/sshd-auth.vcxproj index fd3a28e06214..24d5426e513d 100644 --- a/contrib/win32/openssh/sshd-auth.vcxproj +++ b/contrib/win32/openssh/sshd-auth.vcxproj @@ -461,6 +461,7 @@ + diff --git a/contrib/win32/openssh/sshd-session.vcxproj b/contrib/win32/openssh/sshd-session.vcxproj index 45895f0e1bf2..48cd1f6eab02 100644 --- a/contrib/win32/openssh/sshd-session.vcxproj +++ b/contrib/win32/openssh/sshd-session.vcxproj @@ -462,6 +462,7 @@ + diff --git a/misc-agent.c b/misc-agent.c index d065ab0e5b7a..dd12fc273fea 100644 --- a/misc-agent.c +++ b/misc-agent.c @@ -13,7 +13,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ - +#include "includes.h" #include #include #include @@ -217,6 +217,7 @@ agent_listener(const char *homedir, const char *tag, int *sockp, char **pathp) return 0; } +#ifndef WINDOWS static int socket_is_stale(const char *path) { @@ -326,4 +327,5 @@ agent_cleanup_stale(const char *homedir, int ignore_hosthash) free(dirpath); free(prefix); } +#endif /* !WINDOWS */ From df32151d714bf7461721020bf2ad3f1f2efa89aa Mon Sep 17 00:00:00 2001 From: Tess Gauthier Date: Mon, 4 May 2026 14:18:50 -0400 Subject: [PATCH 237/244] Remove ssh-dss.c from libssh.vcxproj after upstream DSA removal Upstream removed ssh-dss.c in batch 15 (commit 93e904a). Build was failing with C1083 because libssh.vcxproj still referenced the deleted source file. Unit test errors (KEY_DSA, sshkey.dsa) will be resolved by upstream commits in batch 16. --- contrib/win32/openssh/libssh.vcxproj | 3 --- 1 file changed, 3 deletions(-) diff --git a/contrib/win32/openssh/libssh.vcxproj b/contrib/win32/openssh/libssh.vcxproj index c6cfe93058f3..dacb2ad311d7 100644 --- a/contrib/win32/openssh/libssh.vcxproj +++ b/contrib/win32/openssh/libssh.vcxproj @@ -422,9 +422,6 @@ - - true - true From 5e6a43443533c5ffa574bcd5b3472a5579e599cc Mon Sep 17 00:00:00 2001 From: Tess Gauthier Date: Thu, 7 May 2026 11:58:34 -0400 Subject: [PATCH 238/244] Define HAVE_DIRFD=1 on Windows to skip upstream's dirfd() compat shim Upstream batch 19 commit 1511f11 added a no-op dirfd() implementation in openbsd-compat/bsd-misc.{c,h} guarded by #ifndef HAVE_DIRFD. The header pulls in , which on Windows transitively declares a 1-arg system mkdir() prototype. The win32compat sys/stat.h then macro-renames it to w32_mkdir(const char*), conflicting with the real 2-arg w32_mkdir declaration and breaking hostfile.c (and any other file that includes dirent.h via this path).\n\ndirfd is not used on Windows: misc-agent.c users are wrapped in #ifndef WINDOWS, and openbsd-compat shims are not built. Defining HAVE_DIRFD=1 disables the conflicting prototype. --- contrib/win32/openssh/config.h.vs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contrib/win32/openssh/config.h.vs b/contrib/win32/openssh/config.h.vs index 3a19ea051ca9..80f2635ecaaa 100644 --- a/contrib/win32/openssh/config.h.vs +++ b/contrib/win32/openssh/config.h.vs @@ -352,7 +352,9 @@ /* #undef HAVE_DIRENT_H */ /* Define to 1 if you have the `dirfd' function. */ -/* #undef HAVE_DIRFD */ +/* Defined on Windows to suppress upstream's dirfd() compat prototype which + * pulls in and conflicts with the win32compat mkdir macro mapping. */ +#define HAVE_DIRFD 1 /* Define to 1 if you have the `dirname' function. */ /* #define HAVE_DIRNAME 1 */ From 021587df7a800f2f4163b7b63375bc2aaeb17a4d Mon Sep 17 00:00:00 2001 From: Tess Gauthier Date: Tue, 12 May 2026 10:43:46 -0400 Subject: [PATCH 239/244] Build fix: include ssh-gss.h before monitor_wrap.h in sshd.c Commit 0cf38d74 added #include monitor_wrap.h to sshd.c. On Windows GSSAPI is defined for the sshd listener (sshd.vcxproj), so monitor_wrap.h references Gssctxt/gss_OID, which require ssh-gss.h to be included first. sshd-session.c and sshd-auth.c already include ssh-gss.h before monitor_wrap.h; mirror that pattern in sshd.c (guarded by #ifdef GSSAPI). --- sshd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sshd.c b/sshd.c index e0a18067e1df..b1da09382e87 100644 --- a/sshd.c +++ b/sshd.c @@ -100,6 +100,9 @@ #include "addr.h" #include "srclimit.h" #include "atomicio.h" +#ifdef GSSAPI +#include "ssh-gss.h" +#endif #include "monitor_wrap.h" /* Re-exec fds */ From bc793b6567b3b3da7f03c495be1fc074499ebf8f Mon Sep 17 00:00:00 2001 From: Tess Gauthier Date: Mon, 22 Jun 2026 17:15:51 -0400 Subject: [PATCH 240/244] Windows build fixes for PKCS#11 client migration: restore ssh-agent key registry and init label Restore the Windows ssh-agent in-memory key registry (add_key/del_all_keys/lookup_key with pkcs11_keylist TAILQ) that keyagent-request.c links against; these were dropped when ssh-pkcs11-client.c adopted upstream's rewritten architecture. Also TAILQ_INIT the keylist in pkcs11_init and initialize label=NULL in pkcs11_add_provider to satisfy MSVC C4703 (fatal_fr noreturn not recognized). --- ssh-pkcs11-client.c | 59 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/ssh-pkcs11-client.c b/ssh-pkcs11-client.c index 085d604d9932..ba59173cce93 100644 --- a/ssh-pkcs11-client.c +++ b/ssh-pkcs11-client.c @@ -53,6 +53,60 @@ extern char *sshagent_con_username; extern HANDLE sshagent_client_primary_token; static char module_path[PATH_MAX + 1]; +#include "openbsd-compat/sys-queue.h" + +/* + * In-memory registry of keys held by the Windows ssh-agent. These functions + * are consumed by the Windows agent's keyagent-request.c and are independent + * of the upstream helper-subprocess delegation below. + */ +struct pkcs11_keyinfo { + struct sshkey *key; + char *providername, *label; + TAILQ_ENTRY(pkcs11_keyinfo) next; +}; + +TAILQ_HEAD(, pkcs11_keyinfo) pkcs11_keylist; + +void +add_key(struct sshkey *k, char *name) +{ + struct pkcs11_keyinfo *ki; + + ki = xcalloc(1, sizeof(*ki)); + ki->providername = xstrdup(name); + ki->key = k; + TAILQ_INSERT_TAIL(&pkcs11_keylist, ki, next); +} + +void +del_all_keys() +{ + struct pkcs11_keyinfo *ki, *nxt; + + for (ki = TAILQ_FIRST(&pkcs11_keylist); ki; ki = nxt) { + nxt = TAILQ_NEXT(ki, next); + TAILQ_REMOVE(&pkcs11_keylist, ki, next); + free(ki->providername); + sshkey_free(ki->key); + free(ki); + } +} + +/* lookup matching 'private' key */ +struct sshkey * +lookup_key(const struct sshkey *k) +{ + struct pkcs11_keyinfo *ki; + + TAILQ_FOREACH(ki, &pkcs11_keylist, next) { + debug("check %p %s %s", ki, ki->providername, ki->label); + if (sshkey_equal(k, ki->key)) + return (ki->key); + } + return (NULL); +} + static char * find_helper_in_module_path(void) { @@ -274,6 +328,9 @@ recv_msg(int fd, struct sshbuf *m) int pkcs11_init(int interactive) { +#ifdef WINDOWS + TAILQ_INIT(&pkcs11_keylist); +#endif /* WINDOWS */ return 0; } @@ -542,7 +599,7 @@ pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp, { struct sshkey *k; int r, type; - char *label; + char *label = NULL; u_int ret = -1, nkeys, i; struct sshbuf *msg; struct helper *helper; From 0850e29dcb05ea896d253edfbfefa7b148069289 Mon Sep 17 00:00:00 2001 From: Tess Gauthier Date: Thu, 25 Jun 2026 17:02:36 -0400 Subject: [PATCH 241/244] add windows #ifdef --- ssh-pkcs11-client.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ssh-pkcs11-client.c b/ssh-pkcs11-client.c index 534d39a9b603..0af29a55c72e 100644 --- a/ssh-pkcs11-client.c +++ b/ssh-pkcs11-client.c @@ -599,7 +599,11 @@ pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp, { struct sshkey *k; int r, type; +#ifdef WINDOWS char *label = NULL; +#else + char *label; +#endif /* WINDOWS */ u_int ret = -1, nkeys, i; struct sshbuf *msg; struct helper *helper; From eac4491079929e0624cc2603f85809885048d442 Mon Sep 17 00:00:00 2001 From: Tess Gauthier Date: Fri, 26 Jun 2026 15:05:42 -0400 Subject: [PATCH 242/244] Guard upstream SIGINFO handlers with #ifdef SIGINFO for Windows Upstream commits f807a598c (ssh) and dc5147028 (sshd) added SIGINFO handlers to dump active channels. SIGINFO is BSD-specific and undefined on Windows, causing C2065 errors. Guard the handler functions and signal registrations with #ifdef SIGINFO, matching the existing portable idiom used in sshd.c and session.c. --- clientloop.c | 10 ++++++++-- serverloop.c | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/clientloop.c b/clientloop.c index 88c6054a17cd..5602482e1b8a 100644 --- a/clientloop.c +++ b/clientloop.c @@ -225,12 +225,14 @@ window_change_handler(int sig) received_window_change_signal = 1; } +#ifdef SIGINFO /* Signal handler for SIGINFO */ static void siginfo_handler(int sig) { siginfo_received = 1; } +#endif /* * Signal handler for signals that cause the program to terminate. These @@ -1530,7 +1532,9 @@ client_loop(struct ssh *ssh, int have_pty, int escape_char_arg, if (ssh_signal(SIGTERM, SIG_IGN) != SIG_IGN) ssh_signal(SIGTERM, signal_handler); ssh_signal(SIGWINCH, window_change_handler); +#ifdef SIGINFO ssh_signal(SIGINFO, siginfo_handler); +#endif if (have_pty) enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE); @@ -1553,8 +1557,10 @@ client_loop(struct ssh *ssh, int have_pty, int escape_char_arg, sigaddset(&bsigset, SIGHUP) == -1 || sigaddset(&bsigset, SIGINT) == -1 || sigaddset(&bsigset, SIGQUIT) == -1 || - sigaddset(&bsigset, SIGTERM) == -1 || - sigaddset(&bsigset, SIGINFO) == -1) +#ifdef SIGINFO + sigaddset(&bsigset, SIGINFO) == -1 || +#endif + sigaddset(&bsigset, SIGTERM) == -1) error_f("bsigset setup: %s", strerror(errno)); /* Main loop of the client for the interactive session mode. */ diff --git a/serverloop.c b/serverloop.c index dc96288745ea..ca8992a8702d 100644 --- a/serverloop.c +++ b/serverloop.c @@ -104,11 +104,13 @@ sigchld_handler(int sig) child_terminated = 1; } +#ifdef SIGINFO static void siginfo_handler(int sig) { siginfo_received = 1; } +#endif static void client_alive_check(struct ssh *ssh) @@ -334,11 +336,15 @@ server_loop2(struct ssh *ssh, Authctxt *authctxt) debug("Entering interactive session for SSH2."); if (sigemptyset(&bsigset) == -1 || - sigaddset(&bsigset, SIGCHLD) == -1 || - sigaddset(&bsigset, SIGINFO) == -1) +#ifdef SIGINFO + sigaddset(&bsigset, SIGINFO) == -1 || +#endif + sigaddset(&bsigset, SIGCHLD) == -1) error_f("bsigset setup: %s", strerror(errno)); ssh_signal(SIGCHLD, sigchld_handler); +#ifdef SIGINFO ssh_signal(SIGINFO, siginfo_handler); +#endif child_terminated = 0; connection_in = ssh_packet_get_connection_in(ssh); connection_out = ssh_packet_get_connection_out(ssh); From 0a8610f226c5f03765005bed2ecd4733cf5699c9 Mon Sep 17 00:00:00 2001 From: Tess Gauthier Date: Fri, 26 Jun 2026 15:11:36 -0400 Subject: [PATCH 243/244] Remove obsolete ssh_packet_set_interactive args in w32-doexec for QoS refactor Upstream 289239046 changed ssh_packet_set_interactive to take only (ssh, interactive) and now manages IP QoS continually via the channel layer (ssh_packet_set_qos). It removed the set_interactive calls from do_exec_no_pty/do_exec_pty in session.c. Mirror that removal in the Windows w32-doexec.c port to fix C2197 too-many-arguments errors. --- contrib/win32/win32compat/w32-doexec.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/contrib/win32/win32compat/w32-doexec.c b/contrib/win32/win32compat/w32-doexec.c index f996f7ebe5e0..32defa6bc22b 100644 --- a/contrib/win32/win32compat/w32-doexec.c +++ b/contrib/win32/win32compat/w32-doexec.c @@ -473,15 +473,9 @@ int do_exec_windows(struct ssh *ssh, Session *s, const char *command, int pty) { * handle the case that fdin and fdout are the same. */ if (pty) { - /* Set interactive/non-interactive mode */ - ssh_packet_set_interactive(ssh, 1, options.ip_qos_interactive, - options.ip_qos_bulk); session_set_fds(ssh, s, pipein[1], pipeout[0], -1, 1, 1); } else { - /* Set interactive/non-interactive mode */ - ssh_packet_set_interactive(ssh, s->display != NULL, options.ip_qos_interactive, - options.ip_qos_bulk); session_set_fds(ssh, s, pipein[1], pipeout[0], pipeerr[0], s->is_subsystem, 0); } From 8ea89f6a1f396dd0bf64b958386f6df164f0111e Mon Sep 17 00:00:00 2001 From: Tess Gauthier Date: Fri, 26 Jun 2026 15:25:50 -0400 Subject: [PATCH 244/244] Define PLEDGE_EXTRA_INET for Windows build Upstream commits 9184fa3..3ef1a87 added PLEDGE_EXTRA_INET (generated by configure.ac) which clientloop.c prepends to pledge() promise strings. Added an empty define to config.h.vs since Windows pledge is a no-op stub and does not need inet for setsockopt IP_TOS. --- contrib/win32/openssh/config.h.vs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contrib/win32/openssh/config.h.vs b/contrib/win32/openssh/config.h.vs index 80f2635ecaaa..3de8b5b4fb48 100644 --- a/contrib/win32/openssh/config.h.vs +++ b/contrib/win32/openssh/config.h.vs @@ -1393,6 +1393,9 @@ with an extra level of indirection */ /* #undef PAM_SUN_CODEBASE */ +/* need inet in pledge for setsockopt IP_TOS; not required on Windows (pledge is a no-op) */ +#define PLEDGE_EXTRA_INET + /* Work around problematic Linux PAM modules handling of PAM_TTY */ /* #undef PAM_TTY_KLUDGE */