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 1w0qmt-002GEc-12 for pgsql-hackers@arkaria.postgresql.org; Fri, 13 Mar 2026 00:53:59 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1w0qmp-000yLh-06 for pgsql-hackers@arkaria.postgresql.org; Fri, 13 Mar 2026 00:53:55 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1w0qmo-000yLY-1P for pgsql-hackers@lists.postgresql.org; Fri, 13 Mar 2026 00:53:55 +0000 Received: from mail-pf1-x432.google.com ([2607:f8b0:4864:20::432]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1w0qmm-00000001r5u-39eo for pgsql-hackers@postgresql.org; Fri, 13 Mar 2026 00:53:54 +0000 Received: by mail-pf1-x432.google.com with SMTP id d2e1a72fcca58-829781b2b01so1118769b3a.2 for ; Thu, 12 Mar 2026 17:53:52 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1773363232; cv=none; d=google.com; s=arc-20240605; b=j9QrvPk91SCHdTrwldyLlKqRpZsGjz3CCqcS0wmLnMwB4kTxfN6j0diGFx5afUGTYP zG5jIS/YBVK/Da3ogtpnUIjNxDTnmC1PzkxM19jUWd0PcKBUYw0jytciCKJjWNBGZjZK 2qb6bqUetuGNv+HGKyDKo7DLPUNRhOssNj3lLMlYDJwW6FXcIlaCAqvLRPWpWllTdBhC 2tBcQWuMrhlfK/lxYh8F/WwPGT4JENvUv5qcZIwnvtuliIxEVw3TG+khb3MmVQzm2go+ HvfqLW/ZU/IV4D1m/ftvCnFMdO80RdFxjdKLKpfJdXprdzXkkiRdCZ/w+eZHwIGWo/KP bK9A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=cc:to:subject:message-id:date:from:reply-to:in-reply-to:references :mime-version:dkim-signature; bh=F8ZREG82zku+NEdGmF5WLTPYU31Ax1BKNofunUowisk=; fh=wUZBKfeC0dzmgpwPmRfsZkQjhgDHvGbjLlJVyO+xhro=; b=NQ2QH5BogfZ6WwySrfUWYzNRpQS35hGHenDoeNOQe8U6FUGlF/9U/q3l3ATy7vPXSv V+IBARjaVoodrXKmthnoLrBeORc4+pTZYKFjID3l1GyBHVqs2/AYN1eKj9726ppkR7ck d21bQk7jYI7BQDZFh6+tyNKy0j9SARKFKCP380tL+rPqwktjToj++I8ROAPZSHQsguJF 0AMCDAosJFdS37FuJ4MXZmzGTpD8BUtVr1wxhP8YVV0Ov/y+7S2LeQnpj3w9GIieR6iC dz6DajUwl3Dxo34shxVVBaLcdl/r+SwLxrKzmQ6vjJUuTZYj4GIDwYQ8kYjk5W541aAH J5ug==; darn=postgresql.org ARC-Authentication-Results: i=1; mx.google.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773363232; x=1773968032; darn=postgresql.org; h=cc:to:subject:message-id:date:from:reply-to:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=F8ZREG82zku+NEdGmF5WLTPYU31Ax1BKNofunUowisk=; b=i+zVG1We/yDk896MZlgOrQDx5lI+9+UlwihupY7z+FfCE+lr+q9oYtdt/XHtVW++Wv 1dfhiEEaYKOxfj9i55KikygYK+GGEIO9fieK7Me2r+yUt3rqtBZbKctk7A0qvlIYKoLz 8nEtbW8mZNh5W3nXeVtjzbLAA+03LmTHt7O2EPmGuOZs41SfUw8c0sfXeTyk0KXBtERP QazLq4OGevM/4xBLow+8rHNrRrvhbykq4YNuR2i1/b0i/UxvJoS8662McyQ013N2FdoP i5EWWOV8AmpG9+pRDrKXYxDUZNcfkdzEB0UmqDyKaoO3b03q4Sn0NlOjT2fFDXriaF7X ZWVQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773363232; x=1773968032; h=cc:to:subject:message-id:date:from:reply-to:in-reply-to:references :mime-version:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=F8ZREG82zku+NEdGmF5WLTPYU31Ax1BKNofunUowisk=; b=eFMh7ez0dZRvTu2tJhrY9BDcYUCWjRZ12ok6EIMr09tm6gHCd7nGdj4nK9+XaCScrC NreNJ55ESVs07DR4uGYc2t53ukOqD69eCD5Pjn+EN3wmZM2EzSNbZRgUWt7VDDBi9Diz T3UT08uCu6ikyQWSR0KLGrjwArJBEeZYTs5nxR2lPK74A+Z9HA1QK83xUcfakF+uJPqd dgpGKkuOqz91NGch+PdgtActJLpzJdosu7CoLWnI63oj1kEdV0rkIh2WJbdfFzvP39v0 ql8AfFXWX2wx1Cjkhs2SMQteI8CCQnow+m0nWQsAEPKfssGXvV3DdQCji5T6AwPUAB0R U1NQ== X-Forwarded-Encrypted: i=1; AJvYcCVHQGsyNkLbm9s/VxIXuqoZ2doBWTqAglWhXDeSlistwZRA9qDVX0XH8EvRttKPUB9rr2Mu8O884iRs1gCd@postgresql.org X-Gm-Message-State: AOJu0Yxix1XRBj57ICvriC2MgMzHB598F38iG1jxxEzm+yHvXf91LwoN jTW3wfWjPPM8ZKJ1WwJ2/e3fd2z3coJrTwkkwvYflMJGsFCnGI7yZObmJANlO+Lm6L65/HwIsu7 2BHKw1klvUEhuSHFa1YPdk5ECZuZDvkc= X-Gm-Gg: ATEYQzxTxKNWmLWyObD5AsiaoTqhkEvhbFkUGVT/OfFlDYOJQ8EafVJIoLDzDUO6qet ynYgcpTlAHFtMeZtbvDdo6e/hzcxlNASRvh8h/nKIh95y5e8x1dX9swec3wzQZUXLEbve9YPrHt nv4oQsGphlprsdoXesZttVWF7ApyR190d6e1zcJLOKTFHje69LTTuf/85OAdn3MTsQionAMkGpZ cb9+Vqy/QdD/sGAgeGK6idO1XpXq5LoIQXaRoCqpyc0bbOcZci/i+pSy+GVHmdITTWTN25sKbsi Akq9uJ+XqVatotWcOyX4UuAm/Enu0gWA7RRU8GA= X-Received: by 2002:a05:6a00:4fc4:b0:81a:7d1e:8132 with SMTP id d2e1a72fcca58-82a1971abb4mr1065007b3a.21.1773363231713; Thu, 12 Mar 2026 17:53:51 -0700 (PDT) MIME-Version: 1.0 References: <20260312.092125.2016894123875469735.ishii@postgresql.org> <20260312.105500.450470685315646651.ishii@postgresql.org> In-Reply-To: <20260312.105500.450470685315646651.ishii@postgresql.org> Reply-To: assam258@gmail.com From: Henson Choi Date: Fri, 13 Mar 2026 09:53:39 +0900 X-Gm-Features: AaiRm53OtM6MbFST2tZAIBbNbEDVnRU88-QEM40ZM7yPN6SbKFvNNT5WNh0jdls Message-ID: Subject: Re: Row pattern recognition To: Tatsuo Ishii Cc: zsolt.parragi@percona.com, vik@postgresfriends.org, er@xs4all.nl, jacob.champion@enterprisedb.com, david.g.johnston@gmail.com, peter@eisentraut.org, pgsql-hackers@postgresql.org Content-Type: multipart/mixed; boundary="0000000000007cb481064cdd4d24" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --0000000000007cb481064cdd4d24 Content-Type: multipart/alternative; boundary="0000000000007cb47f064cdd4d22" --0000000000007cb47f064cdd4d22 Content-Type: text/plain; charset="UTF-8" Hi Tatsuo, Thank you for your thoughtful feedback on the tle identity concern. Ok. we should be consistent with WHERE etc. unless the standard > requres DEFINE stricter. But if the tle is in the target list > (possibly with resjunk attribute), it could be different from the one > in the DEFINE because of the casting by coerce_to_boolean(). i.e.: > > - tle in the target list has no cast node > - tle in the DEFINE may have cast node > > I don't know how this could affect subsequent RPR process but I would > like to keep the prerequisites that tle in DEINE and the traget list > is identical. > > is identical. That is a very good point regarding tle identity. On the implementation side, the DEFINE clause TargetEntries are already deep-copied via copyObject in the parser (parse_rpr.c), so adding a cast node to the DEFINE tle does not affect the target list tle -- they are independent copies at that point. On the semantic side, the two serve different purposes: the target list produces output columns (where the user expects the original type), while the DEFINE expression is evaluated as a boolean for pattern matching. This is the same pattern as WHERE, where the WHERE expression may carry a cast node but the target list for the same column does not. That said, if you would prefer to keep them structurally identical, an alternative would be to reject non-boolean types in DEFINE with a clear error (using exprType() check). However, this would be stricter than WHERE/HAVING behavior, which might surprise users. I would suggest that allowing coercion is the right choice for consistency, but I am happy to go with whichever approach you prefer. On a separate topic, I have found a server crash bug in the current PREV/NEXT implementation. Nesting navigation functions causes the backend to crash: CREATE TABLE t (id int, price int); INSERT INTO t VALUES (1,10),(2,20),(3,15),(4,25),(5,30); SELECT * FROM t WINDOW w AS ( ORDER BY id ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING PATTERN (A B+) DEFINE B AS prev(prev(b.price)) > 0 ); -- server process crashes The SQL standard (ISO/IEC 19075-5, Section 5.6.2) prohibits nesting PREV/NEXT within PREV/NEXT. The first argument of PREV/NEXT must contain a column reference, not another navigation function call. Currently there is no parser-level check for this, so the nested call passes through to the executor and crashes. I have attached a test file (rpr_nav_nesting_test.txt) containing 6 test cases that cover the prohibited nesting patterns: - PREV(PREV(price)) direct same-kind nesting - NEXT(NEXT(price)) direct same-kind nesting - PREV(NEXT(price)) cross nesting - NEXT(PREV(price)) cross nesting - PREV(ABS(PREV(price))) nesting hidden inside another function - NEXT(ABS(NEXT(price))) nesting hidden inside another function All of these currently crash the server. After a fix, they should all produce a syntax error. Finally, while reviewing the standard and the current PREV/NEXT implementation, I have some thoughts on the design. The current approach uses all three ExprContext slots (scan/outer/inner) with varno rewriting, which fixes offsets at +/-1. The standard requires variable offsets like PREV(price, 3), and the three-slot model cannot support this. I think a simpler approach would be to use just one slot (ecxt_outertuple) and swap it during expression evaluation: For `price > PREV(price, 2)`: ^^^^ ^^^^ ^^^^^ | | | v v v 1. [price] read from current slot --> datum_a 2. [PREV( ,2)] swap slot to (currentpos - 2) 3. [price] read from swapped slot --> datum_b 4. [)] restore slot 5. [>] evaluate datum_a > datum_b Since step 1 already extracts the value as a Datum before the swap in step 2, the result is safe. No varno rewriting is needed -- all column reads just use the one slot, and the swap/restore controls which row they see. One thing I noticed is that the SQL standard explicitly requires all column references inside a navigation function to be qualified by the same row pattern variable (Section 5.2): "All row pattern column references in an aggregate or row pattern navigation operation are qualified by the same row pattern variable." This means the navigation argument is always evaluated in a single row context -- which is exactly what makes the one-slot swap model work. It seems like the standard may have been designed with this kind of implementation in mind. With this approach, the existing varno rewriting infrastructure and the extra slots for PREV/NEXT would no longer be needed, which should simplify the code considerably. I also believe this design would scale well to future extensions. Variable offsets (PREV(price, N)) would work naturally, and when we add FIRST/LAST navigation or row pattern variable qualifiers, only the target row calculation would change -- the swap/restore mechanism itself would remain the same. What do you think about this approach? Best regards, Henson --0000000000007cb47f064cdd4d22 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Hi Tatsuo,

Thank = you for your thoughtful feedback on the tle identity concern.

Ok. we should be consistent with WHERE etc. unless the standard
requres DEFINE stricter. But if the tle is in the target list
(possibly with resjunk attribute), it could be different from the one
in the DEFINE because of the casting by coerce_to_boolean(). i.e.:

- tle in the target list has no cast node
- tle in the DEFINE may have cast node

I don't know how this could affect subsequent RPR process but I would like to keep the prerequisites that tle in DEINE and the traget list
is identical.

> is identical.

That= is a very good point regarding tle identity.

On the implementation = side, the DEFINE clause TargetEntries are
already deep-copied via copyOb= ject in the parser (parse_rpr.c),
so adding a cast node to the DEFINE tl= e does not affect the
target list tle -- they are independent copies at = that point.

On the semantic side, the two serve different purposes: = the target
list produces output columns (where the user expects the orig= inal
type), while the DEFINE expression is evaluated as a boolean forpattern matching. This is the same pattern as WHERE, where the
WHERE ex= pression may carry a cast node but the target list for the
same column d= oes not.

That said, if you would prefer to keep them structurally id= entical,
an alternative would be to reject non-boolean types in DEFINE w= ith
a clear error (using exprType() check). However, this would be
st= ricter than WHERE/HAVING behavior, which might surprise users.

I wou= ld suggest that allowing coercion is the right choice for
consistency, b= ut I am happy to go with whichever approach you
prefer.


On a = separate topic, I have found a server crash bug in the current
PREV/NEXT= implementation. Nesting navigation functions causes the
backend to cras= h:

=C2=A0 =C2=A0 CREATE TABLE t (id int, price int);
=C2=A0 =C2= =A0 INSERT INTO t VALUES (1,10),(2,20),(3,15),(4,25),(5,30);

=C2=A0 = =C2=A0 SELECT * FROM t WINDOW w AS (
=C2=A0 =C2=A0 =C2=A0 =C2=A0 ORDER B= Y id
=C2=A0 =C2=A0 =C2=A0 =C2=A0 ROWS BETWEEN CURRENT ROW AND UNBOUNDED = FOLLOWING
=C2=A0 =C2=A0 =C2=A0 =C2=A0 PATTERN (A B+)
=C2=A0 =C2=A0 = =C2=A0 =C2=A0 DEFINE B AS prev(prev(b.price)) > 0
=C2=A0 =C2=A0 );=C2=A0 =C2=A0 -- server process crashes

The SQL standard (ISO/IEC 1= 9075-5, Section 5.6.2) prohibits nesting
PREV/NEXT within PREV/NEXT. The= first argument of PREV/NEXT must
contain a column reference, not anothe= r navigation function call.
Currently there is no parser-level check for= this, so the nested
call passes through to the executor and crashes.
I have attached a test file (rpr_nav_nesting_test.txt) containing
6= test cases that cover the prohibited nesting patterns:

=C2=A0 - PRE= V(PREV(price)) =C2=A0 =C2=A0 =C2=A0 =C2=A0direct same-kind nesting
=C2= =A0 - NEXT(NEXT(price)) =C2=A0 =C2=A0 =C2=A0 =C2=A0direct same-kind nesting=
=C2=A0 - PREV(NEXT(price)) =C2=A0 =C2=A0 =C2=A0 =C2=A0cross nesting
= =C2=A0 - NEXT(PREV(price)) =C2=A0 =C2=A0 =C2=A0 =C2=A0cross nesting
=C2= =A0 - PREV(ABS(PREV(price))) =C2=A0 nesting hidden inside another function<= br>=C2=A0 - NEXT(ABS(NEXT(price))) =C2=A0 nesting hidden inside another fun= ction

All of these currently crash the server. After a fix, they sho= uld
all produce a syntax error.


Finally, while reviewing the = standard and the current
PREV/NEXT implementation, I have some thoughts = on the
design.

The current approach uses all three ExprContext sl= ots
(scan/outer/inner) with varno rewriting, which fixes offsets at
+= /-1. The standard requires variable offsets like PREV(price, 3),
and the= three-slot model cannot support this.

I think a simpler approach wo= uld be to use just one slot
(ecxt_outertuple) and swap it during express= ion evaluation:

=C2=A0 For `price > PREV= (price, 2)`:
=C2=A0 =C2=A0 =C2=A0 =C2=A0 ^^^^ =C2=A0 =C2=A0^^^^ =C2=A0^^= ^^^
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0| =C2=A0 =C2=A0 =C2=A0 | =C2=A0 = =C2=A0 =C2=A0|
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0v =C2=A0 =C2=A0 =C2=A0 = v =C2=A0 =C2=A0 =C2=A0v
=C2=A0 =C2=A0 1. [price] =C2=A0 =C2=A0 =C2=A0 re= ad from current slot =C2=A0 --> datum_a
=C2=A0 =C2=A0 2. [PREV( ,2)] = =C2=A0 swap slot to (currentpos - 2)
=C2=A0 =C2=A0 3. =C2=A0 [price] =C2= =A0 =C2=A0 read from swapped slot =C2=A0 --> datum_b
=C2=A0 =C2=A0 4.= [)] =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 restore slot
=C2=A0 =C2=A0 5. [&= gt;] =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 evaluate datum_a > datum_b

Since step 1 already extracts the value as a Datum before the
s= wap in step 2, the result is safe. No varno rewriting is needed
-- all c= olumn reads just use the one slot, and the swap/restore
controls which r= ow they see.

One thing I noticed is that the SQL standard explicitly= requires
all column references inside a navigation function to be quali= fied
by the same row pattern variable (Section 5.2):

=C2=A0 "= ;All row pattern column references in an aggregate or row
=C2=A0 =C2=A0p= attern navigation operation are qualified by the same row
=C2=A0 =C2=A0p= attern variable."

This means the navigation argument is always = evaluated in a single
row context -- which is exactly what makes the one= -slot swap model
work. It seems like the standard may have been designed= with this
kind of implementation in mind.

With this approach, th= e existing varno rewriting infrastructure and
the extra slots for PREV/N= EXT would no longer be needed, which
should simplify the code considerab= ly.

I also believe this design would scale well to future extensions= .
Variable offsets (PREV(price, N)) would work naturally, and when
we= add FIRST/LAST navigation or row pattern variable qualifiers,
only the = target row calculation would change -- the swap/restore
mechanism itself= would remain the same.

What do you think about this approach?
Best regards,
Henson=C2=A0
--0000000000007cb47f064cdd4d22-- --0000000000007cb481064cdd4d24 Content-Type: text/plain; charset="US-ASCII"; name="rpr_nav_nesting_test.txt" Content-Disposition: attachment; filename="rpr_nav_nesting_test.txt" Content-Transfer-Encoding: base64 Content-ID: X-Attachment-Id: f_mmo6mi370 LS0gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09 PT09PT09Ci0tIFJQUiBOYXZpZ2F0aW9uIE5lc3RpbmcgVGVzdHMKLS0gVGVzdHMgZm9yIHByb2hp Yml0ZWQgbmVzdGluZyBvZiBQUkVWL05FWFQgKFNRTCBzdGFuZGFyZCA1LjYpCi0tID09PT09PT09 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQotLQot LSBUaGUgU1FMIHN0YW5kYXJkIHByb2hpYml0czoKLS0gICAtIFBSRVYvTkVYVCBuZXN0ZWQgd2l0 aGluIFBSRVYvTkVYVAotLSAgIC0gUFJFVi9ORVhUIG5lc3RlZCB3aXRoaW4gb3RoZXIgZnVuY3Rp b25zIGluc2lkZSBQUkVWL05FWFQKLS0KLS0gVGhlc2Ugc2hvdWxkIGFsbCBwcm9kdWNlIHN5bnRh eCBlcnJvcnMsIG5vdCBzZXJ2ZXIgY3Jhc2hlcy4KLS0gPT09PT09PT09PT09PT09PT09PT09PT09 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CgpDUkVBVEUgVEVNUCBUQUJMRSBu YXZfdGVzdCAoaWQgSU5ULCBwcmljZSBJTlQpOwpJTlNFUlQgSU5UTyBuYXZfdGVzdCBWQUxVRVMg KDEsIDEwKSwgKDIsIDIwKSwgKDMsIDE1KSwgKDQsIDI1KSwgKDUsIDMwKTsKCi0tIFBSRVYoUFJF VihwcmljZSkpIC0gZGlyZWN0IG5lc3RpbmcKU0VMRUNUICogRlJPTSBuYXZfdGVzdCBXSU5ET1cg dyBBUyAoCiAgICBPUkRFUiBCWSBpZAogICAgUk9XUyBCRVRXRUVOIENVUlJFTlQgUk9XIEFORCBV TkJPVU5ERUQgRk9MTE9XSU5HCiAgICBQQVRURVJOIChBIEIrKQogICAgREVGSU5FIEIgQVMgcHJl dihwcmV2KGIucHJpY2UpKSA+IDAKKTsKCi0tIE5FWFQoTkVYVChwcmljZSkpIC0gZGlyZWN0IG5l c3RpbmcKU0VMRUNUICogRlJPTSBuYXZfdGVzdCBXSU5ET1cgdyBBUyAoCiAgICBPUkRFUiBCWSBp ZAogICAgUk9XUyBCRVRXRUVOIENVUlJFTlQgUk9XIEFORCBVTkJPVU5ERUQgRk9MTE9XSU5HCiAg ICBQQVRURVJOIChBIEIrKQogICAgREVGSU5FIEIgQVMgbmV4dChuZXh0KGIucHJpY2UpKSA+IDAK KTsKCi0tIFBSRVYoTkVYVChwcmljZSkpIC0gY3Jvc3MgbmVzdGluZwpTRUxFQ1QgKiBGUk9NIG5h dl90ZXN0IFdJTkRPVyB3IEFTICgKICAgIE9SREVSIEJZIGlkCiAgICBST1dTIEJFVFdFRU4gQ1VS UkVOVCBST1cgQU5EIFVOQk9VTkRFRCBGT0xMT1dJTkcKICAgIFBBVFRFUk4gKEEgQispCiAgICBE RUZJTkUgQiBBUyBwcmV2KG5leHQoYi5wcmljZSkpID4gMAopOwoKLS0gTkVYVChQUkVWKHByaWNl KSkgLSBjcm9zcyBuZXN0aW5nClNFTEVDVCAqIEZST00gbmF2X3Rlc3QgV0lORE9XIHcgQVMgKAog ICAgT1JERVIgQlkgaWQKICAgIFJPV1MgQkVUV0VFTiBDVVJSRU5UIFJPVyBBTkQgVU5CT1VOREVE IEZPTExPV0lORwogICAgUEFUVEVSTiAoQSBCKykKICAgIERFRklORSBCIEFTIG5leHQocHJldihi LnByaWNlKSkgPiAwCik7CgotLSBQUkVWIGluc2lkZSBleHByZXNzaW9uIGluc2lkZSBQUkVWClNF TEVDVCAqIEZST00gbmF2X3Rlc3QgV0lORE9XIHcgQVMgKAogICAgT1JERVIgQlkgaWQKICAgIFJP V1MgQkVUV0VFTiBDVVJSRU5UIFJPVyBBTkQgVU5CT1VOREVEIEZPTExPV0lORwogICAgUEFUVEVS TiAoQSBCKykKICAgIERFRklORSBCIEFTIHByZXYoYWJzKHByZXYoYi5wcmljZSkpKSA+IDAKKTsK Ci0tIE5FWFQgaW5zaWRlIGV4cHJlc3Npb24gaW5zaWRlIE5FWFQKU0VMRUNUICogRlJPTSBuYXZf dGVzdCBXSU5ET1cgdyBBUyAoCiAgICBPUkRFUiBCWSBpZAogICAgUk9XUyBCRVRXRUVOIENVUlJF TlQgUk9XIEFORCBVTkJPVU5ERUQgRk9MTE9XSU5HCiAgICBQQVRURVJOIChBIEIrKQogICAgREVG SU5FIEIgQVMgbmV4dChhYnMobmV4dChiLnByaWNlKSkpID4gMAopOwoKRFJPUCBUQUJMRSBuYXZf dGVzdDsK --0000000000007cb481064cdd4d24--