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.94.2) (envelope-from ) id 1tPwmq-00GWpv-11 for pgsql-hackers@arkaria.postgresql.org; Tue, 24 Dec 2024 04:44:53 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1tPwmo-001XAi-Br for pgsql-hackers@arkaria.postgresql.org; Tue, 24 Dec 2024 04:44:50 +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.94.2) (envelope-from ) id 1tPwmn-001XAU-PG for pgsql-hackers@lists.postgresql.org; Tue, 24 Dec 2024 04:44:49 +0000 Received: from mail.postgrespro.ru ([93.174.131.139]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1tPwmg-001KhA-1q for pgsql-hackers@lists.postgresql.org; Tue, 24 Dec 2024 04:44:48 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=postgrespro.ru; s=mx2023; t=1735015480; bh=IVrOcEzcwDKD5HjMSiqXwm6T2YaYVVpzhpB46DkmMPY=; h=Message-ID:Date:User-Agent:To:From:Subject:From; b=0X5c5+rAsGAc/6iz6gR9xPszai/RczvRaL4kUbHldhwpKfcvHMM7iAc4HqzbdeFY8 196EVEWxRA9Fz7Ab7LPc2zB7gDMvL2YKpA4XtgAejyiDByPYRkGrG4K71KlaH7z70Y ZRbjyQl7qayf7S5Kq3vDE39qJyJsv43/QkTAtU5+oJ4rU1SucIDhCfUx3MQOy3Hc57 udZZoP5hRO7UBBhS5Bf8gG7DqLrX9/sfPAEjQNqQSHBAKEKmKgd/VUYMb/dxZ4S+qa YDVUJptwrg9XgkASQzdc8GS99cxPFqyZUYgjxqmckWiC786BSU7MI700bIiyV8d4rB iiXSVjd3sxaHw== Received: from [172.20.10.4] (unknown [89.113.148.147]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (Client did not present a certificate) (Authenticated sender: a.rybakina@postgrespro.ru) by mail.postgrespro.ru (Postfix/587) with ESMTPSA id A85AD5FD88 for ; Tue, 24 Dec 2024 07:44:40 +0300 (MSK) Content-Type: multipart/mixed; boundary="------------RFr2OLQFP0DiOhNs0p4fFhBK" Message-ID: <0b1f670d-b39d-4966-bf32-f0d502ebc564@postgrespro.ru> Date: Tue, 24 Dec 2024 07:44:38 +0300 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Content-Language: en-US To: PostgreSQL Hackers From: Alena Rybakina Subject: Exists pull-up application with JoinExpr X-KSMG-AntiPhishing: NotDetected X-KSMG-AntiSpam-Interceptor-Info: not scanned X-KSMG-AntiSpam-Status: not scanned, disabled by settings X-KSMG-AntiVirus: Kaspersky Secure Mail Gateway, version 2.1.0.7854, bases: 2024/12/24 02:51:00 #26909592 X-KSMG-AntiVirus-Status: NotDetected, skipped X-KSMG-LinksScanning: not scanned, disabled by settings X-KSMG-Message-Action: skipped X-KSMG-Rule-ID: 1 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. --------------RFr2OLQFP0DiOhNs0p4fFhBK Content-Type: multipart/alternative; boundary="------------GSiAM2qoBQaB00e4p8Z9hQIp" --------------GSiAM2qoBQaB00e4p8Z9hQIp Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit Hi, hackers! I found one pull-up that works if the inner join condition is written through the where condition, |create temp table ta (id int primary key, val int); insert into ta values(1,1); insert into ta values(2,2); ||insert into ta values(3,3);| |create temp table tb (id int primary key, aval int); insert into tb values(4,1); insert into tb values(5,1); insert into tb values(1,2); create temp table tc (id int primary key, aid int); insert into tc values(6,1); insert into tc values(7,2);| |EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) SELECT * FROM ta WHERE EXISTS (SELECT * FROM tb, tc WHERE ta.id = tb.id);| QUERY PLAN ------------------------------------------------------------------------- Nested Loop Semi Join (actual rows=1 loops=1) Buffers: local hit=6 -> Seq Scan on ta (actual rows=3 loops=1) Buffers: local hit=1 -> Nested Loop (actual rows=0 loops=3) Buffers: local hit=5 -> Index Only Scan using tb_pkey on tb (actual rows=0 loops=3) Index Cond: (id = ta.id) Heap Fetches: 1 Buffers: local hit=4 -> Seq Scan on tc (actual rows=1 loops=1) Buffers: local hit=1 Planning: Buffers: shared hit=67 read=12 (14 rows) but it doesn't work if it is written through the outside condition. |alena@postgres=# EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) SELECT * FROM ta WHERE EXISTS (SELECT * FROM tb JOIN tc ON ta.id = tb.id); QUERY PLAN ------------------------------------------------------ Seq Scan on ta (actual rows=1 loops=1) Filter: EXISTS(SubPlan 1) Rows Removed by Filter: 2 Buffers: local hit=5 SubPlan 1 -> Nested Loop (actual rows=0 loops=3) Buffers: local hit=4 -> Seq Scan on tb (actual rows=0 loops=3) Filter: (ta.id = id) Rows Removed by Filter: 3 Buffers: local hit=3 -> Seq Scan on tc (actual rows=1 loops=1) Buffers: local hit=1 Planning: Buffers: shared hit=16 read=9 (15 rows) | |I have written a patch to add this functionality and now it gives an query plan: | |alena@postgres=# EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)  SELECT *    FROM ta   WHERE EXISTS (SELECT *                   FROM tb JOIN tc                   ON ta.id = tb.id);                      QUERY PLAN -------------------------------------------------------------------------  Nested Loop Semi Join (actual rows=1 loops=1)    Buffers: local hit=6    ->  Seq Scan on ta (actual rows=3 loops=1)          Buffers: local hit=1    ->  Nested Loop (actual rows=0 loops=3)          Buffers: local hit=5          ->  Index Only Scan using tb_pkey on tb (actual rows=0 loops=3)                Index Cond: (id = ta.id)                Heap Fetches: 1                Buffers: local hit=4          ->  Seq Scan on tc (actual rows=1 loops=1)                Buffers: local hit=1 (12 rows)| tb and tc form a Cartesian product, but in the case of the intersection condition with tuples from the table ta (ta.id = tb.id). So, according to the join condition, tb intersects only with 1, and only it gets into the result, but at the same time they appear twice - this is because of the Cartesian product of tb with tc |*How it works:* | I rewrote the code a bit so that it considers not only the quals in jointree->quals, but also those in join expression (subselect->jointree->fromlist). If they satisfy the conditions for using pull up, I add them to the list of clauses and form a "Bool" expression from them, joined by an "AND" operation. -- Regards, Alena Rybakina Postgres Professional --------------GSiAM2qoBQaB00e4p8Z9hQIp Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: 8bit

Hi, hackers!

I found one pull-up that works if the inner join condition is written through the where condition,

create temp table ta (id int primary key, val int);
insert into ta values(1,1);
insert into ta values(2,2);
insert into ta values(3,3);

create temp table tb (id int primary key, aval int);
insert into tb values(4,1);
insert into tb values(5,1);
insert into tb values(1,2);

create temp table tc (id int primary key, aid int);
insert into tc values(6,1);
insert into tc values(7,2);

EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
 SELECT *
   FROM ta
  WHERE EXISTS (SELECT *
                  FROM tb, tc
                  WHERE ta.id = tb.id);
                               QUERY PLAN                                
-------------------------------------------------------------------------
 Nested Loop Semi Join (actual rows=1 loops=1)
   Buffers: local hit=6
   ->  Seq Scan on ta (actual rows=3 loops=1)
         Buffers: local hit=1
   ->  Nested Loop (actual rows=0 loops=3)
         Buffers: local hit=5
         ->  Index Only Scan using tb_pkey on tb (actual rows=0 loops=3)
               Index Cond: (id = ta.id)
               Heap Fetches: 1
               Buffers: local hit=4
         ->  Seq Scan on tc (actual rows=1 loops=1)
               Buffers: local hit=1
 Planning:
   Buffers: shared hit=67 read=12
(14 rows)

but it doesn't work if it is written through the outside condition.

alena@postgres=# EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
 SELECT *
   FROM ta
  WHERE EXISTS (SELECT *
                  FROM tb JOIN tc
                  ON ta.id = tb.id);
                      QUERY PLAN                      
------------------------------------------------------
 Seq Scan on ta (actual rows=1 loops=1)
   Filter: EXISTS(SubPlan 1)
   Rows Removed by Filter: 2
   Buffers: local hit=5
   SubPlan 1
     ->  Nested Loop (actual rows=0 loops=3)
           Buffers: local hit=4
           ->  Seq Scan on tb (actual rows=0 loops=3)
                 Filter: (ta.id = id)
                 Rows Removed by Filter: 3
                 Buffers: local hit=3
           ->  Seq Scan on tc (actual rows=1 loops=1)
                 Buffers: local hit=1
 Planning:
   Buffers: shared hit=16 read=9
(15 rows)

I have written a patch to add this functionality and now it gives an query plan:

alena@postgres=# EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
 SELECT *
   FROM ta
  WHERE EXISTS (SELECT *
                  FROM tb JOIN tc
                  ON ta.id = tb.id);
                     QUERY PLAN                                
-------------------------------------------------------------------------
 Nested Loop Semi Join (actual rows=1 loops=1)
   Buffers: local hit=6
   ->  Seq Scan on ta (actual rows=3 loops=1)
         Buffers: local hit=1
   ->  Nested Loop (actual rows=0 loops=3)
         Buffers: local hit=5
         ->  Index Only Scan using tb_pkey on tb (actual rows=0 loops=3)
               Index Cond: (id = ta.id)
               Heap Fetches: 1
               Buffers: local hit=4
         ->  Seq Scan on tc (actual rows=1 loops=1)
               Buffers: local hit=1
(12 rows)

tb and tc form a Cartesian product, but in the case of the intersection condition with tuples from the table ta (ta.id = tb.id). So, according to the join condition, tb intersects only with 1, and only it gets into the result, but at the same time they appear twice - this is because of the Cartesian product of tb with tc

How it works:

I rewrote the code a bit so that it considers not only the quals in jointree->quals, but also those in join expression (subselect->jointree->fromlist). If they satisfy the conditions for using pull up, I add them to the list of clauses and form a "Bool" expression from them, joined by an "AND" operation.

-- 

Regards, Alena Rybakina Postgres Professional

--------------GSiAM2qoBQaB00e4p8Z9hQIp-- --------------RFr2OLQFP0DiOhNs0p4fFhBK Content-Type: text/x-patch; charset=UTF-8; name="0001-Add-EXISTS-pull-up-if-subquery-join-expressions.patch" Content-Disposition: attachment; filename*0="0001-Add-EXISTS-pull-up-if-subquery-join-expressions.patch" Content-Transfer-Encoding: base64 RnJvbSAzYjNkNzYxY2Q0ZDY3ZTI5OWNkYmQzYzJlNmNmNTI1NmYyN2RhNWViIE1vbiBTZXAg MTcgMDA6MDA6MDAgMjAwMQpGcm9tOiBBbGVuYSBSeWJha2luYSA8YS5yeWJha2luYUBwb3N0 Z3Jlc3Byby5ydT4KRGF0ZTogVHVlLCAyNCBEZWMgMjAyNCAwNzoyOTo0MiArMDMwMApTdWJq ZWN0OiBbUEFUQ0hdIEFkZCBFWElTVFMgcHVsbCB1cCBpZiBzdWJxdWVyeSBqb2luIGV4cHJl c3Npb25zICBhcmUKIGluZGVwZW5kZW50IGFuZCBoYXZlIGEgcmVmZXJlbmNlIG9ubHkgdG8g dGhlIG91dGVyIHBhcnQgb2YgdGhlIHN1YnF1ZXJ5ICBvcgogdGhleSBhcmUgY29uc3RhbnQu IFdlIHNob3VsZCB0cmFuc2Zvcm0gZXhwcmVzc2lvbiBvbnRvIHN1YnNlbGVjdCBxdWVyeSAg d2l0aAogdXNpbmcgb24gdGhlIHJlZmVyZW5jZWQgdGFibGUuIFdlIG5lZWQgb25seSB0byBr bm93IHRoYXQgdGhlIHRhYmxlIGlzICBub3QKIGVtcHR5LgoKVGhpcyBxdWVyeToKU0VMRUNU ICoKICAgRlJPTSB0YQogIFdIRVJFIEVYSVNUUyAoU0VMRUNUICoKICAgICAgICAgICAgICAg ICAgRlJPTSB0YgogICAgICAgICAgICAgICAgICAgbGVmdCBvdXRlciBKT0lOIHRjCiAgICAg ICAgICAgICAgICAgICAgT04gdGEuaWQgPSB0Yi5pZCk7CmNhbiBiZSB0cmFuc2Zvcm1lZCB0 bzoKc2VsZWN0ICogZnJvbSB0YSB3aGVyZSBleGlzdHMgKHNlbGVjdCAqIGZyb20gdGIgbGlt aXQgMSk7Ci0tLQogc3JjL2JhY2tlbmQvb3B0aW1pemVyL3BsYW4vc3Vic2VsZWN0LmMgIHwg IDk0ICsrKysrKysrKysrKysrLQogc3JjL3Rlc3QvcmVncmVzcy9leHBlY3RlZC9zdWJzZWxl Y3Qub3V0IHwgMTUxICsrKysrKysrKysrKysrKysrKysrKysrKwogc3JjL3Rlc3QvcmVncmVz cy9zcWwvc3Vic2VsZWN0LnNxbCAgICAgIHwgIDY1ICsrKysrKysrKysKIDMgZmlsZXMgY2hh bmdlZCwgMzA1IGluc2VydGlvbnMoKyksIDUgZGVsZXRpb25zKC0pCgpkaWZmIC0tZ2l0IGEv c3JjL2JhY2tlbmQvb3B0aW1pemVyL3BsYW4vc3Vic2VsZWN0LmMgYi9zcmMvYmFja2VuZC9v cHRpbWl6ZXIvcGxhbi9zdWJzZWxlY3QuYwppbmRleCBlZDYyZTNhMGZjZi4uOWIyYjZhZGRm YWYgMTAwNjQ0Ci0tLSBhL3NyYy9iYWNrZW5kL29wdGltaXplci9wbGFuL3N1YnNlbGVjdC5j CisrKyBiL3NyYy9iYWNrZW5kL29wdGltaXplci9wbGFuL3N1YnNlbGVjdC5jCkBAIC0xMzc2 LDYgKzEzNzYsMTggQEAgY29udmVydF9FWElTVFNfc3VibGlua190b19qb2luKFBsYW5uZXJJ bmZvICpyb290LCBTdWJMaW5rICpzdWJsaW5rLAogCWludAkJCXZhcm5vOwogCVJlbGlkcwkJ Y2xhdXNlX3Zhcm5vczsKIAlSZWxpZHMJCXVwcGVyX3Zhcm5vczsKKwlMaXN0Q2VsbCAqbGM7 CisJTGlzdCAqY2xhdXNlcyA9IE5JTDsKKwlMaXN0ICphbGxfY2xhdXNlcyA9IE5JTDsKKwlp bnQgZmlyc3RfZWxlbSA9IHRydWU7CisJQ29uc3QgKmNvbnN0X3ZhciA9IG1ha2VDb25zdChC T09MT0lELAorCQkJCQkJCQkJLTEsCisJCQkJCQkJCQlJbnZhbGlkT2lkLAorCQkJCQkJCQkJ c2l6ZW9mKGJvb2wpLAorCQkJCQkJCQkJKERhdHVtKSAxLAorCQkJCQkJCQkJZmFsc2UsCisJ CQkJCQkJCQl0cnVlKTsKKwogCiAJQXNzZXJ0KHN1YmxpbmstPnN1YkxpbmtUeXBlID09IEVY SVNUU19TVUJMSU5LKTsKIApAQCAtMTQwMywxNCArMTQxNSw4NiBAQCBjb252ZXJ0X0VYSVNU U19zdWJsaW5rX3RvX2pvaW4oUGxhbm5lckluZm8gKnJvb3QsIFN1YkxpbmsgKnN1Ymxpbmss CiAJICogd2l0aCBub3BsYWNlIHRvIGV2YWx1YXRlIHRoZSB0YXJnZXRsaXN0LgogCSAqLwog CWlmICghc2ltcGxpZnlfRVhJU1RTX3F1ZXJ5KHJvb3QsIHN1YnNlbGVjdCkpCi0JCXJldHVy biBOVUxMOworCXsKKwkJCXJldHVybiBOVUxMOworCX0KKworCWlmIChzdWJzZWxlY3QtPmpv aW50cmVlLT5xdWFscykKKwkJYWxsX2NsYXVzZXMgPSBsYXBwZW5kKGFsbF9jbGF1c2VzLCBz dWJzZWxlY3QtPmpvaW50cmVlLT5xdWFscyk7CisKKwlzdWJzZWxlY3QtPmpvaW50cmVlLT5x dWFscyA9IE5VTEw7CisKKwkvKiBHYXRoZXIgYWxsIGNsYXVzZXMgaW4gbWFpbiBsaXN0IGZv ciB0aGUgZnVydGhlciBjb25zaWRlcmF0aW9uICovCisJYWxsX2NsYXVzZXMgPSBsaXN0X2Nv bmNhdChhbGxfY2xhdXNlcywgc3Vic2VsZWN0LT5qb2ludHJlZS0+ZnJvbWxpc3QpOwogCiAJ LyoKLQkgKiBTZXBhcmF0ZSBvdXQgdGhlIFdIRVJFIGNsYXVzZS4gIChXZSBjb3VsZCB0aGVv cmV0aWNhbGx5IGFsc28gcmVtb3ZlCi0JICogdG9wLWxldmVsIHBsYWluIEpPSU4vT04gY2xh dXNlcywgYnV0IGl0J3MgcHJvYmFibHkgbm90IHdvcnRoIHRoZQotCSAqIHRyb3VibGUuKQor CSAqIFdlIHdpbGwgYWJsZSB0byByZW1vdmUgdG9wLWxldmVsIHBsYWluIEpPSU4vT04gY2xh dXNlcyBpZiB0aGV5IGFyZSBub3Qgb3V0ZXIgam9pbi4KIAkgKi8KLQl3aGVyZUNsYXVzZSA9 IHN1YnNlbGVjdC0+am9pbnRyZWUtPnF1YWxzOworCWZvcmVhY2ggKGxjLCBhbGxfY2xhdXNl cykKKwl7CisJCU5vZGUgKmplID0gKChOb2RlICopIGxmaXJzdChsYykpOworCisJCXdoZXJl Q2xhdXNlID0gamU7CisKKwkJaWYgKElzQShqZSwgUmFuZ2VUYmxSZWYpKQorCQl7CisJCQln b3RvIGVuZDsKKwkJfQorCisJCWlmICgoSXNBKGplLCBKb2luRXhwcikgJiYgKChKb2luRXhw ciAqKWplKS0+am9pbnR5cGUgIT0gSk9JTl9JTk5FUikpCisJCXsKKwkJCWdvdG8gZW5kOwor CQl9CisKKwkJaWYgKElzQShqZSwgSm9pbkV4cHIpICYmICgoSm9pbkV4cHIgKilqZSktPnF1 YWxzICE9IE5VTEwpCisJCQl3aGVyZUNsYXVzZSA9ICgoSm9pbkV4cHIgKilqZSktPnF1YWxz OworCisJCS8qCisJCSogT24gdGhlIG90aGVyIGhhbmQsIHRoZSBXSEVSRSBjbGF1c2UgbXVz dCBjb250YWluIHNvbWUgVmFycyBvZiB0aGUKKwkJKiBwYXJlbnQgcXVlcnksIGVsc2UgaXQn cyBub3QgZ29ubmEgYmUgYSBqb2luLgorCQkqLworCQlpZiAoIWNvbnRhaW5fdmFyc19vZl9s ZXZlbCh3aGVyZUNsYXVzZSwgMSkpCisJCXsKKwkJCWdvdG8gZW5kOworCQl9CisKKwkJLyoK KwkJKiBXZSBkb24ndCByaXNrIG9wdGltaXppbmcgaWYgdGhlIFdIRVJFIGNsYXVzZSBpcyB2 b2xhdGlsZSwgZWl0aGVyLgorCQkqLworCQlpZiAoY29udGFpbl92b2xhdGlsZV9mdW5jdGlv bnMod2hlcmVDbGF1c2UpKQorCQl7CisJCQlnb3RvIGVuZDsKKwkJfQorCisJCS8qCisJCSAq IEluIGNhc2Ugb2YgYSBzdWNjZXNzZnVsIGF0dGVtcHQsIHJlcGxhY2VzIGl0IHdpdGggdGhl IGNvcnJlY3QgY29uZGl0aW9uCisJCSAqLworCQlpZiAoSXNBKGplLCBKb2luRXhwcikpCisJ CQkoKEpvaW5FeHByICopamUpLT5xdWFscyA9IChOb2RlICopIGNvbnN0X3ZhcjsKKworCQlj bGF1c2VzID0gbGFwcGVuZChjbGF1c2VzLCB3aGVyZUNsYXVzZSk7CisKKwkJZmlyc3RfZWxl bSA9IGZhbHNlOworCQlzdWJzZWxlY3QtPmpvaW50cmVlLT5mcm9tbGlzdCA9IGxpc3RfZGVs ZXRlX3B0cihzdWJzZWxlY3QtPmpvaW50cmVlLT5mcm9tbGlzdCwgbGMpOworCisJCWVuZDoK KwkJCWlmIChmaXJzdF9lbGVtKQorCQkJCXJldHVybiBOVUxMOworCQkJY29udGludWU7CisJ fQorCisJbGlzdF9mcmVlKGFsbF9jbGF1c2VzKTsKKworCS8qIFdlIGRvbid0IGhhdmUgYW55 IGNsdXNlcyBmb3IgcHVsbC11cCBjcmVhdGlvbiAqLworCWlmIChjbGF1c2VzID09IE5JTCkK KwkJcmV0dXJuIE5VTEw7CisJZWxzZQorCQkvKiBXZSBjYW4gZWFzaWx5IGNvbWJpbmUgY2xh dXNlcyB0aHJvdWdoIEFORCBvcGVyYXRvciBiZWNhdXNlIHRoZXkgYXJlIGluZGVwZW5kZW50 ICovCisJCXdoZXJlQ2xhdXNlID0gbGlzdF9sZW5ndGgoY2xhdXNlcykgPiAxID8KKwkJCQkJ CQkoTm9kZSAqKSBtYWtlQm9vbEV4cHIoQU5EX0VYUFIsIGNsYXVzZXMsIC0xKSA6CisJCQkJ CQkJKE5vZGUgKikgbGluaXRpYWwoY2xhdXNlcyk7CisKKwogCXN1YnNlbGVjdC0+am9pbnRy ZWUtPnF1YWxzID0gTlVMTDsKIAogCS8qCmRpZmYgLS1naXQgYS9zcmMvdGVzdC9yZWdyZXNz L2V4cGVjdGVkL3N1YnNlbGVjdC5vdXQgYi9zcmMvdGVzdC9yZWdyZXNzL2V4cGVjdGVkL3N1 YnNlbGVjdC5vdXQKaW5kZXggZWJjNTQ1ZTI0NjEuLjY4MDZmYTliYjA2IDEwMDY0NAotLS0g YS9zcmMvdGVzdC9yZWdyZXNzL2V4cGVjdGVkL3N1YnNlbGVjdC5vdXQKKysrIGIvc3JjL3Rl c3QvcmVncmVzcy9leHBlY3RlZC9zdWJzZWxlY3Qub3V0CkBAIC04MTIsNiArODEyLDE1NyBA QCB3aGVyZSBleGlzdHMgKAogICAgICAgZnJvbSB0ZXh0X3RibCApIHNzCiAgIHdoZXJlIHJv YWQubmFtZSA9IHNzLmYxICk7CiByb2xsYmFjazsKKy0tIFRlc3QgY2FzZSBmb3IgZXhpc3Qg c3VibGluayB3aGVyZSB3ZSBjYW4gY29uc2lkZXIgc29tZSB1bmRlcGVuZGVudCBleHByZXNz aW9uCistLSB3aXRoIG91dGVyIGxpbmsKKy0tCitFWFBMQUlOIChBTkFMWVpFLCBDT1NUUyBP RkYsIFNVTU1BUlkgT0ZGLCBUSU1JTkcgT0ZGKQorIFNFTEVDVCAxCisgICBGUk9NIHRhCisg IFdIRVJFIEVYSVNUUyAoU0VMRUNUIDEKKyAgICAgICAgICAgICAgICAgIEZST00gdGIKKyAg ICAgICAgICAgICAgICAgIEpPSU4gdGMKKyAgICAgICAgICAgICAgICAgICAgT04gdGEuaWQg PSB0Yi5pZCk7CisgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUVVFUlkgUExBTiAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCistLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCisg TmVzdGVkIExvb3AgU2VtaSBKb2luIChhY3R1YWwgcm93cz0yIGxvb3BzPTEpCisgICAtPiAg U2VxIFNjYW4gb24gdGEgKGFjdHVhbCByb3dzPTIgbG9vcHM9MSkKKyAgIC0+ICBOZXN0ZWQg TG9vcCAoYWN0dWFsIHJvd3M9MSBsb29wcz0yKQorICAgICAgICAgLT4gIEluZGV4IE9ubHkg U2NhbiB1c2luZyB0Yl9wa2V5IG9uIHRiIChhY3R1YWwgcm93cz0xIGxvb3BzPTIpCisgICAg ICAgICAgICAgICBJbmRleCBDb25kOiAoaWQgPSB0YS5pZCkKKyAgICAgICAgICAgICAgIEhl YXAgRmV0Y2hlczogMgorICAgICAgICAgLT4gIFNlcSBTY2FuIG9uIHRjIChhY3R1YWwgcm93 cz0xIGxvb3BzPTIpCisoNyByb3dzKQorCitFWFBMQUlOIChBTkFMWVpFLCBDT1NUUyBPRkYs IFNVTU1BUlkgT0ZGLCBUSU1JTkcgT0ZGKQorIFNFTEVDVCAxCisgICBGUk9NIHRhCisgIFdI RVJFIEVYSVNUUyAoU0VMRUNUIDEKKyAgICAgICAgICAgICAgICAgIEZST00gdGIKKyAgICAg ICAgICAgICAgICAgIEpPSU4gdGMKKyAgICAgICAgICAgICAgICAgICAgT04gdGEuaWQgPSB0 Yy5pZCk7CisgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUVVFUlkgUExBTiAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgCistLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCisgTmVz dGVkIExvb3AgU2VtaSBKb2luIChhY3R1YWwgcm93cz0yIGxvb3BzPTEpCisgICAtPiAgU2Vx IFNjYW4gb24gdGEgKGFjdHVhbCByb3dzPTIgbG9vcHM9MSkKKyAgIC0+ICBOZXN0ZWQgTG9v cCAoYWN0dWFsIHJvd3M9MSBsb29wcz0yKQorICAgICAgICAgLT4gIEluZGV4IE9ubHkgU2Nh biB1c2luZyB0Y19wa2V5IG9uIHRjIChhY3R1YWwgcm93cz0xIGxvb3BzPTIpCisgICAgICAg ICAgICAgICBJbmRleCBDb25kOiAoaWQgPSB0YS5pZCkKKyAgICAgICAgICAgICAgIEhlYXAg RmV0Y2hlczogMgorICAgICAgICAgLT4gIFNlcSBTY2FuIG9uIHRiIChhY3R1YWwgcm93cz0x IGxvb3BzPTIpCisoNyByb3dzKQorCistLSBKb2luIGNvbXBvdW5kIGV4cHJlc3Npb24KK0VY UExBSU4gKEFOQUxZWkUsIENPU1RTIE9GRiwgU1VNTUFSWSBPRkYsIFRJTUlORyBPRkYpCisg U0VMRUNUIDEKKyAgIEZST00gdGEKKyAgV0hFUkUgRVhJU1RTIChTRUxFQ1QgMQorICAgICAg ICAgICAgICAgICAgRlJPTSB0YgorICAgICAgICAgICAgICAgICAgSk9JTiB0YworICAgICAg ICAgICAgICAgICAgICBPTiB0YS5pZCA9IHRjLmlkIGFuZAorICAgICAgICAgICAgICAgICAg ICAgICB0YS5pZCA9IHRiLmlkKTsKKyAgICAgICAgICAgICAgICAgICAgICAgICBRVUVSWSBQ TEFOICAgICAgICAgICAgICAgICAgICAgICAgICAKKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KKyBIYXNoIFJpZ2h0IFNl bWkgSm9pbiAoYWN0dWFsIHJvd3M9MiBsb29wcz0xKQorICAgSGFzaCBDb25kOiAodGMuaWQg PSB0YS5pZCkKKyAgIC0+ICBIYXNoIEpvaW4gKGFjdHVhbCByb3dzPTIgbG9vcHM9MSkKKyAg ICAgICAgIEhhc2ggQ29uZDogKHRiLmlkID0gdGMuaWQpCisgICAgICAgICAtPiAgU2VxIFNj YW4gb24gdGIgKGFjdHVhbCByb3dzPTQgbG9vcHM9MSkKKyAgICAgICAgIC0+ICBIYXNoIChh Y3R1YWwgcm93cz0yIGxvb3BzPTEpCisgICAgICAgICAgICAgICBCdWNrZXRzOiA0MDk2ICBC YXRjaGVzOiAxICBNZW1vcnkgVXNhZ2U6IDMza0IKKyAgICAgICAgICAgICAgIC0+ICBTZXEg U2NhbiBvbiB0YyAoYWN0dWFsIHJvd3M9MiBsb29wcz0xKQorICAgLT4gIEhhc2ggKGFjdHVh bCByb3dzPTIgbG9vcHM9MSkKKyAgICAgICAgIEJ1Y2tldHM6IDQwOTYgIEJhdGNoZXM6IDEg IE1lbW9yeSBVc2FnZTogMzNrQgorICAgICAgICAgLT4gIFNlcSBTY2FuIG9uIHRhIChhY3R1 YWwgcm93cz0yIGxvb3BzPTEpCisoMTEgcm93cykKKworRVhQTEFJTiAoQU5BTFlaRSwgQ09T VFMgT0ZGLCBTVU1NQVJZIE9GRiwgVElNSU5HIE9GRikKKyBTRUxFQ1QgMQorICAgRlJPTSB0 YQorICBXSEVSRSBFWElTVFMgKFNFTEVDVCAxCisgICAgICAgICAgICAgICAgICBGUk9NIHRi CisgICAgICAgICAgICAgICAgICBKT0lOIHRjCisgICAgICAgICAgICAgICAgICAgIE9OIHRh LmlkID0gdGMuaWQgYW5kCisgICAgICAgICAgICAgICAgICAgICAgIHRhLmlkID0gdGIuaWQp OworICAgICAgICAgICAgICAgICAgICAgICAgIFFVRVJZIFBMQU4gICAgICAgICAgICAgICAg ICAgICAgICAgIAorLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tLS0tLS0tLS0tLQorIEhhc2ggUmlnaHQgU2VtaSBKb2luIChhY3R1YWwgcm93 cz0yIGxvb3BzPTEpCisgICBIYXNoIENvbmQ6ICh0Yy5pZCA9IHRhLmlkKQorICAgLT4gIEhh c2ggSm9pbiAoYWN0dWFsIHJvd3M9MiBsb29wcz0xKQorICAgICAgICAgSGFzaCBDb25kOiAo dGIuaWQgPSB0Yy5pZCkKKyAgICAgICAgIC0+ICBTZXEgU2NhbiBvbiB0YiAoYWN0dWFsIHJv d3M9NCBsb29wcz0xKQorICAgICAgICAgLT4gIEhhc2ggKGFjdHVhbCByb3dzPTIgbG9vcHM9 MSkKKyAgICAgICAgICAgICAgIEJ1Y2tldHM6IDQwOTYgIEJhdGNoZXM6IDEgIE1lbW9yeSBV c2FnZTogMzNrQgorICAgICAgICAgICAgICAgLT4gIFNlcSBTY2FuIG9uIHRjIChhY3R1YWwg cm93cz0yIGxvb3BzPTEpCisgICAtPiAgSGFzaCAoYWN0dWFsIHJvd3M9MiBsb29wcz0xKQor ICAgICAgICAgQnVja2V0czogNDA5NiAgQmF0Y2hlczogMSAgTWVtb3J5IFVzYWdlOiAzM2tC CisgICAgICAgICAtPiAgU2VxIFNjYW4gb24gdGEgKGFjdHVhbCByb3dzPTIgbG9vcHM9MSkK KygxMSByb3dzKQorCistLSBDb21wb3VuZCBleHByZXNzaW9uIHdpdGggY29uc3QgdHlwZQor RVhQTEFJTiAoQU5BTFlaRSwgQ09TVFMgT0ZGLCBTVU1NQVJZIE9GRiwgVElNSU5HIE9GRikK KyBTRUxFQ1QgMQorICAgRlJPTSB0YQorICBXSEVSRSBFWElTVFMgKFNFTEVDVCAxCisgICAg ICAgICAgICAgICAgICBGUk9NIHRiCisgICAgICAgICAgICAgICAgICBKT0lOIHRjCisgICAg ICAgICAgICAgICAgICAgIE9OIHRhLmlkID0gdGMuaWQgYW5kCisgICAgICAgICAgICAgICAg ICAgICAgIHRhLmlkID0gMSk7CisgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUVVF UlkgUExBTiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCistLS0tLS0tLS0tLS0t LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tCisgTmVzdGVkIExvb3AgU2VtaSBKb2luIChhY3R1YWwgcm93cz0xIGxvb3BzPTEp CisgICAtPiAgSW5kZXggT25seSBTY2FuIHVzaW5nIHRhX3BrZXkgb24gdGEgKGFjdHVhbCBy b3dzPTEgbG9vcHM9MSkKKyAgICAgICAgIEluZGV4IENvbmQ6IChpZCA9IDEpCisgICAgICAg ICBIZWFwIEZldGNoZXM6IDEKKyAgIC0+ICBOZXN0ZWQgTG9vcCAoYWN0dWFsIHJvd3M9MSBs b29wcz0xKQorICAgICAgICAgLT4gIEluZGV4IE9ubHkgU2NhbiB1c2luZyB0Y19wa2V5IG9u IHRjIChhY3R1YWwgcm93cz0xIGxvb3BzPTEpCisgICAgICAgICAgICAgICBJbmRleCBDb25k OiAoaWQgPSAxKQorICAgICAgICAgICAgICAgSGVhcCBGZXRjaGVzOiAxCisgICAgICAgICAt PiAgU2VxIFNjYW4gb24gdGIgKGFjdHVhbCByb3dzPTEgbG9vcHM9MSkKKyg5IHJvd3MpCisK K0VYUExBSU4gKEFOQUxZWkUsIENPU1RTIE9GRiwgU1VNTUFSWSBPRkYsIFRJTUlORyBPRkYp CisgU0VMRUNUIDEKKyAgIEZST00gdGEKKyAgV0hFUkUgRVhJU1RTIChTRUxFQ1QgMQorICAg ICAgICAgICAgICAgICAgRlJPTSB0YgorICAgICAgICAgICAgICAgICAgSk9JTiB0YworICAg ICAgICAgICAgICAgICAgICBPTiB0Yi5pZCA9IDEgYW5kCisgICAgICAgICAgICAgICAgICAg ICAgIHRhLmlkID0gMSk7CisgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUVVFUlkg UExBTiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCistLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tCisgTmVzdGVkIExvb3AgU2VtaSBKb2luIChhY3R1YWwgcm93cz0xIGxvb3BzPTEpCisg ICAtPiAgSW5kZXggT25seSBTY2FuIHVzaW5nIHRhX3BrZXkgb24gdGEgKGFjdHVhbCByb3dz PTEgbG9vcHM9MSkKKyAgICAgICAgIEluZGV4IENvbmQ6IChpZCA9IDEpCisgICAgICAgICBI ZWFwIEZldGNoZXM6IDEKKyAgIC0+ICBOZXN0ZWQgTG9vcCAoYWN0dWFsIHJvd3M9MSBsb29w cz0xKQorICAgICAgICAgLT4gIEluZGV4IE9ubHkgU2NhbiB1c2luZyB0Yl9wa2V5IG9uIHRi IChhY3R1YWwgcm93cz0xIGxvb3BzPTEpCisgICAgICAgICAgICAgICBJbmRleCBDb25kOiAo aWQgPSAxKQorICAgICAgICAgICAgICAgSGVhcCBGZXRjaGVzOiAxCisgICAgICAgICAtPiAg U2VxIFNjYW4gb24gdGMgKGFjdHVhbCByb3dzPTEgbG9vcHM9MSkKKyg5IHJvd3MpCisKKy0t IERpc2FibGVkIHB1bGwgdXAgYmVjYXVzZSBpdCBpcyBhcHBsY2FwYWJsZSBmb3IgSU5ORVIg Sk9JTiBjb25uZWN0aW9uCitFWFBMQUlOIChBTkFMWVpFLCBDT1NUUyBPRkYsIFNVTU1BUlkg T0ZGLCBUSU1JTkcgT0ZGKQorIFNFTEVDVCAxCisgICBGUk9NIHRhCisgIFdIRVJFIEVYSVNU UyAoU0VMRUNUIDEKKyAgICAgICAgICAgICAgICAgIEZST00gdGIKKyAgICAgICAgICAgICAg ICAgIFJJR0hUIEpPSU4gdGMKKyAgICAgICAgICAgICAgICAgICAgT04gdGEuaWQgPSB0Yy5p ZCk7CisgICAgICAgICAgICAgICAgICAgICAgICAgUVVFUlkgUExBTiAgICAgICAgICAgICAg ICAgICAgICAgICAKKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t LS0tLS0tLS0tLS0tLS0tLS0tLQorIFNlcSBTY2FuIG9uIHRhIChhY3R1YWwgcm93cz0yIGxv b3BzPTEpCisgICBGaWx0ZXI6IEVYSVNUUyhTdWJQbGFuIDEpCisgICBTdWJQbGFuIDEKKyAg ICAgLT4gIE5lc3RlZCBMb29wIExlZnQgSm9pbiAoYWN0dWFsIHJvd3M9MSBsb29wcz0yKQor ICAgICAgICAgICBKb2luIEZpbHRlcjogKHRhLmlkID0gdGMuaWQpCisgICAgICAgICAgIFJv d3MgUmVtb3ZlZCBieSBKb2luIEZpbHRlcjogMgorICAgICAgICAgICAtPiAgU2VxIFNjYW4g b24gdGMgKGFjdHVhbCByb3dzPTEgbG9vcHM9MikKKyAgICAgICAgICAgLT4gIE1hdGVyaWFs aXplIChhY3R1YWwgcm93cz0yIGxvb3BzPTIpCisgICAgICAgICAgICAgICAgIFN0b3JhZ2U6 IE1lbW9yeSAgTWF4aW11bSBTdG9yYWdlOiAxN2tCCisgICAgICAgICAgICAgICAgIC0+ICBT ZXEgU2NhbiBvbiB0YiAoYWN0dWFsIHJvd3M9NCBsb29wcz0xKQorKDEwIHJvd3MpCisKIC0t CiAtLSBUZXN0IGNhc2UgZm9yIHN1YmxpbmtzIHB1c2hlZCBkb3duIGludG8gc3Vic2VsZWN0 cyB2aWEgam9pbiBhbGlhcyBleHBhbnNpb24KIC0tCmRpZmYgLS1naXQgYS9zcmMvdGVzdC9y ZWdyZXNzL3NxbC9zdWJzZWxlY3Quc3FsIGIvc3JjL3Rlc3QvcmVncmVzcy9zcWwvc3Vic2Vs ZWN0LnNxbAppbmRleCA2ZWQzNjM2YTllNC4uZjczZWI2NWFhYTAgMTAwNjQ0Ci0tLSBhL3Ny Yy90ZXN0L3JlZ3Jlc3Mvc3FsL3N1YnNlbGVjdC5zcWwKKysrIGIvc3JjL3Rlc3QvcmVncmVz cy9zcWwvc3Vic2VsZWN0LnNxbApAQCAtNDM5LDYgKzQzOSw3MSBAQCB3aGVyZSBleGlzdHMg KAogCiByb2xsYmFjazsKIAorLS0gVGVzdCBjYXNlIGZvciBleGlzdCBzdWJsaW5rIHdoZXJl IHdlIGNhbiBjb25zaWRlciBzb21lIHVuZGVwZW5kZW50IGV4cHJlc3Npb24KKy0tIHdpdGgg b3V0ZXIgbGluaworLS0KK0VYUExBSU4gKEFOQUxZWkUsIENPU1RTIE9GRiwgU1VNTUFSWSBP RkYsIFRJTUlORyBPRkYpCisgU0VMRUNUIDEKKyAgIEZST00gdGEKKyAgV0hFUkUgRVhJU1RT IChTRUxFQ1QgMQorICAgICAgICAgICAgICAgICAgRlJPTSB0YgorICAgICAgICAgICAgICAg ICAgSk9JTiB0YworICAgICAgICAgICAgICAgICAgICBPTiB0YS5pZCA9IHRiLmlkKTsKKwor RVhQTEFJTiAoQU5BTFlaRSwgQ09TVFMgT0ZGLCBTVU1NQVJZIE9GRiwgVElNSU5HIE9GRikK KyBTRUxFQ1QgMQorICAgRlJPTSB0YQorICBXSEVSRSBFWElTVFMgKFNFTEVDVCAxCisgICAg ICAgICAgICAgICAgICBGUk9NIHRiCisgICAgICAgICAgICAgICAgICBKT0lOIHRjCisgICAg ICAgICAgICAgICAgICAgIE9OIHRhLmlkID0gdGMuaWQpOworCistLSBKb2luIGNvbXBvdW5k IGV4cHJlc3Npb24KK0VYUExBSU4gKEFOQUxZWkUsIENPU1RTIE9GRiwgU1VNTUFSWSBPRkYs IFRJTUlORyBPRkYpCisgU0VMRUNUIDEKKyAgIEZST00gdGEKKyAgV0hFUkUgRVhJU1RTIChT RUxFQ1QgMQorICAgICAgICAgICAgICAgICAgRlJPTSB0YgorICAgICAgICAgICAgICAgICAg Sk9JTiB0YworICAgICAgICAgICAgICAgICAgICBPTiB0YS5pZCA9IHRjLmlkIGFuZAorICAg ICAgICAgICAgICAgICAgICAgICB0YS5pZCA9IHRiLmlkKTsKKworRVhQTEFJTiAoQU5BTFla RSwgQ09TVFMgT0ZGLCBTVU1NQVJZIE9GRiwgVElNSU5HIE9GRikKKyBTRUxFQ1QgMQorICAg RlJPTSB0YQorICBXSEVSRSBFWElTVFMgKFNFTEVDVCAxCisgICAgICAgICAgICAgICAgICBG Uk9NIHRiCisgICAgICAgICAgICAgICAgICBKT0lOIHRjCisgICAgICAgICAgICAgICAgICAg IE9OIHRhLmlkID0gdGMuaWQgYW5kCisgICAgICAgICAgICAgICAgICAgICAgIHRhLmlkID0g dGIuaWQpOworCistLSBDb21wb3VuZCBleHByZXNzaW9uIHdpdGggY29uc3QgdHlwZQorRVhQ TEFJTiAoQU5BTFlaRSwgQ09TVFMgT0ZGLCBTVU1NQVJZIE9GRiwgVElNSU5HIE9GRikKKyBT RUxFQ1QgMQorICAgRlJPTSB0YQorICBXSEVSRSBFWElTVFMgKFNFTEVDVCAxCisgICAgICAg ICAgICAgICAgICBGUk9NIHRiCisgICAgICAgICAgICAgICAgICBKT0lOIHRjCisgICAgICAg ICAgICAgICAgICAgIE9OIHRhLmlkID0gdGMuaWQgYW5kCisgICAgICAgICAgICAgICAgICAg ICAgIHRhLmlkID0gMSk7CisKK0VYUExBSU4gKEFOQUxZWkUsIENPU1RTIE9GRiwgU1VNTUFS WSBPRkYsIFRJTUlORyBPRkYpCisgU0VMRUNUIDEKKyAgIEZST00gdGEKKyAgV0hFUkUgRVhJ U1RTIChTRUxFQ1QgMQorICAgICAgICAgICAgICAgICAgRlJPTSB0YgorICAgICAgICAgICAg ICAgICAgSk9JTiB0YworICAgICAgICAgICAgICAgICAgICBPTiB0Yi5pZCA9IDEgYW5kCisg ICAgICAgICAgICAgICAgICAgICAgIHRhLmlkID0gMSk7CistLSBEaXNhYmxlZCBwdWxsIHVw IGJlY2F1c2UgaXQgaXMgYXBwbGNhcGFibGUgZm9yIElOTkVSIEpPSU4gY29ubmVjdGlvbgor RVhQTEFJTiAoQU5BTFlaRSwgQ09TVFMgT0ZGLCBTVU1NQVJZIE9GRiwgVElNSU5HIE9GRikK KyBTRUxFQ1QgMQorICAgRlJPTSB0YQorICBXSEVSRSBFWElTVFMgKFNFTEVDVCAxCisgICAg ICAgICAgICAgICAgICBGUk9NIHRiCisgICAgICAgICAgICAgICAgICBSSUdIVCBKT0lOIHRj CisgICAgICAgICAgICAgICAgICAgIE9OIHRhLmlkID0gdGMuaWQpOworCiAtLQogLS0gVGVz dCBjYXNlIGZvciBzdWJsaW5rcyBwdXNoZWQgZG93biBpbnRvIHN1YnNlbGVjdHMgdmlhIGpv aW4gYWxpYXMgZXhwYW5zaW9uCiAtLQotLSAKMi4zNC4xCgo= --------------RFr2OLQFP0DiOhNs0p4fFhBK--