Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1gt6bQ-00031C-Gg for pgsql-performance@arkaria.postgresql.org; Mon, 11 Feb 2019 08:06:09 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1gt6bO-0000Eo-4B for pgsql-performance@arkaria.postgresql.org; Mon, 11 Feb 2019 08:06:06 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1gt6bN-0000Eh-EX for pgsql-performance@lists.postgresql.org; Mon, 11 Feb 2019 08:06:05 +0000 Received: from sonic307-54.consmr.mail.ir2.yahoo.com ([87.248.110.31]) by magus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1gt6bE-0005eD-Kq for pgsql-performance@postgresql.org; Mon, 11 Feb 2019 08:06:03 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.co.uk; s=s2048; t=1549872354; bh=YCNWQ7/2nLRTKGGihflifUJ5mCX+qigW9XqZSSQSkOU=; h=Date:From:To:In-Reply-To:References:Subject:From:Subject; b=W/iA1oYDCpsvDkf1rp5gPV8bYVlkuXBBHcgRfDMngVJhhpNwnJGDTm9uoiqWRn4AuGVlVOx0MAMf4Xc9ghkxPbPFW/qWuyehtpJ2DMb7+sWISoWMDwD2IEyftcYj3HddcAo4kCQZHMlhsPzBjb505W+QMmLFhnaHKn3keIGdNNGUeKVBW6I+TA9s12IdHmiud+hC1M99Zc7dTNBrpXDvj20PvkLPCPAcMJ2vgYP/m/ovCgG77JWhy50tVtJng1D4R3Tsgj3C7Y9G0QPbdGOGG6EHz6kLCg9NlImWWhIvjzATc05HHIl6h2CBrGvjgVriesDh20AjEcjs+IJrNBmlsw== X-YMail-OSG: rLQ9rx4VM1nZtjMpeFR6Dls1yiUfIEZDqEktFVRRFc7O7r9kcOE6RCdBdiq4ksI WHKIRpIGQnJKGxmTy_gUvhZfApeqWLy99HXlZzguFaTnNB9rxJ6gatddQQwUFvvbAylws08H.Q3G ZkeRrHT05h56xqrnB_19cpmBEpV7SvFJ94KjlHpfEUQpC0DpCf0oqnwfKWDJ9ESx_8s_N3zPktys qaAVWjdHo2lcPBprdNOgS67ZMxPFIR8pawjOrgI3s6xNDZL0BNfsZRoW4GZhrYZs3cu8JlTuMxiZ xVngvs4pTHx6elrBcM0FSLJUXucQ8.O6n3RbXcuVCVfawjnupsMCWIk07seULXzkvdFdVKslGh1O .kutw6SMIpIoXzCGMoVLVY7Hskf3iumJqNFy8lichdVD8Svph2d28NzwtjetZxlDZeCAfZMfxD6y QPbJ1wdFMoRswJtHQ7ys48qxTTj3ramF4Km4GT2RmfLJhLmf7SsnBPH36HLenA6liMM018RDz9l6 VkTCf1FhD8gDueeb4VM.G8KMfuyD1DzwHrRZzzBiixaVWxF0lvudqRsl9taoJpDMw_L8TVpZZ3O_ gA8ZtfB67Lv0guiVtxi1WjFH6dtJVe_IitJBmHBjCKpFfqrSpe7jhCC9hNNjvk7y7.9FH7KCKmeF NYEkkOwLe51ft4UL924TrGrWrCLezU6vJDiN1xBsOAf6eNY0S3g_rSIy52QAL.gB7ju1H6RYbqr7 YH.97BRM1mL.DJ2EQpWi4.qXZZRD1O2IfgD9Z.cZbUjoyjqwHvNJx64wn_sC254B24BTQbGsbkjJ 4hub85GGkI0FIazFSm7z.BRMGu8ZJ3kH_Z33jHfEezsryvmz5jp9BI46nPFdGvwpJekfTC2vDKTD F2cqv.cyFFF9NqvPacb8.bn0seGcR4c7ANfIYTVrb300XlPTCArZrqnHMCFCwLnMJuG5mpEzYppc fdTdwNIWBEa6xrutniWqSvlPBBF_dNEjNgO4SQc1lifJf5Dv6gKvvgshaxi75270RpSg1JJuCkS4 cMaMP.CmUIBdexNUq9HxHFq4uKvv0cIPKG9FVMHeK4jG2iZgHEgswT5kgPiqQhxxeWoM_ Received: from sonic.gate.mail.ne1.yahoo.com by sonic307.consmr.mail.ir2.yahoo.com with HTTP; Mon, 11 Feb 2019 08:05:54 +0000 Date: Mon, 11 Feb 2019 08:05:50 +0000 (UTC) From: keith anderson To: "pgsql-performance@postgresql.org" Message-ID: <1270348147.2230544.1549872350935@mail.yahoo.com> In-Reply-To: <20190208130444.GC29720@telsasoft.com> References: <1233297695.414916.1549624431535.ref@mail.yahoo.com> <1233297695.414916.1549624431535@mail.yahoo.com> <20190208130444.GC29720@telsasoft.com> Subject: Re: Partitioning Optimizer Questions and Issues MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_Part_2230543_275789688.1549872350935" X-Mailer: WebService/1.1.13027 YMailNorrin Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Safari/537.36 Content-Length: 25379 List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk ------=_Part_2230543_275789688.1549872350935 Content-Type: multipart/alternative; boundary="----=_Part_2230542_1821760923.1549872350895" ------=_Part_2230542_1821760923.1549872350895 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Thanks for the feedback Justin. You are right, the most-common-values list is empty for my test case and so= it is using n_distinct for the 'id IN()' scenario.And I can see that with = the pg_class.reltuples and the pg_stats.histogram_bounds values how the opt= imizer can conclude with my range query that only 1 in 5 entries in my rang= e query are in each individual partition. However, I can also see that the pg_stats.n_distinct value for tablea shows= -1, as do all the individual child partitions. In my opinion it makes sens= e for the optimizer when using n_distinct on partitioned tables to use the = n_distinct value of the parent table level when estimating row counts rathe= r than a sum of the partition level statistics. Or can someone come up with= a good reason to avoid this?=C2=A0 A couple of examples of different data in a partitioned table: - Unique identifier -> if providing a single value in a query -> using n_di= stinct from parent will estimate 1, using child tables will be 1 * (number = of partitions). Use of parent table would be correct.- Date of activity, wi= th=C2=A0 1000 records per day -> if providing a single day to the query -> = using n_distinct from parent would show 1000 rows returned, using child tab= les will be 1000 * (number of partitions). Use of parent table n_distinct i= s correct. Perhaps when querying on columns that are part of the partition logic you c= ould use the partition level stats, but I think the vast majority of the ti= me, using the parent statistics would be much more reliable/accurate than s= umming across partitions. In terms of the partition strategy, I agree that it should be done with a v= iew to helping performance improve. I will look into more detail at your su= ggestions, but in general it is very hard to use effectively as there are c= ompeting priorities: - I would like to not have to manage massive numbers of partitions- I would= like to be able to archive data easily using date (a big plus point to the= existing date partitioning strategy)- It is hard in most cases to come up = with a partition strategy that allows for partition elimination e.g. consid= er a common 'transaction record' table with a primary key, an account ident= ifier, and a date -> it is natural to want to be able to query on any one o= f these, but as things stand it cannot be achieved performantly with partit= ioning. Global index support feels like it has potential to resolve many of the iss= ues I have with partitioning (beyond the optimizer concern above). I assume= this has been discussed and rejected though by the community? I've attached as a file the original test script. Keith On Friday, 8 February 2019, 13:05:04 GMT, Justin Pryzby wrote: =20 =20 On Fri, Feb 08, 2019 at 11:13:51AM +0000, keith anderson wrote: > So to summarise the findings/questions from above: > - It seems like the Postgres optimizer sometimes uses the partition level= statistics, and sometimes the global table level statistics? Or is it usin= g something else?- With partitioning tables with unique identifier and retr= ieving explicitly on those identifiers, at present the optimizer will alway= s understimate the selectivity and overestimate the rows returned. This ina= ccuracy increases in proportion to the number of partitions.- As a result, = when joining to other tables, you are liable to hitting sequential scans. T= his becomes more likely as you have more partitions or if join to more part= itioned tables (note I am aware I could try and tune random_page_cost to tr= y and prevent this).- To me in the examples queries described above, it mak= es sense to use the partition statistics for the partition level access str= ategy, but the global statistics when estimating the actual rows returned b= y all the individual partition queries. Is there a reason not to do this? O= r do others believe the optimizer is doing the right thing here? > And then some general questions: > - How do other people use partitioning but without a significant performa= nce disadvantage on reading the data? Is there something else I should be d= oing here to achieve the same thing without the overhead? At present my rea= ds have increased optimization cost (as it needs to optimize access to each= partition) and also execution cost (access the index on every partition). = Even without the optimizer issues described above, the cost of reading simp= le data is extremely high relative to non-partitioned data (unless you use = the partition key as a filter for each table to eliminate those partitions)= .- Is there any chance/plan to add global indexes to postgres? If so would = that impact significantly the cost of the partition drop e.g. to clean up t= he index. > Thanks in advance for any feedback/support, An equality or IN() query will use the pg_stats most-common-values list, whereas a range query will use the histogram. The tables probably doesn't have complete MCV list.=C2=A0 By default, that'= s limited to 100 entries.=C2=A0 Since the maximum allowed by ALTER..SET STATISTICS is= 10k, I don't think it'll help to change it (at least for your production use case)= . Each partition's rowcount appears to be estimated from its ndistinct, and n= ot from its content, so each is estimated as having about the same rowcount. Your partitions are sharing a sequence for their ID column, which causes th= e DEFAULT IDs to be unique...but their global uniqueness isn't enforced nor guaranteed. Note, in postgres11, it's possible to create an index on the parent table. It's NOT a global index, but it can be unique if it includes the partition = key. I don't know how closely your example describes your real use case, but I d= on't think that helps with your example; it doesn't seems useful to partition on= a serial column. You seem to be adding unnecessary CHECK constraints that duplicate the partition bounds.=C2=A0 Note, it's still useful to include CHECK constraint= s on key column if you're planning on DETACHing and re-ATTACHing the partitions, in order to avoid seqscan to verify tuples don't violate specified bounds. You might need to rethink your partitioning scheme - you should choose one = that causes performance to improve, and probably naturally includes the partitio= n key in most queries. Perhaps you'd use 2 levels of partitioning: a RANGE partition by date, whic= h allows for archiving, and a HASH partition by ID, which allows for partitio= n pruning.=C2=A0 Note that it's also possible to partition on multiple keys, = like RANGE(id,date) - I don't think that's useful here, though.=C2=A0 PG11 also = allows a "default" partition. Or perhaps you could partition by RANGE(date) but add CHECK constraints on = ID, after the table is fully populated, to optimize queries by allowing for partition pruning. Or you could maybe change the ID column to include the timestamp (like BIND zonesfiles YYYYMMDDNNNNNNNN).=C2=A0 You'd set a bigint sequence on each par= tition's ID as default to the beginning of the month.=C2=A0 A bigint is enough to ha= ndle 5*10^4 times your volume: 20190401000020111222.=C2=A0 (I think this is tryi= ng to be unnecessarily clever, unless there's some reason the other two ideas don't work.) Justin =20 ------=_Part_2230542_1821760923.1549872350895 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable
Thanks for the feedback Justin.

<= /div>
You are right, the most-common-values list is empty for my test c= ase and so it is using n_distinct for the 'id IN()' scenario.
And= I can see that with the pg_class.reltuples and the pg_stats.histogram_boun= ds values how the optimizer can conclude with my range query that only 1 in= 5 entries in my range query are in each individual partition.
However, I can also see that the pg_stats.n_distinct value for= tablea shows -1, as do all the individual child partitions. In my opinion = it makes sense for the optimizer when using n_distinct on partitioned table= s to use the n_distinct value of the parent table level when estimating row= counts rather than a sum of the partition level statistics. Or can someone= come up with a good reason to avoid this? 

A= couple of examples of different data in a partitioned table:
- Unique identifier -> if providing a single value in a quer= y -> using n_distinct from parent will estimate 1, using child tables wi= ll be 1 * (number of partitions). Use of parent table would be correct.
- Date of activity, with  1000 records per day -> if providi= ng a single day to the query -> using n_distinct from parent would show = 1000 rows returned, using child tables will be 1000 * (number of partitions= ). Use of parent table n_distinct is correct.

Perh= aps when querying on columns that are part of the partition logic you could= use the partition level stats, but I think the vast majority of the time, = using the parent statistics would be much more reliable/accurate than summi= ng across partitions.

In terms of the partition st= rategy, I agree that it should be done with a view to helping performance i= mprove. I will look into more detail at your suggestions, but in general it= is very hard to use effectively as there are competing priorities:

- I would like to not have to manage massive numbers of p= artitions
- I would like to be able to archive data easily using = date (a big plus point to the existing date partitioning strategy)
- It is hard in most cases to come up with a partition strategy that allo= ws for partition elimination e.g. consider a common 'transaction record' ta= ble with a primary key, an account identifier, and a date -> it is natur= al to want to be able to query on any one of these, but as things stand it = cannot be achieved performantly with partitioning.

Global index support feels like it has potential to resolve many of the is= sues I have with partitioning (beyond the optimizer concern above). I assum= e this has been discussed and rejected though by the community?
<= br>
I've attached as a file the original test script.
<= br>
Keith



=20
=20
On Friday, 8 February 2019, 13:05:04 GMT, Justin Pryzby= <pryzby@telsasoft.com> wrote:


On Fri, Feb 08, 2019 at 11:13:51AM +0000, keith anders= on wrote:

> So to summarise the findings/questions from abov= e:
> - It seems like the Postgres optimizer sometimes = uses the partition level statistics, and sometimes the global table level s= tatistics? Or is it using something else?- With partitioning tables with un= ique identifier and retrieving explicitly on those identifiers, at present = the optimizer will always understimate the selectivity and overestimate the= rows returned. This inaccuracy increases in proportion to the number of pa= rtitions.- As a result, when joining to other tables, you are liable to hit= ting sequential scans. This becomes more likely as you have more partitions= or if join to more partitioned tables (note I am aware I could try and tun= e random_page_cost to try and prevent this).- To me in the examples queries= described above, it makes sense to use the partition statistics for the pa= rtition level access strategy, but the global statistics when estimating th= e actual rows returned by all the individual partition queries. Is there a = reason not to do this? Or do others believe the optimizer is doing the righ= t thing here?
> And then some general questions:
> - How do other people use partitioning but without a sign= ificant performance disadvantage on reading the data? Is there something el= se I should be doing here to achieve the same thing without the overhead? A= t present my reads have increased optimization cost (as it needs to optimiz= e access to each partition) and also execution cost (access the index on ev= ery partition). Even without the optimizer issues described above, the cost= of reading simple data is extremely high relative to non-partitioned data = (unless you use the partition key as a filter for each table to eliminate t= hose partitions).- Is there any chance/plan to add global indexes to postgr= es? If so would that impact significantly the cost of the partition drop e.= g. to clean up the index.
> Thanks in advance for any = feedback/support,


An equality or= IN() query will use the pg_stats most-common-values list,
whereas a range query will use the histogram.

The tables probably doesn't have complete MCV list.  By defa= ult, that's limited
to 100 entries.  Since the maxim= um allowed by ALTER..SET STATISTICS is 10k, I
don't think= it'll help to change it (at least for your production use case).
Each partition's rowcount appears to be estimated from its ndisti= nct, and not
from its content, so each is estimated as ha= ving about the same rowcount.

Your par= titions are sharing a sequence for their ID column, which causes the
DEFAULT IDs to be unique...but their global uniqueness isn't en= forced nor
guaranteed.

Note, in postgres11, it's possible to create an index on the parent tabl= e.
It's NOT a global index, but it can be unique if it in= cludes the partition key.
I don't know how closely your e= xample describes your real use case, but I don't
think th= at helps with your example; it doesn't seems useful to partition on a
serial column.

You seem t= o be adding unnecessary CHECK constraints that duplicate the
partition bounds.  Note, it's still useful to include CHECK constr= aints on key
column if you're planning on DETACHing and r= e-ATTACHing the partitions, in
order to avoid seqscan to = verify tuples don't violate specified bounds.

You might need to rethink your partitioning scheme - you should c= hoose one that
causes performance to improve, and probabl= y naturally includes the partition
key in most queries.
Perhaps you'd use 2 levels of partition= ing: a RANGE partition by date, which
allows for archivin= g, and a HASH partition by ID, which allows for partition
pruning.  Note that it's also possible to partition on multiple keys,= like
RANGE(id,date) - I don't think that's useful here, = though.  PG11 also allows a
"default" partition.

Or perhaps you could partition by RANGE(d= ate) but add CHECK constraints on ID,
after the table is = fully populated, to optimize queries by allowing for
part= ition pruning.

Or you could maybe chan= ge the ID column to include the timestamp (like BIND
zone= sfiles YYYYMMDDNNNNNNNN).  You'd set a bigint sequence on each partiti= on's
ID as default to the beginning of the month.  A= bigint is enough to handle
5*10^4 times your volume: 201= 90401000020111222.  (I think this is trying to be
un= necessarily clever, unless there's some reason the other two ideas don'twork.)

Justin

------=_Part_2230542_1821760923.1549872350895-- ------=_Part_2230543_275789688.1549872350935 Content-Type: application/sql Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="partitionExample.sql" Content-ID: <7d74ded7-4117-9f99-876c-4b90f2f12e87@yahoo.com> ZHJvcCB0YWJsZSBpZiBleGlzdHMgdGFibGVhIGNhc2NhZGU7CmRyb3AgdGFibGUgaWYgZXhpc3Rz IHRhYmxlYiBjYXNjYWRlOwoKQ1JFQVRFIFRBQkxFIHRhYmxlYSAoCiAgICBpZCAgICAgICAgICAg IHNlcmlhbCwKICAgIHJlZmVyZW5jZSAgICAgaW50IG5vdCBudWxsLAogICAgY3JlYXRlZCAgICAg ICBkYXRlIG5vdCBudWxsCikgIFBBUlRJVElPTiBCWSBSQU5HRSAoY3JlYXRlZCk7CgoKQ1JFQVRF IFRBQkxFIHRhYmxlYV9wYXJ0MSBQQVJUSVRJT04gT0YgdGFibGVhCiAgICBGT1IgVkFMVUVTIEZS T00gKCcyMDE4LTAxLTAxJykgVE8gKCcyMDE4LTAxLTAyJyk7CkNSRUFURSBUQUJMRSB0YWJsZWFf cGFydDIgUEFSVElUSU9OIE9GIHRhYmxlYQogICAgRk9SIFZBTFVFUyBGUk9NICgnMjAxOC0wMS0w MicpIFRPICgnMjAxOC0wMS0wMycpOwpDUkVBVEUgVEFCTEUgdGFibGVhX3BhcnQzIFBBUlRJVElP TiBPRiB0YWJsZWEKICAgIEZPUiBWQUxVRVMgRlJPTSAoJzIwMTgtMDEtMDMnKSBUTyAoJzIwMTgt MDEtMDQnKTsKQ1JFQVRFIFRBQkxFIHRhYmxlYV9wYXJ0NCBQQVJUSVRJT04gT0YgdGFibGVhCiAg ICBGT1IgVkFMVUVTIEZST00gKCcyMDE4LTAxLTA0JykgVE8gKCcyMDE4LTAxLTA1Jyk7CkNSRUFU RSBUQUJMRSB0YWJsZWFfcGFydDUgUEFSVElUSU9OIE9GIHRhYmxlYQogICAgRk9SIFZBTFVFUyBG Uk9NICgnMjAxOC0wMS0wNScpIFRPICgnMjAxOC0wMS0wNicpOwoKQ1JFQVRFIElOREVYIHRhYmxl YV9pZF8xIE9OIHRhYmxlYV9wYXJ0MSAoaWQpOwpDUkVBVEUgSU5ERVggdGFibGVhX2lkXzIgT04g dGFibGVhX3BhcnQyIChpZCk7CkNSRUFURSBJTkRFWCB0YWJsZWFfaWRfMyBPTiB0YWJsZWFfcGFy dDMgKGlkKTsKQ1JFQVRFIElOREVYIHRhYmxlYV9pZF80IE9OIHRhYmxlYV9wYXJ0NCAoaWQpOwpD UkVBVEUgSU5ERVggdGFibGVhX2lkXzUgT04gdGFibGVhX3BhcnQ1IChpZCk7CkNSRUFURSBJTkRF WCB0YWJsZWFfcmVmZXJlbmNlXzEgT04gdGFibGVhX3BhcnQxIChyZWZlcmVuY2UpOwpDUkVBVEUg SU5ERVggdGFibGVhX3JlZmVyZW5jZV8yIE9OIHRhYmxlYV9wYXJ0MiAocmVmZXJlbmNlKTsKQ1JF QVRFIElOREVYIHRhYmxlYV9yZWZlcmVuY2VfMyBPTiB0YWJsZWFfcGFydDMgKHJlZmVyZW5jZSk7 CkNSRUFURSBJTkRFWCB0YWJsZWFfcmVmZXJlbmNlXzQgT04gdGFibGVhX3BhcnQ0IChyZWZlcmVu Y2UpOwpDUkVBVEUgSU5ERVggdGFibGVhX3JlZmVyZW5jZV81IE9OIHRhYmxlYV9wYXJ0NSAocmVm ZXJlbmNlKTsKQ1JFQVRFIElOREVYIHRhYmxlYV9jcmVhdGVkXzEgT04gdGFibGVhX3BhcnQxIChj cmVhdGVkKTsKQ1JFQVRFIElOREVYIHRhYmxlYV9jcmVhdGVkXzIgT04gdGFibGVhX3BhcnQyIChj cmVhdGVkKTsKQ1JFQVRFIElOREVYIHRhYmxlYV9jcmVhdGVkXzMgT04gdGFibGVhX3BhcnQzIChj cmVhdGVkKTsKQ1JFQVRFIElOREVYIHRhYmxlYV9jcmVhdGVkXzQgT04gdGFibGVhX3BhcnQ0IChj cmVhdGVkKTsKQ1JFQVRFIElOREVYIHRhYmxlYV9jcmVhdGVkXzUgT04gdGFibGVhX3BhcnQ1IChj cmVhdGVkKTsKYWx0ZXIgdGFibGUgdGFibGVhX3BhcnQxIGFkZCBDSEVDSyAoIGNyZWF0ZWQgPj0g REFURSAnMjAxOC0wMS0wMScgQU5EIGNyZWF0ZWQgPCBEQVRFICcyMDE4LTAxLTAyJyk7CmFsdGVy IHRhYmxlIHRhYmxlYV9wYXJ0MiBhZGQgQ0hFQ0sgKCBjcmVhdGVkID49IERBVEUgJzIwMTgtMDEt MDInIEFORCBjcmVhdGVkIDwgREFURSAnMjAxOC0wMS0wMycpOwphbHRlciB0YWJsZSB0YWJsZWFf cGFydDMgYWRkIENIRUNLICggY3JlYXRlZCA+PSBEQVRFICcyMDE4LTAxLTAzJyBBTkQgY3JlYXRl ZCA8IERBVEUgJzIwMTgtMDEtMDQnKTsKYWx0ZXIgdGFibGUgdGFibGVhX3BhcnQ0IGFkZCBDSEVD SyAoIGNyZWF0ZWQgPj0gREFURSAnMjAxOC0wMS0wNCcgQU5EIGNyZWF0ZWQgPCBEQVRFICcyMDE4 LTAxLTA1Jyk7CmFsdGVyIHRhYmxlIHRhYmxlYV9wYXJ0NSBhZGQgQ0hFQ0sgKCBjcmVhdGVkID49 IERBVEUgJzIwMTgtMDEtMDUnIEFORCBjcmVhdGVkIDwgREFURSAnMjAxOC0wMS0wNicpOwoKY3Jl YXRlIG9yIHJlcGxhY2UgZnVuY3Rpb24gcG9wdWxhdGVfdGFibGVhKCkKIFJFVFVSTlMgaW50ZWdl ciBBUwokQk9EWSQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgCkRFQ0xBUkUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgIAogIGkgaW50ZWdlcjsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogIHZf Y3JlYXRlZCBkYXRlOwpCRUdJTiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAKICAgIGkgOj0gMDsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAK ICAgIFdISUxFIChpIDwgNTAwMDApCiAgICBsb29wCiAgICAgICAgaSA6PSBpICsgMTsgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgSUYgKG1vZChpLDUpID0g MSkgVEhFTgogICAgICAgICAgICB2X2NyZWF0ZWQgPSAnMjAxOC0wMS0wMSc7CiAgICAgICAgRUxT SUYgKG1vZChpLDUpID0gMikgVEhFTgogICAgICAgICAgICB2X2NyZWF0ZWQgPSAnMjAxOC0wMS0w Mic7CiAgICAgICAgIEVMU0lGIChtb2QoaSw1KSA9IDMpIFRIRU4KICAgICAgICAgICAgdl9jcmVh dGVkID0gJzIwMTgtMDEtMDMnOwogICAgICAgIEVMU0lGIChtb2QoaSw1KSA9IDQpIFRIRU4KICAg ICAgICAgICAgdl9jcmVhdGVkID0gJzIwMTgtMDEtMDQnOwogICAgICAgIEVMU0lGIChtb2QoaSw1 KSA9IDApIFRIRU4KICAgICAgICAgICAgdl9jcmVhdGVkID0gJzIwMTgtMDEtMDUnOwogICAgICAg IEVORCBJRjsgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgaW5zZXJ0IGludG8g dGFibGVhIHZhbHVlcyAoaSwgaSwgdl9jcmVhdGVkKTsKCiAgICBlbmQgbG9vcDsgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgIAogICAgICAgICAgIAogICAgUkVUVVJOIGk7CkVORDsKJEJPRFkkCkxB TkdVQUdFIHBscGdzcWwgVk9MQVRJTEUKICAgIENPU1QgMTAwOwoKQ1JFQVRFIFRBQkxFIHRhYmxl YigKICAgIGlkICAgICAgICAgc2VyaWFsLAogICAgcmVmZXJlbmNlICBpbnQgbm90IG51bGwsCiAg ICBjcmVhdGVkICAgIGRhdGUgbm90IG51bGwKKSBQQVJUSVRJT04gQlkgUkFOR0UgKGNyZWF0ZWQp OwoKCkNSRUFURSBUQUJMRSB0YWJsZWJfcGFydDEgUEFSVElUSU9OIE9GIHRhYmxlYgogICAgRk9S IFZBTFVFUyBGUk9NICgnMjAxOC0wMS0wMScpIFRPICgnMjAxOC0wMS0wMicpOwpDUkVBVEUgVEFC TEUgdGFibGViX3BhcnQyIFBBUlRJVElPTiBPRiB0YWJsZWIKICAgIEZPUiBWQUxVRVMgRlJPTSAo JzIwMTgtMDEtMDInKSBUTyAoJzIwMTgtMDEtMDMnKTsKQ1JFQVRFIFRBQkxFIHRhYmxlYl9wYXJ0 MyBQQVJUSVRJT04gT0YgdGFibGViCiAgICBGT1IgVkFMVUVTIEZST00gKCcyMDE4LTAxLTAzJykg VE8gKCcyMDE4LTAxLTA0Jyk7CkNSRUFURSBUQUJMRSB0YWJsZWJfcGFydDQgUEFSVElUSU9OIE9G IHRhYmxlYgogICAgRk9SIFZBTFVFUyBGUk9NICgnMjAxOC0wMS0wNCcpIFRPICgnMjAxOC0wMS0w NScpOwpDUkVBVEUgVEFCTEUgdGFibGViX3BhcnQ1IFBBUlRJVElPTiBPRiB0YWJsZWIKICAgIEZP UiBWQUxVRVMgRlJPTSAoJzIwMTgtMDEtMDUnKSBUTyAoJzIwMTgtMDEtMDYnKTsKCgpDUkVBVEUg SU5ERVggdGFibGViX2lkXzEgT04gdGFibGViX3BhcnQxIChpZCk7CkNSRUFURSBJTkRFWCB0YWJs ZWJfaWRfMiBPTiB0YWJsZWJfcGFydDIgKGlkKTsKQ1JFQVRFIElOREVYIHRhYmxlYl9pZF8zIE9O IHRhYmxlYl9wYXJ0MyAoaWQpOwpDUkVBVEUgSU5ERVggdGFibGViX2lkXzQgT04gdGFibGViX3Bh cnQ0IChpZCk7CkNSRUFURSBJTkRFWCB0YWJsZWJfaWRfNSBPTiB0YWJsZWJfcGFydDUgKGlkKTsK Q1JFQVRFIElOREVYIHRhYmxlYl9yZWZlcmVuY2VfMSBPTiB0YWJsZWJfcGFydDEgKHJlZmVyZW5j ZSk7CkNSRUFURSBJTkRFWCB0YWJsZWJfcmVmZXJlbmNlXzIgT04gdGFibGViX3BhcnQyIChyZWZl cmVuY2UpOwpDUkVBVEUgSU5ERVggdGFibGViX3JlZmVyZW5jZV8zIE9OIHRhYmxlYl9wYXJ0MyAo cmVmZXJlbmNlKTsKQ1JFQVRFIElOREVYIHRhYmxlYl9yZWZlcmVuY2VfNCBPTiB0YWJsZWJfcGFy dDQgKHJlZmVyZW5jZSk7CkNSRUFURSBJTkRFWCB0YWJsZWJfcmVmZXJlbmNlXzUgT04gdGFibGVi X3BhcnQ1IChyZWZlcmVuY2UpOwpDUkVBVEUgSU5ERVggdGFibGViX2NyZWF0ZWRfMSBPTiB0YWJs ZWJfcGFydDEgKGNyZWF0ZWQpOwpDUkVBVEUgSU5ERVggdGFibGViX2NyZWF0ZWRfMiBPTiB0YWJs ZWJfcGFydDIgKGNyZWF0ZWQpOwpDUkVBVEUgSU5ERVggdGFibGViX2NyZWF0ZWRfMyBPTiB0YWJs ZWJfcGFydDMgKGNyZWF0ZWQpOwpDUkVBVEUgSU5ERVggdGFibGViX2NyZWF0ZWRfNCBPTiB0YWJs ZWJfcGFydDQgKGNyZWF0ZWQpOwpDUkVBVEUgSU5ERVggdGFibGViX2NyZWF0ZWRfNSBPTiB0YWJs ZWJfcGFydDUgKGNyZWF0ZWQpOwphbHRlciB0YWJsZSB0YWJsZWJfcGFydDEgYWRkIENIRUNLICgg Y3JlYXRlZCA+PSBEQVRFICcyMDE4LTAxLTAxJyBBTkQgY3JlYXRlZCA8IERBVEUgJzIwMTgtMDEt MDInKTsKYWx0ZXIgdGFibGUgdGFibGViX3BhcnQyIGFkZCBDSEVDSyAoIGNyZWF0ZWQgPj0gREFU RSAnMjAxOC0wMS0wMicgQU5EIGNyZWF0ZWQgPCBEQVRFICcyMDE4LTAxLTAzJyk7CmFsdGVyIHRh YmxlIHRhYmxlYl9wYXJ0MyBhZGQgQ0hFQ0sgKCBjcmVhdGVkID49IERBVEUgJzIwMTgtMDEtMDMn IEFORCBjcmVhdGVkIDwgREFURSAnMjAxOC0wMS0wNCcpOwphbHRlciB0YWJsZSB0YWJsZWJfcGFy dDQgYWRkIENIRUNLICggY3JlYXRlZCA+PSBEQVRFICcyMDE4LTAxLTA0JyBBTkQgY3JlYXRlZCA8 IERBVEUgJzIwMTgtMDEtMDUnKTsKYWx0ZXIgdGFibGUgdGFibGViX3BhcnQ1IGFkZCBDSEVDSyAo IGNyZWF0ZWQgPj0gREFURSAnMjAxOC0wMS0wNScgQU5EIGNyZWF0ZWQgPCBEQVRFICcyMDE4LTAx LTA2Jyk7CgoKY3JlYXRlIG9yIHJlcGxhY2UgZnVuY3Rpb24gcG9wdWxhdGVfdGFibGViKCkKIFJF VFVSTlMgaW50ZWdlciBBUwokQk9EWSQKREVDTEFSRQogIGkgaW50ZWdlcjsKICB2X2NyZWF0ZWQg ZGF0ZTsKQkVHSU4KICAgIGkgOj0gMDsKICAgIFdISUxFIChpIDwgNTAwMDApCiAgICBsb29wCiAg ICAgICAgaSA6PSBpICsgMTsKICAgICAgICBJRiAobW9kKGksNSkgPSAwKSBUSEVOCiAgICAgICAg ICAgIHZfY3JlYXRlZCA9ICcyMDE4LTAxLTAxJzsKICAgICAgICBFTFNJRiAobW9kKGksNSkgPSAx KSBUSEVOCiAgICAgICAgICAgIHZfY3JlYXRlZCA9ICcyMDE4LTAxLTAyJzsKICAgICAgICAgRUxT SUYgKG1vZChpLDUpID0gMikgVEhFTgogICAgICAgICAgICB2X2NyZWF0ZWQgPSAnMjAxOC0wMS0w Myc7CiAgICAgICAgRUxTSUYgKG1vZChpLDUpID0gMykgVEhFTgogICAgICAgICAgICB2X2NyZWF0 ZWQgPSAnMjAxOC0wMS0wNCc7CiAgICAgICAgRUxTSUYgKG1vZChpLDUpID0gNCkgVEhFTgogICAg ICAgICAgICB2X2NyZWF0ZWQgPSAnMjAxOC0wMS0wNSc7ICAgIAogICAgICAgIEVORCBJRjsKICAg ICAgICBpbnNlcnQgaW50byB0YWJsZWIgdmFsdWVzIChpLCBpLCB2X2NyZWF0ZWQpOwogICAgZW5k IGxvb3A7CiAgICBSRVRVUk4gaTsKRU5EOwokQk9EWSQKTEFOR1VBR0UgcGxwZ3NxbCBWT0xBVElM RQogICAgQ09TVCAxMDA7CgpzZWxlY3QgcG9wdWxhdGVfdGFibGVhKCk7CnNlbGVjdCBwb3B1bGF0 ZV90YWJsZWIoKTsKdmFjdXVtIGFuYWx5emU7 ------=_Part_2230543_275789688.1549872350935--