Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1pQ3Ri-0007WZ-RA for pgsql-hackers@arkaria.postgresql.org; Thu, 09 Feb 2023 09:42:27 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1pQ3Rh-0007Dq-NE for pgsql-hackers@arkaria.postgresql.org; Thu, 09 Feb 2023 09:42:25 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1pQ3Rh-0007Dh-CC for pgsql-hackers@lists.postgresql.org; Thu, 09 Feb 2023 09:42:25 +0000 Received: from relay10.mail.gandi.net ([2001:4b98:dc4:8::230]) by magus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1pQ3Rf-0001gi-IF for pgsql-hackers@lists.postgresql.org; Thu, 09 Feb 2023 09:42:24 +0000 Received: (Authenticated sender: vik@postgresfriends.org) by mail.gandi.net (Postfix) with ESMTPSA id 234E9240010; Thu, 9 Feb 2023 09:42:18 +0000 (UTC) Content-Type: multipart/mixed; boundary="------------pqb5hJtH4BTQXgSY6x1JJikZ" Message-ID: <15c31fa6-b84a-8705-f5a2-987d165a89db@postgresfriends.org> Date: Thu, 9 Feb 2023 10:42:16 +0100 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.4.2 Subject: Re: ANY_VALUE aggregate Content-Language: en-US To: David Rowley Cc: Peter Eisentraut , PostgreSQL Hackers References: <5cff866c-10a8-d2df-32cb-e9072e6b04a2@postgresfriends.org> <464ece4e-fabb-ddac-60da-897493c4476d@enterprisedb.com> <538ac95d-f12e-92b8-0e22-85b6e35fdec9@postgresfriends.org> From: Vik Fearing In-Reply-To: List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk This is a multi-part message in MIME format. --------------pqb5hJtH4BTQXgSY6x1JJikZ Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit On 1/23/23 08:50, David Rowley wrote: > On Thu, 19 Jan 2023 at 06:01, Vik Fearing wrote: >> Thank you for the review. Attached is a new version rebased to d540a02a72. > > I've only a bunch of nit-picks, personal preferences and random > thoughts to offer as a review: > > 1. I'd be inclined *not* to mention the possible future optimisation in: > > + * Currently this just returns the first value, but in the future it might be > + * able to signal to the aggregate that it does not need to be called anymore. > > I think it's unlikely that the transfn would "signal" such a thing. It > seems more likely if we did anything about it that nodeAgg.c would > maybe have some additional knowledge not to call that function if the > agg state already has a value. Just so we're not preempting how we > might do such a thing in the future, it seems best just to remove the > mention of it. I don't really think it serves as a good reminder that > we might want to do this one day anyway. Modified. My logic in having the transition function signal that it is finished is to one day allow something like: array_agg(x order by y limit z) > 2. +any_value_trans(PG_FUNCTION_ARGS) > > Many of transition function names end in "transfn", not "trans". I > think it's better to follow the existing (loosely followed) naming > pattern that a few aggregates seem to follow rather than invent a new > one. Renamed. > 3. I tend to try to copy the capitalisation of keywords from the > surrounding regression tests. I see the following breaks that. > > +SELECT any_value(v) FILTER (WHERE v > 2) FROM (VALUES (1), (2), (3)) AS v (v); > > (obviously, ideally, we'd always just follow the same capitalisation > of keywords everywhere in each .sql file, but we've long broken that > and the best way can do is be consistent with surrounding tests) Downcased. > 4. I think I'd use the word "Returns" instead of "Chooses" in: > > + Chooses a non-deterministic value from the non-null input values. Done. > 5. I've not managed to find a copy of the 2023 draft, so I'm assuming > you've got the ignoring of NULLs correct. Yes, I do. This is part of , so SQL:2016 10.9 GR 7.a applies. > 6. Is it worth adding a WindowFunc test somewhere in window.sql with > an any_value(...) over (...)? Is what any_value() returns as a > WindowFunc equally as non-deterministic as when it's used as an > Aggref? Can we assume there's no guarantee that it'll return the same > value for each partition in each row? Does the spec mention anything > about that? This is governed by SQL:2016 10.9 GR 1.d and 1.e which defines the source rows for the aggregate: either a group or a window frame. There is no difference in behavior. I don't think a windowed test is useful here unless I were to implement moving transitions. I think that might be overkill for this function. > 7. I wondered if it's worth adding a > SupportRequestOptimizeWindowClause support function for this > aggregate. I'm thinking that it might not be as likely people would > use something more specific like first_value/nth_value/last_value > instead of using any_value as a WindowFunc. Also, I'm currently > thinking that a SupportRequestWFuncMonotonic for any_value() is not > worth the dozen or so lines of code it would take to write it. I'm > assuming it would always be a MONOTONICFUNC_BOTH function. It seems > unlikely that someone would have a subquery with a WHERE clause in the > upper-level query referencing the any_value() aggregate. Thought I'd > mention both of these things anyway as someone else might think of > some good reason we should add them that I didn't think of. I thought about this for a while and decided that it was not worthwhile. v4 attached. I am putting this back to Needs Review in the commitfest app, but these changes were editorial so it is probably RfC like Peter had set it. I will let you be the judge of that. -- Vik Fearing --------------pqb5hJtH4BTQXgSY6x1JJikZ Content-Type: text/x-patch; charset=UTF-8; name="v4-0001-Implement-ANY_VALUE-aggregate.patch" Content-Disposition: attachment; filename="v4-0001-Implement-ANY_VALUE-aggregate.patch" Content-Transfer-Encoding: base64 RnJvbSA0MTA3NTFjZmE2MzY3ZTU0MzZlMjAwMTFmM2Y0N2YzNzg4ODE5MGExIE1vbiBTZXAg MTcgMDA6MDA6MDAgMjAwMQpGcm9tOiBWaWsgRmVhcmluZyA8dmlrQHBvc3RncmVzZnJpZW5k cy5vcmc+CkRhdGU6IFRodSwgOSBGZWIgMjAyMyAxMDozNzoxMCArMDEwMApTdWJqZWN0OiBb UEFUQ0ggdjRdIEltcGxlbWVudCBBTllfVkFMVUUgYWdncmVnYXRlCgpTUUw6MjAyMyBkZWZp bmVzIGFuIEFOWV9WQUxVRSBhZ2dyZWdhdGUgd2hvc2UgcHVycG9zZSBpcyB0byBlbWl0IGFu CmltcGxlbWVudGF0aW9uLWRlcGVuZGVudCAoaS5lLiBub24tZGV0ZXJtaW5pc3RpYykgdmFs dWUgZnJvbSB0aGUKYWdncmVnYXRlZCByb3dzLgotLS0KIGRvYy9zcmMvc2dtbC9mdW5jLnNn bWwgICAgICAgICAgICAgICAgICAgfCAxNCArKysrKysrKysrKysrKwogc3JjL2JhY2tlbmQv Y2F0YWxvZy9zcWxfZmVhdHVyZXMudHh0ICAgICB8ICAxICsKIHNyYy9iYWNrZW5kL3V0aWxz L2FkdC9taXNjLmMgICAgICAgICAgICAgfCAxMCArKysrKysrKysrCiBzcmMvaW5jbHVkZS9j YXRhbG9nL3BnX2FnZ3JlZ2F0ZS5kYXQgICAgIHwgIDQgKysrKwogc3JjL2luY2x1ZGUvY2F0 YWxvZy9wZ19wcm9jLmRhdCAgICAgICAgICB8ICA4ICsrKysrKysrCiBzcmMvdGVzdC9yZWdy ZXNzL2V4cGVjdGVkL2FnZ3JlZ2F0ZXMub3V0IHwgMjQgKysrKysrKysrKysrKysrKysrKysr KysrCiBzcmMvdGVzdC9yZWdyZXNzL3NxbC9hZ2dyZWdhdGVzLnNxbCAgICAgIHwgIDYgKysr KysrCiA3IGZpbGVzIGNoYW5nZWQsIDY3IGluc2VydGlvbnMoKykKCmRpZmYgLS1naXQgYS9k b2Mvc3JjL3NnbWwvZnVuYy5zZ21sIGIvZG9jL3NyYy9zZ21sL2Z1bmMuc2dtbAppbmRleCBl MDllMjg5YTQzLi44YmRlZjZlYjMyIDEwMDY0NAotLS0gYS9kb2Mvc3JjL3NnbWwvZnVuYy5z Z21sCisrKyBiL2RvYy9zcmMvc2dtbC9mdW5jLnNnbWwKQEAgLTE5NzM1LDYgKzE5NzM1LDIw IEBAIFNFTEVDVCBOVUxMSUYodmFsdWUsICcobm9uZSknKSAuLi4KICAgICAgPC90aGVhZD4K IAogICAgICA8dGJvZHk+CisgICAgICA8cm93PgorICAgICAgIDxlbnRyeSByb2xlPSJmdW5j X3RhYmxlX2VudHJ5Ij48cGFyYSByb2xlPSJmdW5jX3NpZ25hdHVyZSI+CisgICAgICAgIDxp bmRleHRlcm0+CisgICAgICAgICA8cHJpbWFyeT5hbnlfdmFsdWU8L3ByaW1hcnk+CisgICAg ICAgIDwvaW5kZXh0ZXJtPgorICAgICAgICA8ZnVuY3Rpb24+YW55X3ZhbHVlPC9mdW5jdGlv bj4gKCA8dHlwZT5hbnllbGVtZW50PC90eXBlPiApCisgICAgICAgIDxyZXR1cm52YWx1ZT48 cmVwbGFjZWFibGU+c2FtZSBhcyBpbnB1dCB0eXBlPC9yZXBsYWNlYWJsZT48L3JldHVybnZh bHVlPgorICAgICAgIDwvcGFyYT4KKyAgICAgICA8cGFyYT4KKyAgICAgICAgUmV0dXJucyBh IG5vbi1kZXRlcm1pbmlzdGljIHZhbHVlIGZyb20gdGhlIG5vbi1udWxsIGlucHV0IHZhbHVl cy4KKyAgICAgICA8L3BhcmE+PC9lbnRyeT4KKyAgICAgICA8ZW50cnk+WWVzPC9lbnRyeT4K KyAgICAgIDwvcm93PgorCiAgICAgICA8cm93PgogICAgICAgIDxlbnRyeSByb2xlPSJmdW5j X3RhYmxlX2VudHJ5Ij48cGFyYSByb2xlPSJmdW5jX3NpZ25hdHVyZSI+CiAgICAgICAgIDxp bmRleHRlcm0+CmRpZmYgLS1naXQgYS9zcmMvYmFja2VuZC9jYXRhbG9nL3NxbF9mZWF0dXJl cy50eHQgYi9zcmMvYmFja2VuZC9jYXRhbG9nL3NxbF9mZWF0dXJlcy50eHQKaW5kZXggMzc2 Njc2MmFlMy4uMGViOTA1YzE3NyAxMDA2NDQKLS0tIGEvc3JjL2JhY2tlbmQvY2F0YWxvZy9z cWxfZmVhdHVyZXMudHh0CisrKyBiL3NyYy9iYWNrZW5kL2NhdGFsb2cvc3FsX2ZlYXR1cmVz LnR4dApAQCAtNTIwLDYgKzUyMCw3IEBAIFQ2MjIJVHJpZ29ub21ldHJpYyBmdW5jdGlvbnMJ CQlZRVMKIFQ2MjMJR2VuZXJhbCBsb2dhcml0aG0gZnVuY3Rpb25zCQkJWUVTCQogVDYyNAlD b21tb24gbG9nYXJpdGhtIGZ1bmN0aW9ucwkJCVlFUwkKIFQ2MjUJTElTVEFHRwkJCU5PCQor VDYyNglBTllfVkFMVUUJCQlZRVMJCiBUNjMxCUlOIHByZWRpY2F0ZSB3aXRoIG9uZSBsaXN0 IGVsZW1lbnQJCQlZRVMJCiBUNjQxCU11bHRpcGxlIGNvbHVtbiBhc3NpZ25tZW50CQkJTk8J b25seSBzb21lIHN5bnRheCB2YXJpYW50cyBzdXBwb3J0ZWQKIFQ2NTEJU1FMLXNjaGVtYSBz dGF0ZW1lbnRzIGluIFNRTCByb3V0aW5lcwkJCVlFUwkKZGlmZiAtLWdpdCBhL3NyYy9iYWNr ZW5kL3V0aWxzL2FkdC9taXNjLmMgYi9zcmMvYmFja2VuZC91dGlscy9hZHQvbWlzYy5jCmlu ZGV4IDIyMGRkYjhjMDEuLjBmMDAxMGIwNmQgMTAwNjQ0Ci0tLSBhL3NyYy9iYWNrZW5kL3V0 aWxzL2FkdC9taXNjLmMKKysrIGIvc3JjL2JhY2tlbmQvdXRpbHMvYWR0L21pc2MuYwpAQCAt MTA0MSwzICsxMDQxLDEzIEBAIHBnX2dldF9yZXBsaWNhX2lkZW50aXR5X2luZGV4KFBHX0ZV TkNUSU9OX0FSR1MpCiAJZWxzZQogCQlQR19SRVRVUk5fTlVMTCgpOwogfQorCisvKgorICog VHJhbnNpdGlvbiBmdW5jdGlvbiBmb3IgdGhlIEFOWV9WQUxVRSBhZ2dyZWdhdGUKKyAqLwor RGF0dW0KK2FueV92YWx1ZV90cmFuc2ZuKFBHX0ZVTkNUSU9OX0FSR1MpCit7CisJUEdfUkVU VVJOX0RBVFVNKFBHX0dFVEFSR19EQVRVTSgwKSk7Cit9CisKZGlmZiAtLWdpdCBhL3NyYy9p bmNsdWRlL2NhdGFsb2cvcGdfYWdncmVnYXRlLmRhdCBiL3NyYy9pbmNsdWRlL2NhdGFsb2cv cGdfYWdncmVnYXRlLmRhdAppbmRleCA0ZmVhN2Q4ZGMxLi5kNzg5NWNkNjc2IDEwMDY0NAot LS0gYS9zcmMvaW5jbHVkZS9jYXRhbG9nL3BnX2FnZ3JlZ2F0ZS5kYXQKKysrIGIvc3JjL2lu Y2x1ZGUvY2F0YWxvZy9wZ19hZ2dyZWdhdGUuZGF0CkBAIC02MzQsNCArNjM0LDggQEAKICAg YWdnZmluYWxmbiA9PiAnZGVuc2VfcmFua19maW5hbCcsIGFnZ2ZpbmFsZXh0cmEgPT4gJ3Qn LCBhZ2dmaW5hbG1vZGlmeSA9PiAndycsCiAgIGFnZ21maW5hbG1vZGlmeSA9PiAndycsIGFn Z3RyYW5zdHlwZSA9PiAnaW50ZXJuYWwnIH0sCiAKKyMgYW55X3ZhbHVlCit7IGFnZ2Zub2lk ID0+ICdhbnlfdmFsdWUoYW55ZWxlbWVudCknLCBhZ2d0cmFuc2ZuID0+ICdhbnlfdmFsdWVf dHJhbnNmbicsCisgIGFnZ2NvbWJpbmVmbiA9PiAnYW55X3ZhbHVlX3RyYW5zZm4nLCBhZ2d0 cmFuc3R5cGUgPT4gJ2FueWVsZW1lbnQnIH0sCisKIF0KZGlmZiAtLWdpdCBhL3NyYy9pbmNs dWRlL2NhdGFsb2cvcGdfcHJvYy5kYXQgYi9zcmMvaW5jbHVkZS9jYXRhbG9nL3BnX3Byb2Mu ZGF0CmluZGV4IGMwZjJhOGE3N2MuLmQwM2E3MmRhZjAgMTAwNjQ0Ci0tLSBhL3NyYy9pbmNs dWRlL2NhdGFsb2cvcGdfcHJvYy5kYXQKKysrIGIvc3JjL2luY2x1ZGUvY2F0YWxvZy9wZ19w cm9jLmRhdApAQCAtMTE5MTgsNCArMTE5MTgsMTIgQEAKICAgcHJvcmV0dHlwZSA9PiAnYnl0 ZWEnLCBwcm9hcmd0eXBlcyA9PiAncGdfYnJpbl9taW5tYXhfbXVsdGlfc3VtbWFyeScsCiAg IHByb3NyYyA9PiAnYnJpbl9taW5tYXhfbXVsdGlfc3VtbWFyeV9zZW5kJyB9LAogCit7IG9p ZCA9PiAnODk4MScsIGRlc2NyID0+ICdhcmJpdHJhcnkgdmFsdWUgZnJvbSBhbW9uZyBpbnB1 dCB2YWx1ZXMnLAorICBwcm9uYW1lID0+ICdhbnlfdmFsdWUnLCBwcm9raW5kID0+ICdhJywg cHJvaXNzdHJpY3QgPT4gJ2YnLAorICBwcm9yZXR0eXBlID0+ICdhbnllbGVtZW50JywgcHJv YXJndHlwZXMgPT4gJ2FueWVsZW1lbnQnLAorICBwcm9zcmMgPT4gJ2FnZ3JlZ2F0ZV9kdW1t eScgfSwKK3sgb2lkID0+ICc4OTgyJywgZGVzY3IgPT4gJ2FueV92YWx1ZSB0cmFuc2l0aW9u IGZ1bmN0aW9uJywKKyAgcHJvbmFtZSA9PiAnYW55X3ZhbHVlX3RyYW5zZm4nLCBwcm9yZXR0 eXBlID0+ICdhbnllbGVtZW50JywgcHJvYXJndHlwZXMgPT4gJ2FueWVsZW1lbnQgYW55ZWxl bWVudCcsCisgIHByb3NyYyA9PiAnYW55X3ZhbHVlX3RyYW5zZm4nIH0sCisKIF0KZGlmZiAt LWdpdCBhL3NyYy90ZXN0L3JlZ3Jlc3MvZXhwZWN0ZWQvYWdncmVnYXRlcy5vdXQgYi9zcmMv dGVzdC9yZWdyZXNzL2V4cGVjdGVkL2FnZ3JlZ2F0ZXMub3V0CmluZGV4IDgyZDA5NjE1MjQu Ljk1YmY0OWYzZDkgMTAwNjQ0Ci0tLSBhL3NyYy90ZXN0L3JlZ3Jlc3MvZXhwZWN0ZWQvYWdn cmVnYXRlcy5vdXQKKysrIGIvc3JjL3Rlc3QvcmVncmVzcy9leHBlY3RlZC9hZ2dyZWdhdGVz Lm91dApAQCAtMjUsNiArMjUsMjQgQEAgU0VMRUNUIGF2ZyhhKSBBUyBhdmdfMzIgRlJPTSBh Z2d0ZXN0IFdIRVJFIGEgPCAxMDA7CiAgMzIuNjY2NjY2NjY2NjY2NjY2NwogKDEgcm93KQog CitTRUxFQ1QgYW55X3ZhbHVlKHYpIEZST00gKFZBTFVFUyAoMSkpIEFTIHYgKHYpOworIGFu eV92YWx1ZSAKKy0tLS0tLS0tLS0tCisgICAgICAgICAxCisoMSByb3cpCisKK1NFTEVDVCBh bnlfdmFsdWUodikgRlJPTSAoVkFMVUVTIChOVUxMKSkgQVMgdiAodik7CisgYW55X3ZhbHVl IAorLS0tLS0tLS0tLS0KKyAKKygxIHJvdykKKworU0VMRUNUIGFueV92YWx1ZSh2KSBGUk9N IChWQUxVRVMgKGFycmF5WydoZWxsbycsICd3b3JsZCddKSkgQVMgdiAodik7CisgICBhbnlf dmFsdWUgICAKKy0tLS0tLS0tLS0tLS0tLQorIHtoZWxsbyx3b3JsZH0KKygxIHJvdykKKwog LS0gSW4gNy4xLCBhdmcoZmxvYXQ0KSBpcyBjb21wdXRlZCB1c2luZyBmbG9hdDggYXJpdGht ZXRpYy4KIC0tIFJvdW5kIHRoZSByZXN1bHQgdG8gMyBkaWdpdHMgdG8gYXZvaWQgcGxhdGZv cm0tc3BlY2lmaWMgcmVzdWx0cy4KIFNFTEVDVCBhdmcoYik6Om51bWVyaWMoMTAsMykgQVMg YXZnXzEwN185NDMgRlJPTSBhZ2d0ZXN0OwpAQCAtMjAyNSw2ICsyMDQzLDEyIEBAIGZyb20g KHZhbHVlcyAoJ2EnLCAnYicpKSBBUyB2KGZvbyxiYXIpOwogIGEKICgxIHJvdykKIAorc2Vs ZWN0IGFueV92YWx1ZSh2KSBmaWx0ZXIgKHdoZXJlIHYgPiAyKSBmcm9tICh2YWx1ZXMgKDEp LCAoMiksICgzKSkgYXMgdiAodik7CisgYW55X3ZhbHVlIAorLS0tLS0tLS0tLS0KKyAgICAg ICAgIDMKKygxIHJvdykKKwogLS0gb3V0ZXIgcmVmZXJlbmNlIGluIEZJTFRFUiAoUG9zdGdy ZVNRTCBleHRlbnNpb24pCiBzZWxlY3QgKHNlbGVjdCBjb3VudCgqKQogICAgICAgICBmcm9t ICh2YWx1ZXMgKDEpKSB0MChpbm5lcl9jKSkKZGlmZiAtLWdpdCBhL3NyYy90ZXN0L3JlZ3Jl c3Mvc3FsL2FnZ3JlZ2F0ZXMuc3FsIGIvc3JjL3Rlc3QvcmVncmVzcy9zcWwvYWdncmVnYXRl cy5zcWwKaW5kZXggZTgxYTIyNDY1Yi4uZTgzYzk4NGVkMCAxMDA2NDQKLS0tIGEvc3JjL3Rl c3QvcmVncmVzcy9zcWwvYWdncmVnYXRlcy5zcWwKKysrIGIvc3JjL3Rlc3QvcmVncmVzcy9z cWwvYWdncmVnYXRlcy5zcWwKQEAgLTI0LDYgKzI0LDEwIEBAIFNFTEVDVCBhdmcoZm91cikg QVMgYXZnXzEgRlJPTSBvbmVrOwogCiBTRUxFQ1QgYXZnKGEpIEFTIGF2Z18zMiBGUk9NIGFn Z3Rlc3QgV0hFUkUgYSA8IDEwMDsKIAorU0VMRUNUIGFueV92YWx1ZSh2KSBGUk9NIChWQUxV RVMgKDEpKSBBUyB2ICh2KTsKK1NFTEVDVCBhbnlfdmFsdWUodikgRlJPTSAoVkFMVUVTIChO VUxMKSkgQVMgdiAodik7CitTRUxFQ1QgYW55X3ZhbHVlKHYpIEZST00gKFZBTFVFUyAoYXJy YXlbJ2hlbGxvJywgJ3dvcmxkJ10pKSBBUyB2ICh2KTsKKwogLS0gSW4gNy4xLCBhdmcoZmxv YXQ0KSBpcyBjb21wdXRlZCB1c2luZyBmbG9hdDggYXJpdGhtZXRpYy4KIC0tIFJvdW5kIHRo ZSByZXN1bHQgdG8gMyBkaWdpdHMgdG8gYXZvaWQgcGxhdGZvcm0tc3BlY2lmaWMgcmVzdWx0 cy4KIApAQCAtODA2LDYgKzgxMCw4IEBAIGhhdmluZyBleGlzdHMgKHNlbGVjdCAxIGZyb20g b25layBiIHdoZXJlIHN1bShkaXN0aW5jdCBhLmZvdXIpID0gYi5mb3VyKTsKIHNlbGVjdCBt YXgoZm9vIENPTExBVEUgIkMiKSBmaWx0ZXIgKHdoZXJlIChiYXIgY29sbGF0ZSAiUE9TSVgi KSA+ICcwJykKIGZyb20gKHZhbHVlcyAoJ2EnLCAnYicpKSBBUyB2KGZvbyxiYXIpOwogCitz ZWxlY3QgYW55X3ZhbHVlKHYpIGZpbHRlciAod2hlcmUgdiA+IDIpIGZyb20gKHZhbHVlcyAo MSksICgyKSwgKDMpKSBhcyB2ICh2KTsKKwogLS0gb3V0ZXIgcmVmZXJlbmNlIGluIEZJTFRF UiAoUG9zdGdyZVNRTCBleHRlbnNpb24pCiBzZWxlY3QgKHNlbGVjdCBjb3VudCgqKQogICAg ICAgICBmcm9tICh2YWx1ZXMgKDEpKSB0MChpbm5lcl9jKSkKCmJhc2UtY29tbWl0OiBlZjcw MDJkYmUwYjA2ZTRlNWI0MmM4OWJlY2Q0ZWI5YmUyZTlhYTg5Ci0tIAoyLjM0LjEKCg== --------------pqb5hJtH4BTQXgSY6x1JJikZ--