From oliver at analyticspot.com Wed Sep 7 20:58:48 2016 Content-Type: multipart/mixed; boundary="===============0085737254904233968==" MIME-Version: 1.0 From: Oliver Dain To: undertow-dev at lists.jboss.org Subject: Re: [undertow-dev] Docs for templates Date: Thu, 08 Sep 2016 00:58:37 +0000 Message-ID: In-Reply-To: CACSC6EUgjmGnmpxET6dbsrG4PX4TU=7mNwSTndq32THU98sySQ@mail.gmail.com --===============0085737254904233968== Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Hey all, I added my own router handler that does everything I need it to do. It's pretty well documented and very well tested. I'd be willing to submit a pull request to have this added to Undertow if that'd be valuable to anyone. Here's a taste of the code (the core stuff is in PathTrie): package com.analyticspot.uservices.server.router; import com.analyticspot.httputils.HttpVerb; import com.analyticspot.httputils.ResponseCodes; import com.memoizrlabs.retrooptional.Optional; import io.undertow.server.HttpHandler; import io.undertow.server.HttpServerExchange; import io.undertow.util.AttachmentKey; import java.util.Map; import java.util.TreeMap; /** * An HttpHandler that routes requests to other handlers based on paths and path templates. It is thread safe to * search this class concurrently (match paths) but adding paths is not thread safe. Thus the expected use-case is * that all paths are set up before the handler is added as an Undertow listener. * *

The rules for path matching are: *

* *

We added our own router due to limitations in the Undertow PathTemplateHandler and RoutingHandler. See * http://lists.jboss.org/pipermail/undertow-dev/2016-September/001685.html for details. */ public class PathRoutingHandler implements HttpHandler { public static AttachmentKey PATH_MATCH_KEY =3D AttachmentKey.create(PathMatch.class); // Map from HTTP verb to the PathTrie for the handlers for that route. private final Map verbToPathTrie =3D new TreeMap<>(); // If present and none of the paths match this handler will be called. Optional fallbackHandler; public PathRoutingHandler() { fallbackHandler =3D Optional.empty(); } /** * Provides a fallback handler which will handle the request if nothing in the trie matches. */ public PathRoutingHandler(HttpHandler fallbackHandler) { this.fallbackHandler =3D Optional.of(fallbackHandler); } /** * Adds a handler for the given URL/verb combination. The path can be a template as per the class comment. */ public void addHandler(HttpVerb verb, String path, HttpHandler handler) { PathTrie trie =3D getTrie(verb); trie.addPath(path, handler); } /** * Like {@link #addHandler(HttpVerb, String, HttpHandler)}but add a prefix handler. */ public void addPrefixHandler(HttpVerb verb, String path, HttpHandler handler) { PathTrie trie =3D getTrie(verb); trie.addPrefixPath(path, handler); } private PathTrie getTrie(HttpVerb verb) { if (!verbToPathTrie.containsKey(verb)) { PathTrie trie =3D new PathTrie(); verbToPathTrie.put(verb, trie); return trie; } else { return verbToPathTrie.get(verb); } } @Override public void handleRequest(HttpServerExchange exchange) throws Exception { HttpVerb verb =3D HttpVerb.fromString(exchange.getRequestMethod().toString()); PathTrie trie =3D verbToPathTrie.get(verb); if (trie =3D=3D null) { handleNoMatch(exchange); } else { Optional optMatch =3D trie.findMatch(exchange.getRelativePath()); if (optMatch.isPresent()) { exchange.putAttachment(PATH_MATCH_KEY, optMatch.get()); optMatch.get().getHandler().handleRequest(exchange); } else { handleNoMatch(exchange); } } } private void handleNoMatch(HttpServerExchange exchange) throws Exception { if (fallbackHandler.isPresent()) { fallbackHandler.get().handleRequest(exchange); } else { exchange.setStatusCode(ResponseCodes.NOT_FOUND.getCode()); exchange.endExchange(); } } } -- Oliver On Wed, Sep 7, 2016 at 11:35 AM Oliver Dain wro= te: > Thanks Greg and Bill! > > On Wed, Sep 7, 2016 at 6:20 AM Bill O'Neil wrote: > >> I did something similar to Greg by delegating to a RoutingHandler which >> has a PathHandler fallback. >> >> https://gist.github.com/billoneil/08b1648a3b2a849e02c57e133bd6d45c >> >> This allows me to add prefix routes but still not flexible enough for all >> uses cases. The main drawback with this approach is the prefix handler >> doesn't route based on Verb but it has worked for all of my use cases so >> far. >> >> I would also like to know if there is a way the RoutingHandler can be >> extended to have wildcard functionality. >> >> On Wed, Sep 7, 2016 at 8:08 AM, Greg Hellings >> wrote: >> >>> Oliver, >>> >>> I found it very difficult to work with the PathTemplateHandler and its >>> set of matching operations seemed very minimal to me. I also found no >>> efficient way to mix-and-match between full Paths and PathTemplate >>> entries. So I created my own handler class that gave the ability to >>> match based on both HTTP Verb and various path components. >>> >>> >>> https://github.com/greg-hellings/gully/blob/master/src/main/java/com/th= ehellings/gully/Router.java >>> >>> https://github.com/greg-hellings/gully/blob/master/src/main/java/com/th= ehellings/gully/PlainRouter.java >>> >>> I haven't used it extensively, but in my own local testing it seems to >>> work exactly the way I wanted - it's still just an HttpHandler >>> underneath, so it can be placed anywhere in a handler chain. And it >>> operates on the result of getRelativePath, so you can nest them within >>> each other, or place them within other components in a handler chain >>> and the class should operate properly. >>> >>> The whole set of handler and its dependent classes should be available >>> as a Maven artifact if you want to play with it. If this sort of >>> functionality exists somewhere in core Undertow, I've been entirely >>> unable to decipher it and locate its functioning. >>> >>> --Greg >>> >>> On Tue, Sep 6, 2016 at 9:41 PM, Oliver Dain >>> wrote: >>> > Hey all, >>> > >>> > I haven't seen any documentation on the format of a template accepted >>> by a >>> > PathTemplateHandler. I know the basics: "/foo", "/foo/{userId}", etc. >>> but >>> > are wildcards allowed? Is there a way to specify a handler for >>> anything with >>> > a certain prefix? If two handlers would match how is the tie broken, >>> etc. >>> > >>> > Thanks, >>> > Oliver >>> > -- >>> > CTO, Analytic Spot >>> > 44 West Broadway #222 >>> > Eugene, OR 97401 >>> > analyticspot.com =E2=80=A2 425-296-6556 >>> > www.linkedin.com/in/oliverdain >>> > >>> > _______________________________________________ >>> > undertow-dev mailing list >>> > undertow-dev(a)lists.jboss.org >>> > https://lists.jboss.org/mailman/listinfo/undertow-dev >>> >>> _______________________________________________ >>> undertow-dev mailing list >>> undertow-dev(a)lists.jboss.org >>> https://lists.jboss.org/mailman/listinfo/undertow-dev >> >> >> -- > CTO, Analytic Spot > 44 West Broadway #222 > Eugene, OR 97401 > analyticspot.com =E2=80=A2 425-296-6556 > www.linkedin.com/in/oliverdain > -- = CTO, Analytic Spot 44 West Broadway #222 Eugene, OR 97401 analyticspot.com =E2=80=A2 425-296-6556 www.linkedin.com/in/oliverdain --===============0085737254904233968== Content-Type: text/html MIME-Version: 1.0 Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="attachment.html" PGRpdiBkaXI9Imx0ciI+SGV5IGFsbCw8ZGl2Pjxicj48L2Rpdj48ZGl2PkkgYWRkZWQgbXkgb3du IHJvdXRlciBoYW5kbGVyIHRoYXQgZG9lcyBldmVyeXRoaW5nIEkgbmVlZCBpdCB0byBkby4gSXQm IzM5O3MgcHJldHR5IHdlbGwgZG9jdW1lbnRlZCBhbmQgdmVyeSB3ZWxsIHRlc3RlZC4gSSYjMzk7 ZCBiZSB3aWxsaW5nIHRvIHN1Ym1pdCBhIHB1bGwgcmVxdWVzdCB0byBoYXZlIHRoaXMgYWRkZWQg dG8gVW5kZXJ0b3cgaWYgdGhhdCYjMzk7ZCBiZSB2YWx1YWJsZSB0byBhbnlvbmUuIEhlcmUmIzM5 O3MgYSB0YXN0ZSBvZiB0aGUgY29kZSAodGhlIGNvcmUgc3R1ZmYgaXMgaW4gUGF0aFRyaWUpOjwv ZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+PGRpdj5wYWNrYWdlIGNvbS5hbmFseXRpY3Nwb3QudXNl cnZpY2VzLnNlcnZlci5yb3V0ZXI7PC9kaXY+PGRpdj48YnI+PC9kaXY+PGRpdj5pbXBvcnQgY29t LmFuYWx5dGljc3BvdC5odHRwdXRpbHMuSHR0cFZlcmI7PC9kaXY+PGRpdj5pbXBvcnQgY29tLmFu YWx5dGljc3BvdC5odHRwdXRpbHMuUmVzcG9uc2VDb2Rlczs8L2Rpdj48ZGl2PmltcG9ydCBjb20u bWVtb2l6cmxhYnMucmV0cm9vcHRpb25hbC5PcHRpb25hbDs8L2Rpdj48ZGl2PmltcG9ydCBpby51 bmRlcnRvdy5zZXJ2ZXIuSHR0cEhhbmRsZXI7PC9kaXY+PGRpdj5pbXBvcnQgaW8udW5kZXJ0b3cu c2VydmVyLkh0dHBTZXJ2ZXJFeGNoYW5nZTs8L2Rpdj48ZGl2PmltcG9ydCBpby51bmRlcnRvdy51 dGlsLkF0dGFjaG1lbnRLZXk7PC9kaXY+PGRpdj48YnI+PC9kaXY+PGRpdj5pbXBvcnQgamF2YS51 dGlsLk1hcDs8L2Rpdj48ZGl2PmltcG9ydCBqYXZhLnV0aWwuVHJlZU1hcDs8L2Rpdj48ZGl2Pjxi cj48L2Rpdj48ZGl2Pi8qKjwvZGl2PjxkaXY+wqAqIEFuIEh0dHBIYW5kbGVyIHRoYXQgcm91dGVz IHJlcXVlc3RzIHRvIG90aGVyIGhhbmRsZXJzIGJhc2VkIG9uIHBhdGhzIGFuZCBwYXRoIHRlbXBs YXRlcy4gSXQgaXMgdGhyZWFkIHNhZmUgdG88L2Rpdj48ZGl2PsKgKiBzZWFyY2ggdGhpcyBjbGFz cyBjb25jdXJyZW50bHkgKG1hdGNoIHBhdGhzKSBidXQgYWRkaW5nIHBhdGhzIGlzIG5vdCB0aHJl YWQgc2FmZS4gVGh1cyB0aGUgZXhwZWN0ZWQgdXNlLWNhc2UgaXM8L2Rpdj48ZGl2PsKgKiB0aGF0 IGFsbCBwYXRocyBhcmUgc2V0IHVwIGJlZm9yZSB0aGUgaGFuZGxlciBpcyBhZGRlZCBhcyBhbiBV bmRlcnRvdyBsaXN0ZW5lci48L2Rpdj48ZGl2PsKgKjwvZGl2PjxkaXY+wqAqICZsdDtwJmd0O1Ro ZSBydWxlcyBmb3IgcGF0aCBtYXRjaGluZyBhcmU6PC9kaXY+PGRpdj7CoCogJmx0O3VsJmd0Ozwv ZGl2PjxkaXY+wqAqIMKgICZsdDtsaSZndDtBbGwgcGF0aHMgbXVzdCBiZWdpbiB3aXRoIGEgJnF1 b3Q7LyZxdW90OyZsdDsvbGkmZ3Q7PC9kaXY+PGRpdj7CoCogwqAgJmx0O2xpJmd0O1dpbGRjYXJk IG1hdGNoZXMgYXJlIGFsbG93ZWQgYnkgYWRkaW5nICZxdW90O3tYfSZxdW90OyB0byB0aGUgcGF0 aC4gVGhlbiB7QGNvZGUgWH0gYW5kIHdoYXQgbWF0Y2hlZCBpdCBhcmUgYXR0YWNoZWQ8L2Rpdj48 ZGl2PsKgKiDCoCB0byB0aGUgcmVxdWVzdCBpbiBhIHtAY29kZSBNYXB9IGZyb20ge0Bjb2RlIFh9 IHRvIHRoZSB2YWx1ZSB0aGF0IG1hdGNoZWQuIEZvciBleGFtcGxlLCBpZiB0aGUgYWRkZWQgcGF0 aCB3YXM8L2Rpdj48ZGl2PsKgKiDCoCAmcXVvdDsvZm9vL3tuYW1lfS9zdHVmZi97YWdlfSZxdW90 OyBhbmQgdGhlIG9ic2VydmVkIHBhdGggd2FzICZxdW90Oy9mb28vYmFyL3N0dWZmLzIyJnF1b3Q7 IHRoZW4gdGhlIGF0dGFjaG1lbnQgd291bGQgaGF2ZSBhIG1hcDwvZGl2PjxkaXY+wqAqIMKgIGxp a2UgJnF1b3Q7e25hbWU6IGJhciwgYWdlOiAyMn0uJmx0Oy9saSZndDs8L2Rpdj48ZGl2PsKgKiDC oCAmbHQ7bGkmZ3Q7UHJlZml4IHBhdGhzIGFyZSBhbGxvd2VkLiBTdWNoIHBhdGhzIHdpbGwgbWF0 Y2ggYW55dGhpbmcgdGhhdCBiZWdpbnMgd2l0aCB0aGUgcHJvdmlkZWQgcHJlZml4LiZsdDsvbGkm Z3Q7PC9kaXY+PGRpdj7CoCogwqAgJmx0O2xpJmd0O0V4YWN0IG1hdGNoZXMgYW5kL29yIGxvbmdl ciBtYXRjaGVzIHRha2UgcHJlY2VkZW5jZSBvdmVyIGJvdGggcHJlZml4IGFuZCB3aWxkY2FyZCBt YXRjaGVzLiBUaHVzLCBnaXZlbiB0aGU8L2Rpdj48ZGl2PsKgKiDCoCB3aWxkY2FyZCBwYXRoICZx dW90Oy9mb28ve25hbWV9JnF1b3Q7LCB0aGUgcHJlZml4IHBhdGggJnF1b3Q7L2Zvby9iYXomcXVv dDssIGFuZCB0aGUgZXhhY3QgcGF0aCAmcXVvdDsvZm9vL2JhciZxdW90Oywgd2Ugd291bGQgZXhw ZWN0IHRoZTwvZGl2PjxkaXY+wqAqIMKgIGZvbGxvd2luZyBtYXRjaGVzOjwvZGl2PjxkaXY+wqAq IMKgICZsdDt0YWJsZSZndDs8L2Rpdj48ZGl2PsKgKiDCoCDCoCAmbHQ7dHImZ3Q7Jmx0O3RkJmd0 O09ic2VydmVkIFBhdGgmbHQ7L3RkJmd0OyZsdDt0ZCZndDtNYXRjaGVkIFBhdGgmbHQ7L3RkJmd0 OyZsdDsvdHImZ3Q7PC9kaXY+PGRpdj7CoCogwqAgwqAgJmx0O3RyJmd0OyZsdDt0ZCZndDsvZm9v L2JhciZsdDsvdGQmZ3Q7Jmx0O3RkJmd0Oy9mb28vYmFyJmx0Oy90ZCZndDsmbHQ7L3RyJmd0Ozwv ZGl2PjxkaXY+wqAqIMKgIMKgICZsdDt0ciZndDsmbHQ7dGQmZ3Q7L2Zvby9iYXombHQ7L3RkJmd0 OyZsdDt0ZCZndDsvZm9vL2JheiZsdDsvdGQmZ3Q7Jmx0Oy90ciZndDs8L2Rpdj48ZGl2PsKgKiDC oCDCoCAmbHQ7dHImZ3Q7Jmx0O3RkJmd0Oy9mb28vYmF6L2J1bXAmbHQ7L3RkJmd0OyZsdDt0ZCZn dDsvZm9vL2JheiZsdDsvdGQmZ3Q7Jmx0Oy90ciZndDs8L2Rpdj48ZGl2PsKgKiDCoCDCoCAmbHQ7 dHImZ3Q7Jmx0O3RkJmd0Oy9mb28vZ291cmR5Jmx0Oy90ZCZndDsmbHQ7dGQmZ3Q7L2Zvby97bmFt ZX0mbHQ7L3RkJmd0OyZsdDsvdHImZ3Q7PC9kaXY+PGRpdj7CoCogwqAgJmx0Oy90YWJsZSZndDs8 L2Rpdj48ZGl2PsKgKiDCoCAmbHQ7L2xpJmd0OzwvZGl2PjxkaXY+wqAqIMKgICZsdDtsaSZndDtU aGlzIGlzIG5vdCBhICZxdW90O2JhY2t0cmFja2luZyZxdW90OyBtYXRjaGVyLiBUaHVzLCBnaXZl biBhIHByZWZpeCBwYXRoIG9mICZxdW90Oy9mb28vYmFyJnF1b3Q7IGFuZCBhbiBleGFjdCBwYXRo PC9kaXY+PGRpdj7CoCogwqAgJnF1b3Q7L2Zvby9iYXIvYmF6JnF1b3Q7LCB0aGUgb2JzZXJ2ZWQg cGF0aCAmcXVvdDsvZm9vL2Jhci9iYXovYml6emxlJnF1b3Q7IHdvdWxkIGhhdmUgJmx0O2ImZ3Q7 bm8gbWF0Y2gmbHQ7L2ImZ3Q7IGJlY2F1c2UgJnF1b3Q7L2Zvby9iYXIvYmF6JnF1b3Q7PC9kaXY+ PGRpdj7CoCogwqAgZG9lc24mIzM5O3QgbWF0Y2ggYW5kIHdlIGRvIG5vdCBiYWNrdHJhY2sgdG8g dGhlIHNob3J0ZXIgJnF1b3Q7L2Zvby9iYXImcXVvdDsgcHJlZml4IHRvIHNlZSBpZiBpdCBtYXRj aGVzLiZsdDsvbGkmZ3Q7PC9kaXY+PGRpdj7CoCogwqAgJmx0O2xpJmd0O0lmIGJvdGggYSBwcmVm aXggYW5kIGEgd2lsZGNhcmQgbWF0Y2gsIHRoZSB3aWxkY2FyZCB0YWtlcyBwcmVjZW5kZW5jZS4g VGh1cyBnaXZlbiBwcmVmaXggcGF0aCAmcXVvdDsvZm9vJnF1b3Q7IGFuZDwvZGl2PjxkaXY+wqAq IMKgIHdpbGRjYXJkIHBhdGggJnF1b3Q7L2Zvby97bmFtZX0mcXVvdDssIHRoZSBtYXRjaCBmb3Ig b2Jlc2VydmVkIHBhdGggJnF1b3Q7L2Zvby9iYXImcXVvdDsgd291bGQgYmUgdGhlIHdpbGRjYXJk IHBhdGguJmx0Oy9saSZndDs8L2Rpdj48ZGl2PsKgKiAmbHQ7L3VsJmd0OzwvZGl2PjxkaXY+wqAq PC9kaXY+PGRpdj7CoCogJmx0O3AmZ3Q7V2UgYWRkZWQgb3VyIG93biByb3V0ZXIgZHVlIHRvIGxp bWl0YXRpb25zIGluIHRoZSBVbmRlcnRvdyBQYXRoVGVtcGxhdGVIYW5kbGVyIGFuZCBSb3V0aW5n SGFuZGxlci4gU2VlPC9kaXY+PGRpdj7CoCogPGEgaHJlZj0iaHR0cDovL2xpc3RzLmpib3NzLm9y Zy9waXBlcm1haWwvdW5kZXJ0b3ctZGV2LzIwMTYtU2VwdGVtYmVyLzAwMTY4NS5odG1sIj5odHRw Oi8vbGlzdHMuamJvc3Mub3JnL3BpcGVybWFpbC91bmRlcnRvdy1kZXYvMjAxNi1TZXB0ZW1iZXIv MDAxNjg1Lmh0bWw8L2E+IGZvciBkZXRhaWxzLjwvZGl2PjxkaXY+wqAqLzwvZGl2PjxkaXY+cHVi bGljIGNsYXNzIFBhdGhSb3V0aW5nSGFuZGxlciBpbXBsZW1lbnRzIEh0dHBIYW5kbGVyIHs8L2Rp dj48ZGl2PsKgIHB1YmxpYyBzdGF0aWMgQXR0YWNobWVudEtleSZsdDtQYXRoTWF0Y2gmZ3Q7IFBB VEhfTUFUQ0hfS0VZID0gQXR0YWNobWVudEtleS5jcmVhdGUoUGF0aE1hdGNoLmNsYXNzKTs8L2Rp dj48ZGl2Pjxicj48L2Rpdj48ZGl2PsKgIC8vIE1hcCBmcm9tIEhUVFAgdmVyYiB0byB0aGUgUGF0 aFRyaWUgZm9yIHRoZSBoYW5kbGVycyBmb3IgdGhhdCByb3V0ZS48L2Rpdj48ZGl2PsKgIHByaXZh dGUgZmluYWwgTWFwJmx0O0h0dHBWZXJiLCBQYXRoVHJpZSZndDsgdmVyYlRvUGF0aFRyaWUgPSBu ZXcgVHJlZU1hcCZsdDsmZ3Q7KCk7PC9kaXY+PGRpdj7CoCAvLyBJZiBwcmVzZW50IGFuZCBub25l IG9mIHRoZSBwYXRocyBtYXRjaCB0aGlzIGhhbmRsZXIgd2lsbCBiZSBjYWxsZWQuPC9kaXY+PGRp dj7CoCBPcHRpb25hbCZsdDtIdHRwSGFuZGxlciZndDsgZmFsbGJhY2tIYW5kbGVyOzwvZGl2Pjxk aXY+PGJyPjwvZGl2PjxkaXY+wqAgcHVibGljIFBhdGhSb3V0aW5nSGFuZGxlcigpIHs8L2Rpdj48 ZGl2PsKgIMKgIGZhbGxiYWNrSGFuZGxlciA9IE9wdGlvbmFsLmVtcHR5KCk7PC9kaXY+PGRpdj7C oCB9PC9kaXY+PGRpdj48YnI+PC9kaXY+PGRpdj7CoCAvKio8L2Rpdj48ZGl2PsKgIMKgKiBQcm92 aWRlcyBhIGZhbGxiYWNrIGhhbmRsZXIgd2hpY2ggd2lsbCBoYW5kbGUgdGhlIHJlcXVlc3QgaWYg bm90aGluZyBpbiB0aGUgdHJpZSBtYXRjaGVzLjwvZGl2PjxkaXY+wqAgwqAqLzwvZGl2PjxkaXY+ wqAgcHVibGljIFBhdGhSb3V0aW5nSGFuZGxlcihIdHRwSGFuZGxlciBmYWxsYmFja0hhbmRsZXIp IHs8L2Rpdj48ZGl2PsKgIMKgIHRoaXMuZmFsbGJhY2tIYW5kbGVyID0gT3B0aW9uYWwub2YoZmFs bGJhY2tIYW5kbGVyKTs8L2Rpdj48ZGl2PsKgIH08L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl2PsKg IC8qKjwvZGl2PjxkaXY+wqAgwqAqIEFkZHMgYSBoYW5kbGVyIGZvciB0aGUgZ2l2ZW4gVVJML3Zl cmIgY29tYmluYXRpb24uIFRoZSBwYXRoIGNhbiBiZSBhIHRlbXBsYXRlIGFzIHBlciB0aGUgY2xh c3MgY29tbWVudC48L2Rpdj48ZGl2PsKgIMKgKi88L2Rpdj48ZGl2PsKgIHB1YmxpYyB2b2lkIGFk ZEhhbmRsZXIoSHR0cFZlcmIgdmVyYiwgU3RyaW5nIHBhdGgsIEh0dHBIYW5kbGVyIGhhbmRsZXIp IHs8L2Rpdj48ZGl2PsKgIMKgIFBhdGhUcmllIHRyaWUgPSBnZXRUcmllKHZlcmIpOzwvZGl2Pjxk aXY+wqAgwqAgdHJpZS5hZGRQYXRoKHBhdGgsIGhhbmRsZXIpOzwvZGl2PjxkaXY+wqAgfTwvZGl2 PjxkaXY+PGJyPjwvZGl2PjxkaXY+wqAgLyoqPC9kaXY+PGRpdj7CoCDCoCogTGlrZSB7QGxpbmsg I2FkZEhhbmRsZXIoSHR0cFZlcmIsIFN0cmluZywgSHR0cEhhbmRsZXIpfWJ1dCBhZGQgYSBwcmVm aXggaGFuZGxlci48L2Rpdj48ZGl2PsKgIMKgKi88L2Rpdj48ZGl2PsKgIHB1YmxpYyB2b2lkIGFk ZFByZWZpeEhhbmRsZXIoSHR0cFZlcmIgdmVyYiwgU3RyaW5nIHBhdGgsIEh0dHBIYW5kbGVyIGhh bmRsZXIpIHs8L2Rpdj48ZGl2PsKgIMKgIFBhdGhUcmllIHRyaWUgPSBnZXRUcmllKHZlcmIpOzwv ZGl2PjxkaXY+wqAgwqAgdHJpZS5hZGRQcmVmaXhQYXRoKHBhdGgsIGhhbmRsZXIpOzwvZGl2Pjxk aXY+wqAgfTwvZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+wqAgcHJpdmF0ZSBQYXRoVHJpZSBnZXRU cmllKEh0dHBWZXJiIHZlcmIpIHs8L2Rpdj48ZGl2PsKgIMKgIGlmICghdmVyYlRvUGF0aFRyaWUu Y29udGFpbnNLZXkodmVyYikpIHs8L2Rpdj48ZGl2PsKgIMKgIMKgIFBhdGhUcmllIHRyaWUgPSBu ZXcgUGF0aFRyaWUoKTs8L2Rpdj48ZGl2PsKgIMKgIMKgIHZlcmJUb1BhdGhUcmllLnB1dCh2ZXJi LCB0cmllKTs8L2Rpdj48ZGl2PsKgIMKgIMKgIHJldHVybiB0cmllOzwvZGl2PjxkaXY+wqAgwqAg fSBlbHNlIHs8L2Rpdj48ZGl2PsKgIMKgIMKgIHJldHVybiB2ZXJiVG9QYXRoVHJpZS5nZXQodmVy Yik7PC9kaXY+PGRpdj7CoCDCoCB9PC9kaXY+PGRpdj7CoCB9PC9kaXY+PGRpdj48YnI+PC9kaXY+ PGRpdj7CoCBAT3ZlcnJpZGU8L2Rpdj48ZGl2PsKgIHB1YmxpYyB2b2lkIGhhbmRsZVJlcXVlc3Qo SHR0cFNlcnZlckV4Y2hhbmdlIGV4Y2hhbmdlKSB0aHJvd3MgRXhjZXB0aW9uIHs8L2Rpdj48ZGl2 PsKgIMKgIEh0dHBWZXJiIHZlcmIgPSBIdHRwVmVyYi5mcm9tU3RyaW5nKGV4Y2hhbmdlLmdldFJl cXVlc3RNZXRob2QoKS50b1N0cmluZygpKTs8L2Rpdj48ZGl2PsKgIMKgIFBhdGhUcmllIHRyaWUg PSB2ZXJiVG9QYXRoVHJpZS5nZXQodmVyYik7PC9kaXY+PGRpdj7CoCDCoCBpZiAodHJpZSA9PSBu dWxsKSB7PC9kaXY+PGRpdj7CoCDCoCDCoCBoYW5kbGVOb01hdGNoKGV4Y2hhbmdlKTs8L2Rpdj48 ZGl2PsKgIMKgIH0gZWxzZSB7PC9kaXY+PGRpdj7CoCDCoCDCoCBPcHRpb25hbCZsdDtQYXRoTWF0 Y2gmZ3Q7IG9wdE1hdGNoID0gdHJpZS5maW5kTWF0Y2goZXhjaGFuZ2UuZ2V0UmVsYXRpdmVQYXRo KCkpOzwvZGl2PjxkaXY+wqAgwqAgwqAgaWYgKG9wdE1hdGNoLmlzUHJlc2VudCgpKSB7PC9kaXY+ PGRpdj7CoCDCoCDCoCDCoCBleGNoYW5nZS5wdXRBdHRhY2htZW50KFBBVEhfTUFUQ0hfS0VZLCBv cHRNYXRjaC5nZXQoKSk7PC9kaXY+PGRpdj7CoCDCoCDCoCDCoCBvcHRNYXRjaC5nZXQoKS5nZXRI YW5kbGVyKCkuaGFuZGxlUmVxdWVzdChleGNoYW5nZSk7PC9kaXY+PGRpdj7CoCDCoCDCoCB9IGVs c2UgezwvZGl2PjxkaXY+wqAgwqAgwqAgwqAgaGFuZGxlTm9NYXRjaChleGNoYW5nZSk7PC9kaXY+ PGRpdj7CoCDCoCDCoCB9PC9kaXY+PGRpdj7CoCDCoCB9PC9kaXY+PGRpdj7CoCB9PC9kaXY+PGRp dj48YnI+PC9kaXY+PGRpdj7CoCBwcml2YXRlIHZvaWQgaGFuZGxlTm9NYXRjaChIdHRwU2VydmVy RXhjaGFuZ2UgZXhjaGFuZ2UpIHRocm93cyBFeGNlcHRpb24gezwvZGl2PjxkaXY+wqAgwqAgaWYg KGZhbGxiYWNrSGFuZGxlci5pc1ByZXNlbnQoKSkgezwvZGl2PjxkaXY+wqAgwqAgwqAgZmFsbGJh Y2tIYW5kbGVyLmdldCgpLmhhbmRsZVJlcXVlc3QoZXhjaGFuZ2UpOzwvZGl2PjxkaXY+wqAgwqAg fSBlbHNlIHs8L2Rpdj48ZGl2PsKgIMKgIMKgIGV4Y2hhbmdlLnNldFN0YXR1c0NvZGUoUmVzcG9u c2VDb2Rlcy5OT1RfRk9VTkQuZ2V0Q29kZSgpKTs8L2Rpdj48ZGl2PsKgIMKgIMKgIGV4Y2hhbmdl LmVuZEV4Y2hhbmdlKCk7PC9kaXY+PGRpdj7CoCDCoCB9PC9kaXY+PGRpdj7CoCB9PC9kaXY+PGRp dj59PC9kaXY+PC9kaXY+PGRpdj48YnI+PC9kaXY+PGRpdj4tLSBPbGl2ZXI8L2Rpdj48L2Rpdj48 YnI+PGRpdiBjbGFzcz0iZ21haWxfcXVvdGUiPjxkaXYgZGlyPSJsdHIiPk9uIFdlZCwgU2VwIDcs IDIwMTYgYXQgMTE6MzUgQU0gT2xpdmVyIERhaW4gJmx0OzxhIGhyZWY9Im1haWx0bzpvbGl2ZXJA YW5hbHl0aWNzcG90LmNvbSI+b2xpdmVyQGFuYWx5dGljc3BvdC5jb208L2E+Jmd0OyB3cm90ZTo8 YnI+PC9kaXY+PGJsb2NrcXVvdGUgY2xhc3M9ImdtYWlsX3F1b3RlIiBzdHlsZT0ibWFyZ2luOjAg MCAwIC44ZXg7Ym9yZGVyLWxlZnQ6MXB4ICNjY2Mgc29saWQ7cGFkZGluZy1sZWZ0OjFleCI+PGRp diBkaXI9Imx0ciI+VGhhbmtzIEdyZWcgYW5kIEJpbGwhPC9kaXY+PGJyPjxkaXYgY2xhc3M9Imdt YWlsX3F1b3RlIj48ZGl2IGRpcj0ibHRyIj5PbiBXZWQsIFNlcCA3LCAyMDE2IGF0IDY6MjAgQU0g QmlsbCBPJiMzOTtOZWlsICZsdDs8YSBocmVmPSJtYWlsdG86YmlsbEBkYXJ0YWxsZXkuY29tIiB0 YXJnZXQ9Il9ibGFuayI+YmlsbEBkYXJ0YWxsZXkuY29tPC9hPiZndDsgd3JvdGU6PGJyPjwvZGl2 PjxibG9ja3F1b3RlIGNsYXNzPSJnbWFpbF9xdW90ZSIgc3R5bGU9Im1hcmdpbjowIDAgMCAuOGV4 O2JvcmRlci1sZWZ0OjFweCAjY2NjIHNvbGlkO3BhZGRpbmctbGVmdDoxZXgiPjxkaXYgZGlyPSJs dHIiPkkgZGlkIHNvbWV0aGluZyBzaW1pbGFyIHRvIEdyZWcgYnkgZGVsZWdhdGluZyB0byBhIFJv dXRpbmdIYW5kbGVyIHdoaWNoIGhhcyBhIFBhdGhIYW5kbGVyIGZhbGxiYWNrLjxkaXY+PGJyPjwv ZGl2PjxkaXY+PGEgaHJlZj0iaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vYmlsbG9uZWlsLzA4YjE2 NDhhM2IyYTg0OWUwMmM1N2UxMzNiZDZkNDVjIiB0YXJnZXQ9Il9ibGFuayI+aHR0cHM6Ly9naXN0 LmdpdGh1Yi5jb20vYmlsbG9uZWlsLzA4YjE2NDhhM2IyYTg0OWUwMmM1N2UxMzNiZDZkNDVjPC9h Pjxicj48L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl2PlRoaXMgYWxsb3dzIG1lIHRvIGFkZCBwcmVm aXggcm91dGVzIGJ1dCBzdGlsbCBub3QgZmxleGlibGUgZW5vdWdoIGZvciBhbGwgdXNlcyBjYXNl cy4gVGhlIG1haW4gZHJhd2JhY2sgd2l0aCB0aGlzIGFwcHJvYWNoIGlzIHRoZSBwcmVmaXggaGFu ZGxlciBkb2VzbiYjMzk7dCByb3V0ZSBiYXNlZCBvbiBWZXJiIGJ1dCBpdCBoYXMgd29ya2VkIGZv ciBhbGwgb2YgbXkgdXNlIGNhc2VzIHNvIGZhci48L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl2Pkkg d291bGQgYWxzbyBsaWtlIHRvIGtub3cgaWYgdGhlcmUgaXMgYSB3YXkgdGhlIFJvdXRpbmdIYW5k bGVyIGNhbiBiZSBleHRlbmRlZCB0byBoYXZlIHdpbGRjYXJkIGZ1bmN0aW9uYWxpdHkuPC9kaXY+ PC9kaXY+PGRpdiBjbGFzcz0iZ21haWxfZXh0cmEiPjxicj48ZGl2IGNsYXNzPSJnbWFpbF9xdW90 ZSI+T24gV2VkLCBTZXAgNywgMjAxNiBhdCA4OjA4IEFNLCBHcmVnIEhlbGxpbmdzIDxzcGFuIGRp cj0ibHRyIj4mbHQ7PGEgaHJlZj0ibWFpbHRvOmdyZWcuaGVsbGluZ3NAZ21haWwuY29tIiB0YXJn ZXQ9Il9ibGFuayI+Z3JlZy5oZWxsaW5nc0BnbWFpbC5jb208L2E+Jmd0Ozwvc3Bhbj4gd3JvdGU6 PGJyPjxibG9ja3F1b3RlIGNsYXNzPSJnbWFpbF9xdW90ZSIgc3R5bGU9Im1hcmdpbjowIDAgMCAu OGV4O2JvcmRlci1sZWZ0OjFweCAjY2NjIHNvbGlkO3BhZGRpbmctbGVmdDoxZXgiPk9saXZlciw8 YnI+Cjxicj4KSSBmb3VuZCBpdCB2ZXJ5IGRpZmZpY3VsdCB0byB3b3JrIHdpdGggdGhlIFBhdGhU ZW1wbGF0ZUhhbmRsZXIgYW5kIGl0czxicj4Kc2V0IG9mIG1hdGNoaW5nIG9wZXJhdGlvbnMgc2Vl bWVkIHZlcnkgbWluaW1hbCB0byBtZS4gSSBhbHNvIGZvdW5kIG5vPGJyPgplZmZpY2llbnQgd2F5 IHRvIG1peC1hbmQtbWF0Y2ggYmV0d2VlbiBmdWxsIFBhdGhzIGFuZCBQYXRoVGVtcGxhdGU8YnI+ CmVudHJpZXMuIFNvIEkgY3JlYXRlZCBteSBvd24gaGFuZGxlciBjbGFzcyB0aGF0IGdhdmUgdGhl IGFiaWxpdHkgdG88YnI+Cm1hdGNoIGJhc2VkIG9uIGJvdGggSFRUUCBWZXJiIGFuZCB2YXJpb3Vz IHBhdGggY29tcG9uZW50cy48YnI+Cjxicj4KPGEgaHJlZj0iaHR0cHM6Ly9naXRodWIuY29tL2dy ZWctaGVsbGluZ3MvZ3VsbHkvYmxvYi9tYXN0ZXIvc3JjL21haW4vamF2YS9jb20vdGhlaGVsbGlu Z3MvZ3VsbHkvUm91dGVyLmphdmEiIHJlbD0ibm9yZWZlcnJlciIgdGFyZ2V0PSJfYmxhbmsiPmh0 dHBzOi8vZ2l0aHViLmNvbS9ncmVnLWhlbGxpbmdzL2d1bGx5L2Jsb2IvbWFzdGVyL3NyYy9tYWlu L2phdmEvY29tL3RoZWhlbGxpbmdzL2d1bGx5L1JvdXRlci5qYXZhPC9hPjxicj4KPGEgaHJlZj0i aHR0cHM6Ly9naXRodWIuY29tL2dyZWctaGVsbGluZ3MvZ3VsbHkvYmxvYi9tYXN0ZXIvc3JjL21h aW4vamF2YS9jb20vdGhlaGVsbGluZ3MvZ3VsbHkvUGxhaW5Sb3V0ZXIuamF2YSIgcmVsPSJub3Jl ZmVycmVyIiB0YXJnZXQ9Il9ibGFuayI+aHR0cHM6Ly9naXRodWIuY29tL2dyZWctaGVsbGluZ3Mv Z3VsbHkvYmxvYi9tYXN0ZXIvc3JjL21haW4vamF2YS9jb20vdGhlaGVsbGluZ3MvZ3VsbHkvUGxh aW5Sb3V0ZXIuamF2YTwvYT48YnI+Cjxicj4KSSBoYXZlbiYjMzk7dCB1c2VkIGl0IGV4dGVuc2l2 ZWx5LCBidXQgaW4gbXkgb3duIGxvY2FsIHRlc3RpbmcgaXQgc2VlbXMgdG88YnI+CndvcmsgZXhh Y3RseSB0aGUgd2F5IEkgd2FudGVkIC0gaXQmIzM5O3Mgc3RpbGwganVzdCBhbiBIdHRwSGFuZGxl cjxicj4KdW5kZXJuZWF0aCwgc28gaXQgY2FuIGJlIHBsYWNlZCBhbnl3aGVyZSBpbiBhIGhhbmRs ZXIgY2hhaW4uIEFuZCBpdDxicj4Kb3BlcmF0ZXMgb24gdGhlIHJlc3VsdCBvZiBnZXRSZWxhdGl2 ZVBhdGgsIHNvIHlvdSBjYW4gbmVzdCB0aGVtIHdpdGhpbjxicj4KZWFjaCBvdGhlciwgb3IgcGxh Y2UgdGhlbSB3aXRoaW4gb3RoZXIgY29tcG9uZW50cyBpbiBhIGhhbmRsZXIgY2hhaW48YnI+CmFu ZCB0aGUgY2xhc3Mgc2hvdWxkIG9wZXJhdGUgcHJvcGVybHkuPGJyPgo8YnI+ClRoZSB3aG9sZSBz ZXQgb2YgaGFuZGxlciBhbmQgaXRzIGRlcGVuZGVudCBjbGFzc2VzIHNob3VsZCBiZSBhdmFpbGFi bGU8YnI+CmFzIGEgTWF2ZW4gYXJ0aWZhY3QgaWYgeW91IHdhbnQgdG8gcGxheSB3aXRoIGl0LiBJ ZiB0aGlzIHNvcnQgb2Y8YnI+CmZ1bmN0aW9uYWxpdHkgZXhpc3RzIHNvbWV3aGVyZSBpbiBjb3Jl IFVuZGVydG93LCBJJiMzOTt2ZSBiZWVuIGVudGlyZWx5PGJyPgp1bmFibGUgdG8gZGVjaXBoZXIg aXQgYW5kIGxvY2F0ZSBpdHMgZnVuY3Rpb25pbmcuPGJyPgo8YnI+Ci0tR3JlZzxicj4KPGRpdj48 ZGl2Pjxicj4KT24gVHVlLCBTZXAgNiwgMjAxNiBhdCA5OjQxIFBNLCBPbGl2ZXIgRGFpbiAmbHQ7 PGEgaHJlZj0ibWFpbHRvOm9saXZlckBhbmFseXRpY3Nwb3QuY29tIiB0YXJnZXQ9Il9ibGFuayI+ b2xpdmVyQGFuYWx5dGljc3BvdC5jb208L2E+Jmd0OyB3cm90ZTo8YnI+CiZndDsgSGV5IGFsbCw8 YnI+CiZndDs8YnI+CiZndDsgSSBoYXZlbiYjMzk7dCBzZWVuIGFueSBkb2N1bWVudGF0aW9uIG9u IHRoZSBmb3JtYXQgb2YgYSB0ZW1wbGF0ZSBhY2NlcHRlZCBieSBhPGJyPgomZ3Q7IFBhdGhUZW1w bGF0ZUhhbmRsZXIuIEkga25vdyB0aGUgYmFzaWNzOiAmcXVvdDsvZm9vJnF1b3Q7LCAmcXVvdDsv Zm9vL3t1c2VySWR9JnF1b3Q7LCBldGMuIGJ1dDxicj4KJmd0OyBhcmUgd2lsZGNhcmRzIGFsbG93 ZWQ/IElzIHRoZXJlIGEgd2F5IHRvIHNwZWNpZnkgYSBoYW5kbGVyIGZvciBhbnl0aGluZyB3aXRo PGJyPgomZ3Q7IGEgY2VydGFpbiBwcmVmaXg/IElmIHR3byBoYW5kbGVycyB3b3VsZCBtYXRjaCBo b3cgaXMgdGhlIHRpZSBicm9rZW4sIGV0Yy48YnI+CiZndDs8YnI+CiZndDsgVGhhbmtzLDxicj4K Jmd0OyBPbGl2ZXI8YnI+CiZndDsgLS08YnI+CiZndDsgQ1RPLCBBbmFseXRpYyBTcG90PGJyPgom Z3Q7IDQ0IFdlc3QgQnJvYWR3YXkgIzIyMjxicj4KJmd0OyBFdWdlbmUsIE9SIDk3NDAxPGJyPgom Z3Q7IDxhIGhyZWY9Imh0dHA6Ly9hbmFseXRpY3Nwb3QuY29tIiByZWw9Im5vcmVmZXJyZXIiIHRh cmdldD0iX2JsYW5rIj5hbmFseXRpY3Nwb3QuY29tPC9hPiDigKIgPGEgaHJlZj0idGVsOjQyNS0y OTYtNjU1NiIgdmFsdWU9IisxNDI1Mjk2NjU1NiIgdGFyZ2V0PSJfYmxhbmsiPjQyNS0yOTYtNjU1 NjwvYT48YnI+CiZndDsgPGEgaHJlZj0iaHR0cDovL3d3dy5saW5rZWRpbi5jb20vaW4vb2xpdmVy ZGFpbiIgcmVsPSJub3JlZmVycmVyIiB0YXJnZXQ9Il9ibGFuayI+d3d3LmxpbmtlZGluLmNvbS9p bi9vbGl2ZXJkYWluPC9hPjxicj4KJmd0Ozxicj4KPC9kaXY+PC9kaXY+Jmd0OyBfX19fX19fX19f X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXzxicj4KJmd0OyB1bmRlcnRvdy1k ZXYgbWFpbGluZyBsaXN0PGJyPgomZ3Q7IDxhIGhyZWY9Im1haWx0bzp1bmRlcnRvdy1kZXZAbGlz dHMuamJvc3Mub3JnIiB0YXJnZXQ9Il9ibGFuayI+dW5kZXJ0b3ctZGV2QGxpc3RzLmpib3NzLm9y ZzwvYT48YnI+CiZndDsgPGEgaHJlZj0iaHR0cHM6Ly9saXN0cy5qYm9zcy5vcmcvbWFpbG1hbi9s aXN0aW5mby91bmRlcnRvdy1kZXYiIHJlbD0ibm9yZWZlcnJlciIgdGFyZ2V0PSJfYmxhbmsiPmh0 dHBzOi8vbGlzdHMuamJvc3Mub3JnL21haWxtYW4vbGlzdGluZm8vdW5kZXJ0b3ctZGV2PC9hPjxi cj4KPGJyPgpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXzxi cj4KdW5kZXJ0b3ctZGV2IG1haWxpbmcgbGlzdDxicj4KPGEgaHJlZj0ibWFpbHRvOnVuZGVydG93 LWRldkBsaXN0cy5qYm9zcy5vcmciIHRhcmdldD0iX2JsYW5rIj51bmRlcnRvdy1kZXZAbGlzdHMu amJvc3Mub3JnPC9hPjxicj4KPGEgaHJlZj0iaHR0cHM6Ly9saXN0cy5qYm9zcy5vcmcvbWFpbG1h bi9saXN0aW5mby91bmRlcnRvdy1kZXYiIHJlbD0ibm9yZWZlcnJlciIgdGFyZ2V0PSJfYmxhbmsi Pmh0dHBzOi8vbGlzdHMuamJvc3Mub3JnL21haWxtYW4vbGlzdGluZm8vdW5kZXJ0b3ctZGV2PC9h PjwvYmxvY2txdW90ZT48L2Rpdj48YnI+PC9kaXY+CjwvYmxvY2txdW90ZT48L2Rpdj48ZGl2IGRp cj0ibHRyIj4tLSA8YnI+PC9kaXY+PGRpdiBkYXRhLXNtYXJ0bWFpbD0iZ21haWxfc2lnbmF0dXJl Ij48ZGl2IGRpcj0ibHRyIj48ZGl2IHN0eWxlPSJmb250LXNpemU6c21hbGwiPjxkaXYgc3R5bGU9 ImZvbnQtc2l6ZToxM3B4O2xpbmUtaGVpZ2h0OjE5LjVweCI+Q1RPLCBBbmFseXRpYyBTcG90PC9k aXY+PGRpdiBzdHlsZT0iZm9udC1zaXplOjEzcHg7bGluZS1oZWlnaHQ6MTkuNXB4Ij40NCBXZXN0 IEJyb2Fkd2F5ICMyMjI8L2Rpdj48ZGl2IHN0eWxlPSJmb250LXNpemU6MTNweDtsaW5lLWhlaWdo dDoxOS41cHgiPkV1Z2VuZSwgT1IgOTc0MDE8YnI+PC9kaXY+PGRpdiBzdHlsZT0iZm9udC1zaXpl OjEzcHg7bGluZS1oZWlnaHQ6MTkuNXB4Ij48YSBocmVmPSJodHRwOi8vYW5hbHl0aWNzcG90LmNv bS8iIHRhcmdldD0iX2JsYW5rIj5hbmFseXRpY3Nwb3QuY29tPC9hPsKgPHNwYW4gc3R5bGU9ImNv bG9yOnJnYigxMjcsMTI3LDEyNyk7Zm9udC1mYW1pbHk6JiMzOTtoZWx2ZXRpY2EgbmV1ZSYjMzk7 O2ZvbnQtc2l6ZToxMXB4O2xpbmUtaGVpZ2h0Om5vcm1hbCI+4oCiwqA8L3NwYW4+NDI1LTI5Ni02 NTU2PC9kaXY+PC9kaXY+PGRpdiBzdHlsZT0iZm9udC1zaXplOnNtYWxsIj48c3BhbiBzdHlsZT0i bGluZS1oZWlnaHQ6MTkuNXB4Ij48YSBocmVmPSJodHRwOi8vd3d3LmxpbmtlZGluLmNvbS9pbi9v bGl2ZXJkYWluIiB0YXJnZXQ9Il9ibGFuayI+d3d3LmxpbmtlZGluLmNvbS9pbi9vbGl2ZXJkYWlu PC9hPjwvc3Bhbj48L2Rpdj48L2Rpdj48L2Rpdj48L2Jsb2NrcXVvdGU+PC9kaXY+PGRpdiBkaXI9 Imx0ciI+LS0gPGJyPjwvZGl2PjxkaXYgZGF0YS1zbWFydG1haWw9ImdtYWlsX3NpZ25hdHVyZSI+ PGRpdiBkaXI9Imx0ciI+PGRpdiBzdHlsZT0iZm9udC1zaXplOnNtYWxsIj48ZGl2IHN0eWxlPSJm b250LXNpemU6MTNweDtsaW5lLWhlaWdodDoxOS41cHgiPkNUTywgQW5hbHl0aWMgU3BvdDwvZGl2 PjxkaXYgc3R5bGU9ImZvbnQtc2l6ZToxM3B4O2xpbmUtaGVpZ2h0OjE5LjVweCI+NDQgV2VzdCBC cm9hZHdheSAjMjIyPC9kaXY+PGRpdiBzdHlsZT0iZm9udC1zaXplOjEzcHg7bGluZS1oZWlnaHQ6 MTkuNXB4Ij5FdWdlbmUsIE9SIDk3NDAxPGJyPjwvZGl2PjxkaXYgc3R5bGU9ImZvbnQtc2l6ZTox M3B4O2xpbmUtaGVpZ2h0OjE5LjVweCI+PGEgaHJlZj0iaHR0cDovL2FuYWx5dGljc3BvdC5jb20v IiBzdHlsZT0iei1pbmRleDogMDsiPmFuYWx5dGljc3BvdC5jb208L2E+wqA8c3BhbiBzdHlsZT0i Y29sb3I6cmdiKDEyNywxMjcsMTI3KTtmb250LWZhbWlseTomIzM5O2hlbHZldGljYSBuZXVlJiMz OTs7Zm9udC1zaXplOjExcHg7bGluZS1oZWlnaHQ6bm9ybWFsIj7igKLCoDwvc3Bhbj40MjUtMjk2 LTY1NTY8L2Rpdj48L2Rpdj48ZGl2IHN0eWxlPSJmb250LXNpemU6c21hbGwiPjxzcGFuIHN0eWxl PSJsaW5lLWhlaWdodDoxOS41cHgiPjxhIGhyZWY9Imh0dHA6Ly93d3cubGlua2VkaW4uY29tL2lu L29saXZlcmRhaW4iIHN0eWxlPSJ6LWluZGV4OiAwOyI+d3d3LmxpbmtlZGluLmNvbS9pbi9vbGl2 ZXJkYWluPC9hPjwvc3Bhbj48L2Rpdj48L2Rpdj48L2Rpdj4K --===============0085737254904233968==--