Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wTs8M-000nv4-06 for pgsql-bugs@arkaria.postgresql.org; Mon, 01 Jun 2026 02:12:06 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wTs8K-008RYj-1i for pgsql-bugs@arkaria.postgresql.org; Mon, 01 Jun 2026 02:12:04 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wTs8J-008RYU-2r for pgsql-bugs@lists.postgresql.org; Mon, 01 Jun 2026 02:12:04 +0000 Received: from fout-b5-smtp.messagingengine.com ([202.12.124.148]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1wTs8G-00000000Zg5-32nI for pgsql-bugs@lists.postgresql.org; Mon, 01 Jun 2026 02:12:04 +0000 Received: from phl-compute-02.internal (phl-compute-02.internal [10.202.2.42]) by mailfout.stl.internal (Postfix) with ESMTP id F00301D00010; Sun, 31 May 2026 22:11:57 -0400 (EDT) Received: from phl-frontend-04 ([10.202.2.163]) by phl-compute-02.internal (MEProxy); Sun, 31 May 2026 22:11:58 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=paquier.xyz; h= cc:cc:content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm3; t=1780279917; x=1780366317; bh=roGnxMD9PI pP6ToBthAFDzL2XMtW9bZFK0C/EZWfMIU=; b=tCjRssp6iCSZgDLfcpMTOygiUG d8+Poqa2PxhJ/Ntx936971t6fOJGV7TCcpNdiYa/wtWzZJ+MCBTeGzgCuFxtbuzU Lyl7NPvD5+fuPHed+QCZ27JBL/+De1QeAiWTMC8q1m7PaANmO9h7byQw4OZ3VEc/ dReUPea930qwxdyZMw15SqGNMLe7p9wEnk8gE6idsJQYOqERVy6+wcb9hyZfWTn9 Hqu2csALcBf3Eao3ESdu/T1TtKVeYS+baPrYlrYFgma6aQ5+GdAmfwavnSxJP9PU cJpLMEXdPG4zVYo0BRKsxGJK8YjxjX2mgwsCHxffP9grt5jcRAroiy3F03SA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm3; t= 1780279917; x=1780366317; bh=roGnxMD9PIpP6ToBthAFDzL2XMtW9bZFK0C /EZWfMIU=; b=Hp89p8hkInRklr1z0MZxj1ltKDT6PJ1ZMI3PGYYF+NFGBSGXFxj qnNayLB1HSpRB8eu4+mFYczxkrVX9NTkszff6z0O4y9oB3uHSIPxmG+ogIFoIwGN iLP5NM+xalmWd3oWF1vt33Eim6jEEiIJOVZie9olKLzF2Ibetp0bB36HsDcX4BPR ImbVQbgdJc+wIflvbEF4jG144t1CSn/UxXLZk1qNTfqcMRQjfl58s+x/jiunLHBb k0egUVsxgHak+2mtbDyq9uH4SL/kle3ASfxCjkYIVD2vIM9iDHeeW4rBSVED+Mu/ SvD3+MngMusGajH38eV/0oM+cGRieKr74Ng== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: dmFkZTGlt7oEDW2OeneVsOf35qvZ9EBejdkRQCakc77O24b0mqSWCk5DIWvlbZj7PLD3fS bKvWH3OgI8HR60pl+vgUV3PDHCk1hNn3Wpz18G39fHqEhIT0qZuDuXmYwS/jVIOhmaLpLF 2klyoxHLVlh1kcf82KNT1rsJoGxCx6b4tPS7xLGkYnSp6/xvyqex+RG8bh2GCtbwIM9P7M 2IzEN1sL8zharzwWMxyWGQmFruy5Ry0xuDrEZ2Vo9ruaxaHkmOBPSPGkgqA1De7B2Tie0f 2jPvl/7efaXrUIhRThTMxx17t5TehDJYWxmW3yZVeO0QtunqrWyEVJzoHZCZXqqm1nlUqi 5nwp3BMlBvakXDRO4J/RaLr+ONVYEQ+NCsDcHLItsIaktSkhHKg9tirw7pI+LEYZic2+/U VMEUkDJWVW4gQlkLUEfgx/RjlF1nvBbZsuQ8T54Ah6UYoxSYMuXZKS3/PXRtkS/9IPX7wb HdZcO8WvnzivZ9IHmRxKnRz4gtJcD6sSV2FXem9cOEon7QEj8QyQRiV4BVe3u2pWlDP7wC e4n3tKOUHEelInzKgg6ak/sYaOwb4uNYD/jK4DMX1Zp3QRPULgtCyIB9J1F96w9Ek1lPyb NDWEOPtmgZhvCllXFKHahrJGmFddBgscRLVIQ44qzfEzaoMQ1Exab+B9iwWw X-ME-Proxy: Feedback-ID: i0fe9450f:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Sun, 31 May 2026 22:11:56 -0400 (EDT) Date: Mon, 1 Jun 2026 11:11:52 +0900 From: Michael Paquier To: Alexander Lakhin Cc: pgsql-bugs@lists.postgresql.org Subject: Re: BUG #19494: Error on transaction commit inside pipeline triggers psql's Assert Message-ID: References: <19494-97a86d84fee71c47@postgresql.org> MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha512; protocol="application/pgp-signature"; boundary="x/nN2W37lHMDmQqy" Content-Disposition: inline In-Reply-To: List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --x/nN2W37lHMDmQqy Content-Type: multipart/mixed; boundary="wc4EVzyoXqunG/0G" Content-Disposition: inline --wc4EVzyoXqunG/0G Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable On Sun, May 31, 2026 at 12:00:01PM +0300, Alexander Lakhin wrote: > I've found a way to trigger another assertion, but I don't think it's > legitimate: > --- a/src/backend/libpq/pqcomm.c > +++ b/src/backend/libpq/pqcomm.c > @@ -880,7 +880,7 @@ RemoveSocketFiles(void) > =A0static void > =A0socket_set_nonblocking(bool nonblocking) > =A0{ > -=A0=A0=A0=A0=A0=A0 if (MyProcPort =3D=3D NULL) > +=A0=A0=A0=A0=A0=A0 if ((MyProcPort =3D=3D NULL) || (rand() % 10 =3D=3D 0= )) > =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 ereport(ERROR, > (errcode(ERRCODE_CONNECTION_DOES_NOT_EXIST), > =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0 errmsg("there is no client connection"))); Server-side error injection. Noice. > trigger > psql: common.c:2055: ExecQueryAndProcessResults: Assertion > `pset.piped_syncs > 0' failed. This one would be in the same spirit as the others, if we cannot really guarantee that the counters will be correct all the time we can just more more defensive. That's an error thrown while the sync message is processing itself, causing piped_syncs to get out of step. > Probably there could be another way to throw an ERROR on \syncpipeline, > but I have no good idea yet. There is one challenge here, as far as I can see: libpq does not really offer a way to make the difference between this thrown error and an error that comes from a Sync, so it seems like we cannot do much on the psql side except be more defensive? I am not sure if this is worth the extra facility in libpq, the point would be moot in the back branches anyway. And there is a benefit in keeping the psql code as simple as possible, as well, so I'd tend to keep it more useful still simpler. > Running psql_pipeline in a loop with the above modification applied: > for i in {1..1000}; do echo "ITERATION $i"; NO_TEMP_INSTALL=3D1 TESTS=3Dp= sql_pipeline make -s check-tests; done > I also observed the test hanging (at iterations 284. 543, 218) due to loss > of synchronization between psql and postgres. I have looked at that as well, and I don't think that this is fixable=20 only from the point of psql, because the error injected creates a state where libpq's internal command queue gets out of sync regarding what the backend has sent. The only thing that could be done is inside libpq, as far as I can see, where we should try to detect that the state is not synchronized anymore and fail rather than block. So IMO, and with the error injected (which would never happen in production in practice), the best thing I can come up with is the attached for now. One thing that I could see ourselves do as an extra improvement in ExecQueryAndProcessResults() where we consume the results and check if we're still in a busy state (some PQconsumeInput+PQisBusy). I don't think that this should be a problem in practice, but this feels like just hiding the real problem on the libpq side with the inconsistent protocol state generated by the backend. I have also quickly tested an approach based on that, unfortunately this leads to some instability in the tests to due the async nature of the commands. Anyway, the v3 attached passes the regression tests, handles the pg_terminate_backend() case gracefully, handles the error case with the error injected on backend-side a but better, and can avoid=20 some of the issues in the fourth case, but not all as we don't have access to the pipe state when reaching the results do to the backend missing up with the libpq state. Handling the 4th case more gracefully would require some libpq changes, which may not justify the=20 cases we are dealing with here, at least to me. As a whole, I'd feel that v3 is a good improvement in itself, and it addresses your original issues and the assertions. What do you think? -- Michael --wc4EVzyoXqunG/0G Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename=v3-0001-psql-Fix-issues-with-deferred-errors-in-pipelines.patch Content-Transfer-Encoding: quoted-printable =46rom 7fe4b3adf207f08d7a7bac2bc25521096959aa5e Mon Sep 17 00:00:00 2001 =46rom: Michael Paquier Date: Mon, 1 Jun 2026 10:58:09 +0900 Subject: [PATCH v3] psql: Fix issues with deferred errors in pipelines When an error is raised while processing a Sync message in a pipeline, e like a deferred constraint violation, the error was not associated with the piped command and was not counted in available_results. This caused assertion failures in discardAbortedPipelineResults(), keeping an incorrect state at pipeline exit, because the code assumed that the number of available and requested results would always be positive, expecting all the counters to be 0 at the end of a pipeline. This commit switches discardAbortedPipelineResults() and ExecQueryAndProcessResults() to take a softer approach when consuming and draining the results after an error. The reporter has shown a couple of assertion failures reachable. While investigating more this issue I have bumped into two more. All these cases are covered by the regression tests added in this commit, plus some bonuses. Reported-by: Alexander Lakhin Author: Michael Paquier Discussion: https://postgr.es/m/19494-97a86d84fee71c47@postgresql.org Backpatch-through: 18 --- src/bin/psql/common.c | 76 +++++++++--- src/test/regress/expected/psql_pipeline.out | 124 ++++++++++++++++++++ src/test/regress/sql/psql_pipeline.sql | 63 ++++++++++ 3 files changed, 245 insertions(+), 18 deletions(-) diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c index 1a4e2ea0da82..13202a974d1e 100644 --- a/src/bin/psql/common.c +++ b/src/bin/psql/common.c @@ -1499,11 +1499,24 @@ discardAbortedPipelineResults(void) } else if (res =3D=3D NULL) { - /* A query was processed, decrement the counters */ - Assert(pset.available_results > 0); - Assert(pset.requested_results > 0); - pset.available_results--; - pset.requested_results--; + /* + * A query was processed, decrement the counters. + * + * It is possible to get here with available_results =3D=3D 0 when an + * error is generated by the Sync message processing itself. Such + * errors are not counted in available_results because they are + * not associated with a piped command. In that case, skip the + * counter decrements and continue to find the Sync result. + * + * If the connection has been lost, there will never be any more + * results to read, so bail out. + */ + if (!ConnectionUp()) + return NULL; + if (pset.available_results > 0) + pset.available_results--; + if (pset.requested_results > 0) + pset.requested_results--; } =20 if (pset.requested_results =3D=3D 0) @@ -2044,14 +2057,16 @@ ExecQueryAndProcessResults(const char *query, =20 if (result_status =3D=3D PGRES_PIPELINE_SYNC) { - Assert(pset.piped_syncs > 0); - /* * Sync response, decrease the sync and requested_results - * counters. + * counters. Guard against underflow: an error during Sync + * processing on the server can cause the client-side counter + * to drift. */ - pset.piped_syncs--; - pset.requested_results--; + if (pset.piped_syncs > 0) + pset.piped_syncs--; + if (pset.requested_results > 0) + pset.requested_results--; =20 /* * After a synchronisation point, reset success state to print @@ -2073,8 +2088,10 @@ ExecQueryAndProcessResults(const char *query, * In a pipeline with a non-sync response? Decrease the result * counters. */ - pset.available_results--; - pset.requested_results--; + if (pset.available_results > 0) + pset.available_results--; + if (pset.requested_results > 0) + pset.requested_results--; } =20 /* @@ -2175,14 +2192,37 @@ ExecQueryAndProcessResults(const char *query, =20 if (end_pipeline) { - /* after a pipeline is processed, pipeline piped_syncs should be 0 */ - Assert(pset.piped_syncs =3D=3D 0); - /* all commands have been processed */ - Assert(pset.piped_commands =3D=3D 0); - /* all results were read */ - Assert(pset.available_results =3D=3D 0); + /* + * Reset available/requested results. Normally these are already 0, + * but an error generated by a Sync processing itself can leave some + * of them behind. Consume them before exiting pipeline mode. + */ + while (pset.piped_syncs > 0) + { + PGresult *remaining; + + remaining =3D PQgetResult(pset.db); + + if (remaining =3D=3D NULL) + { + if (!ConnectionUp()) + break; + continue; + } + if (PQresultStatus(remaining) =3D=3D PGRES_PIPELINE_SYNC) + pset.piped_syncs--; + PQclear(remaining); + } + pset.piped_syncs =3D 0; + pset.piped_commands =3D 0; + pset.available_results =3D 0; + pset.requested_results =3D 0; + + if (PQpipelineStatus(pset.db) !=3D PQ_PIPELINE_OFF) + PQexitPipelineMode(pset.db); } Assert(pset.requested_results =3D=3D 0); + SetPipelineVariables(); =20 /* may need this to recover from conn loss during COPY */ diff --git a/src/test/regress/expected/psql_pipeline.out b/src/test/regress= /expected/psql_pipeline.out index a0816fb10b68..a931d63cafe7 100644 --- a/src/test/regress/expected/psql_pipeline.out +++ b/src/test/regress/expected/psql_pipeline.out @@ -764,5 +764,129 @@ VACUUM psql_pipeline \bind \sendpipeline 1 (1 row) =20 +-- Deferred constraint violation at commit time in a pipeline. +CREATE TABLE psql_pipeline_defer (a INTEGER PRIMARY KEY DEFERRABLE INITIAL= LY DEFERRED); +\startpipeline +INSERT INTO psql_pipeline_defer VALUES ($1), ($1) RETURNING * \bind 1 \sen= dpipeline +\endpipeline + a=20 +--- + 1 + 1 +(2 rows) + +ERROR: duplicate key value violates unique constraint "psql_pipeline_defe= r_pkey" +DETAIL: Key (a)=3D(1) already exists. +-- Same with \syncpipeline and commands after the failing sync. +\startpipeline +INSERT INTO psql_pipeline_defer VALUES ($1), ($1) \bind 1 \sendpipeline +\syncpipeline +SELECT $1 \bind 'after_sync_1' \sendpipeline +\endpipeline +ERROR: duplicate key value violates unique constraint "psql_pipeline_defe= r_pkey" +DETAIL: Key (a)=3D(1) already exists. + ?column? =20 +-------------- + after_sync_1 +(1 row) + +-- More patterns with more \syncpipeline, more commands and \getresults +\startpipeline +INSERT INTO psql_pipeline_defer VALUES ($1), ($1) \bind 1 \sendpipeline +INSERT INTO psql_pipeline_defer VALUES ($1), ($1) \bind 1 \sendpipeline +\syncpipeline +SELECT $1 \bind 'after_sync_1' \sendpipeline +\getresults +ERROR: duplicate key value violates unique constraint "psql_pipeline_defe= r_pkey" +DETAIL: Key (a)=3D(1) already exists. +SELECT $1 \bind 'after_sync_2' \sendpipeline +\endpipeline + ?column? =20 +-------------- + after_sync_1 +(1 row) + + ?column? =20 +-------------- + after_sync_2 +(1 row) + +\startpipeline +INSERT INTO psql_pipeline_defer VALUES ($1), ($1) \bind 1 \sendpipeline +INSERT INTO psql_pipeline_defer VALUES ($1), ($1) \bind 1 \sendpipeline +\syncpipeline +\getresults +ERROR: duplicate key value violates unique constraint "psql_pipeline_defe= r_pkey" +DETAIL: Key (a)=3D(1) already exists. +SELECT $1 \bind 'after_sync_1' \sendpipeline +\getresults +SELECT $1 \bind 'after_sync_2' \sendpipeline +INSERT INTO psql_pipeline_defer VALUES ($1), ($1) \bind 1 \sendpipeline +INSERT INTO psql_pipeline_defer VALUES ($1), ($1) \bind 1 \sendpipeline +SELECT $1 \bind 'after_sync_3' \sendpipeline +SELECT $1 \bind 'after_sync_4' \sendpipeline +SELECT $1 \bind 'after_sync_5' \sendpipeline +\endpipeline + ?column? =20 +-------------- + after_sync_1 +(1 row) + + ?column? =20 +-------------- + after_sync_2 +(1 row) + + ?column? =20 +-------------- + after_sync_3 +(1 row) + + ?column? =20 +-------------- + after_sync_4 +(1 row) + + ?column? =20 +-------------- + after_sync_5 +(1 row) + +ERROR: duplicate key value violates unique constraint "psql_pipeline_defe= r_pkey" +DETAIL: Key (a)=3D(1) already exists. +-- Deferred error combined with a regular command error after the sync. +\startpipeline +INSERT INTO psql_pipeline_defer VALUES ($1), ($1) \bind 1 \sendpipeline +\syncpipeline +SELECT $1 \bind \sendpipeline +SELECT $1 \bind 'after_error' \sendpipeline +\endpipeline +ERROR: duplicate key value violates unique constraint "psql_pipeline_defe= r_pkey" +DETAIL: Key (a)=3D(1) already exists. +ERROR: bind message supplies 0 parameters, but prepared statement "" requ= ires 1 +-- Empty sync segment followed by a deferred error. +\startpipeline +\syncpipeline +INSERT INTO psql_pipeline_defer VALUES ($1), ($1) \bind 1 \sendpipeline +\endpipeline +ERROR: duplicate key value violates unique constraint "psql_pipeline_defe= r_pkey" +DETAIL: Key (a)=3D(1) already exists. +-- Deferred error with \getresults reading results one at a time. +\startpipeline +INSERT INTO psql_pipeline_defer VALUES ($1), ($1) \bind 1 \sendpipeline +SELECT $1 \bind 'partial' \sendpipeline +\syncpipeline +\getresults 1 +\getresults 1 + ?column?=20 +---------- + partial +(1 row) + +\getresults +ERROR: duplicate key value violates unique constraint "psql_pipeline_defe= r_pkey" +DETAIL: Key (a)=3D(1) already exists. +\endpipeline +DROP TABLE psql_pipeline_defer; -- Clean up DROP TABLE psql_pipeline; diff --git a/src/test/regress/sql/psql_pipeline.sql b/src/test/regress/sql/= psql_pipeline.sql index 6788dceee2e9..468ef1d090b6 100644 --- a/src/test/regress/sql/psql_pipeline.sql +++ b/src/test/regress/sql/psql_pipeline.sql @@ -438,5 +438,68 @@ SELECT 1 \bind \sendpipeline VACUUM psql_pipeline \bind \sendpipeline \endpipeline =20 +-- Deferred constraint violation at commit time in a pipeline. +CREATE TABLE psql_pipeline_defer (a INTEGER PRIMARY KEY DEFERRABLE INITIAL= LY DEFERRED); +\startpipeline +INSERT INTO psql_pipeline_defer VALUES ($1), ($1) RETURNING * \bind 1 \sen= dpipeline +\endpipeline + +-- Same with \syncpipeline and commands after the failing sync. +\startpipeline +INSERT INTO psql_pipeline_defer VALUES ($1), ($1) \bind 1 \sendpipeline +\syncpipeline +SELECT $1 \bind 'after_sync_1' \sendpipeline +\endpipeline + +-- More patterns with more \syncpipeline, more commands and \getresults +\startpipeline +INSERT INTO psql_pipeline_defer VALUES ($1), ($1) \bind 1 \sendpipeline +INSERT INTO psql_pipeline_defer VALUES ($1), ($1) \bind 1 \sendpipeline +\syncpipeline +SELECT $1 \bind 'after_sync_1' \sendpipeline +\getresults +SELECT $1 \bind 'after_sync_2' \sendpipeline +\endpipeline +\startpipeline +INSERT INTO psql_pipeline_defer VALUES ($1), ($1) \bind 1 \sendpipeline +INSERT INTO psql_pipeline_defer VALUES ($1), ($1) \bind 1 \sendpipeline +\syncpipeline +\getresults +SELECT $1 \bind 'after_sync_1' \sendpipeline +\getresults +SELECT $1 \bind 'after_sync_2' \sendpipeline +INSERT INTO psql_pipeline_defer VALUES ($1), ($1) \bind 1 \sendpipeline +INSERT INTO psql_pipeline_defer VALUES ($1), ($1) \bind 1 \sendpipeline +SELECT $1 \bind 'after_sync_3' \sendpipeline +SELECT $1 \bind 'after_sync_4' \sendpipeline +SELECT $1 \bind 'after_sync_5' \sendpipeline +\endpipeline + +-- Deferred error combined with a regular command error after the sync. +\startpipeline +INSERT INTO psql_pipeline_defer VALUES ($1), ($1) \bind 1 \sendpipeline +\syncpipeline +SELECT $1 \bind \sendpipeline +SELECT $1 \bind 'after_error' \sendpipeline +\endpipeline + +-- Empty sync segment followed by a deferred error. +\startpipeline +\syncpipeline +INSERT INTO psql_pipeline_defer VALUES ($1), ($1) \bind 1 \sendpipeline +\endpipeline + +-- Deferred error with \getresults reading results one at a time. +\startpipeline +INSERT INTO psql_pipeline_defer VALUES ($1), ($1) \bind 1 \sendpipeline +SELECT $1 \bind 'partial' \sendpipeline +\syncpipeline +\getresults 1 +\getresults 1 +\getresults +\endpipeline + +DROP TABLE psql_pipeline_defer; + -- Clean up DROP TABLE psql_pipeline; --=20 2.54.0 --wc4EVzyoXqunG/0G-- --x/nN2W37lHMDmQqy Content-Type: application/pgp-signature; name=signature.asc -----BEGIN PGP SIGNATURE----- iQIzBAEBCgAdFiEEG72nH6vTowiyblFKnvQgOdbyQH0FAmoc6mgACgkQnvQgOdby QH3I3hAAmp9mFJG9/poPFQKCkGWPaENRIBC5/5mV4HbrQ7o6t2Eo8BNoOVKd7l0X ilWs7x9KOO0hJ0HB4hTbtVa3fveiePabAN6bnn58uG3ij+1p3JwDeYULT5sdH+X3 Yx2NKjqTeGkwQ32cTce8eDsercyo8QZZ1Ed+57P7cF9jHs/vir/A2HFii15PbeLr BhaXqvyIWm7XAsCJGas1YL/X+T2maV6bvpL2iktOIRTIjx0rRKjhLe8j/cnQaYVS jQJhdU7U09id6Omkt71rrxE4aK4qwDOU9sM6tNQMkVsQytJElRKoBTGoSzka8j6u akWiv4usCnM8KJNy0GyBaOWIywDrSLuDeUeVaIIy79l7fo1ggFTwdnGNu8ihGxA6 cm5bEdR6bJEbCojbkClchSLxUCH7YtAg0Jxdi1AD9YhO/RQ38iY2hfdHTELT+KA8 zeO8rvPw5HTF6vD55yIbSux+/l/TCix4zjfua2O99xzwt/GG1kzVsORfSRrGZMdi yGEiDKXem6oIrfxu1lTwk+K5x9xQm0+hKqwZgxS9Eemru8M2AsZx2AHOht0TAQu9 KtTbTchMKjLvhRVzp09wubxyP9hN7tadilMROXLzFqhJoQpnq4A+Fz5f7nquIC9D B3SV1PNkOtFEDESs2bzcIV9t+Wnc1t8u1GG35rJgtgGQ6pESzXA= =Q4ZO -----END PGP SIGNATURE----- --x/nN2W37lHMDmQqy--