From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=-0.8 required=5.0 tests=DKIM_ADSP_CUSTOM_MED, DKIM_INVALID,DKIM_SIGNED,FREEMAIL_FROM,HTML_MESSAGE,MAILING_LIST_MULTI, RCVD_IN_MSPIKE_H2 autolearn=ham autolearn_force=no version=3.4.4 Received: (qmail 26936 invoked from network); 24 Oct 2022 01:27:13 -0000 Received: from second.openwall.net (193.110.157.125) by inbox.vuxu.org with ESMTPUTF8; 24 Oct 2022 01:27:13 -0000 Received: (qmail 13825 invoked by uid 550); 24 Oct 2022 01:27:10 -0000 Mailing-List: contact musl-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Reply-To: musl@lists.openwall.com Received: (qmail 3431 invoked from network); 24 Oct 2022 01:06:49 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=a+HFM4HbC39zwCclvgB/9yZMAeNaOgSrBHi2+zQLph0=; b=oq9sgItfH/GszXmHYzeQRoruiGrHOdbxvDRK5sUhHly2rpIoEbn2FuMYIl0GSvqimm 1g9Ptb6Z2GT+rKNBu29WcMhmeIp86aOBj54GeoSCZjxa1t+N/l90YV4/jor/XYXYAo3U Dq06X6yJj4epFAnes+pQcvPEinAYCNstsFDUD1G6khzkOFFFlEzopyyfcffBv+K/ZoRR SKAAdqk8//dLU9+5aO+VEpJ0hvSo43xZzeAOTE48C90jKnqZUUSy9L1JGq7Y0jdTCdai JXzouVH+isIzEUJ0C4/bN1GttJFT0PWJMTCd8zZ7jWcT9yov6315NCv/4/OZHuWMLBuC iY9w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=a+HFM4HbC39zwCclvgB/9yZMAeNaOgSrBHi2+zQLph0=; b=QsCpjhf4s22kfYcC1WO4dFOkpQaZk17C7Git3mCsZouL6k6ZTQq82toofW6qMp54Tl ksphlSpbk98zoh4W5Mkjlp4tF961grm2N9ejg3VQR1fsQ5fC0htsr0EIo5EXQoNlZK20 q5PwFv+uw3fPAbDwtIrO4wkE0acmaShEP3Yg/uXQZHhnoLA3j9ZBMSLqL3Ij57XbuI13 8lmmJ30kONc8DvtN0nU7Hjl/4yAYYYXA5LL28aaAbG6nyibtl4RoCRQpY51h1XLKMUw3 vH9INY+nRuEprKfb9t26BvdgoDO6ir224oI3kLerqRZ4OBW3LpEX9KKLNbs3bs4tBRaQ acog== X-Gm-Message-State: ACrzQf2u/8WP8MyqMwikBFa52JUE9PGQFQaQRAVCkH1BXd7h3+GJTzrI xr48weD53Oq401L1lx+0UApE3QnYFQ+S1pIb08U= X-Google-Smtp-Source: AMsMyM6N6h21HE80N52CPX5kqWTIrmS0Em4rl20fB/MybsVma3JitsZJN594D06M3rtXpF8ZPicrz0o1DwDE2pQlALY= X-Received: by 2002:a02:a1c5:0:b0:372:d180:fbc1 with SMTP id o5-20020a02a1c5000000b00372d180fbc1mr2675454jah.297.1666573597462; Sun, 23 Oct 2022 18:06:37 -0700 (PDT) MIME-Version: 1.0 References: <20221023111801.515290-1-qingtao.cao@digi.com> <20221023153229.GR29905@brightrain.aerifal.cx> In-Reply-To: <20221023153229.GR29905@brightrain.aerifal.cx> From: Qingtao Cao Date: Mon, 24 Oct 2022 11:06:26 +1000 Message-ID: To: Rich Felker Cc: musl@lists.openwall.com, Qingtao Cao Content-Type: multipart/alternative; boundary="00000000000044d54a05ebbd67e9" Subject: Re: [musl] [PATCH 1/1] musl/resolver: serialise querying name servers --00000000000044d54a05ebbd67e9 Content-Type: text/plain; charset="UTF-8" Hi Rich, Many thanks for your feedback, much appreciated! Yep, you've got my idea. Basically my box has multiple DNS servers setup in resolv.conf, for example, the one specified from my ISP, another public one if needed and the one from my private network (after I setup a VPN tunnel to my office network) and only the latter understand private host names (such as AAA server or remote syslog servers in the office network). Given the current mechanism implemented by musl's resolver, different servers could reply conflicted answers, for example, NXDOMAIN from public server for private hostnames whereas NOERROR from the private DNS server. I understand your suggestion to further manipulate a local unioning nameserver to handle conflicted replies. Frankly speaking, in my use case the situation is even more complicated. My boxes are mult-homed, for example, with eth0 and cellular interfaces, the ISP in each network will provide different DNS server. The default gateway for my device may ping-pong among that of eth0 and that of cellular interface, should the cable/eth0 connection becomes down or resumed. In this case I need to re-order nameservers in resolv.conf to put first the name servers associated with the current default gateway's interface. Again, it is arguable that this can also be handled by changing the policy adopted by the local unioning name server (to prefer which nameserver when handling conflicts). In my mind, serialising DNS servers' queries would spare the need of setting local unioning server and changing its policy - the ordering of nameservers in resolv.conf can be adjusted anytime to put the preferred one first. What if I introduce a new macro to provide nameserver serialisation along with parallelism? the new macro will default to off to keep the current behaviour. Should the need arise for musl users to put some weight, or precedence on name servers, they could opt in to serialisation and don't worry about further setting up local unioning name server? Looking forward to your feedback. Harry On Mon, Oct 24, 2022 at 1:32 AM Rich Felker wrote: > On Sun, Oct 23, 2022 at 09:18:01PM +1000, Qingtao Cao wrote: > > Querying all configured DNS servers in parallel boost performance but > makes > > it impossible to prefer private DNS servers to public ones. Serialise DNS > > servers access from the top of the nameserver specified in resolv.conf > and > > only move on to the next, or less preferred DNS server when the current > one > > either timed out or replied NOERROR and NXDOMAIN for all queries > > > > When querying the next or less perferred DNS servers, only unsuccessfully > > resolved host names were queried. When replies are received, they won't > replace > > a perviously successful answer. This ensures successful answers from > higher > > prioritised DNS servers won't be overridden > > > > This eliminates a racy condition when different DNS servers replies > differently > > to a query, the last received one wins > > > > Last but not least, using a local array to save the currently received > reply to > > simplify the logic to re-shuffle answers[next] to the corresponding > answers[i] > > > > Signed-off-by: Qingtao Cao > > This patch is being submitted as one to change a very intentional and > longstanding behavior (and with that impose a new contract) and is not > going to be accepted. A basic premise of musl's resolver, that's not > just arbitrary but a consequence of a "fallback" model, is that all > the nameservers provided present a consistent view of a global dns > namespace. > > Some people mistake "fallback" for "search" because it kinda appears > to work that way if you don't actually question what happens in the > corner cases. But if you're using fallback as search, failure of the > primary server to answer in time will *change the results* of the > query. This is not how fallback is supposed to work. > > It would have been a lot more productive to start from a standpoint of > what you're trying to do. I assume that's "unioning" where you have a > local nameserver serving fake names that don't actually exist in the > real DNS namespace, and a real nameserver that's serving the real DNS > namespace. There are at least 2 valid ways to achieve this that don't > break in the above manner. > > 1. Run a unioning nameserver locally. The unioning nameserver handles > all the complex logic of handling clashes and which upstream source > takes precedence, querying both and only answering if it gets > sufficient answers to draw a conclusive result about which result > it can use (and ServFail otherwise). > > 2. Put your local names under an actual DNS domain (or subdomain zone) > you actually own. Set the public DNS delegations to point to > nameservers that don't exist. Now the public DNS will always > ServFail. Set your private local nameserver to only return results > for this local zone, and ServFail otherwise. As a result, neither > is providing conflicting answers for the part of the namespace the > other is responsible for. > > There are likely other ways too. > > > --- > > src/network/res_msend.c | 100 +++++++++++++++++++++++++++------------- > > 1 file changed, 68 insertions(+), 32 deletions(-) > > > > diff --git a/src/network/res_msend.c b/src/network/res_msend.c > > index 9adaea13..130ac4fe 100644 > > --- a/src/network/res_msend.c > > +++ b/src/network/res_msend.c > > @@ -10,6 +10,7 @@ > > #include > > #include > > #include > > +#include > > #include "stdio_impl.h" > > #include "syscall.h" > > #include "lookup.h" > > @@ -41,11 +42,12 @@ int __res_msend_rc(int nqueries, const unsigned char > *const *queries, > > int nns = 0; > > int family = AF_INET; > > int rlen; > > - int next; > > - int i, j; > > + int i; > > int cs; > > struct pollfd pfd; > > unsigned long t0, t1, t2; > > + int ns_index, rcode, all_done, unanswered; > > + unsigned char answer[512]; > > > > pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); > > > > @@ -115,19 +117,27 @@ int __res_msend_rc(int nqueries, const unsigned > char *const *queries, > > pfd.fd = fd; > > pfd.events = POLLIN; > > retry_interval = timeout / attempts; > > - next = 0; > > + > > + ns_index = 0; /* Start from the top name server */ > > + > > +next_ns: > > t0 = t2 = mtime(); > > t1 = t2 - retry_interval; > > > > + unanswered = 0; > > + > > for (; t2-t0 < timeout; t2=mtime()) { > > if (t2-t1 >= retry_interval) { > > - /* Query all configured namservers in parallel */ > > - for (i=0; i > - if (!alens[i]) > > - for (j=0; j > - sendto(fd, queries[i], > > - qlens[i], > MSG_NOSIGNAL, > > - (void *)&ns[j], > sl); > > + for (i=0; i > + /* Only query unresolved or negative > resolved host names */ > > + rcode = answers[i][3] & 15; > > + if (!alens[i] || rcode != NOERROR) { > > + sendto(fd, queries[i], > > + qlens[i], MSG_NOSIGNAL, > > + (void *)&ns[ns_index], sl); > > + unanswered++; > > + } > > + } > > t1 = t2; > > servfail_retry = 2 * nqueries; > > } > > @@ -135,51 +145,77 @@ int __res_msend_rc(int nqueries, const unsigned > char *const *queries, > > /* Wait for a response, or until time to retry */ > > if (poll(&pfd, 1, t1+retry_interval-t2) <= 0) continue; > > > > - while ((rlen = recvfrom(fd, answers[next], asize, 0, > > + while ((rlen = recvfrom(fd, answer, 512, 0, > > (void *)&sa, (socklen_t[1]){sl})) >= 0) { > > > > /* Ignore non-identifiable packets */ > > if (rlen < 4) continue; > > > > /* Ignore replies from addresses we didn't send to > */ > > - for (j=0; j > - if (j==nns) continue; > > + if (memcmp(ns+ns_index, &sa, sl)) > > + continue; > > > > /* Find which query this answer goes with, if any > */ > > - for (i=next; i > - answers[next][0] != queries[i][0] || > > - answers[next][1] != queries[i][1] ); i++); > > + for (i=0; i > + answer[0] != queries[i][0] || > > + answer[1] != queries[i][1] ); i++); > > if (i==nqueries) continue; > > - if (alens[i]) continue; > > + > > + rcode = answers[i][3] & 15; > > + if (alens[i] && rcode == NOERROR) { > > + /* Do not override successful answers from > a more prioritied server */ > > + continue; > > + } > > > > /* Only accept positive or negative responses; > > * retry immediately on server failure, and ignore > > * all other codes such as refusal. */ > > - switch (answers[next][3] & 15) { > > - case 0: > > - case 3: > > - break; > > - case 2: > > + rcode = answer[3] & 15; > > + switch (rcode) { > > + case NOERROR: > > + case NXDOMAIN: > > + alens[i] = rlen; > > + memcpy(answers[i], answer, rlen); > > + unanswered--; > > + continue; > > + case SERVFAIL: > > if (servfail_retry && servfail_retry--) > > sendto(fd, queries[i], > > qlens[i], MSG_NOSIGNAL, > > - (void *)&ns[j], sl); > > + (void *)&ns[ns_index], sl); > > default: > > continue; > > } > > + } > > > > - /* Store answer in the right slot, or update next > > - * available temp slot if it's already in place. */ > > - alens[i] = rlen; > > - if (i == next) > > - for (; next next++); > > - else > > - memcpy(answers[i], answers[next], rlen); > > + /* Check if all sent queries have got NOERROR or NXDOMAIN > replies from this server, > > + * no need to retry it anymore even when not timed out > yet. When the unanswered counter > > + * drops to zero, any remaining NXDOMAIN replies were sure > sent from this server */ > > + if (!unanswered) { > > + all_done = 1; > > + for (i = 0; i < nqueries; i++) { > > + rcode = answers[i][3] & 15; > > + if (!(alens[i] && ((rcode == NOERROR) || > (rcode == NXDOMAIN)))) { > > + all_done = 0; > > + break; > > + } > > + } > > > > - if (next == nqueries) goto out; > > + if (all_done) > > + break; > > } > > } > > -out: > > + > > + /* Check if any queries is unresolved or unsuccessful (regardless > of failure code) > > + * try the next DNS server if available */ > > + if (++ns_index < conf->nns) { > > + for (i = 0; i < nqueries; i++) { > > + rcode = answers[i][3] & 15; > > + if (!alens[i] || rcode != NOERROR) > > + goto next_ns; > > + } > > + } > > + > > pthread_cleanup_pop(1); > > > > return 0; > > -- > > 2.34.1 > --00000000000044d54a05ebbd67e9 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: base64 PGRpdiBkaXI9Imx0ciI+SGkgUmljaCw8YnI+PGJyPk1hbnnCoHRoYW5rcyBmb3IgeW91ciBmZWVk YmFjaywgbXVjaCBhcHByZWNpYXRlZCE8YnI+PGJyPlllcCwgeW91JiMzOTt2ZSBnb3QgbXkgaWRl YS4gQmFzaWNhbGx5IG15IGJveCBoYXMgbXVsdGlwbGUgRE5TIHNlcnZlcnMgc2V0dXAgaW4gcmVz b2x2LmNvbmYsIGZvciBleGFtcGxlLCB0aGUgb25lIHNwZWNpZmllZCBmcm9tIG15IElTUCwgYW5v dGhlciBwdWJsaWMgb25lIGlmIG5lZWRlZCBhbmQgdGhlIG9uZSBmcm9tIG15IHByaXZhdGUgbmV0 d29yayAoYWZ0ZXIgSSBzZXR1cCBhIFZQTiB0dW5uZWwgdG8gbXkgb2ZmaWNlIG5ldHdvcmspIGFu ZCBvbmx5IHRoZSBsYXR0ZXIgdW5kZXJzdGFuZCBwcml2YXRlIGhvc3QgbmFtZXMgKHN1Y2ggYXMg QUFBIHNlcnZlciBvciByZW1vdGUgc3lzbG9nIHNlcnZlcnMgaW4gdGhlIG9mZmljZSBuZXR3b3Jr KS48YnI+PGJyPkdpdmVuIHRoZSBjdXJyZW50IG1lY2hhbmlzbSBpbXBsZW1lbnRlZCBieSBtdXNs JiMzOTtzIHJlc29sdmVyLCBkaWZmZXJlbnQgc2VydmVycyBjb3VsZCByZXBseSBjb25mbGljdGVk IGFuc3dlcnMsIGZvciBleGFtcGxlLCBOWERPTUFJTiBmcm9tIHB1YmxpYyBzZXJ2ZXIgZm9yIHBy aXZhdGUgaG9zdG5hbWVzIHdoZXJlYXMgTk9FUlJPUiBmcm9tIHRoZSBwcml2YXRlIEROUyBzZXJ2 ZXIuIEkgdW5kZXJzdGFuZMKgeW91ciBzdWdnZXN0aW9uIHRvIGZ1cnRoZXIgbWFuaXB1bGF0ZSBh IGxvY2FsIHVuaW9uaW5nIG5hbWVzZXJ2ZXIgdG8gaGFuZGxlIGNvbmZsaWN0ZWQgcmVwbGllcy48 YnI+PGJyPkZyYW5rbHkgc3BlYWtpbmcsIGluIG15IHVzZSBjYXNlIHRoZSBzaXR1YXRpb24gaXMg ZXZlbiBtb3JlIGNvbXBsaWNhdGVkLiBNeSBib3hlcyBhcmUgbXVsdC1ob21lZCwgZm9yIGV4YW1w bGUsIHdpdGggZXRoMCBhbmQgY2VsbHVsYXIgaW50ZXJmYWNlcywgdGhlIElTUCBpbiBlYWNoIG5l dHdvcmsgd2lsbCBwcm92aWRlIGRpZmZlcmVudCBETlMgc2VydmVyLiBUaGUgZGVmYXVsdCBnYXRl d2F5IGZvciBteSBkZXZpY2UgbWF5IHBpbmctcG9uZyBhbW9uZyB0aGF0IG9mIGV0aDAgYW5kIHRo YXQgb2YgY2VsbHVsYXIgaW50ZXJmYWNlLCBzaG91bGQgdGhlIGNhYmxlL2V0aDAgY29ubmVjdGlv biBiZWNvbWVzIGRvd24gb3IgcmVzdW1lZC4gSW4gdGhpcyBjYXNlIEkgbmVlZCB0byByZS1vcmRl ciBuYW1lc2VydmVycyBpbiByZXNvbHYuY29uZiB0byBwdXQgZmlyc3QgdGhlIG5hbWUgc2VydmVy cyBhc3NvY2lhdGVkIHdpdGggdGhlIGN1cnJlbnQgZGVmYXVsdCBnYXRld2F5JiMzOTtzIGludGVy ZmFjZS48YnI+PGJyPkFnYWluLCBpdCBpcyBhcmd1YWJsZSB0aGF0IHRoaXMgY2FuIGFsc28gYmUg aGFuZGxlZCBieSBjaGFuZ2luZyB0aGUgcG9saWN5IGFkb3B0ZWQgYnkgdGhlIGxvY2FsIHVuaW9u aW5nIG5hbWUgc2VydmVyICh0byBwcmVmZXIgd2hpY2ggbmFtZXNlcnZlciB3aGVuIGhhbmRsaW5n IGNvbmZsaWN0cykuIEluIG15IG1pbmQsIHNlcmlhbGlzaW5nIEROUyBzZXJ2ZXJzJiMzOTsgcXVl cmllcyB3b3VsZCBzcGFyZSB0aGUgbmVlZCBvZiBzZXR0aW5nIGxvY2FsIHVuaW9uaW5nIHNlcnZl ciBhbmQgY2hhbmdpbmcgaXRzIHBvbGljeSAtIHRoZSBvcmRlcmluZyBvZiBuYW1lc2VydmVycyBp biByZXNvbHYuY29uZiBjYW4gYmUgYWRqdXN0ZWQgYW55dGltZSB0byBwdXQgdGhlIHByZWZlcnJl ZCBvbmUgZmlyc3QuPGJyPjxicj5XaGF0IGlmIEkgaW50cm9kdWNlIGEgbmV3IG1hY3JvIHRvIHBy b3ZpZGUgbmFtZXNlcnZlciBzZXJpYWxpc2F0aW9uIGFsb25nIHdpdGggcGFyYWxsZWxpc20/IHRo ZSBuZXcgbWFjcm8gd2lsbCBkZWZhdWx0IHRvIG9mZiB0byBrZWVwIHRoZSBjdXJyZW50IGJlaGF2 aW91ci4gU2hvdWxkIHRoZSBuZWVkIGFyaXNlIGZvciBtdXNsIHVzZXJzIHRvIHB1dCBzb21lIHdl aWdodCwgb3IgcHJlY2VkZW5jZSBvbiBuYW1lIHNlcnZlcnMsIHRoZXkgY291bGQgb3B0IGluIHRv IHNlcmlhbGlzYXRpb24gYW5kIGRvbiYjMzk7dCB3b3JyeSBhYm91dCBmdXJ0aGVyIHNldHRpbmcg dXAgbG9jYWwgdW5pb25pbmcgbmFtZSBzZXJ2ZXI/PGJyPjxicj5Mb29raW5nIGZvcndhcmQgdG8g eW91ciBmZWVkYmFjay48YnI+PGJyPkhhcnJ5PGJyPjxicj48YnI+PC9kaXY+PGJyPjxkaXYgY2xh c3M9ImdtYWlsX3F1b3RlIj48ZGl2IGRpcj0ibHRyIiBjbGFzcz0iZ21haWxfYXR0ciI+T24gTW9u LCBPY3QgMjQsIDIwMjIgYXQgMTozMiBBTSBSaWNoIEZlbGtlciAmbHQ7PGEgaHJlZj0ibWFpbHRv OmRhbGlhc0BhZXJpZmFsLmN4Ij5kYWxpYXNAYWVyaWZhbC5jeDwvYT4mZ3Q7IHdyb3RlOjxicj48 L2Rpdj48YmxvY2txdW90ZSBjbGFzcz0iZ21haWxfcXVvdGUiIHN0eWxlPSJtYXJnaW46MHB4IDBw eCAwcHggMC44ZXg7Ym9yZGVyLWxlZnQ6MXB4IHNvbGlkIHJnYigyMDQsMjA0LDIwNCk7cGFkZGlu Zy1sZWZ0OjFleCI+T24gU3VuLCBPY3QgMjMsIDIwMjIgYXQgMDk6MTg6MDFQTSArMTAwMCwgUWlu Z3RhbyBDYW8gd3JvdGU6PGJyPg0KJmd0OyBRdWVyeWluZyBhbGwgY29uZmlndXJlZCBETlMgc2Vy dmVycyBpbiBwYXJhbGxlbCBib29zdCBwZXJmb3JtYW5jZSBidXQgbWFrZXM8YnI+DQomZ3Q7IGl0 IGltcG9zc2libGUgdG8gcHJlZmVyIHByaXZhdGUgRE5TIHNlcnZlcnMgdG8gcHVibGljIG9uZXMu IFNlcmlhbGlzZSBETlM8YnI+DQomZ3Q7IHNlcnZlcnMgYWNjZXNzIGZyb20gdGhlIHRvcCBvZiB0 aGUgbmFtZXNlcnZlciBzcGVjaWZpZWQgaW4gcmVzb2x2LmNvbmYgYW5kPGJyPg0KJmd0OyBvbmx5 IG1vdmUgb24gdG8gdGhlIG5leHQsIG9yIGxlc3MgcHJlZmVycmVkIEROUyBzZXJ2ZXIgd2hlbiB0 aGUgY3VycmVudCBvbmU8YnI+DQomZ3Q7IGVpdGhlciB0aW1lZCBvdXQgb3IgcmVwbGllZCBOT0VS Uk9SIGFuZCBOWERPTUFJTiBmb3IgYWxsIHF1ZXJpZXM8YnI+DQomZ3Q7IDxicj4NCiZndDsgV2hl biBxdWVyeWluZyB0aGUgbmV4dCBvciBsZXNzIHBlcmZlcnJlZCBETlMgc2VydmVycywgb25seSB1 bnN1Y2Nlc3NmdWxseTxicj4NCiZndDsgcmVzb2x2ZWQgaG9zdCBuYW1lcyB3ZXJlIHF1ZXJpZWQu IFdoZW4gcmVwbGllcyBhcmUgcmVjZWl2ZWQsIHRoZXkgd29uJiMzOTt0IHJlcGxhY2U8YnI+DQom Z3Q7IGEgcGVydmlvdXNseSBzdWNjZXNzZnVsIGFuc3dlci4gVGhpcyBlbnN1cmVzIHN1Y2Nlc3Nm dWwgYW5zd2VycyBmcm9tIGhpZ2hlcjxicj4NCiZndDsgcHJpb3JpdGlzZWQgRE5TIHNlcnZlcnMg d29uJiMzOTt0IGJlIG92ZXJyaWRkZW48YnI+DQomZ3Q7IDxicj4NCiZndDsgVGhpcyBlbGltaW5h dGVzIGEgcmFjeSBjb25kaXRpb24gd2hlbiBkaWZmZXJlbnQgRE5TIHNlcnZlcnMgcmVwbGllcyBk aWZmZXJlbnRseTxicj4NCiZndDsgdG8gYSBxdWVyeSwgdGhlIGxhc3QgcmVjZWl2ZWQgb25lIHdp bnM8YnI+DQomZ3Q7IDxicj4NCiZndDsgTGFzdCBidXQgbm90IGxlYXN0LCB1c2luZyBhIGxvY2Fs IGFycmF5IHRvIHNhdmUgdGhlIGN1cnJlbnRseSByZWNlaXZlZCByZXBseSB0bzxicj4NCiZndDsg c2ltcGxpZnkgdGhlIGxvZ2ljIHRvIHJlLXNodWZmbGUgYW5zd2Vyc1tuZXh0XSB0byB0aGUgY29y cmVzcG9uZGluZyBhbnN3ZXJzW2ldPGJyPg0KJmd0OyA8YnI+DQomZ3Q7IFNpZ25lZC1vZmYtYnk6 IFFpbmd0YW8gQ2FvICZsdDs8YSBocmVmPSJtYWlsdG86cWluZ3Rhby5jYW9AZGlnaS5jb20iIHRh cmdldD0iX2JsYW5rIj5xaW5ndGFvLmNhb0BkaWdpLmNvbTwvYT4mZ3Q7PGJyPg0KPGJyPg0KVGhp cyBwYXRjaCBpcyBiZWluZyBzdWJtaXR0ZWQgYXMgb25lIHRvIGNoYW5nZSBhIHZlcnkgaW50ZW50 aW9uYWwgYW5kPGJyPg0KbG9uZ3N0YW5kaW5nIGJlaGF2aW9yIChhbmQgd2l0aCB0aGF0IGltcG9z ZSBhIG5ldyBjb250cmFjdCkgYW5kIGlzIG5vdDxicj4NCmdvaW5nIHRvIGJlIGFjY2VwdGVkLiBB IGJhc2ljIHByZW1pc2Ugb2YgbXVzbCYjMzk7cyByZXNvbHZlciwgdGhhdCYjMzk7cyBub3Q8YnI+ DQpqdXN0IGFyYml0cmFyeSBidXQgYSBjb25zZXF1ZW5jZSBvZiBhICZxdW90O2ZhbGxiYWNrJnF1 b3Q7IG1vZGVsLCBpcyB0aGF0IGFsbDxicj4NCnRoZSBuYW1lc2VydmVycyBwcm92aWRlZCBwcmVz ZW50IGEgY29uc2lzdGVudCB2aWV3IG9mIGEgZ2xvYmFsIGRuczxicj4NCm5hbWVzcGFjZS4gPGJy Pg0KPGJyPg0KU29tZSBwZW9wbGUgbWlzdGFrZSAmcXVvdDtmYWxsYmFjayZxdW90OyBmb3IgJnF1 b3Q7c2VhcmNoJnF1b3Q7IGJlY2F1c2UgaXQga2luZGEgYXBwZWFyczxicj4NCnRvIHdvcmsgdGhh dCB3YXkgaWYgeW91IGRvbiYjMzk7dCBhY3R1YWxseSBxdWVzdGlvbiB3aGF0IGhhcHBlbnMgaW4g dGhlPGJyPg0KY29ybmVyIGNhc2VzLiBCdXQgaWYgeW91JiMzOTtyZSB1c2luZyBmYWxsYmFjayBh cyBzZWFyY2gsIGZhaWx1cmUgb2YgdGhlPGJyPg0KcHJpbWFyeSBzZXJ2ZXIgdG8gYW5zd2VyIGlu IHRpbWUgd2lsbCAqY2hhbmdlIHRoZSByZXN1bHRzKiBvZiB0aGU8YnI+DQpxdWVyeS4gVGhpcyBp cyBub3QgaG93IGZhbGxiYWNrIGlzIHN1cHBvc2VkIHRvIHdvcmsuPGJyPg0KPGJyPg0KSXQgd291 bGQgaGF2ZSBiZWVuIGEgbG90IG1vcmUgcHJvZHVjdGl2ZSB0byBzdGFydCBmcm9tIGEgc3RhbmRw b2ludCBvZjxicj4NCndoYXQgeW91JiMzOTtyZSB0cnlpbmcgdG8gZG8uIEkgYXNzdW1lIHRoYXQm IzM5O3MgJnF1b3Q7dW5pb25pbmcmcXVvdDsgd2hlcmUgeW91IGhhdmUgYTxicj4NCmxvY2FsIG5h bWVzZXJ2ZXIgc2VydmluZyBmYWtlIG5hbWVzIHRoYXQgZG9uJiMzOTt0IGFjdHVhbGx5IGV4aXN0 IGluIHRoZTxicj4NCnJlYWwgRE5TIG5hbWVzcGFjZSwgYW5kIGEgcmVhbCBuYW1lc2VydmVyIHRo YXQmIzM5O3Mgc2VydmluZyB0aGUgcmVhbCBETlM8YnI+DQpuYW1lc3BhY2UuIFRoZXJlIGFyZSBh dCBsZWFzdCAyIHZhbGlkIHdheXMgdG8gYWNoaWV2ZSB0aGlzIHRoYXQgZG9uJiMzOTt0PGJyPg0K YnJlYWsgaW4gdGhlIGFib3ZlIG1hbm5lci48YnI+DQo8YnI+DQoxLiBSdW4gYSB1bmlvbmluZyBu YW1lc2VydmVyIGxvY2FsbHkuIFRoZSB1bmlvbmluZyBuYW1lc2VydmVyIGhhbmRsZXM8YnI+DQrC oCDCoGFsbCB0aGUgY29tcGxleCBsb2dpYyBvZiBoYW5kbGluZyBjbGFzaGVzIGFuZCB3aGljaCB1 cHN0cmVhbSBzb3VyY2U8YnI+DQrCoCDCoHRha2VzIHByZWNlZGVuY2UsIHF1ZXJ5aW5nIGJvdGgg YW5kIG9ubHkgYW5zd2VyaW5nIGlmIGl0IGdldHM8YnI+DQrCoCDCoHN1ZmZpY2llbnQgYW5zd2Vy cyB0byBkcmF3IGEgY29uY2x1c2l2ZSByZXN1bHQgYWJvdXQgd2hpY2ggcmVzdWx0PGJyPg0KwqAg wqBpdCBjYW4gdXNlIChhbmQgU2VydkZhaWwgb3RoZXJ3aXNlKS48YnI+DQo8YnI+DQoyLiBQdXQg eW91ciBsb2NhbCBuYW1lcyB1bmRlciBhbiBhY3R1YWwgRE5TIGRvbWFpbiAob3Igc3ViZG9tYWlu IHpvbmUpPGJyPg0KwqAgwqB5b3UgYWN0dWFsbHkgb3duLiBTZXQgdGhlIHB1YmxpYyBETlMgZGVs ZWdhdGlvbnMgdG8gcG9pbnQgdG88YnI+DQrCoCDCoG5hbWVzZXJ2ZXJzIHRoYXQgZG9uJiMzOTt0 IGV4aXN0LiBOb3cgdGhlIHB1YmxpYyBETlMgd2lsbCBhbHdheXM8YnI+DQrCoCDCoFNlcnZGYWls LiBTZXQgeW91ciBwcml2YXRlIGxvY2FsIG5hbWVzZXJ2ZXIgdG8gb25seSByZXR1cm4gcmVzdWx0 czxicj4NCsKgIMKgZm9yIHRoaXMgbG9jYWwgem9uZSwgYW5kIFNlcnZGYWlsIG90aGVyd2lzZS4g QXMgYSByZXN1bHQsIG5laXRoZXI8YnI+DQrCoCDCoGlzIHByb3ZpZGluZyBjb25mbGljdGluZyBh bnN3ZXJzIGZvciB0aGUgcGFydCBvZiB0aGUgbmFtZXNwYWNlIHRoZTxicj4NCsKgIMKgb3RoZXIg aXMgcmVzcG9uc2libGUgZm9yLjxicj4NCjxicj4NClRoZXJlIGFyZSBsaWtlbHkgb3RoZXIgd2F5 cyB0b28uPGJyPg0KPGJyPg0KJmd0OyAtLS08YnI+DQomZ3Q7wqAgc3JjL25ldHdvcmsvcmVzX21z ZW5kLmMgfCAxMDAgKysrKysrKysrKysrKysrKysrKysrKysrKysrLS0tLS0tLS0tLS0tLTxicj4N CiZndDvCoCAxIGZpbGUgY2hhbmdlZCwgNjggaW5zZXJ0aW9ucygrKSwgMzIgZGVsZXRpb25zKC0p PGJyPg0KJmd0OyA8YnI+DQomZ3Q7IGRpZmYgLS1naXQgYS9zcmMvbmV0d29yay9yZXNfbXNlbmQu YyBiL3NyYy9uZXR3b3JrL3Jlc19tc2VuZC5jPGJyPg0KJmd0OyBpbmRleCA5YWRhZWExMy4uMTMw YWM0ZmUgMTAwNjQ0PGJyPg0KJmd0OyAtLS0gYS9zcmMvbmV0d29yay9yZXNfbXNlbmQuYzxicj4N CiZndDsgKysrIGIvc3JjL25ldHdvcmsvcmVzX21zZW5kLmM8YnI+DQomZ3Q7IEBAIC0xMCw2ICsx MCw3IEBAPGJyPg0KJmd0O8KgICNpbmNsdWRlICZsdDt1bmlzdGQuaCZndDs8YnI+DQomZ3Q7wqAg I2luY2x1ZGUgJmx0O2Vycm5vLmgmZ3Q7PGJyPg0KJmd0O8KgICNpbmNsdWRlICZsdDtwdGhyZWFk LmgmZ3Q7PGJyPg0KJmd0OyArI2luY2x1ZGUgJmx0O2FycGEvbmFtZXNlci5oJmd0Ozxicj4NCiZn dDvCoCAjaW5jbHVkZSAmcXVvdDtzdGRpb19pbXBsLmgmcXVvdDs8YnI+DQomZ3Q7wqAgI2luY2x1 ZGUgJnF1b3Q7c3lzY2FsbC5oJnF1b3Q7PGJyPg0KJmd0O8KgICNpbmNsdWRlICZxdW90O2xvb2t1 cC5oJnF1b3Q7PGJyPg0KJmd0OyBAQCAtNDEsMTEgKzQyLDEyIEBAIGludCBfX3Jlc19tc2VuZF9y YyhpbnQgbnF1ZXJpZXMsIGNvbnN0IHVuc2lnbmVkIGNoYXIgKmNvbnN0ICpxdWVyaWVzLDxicj4N CiZndDvCoCDCoCDCoCDCoGludCBubnMgPSAwOzxicj4NCiZndDvCoCDCoCDCoCDCoGludCBmYW1p bHkgPSBBRl9JTkVUOzxicj4NCiZndDvCoCDCoCDCoCDCoGludCBybGVuOzxicj4NCiZndDsgLcKg IMKgIMKgaW50IG5leHQ7PGJyPg0KJmd0OyAtwqAgwqAgwqBpbnQgaSwgajs8YnI+DQomZ3Q7ICvC oCDCoCDCoGludCBpOzxicj4NCiZndDvCoCDCoCDCoCDCoGludCBjczs8YnI+DQomZ3Q7wqAgwqAg wqAgwqBzdHJ1Y3QgcG9sbGZkIHBmZDs8YnI+DQomZ3Q7wqAgwqAgwqAgwqB1bnNpZ25lZCBsb25n IHQwLCB0MSwgdDI7PGJyPg0KJmd0OyArwqAgwqAgwqBpbnQgbnNfaW5kZXgsIHJjb2RlLCBhbGxf ZG9uZSwgdW5hbnN3ZXJlZDs8YnI+DQomZ3Q7ICvCoCDCoCDCoHVuc2lnbmVkIGNoYXIgYW5zd2Vy WzUxMl07PGJyPg0KJmd0O8KgIDxicj4NCiZndDvCoCDCoCDCoCDCoHB0aHJlYWRfc2V0Y2FuY2Vs c3RhdGUoUFRIUkVBRF9DQU5DRUxfRElTQUJMRSwgJmFtcDtjcyk7PGJyPg0KJmd0O8KgIDxicj4N CiZndDsgQEAgLTExNSwxOSArMTE3LDI3IEBAIGludCBfX3Jlc19tc2VuZF9yYyhpbnQgbnF1ZXJp ZXMsIGNvbnN0IHVuc2lnbmVkIGNoYXIgKmNvbnN0ICpxdWVyaWVzLDxicj4NCiZndDvCoCDCoCDC oCDCoHBmZC5mZCA9IGZkOzxicj4NCiZndDvCoCDCoCDCoCDCoHBmZC5ldmVudHMgPSBQT0xMSU47 PGJyPg0KJmd0O8KgIMKgIMKgIMKgcmV0cnlfaW50ZXJ2YWwgPSB0aW1lb3V0IC8gYXR0ZW1wdHM7 PGJyPg0KJmd0OyAtwqAgwqAgwqBuZXh0ID0gMDs8YnI+DQomZ3Q7ICs8YnI+DQomZ3Q7ICvCoCDC oCDCoG5zX2luZGV4ID0gMDsgLyogU3RhcnQgZnJvbSB0aGUgdG9wIG5hbWUgc2VydmVyICovPGJy Pg0KJmd0OyArPGJyPg0KJmd0OyArbmV4dF9uczo8YnI+DQomZ3Q7wqAgwqAgwqAgwqB0MCA9IHQy ID0gbXRpbWUoKTs8YnI+DQomZ3Q7wqAgwqAgwqAgwqB0MSA9IHQyIC0gcmV0cnlfaW50ZXJ2YWw7 PGJyPg0KJmd0O8KgIDxicj4NCiZndDsgK8KgIMKgIMKgdW5hbnN3ZXJlZCA9IDA7PGJyPg0KJmd0 OyArPGJyPg0KJmd0O8KgIMKgIMKgIMKgZm9yICg7IHQyLXQwICZsdDsgdGltZW91dDsgdDI9bXRp bWUoKSkgezxicj4NCiZndDvCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoGlmICh0Mi10MSAmZ3Q7PSBy ZXRyeV9pbnRlcnZhbCkgezxicj4NCiZndDsgLcKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgLyogUXVlcnkgYWxsIGNvbmZpZ3VyZWQgbmFtc2VydmVycyBpbiBwYXJhbGxlbCAqLzxicj4N CiZndDsgLcKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgZm9yIChpPTA7IGkmbHQ7bnF1 ZXJpZXM7IGkrKyk8YnI+DQomZ3Q7IC3CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoGlmICghYWxlbnNbaV0pPGJyPg0KJmd0OyAtwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBmb3IgKGo9MDsgaiZsdDtubnM7IGor Kyk8YnI+DQomZ3Q7IC3CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoHNlbmR0byhmZCwgcXVlcmllc1tpXSw8YnI+DQomZ3Q7 IC3CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoHFsZW5zW2ldLCBNU0dfTk9TSUdOQUwsPGJyPg0KJmd0 OyAtwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAodm9pZCAqKSZhbXA7bnNbal0sIHNsKTs8YnI+DQom Z3Q7ICvCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoGZvciAoaT0wOyBpJmx0O25xdWVy aWVzOyBpKyspIHs8YnI+DQomZ3Q7ICvCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoC8qIE9ubHkgcXVlcnkgdW5yZXNvbHZlZCBvciBuZWdhdGl2ZSByZXNvbHZlZCBo b3N0IG5hbWVzICovPGJyPg0KJmd0OyArwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAgwqByY29kZSA9IGFuc3dlcnNbaV1bM10gJmFtcDsgMTU7PGJyPg0KJmd0OyArwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBpZiAoIWFsZW5zW2ldIHx8 IHJjb2RlICE9IE5PRVJST1IpIHs8YnI+DQomZ3Q7ICvCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoHNlbmR0byhmZCwgcXVlcmllc1tpXSw8YnI+ DQomZ3Q7ICvCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoHFsZW5zW2ldLCBNU0dfTk9TSUdOQUwsPGJyPg0KJmd0OyArwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAodm9pZCAqKSZhbXA7bnNbbnNfaW5kZXhdLCBzbCk7PGJyPg0KJmd0OyArwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqB1bmFuc3dl cmVkKys7PGJyPg0KJmd0OyArwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqB9PGJyPg0KJmd0OyArwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqB9PGJyPg0K Jmd0O8KgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgdDEgPSB0Mjs8YnI+DQomZ3Q7 wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBzZXJ2ZmFpbF9yZXRyeSA9IDIgKiBu cXVlcmllczs8YnI+DQomZ3Q7wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqB9PGJyPg0KJmd0OyBAQCAt MTM1LDUxICsxNDUsNzcgQEAgaW50IF9fcmVzX21zZW5kX3JjKGludCBucXVlcmllcywgY29uc3Qg dW5zaWduZWQgY2hhciAqY29uc3QgKnF1ZXJpZXMsPGJyPg0KJmd0O8KgIMKgIMKgIMKgIMKgIMKg IMKgIMKgLyogV2FpdCBmb3IgYSByZXNwb25zZSwgb3IgdW50aWwgdGltZSB0byByZXRyeSAqLzxi cj4NCiZndDvCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoGlmIChwb2xsKCZhbXA7cGZkLCAxLCB0MSty ZXRyeV9pbnRlcnZhbC10MikgJmx0Oz0gMCkgY29udGludWU7PGJyPg0KJmd0O8KgIDxicj4NCiZn dDsgLcKgIMKgIMKgIMKgIMKgIMKgIMKgd2hpbGUgKChybGVuID0gcmVjdmZyb20oZmQsIGFuc3dl cnNbbmV4dF0sIGFzaXplLCAwLDxicj4NCiZndDsgK8KgIMKgIMKgIMKgIMKgIMKgIMKgd2hpbGUg KChybGVuID0gcmVjdmZyb20oZmQsIGFuc3dlciwgNTEyLCAwLDxicj4NCiZndDvCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCh2b2lkICopJmFtcDtzYSwgKHNvY2tsZW5fdFsxXSl7c2x9KSkgJmd0 Oz0gMCkgezxicj4NCiZndDvCoCA8YnI+DQomZ3Q7wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAvKiBJZ25vcmUgbm9uLWlkZW50aWZpYWJsZSBwYWNrZXRzICovPGJyPg0KJmd0O8Kg IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgaWYgKHJsZW4gJmx0OyA0KSBjb250aW51 ZTs8YnI+DQomZ3Q7wqAgPGJyPg0KJmd0O8KgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgLyogSWdub3JlIHJlcGxpZXMgZnJvbSBhZGRyZXNzZXMgd2UgZGlkbiYjMzk7dCBzZW5kIHRv ICovPGJyPg0KJmd0OyAtwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBmb3IgKGo9MDsg aiZsdDtubnMgJmFtcDsmYW1wOyBtZW1jbXAobnMraiwgJmFtcDtzYSwgc2wpOyBqKyspOzxicj4N CiZndDsgLcKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgaWYgKGo9PW5ucykgY29udGlu dWU7PGJyPg0KJmd0OyArwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBpZiAobWVtY21w KG5zK25zX2luZGV4LCAmYW1wO3NhLCBzbCkpPGJyPg0KJmd0OyArwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBjb250aW51ZTs8YnI+DQomZ3Q7wqAgPGJyPg0KJmd0 O8KgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgLyogRmluZCB3aGljaCBxdWVyeSB0 aGlzIGFuc3dlciBnb2VzIHdpdGgsIGlmIGFueSAqLzxicj4NCiZndDsgLcKgIMKgIMKgIMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgZm9yIChpPW5leHQ7IGkmbHQ7bnF1ZXJpZXMgJmFtcDsmYW1wOyAo PGJyPg0KJmd0OyAtwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBh bnN3ZXJzW25leHRdWzBdICE9IHF1ZXJpZXNbaV1bMF0gfHw8YnI+DQomZ3Q7IC3CoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoGFuc3dlcnNbbmV4dF1bMV0gIT0gcXVl cmllc1tpXVsxXSApOyBpKyspOzxicj4NCiZndDsgK8KgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgIMKgZm9yIChpPTA7IGkmbHQ7bnF1ZXJpZXMgJmFtcDsmYW1wOyAoPGJyPg0KJmd0OyArwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBhbnN3ZXJbMF0gIT0gcXVl cmllc1tpXVswXSB8fDxicj4NCiZndDsgK8KgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgIMKgIMKgIMKgYW5zd2VyWzFdICE9IHF1ZXJpZXNbaV1bMV0gKTsgaSsrKTs8YnI+DQomZ3Q7 wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBpZiAoaT09bnF1ZXJpZXMpIGNvbnRp bnVlOzxicj4NCiZndDsgLcKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgaWYgKGFsZW5z W2ldKSBjb250aW51ZTs8YnI+DQomZ3Q7ICs8YnI+DQomZ3Q7ICvCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoHJjb2RlID0gYW5zd2Vyc1tpXVszXSAmYW1wOyAxNTs8YnI+DQomZ3Q7ICvC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoGlmIChhbGVuc1tpXSAmYW1wOyZhbXA7IHJj b2RlID09IE5PRVJST1IpIHs8YnI+DQomZ3Q7ICvCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoC8qIERvIG5vdCBvdmVycmlkZSBzdWNjZXNzZnVsIGFuc3dlcnMgZnJv bSBhIG1vcmUgcHJpb3JpdGllZCBzZXJ2ZXIgKi88YnI+DQomZ3Q7ICvCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoGNvbnRpbnVlOzxicj4NCiZndDsgK8KgIMKgIMKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgfTxicj4NCiZndDvCoCA8YnI+DQomZ3Q7wqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAvKiBPbmx5IGFjY2VwdCBwb3NpdGl2ZSBvciBuZWdh dGl2ZSByZXNwb25zZXM7PGJyPg0KJmd0O8KgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgICogcmV0cnkgaW1tZWRpYXRlbHkgb24gc2VydmVyIGZhaWx1cmUsIGFuZCBpZ25vcmU8YnI+ DQomZ3Q7wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgKiBhbGwgb3RoZXIgY29k ZXMgc3VjaCBhcyByZWZ1c2FsLiAqLzxicj4NCiZndDsgLcKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgIMKgIMKgc3dpdGNoIChhbnN3ZXJzW25leHRdWzNdICZhbXA7IDE1KSB7PGJyPg0KJmd0OyAt wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBjYXNlIDA6PGJyPg0KJmd0OyAtwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBjYXNlIDM6PGJyPg0KJmd0OyAtwqAgwqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBicmVhazs8YnI+DQomZ3Q7IC3CoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoGNhc2UgMjo8YnI+DQomZ3Q7ICvCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoHJjb2RlID0gYW5zd2VyWzNdICZhbXA7IDE1Ozxicj4NCiZndDsg K8KgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgc3dpdGNoIChyY29kZSkgezxicj4NCiZn dDsgK8KgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgY2FzZSBOT0VSUk9SOjxicj4NCiZn dDsgK8KgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgY2FzZSBOWERPTUFJTjo8YnI+DQom Z3Q7ICvCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoGFsZW5zW2ld ID0gcmxlbjs8YnI+DQomZ3Q7ICvCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoG1lbWNweShhbnN3ZXJzW2ldLCBhbnN3ZXIsIHJsZW4pOzxicj4NCiZndDsgK8KgIMKg IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgdW5hbnN3ZXJlZC0tOzxicj4N CiZndDsgK8KgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgY29udGlu dWU7PGJyPg0KJmd0OyArwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBjYXNlIFNFUlZG QUlMOjxicj4NCiZndDvCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoGlmIChzZXJ2ZmFpbF9yZXRyeSAmYW1wOyZhbXA7IHNlcnZmYWlsX3JldHJ5LS0pPGJyPg0K Jmd0O8KgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgIMKgc2VuZHRvKGZkLCBxdWVyaWVzW2ldLDxicj4NCiZndDvCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoHFsZW5z W2ldLCBNU0dfTk9TSUdOQUwsPGJyPg0KJmd0OyAtwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAodm9pZCAqKSZhbXA7bnNb al0sIHNsKTs8YnI+DQomZ3Q7ICvCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCh2b2lkICopJmFtcDtuc1tuc19pbmRleF0s IHNsKTs8YnI+DQomZ3Q7wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBkZWZhdWx0 Ojxicj4NCiZndDvCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oGNvbnRpbnVlOzxicj4NCiZndDvCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoH08 YnI+DQomZ3Q7ICvCoCDCoCDCoCDCoCDCoCDCoCDCoH08YnI+DQomZ3Q7wqAgPGJyPg0KJmd0OyAt wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAvKiBTdG9yZSBhbnN3ZXIgaW4gdGhlIHJp Z2h0IHNsb3QsIG9yIHVwZGF0ZSBuZXh0PGJyPg0KJmd0OyAtwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAgwqAgKiBhdmFpbGFibGUgdGVtcCBzbG90IGlmIGl0JiMzOTtzIGFscmVhZHkgaW4g cGxhY2UuICovPGJyPg0KJmd0OyAtwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBhbGVu c1tpXSA9IHJsZW47PGJyPg0KJmd0OyAtwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBp ZiAoaSA9PSBuZXh0KTxicj4NCiZndDsgLcKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg IMKgIMKgIMKgIMKgZm9yICg7IG5leHQmbHQ7bnF1ZXJpZXMgJmFtcDsmYW1wOyBhbGVuc1tuZXh0 XTsgbmV4dCsrKTs8YnI+DQomZ3Q7IC3CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoGVs c2U8YnI+DQomZ3Q7IC3CoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC oG1lbWNweShhbnN3ZXJzW2ldLCBhbnN3ZXJzW25leHRdLCBybGVuKTs8YnI+DQomZ3Q7ICvCoCDC oCDCoCDCoCDCoCDCoCDCoC8qIENoZWNrIGlmIGFsbCBzZW50IHF1ZXJpZXMgaGF2ZSBnb3QgTk9F UlJPUiBvciBOWERPTUFJTiByZXBsaWVzIGZyb20gdGhpcyBzZXJ2ZXIsPGJyPg0KJmd0OyArwqAg wqAgwqAgwqAgwqAgwqAgwqAgKiBubyBuZWVkIHRvIHJldHJ5IGl0IGFueW1vcmUgZXZlbiB3aGVu IG5vdCB0aW1lZCBvdXQgeWV0LiBXaGVuIHRoZSB1bmFuc3dlcmVkIGNvdW50ZXI8YnI+DQomZ3Q7 ICvCoCDCoCDCoCDCoCDCoCDCoCDCoCAqIGRyb3BzIHRvIHplcm8sIGFueSByZW1haW5pbmcgTlhE T01BSU4gcmVwbGllcyB3ZXJlIHN1cmUgc2VudCBmcm9tIHRoaXMgc2VydmVyICovPGJyPg0KJmd0 OyArwqAgwqAgwqAgwqAgwqAgwqAgwqBpZiAoIXVuYW5zd2VyZWQpIHs8YnI+DQomZ3Q7ICvCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoGFsbF9kb25lID0gMTs8YnI+DQomZ3Q7ICvCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoGZvciAoaSA9IDA7IGkgJmx0OyBucXVlcmllczsg aSsrKSB7PGJyPg0KJmd0OyArwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqByY29kZSA9IGFuc3dlcnNbaV1bM10gJmFtcDsgMTU7PGJyPg0KJmd0OyArwqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBpZiAoIShhbGVuc1tpXSAmYW1wOyZh bXA7ICgocmNvZGUgPT0gTk9FUlJPUikgfHwgKHJjb2RlID09IE5YRE9NQUlOKSkpKSB7PGJyPg0K Jmd0OyArwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqBhbGxfZG9uZSA9IDA7PGJyPg0KJmd0OyArwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBicmVhazs8YnI+DQomZ3Q7ICvCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoH08YnI+DQomZ3Q7ICvCoCDCoCDCoCDC oCDCoCDCoCDCoCDCoCDCoCDCoCDCoH08YnI+DQomZ3Q7wqAgPGJyPg0KJmd0OyAtwqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBpZiAobmV4dCA9PSBucXVlcmllcykgZ290byBvdXQ7PGJy Pg0KJmd0OyArwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBpZiAoYWxsX2RvbmUpPGJy Pg0KJmd0OyArwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBicmVh azs8YnI+DQomZ3Q7wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqB9PGJyPg0KJmd0O8KgIMKgIMKgIMKg fTxicj4NCiZndDsgLW91dDo8YnI+DQomZ3Q7ICs8YnI+DQomZ3Q7ICvCoCDCoCDCoC8qIENoZWNr IGlmIGFueSBxdWVyaWVzIGlzIHVucmVzb2x2ZWQgb3IgdW5zdWNjZXNzZnVsIChyZWdhcmRsZXNz IG9mIGZhaWx1cmUgY29kZSk8YnI+DQomZ3Q7ICvCoCDCoCDCoCAqIHRyeSB0aGUgbmV4dCBETlMg c2VydmVyIGlmIGF2YWlsYWJsZSAqLzxicj4NCiZndDsgK8KgIMKgIMKgaWYgKCsrbnNfaW5kZXgg Jmx0OyBjb25mLSZndDtubnMpIHs8YnI+DQomZ3Q7ICvCoCDCoCDCoCDCoCDCoCDCoCDCoGZvciAo aSA9IDA7IGkgJmx0OyBucXVlcmllczsgaSsrKSB7PGJyPg0KJmd0OyArwqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAgwqAgwqAgwqByY29kZSA9IGFuc3dlcnNbaV1bM10gJmFtcDsgMTU7PGJyPg0KJmd0 OyArwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBpZiAoIWFsZW5zW2ldIHx8IHJjb2Rl ICE9IE5PRVJST1IpPGJyPg0KJmd0OyArwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg wqAgwqAgwqAgwqBnb3RvIG5leHRfbnM7PGJyPg0KJmd0OyArwqAgwqAgwqAgwqAgwqAgwqAgwqB9 PGJyPg0KJmd0OyArwqAgwqAgwqB9PGJyPg0KJmd0OyArPGJyPg0KJmd0O8KgIMKgIMKgIMKgcHRo cmVhZF9jbGVhbnVwX3BvcCgxKTs8YnI+DQomZ3Q7wqAgPGJyPg0KJmd0O8KgIMKgIMKgIMKgcmV0 dXJuIDA7PGJyPg0KJmd0OyAtLSA8YnI+DQomZ3Q7IDIuMzQuMTxicj4NCjwvYmxvY2txdW90ZT48 L2Rpdj4NCg== --00000000000044d54a05ebbd67e9--