Re: [Engine-devel] UI Plugins configuration

------=_Part_12944838_269192103.1345724057851 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit Hi Chris, thanks for taking the time to make this patch, these are some excellent ideas! (CC'ing engine-devel so that we can discuss this with other guys as well) First of all, I really like the way you designed plugin source page URLs (going through PluginSourcePageServlet ), e.g. "/webadmin/webadmin/plugin/<pluginName>/<pluginSourcePage>.html", plus the concept of "path" JSON attribute. WebadminDynamicHostingServlet loads and caches all plugin definitions ( *.json files), and directly embeds them into WebAdmin host page as pluginDefinitions JavaScript object. I'm assuming that pluginDefinitions object will now look like this: var pluginDefinitions = { "test": { "name": "test", "version": "1.0", "url": "/webadmin/webadmin/plugin/test/foo.html", "path": "/tmp", "config": {"a":1, "b":2, "c":3} } } Originally, the pluginDefinitions object looked like this: var pluginDefinitions = { "test": "/webadmin/webadmin/plugin/test/foo.html" // Simple pluginName -> pluginSourcePageUrl mappings } This is because PluginManager (WebAdmin) only needs pluginName ("name") and pluginSourcePageUrl ("url") during startup, when creating plugin iframe. But this can be changed :) Plugin "version" makes sense, plus the plugin configuration object ("config") can be useful directly on the client. Let me explain: Originally, plugin configuration was supposed to be passed to actual plugin code (through immediately-invoked-function-expression, or IIFE), just like this: (function (pluginApi, pluginConfig) { // JavaScript IIFE // ... actual plugin code ... })( parent.pluginApi, /* reference to global pluginApi object */ {"a":1, "b":2, "c":3} /* embedded plugin configuration as JavaScript object */ ); The whole purpose of PluginSourcePageServlet was to "wrap" actual plugin code into HTML, so that users don't need to write HTML pages for their plugins manually. PluginSourcePageServlet would handle any plugin dependencies (placed into HTML head), with actual plugin code being wrapped into IIFE, as shown above. Plugin configuration was meant to be stored in a separate file, e.g. <pluginName>-config.json , so that users could change the default plugin configuration to suit their needs. Inspired by your patch, rather than reading/embedding plugin configuration when serving plugin HTML page ( PluginSourcePageServlet ), it's even better to have the plugin configuration embedded directly into WebAdmin host page, along with introducing new pluginApi function to retrieve the plugin configuration object. Based on this, I suggest following modifications to the original concept: - modify original pluginDefinitions structure, from pluginName -> pluginSourcePageUrl , to pluginName -> pluginDefObject - pluginDefObject is basically a subset of physical plugin definition ( test.json , see below), suitable for use on the client - add following attributes to pluginDefObject : version , url , config * note #1: name is not needed, since it's already the key of pluginName -> pluginDefObject mapping * note #2: path is not needed on the client (more on this below) - introduce pluginApi.config(pluginName) function for plugins to retrieve their configuration object, and remove pluginConfig parameter from main IIFE (as shown above) [a] Physical plugin definition file (JSON) might be located at oVirt "DataDir", e.g. /usr/share/ovirt-engine/ui-plugins/test.json , for example: { "name": "test", "version": "1.0", "url": "/webadmin/webadmin/plugin/test/start.html", "path": "/tmp", "config": "test-config.json" } [b] Plugin configuration file (JSON) might be located at oVirt "ConfigDir", e.g. /etc/ovirt-engine/ui-plugins/test-config.json , for example: { "a":1, "b":2, "c":3 } [c] Finally, plugin static resources (plugin source page, actual plugin code, plugin dependencies, CSS/images, etc.) would be located at /tmp (as shown in [a]), for example: /tmp/start.html -> plugin source page, used to load actual plugin code /tmp/test.js -> actual plugin code /tmp/deps/jquery-min.js -> simulate 3rd party plugin dependency For example: "/webadmin/webadmin/plugin/test/start.html" will be mapped to /tmp/start.html "/webadmin/webadmin/plugin/test/deps/jquery-min.js" will be mapped to /tmp/deps/jquery-min.js This approach has some pros and cons: (+) plugin static resources can be served through PluginSourcePageServlet (pretty much like oVirt documentation resources, served through oVirt Engine root war's FileServlet ) (+) plugin author has complete control over plugin source page (-) plugin author actually needs to write plugin source page Overall, I think this approach is better than the previous one (where PluginSourcePageServlet took care of rendering plugin source page, but sacrificed some flexibility). By the way, here's what would happen behind the scenes: 1. user requests WebAdmin host page, WebadminDynamicHostingServlet loads and caches all plugin definitions [a] + plugin configurations [b] and constructs/embeds appropriate pluginDefinitions JavaScript object 2. during WebAdmin startup, PluginManager registers the plugin (name/version/url/config), and creates/attaches the iframe to fetch plugin source page ansynchronously 3. PluginSourcePageServlet handles plugin source page request, resolves the correct path [c] and just streams the file content back to client
1. The plugin configuration files should probably have an "enabled" field and an "apiVersion" field that should be examined to determine whether or not to use the plugin.
Sounds good, we can implement these later on :)
2. I suspect the way I've modified PluginSourcePage makes it vulnerable to directory climbing attacks.
Yes, but we can defend against these, restricting access only to plugin's "path" and its sub-directories.
3. Is /usr/share/ovirt-engine the right place for the plugin config files?
<br><span style=3D"font-style: italic;">WebadminDynamicHostingServlet</spa= n> loads and caches all plugin definitions (<span style=3D"font-style: ital= ic;">*.json</span> files), and directly embeds them into WebAdmin host page= as <span style=3D"font-style: italic;">pluginDefinitions</span> JavaScript= object. I'm assuming that <span style=3D"font-style: italic;">pluginDefini= tions</span> object will now look like this:<br><br><span style=3D"font-fam= ily: courier new,courier,monaco,monospace,sans-serif;">var pluginDefinition= s =3D {</span><br style=3D"font-family: courier new,courier,monaco,monospac= e,sans-serif;"><span style=3D"font-family: courier new,courier,monaco,monos=
was to "wrap" actual plugin code into HTML, so that users don't need to w= rite HTML pages for their plugins manually. <span style=3D"font-style: ital= ic;">PluginSourcePageServlet</span> would handle any plugin dependencies (p= laced into HTML head), with actual plugin code being wrapped into IIFE, as = shown above. Plugin configuration was meant to be stored in a separate file= , e.g. <span style=3D"font-style: italic;"><pluginName>-config.json</= span>, so that users could change the default plugin configuration to suit =
}<br><br>The engine reads all of the *.json files in that directory to bui= ld the list of known plugins and gives that list to the webadmin.<br><br>Wh= en webadmin loads a plugin, it requests the URL given in the plugin config = file. The "plugin" URL is mapped to PluginSourcePage, which will tran= slate the first part of the path ("test") into whatever path is stored in p= luginConfig ("/tmp") in this case, and then serve the static file (e.g. "/t= mp/foo.html").<br><br>I didn't use the renderPluginSourcePage() method in f= avor of just serving a static file, but I have no strong opinion on the mat= ter. However, a plugin may want to store static resources at "path" a= nd have the engine serve those resources. By just serving files throu= gh PluginSourcePage, we don't need any other servlets to provide those reso= urces.<br><br>There is still a bit of work to do:<br><br>1. The plugi= n configuration files should probably have an "enabled" field and an "apiVe= rsion" field that should be examined to determine whether or not to use the=
I suppose you mean plugin definition files [a], cannot tell for sure, but we can change this anytime :) Chris, please let me know what you think, and again - many thanks for sending the patch! Regards, Vojtech ----- Original Message ----- From: "Chris Frantz" <Chris.Frantz@hp.com> To: vszocs@redhat.com Sent: Wednesday, August 22, 2012 7:56:45 PM Subject: UI Plugins configuration Vojtech, I decided to work on making the plugin patch a bit more configurable, following some of the ideas expressed by Itamar and others in the meeting yesterday. The attached patch is a simple first-attempt. Plugin configurations are stored in /usr/share/ovirt-engine/ui-plugins/*.json. Example: { "name": "test", "version": "1.0", "url": "/webadmin/webadmin/plugin/test/foo.html", "path": "/tmp", "config": {"a":1, "b":2, "c": 3} } The engine reads all of the *.json files in that directory to build the list of known plugins and gives that list to the webadmin. When webadmin loads a plugin, it requests the URL given in the plugin config file. The "plugin" URL is mapped to PluginSourcePage, which will translate the first part of the path ("test") into whatever path is stored in pluginConfig ("/tmp") in this case, and then serve the static file (e.g. "/tmp/foo.html"). I didn't use the renderPluginSourcePage() method in favor of just serving a static file, but I have no strong opinion on the matter. However, a plugin may want to store static resources at "path" and have the engine serve those resources. By just serving files through PluginSourcePage, we don't need any other servlets to provide those resources. There is still a bit of work to do: 1. The plugin configuration files should probably have an "enabled" field and an "apiVersion" field that should be examined to determine whether or not to use the plugin. 2. I suspect the way I've modified PluginSourcePage makes it vulnerable to directory climbing attacks. 3. Is /usr/share/ovirt-engine the right place for the plugin config files? Let me know what you think, --Chris ------=_Part_12944838_269192103.1345724057851 Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable <html><head><style type=3D'text/css'>p { margin: 0; }</style></head><body><= div style=3D'font-family: times new roman,new york,times,serif; font-size: = 12pt; color: #000000'>Hi Chris,<br><br>thanks for taking the time to make t= his patch, these are some excellent ideas! (CC'ing engine-devel so that we = can discuss this with other guys as well)<br><br>First of all, I really lik= e the way you designed plugin source page URLs (going through <em>PluginSou= rcePageServlet</em>), e.g. "/webadmin/webadmin/plugin/<pluginName>/&l= t;pluginSourcePage>.html", plus the concept of "path" JSON attribute.<br= pace,sans-serif;"> "test": {</span><br style=3D"font-family: cou= rier new,courier,monaco,monospace,sans-serif;"><span style=3D"font-family: = courier new,courier,monaco,monospace,sans-serif;"> "name"= : "test",</span><br style=3D"font-family: courier new,courier,monaco,monosp= ace,sans-serif;"><span style=3D"font-family: courier new,courier,monaco,mon= ospace,sans-serif;"> "version": "1.0",</span><br style=3D= "font-family: courier new,courier,monaco,monospace,sans-serif;"><span style= =3D"font-family: courier new,courier,monaco,monospace,sans-serif;"> &n= bsp; "url": "/webadmin/webadmin/plugin/test/foo.html",</span><br styl= e=3D"font-family: courier new,courier,monaco,monospace,sans-serif;"><span s= tyle=3D"font-family: courier new,courier,monaco,monospace,sans-serif;">&nbs= p; "path": "/tmp",</span><br style=3D"font-family: courier new,= courier,monaco,monospace,sans-serif;"><span style=3D"font-family: courier n= ew,courier,monaco,monospace,sans-serif;"> "config": {"a":= 1, "b":2, "c":3}</span><br style=3D"font-family: courier new,courier,monaco= ,monospace,sans-serif;"><span style=3D"font-family: courier new,courier,mon= aco,monospace,sans-serif;"> }</span><br style=3D"font-family: co= urier new,courier,monaco,monospace,sans-serif;"><span style=3D"font-family:= courier new,courier,monaco,monospace,sans-serif;">}</span><br><br>Original= ly, the <span style=3D"font-style: italic;">pluginDefinitions</span> object= looked like this:<br><br style=3D"font-family: courier new,courier,monaco,= monospace,sans-serif;"><span style=3D"font-family: courier new,courier,mona= co,monospace,sans-serif;">var pluginDefinitions =3D {</span><br style=3D"fo= nt-family: courier new,courier,monaco,monospace,sans-serif;"><span style=3D= "font-family: courier new,courier,monaco,monospace,sans-serif;">  = ;"test": "/webadmin/webadmin/plugin/test/foo.html" // Simple pluginName -&g= t; pluginSourcePageUrl mappings</span><br style=3D"font-family: courier new= ,courier,monaco,monospace,sans-serif;"><span style=3D"font-family: courier = new,courier,monaco,monospace,sans-serif;">}</span><br><br>This is because P= luginManager (WebAdmin) only needs <span style=3D"font-style: italic;">plug= inName</span> ("name") and <span style=3D"font-style: italic;">pluginSource= PageUrl</span> ("url") during startup, when creating plugin iframe. But thi= s can be changed :)<br><br>Plugin "version" makes sense, plus the plugin co= nfiguration object ("config") can be useful directly on the client. Let me = explain:<br><br>Originally, plugin configuration was supposed to be passed = to actual plugin code (through immediately-invoked-function-expression, or = IIFE), just like this:<br><br style=3D"font-family: courier new,courier,mon= aco,monospace,sans-serif;"><span style=3D"font-family: courier new,courier,= monaco,monospace,sans-serif;">(function (pluginApi, pluginConfig) { // Java= Script IIFE</span><br style=3D"font-family: courier new,courier,monaco,mono= space,sans-serif;"><span style=3D"font-family: courier new,courier,monaco,m= onospace,sans-serif;"> // ... actual plugin code ...</span><br s= tyle=3D"font-family: courier new,courier,monaco,monospace,sans-serif;"><spa= n style=3D"font-family: courier new,courier,monaco,monospace,sans-serif;">}= )(</span><br style=3D"font-family: courier new,courier,monaco,monospace,san= s-serif;"><span style=3D"font-family: courier new,courier,monaco,monospace,= sans-serif;"> parent.pluginApi, /* reference to global pluginApi= object */</span><br style=3D"font-family: courier new,courier,monaco,monos= pace,sans-serif;"><span style=3D"font-family: courier new,courier,monaco,mo= nospace,sans-serif;"> {"a":1, "b":2, "c":3} /* embedded plugin c= onfiguration as JavaScript object */</span><br style=3D"font-family: courie= r new,courier,monaco,monospace,sans-serif;"><span style=3D"font-family: cou= rier new,courier,monaco,monospace,sans-serif;">);</span><br><br>The whole p= urpose of <span style=3D"font-style: italic;">PluginSourcePageServlet</span= their needs.<br><br>Inspired by your patch, rather than reading/embedding p= lugin configuration when serving plugin HTML page (<span style=3D"font-styl= e: italic;">PluginSourcePageServlet</span>), it's even better to have the p= lugin configuration embedded directly into WebAdmin host page, along with i= ntroducing new <span style=3D"font-style: italic;">pluginApi</span> functio= n to retrieve the plugin configuration object.<br><br>Based on this, I sugg= est following modifications to the original concept:<br><br>- modify origin= al <span style=3D"font-style: italic;">pluginDefinitions</span> structure, = from <span style=3D"font-style: italic;">pluginName -> pluginSourcePageU= rl</span>, to <span style=3D"font-style: italic;">pluginName -> pluginDe= fObject</span><br>- <span style=3D"font-style: italic;">pluginDefObject</sp= an> is basically a subset of physical plugin definition (<span style=3D"fon= t-style: italic;">test.json</span>, see below), suitable for use on the cli= ent<br>- add following attributes to <span style=3D"font-style: italic;">pl= uginDefObject</span>: <span style=3D"font-style: italic;">version</span>, <= span style=3D"font-style: italic;">url</span>, <span style=3D"font-style: i= talic;">config</span><br> * note #1: <span style=3D"font-style: = italic;">name</span> is not needed, since it's already the key of <span sty= le=3D"font-style: italic;">pluginName -> pluginDefObject</span> mapping<= br> * note #2: <span style=3D"font-style: italic;">path</span> i= s not needed on the client (more on this below)<br>- introduce <span style= =3D"font-style: italic;">pluginApi.config(pluginName)</span> function for p= lugins to retrieve their configuration object, and remove <span style=3D"fo= nt-style: italic;">pluginConfig</span> parameter from main IIFE (as shown a= bove)<br><br>[a] Physical plugin definition file (JSON) might be located at= oVirt "DataDir", e.g. <span style=3D"font-style: italic;">/usr/share/ovirt= -engine/ui-plugins/test.json</span>, for example:<br><br style=3D"font-fami= ly: courier new,courier,monaco,monospace,sans-serif;"><span style=3D"font-f= amily: courier new,courier,monaco,monospace,sans-serif;">{</span><br style= =3D"font-family: courier new,courier,monaco,monospace,sans-serif;"><span st= yle=3D"font-family: courier new,courier,monaco,monospace,sans-serif;"> = ; "name": "test",</span><br style=3D"font-family: courier new,courier,= monaco,monospace,sans-serif;"><span style=3D"font-family: courier new,couri= er,monaco,monospace,sans-serif;"> "version": "1.0",</span><br st= yle=3D"font-family: courier new,courier,monaco,monospace,sans-serif;"><span= style=3D"font-family: courier new,courier,monaco,monospace,sans-serif;">&n= bsp; "url": "/webadmin/webadmin/plugin/test/start.html",</span><br sty= le=3D"font-family: courier new,courier,monaco,monospace,sans-serif;"><span = style=3D"font-family: courier new,courier,monaco,monospace,sans-serif;">&nb= sp; "path": "/tmp",</span><br style=3D"font-family: courier new,courie= r,monaco,monospace,sans-serif;"><span style=3D"font-family: courier new,cou= rier,monaco,monospace,sans-serif;"> "config": "test-config.json"= </span><br style=3D"font-family: courier new,courier,monaco,monospace,sans-= serif;"><span style=3D"font-family: courier new,courier,monaco,monospace,sa= ns-serif;">}</span><br><br>[b] Plugin configuration file (JSON) might be lo= cated at oVirt "ConfigDir", e.g. <span style=3D"font-style: italic;">/etc/o= virt-engine/ui-plugins/test-config.json</span>, for example:<br><br style= =3D"font-family: courier new,courier,monaco,monospace,sans-serif;"><span st= yle=3D"font-family: courier new,courier,monaco,monospace,sans-serif;">{</sp= an><br style=3D"font-family: courier new,courier,monaco,monospace,sans-seri= f;"><span style=3D"font-family: courier new,courier,monaco,monospace,sans-s= erif;"> "a":1, "b":2, "c":3</span><br style=3D"font-family: cour= ier new,courier,monaco,monospace,sans-serif;"><span style=3D"font-family: c= ourier new,courier,monaco,monospace,sans-serif;">}</span><br><br>[c] Finall= y, plugin static resources (plugin source page, actual plugin code, plugin = dependencies, CSS/images, etc.) would be located at <span style=3D"font-sty= le: italic;">/tmp</span> (as shown in [a]), for example:<br><br style=3D"fo= nt-family: courier new,courier,monaco,monospace,sans-serif;"><span style=3D= "font-family: courier new,courier,monaco,monospace,sans-serif;">/tmp/start.= html -> plugin source page, used to load actual plugin code</span><br st= yle=3D"font-family: courier new,courier,monaco,monospace,sans-serif;"><span= style=3D"font-family: courier new,courier,monaco,monospace,sans-serif;">/t= mp/test.js -> actual plugin code</span><br style=3D"font-family: courier= new,courier,monaco,monospace,sans-serif;"><span style=3D"font-family: cour= ier new,courier,monaco,monospace,sans-serif;">/tmp/deps/jquery-min.js ->= simulate 3rd party plugin dependency</span><br><br>For example:<br>"/webad= min/webadmin/plugin/test/start.html" will be mapped to <span style=3D"font-= style: italic;">/tmp/start.html</span><br>"/webadmin/webadmin/plugin/test/d= eps/jquery-min.js" will be mapped to <span style=3D"font-style: italic;">/t= mp/deps/jquery-min.js</span><br><br>This approach has some pros and cons:<b= r>(+) plugin static resources can be served through <span style=3D"font-sty= le: italic;">PluginSourcePageServlet</span> (pretty much like oVirt documen= tation resources, served through oVirt Engine root war's <span style=3D"fon= t-style: italic;">FileServlet</span>)<br>(+) plugin author has complete con= trol over plugin source page<br>(-) plugin author actually needs to write p= lugin source page<br><br>Overall, I think this approach is better than the = previous one (where <span style=3D"font-style: italic;">PluginSourcePageSer= vlet</span> took care of rendering plugin source page, but sacrificed some = flexibility).<br><br>By the way, here's what would happen behind the scenes= :<br><ol><li>user requests WebAdmin host page, <span style=3D"font-style: i= talic;">WebadminDynamicHostingServlet</span> loads and caches all plugin de= finitions [a] + plugin configurations [b] and constructs/embeds appropriate= <span style=3D"font-style: italic;">pluginDefinitions</span> JavaScript ob= ject<br><br></li><li>during WebAdmin startup, <span style=3D"font-style: it= alic;">PluginManager</span> registers the plugin (name/version/url/config),= and creates/attaches the iframe to fetch plugin source page ansynchronousl= y<br><br></li><li><span style=3D"font-style: italic;">PluginSourcePageServl= et</span> handles plugin source page request, resolves the correct path [c]= and just streams the file content back to client<br><br></li></ol>> 1. = The plugin configuration files should probably have an "enabled"=20 field and an "apiVersion" field that should be examined to determine=20 whether or not to use the plugin.<br><br>Sounds good, we can implement thes= e later on :)<br><br>> 2. I suspect the way I've modified PluginSo= urcePage makes it vulnerable to directory climbing attacks.<br><br>Yes, but= we can defend against these, restricting access only to plugin's "path" an= d its sub-directories.<br><br>> 3. Is /usr/share/ovirt-engine the = right place for the plugin config files?<br><br>I suppose you mean plugin d= efinition files [a], cannot tell for sure, but we can change this anytime := )<br><br><br>Chris, please let me know what you think, and again - many tha= nks for sending the patch!<br><br><br>Regards,<br>Vojtech<br><br><br><hr id= =3D"zwchr"><br>From: "Chris Frantz" <Chris.Frantz@hp.com><br>To: vszo= cs@redhat.com<br>Sent: Wednesday, August 22, 2012 7:56:45 PM<br>Subject: UI= Plugins configuration<br><br>Vojtech,<br><br>I decided to work on making t= he plugin patch a bit more configurable, following some of the ideas expres= sed by Itamar and others in the meeting yesterday. The attached patch= is a simple first-attempt.<br><br>Plugin configurations are stored in /usr= /share/ovirt-engine/ui-plugins/*.json.<br><br>Example:<br>{<br> = "name": "test",<br> &n= bsp; "version": "1.0",<br> &n= bsp; "url": "/webadmin/webadmin/plugin/test/foo.html",<br>= "path": "/tmp",<br> &n= bsp; "config": {"a":1, "b":2, "c": 3}<br= plugin.<br><br>2. I suspect the way I've modified PluginSourcePage m= akes it vulnerable to directory climbing attacks.<br><br>3. Is /usr/s= hare/ovirt-engine the right place for the plugin config files?<br><br>Let m= e know what you think,<br>--Chris<br><br></div></body></html> ------=_Part_12944838_269192103.1345724057851--

--_000_6C8AC8C50E170C4E9B44D47B39B24A480931C86FSACEXCMBX04PRDh_ Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 VGhhbmtzIENocmlzIGFuZCBWb2p0ZWNoIGZvciBjb250aW51aW5nIHRoaXMgZGlzY3Vzc2lvbi4g IEkgdGhpbmsgSeKAmW0gbWlzc2luZyB0aGUgbGluayBiZXR3ZWVuIHByb3ZpZGluZyB0aGUgcGx1 Z2luIGRlZmluaXRpb24gZmlsZSBhbmQgZGVmaW5pbmcgdGhlIHBsdWdpbnMuICBJZiBJIHdhbnQg dG8gYWRkIDMgbWFpbiB0YWJzIGFuZCA2IGNvbnRleHQgbWVudXMsIGRvIEkgcHJvdmlkZSA5IHBs dWdpbiBkZWZpbml0aW9ucz8gIE9yIGRvIEkgcHJvdmlkZSAxIHBsdWdpbiBkZWZpbml0aW9uIHdp dGggbXVsdGlwbGUg4oCcdXJsc+KAnSB3aGVyZSBlYWNoIG9uZSBwb2ludHMgdG8gYSBkaXN0aW5j dCBwYXRoPw0KDQpJZiDigJx1cmzigJ0gaXMgY29uZmlndXJlZCB0byBwb2ludCB0byBhbiBleHRl cm5hbCBhcHBsaWNhdGlvbiBzZXJ2ZXIgaG9zdGluZyBteSBwbHVnaW4sIHdoYXQgaXMgdGhlIGlu dGVudCBvZiDigJxwYXRo4oCdPyAgRm9yIGV4YW1wbGUsIGlmIEkgY29uZmlndXJlIOKAnHVybOKA nSB0byBwb2ludCB0byDigJxodHRwczovLzEwLjEwLjEwLjEwL215cGx1Z2luL2VudHJ5cG9pbnQu aHRtbOKAnSB0aGVuIHByZXN1bWFibHkgdGhlIGFwcGxpY2F0aW9uIHNlcnZlciB3aWxsIHJlbmRl ciB0aGUgcGFnZSBpdCBuZWVkcyBhcyBhIG1haW4gdGFiIG9yIGNvbnRleHQgbWVudS4gIEl0IHdv dWxkIGhhdmUgbm8gbmVlZCBmb3Ig4oCccGF0aOKAnSBzaW5jZSBhbGwgZGVwZW5kZW5jaWVzIHdv dWxkIGJlIHJlc29sdmVkIGJ5IHRoZSBhcHBsaWNhdGlvbiBzZXJ2ZXIuDQoNCkdlb3JnZQ0KDQpG cm9tOiBlbmdpbmUtZGV2ZWwtYm91bmNlc0BvdmlydC5vcmcgW21haWx0bzplbmdpbmUtZGV2ZWwt Ym91bmNlc0BvdmlydC5vcmddIE9uIEJlaGFsZiBPZiBWb2p0ZWNoIFN6b2NzDQpTZW50OiBUaHVy c2RheSwgQXVndXN0IDIzLCAyMDEyIDg6MTQgQU0NClRvOiBDaHJpcyBGcmFudHoNCkNjOiBlbmdp bmUtZGV2ZWwNClN1YmplY3Q6IFJlOiBbRW5naW5lLWRldmVsXSBVSSBQbHVnaW5zIGNvbmZpZ3Vy YXRpb24NCg0KSGkgQ2hyaXMsDQoNCnRoYW5rcyBmb3IgdGFraW5nIHRoZSB0aW1lIHRvIG1ha2Ug dGhpcyBwYXRjaCwgdGhlc2UgYXJlIHNvbWUgZXhjZWxsZW50IGlkZWFzISAoQ0MnaW5nIGVuZ2lu ZS1kZXZlbCBzbyB0aGF0IHdlIGNhbiBkaXNjdXNzIHRoaXMgd2l0aCBvdGhlciBndXlzIGFzIHdl bGwpDQoNCkZpcnN0IG9mIGFsbCwgSSByZWFsbHkgbGlrZSB0aGUgd2F5IHlvdSBkZXNpZ25lZCBw bHVnaW4gc291cmNlIHBhZ2UgVVJMcyAoZ29pbmcgdGhyb3VnaCBQbHVnaW5Tb3VyY2VQYWdlU2Vy dmxldCksIGUuZy4gIi93ZWJhZG1pbi93ZWJhZG1pbi9wbHVnaW4vPHBsdWdpbk5hbWU+LzxwbHVn aW5Tb3VyY2VQYWdlPi5odG1sIiwgcGx1cyB0aGUgY29uY2VwdCBvZiAicGF0aCIgSlNPTiBhdHRy aWJ1dGUuDQoNCldlYmFkbWluRHluYW1pY0hvc3RpbmdTZXJ2bGV0IGxvYWRzIGFuZCBjYWNoZXMg YWxsIHBsdWdpbiBkZWZpbml0aW9ucyAoKi5qc29uIGZpbGVzKSwgYW5kIGRpcmVjdGx5IGVtYmVk cyB0aGVtIGludG8gV2ViQWRtaW4gaG9zdCBwYWdlIGFzIHBsdWdpbkRlZmluaXRpb25zIEphdmFT Y3JpcHQgb2JqZWN0LiBJJ20gYXNzdW1pbmcgdGhhdCBwbHVnaW5EZWZpbml0aW9ucyBvYmplY3Qg d2lsbCBub3cgbG9vayBsaWtlIHRoaXM6DQoNCnZhciBwbHVnaW5EZWZpbml0aW9ucyA9IHsNCiAg InRlc3QiOiB7DQogICAgIm5hbWUiOiAidGVzdCIsDQogICAgInZlcnNpb24iOiAiMS4wIiwNCiAg ICAidXJsIjogIi93ZWJhZG1pbi93ZWJhZG1pbi9wbHVnaW4vdGVzdC9mb28uaHRtbCIsDQogICAg InBhdGgiOiAiL3RtcCIsDQogICAgImNvbmZpZyI6IHsiYSI6MSwgImIiOjIsICJjIjozfQ0KICB9 DQp9DQoNCk9yaWdpbmFsbHksIHRoZSBwbHVnaW5EZWZpbml0aW9ucyBvYmplY3QgbG9va2VkIGxp a2UgdGhpczoNCg0KdmFyIHBsdWdpbkRlZmluaXRpb25zID0gew0KICAidGVzdCI6ICIvd2ViYWRt aW4vd2ViYWRtaW4vcGx1Z2luL3Rlc3QvZm9vLmh0bWwiIC8vIFNpbXBsZSBwbHVnaW5OYW1lIC0+ IHBsdWdpblNvdXJjZVBhZ2VVcmwgbWFwcGluZ3MNCn0NCg0KVGhpcyBpcyBiZWNhdXNlIFBsdWdp bk1hbmFnZXIgKFdlYkFkbWluKSBvbmx5IG5lZWRzIHBsdWdpbk5hbWUgKCJuYW1lIikgYW5kIHBs dWdpblNvdXJjZVBhZ2VVcmwgKCJ1cmwiKSBkdXJpbmcgc3RhcnR1cCwgd2hlbiBjcmVhdGluZyBw bHVnaW4gaWZyYW1lLiBCdXQgdGhpcyBjYW4gYmUgY2hhbmdlZCA6KQ0KDQpQbHVnaW4gInZlcnNp b24iIG1ha2VzIHNlbnNlLCBwbHVzIHRoZSBwbHVnaW4gY29uZmlndXJhdGlvbiBvYmplY3QgKCJj b25maWciKSBjYW4gYmUgdXNlZnVsIGRpcmVjdGx5IG9uIHRoZSBjbGllbnQuIExldCBtZSBleHBs YWluOg0KDQpPcmlnaW5hbGx5LCBwbHVnaW4gY29uZmlndXJhdGlvbiB3YXMgc3VwcG9zZWQgdG8g YmUgcGFzc2VkIHRvIGFjdHVhbCBwbHVnaW4gY29kZSAodGhyb3VnaCBpbW1lZGlhdGVseS1pbnZv a2VkLWZ1bmN0aW9uLWV4cHJlc3Npb24sIG9yIElJRkUpLCBqdXN0IGxpa2UgdGhpczoNCg0KKGZ1 bmN0aW9uIChwbHVnaW5BcGksIHBsdWdpbkNvbmZpZykgeyAvLyBKYXZhU2NyaXB0IElJRkUNCiAg Ly8gLi4uIGFjdHVhbCBwbHVnaW4gY29kZSAuLi4NCn0pKA0KICBwYXJlbnQucGx1Z2luQXBpLCAv KiByZWZlcmVuY2UgdG8gZ2xvYmFsIHBsdWdpbkFwaSBvYmplY3QgKi8NCiAgeyJhIjoxLCAiYiI6 MiwgImMiOjN9IC8qIGVtYmVkZGVkIHBsdWdpbiBjb25maWd1cmF0aW9uIGFzIEphdmFTY3JpcHQg b2JqZWN0ICovDQopOw0KDQpUaGUgd2hvbGUgcHVycG9zZSBvZiBQbHVnaW5Tb3VyY2VQYWdlU2Vy dmxldCB3YXMgdG8gIndyYXAiIGFjdHVhbCBwbHVnaW4gY29kZSBpbnRvIEhUTUwsIHNvIHRoYXQg dXNlcnMgZG9uJ3QgbmVlZCB0byB3cml0ZSBIVE1MIHBhZ2VzIGZvciB0aGVpciBwbHVnaW5zIG1h bnVhbGx5LiBQbHVnaW5Tb3VyY2VQYWdlU2VydmxldCB3b3VsZCBoYW5kbGUgYW55IHBsdWdpbiBk ZXBlbmRlbmNpZXMgKHBsYWNlZCBpbnRvIEhUTUwgaGVhZCksIHdpdGggYWN0dWFsIHBsdWdpbiBj b2RlIGJlaW5nIHdyYXBwZWQgaW50byBJSUZFLCBhcyBzaG93biBhYm92ZS4gUGx1Z2luIGNvbmZp Z3VyYXRpb24gd2FzIG1lYW50IHRvIGJlIHN0b3JlZCBpbiBhIHNlcGFyYXRlIGZpbGUsIGUuZy4g PHBsdWdpbk5hbWU+LWNvbmZpZy5qc29uLCBzbyB0aGF0IHVzZXJzIGNvdWxkIGNoYW5nZSB0aGUg ZGVmYXVsdCBwbHVnaW4gY29uZmlndXJhdGlvbiB0byBzdWl0IHRoZWlyIG5lZWRzLg0KDQpJbnNw aXJlZCBieSB5b3VyIHBhdGNoLCByYXRoZXIgdGhhbiByZWFkaW5nL2VtYmVkZGluZyBwbHVnaW4g Y29uZmlndXJhdGlvbiB3aGVuIHNlcnZpbmcgcGx1Z2luIEhUTUwgcGFnZSAoUGx1Z2luU291cmNl UGFnZVNlcnZsZXQpLCBpdCdzIGV2ZW4gYmV0dGVyIHRvIGhhdmUgdGhlIHBsdWdpbiBjb25maWd1 cmF0aW9uIGVtYmVkZGVkIGRpcmVjdGx5IGludG8gV2ViQWRtaW4gaG9zdCBwYWdlLCBhbG9uZyB3 aXRoIGludHJvZHVjaW5nIG5ldyBwbHVnaW5BcGkgZnVuY3Rpb24gdG8gcmV0cmlldmUgdGhlIHBs dWdpbiBjb25maWd1cmF0aW9uIG9iamVjdC4NCg0KQmFzZWQgb24gdGhpcywgSSBzdWdnZXN0IGZv bGxvd2luZyBtb2RpZmljYXRpb25zIHRvIHRoZSBvcmlnaW5hbCBjb25jZXB0Og0KDQotIG1vZGlm eSBvcmlnaW5hbCBwbHVnaW5EZWZpbml0aW9ucyBzdHJ1Y3R1cmUsIGZyb20gcGx1Z2luTmFtZSAt PiBwbHVnaW5Tb3VyY2VQYWdlVXJsLCB0byBwbHVnaW5OYW1lIC0+IHBsdWdpbkRlZk9iamVjdA0K LSBwbHVnaW5EZWZPYmplY3QgaXMgYmFzaWNhbGx5IGEgc3Vic2V0IG9mIHBoeXNpY2FsIHBsdWdp biBkZWZpbml0aW9uICh0ZXN0Lmpzb24sIHNlZSBiZWxvdyksIHN1aXRhYmxlIGZvciB1c2Ugb24g dGhlIGNsaWVudA0KLSBhZGQgZm9sbG93aW5nIGF0dHJpYnV0ZXMgdG8gcGx1Z2luRGVmT2JqZWN0 OiB2ZXJzaW9uLCB1cmwsIGNvbmZpZw0KICAqIG5vdGUgIzE6IG5hbWUgaXMgbm90IG5lZWRlZCwg c2luY2UgaXQncyBhbHJlYWR5IHRoZSBrZXkgb2YgcGx1Z2luTmFtZSAtPiBwbHVnaW5EZWZPYmpl Y3QgbWFwcGluZw0KICAqIG5vdGUgIzI6IHBhdGggaXMgbm90IG5lZWRlZCBvbiB0aGUgY2xpZW50 IChtb3JlIG9uIHRoaXMgYmVsb3cpDQotIGludHJvZHVjZSBwbHVnaW5BcGkuY29uZmlnKHBsdWdp bk5hbWUpIGZ1bmN0aW9uIGZvciBwbHVnaW5zIHRvIHJldHJpZXZlIHRoZWlyIGNvbmZpZ3VyYXRp b24gb2JqZWN0LCBhbmQgcmVtb3ZlIHBsdWdpbkNvbmZpZyBwYXJhbWV0ZXIgZnJvbSBtYWluIElJ RkUgKGFzIHNob3duIGFib3ZlKQ0KDQpbYV0gUGh5c2ljYWwgcGx1Z2luIGRlZmluaXRpb24gZmls ZSAoSlNPTikgbWlnaHQgYmUgbG9jYXRlZCBhdCBvVmlydCAiRGF0YURpciIsIGUuZy4gL3Vzci9z aGFyZS9vdmlydC1lbmdpbmUvdWktcGx1Z2lucy90ZXN0Lmpzb24sIGZvciBleGFtcGxlOg0KDQp7 DQogICJuYW1lIjogInRlc3QiLA0KICAidmVyc2lvbiI6ICIxLjAiLA0KICAidXJsIjogIi93ZWJh ZG1pbi93ZWJhZG1pbi9wbHVnaW4vdGVzdC9zdGFydC5odG1sIiwNCiAgInBhdGgiOiAiL3RtcCIs DQogICJjb25maWciOiAidGVzdC1jb25maWcuanNvbiINCn0NCg0KW2JdIFBsdWdpbiBjb25maWd1 cmF0aW9uIGZpbGUgKEpTT04pIG1pZ2h0IGJlIGxvY2F0ZWQgYXQgb1ZpcnQgIkNvbmZpZ0RpciIs IGUuZy4gL2V0Yy9vdmlydC1lbmdpbmUvdWktcGx1Z2lucy90ZXN0LWNvbmZpZy5qc29uLCBmb3Ig ZXhhbXBsZToNCg0Kew0KICAiYSI6MSwgImIiOjIsICJjIjozDQp9DQoNCltjXSBGaW5hbGx5LCBw bHVnaW4gc3RhdGljIHJlc291cmNlcyAocGx1Z2luIHNvdXJjZSBwYWdlLCBhY3R1YWwgcGx1Z2lu IGNvZGUsIHBsdWdpbiBkZXBlbmRlbmNpZXMsIENTUy9pbWFnZXMsIGV0Yy4pIHdvdWxkIGJlIGxv Y2F0ZWQgYXQgL3RtcCAoYXMgc2hvd24gaW4gW2FdKSwgZm9yIGV4YW1wbGU6DQoNCi90bXAvc3Rh cnQuaHRtbCAtPiBwbHVnaW4gc291cmNlIHBhZ2UsIHVzZWQgdG8gbG9hZCBhY3R1YWwgcGx1Z2lu IGNvZGUNCi90bXAvdGVzdC5qcyAtPiBhY3R1YWwgcGx1Z2luIGNvZGUNCi90bXAvZGVwcy9qcXVl cnktbWluLmpzIC0+IHNpbXVsYXRlIDNyZCBwYXJ0eSBwbHVnaW4gZGVwZW5kZW5jeQ0KDQpGb3Ig ZXhhbXBsZToNCiIvd2ViYWRtaW4vd2ViYWRtaW4vcGx1Z2luL3Rlc3Qvc3RhcnQuaHRtbCIgd2ls bCBiZSBtYXBwZWQgdG8gL3RtcC9zdGFydC5odG1sDQoiL3dlYmFkbWluL3dlYmFkbWluL3BsdWdp bi90ZXN0L2RlcHMvanF1ZXJ5LW1pbi5qcyIgd2lsbCBiZSBtYXBwZWQgdG8gL3RtcC9kZXBzL2px dWVyeS1taW4uanMNCg0KVGhpcyBhcHByb2FjaCBoYXMgc29tZSBwcm9zIGFuZCBjb25zOg0KKCsp IHBsdWdpbiBzdGF0aWMgcmVzb3VyY2VzIGNhbiBiZSBzZXJ2ZWQgdGhyb3VnaCBQbHVnaW5Tb3Vy Y2VQYWdlU2VydmxldCAocHJldHR5IG11Y2ggbGlrZSBvVmlydCBkb2N1bWVudGF0aW9uIHJlc291 cmNlcywgc2VydmVkIHRocm91Z2ggb1ZpcnQgRW5naW5lIHJvb3Qgd2FyJ3MgRmlsZVNlcnZsZXQp DQooKykgcGx1Z2luIGF1dGhvciBoYXMgY29tcGxldGUgY29udHJvbCBvdmVyIHBsdWdpbiBzb3Vy Y2UgcGFnZQ0KKC0pIHBsdWdpbiBhdXRob3IgYWN0dWFsbHkgbmVlZHMgdG8gd3JpdGUgcGx1Z2lu IHNvdXJjZSBwYWdlDQoNCk92ZXJhbGwsIEkgdGhpbmsgdGhpcyBhcHByb2FjaCBpcyBiZXR0ZXIg dGhhbiB0aGUgcHJldmlvdXMgb25lICh3aGVyZSBQbHVnaW5Tb3VyY2VQYWdlU2VydmxldCB0b29r IGNhcmUgb2YgcmVuZGVyaW5nIHBsdWdpbiBzb3VyY2UgcGFnZSwgYnV0IHNhY3JpZmljZWQgc29t ZSBmbGV4aWJpbGl0eSkuDQoNCkJ5IHRoZSB3YXksIGhlcmUncyB3aGF0IHdvdWxkIGhhcHBlbiBi ZWhpbmQgdGhlIHNjZW5lczoNCg0KICAxLiAgdXNlciByZXF1ZXN0cyBXZWJBZG1pbiBob3N0IHBh Z2UsIFdlYmFkbWluRHluYW1pY0hvc3RpbmdTZXJ2bGV0IGxvYWRzIGFuZCBjYWNoZXMgYWxsIHBs dWdpbiBkZWZpbml0aW9ucyBbYV0gKyBwbHVnaW4gY29uZmlndXJhdGlvbnMgW2JdIGFuZCBjb25z dHJ1Y3RzL2VtYmVkcyBhcHByb3ByaWF0ZSBwbHVnaW5EZWZpbml0aW9ucyBKYXZhU2NyaXB0IG9i amVjdA0KICAyLiAgZHVyaW5nIFdlYkFkbWluIHN0YXJ0dXAsIFBsdWdpbk1hbmFnZXIgcmVnaXN0 ZXJzIHRoZSBwbHVnaW4gKG5hbWUvdmVyc2lvbi91cmwvY29uZmlnKSwgYW5kIGNyZWF0ZXMvYXR0 YWNoZXMgdGhlIGlmcmFtZSB0byBmZXRjaCBwbHVnaW4gc291cmNlIHBhZ2UgYW5zeW5jaHJvbm91 c2x5DQogIDMuICBQbHVnaW5Tb3VyY2VQYWdlU2VydmxldCBoYW5kbGVzIHBsdWdpbiBzb3VyY2Ug cGFnZSByZXF1ZXN0LCByZXNvbHZlcyB0aGUgY29ycmVjdCBwYXRoIFtjXSBhbmQganVzdCBzdHJl YW1zIHRoZSBmaWxlIGNvbnRlbnQgYmFjayB0byBjbGllbnQNCj4gMS4gIFRoZSBwbHVnaW4gY29u ZmlndXJhdGlvbiBmaWxlcyBzaG91bGQgcHJvYmFibHkgaGF2ZSBhbiAiZW5hYmxlZCIgZmllbGQg YW5kIGFuICJhcGlWZXJzaW9uIiBmaWVsZCB0aGF0IHNob3VsZCBiZSBleGFtaW5lZCB0byBkZXRl cm1pbmUgd2hldGhlciBvciBub3QgdG8gdXNlIHRoZSBwbHVnaW4uDQoNClNvdW5kcyBnb29kLCB3 ZSBjYW4gaW1wbGVtZW50IHRoZXNlIGxhdGVyIG9uIDopDQoNCj4gMi4gIEkgc3VzcGVjdCB0aGUg d2F5IEkndmUgbW9kaWZpZWQgUGx1Z2luU291cmNlUGFnZSBtYWtlcyBpdCB2dWxuZXJhYmxlIHRv IGRpcmVjdG9yeSBjbGltYmluZyBhdHRhY2tzLg0KDQpZZXMsIGJ1dCB3ZSBjYW4gZGVmZW5kIGFn YWluc3QgdGhlc2UsIHJlc3RyaWN0aW5nIGFjY2VzcyBvbmx5IHRvIHBsdWdpbidzICJwYXRoIiBh bmQgaXRzIHN1Yi1kaXJlY3Rvcmllcy4NCg0KPiAzLiAgSXMgL3Vzci9zaGFyZS9vdmlydC1lbmdp bmUgdGhlIHJpZ2h0IHBsYWNlIGZvciB0aGUgcGx1Z2luIGNvbmZpZyBmaWxlcz8NCg0KSSBzdXBw b3NlIHlvdSBtZWFuIHBsdWdpbiBkZWZpbml0aW9uIGZpbGVzIFthXSwgY2Fubm90IHRlbGwgZm9y IHN1cmUsIGJ1dCB3ZSBjYW4gY2hhbmdlIHRoaXMgYW55dGltZSA6KQ0KDQoNCkNocmlzLCBwbGVh c2UgbGV0IG1lIGtub3cgd2hhdCB5b3UgdGhpbmssIGFuZCBhZ2FpbiAtIG1hbnkgdGhhbmtzIGZv ciBzZW5kaW5nIHRoZSBwYXRjaCENCg0KDQpSZWdhcmRzLA0KVm9qdGVjaA0KDQpfX19fX19fX19f X19fX19fX19fX19fX19fX19fX19fXw0KDQpGcm9tOiAiQ2hyaXMgRnJhbnR6IiA8Q2hyaXMuRnJh bnR6QGhwLmNvbTxtYWlsdG86Q2hyaXMuRnJhbnR6QGhwLmNvbT4+DQpUbzogdnN6b2NzQHJlZGhh dC5jb208bWFpbHRvOnZzem9jc0ByZWRoYXQuY29tPg0KU2VudDogV2VkbmVzZGF5LCBBdWd1c3Qg MjIsIDIwMTIgNzo1Njo0NSBQTQ0KU3ViamVjdDogVUkgUGx1Z2lucyBjb25maWd1cmF0aW9uDQoN ClZvanRlY2gsDQoNCkkgZGVjaWRlZCB0byB3b3JrIG9uIG1ha2luZyB0aGUgcGx1Z2luIHBhdGNo IGEgYml0IG1vcmUgY29uZmlndXJhYmxlLCBmb2xsb3dpbmcgc29tZSBvZiB0aGUgaWRlYXMgZXhw cmVzc2VkIGJ5IEl0YW1hciBhbmQgb3RoZXJzIGluIHRoZSBtZWV0aW5nIHllc3RlcmRheS4gIFRo ZSBhdHRhY2hlZCBwYXRjaCBpcyBhIHNpbXBsZSBmaXJzdC1hdHRlbXB0Lg0KDQpQbHVnaW4gY29u ZmlndXJhdGlvbnMgYXJlIHN0b3JlZCBpbiAvdXNyL3NoYXJlL292aXJ0LWVuZ2luZS91aS1wbHVn aW5zLyouanNvbi4NCg0KRXhhbXBsZToNCnsNCiAgICAgICAgIm5hbWUiOiAidGVzdCIsDQogICAg ICAgICJ2ZXJzaW9uIjogIjEuMCIsDQogICAgICAgICJ1cmwiOiAiL3dlYmFkbWluL3dlYmFkbWlu L3BsdWdpbi90ZXN0L2Zvby5odG1sIiwNCiAgICAgICAgInBhdGgiOiAiL3RtcCIsDQogICAgICAg ICJjb25maWciOiB7ImEiOjEsICJiIjoyLCAiYyI6IDN9DQp9DQoNClRoZSBlbmdpbmUgcmVhZHMg YWxsIG9mIHRoZSAqLmpzb24gZmlsZXMgaW4gdGhhdCBkaXJlY3RvcnkgdG8gYnVpbGQgdGhlIGxp c3Qgb2Yga25vd24gcGx1Z2lucyBhbmQgZ2l2ZXMgdGhhdCBsaXN0IHRvIHRoZSB3ZWJhZG1pbi4N Cg0KV2hlbiB3ZWJhZG1pbiBsb2FkcyBhIHBsdWdpbiwgaXQgcmVxdWVzdHMgdGhlIFVSTCBnaXZl biBpbiB0aGUgcGx1Z2luIGNvbmZpZyBmaWxlLiAgVGhlICJwbHVnaW4iIFVSTCBpcyBtYXBwZWQg dG8gUGx1Z2luU291cmNlUGFnZSwgd2hpY2ggd2lsbCB0cmFuc2xhdGUgdGhlIGZpcnN0IHBhcnQg b2YgdGhlIHBhdGggKCJ0ZXN0IikgaW50byB3aGF0ZXZlciBwYXRoIGlzIHN0b3JlZCBpbiBwbHVn aW5Db25maWcgKCIvdG1wIikgaW4gdGhpcyBjYXNlLCBhbmQgdGhlbiBzZXJ2ZSB0aGUgc3RhdGlj IGZpbGUgKGUuZy4gIi90bXAvZm9vLmh0bWwiKS4NCg0KSSBkaWRuJ3QgdXNlIHRoZSByZW5kZXJQ bHVnaW5Tb3VyY2VQYWdlKCkgbWV0aG9kIGluIGZhdm9yIG9mIGp1c3Qgc2VydmluZyBhIHN0YXRp YyBmaWxlLCBidXQgSSBoYXZlIG5vIHN0cm9uZyBvcGluaW9uIG9uIHRoZSBtYXR0ZXIuICBIb3dl dmVyLCBhIHBsdWdpbiBtYXkgd2FudCB0byBzdG9yZSBzdGF0aWMgcmVzb3VyY2VzIGF0ICJwYXRo IiBhbmQgaGF2ZSB0aGUgZW5naW5lIHNlcnZlIHRob3NlIHJlc291cmNlcy4gIEJ5IGp1c3Qgc2Vy dmluZyBmaWxlcyB0aHJvdWdoIFBsdWdpblNvdXJjZVBhZ2UsIHdlIGRvbid0IG5lZWQgYW55IG90 aGVyIHNlcnZsZXRzIHRvIHByb3ZpZGUgdGhvc2UgcmVzb3VyY2VzLg0KDQpUaGVyZSBpcyBzdGls bCBhIGJpdCBvZiB3b3JrIHRvIGRvOg0KDQoxLiAgVGhlIHBsdWdpbiBjb25maWd1cmF0aW9uIGZp bGVzIHNob3VsZCBwcm9iYWJseSBoYXZlIGFuICJlbmFibGVkIiBmaWVsZCBhbmQgYW4gImFwaVZl cnNpb24iIGZpZWxkIHRoYXQgc2hvdWxkIGJlIGV4YW1pbmVkIHRvIGRldGVybWluZSB3aGV0aGVy IG9yIG5vdCB0byB1c2UgdGhlIHBsdWdpbi4NCg0KMi4gIEkgc3VzcGVjdCB0aGUgd2F5IEkndmUg bW9kaWZpZWQgUGx1Z2luU291cmNlUGFnZSBtYWtlcyBpdCB2dWxuZXJhYmxlIHRvIGRpcmVjdG9y eSBjbGltYmluZyBhdHRhY2tzLg0KDQozLiAgSXMgL3Vzci9zaGFyZS9vdmlydC1lbmdpbmUgdGhl IHJpZ2h0IHBsYWNlIGZvciB0aGUgcGx1Z2luIGNvbmZpZyBmaWxlcz8NCg0KTGV0IG1lIGtub3cg d2hhdCB5b3UgdGhpbmssDQotLUNocmlzDQo= --_000_6C8AC8C50E170C4E9B44D47B39B24A480931C86FSACEXCMBX04PRDh_ Content-Type: text/html; charset="utf-8" Content-Transfer-Encoding: base64 PGh0bWwgeG1sbnM6dj0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp2bWwiIHhtbG5zOm89InVy bjpzY2hlbWFzLW1pY3Jvc29mdC1jb206b2ZmaWNlOm9mZmljZSIgeG1sbnM6dz0idXJuOnNjaGVt YXMtbWljcm9zb2Z0LWNvbTpvZmZpY2U6d29yZCIgeG1sbnM6bT0iaHR0cDovL3NjaGVtYXMubWlj cm9zb2Z0LmNvbS9vZmZpY2UvMjAwNC8xMi9vbW1sIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv VFIvUkVDLWh0bWw0MCI+DQo8aGVhZD4NCjxtZXRhIGh0dHAtZXF1aXY9IkNvbnRlbnQtVHlwZSIg Y29udGVudD0idGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04Ij4NCjxtZXRhIG5hbWU9IkdlbmVyYXRv ciIgY29udGVudD0iTWljcm9zb2Z0IFdvcmQgMTQgKGZpbHRlcmVkIG1lZGl1bSkiPg0KPCEtLVtp ZiAhbXNvXT48c3R5bGU+dlw6KiB7YmVoYXZpb3I6dXJsKCNkZWZhdWx0I1ZNTCk7fQ0Kb1w6KiB7 YmVoYXZpb3I6dXJsKCNkZWZhdWx0I1ZNTCk7fQ0Kd1w6KiB7YmVoYXZpb3I6dXJsKCNkZWZhdWx0 I1ZNTCk7fQ0KLnNoYXBlIHtiZWhhdmlvcjp1cmwoI2RlZmF1bHQjVk1MKTt9DQo8L3N0eWxlPjwh W2VuZGlmXS0tPjxzdHlsZT48IS0tDQovKiBGb250IERlZmluaXRpb25zICovDQpAZm9udC1mYWNl DQoJe2ZvbnQtZmFtaWx5OkNhbGlicmk7DQoJcGFub3NlLTE6MiAxNSA1IDIgMiAyIDQgMyAyIDQ7 fQ0KQGZvbnQtZmFjZQ0KCXtmb250LWZhbWlseTpUYWhvbWE7DQoJcGFub3NlLTE6MiAxMSA2IDQg MyA1IDQgNCAyIDQ7fQ0KLyogU3R5bGUgRGVmaW5pdGlvbnMgKi8NCnAuTXNvTm9ybWFsLCBsaS5N c29Ob3JtYWwsIGRpdi5Nc29Ob3JtYWwNCgl7bWFyZ2luOjBpbjsNCgltYXJnaW4tYm90dG9tOi4w MDAxcHQ7DQoJZm9udC1zaXplOjEyLjBwdDsNCglmb250LWZhbWlseToiVGltZXMgTmV3IFJvbWFu Iiwic2VyaWYiO30NCmE6bGluaywgc3Bhbi5Nc29IeXBlcmxpbmsNCgl7bXNvLXN0eWxlLXByaW9y aXR5Ojk5Ow0KCWNvbG9yOmJsdWU7DQoJdGV4dC1kZWNvcmF0aW9uOnVuZGVybGluZTt9DQphOnZp c2l0ZWQsIHNwYW4uTXNvSHlwZXJsaW5rRm9sbG93ZWQNCgl7bXNvLXN0eWxlLXByaW9yaXR5Ojk5 Ow0KCWNvbG9yOnB1cnBsZTsNCgl0ZXh0LWRlY29yYXRpb246dW5kZXJsaW5lO30NCnANCgl7bXNv LXN0eWxlLXByaW9yaXR5Ojk5Ow0KCW1hcmdpbjowaW47DQoJbWFyZ2luLWJvdHRvbTouMDAwMXB0 Ow0KCWZvbnQtc2l6ZToxMi4wcHQ7DQoJZm9udC1mYW1pbHk6IlRpbWVzIE5ldyBSb21hbiIsInNl cmlmIjt9DQpzcGFuLkVtYWlsU3R5bGUxOQ0KCXttc28tc3R5bGUtdHlwZTpwZXJzb25hbC1yZXBs eTsNCglmb250LWZhbWlseToiQ2FsaWJyaSIsInNhbnMtc2VyaWYiOw0KCWNvbG9yOiMxRjQ5N0Q7 fQ0KLk1zb0NocERlZmF1bHQNCgl7bXNvLXN0eWxlLXR5cGU6ZXhwb3J0LW9ubHk7DQoJZm9udC1z aXplOjEwLjBwdDt9DQpAcGFnZSBXb3JkU2VjdGlvbjENCgl7c2l6ZTo4LjVpbiAxMS4waW47DQoJ bWFyZ2luOjEuMGluIDEuMGluIDEuMGluIDEuMGluO30NCmRpdi5Xb3JkU2VjdGlvbjENCgl7cGFn ZTpXb3JkU2VjdGlvbjE7fQ0KLyogTGlzdCBEZWZpbml0aW9ucyAqLw0KQGxpc3QgbDANCgl7bXNv LWxpc3QtaWQ6MzA2NzM5NjI2Ow0KCW1zby1saXN0LXRlbXBsYXRlLWlkczotMjExMjQ4MjQ1Mjt9 DQpvbA0KCXttYXJnaW4tYm90dG9tOjBpbjt9DQp1bA0KCXttYXJnaW4tYm90dG9tOjBpbjt9DQot LT48L3N0eWxlPjwhLS1baWYgZ3RlIG1zbyA5XT48eG1sPg0KPG86c2hhcGVkZWZhdWx0cyB2OmV4 dD0iZWRpdCIgc3BpZG1heD0iMTAyNiIgLz4NCjwveG1sPjwhW2VuZGlmXS0tPjwhLS1baWYgZ3Rl IG1zbyA5XT48eG1sPg0KPG86c2hhcGVsYXlvdXQgdjpleHQ9ImVkaXQiPg0KPG86aWRtYXAgdjpl eHQ9ImVkaXQiIGRhdGE9IjEiIC8+DQo8L286c2hhcGVsYXlvdXQ+PC94bWw+PCFbZW5kaWZdLS0+ DQo8L2hlYWQ+DQo8Ym9keSBsYW5nPSJFTi1VUyIgbGluaz0iYmx1ZSIgdmxpbms9InB1cnBsZSI+ DQo8ZGl2IGNsYXNzPSJXb3JkU2VjdGlvbjEiPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNwYW4g c3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7Zm9udC1mYW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90Oywm cXVvdDtzYW5zLXNlcmlmJnF1b3Q7O2NvbG9yOiMxRjQ5N0QiPlRoYW5rcyBDaHJpcyBhbmQgVm9q dGVjaCBmb3IgY29udGludWluZyB0aGlzIGRpc2N1c3Npb24uJm5ic3A7IEkgdGhpbmsgSeKAmW0g bWlzc2luZyB0aGUgbGluayBiZXR3ZWVuIHByb3ZpZGluZyB0aGUgcGx1Z2luIGRlZmluaXRpb24g ZmlsZSBhbmQgZGVmaW5pbmcgdGhlIHBsdWdpbnMuJm5ic3A7DQogSWYgSSB3YW50IHRvIGFkZCAz IG1haW4gdGFicyBhbmQgNiBjb250ZXh0IG1lbnVzLCBkbyBJIHByb3ZpZGUgOSBwbHVnaW4gZGVm aW5pdGlvbnM/Jm5ic3A7IE9yIGRvIEkgcHJvdmlkZSAxIHBsdWdpbiBkZWZpbml0aW9uIHdpdGgg bXVsdGlwbGUg4oCcdXJsc+KAnSB3aGVyZSBlYWNoIG9uZSBwb2ludHMgdG8gYSBkaXN0aW5jdCBw YXRoPzxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFuIHN0 eWxlPSJmb250LXNpemU6MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGlicmkmcXVvdDssJnF1 b3Q7c2Fucy1zZXJpZiZxdW90Oztjb2xvcjojMUY0OTdEIj48bzpwPiZuYnNwOzwvbzpwPjwvc3Bh bj48L3A+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjExLjBw dDtmb250LWZhbWlseTomcXVvdDtDYWxpYnJpJnF1b3Q7LCZxdW90O3NhbnMtc2VyaWYmcXVvdDs7 Y29sb3I6IzFGNDk3RCI+SWYg4oCcdXJs4oCdIGlzIGNvbmZpZ3VyZWQgdG8gcG9pbnQgdG8gYW4g ZXh0ZXJuYWwgYXBwbGljYXRpb24gc2VydmVyIGhvc3RpbmcgbXkgcGx1Z2luLCB3aGF0IGlzIHRo ZSBpbnRlbnQgb2Yg4oCccGF0aOKAnT8mbmJzcDsgRm9yIGV4YW1wbGUsIGlmIEkgY29uZmlndXJl IOKAnHVybOKAnSB0byBwb2ludA0KIHRvIOKAnGh0dHBzOi8vMTAuMTAuMTAuMTAvbXlwbHVnaW4v ZW50cnlwb2ludC5odG1s4oCdIHRoZW4gcHJlc3VtYWJseSB0aGUgYXBwbGljYXRpb24gc2VydmVy IHdpbGwgcmVuZGVyIHRoZSBwYWdlIGl0IG5lZWRzIGFzIGEgbWFpbiB0YWIgb3IgY29udGV4dCBt ZW51LiZuYnNwOyBJdCB3b3VsZCBoYXZlIG5vIG5lZWQgZm9yIOKAnHBhdGjigJ0gc2luY2UgYWxs IGRlcGVuZGVuY2llcyB3b3VsZCBiZSByZXNvbHZlZCBieSB0aGUgYXBwbGljYXRpb24gc2VydmVy LjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFuIHN0eWxl PSJmb250LXNpemU6MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGlicmkmcXVvdDssJnF1b3Q7 c2Fucy1zZXJpZiZxdW90Oztjb2xvcjojMUY0OTdEIj48bzpwPiZuYnNwOzwvbzpwPjwvc3Bhbj48 L3A+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjExLjBwdDtm b250LWZhbWlseTomcXVvdDtDYWxpYnJpJnF1b3Q7LCZxdW90O3NhbnMtc2VyaWYmcXVvdDs7Y29s b3I6IzFGNDk3RCI+R2VvcmdlPG86cD48L286cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05v cm1hbCI+PGEgbmFtZT0iX01haWxFbmRDb21wb3NlIj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjEx LjBwdDtmb250LWZhbWlseTomcXVvdDtDYWxpYnJpJnF1b3Q7LCZxdW90O3NhbnMtc2VyaWYmcXVv dDs7Y29sb3I6IzFGNDk3RCI+PG86cD4mbmJzcDs8L286cD48L3NwYW4+PC9hPjwvcD4NCjxkaXY+ DQo8ZGl2IHN0eWxlPSJib3JkZXI6bm9uZTtib3JkZXItdG9wOnNvbGlkICNCNUM0REYgMS4wcHQ7 cGFkZGluZzozLjBwdCAwaW4gMGluIDBpbiI+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48Yj48c3Bh biBzdHlsZT0iZm9udC1zaXplOjEwLjBwdDtmb250LWZhbWlseTomcXVvdDtUYWhvbWEmcXVvdDss JnF1b3Q7c2Fucy1zZXJpZiZxdW90OyI+RnJvbTo8L3NwYW4+PC9iPjxzcGFuIHN0eWxlPSJmb250 LXNpemU6MTAuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O1RhaG9tYSZxdW90OywmcXVvdDtzYW5zLXNl cmlmJnF1b3Q7Ij4gZW5naW5lLWRldmVsLWJvdW5jZXNAb3ZpcnQub3JnIFttYWlsdG86ZW5naW5l LWRldmVsLWJvdW5jZXNAb3ZpcnQub3JnXQ0KPGI+T24gQmVoYWxmIE9mIDwvYj5Wb2p0ZWNoIFN6 b2NzPGJyPg0KPGI+U2VudDo8L2I+IFRodXJzZGF5LCBBdWd1c3QgMjMsIDIwMTIgODoxNCBBTTxi cj4NCjxiPlRvOjwvYj4gQ2hyaXMgRnJhbnR6PGJyPg0KPGI+Q2M6PC9iPiBlbmdpbmUtZGV2ZWw8 YnI+DQo8Yj5TdWJqZWN0OjwvYj4gUmU6IFtFbmdpbmUtZGV2ZWxdIFVJIFBsdWdpbnMgY29uZmln dXJhdGlvbjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCjwvZGl2Pg0KPC9kaXY+DQo8cCBjbGFzcz0i TXNvTm9ybWFsIj48bzpwPiZuYnNwOzwvbzpwPjwvcD4NCjxkaXY+DQo8cCBjbGFzcz0iTXNvTm9y bWFsIj48c3BhbiBzdHlsZT0iY29sb3I6YmxhY2siPkhpIENocmlzLDxicj4NCjxicj4NCnRoYW5r cyBmb3IgdGFraW5nIHRoZSB0aW1lIHRvIG1ha2UgdGhpcyBwYXRjaCwgdGhlc2UgYXJlIHNvbWUg ZXhjZWxsZW50IGlkZWFzISAoQ0MnaW5nIGVuZ2luZS1kZXZlbCBzbyB0aGF0IHdlIGNhbiBkaXNj dXNzIHRoaXMgd2l0aCBvdGhlciBndXlzIGFzIHdlbGwpPGJyPg0KPGJyPg0KRmlyc3Qgb2YgYWxs LCBJIHJlYWxseSBsaWtlIHRoZSB3YXkgeW91IGRlc2lnbmVkIHBsdWdpbiBzb3VyY2UgcGFnZSBV UkxzIChnb2luZyB0aHJvdWdoDQo8ZW0+UGx1Z2luU291cmNlUGFnZVNlcnZsZXQ8L2VtPiksIGUu Zy4gJnF1b3Q7L3dlYmFkbWluL3dlYmFkbWluL3BsdWdpbi8mbHQ7cGx1Z2luTmFtZSZndDsvJmx0 O3BsdWdpblNvdXJjZVBhZ2UmZ3Q7Lmh0bWwmcXVvdDssIHBsdXMgdGhlIGNvbmNlcHQgb2YgJnF1 b3Q7cGF0aCZxdW90OyBKU09OIGF0dHJpYnV0ZS48YnI+DQo8YnI+DQo8aT5XZWJhZG1pbkR5bmFt aWNIb3N0aW5nU2VydmxldDwvaT4gbG9hZHMgYW5kIGNhY2hlcyBhbGwgcGx1Z2luIGRlZmluaXRp b25zICg8aT4qLmpzb248L2k+IGZpbGVzKSwgYW5kIGRpcmVjdGx5IGVtYmVkcyB0aGVtIGludG8g V2ViQWRtaW4gaG9zdCBwYWdlIGFzDQo8aT5wbHVnaW5EZWZpbml0aW9uczwvaT4gSmF2YVNjcmlw dCBvYmplY3QuIEknbSBhc3N1bWluZyB0aGF0IDxpPnBsdWdpbkRlZmluaXRpb25zPC9pPiBvYmpl Y3Qgd2lsbCBub3cgbG9vayBsaWtlIHRoaXM6PGJyPg0KPGJyPg0KPC9zcGFuPjxzcGFuIHN0eWxl PSJmb250LWZhbWlseTomcXVvdDtDb3VyaWVyIE5ldyZxdW90Oztjb2xvcjpibGFjayI+dmFyIHBs dWdpbkRlZmluaXRpb25zID0gezxicj4NCiZuYnNwOyZuYnNwOyZxdW90O3Rlc3QmcXVvdDs6IHs8 YnI+DQombmJzcDsmbmJzcDsgJm5ic3A7JnF1b3Q7bmFtZSZxdW90OzogJnF1b3Q7dGVzdCZxdW90 Oyw8YnI+DQombmJzcDsmbmJzcDsgJm5ic3A7JnF1b3Q7dmVyc2lvbiZxdW90OzogJnF1b3Q7MS4w JnF1b3Q7LDxicj4NCiZuYnNwOyZuYnNwOyAmbmJzcDsmcXVvdDt1cmwmcXVvdDs6ICZxdW90Oy93 ZWJhZG1pbi93ZWJhZG1pbi9wbHVnaW4vdGVzdC9mb28uaHRtbCZxdW90Oyw8YnI+DQombmJzcDsm bmJzcDsgJm5ic3A7JnF1b3Q7cGF0aCZxdW90OzogJnF1b3Q7L3RtcCZxdW90Oyw8YnI+DQombmJz cDsmbmJzcDsgJm5ic3A7JnF1b3Q7Y29uZmlnJnF1b3Q7OiB7JnF1b3Q7YSZxdW90OzoxLCAmcXVv dDtiJnF1b3Q7OjIsICZxdW90O2MmcXVvdDs6M308YnI+DQombmJzcDsmbmJzcDt9PGJyPg0KfTwv c3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6YmxhY2siPjxicj4NCjxicj4NCk9yaWdpbmFsbHksIHRo ZSA8aT5wbHVnaW5EZWZpbml0aW9uczwvaT4gb2JqZWN0IGxvb2tlZCBsaWtlIHRoaXM6PGJyPg0K PC9zcGFuPjxzcGFuIHN0eWxlPSJmb250LWZhbWlseTomcXVvdDtDb3VyaWVyIE5ldyZxdW90Oztj b2xvcjpibGFjayI+PGJyPg0KdmFyIHBsdWdpbkRlZmluaXRpb25zID0gezxicj4NCiZuYnNwOyZu YnNwOyZxdW90O3Rlc3QmcXVvdDs6ICZxdW90Oy93ZWJhZG1pbi93ZWJhZG1pbi9wbHVnaW4vdGVz dC9mb28uaHRtbCZxdW90OyAvLyBTaW1wbGUgcGx1Z2luTmFtZSAtJmd0OyBwbHVnaW5Tb3VyY2VQ YWdlVXJsIG1hcHBpbmdzPGJyPg0KfTwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6YmxhY2siPjxi cj4NCjxicj4NClRoaXMgaXMgYmVjYXVzZSBQbHVnaW5NYW5hZ2VyIChXZWJBZG1pbikgb25seSBu ZWVkcyA8aT5wbHVnaW5OYW1lPC9pPiAoJnF1b3Q7bmFtZSZxdW90OykgYW5kDQo8aT5wbHVnaW5T b3VyY2VQYWdlVXJsPC9pPiAoJnF1b3Q7dXJsJnF1b3Q7KSBkdXJpbmcgc3RhcnR1cCwgd2hlbiBj cmVhdGluZyBwbHVnaW4gaWZyYW1lLiBCdXQgdGhpcyBjYW4gYmUgY2hhbmdlZCA6KTxicj4NCjxi cj4NClBsdWdpbiAmcXVvdDt2ZXJzaW9uJnF1b3Q7IG1ha2VzIHNlbnNlLCBwbHVzIHRoZSBwbHVn aW4gY29uZmlndXJhdGlvbiBvYmplY3QgKCZxdW90O2NvbmZpZyZxdW90OykgY2FuIGJlIHVzZWZ1 bCBkaXJlY3RseSBvbiB0aGUgY2xpZW50LiBMZXQgbWUgZXhwbGFpbjo8YnI+DQo8YnI+DQpPcmln aW5hbGx5LCBwbHVnaW4gY29uZmlndXJhdGlvbiB3YXMgc3VwcG9zZWQgdG8gYmUgcGFzc2VkIHRv IGFjdHVhbCBwbHVnaW4gY29kZSAodGhyb3VnaCBpbW1lZGlhdGVseS1pbnZva2VkLWZ1bmN0aW9u LWV4cHJlc3Npb24sIG9yIElJRkUpLCBqdXN0IGxpa2UgdGhpczo8YnI+DQo8L3NwYW4+PHNwYW4g c3R5bGU9ImZvbnQtZmFtaWx5OiZxdW90O0NvdXJpZXIgTmV3JnF1b3Q7O2NvbG9yOmJsYWNrIj48 YnI+DQooZnVuY3Rpb24gKHBsdWdpbkFwaSwgcGx1Z2luQ29uZmlnKSB7IC8vIEphdmFTY3JpcHQg SUlGRTxicj4NCiZuYnNwOyZuYnNwOy8vIC4uLiBhY3R1YWwgcGx1Z2luIGNvZGUgLi4uPGJyPg0K fSkoPGJyPg0KJm5ic3A7Jm5ic3A7cGFyZW50LnBsdWdpbkFwaSwgLyogcmVmZXJlbmNlIHRvIGds b2JhbCBwbHVnaW5BcGkgb2JqZWN0ICovPGJyPg0KJm5ic3A7Jm5ic3A7eyZxdW90O2EmcXVvdDs6 MSwgJnF1b3Q7YiZxdW90OzoyLCAmcXVvdDtjJnF1b3Q7OjN9IC8qIGVtYmVkZGVkIHBsdWdpbiBj b25maWd1cmF0aW9uIGFzIEphdmFTY3JpcHQgb2JqZWN0ICovPGJyPg0KKTs8L3NwYW4+PHNwYW4g c3R5bGU9ImNvbG9yOmJsYWNrIj48YnI+DQo8YnI+DQpUaGUgd2hvbGUgcHVycG9zZSBvZiA8aT5Q bHVnaW5Tb3VyY2VQYWdlU2VydmxldDwvaT4gd2FzIHRvICZxdW90O3dyYXAmcXVvdDsgYWN0dWFs IHBsdWdpbiBjb2RlIGludG8gSFRNTCwgc28gdGhhdCB1c2VycyBkb24ndCBuZWVkIHRvIHdyaXRl IEhUTUwgcGFnZXMgZm9yIHRoZWlyIHBsdWdpbnMgbWFudWFsbHkuDQo8aT5QbHVnaW5Tb3VyY2VQ YWdlU2VydmxldDwvaT4gd291bGQgaGFuZGxlIGFueSBwbHVnaW4gZGVwZW5kZW5jaWVzIChwbGFj ZWQgaW50byBIVE1MIGhlYWQpLCB3aXRoIGFjdHVhbCBwbHVnaW4gY29kZSBiZWluZyB3cmFwcGVk IGludG8gSUlGRSwgYXMgc2hvd24gYWJvdmUuIFBsdWdpbiBjb25maWd1cmF0aW9uIHdhcyBtZWFu dCB0byBiZSBzdG9yZWQgaW4gYSBzZXBhcmF0ZSBmaWxlLCBlLmcuDQo8aT4mbHQ7cGx1Z2luTmFt ZSZndDstY29uZmlnLmpzb248L2k+LCBzbyB0aGF0IHVzZXJzIGNvdWxkIGNoYW5nZSB0aGUgZGVm YXVsdCBwbHVnaW4gY29uZmlndXJhdGlvbiB0byBzdWl0IHRoZWlyIG5lZWRzLjxicj4NCjxicj4N Ckluc3BpcmVkIGJ5IHlvdXIgcGF0Y2gsIHJhdGhlciB0aGFuIHJlYWRpbmcvZW1iZWRkaW5nIHBs dWdpbiBjb25maWd1cmF0aW9uIHdoZW4gc2VydmluZyBwbHVnaW4gSFRNTCBwYWdlICg8aT5QbHVn aW5Tb3VyY2VQYWdlU2VydmxldDwvaT4pLCBpdCdzIGV2ZW4gYmV0dGVyIHRvIGhhdmUgdGhlIHBs dWdpbiBjb25maWd1cmF0aW9uIGVtYmVkZGVkIGRpcmVjdGx5IGludG8gV2ViQWRtaW4gaG9zdCBw YWdlLCBhbG9uZyB3aXRoIGludHJvZHVjaW5nIG5ldw0KPGk+cGx1Z2luQXBpPC9pPiBmdW5jdGlv biB0byByZXRyaWV2ZSB0aGUgcGx1Z2luIGNvbmZpZ3VyYXRpb24gb2JqZWN0Ljxicj4NCjxicj4N CkJhc2VkIG9uIHRoaXMsIEkgc3VnZ2VzdCBmb2xsb3dpbmcgbW9kaWZpY2F0aW9ucyB0byB0aGUg b3JpZ2luYWwgY29uY2VwdDo8YnI+DQo8YnI+DQotIG1vZGlmeSBvcmlnaW5hbCA8aT5wbHVnaW5E ZWZpbml0aW9uczwvaT4gc3RydWN0dXJlLCBmcm9tIDxpPnBsdWdpbk5hbWUgLSZndDsgcGx1Z2lu U291cmNlUGFnZVVybDwvaT4sIHRvDQo8aT5wbHVnaW5OYW1lIC0mZ3Q7IHBsdWdpbkRlZk9iamVj dDwvaT48YnI+DQotIDxpPnBsdWdpbkRlZk9iamVjdDwvaT4gaXMgYmFzaWNhbGx5IGEgc3Vic2V0 IG9mIHBoeXNpY2FsIHBsdWdpbiBkZWZpbml0aW9uICg8aT50ZXN0Lmpzb248L2k+LCBzZWUgYmVs b3cpLCBzdWl0YWJsZSBmb3IgdXNlIG9uIHRoZSBjbGllbnQ8YnI+DQotIGFkZCBmb2xsb3dpbmcg YXR0cmlidXRlcyB0byA8aT5wbHVnaW5EZWZPYmplY3Q8L2k+OiA8aT52ZXJzaW9uPC9pPiwgPGk+ dXJsPC9pPiwNCjxpPmNvbmZpZzwvaT48YnI+DQombmJzcDsmbmJzcDsqIG5vdGUgIzE6IDxpPm5h bWU8L2k+IGlzIG5vdCBuZWVkZWQsIHNpbmNlIGl0J3MgYWxyZWFkeSB0aGUga2V5IG9mIDxpPnBs dWdpbk5hbWUgLSZndDsgcGx1Z2luRGVmT2JqZWN0PC9pPiBtYXBwaW5nPGJyPg0KJm5ic3A7Jm5i c3A7KiBub3RlICMyOiA8aT5wYXRoPC9pPiBpcyBub3QgbmVlZGVkIG9uIHRoZSBjbGllbnQgKG1v cmUgb24gdGhpcyBiZWxvdyk8YnI+DQotIGludHJvZHVjZSA8aT5wbHVnaW5BcGkuY29uZmlnKHBs dWdpbk5hbWUpPC9pPiBmdW5jdGlvbiBmb3IgcGx1Z2lucyB0byByZXRyaWV2ZSB0aGVpciBjb25m aWd1cmF0aW9uIG9iamVjdCwgYW5kIHJlbW92ZQ0KPGk+cGx1Z2luQ29uZmlnPC9pPiBwYXJhbWV0 ZXIgZnJvbSBtYWluIElJRkUgKGFzIHNob3duIGFib3ZlKTxicj4NCjxicj4NClthXSBQaHlzaWNh bCBwbHVnaW4gZGVmaW5pdGlvbiBmaWxlIChKU09OKSBtaWdodCBiZSBsb2NhdGVkIGF0IG9WaXJ0 ICZxdW90O0RhdGFEaXImcXVvdDssIGUuZy4NCjxpPi91c3Ivc2hhcmUvb3ZpcnQtZW5naW5lL3Vp LXBsdWdpbnMvdGVzdC5qc29uPC9pPiwgZm9yIGV4YW1wbGU6PGJyPg0KPC9zcGFuPjxzcGFuIHN0 eWxlPSJmb250LWZhbWlseTomcXVvdDtDb3VyaWVyIE5ldyZxdW90Oztjb2xvcjpibGFjayI+PGJy Pg0Kezxicj4NCiZuYnNwOyZuYnNwOyZxdW90O25hbWUmcXVvdDs6ICZxdW90O3Rlc3QmcXVvdDss PGJyPg0KJm5ic3A7Jm5ic3A7JnF1b3Q7dmVyc2lvbiZxdW90OzogJnF1b3Q7MS4wJnF1b3Q7LDxi cj4NCiZuYnNwOyZuYnNwOyZxdW90O3VybCZxdW90OzogJnF1b3Q7L3dlYmFkbWluL3dlYmFkbWlu L3BsdWdpbi90ZXN0L3N0YXJ0Lmh0bWwmcXVvdDssPGJyPg0KJm5ic3A7Jm5ic3A7JnF1b3Q7cGF0 aCZxdW90OzogJnF1b3Q7L3RtcCZxdW90Oyw8YnI+DQombmJzcDsmbmJzcDsmcXVvdDtjb25maWcm cXVvdDs6ICZxdW90O3Rlc3QtY29uZmlnLmpzb24mcXVvdDs8YnI+DQp9PC9zcGFuPjxzcGFuIHN0 eWxlPSJjb2xvcjpibGFjayI+PGJyPg0KPGJyPg0KW2JdIFBsdWdpbiBjb25maWd1cmF0aW9uIGZp bGUgKEpTT04pIG1pZ2h0IGJlIGxvY2F0ZWQgYXQgb1ZpcnQgJnF1b3Q7Q29uZmlnRGlyJnF1b3Q7 LCBlLmcuIDxpPg0KL2V0Yy9vdmlydC1lbmdpbmUvdWktcGx1Z2lucy90ZXN0LWNvbmZpZy5qc29u PC9pPiwgZm9yIGV4YW1wbGU6PGJyPg0KPC9zcGFuPjxzcGFuIHN0eWxlPSJmb250LWZhbWlseTom cXVvdDtDb3VyaWVyIE5ldyZxdW90Oztjb2xvcjpibGFjayI+PGJyPg0Kezxicj4NCiZuYnNwOyZu YnNwOyZxdW90O2EmcXVvdDs6MSwgJnF1b3Q7YiZxdW90OzoyLCAmcXVvdDtjJnF1b3Q7OjM8YnI+ DQp9PC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjpibGFjayI+PGJyPg0KPGJyPg0KW2NdIEZpbmFs bHksIHBsdWdpbiBzdGF0aWMgcmVzb3VyY2VzIChwbHVnaW4gc291cmNlIHBhZ2UsIGFjdHVhbCBw bHVnaW4gY29kZSwgcGx1Z2luIGRlcGVuZGVuY2llcywgQ1NTL2ltYWdlcywgZXRjLikgd291bGQg YmUgbG9jYXRlZCBhdA0KPGk+L3RtcDwvaT4gKGFzIHNob3duIGluIFthXSksIGZvciBleGFtcGxl Ojxicj4NCjwvc3Bhbj48c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6JnF1b3Q7Q291cmllciBOZXcm cXVvdDs7Y29sb3I6YmxhY2siPjxicj4NCi90bXAvc3RhcnQuaHRtbCAtJmd0OyBwbHVnaW4gc291 cmNlIHBhZ2UsIHVzZWQgdG8gbG9hZCBhY3R1YWwgcGx1Z2luIGNvZGU8YnI+DQovdG1wL3Rlc3Qu anMgLSZndDsgYWN0dWFsIHBsdWdpbiBjb2RlPGJyPg0KL3RtcC9kZXBzL2pxdWVyeS1taW4uanMg LSZndDsgc2ltdWxhdGUgM3JkIHBhcnR5IHBsdWdpbiBkZXBlbmRlbmN5PC9zcGFuPjxzcGFuIHN0 eWxlPSJjb2xvcjpibGFjayI+PGJyPg0KPGJyPg0KRm9yIGV4YW1wbGU6PGJyPg0KJnF1b3Q7L3dl YmFkbWluL3dlYmFkbWluL3BsdWdpbi90ZXN0L3N0YXJ0Lmh0bWwmcXVvdDsgd2lsbCBiZSBtYXBw ZWQgdG8gPGk+L3RtcC9zdGFydC5odG1sPC9pPjxicj4NCiZxdW90Oy93ZWJhZG1pbi93ZWJhZG1p bi9wbHVnaW4vdGVzdC9kZXBzL2pxdWVyeS1taW4uanMmcXVvdDsgd2lsbCBiZSBtYXBwZWQgdG8g PGk+L3RtcC9kZXBzL2pxdWVyeS1taW4uanM8L2k+PGJyPg0KPGJyPg0KVGhpcyBhcHByb2FjaCBo YXMgc29tZSBwcm9zIGFuZCBjb25zOjxicj4NCigmIzQzOykgcGx1Z2luIHN0YXRpYyByZXNvdXJj ZXMgY2FuIGJlIHNlcnZlZCB0aHJvdWdoIDxpPlBsdWdpblNvdXJjZVBhZ2VTZXJ2bGV0PC9pPiAo cHJldHR5IG11Y2ggbGlrZSBvVmlydCBkb2N1bWVudGF0aW9uIHJlc291cmNlcywgc2VydmVkIHRo cm91Z2ggb1ZpcnQgRW5naW5lIHJvb3Qgd2FyJ3MNCjxpPkZpbGVTZXJ2bGV0PC9pPik8YnI+DQoo JiM0MzspIHBsdWdpbiBhdXRob3IgaGFzIGNvbXBsZXRlIGNvbnRyb2wgb3ZlciBwbHVnaW4gc291 cmNlIHBhZ2U8YnI+DQooLSkgcGx1Z2luIGF1dGhvciBhY3R1YWxseSBuZWVkcyB0byB3cml0ZSBw bHVnaW4gc291cmNlIHBhZ2U8YnI+DQo8YnI+DQpPdmVyYWxsLCBJIHRoaW5rIHRoaXMgYXBwcm9h Y2ggaXMgYmV0dGVyIHRoYW4gdGhlIHByZXZpb3VzIG9uZSAod2hlcmUgPGk+UGx1Z2luU291cmNl UGFnZVNlcnZsZXQ8L2k+IHRvb2sgY2FyZSBvZiByZW5kZXJpbmcgcGx1Z2luIHNvdXJjZSBwYWdl LCBidXQgc2FjcmlmaWNlZCBzb21lIGZsZXhpYmlsaXR5KS48YnI+DQo8YnI+DQpCeSB0aGUgd2F5 LCBoZXJlJ3Mgd2hhdCB3b3VsZCBoYXBwZW4gYmVoaW5kIHRoZSBzY2VuZXM6PG86cD48L286cD48 L3NwYW4+PC9wPg0KPG9sIHN0YXJ0PSIxIiB0eXBlPSIxIj4NCjxsaSBjbGFzcz0iTXNvTm9ybWFs IiBzdHlsZT0iY29sb3I6YmxhY2s7bXNvLW1hcmdpbi10b3AtYWx0OmF1dG87bWFyZ2luLWJvdHRv bToxMi4wcHQ7bXNvLWxpc3Q6bDAgbGV2ZWwxIGxmbzEiPg0KdXNlciByZXF1ZXN0cyBXZWJBZG1p biBob3N0IHBhZ2UsIDxpPldlYmFkbWluRHluYW1pY0hvc3RpbmdTZXJ2bGV0PC9pPiBsb2FkcyBh bmQgY2FjaGVzIGFsbCBwbHVnaW4gZGVmaW5pdGlvbnMgW2FdICYjNDM7IHBsdWdpbiBjb25maWd1 cmF0aW9ucyBbYl0gYW5kIGNvbnN0cnVjdHMvZW1iZWRzIGFwcHJvcHJpYXRlDQo8aT5wbHVnaW5E ZWZpbml0aW9uczwvaT4gSmF2YVNjcmlwdCBvYmplY3Q8bzpwPjwvbzpwPjwvbGk+PGxpIGNsYXNz PSJNc29Ob3JtYWwiIHN0eWxlPSJjb2xvcjpibGFjazttc28tbWFyZ2luLXRvcC1hbHQ6YXV0bztt YXJnaW4tYm90dG9tOjEyLjBwdDttc28tbGlzdDpsMCBsZXZlbDEgbGZvMSI+DQpkdXJpbmcgV2Vi QWRtaW4gc3RhcnR1cCwgPGk+UGx1Z2luTWFuYWdlcjwvaT4gcmVnaXN0ZXJzIHRoZSBwbHVnaW4g KG5hbWUvdmVyc2lvbi91cmwvY29uZmlnKSwgYW5kIGNyZWF0ZXMvYXR0YWNoZXMgdGhlIGlmcmFt ZSB0byBmZXRjaCBwbHVnaW4gc291cmNlIHBhZ2UgYW5zeW5jaHJvbm91c2x5PG86cD48L286cD48 L2xpPjxsaSBjbGFzcz0iTXNvTm9ybWFsIiBzdHlsZT0iY29sb3I6YmxhY2s7bXNvLW1hcmdpbi10 b3AtYWx0OmF1dG87bWFyZ2luLWJvdHRvbToxMi4wcHQ7bXNvLWxpc3Q6bDAgbGV2ZWwxIGxmbzEi Pg0KPGk+UGx1Z2luU291cmNlUGFnZVNlcnZsZXQ8L2k+IGhhbmRsZXMgcGx1Z2luIHNvdXJjZSBw YWdlIHJlcXVlc3QsIHJlc29sdmVzIHRoZSBjb3JyZWN0IHBhdGggW2NdIGFuZCBqdXN0IHN0cmVh bXMgdGhlIGZpbGUgY29udGVudCBiYWNrIHRvIGNsaWVudDxvOnA+PC9vOnA+PC9saT48L29sPg0K PHAgY2xhc3M9Ik1zb05vcm1hbCIgc3R5bGU9Im1hcmdpbi1ib3R0b206MTIuMHB0Ij48c3BhbiBz dHlsZT0iY29sb3I6YmxhY2siPiZndDsgMS4gJm5ic3A7VGhlIHBsdWdpbiBjb25maWd1cmF0aW9u IGZpbGVzIHNob3VsZCBwcm9iYWJseSBoYXZlIGFuICZxdW90O2VuYWJsZWQmcXVvdDsgZmllbGQg YW5kIGFuICZxdW90O2FwaVZlcnNpb24mcXVvdDsgZmllbGQgdGhhdCBzaG91bGQgYmUgZXhhbWlu ZWQgdG8gZGV0ZXJtaW5lIHdoZXRoZXIgb3Igbm90IHRvIHVzZSB0aGUgcGx1Z2luLjxicj4NCjxi cj4NClNvdW5kcyBnb29kLCB3ZSBjYW4gaW1wbGVtZW50IHRoZXNlIGxhdGVyIG9uIDopPGJyPg0K PGJyPg0KJmd0OyAyLiAmbmJzcDtJIHN1c3BlY3QgdGhlIHdheSBJJ3ZlIG1vZGlmaWVkIFBsdWdp blNvdXJjZVBhZ2UgbWFrZXMgaXQgdnVsbmVyYWJsZSB0byBkaXJlY3RvcnkgY2xpbWJpbmcgYXR0 YWNrcy48YnI+DQo8YnI+DQpZZXMsIGJ1dCB3ZSBjYW4gZGVmZW5kIGFnYWluc3QgdGhlc2UsIHJl c3RyaWN0aW5nIGFjY2VzcyBvbmx5IHRvIHBsdWdpbidzICZxdW90O3BhdGgmcXVvdDsgYW5kIGl0 cyBzdWItZGlyZWN0b3JpZXMuPGJyPg0KPGJyPg0KJmd0OyAzLiAmbmJzcDtJcyAvdXNyL3NoYXJl L292aXJ0LWVuZ2luZSB0aGUgcmlnaHQgcGxhY2UgZm9yIHRoZSBwbHVnaW4gY29uZmlnIGZpbGVz Pzxicj4NCjxicj4NCkkgc3VwcG9zZSB5b3UgbWVhbiBwbHVnaW4gZGVmaW5pdGlvbiBmaWxlcyBb YV0sIGNhbm5vdCB0ZWxsIGZvciBzdXJlLCBidXQgd2UgY2FuIGNoYW5nZSB0aGlzIGFueXRpbWUg Oik8YnI+DQo8YnI+DQo8YnI+DQpDaHJpcywgcGxlYXNlIGxldCBtZSBrbm93IHdoYXQgeW91IHRo aW5rLCBhbmQgYWdhaW4gLSBtYW55IHRoYW5rcyBmb3Igc2VuZGluZyB0aGUgcGF0Y2ghPGJyPg0K PGJyPg0KPGJyPg0KUmVnYXJkcyw8YnI+DQpWb2p0ZWNoPGJyPg0KPGJyPg0KPG86cD48L286cD48 L3NwYW4+PC9wPg0KPGRpdiBjbGFzcz0iTXNvTm9ybWFsIiBhbGlnbj0iY2VudGVyIiBzdHlsZT0i dGV4dC1hbGlnbjpjZW50ZXIiPjxzcGFuIHN0eWxlPSJjb2xvcjpibGFjayI+DQo8aHIgc2l6ZT0i MiIgd2lkdGg9IjEwMCUiIGFsaWduPSJjZW50ZXIiIGlkPSJ6d2NociI+DQo8L3NwYW4+PC9kaXY+ DQo8cCBjbGFzcz0iTXNvTm9ybWFsIiBzdHlsZT0ibWFyZ2luLWJvdHRvbToxMi4wcHQiPjxzcGFu IHN0eWxlPSJjb2xvcjpibGFjayI+PGJyPg0KRnJvbTogJnF1b3Q7Q2hyaXMgRnJhbnR6JnF1b3Q7 ICZsdDs8YSBocmVmPSJtYWlsdG86Q2hyaXMuRnJhbnR6QGhwLmNvbSI+Q2hyaXMuRnJhbnR6QGhw LmNvbTwvYT4mZ3Q7PGJyPg0KVG86IDxhIGhyZWY9Im1haWx0bzp2c3pvY3NAcmVkaGF0LmNvbSI+ dnN6b2NzQHJlZGhhdC5jb208L2E+PGJyPg0KU2VudDogV2VkbmVzZGF5LCBBdWd1c3QgMjIsIDIw MTIgNzo1Njo0NSBQTTxicj4NClN1YmplY3Q6IFVJIFBsdWdpbnMgY29uZmlndXJhdGlvbjxicj4N Cjxicj4NClZvanRlY2gsPGJyPg0KPGJyPg0KSSBkZWNpZGVkIHRvIHdvcmsgb24gbWFraW5nIHRo ZSBwbHVnaW4gcGF0Y2ggYSBiaXQgbW9yZSBjb25maWd1cmFibGUsIGZvbGxvd2luZyBzb21lIG9m IHRoZSBpZGVhcyBleHByZXNzZWQgYnkgSXRhbWFyIGFuZCBvdGhlcnMgaW4gdGhlIG1lZXRpbmcg eWVzdGVyZGF5LiAmbmJzcDtUaGUgYXR0YWNoZWQgcGF0Y2ggaXMgYSBzaW1wbGUgZmlyc3QtYXR0 ZW1wdC48YnI+DQo8YnI+DQpQbHVnaW4gY29uZmlndXJhdGlvbnMgYXJlIHN0b3JlZCBpbiAvdXNy L3NoYXJlL292aXJ0LWVuZ2luZS91aS1wbHVnaW5zLyouanNvbi48YnI+DQo8YnI+DQpFeGFtcGxl Ojxicj4NCns8YnI+DQombmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsm bmJzcDsmcXVvdDtuYW1lJnF1b3Q7OiAmcXVvdDt0ZXN0JnF1b3Q7LDxicj4NCiZuYnNwOyZuYnNw OyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZxdW90O3ZlcnNpb24mcXVvdDs6 ICZxdW90OzEuMCZxdW90Oyw8YnI+DQombmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJz cDsmbmJzcDsmbmJzcDsmcXVvdDt1cmwmcXVvdDs6ICZxdW90Oy93ZWJhZG1pbi93ZWJhZG1pbi9w bHVnaW4vdGVzdC9mb28uaHRtbCZxdW90Oyw8YnI+DQombmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsm bmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmcXVvdDtwYXRoJnF1b3Q7OiAmcXVvdDsvdG1wJnF1b3Q7 LDxicj4NCiZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZx dW90O2NvbmZpZyZxdW90OzogeyZxdW90O2EmcXVvdDs6MSwgJnF1b3Q7YiZxdW90OzoyLCAmcXVv dDtjJnF1b3Q7OiAzfTxicj4NCn08YnI+DQo8YnI+DQpUaGUgZW5naW5lIHJlYWRzIGFsbCBvZiB0 aGUgKi5qc29uIGZpbGVzIGluIHRoYXQgZGlyZWN0b3J5IHRvIGJ1aWxkIHRoZSBsaXN0IG9mIGtu b3duIHBsdWdpbnMgYW5kIGdpdmVzIHRoYXQgbGlzdCB0byB0aGUgd2ViYWRtaW4uPGJyPg0KPGJy Pg0KV2hlbiB3ZWJhZG1pbiBsb2FkcyBhIHBsdWdpbiwgaXQgcmVxdWVzdHMgdGhlIFVSTCBnaXZl biBpbiB0aGUgcGx1Z2luIGNvbmZpZyBmaWxlLiAmbmJzcDtUaGUgJnF1b3Q7cGx1Z2luJnF1b3Q7 IFVSTCBpcyBtYXBwZWQgdG8gUGx1Z2luU291cmNlUGFnZSwgd2hpY2ggd2lsbCB0cmFuc2xhdGUg dGhlIGZpcnN0IHBhcnQgb2YgdGhlIHBhdGggKCZxdW90O3Rlc3QmcXVvdDspIGludG8gd2hhdGV2 ZXIgcGF0aCBpcyBzdG9yZWQgaW4gcGx1Z2luQ29uZmlnICgmcXVvdDsvdG1wJnF1b3Q7KSBpbiB0 aGlzIGNhc2UsDQogYW5kIHRoZW4gc2VydmUgdGhlIHN0YXRpYyBmaWxlIChlLmcuICZxdW90Oy90 bXAvZm9vLmh0bWwmcXVvdDspLjxicj4NCjxicj4NCkkgZGlkbid0IHVzZSB0aGUgcmVuZGVyUGx1 Z2luU291cmNlUGFnZSgpIG1ldGhvZCBpbiBmYXZvciBvZiBqdXN0IHNlcnZpbmcgYSBzdGF0aWMg ZmlsZSwgYnV0IEkgaGF2ZSBubyBzdHJvbmcgb3BpbmlvbiBvbiB0aGUgbWF0dGVyLiAmbmJzcDtI b3dldmVyLCBhIHBsdWdpbiBtYXkgd2FudCB0byBzdG9yZSBzdGF0aWMgcmVzb3VyY2VzIGF0ICZx dW90O3BhdGgmcXVvdDsgYW5kIGhhdmUgdGhlIGVuZ2luZSBzZXJ2ZSB0aG9zZSByZXNvdXJjZXMu ICZuYnNwO0J5IGp1c3Qgc2VydmluZw0KIGZpbGVzIHRocm91Z2ggUGx1Z2luU291cmNlUGFnZSwg d2UgZG9uJ3QgbmVlZCBhbnkgb3RoZXIgc2VydmxldHMgdG8gcHJvdmlkZSB0aG9zZSByZXNvdXJj ZXMuPGJyPg0KPGJyPg0KVGhlcmUgaXMgc3RpbGwgYSBiaXQgb2Ygd29yayB0byBkbzo8YnI+DQo8 YnI+DQoxLiAmbmJzcDtUaGUgcGx1Z2luIGNvbmZpZ3VyYXRpb24gZmlsZXMgc2hvdWxkIHByb2Jh Ymx5IGhhdmUgYW4gJnF1b3Q7ZW5hYmxlZCZxdW90OyBmaWVsZCBhbmQgYW4gJnF1b3Q7YXBpVmVy c2lvbiZxdW90OyBmaWVsZCB0aGF0IHNob3VsZCBiZSBleGFtaW5lZCB0byBkZXRlcm1pbmUgd2hl dGhlciBvciBub3QgdG8gdXNlIHRoZSBwbHVnaW4uPGJyPg0KPGJyPg0KMi4gJm5ic3A7SSBzdXNw ZWN0IHRoZSB3YXkgSSd2ZSBtb2RpZmllZCBQbHVnaW5Tb3VyY2VQYWdlIG1ha2VzIGl0IHZ1bG5l cmFibGUgdG8gZGlyZWN0b3J5IGNsaW1iaW5nIGF0dGFja3MuPGJyPg0KPGJyPg0KMy4gJm5ic3A7 SXMgL3Vzci9zaGFyZS9vdmlydC1lbmdpbmUgdGhlIHJpZ2h0IHBsYWNlIGZvciB0aGUgcGx1Z2lu IGNvbmZpZyBmaWxlcz88YnI+DQo8YnI+DQpMZXQgbWUga25vdyB3aGF0IHlvdSB0aGluayw8YnI+ DQotLUNocmlzPG86cD48L286cD48L3NwYW4+PC9wPg0KPC9kaXY+DQo8L2Rpdj4NCjwvYm9keT4N CjwvaHRtbD4NCg== --_000_6C8AC8C50E170C4E9B44D47B39B24A480931C86FSACEXCMBX04PRDh_--

------=_Part_14076039_700554763.1346074851578 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Hi George,=20
If I want to add 3 main tabs and 6 context menus, do I provide 9 plugin d= efinitions? Or do I provide 1 plugin definition with multiple =E2=80=9Curls= =E2=80=9D where each one points to a distinct path?=20
The JSON plugin definition file (maybe we should call it "plugin descriptor= ") should contain basic information about the plugin and how it's supposed = to be loaded by WebAdmin, for example:=20 {=20 "name": "test",=20 "version": "1.0",=20 "url": "/webadmin/webadmin/plugin/test/start.html", // Invokes the actual p= lugin code=20 ... more attributes ...=20 }=20 You can do many things inside one plugin (add multiple tabs, context menu i= tems, etc.) - you just need to add multiple event handler functions inside = the actual plugin code, for example:=20 pluginApi.plugins['test'] =3D {=20 // UiInit event handler function, the first function to be called on the pl= ugin=20 UiInit: function() {=20 pluginApi.ui.addMainTab('Custom Tab One', 'custom-tab-1', 'http://www.examp= le.com/1');=20 pluginApi.ui.addMainTab('Custom Tab Two', 'custom-tab-2', 'http://www.examp= le.com/2');=20 } ,=20 // HostContextMenu event handler function, just an example (not implemented= yet)=20 HostContextMenu: function(ctx) {=20 // 'ctx' represents the context of this event handler function, containing:= =20 // - information about host(s) currently selected=20 // - API (functions) to add custom context menu items=20 }=20 // Similarly, we could define VmContextMenu, etc. (everything inside one pl= ugin)=20 };=20
If =E2=80=9Curl=E2=80=9D is configured to point to an external applicatio= n server hosting my plugin, what is the intent of =E2=80=9Cpath=E2=80=9D? F= or example, if I configure =E2=80=9Curl=E2=80=9D to point to =E2=80=9Chttps= ://10.10.10.10/myplugin/entrypoint.html=E2=80=9D then presumably the applic= ation server will render the page it needs as a main tab or context menu. I= t would have no need for =E2=80=9Cpath=E2=80=9D since all dependencies woul= d be resolved by the application server.=20
You're right, the "path" attribute makes sense only when serving plugin res= ources (most importantly, plugin HTML page) through a special oVirt Engine = servlet (currently called PluginSourcePageServlet , should be renamed to so= mething like "PluginResourceServlet"). If "url" points to some external app= lication server, the "path" attribute can be omitted (optional attribute). = However, the "url" attribute denotes the location from which plugin HTML pa= ge will be requested by the plugin's iframe.=20 Regards,=20 Vojtech=20 ----- Original Message ----- From: "George Costea" <George.Costea@netapp.com>=20 To: "Vojtech Szocs" <vszocs@redhat.com>, "Chris Frantz" <Chris.Frantz@hp.co= m>=20 Cc: "engine-devel" <engine-devel@ovirt.org>=20 Sent: Thursday, August 23, 2012 3:09:05 PM=20 Subject: RE: [Engine-devel] UI Plugins configuration=20 Thanks Chris and Vojtech for continuing this discussion. I think I=E2=80=99= m missing the link between providing the plugin definition file and definin= g the plugins. If I want to add 3 main tabs and 6 context menus, do I provi= de 9 plugin definitions? Or do I provide 1 plugin definition with multiple = =E2=80=9Curls=E2=80=9D where each one points to a distinct path?=20 If =E2=80=9Curl=E2=80=9D is configured to point to an external application = server hosting my plugin, what is the intent of =E2=80=9Cpath=E2=80=9D? For= example, if I configure =E2=80=9Curl=E2=80=9D to point to =E2=80=9Chttps:/= /10.10.10.10/myplugin/entrypoint.html=E2=80=9D then presumably the applicat= ion server will render the page it needs as a main tab or context menu. It = would have no need for =E2=80=9Cpath=E2=80=9D since all dependencies would = be resolved by the application server.=20 George=20 From: engine-devel-bounces@ovirt.org [mailto:engine-devel-bounces@ovirt.org= ] On Behalf Of Vojtech Szocs=20 Sent: Thursday, August 23, 2012 8:14 AM=20 To: Chris Frantz=20 Cc: engine-devel=20 Subject: Re: [Engine-devel] UI Plugins configuration=20 Hi Chris,=20 thanks for taking the time to make this patch, these are some excellent ide= as! (CC'ing engine-devel so that we can discuss this with other guys as wel= l)=20 First of all, I really like the way you designed plugin source page URLs (g= oing through PluginSourcePageServlet ), e.g. "/webadmin/webadmin/plugin/<pl= uginName>/<pluginSourcePage>.html", plus the concept of "path" JSON attribu= te.=20 WebadminDynamicHostingServlet loads and caches all plugin definitions ( *.j= son files), and directly embeds them into WebAdmin host page as pluginDefin= itions JavaScript object. I'm assuming that pluginDefinitions object will n= ow look like this:=20 var pluginDefinitions =3D {=20 "test": {=20 "name": "test",=20 "version": "1.0",=20 "url": "/webadmin/webadmin/plugin/test/foo.html",=20 "path": "/tmp",=20 "config": {"a":1, "b":2, "c":3}=20 }=20 }=20 Originally, the pluginDefinitions object looked like this:=20 var pluginDefinitions =3D {=20 "test": "/webadmin/webadmin/plugin/test/foo.html" // Simple pluginName -> p= luginSourcePageUrl mappings=20 }=20 This is because PluginManager (WebAdmin) only needs pluginName ("name") and= pluginSourcePageUrl ("url") during startup, when creating plugin iframe. B= ut this can be changed :)=20 Plugin "version" makes sense, plus the plugin configuration object ("config= ") can be useful directly on the client. Let me explain:=20 Originally, plugin configuration was supposed to be passed to actual plugin= code (through immediately-invoked-function-expression, or IIFE), just like= this:=20 (function (pluginApi, pluginConfig) { // JavaScript IIFE=20 // ... actual plugin code ...=20 })(=20 parent.pluginApi, /* reference to global pluginApi object */=20 {"a":1, "b":2, "c":3} /* embedded plugin configuration as JavaScript object= */=20 );=20 The whole purpose of PluginSourcePageServlet was to "wrap" actual plugin co= de into HTML, so that users don't need to write HTML pages for their plugin= s manually. PluginSourcePageServlet would handle any plugin dependencies (p= laced into HTML head), with actual plugin code being wrapped into IIFE, as = shown above. Plugin configuration was meant to be stored in a separate file= , e.g. <pluginName>-config.json , so that users could change the default pl= ugin configuration to suit their needs.=20 Inspired by your patch, rather than reading/embedding plugin configuration = when serving plugin HTML page ( PluginSourcePageServlet ), it's even better= to have the plugin configuration embedded directly into WebAdmin host page= , along with introducing new pluginApi function to retrieve the plugin conf= iguration object.=20 Based on this, I suggest following modifications to the original concept:= =20 - modify original pluginDefinitions structure, from pluginName -> pluginSou= rcePageUrl , to pluginName -> pluginDefObject=20 - pluginDefObject is basically a subset of physical plugin definition ( tes= t.json , see below), suitable for use on the client=20 - add following attributes to pluginDefObject : version , url , config=20 * note #1: name is not needed, since it's already the key of pluginName -> = pluginDefObject mapping=20 * note #2: path is not needed on the client (more on this below)=20 - introduce pluginApi.config(pluginName) function for plugins to retrieve t= heir configuration object, and remove pluginConfig parameter from main IIFE= (as shown above)=20 [a] Physical plugin definition file (JSON) might be located at oVirt "DataD= ir", e.g. /usr/share/ovirt-engine/ui-plugins/test.json , for example:=20 {=20 "name": "test",=20 "version": "1.0",=20 "url": "/webadmin/webadmin/plugin/test/start.html",=20 "path": "/tmp",=20 "config": "test-config.json"=20 }=20 [b] Plugin configuration file (JSON) might be located at oVirt "ConfigDir",= e.g. /etc/ovirt-engine/ui-plugins/test-config.json , for example:=20 {=20 "a":1, "b":2, "c":3=20 }=20 [c] Finally, plugin static resources (plugin source page, actual plugin cod= e, plugin dependencies, CSS/images, etc.) would be located at /tmp (as show= n in [a]), for example:=20 /tmp/start.html -> plugin source page, used to load actual plugin code=20 /tmp/test.js -> actual plugin code=20 /tmp/deps/jquery-min.js -> simulate 3rd party plugin dependency=20 For example:=20 "/webadmin/webadmin/plugin/test/start.html" will be mapped to /tmp/start.ht= ml=20 "/webadmin/webadmin/plugin/test/deps/jquery-min.js" will be mapped to /tmp/= deps/jquery-min.js=20 This approach has some pros and cons:=20 (+) plugin static resources can be served through PluginSourcePageServlet (= pretty much like oVirt documentation resources, served through oVirt Engine= root war's FileServlet )=20 (+) plugin author has complete control over plugin source page=20 (-) plugin author actually needs to write plugin source page=20 Overall, I think this approach is better than the previous one (where Plugi= nSourcePageServlet took care of rendering plugin source page, but sacrifice= d some flexibility).=20 By the way, here's what would happen behind the scenes:=20 1. user requests WebAdmin host page, WebadminDynamicHostingServlet load= s and caches all plugin definitions [a] + plugin configurations [b] and con= structs/embeds appropriate pluginDefinitions JavaScript object=20 2. during WebAdmin startup, PluginManager registers the plugin (name/ve= rsion/url/config), and creates/attaches the iframe to fetch plugin source p= age ansynchronously=20 3. PluginSourcePageServlet handles plugin source page request, resolves= the correct path [c] and just streams the file content back to client=20
1. The plugin configuration files should probably have an "enabled" field= and an "apiVersion" field that should be examined to determine whether or = not to use the plugin.=20
Sounds good, we can implement these later on :)=20
2. I suspect the way I've modified PluginSourcePage makes it vulnerable t= o directory climbing attacks.=20
Yes, but we can defend against these, restricting access only to plugin's "= path" and its sub-directories.=20
3. Is /usr/share/ovirt-engine the right place for the plugin config files= ?=20
I suppose you mean plugin definition files [a], cannot tell for sure, but w= e can change this anytime :)=20 Chris, please let me know what you think, and again - many thanks for sendi= ng the patch!=20 Regards,=20 Vojtech=20 ----- Original Message ----- From: "Chris Frantz" < Chris.Frantz@hp.com >=20 To: vszocs@redhat.com=20 Sent: Wednesday, August 22, 2012 7:56:45 PM=20 Subject: UI Plugins configuration=20 Vojtech,=20 I decided to work on making the plugin patch a bit more configurable, follo= wing some of the ideas expressed by Itamar and others in the meeting yester= day. The attached patch is a simple first-attempt.=20 Plugin configurations are stored in /usr/share/ovirt-engine/ui-plugins/*.js= on.=20 Example:=20 {=20 "name": "test",=20 "version": "1.0",=20 "url": "/webadmin/webadmin/plugin/test/foo.html",=20 "path": "/tmp",=20 "config": {"a":1, "b":2, "c": 3}=20 }=20 The engine reads all of the *.json files in that directory to build the lis= t of known plugins and gives that list to the webadmin.=20 When webadmin loads a plugin, it requests the URL given in the plugin confi= g file. The "plugin" URL is mapped to PluginSourcePage, which will translat= e the first part of the path ("test") into whatever path is stored in plugi= nConfig ("/tmp") in this case, and then serve the static file (e.g. "/tmp/f= oo.html").=20 I didn't use the renderPluginSourcePage() method in favor of just serving a= static file, but I have no strong opinion on the matter. However, a plugin= may want to store static resources at "path" and have the engine serve tho= se resources. By just serving files through PluginSourcePage, we don't need= any other servlets to provide those resources.=20 There is still a bit of work to do:=20 1. The plugin configuration files should probably have an "enabled" field a= nd an "apiVersion" field that should be examined to determine whether or no= t to use the plugin.=20 2. I suspect the way I've modified PluginSourcePage makes it vulnerable to = directory climbing attacks.=20 3. Is /usr/share/ovirt-engine the right place for the plugin config files?= =20 Let me know what you think,=20 --Chris=20 ------=_Part_14076039_700554763.1346074851578 Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable <html><head><style type=3D'text/css'>p { margin: 0; }</style></head><body><= div style=3D'font-family: times new roman,new york,times,serif; font-size: = 12pt; color: #000000'>Hi George,<br><br><span style=3D"font-size:11.0pt;fon= t-family:"Calibri","sans-serif";color:#1F497D">> If I want to add 3 main tabs and 6 context menus, do I provide 9 plugin=20 definitions? Or do I provide 1 plugin definition with multiple =E2=80= =9Curls=E2=80=9D=20 where each one points to a distinct path?</span><br><br>The JSON plugin def= inition file (maybe we should call it "plugin descriptor") should contain b= asic information about the plugin and how it's supposed to be loaded by Web= Admin, for example:<br><br style=3D"font-family: courier new,courier,monaco= ,monospace,sans-serif;"><span style=3D"font-family: courier new,courier,mon= aco,monospace,sans-serif;">{</span><br style=3D"font-family: courier new,co= urier,monaco,monospace,sans-serif;"><span style=3D"font-family: courier new= ,courier,monaco,monospace,sans-serif;"> "name": "test",</span><br sty= le=3D"font-family: courier new,courier,monaco,monospace,sans-serif;"><span = style=3D"font-family: courier new,courier,monaco,monospace,sans-serif;">&nb= sp; "version": "1.0",</span><br style=3D"font-family: courier new,courier,m= onaco,monospace,sans-serif;"><span style=3D"font-family: courier new,courie= r,monaco,monospace,sans-serif;"> "url": "/webadmin/webadmin/plugin/te= st/start.html", // Invokes the actual plugin code</span><br style=3D"font-f= amily: courier new,courier,monaco,monospace,sans-serif;"><span style=3D"fon= t-family: courier new,courier,monaco,monospace,sans-serif;"> ... more= attributes ...</span><br style=3D"font-family: courier new,courier,monaco,= monospace,sans-serif;"><span style=3D"font-family: courier new,courier,mona= co,monospace,sans-serif;">}</span><br><br>You can do many things inside one= plugin (add multiple tabs, context menu items, etc.) - you just need to ad= d multiple event handler functions inside the actual plugin code, for examp= le:<br><br><span style=3D"font-family: courier new,courier,monaco,monospace= ,sans-serif;">pluginApi.plugins['test'] =3D {</span><br><br style=3D"font-f= amily: courier new,courier,monaco,monospace,sans-serif;"><span style=3D"fon= t-family: courier new,courier,monaco,monospace,sans-serif;"> // UiIni= t event handler function, the first function to be called on the plugin</sp= an><br style=3D"font-family: courier new,courier,monaco,monospace,sans-seri= f;"><span style=3D"font-family: courier new,courier,monaco,monospace,sans-s= erif;"> UiInit: function() {</span><br style=3D"font-family: courier = new,courier,monaco,monospace,sans-serif;"><span style=3D"font-family: couri= er new,courier,monaco,monospace,sans-serif;"> pluginApi.u= i.addMainTab('Custom Tab One', 'custom-tab-1', 'http://www.example.com/1');= </span><br style=3D"font-family: courier new,courier,monaco,monospace,sans-= serif;"><span style=3D"font-family: courier new,courier,monaco,monospace,sa= ns-serif;"> pluginApi.ui.addMainTab('Custom Tab Two', 'cu= stom-tab-2', 'http://www.example.com/2');</span><br style=3D"font-family: c= ourier new,courier,monaco,monospace,sans-serif;"><span style=3D"font-family= : courier new,courier,monaco,monospace,sans-serif;"> },</span><br sty= le=3D"font-family: courier new,courier,monaco,monospace,sans-serif;"><br st= yle=3D"font-family: courier new,courier,monaco,monospace,sans-serif;"><span= style=3D"font-family: courier new,courier,monaco,monospace,sans-serif;">&n= bsp; // HostContextMenu event handler function, just an example (not implem= ented yet)</span><br style=3D"font-family: courier new,courier,monaco,monos= pace,sans-serif;"><span style=3D"font-family: courier new,courier,monaco,mo= nospace,sans-serif;"> HostContextMenu: function(ctx) {</span><br><spa= n style=3D"font-family: courier new,courier,monaco,monospace,sans-serif;">&= nbsp; // 'ctx' represents the context of this event handler fun= ction, containing:<br> // - information about host(s) cur= rently selected<br style=3D"font-family: courier new,courier,monaco,monospa= ce,sans-serif;"></span><span style=3D"font-family: courier new,courier,mona= co,monospace,sans-serif;"></span><span style=3D"font-family: courier new,co= urier,monaco,monospace,sans-serif;"> // - API (functions) to a= dd custom context menu items<br></span><span style=3D"font-family: courier = new,courier,monaco,monospace,sans-serif;"> }</span><br style=3D"font-= family: courier new,courier,monaco,monospace,sans-serif;"><br style=3D"font= -family: courier new,courier,monaco,monospace,sans-serif;"><span style=3D"f= ont-family: courier new,courier,monaco,monospace,sans-serif;"> // Sim= ilarly, we could define VmContextMenu, etc. (everything inside one plugin)<= /span><br style=3D"font-family: courier new,courier,monaco,monospace,sans-s= erif;"><br style=3D"font-family: courier new,courier,monaco,monospace,sans-= serif;"><span style=3D"font-family: courier new,courier,monaco,monospace,sa= ns-serif;">};</span><br><br><span style=3D"font-size:11.0pt;font-family:&qu= ot;Calibri","sans-serif";color:#1F497D">> If =E2=80=9Curl=E2=80=9D is configured to point to an external application se= rver hosting=20 my plugin, what is the intent of =E2=80=9Cpath=E2=80=9D? For example,= if I configure=20 =E2=80=9Curl=E2=80=9D to point to =E2=80=9Chttps://10.10.10.10/myplugin/entrypoint.html=E2=80=9D then pre= sumably the application server will render the page it needs as a main tab = or=20 context menu. It would have no need for =E2=80=9Cpath=E2=80=9D since = all dependencies=20 would be resolved by the application server.</span><br><br>You're right, th= e "path" attribute makes sense only when serving plugin resources (most imp= ortantly, plugin HTML page) through a special oVirt Engine servlet (current= ly called <em>PluginSourcePageServlet</em>, should be renamed to something = like "PluginResourceServlet"). If "url" points to some external application= server, the "path" attribute can be omitted (optional attribute). However,= the "url" attribute denotes the location from which plugin HTML page will = be requested by the plugin's iframe.<br><br>Regards,<br>Vojtech<br><br><br>= <hr id=3D"zwchr"><div style=3D"color:#000;font-weight:normal;font-style:nor= mal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:1= 2pt;"><b>From: </b>"George Costea" <George.Costea@netapp.com><br><b>T= o: </b>"Vojtech Szocs" <vszocs@redhat.com>, "Chris Frantz" <Chris.= Frantz@hp.com><br><b>Cc: </b>"engine-devel" <engine-devel@ovirt.org&g= t;<br><b>Sent: </b>Thursday, August 23, 2012 3:09:05 PM<br><b>Subject: </b>= RE: [Engine-devel] UI Plugins configuration<br><br> <style><!-- @font-face =09{font-family:Calibri; =09panose-1:2 15 5 2 2 2 4 3 2 4;} @font-face =09{font-family:Tahoma; =09panose-1:2 11 6 4 3 5 4 4 2 4;} p.MsoNormal, li.MsoNormal, div.MsoNormal =09{margin:0in; =09margin-bottom:.0001pt; =09font-size:12.0pt; =09font-family:"Times New Roman","serif";} a:link, span.MsoHyperlink =09{mso-style-priority:99; =09color:blue; =09text-decoration:underline;} a:visited, span.MsoHyperlinkFollowed =09{mso-style-priority:99; =09color:purple; =09text-decoration:underline;} p =09{mso-style-priority:99; =09margin:0in; =09margin-bottom:.0001pt; =09font-size:12.0pt; =09font-family:"Times New Roman","serif";} span.EmailStyle19 =09{mso-style-type:personal-reply; =09font-family:"Calibri","sans-serif"; =09color:#1F497D;} .MsoChpDefault =09{mso-style-type:export-only; =09font-size:10.0pt;} @page WordSection1 =09{size:8.5in 11.0in; =09margin:1.0in 1.0in 1.0in 1.0in;} div.WordSection1 =09{page:WordSection1;} @list l0 =09{mso-list-id:306739626; =09mso-list-template-ids:-2112482452;} ol =09{margin-bottom:0in;} ul =09{margin-bottom:0in;} --></style> <div class=3D"WordSection1"> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D">Thanks Chris and Vojtech = for continuing this discussion. I think I=E2=80=99m missing the link = between providing the plugin definition file and defining the plugins. = ; If I want to add 3 main tabs and 6 context menus, do I provide 9 plugin de= finitions? Or do I provide 1 plugin definition with multiple =E2=80= =9Curls=E2=80=9D where each one points to a distinct path?</span></p> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D"> </span></p> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D">If =E2=80=9Curl=E2=80=9D = is configured to point to an external application server hosting my plugin,= what is the intent of =E2=80=9Cpath=E2=80=9D? For example, if I conf= igure =E2=80=9Curl=E2=80=9D to point to =E2=80=9Chttps://10.10.10.10/myplugin/entrypoint.html=E2=80=9D then pre= sumably the application server will render the page it needs as a main tab = or context menu. It would have no need for =E2=80=9Cpath=E2=80=9D sin= ce all dependencies would be resolved by the application server.</span></p> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D"> </span></p> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D">George</span></p> <p class=3D"MsoNormal"><a name=3D"_MailEndCompose"><span style=3D"font-size= :11.0pt;font-family:"Calibri","sans-serif";color:#1F497= D"> </span></a></p> <div> <div style=3D"border:none;border-top:solid #B5C4DF 1.0pt;padding:3.0pt 0in = 0in 0in"> <p class=3D"MsoNormal"><b><span style=3D"font-size:10.0pt;font-family:"= ;Tahoma","sans-serif"">From:</span></b><span style=3D"font-s= ize:10.0pt;font-family:"Tahoma","sans-serif""> engine-d= evel-bounces@ovirt.org [mailto:engine-devel-bounces@ovirt.org] <b>On Behalf Of </b>Vojtech Szocs<br> <b>Sent:</b> Thursday, August 23, 2012 8:14 AM<br> <b>To:</b> Chris Frantz<br> <b>Cc:</b> engine-devel<br> <b>Subject:</b> Re: [Engine-devel] UI Plugins configuration</span></p> </div> </div> <p class=3D"MsoNormal"> </p> <div> <p class=3D"MsoNormal"><span style=3D"color:black">Hi Chris,<br> <br> thanks for taking the time to make this patch, these are some excellent ide= as! (CC'ing engine-devel so that we can discuss this with other guys as wel= l)<br> <br> First of all, I really like the way you designed plugin source page URLs (g= oing through <em>PluginSourcePageServlet</em>), e.g. "/webadmin/webadmin/plugin/<plug= inName>/<pluginSourcePage>.html", plus the concept of "path" JSON = attribute.<br> <br> <i>WebadminDynamicHostingServlet</i> loads and caches all plugin definition= s (<i>*.json</i> files), and directly embeds them into WebAdmin host page a= s <i>pluginDefinitions</i> JavaScript object. I'm assuming that <i>pluginDefi= nitions</i> object will now look like this:<br> <br> </span><span style=3D"font-family:"Courier New";color:black">var = pluginDefinitions =3D {<br> "test": {<br> "name": "test",<br> "version": "1.0",<br> "url": "/webadmin/webadmin/plugin/test/foo.html",<br> "path": "/tmp",<br> "config": {"a":1, "b":2, "c":3}<br> }<br> }</span><span style=3D"color:black"><br> <br> Originally, the <i>pluginDefinitions</i> object looked like this:<br> </span><span style=3D"font-family:"Courier New";color:black"><br> var pluginDefinitions =3D {<br> "test": "/webadmin/webadmin/plugin/test/foo.html" // Simple plu= ginName -> pluginSourcePageUrl mappings<br> }</span><span style=3D"color:black"><br> <br> This is because PluginManager (WebAdmin) only needs <i>pluginName</i> ("nam= e") and <i>pluginSourcePageUrl</i> ("url") during startup, when creating plugin ifr= ame. But this can be changed :)<br> <br> Plugin "version" makes sense, plus the plugin configuration object ("config= ") can be useful directly on the client. Let me explain:<br> <br> Originally, plugin configuration was supposed to be passed to actual plugin= code (through immediately-invoked-function-expression, or IIFE), just like= this:<br> </span><span style=3D"font-family:"Courier New";color:black"><br> (function (pluginApi, pluginConfig) { // JavaScript IIFE<br> // ... actual plugin code ...<br> })(<br> parent.pluginApi, /* reference to global pluginApi object */<br=
{"a":1, "b":2, "c":3} /* embedded plugin configuration as JavaS= cript object */<br> );</span><span style=3D"color:black"><br> <br> The whole purpose of <i>PluginSourcePageServlet</i> was to "wrap" actual pl= ugin code into HTML, so that users don't need to write HTML pages for their= plugins manually. <i>PluginSourcePageServlet</i> would handle any plugin dependencies (placed= into HTML head), with actual plugin code being wrapped into IIFE, as shown= above. Plugin configuration was meant to be stored in a separate file, e.g= . <i><pluginName>-config.json</i>, so that users could change the defau= lt plugin configuration to suit their needs.<br> <br> Inspired by your patch, rather than reading/embedding plugin configuration = when serving plugin HTML page (<i>PluginSourcePageServlet</i>), it's even b= etter to have the plugin configuration embedded directly into WebAdmin host= page, along with introducing new <i>pluginApi</i> function to retrieve the plugin configuration object.<br> <br> Based on this, I suggest following modifications to the original concept:<b= r> <br> - modify original <i>pluginDefinitions</i> structure, from <i>pluginName -&= gt; pluginSourcePageUrl</i>, to <i>pluginName -> pluginDefObject</i><br> - <i>pluginDefObject</i> is basically a subset of physical plugin definitio= n (<i>test.json</i>, see below), suitable for use on the client<br> - add following attributes to <i>pluginDefObject</i>: <i>version</i>, <i>ur= l</i>, <i>config</i><br> * note #1: <i>name</i> is not needed, since it's already the ke= y of <i>pluginName -> pluginDefObject</i> mapping<br> * note #2: <i>path</i> is not needed on the client (more on thi= s below)<br> - introduce <i>pluginApi.config(pluginName)</i> function for plugins to ret= rieve their configuration object, and remove <i>pluginConfig</i> parameter from main IIFE (as shown above)<br> <br> [a] Physical plugin definition file (JSON) might be located at oVirt "DataD= ir", e.g. <i>/usr/share/ovirt-engine/ui-plugins/test.json</i>, for example:<br> </span><span style=3D"font-family:"Courier New";color:black"><br> {<br> "name": "test",<br> "version": "1.0",<br> "url": "/webadmin/webadmin/plugin/test/start.html",<br> "path": "/tmp",<br> "config": "test-config.json"<br> }</span><span style=3D"color:black"><br> <br> [b] Plugin configuration file (JSON) might be located at oVirt "ConfigDir",= e.g. <i> /etc/ovirt-engine/ui-plugins/test-config.json</i>, for example:<br> </span><span style=3D"font-family:"Courier New";color:black"><br> {<br> "a":1, "b":2, "c":3<br> }</span><span style=3D"color:black"><br> <br> [c] Finally, plugin static resources (plugin source page, actual plugin cod= e, plugin dependencies, CSS/images, etc.) would be located at <i>/tmp</i> (as shown in [a]), for example:<br> </span><span style=3D"font-family:"Courier New";color:black"><br> /tmp/start.html -> plugin source page, used to load actual plugin code<b= r> /tmp/test.js -> actual plugin code<br> /tmp/deps/jquery-min.js -> simulate 3rd party plugin dependency</span><s= pan style=3D"color:black"><br> <br> For example:<br> "/webadmin/webadmin/plugin/test/start.html" will be mapped to <i>/tmp/start= .html</i><br> "/webadmin/webadmin/plugin/test/deps/jquery-min.js" will be mapped to <i>/t= mp/deps/jquery-min.js</i><br> <br> This approach has some pros and cons:<br> (+) plugin static resources can be served through <i>PluginSourcePageServle= t</i> (pretty much like oVirt documentation resources, served through oVirt= Engine root war's <i>FileServlet</i>)<br> (+) plugin author has complete control over plugin source page<br> (-) plugin author actually needs to write plugin source page<br> <br> Overall, I think this approach is better than the previous one (where <i>Pl= uginSourcePageServlet</i> took care of rendering plugin source page, but sa= crificed some flexibility).<br> <br> By the way, here's what would happen behind the scenes:</span></p> <ol start=3D"1" type=3D"1"> <li class=3D"MsoNormal" style=3D"color:black;mso-margin-top-alt:auto;margin= -bottom:12.0pt;mso-list:l0 level1 lfo1"> user requests WebAdmin host page, <i>WebadminDynamicHostingServlet</i> load= s and caches all plugin definitions [a] + plugin configurations [b] and con= structs/embeds appropriate <i>pluginDefinitions</i> JavaScript object</li><li class=3D"MsoNormal" styl= e=3D"color:black;mso-margin-top-alt:auto;margin-bottom:12.0pt;mso-list:l0 l= evel1 lfo1"> during WebAdmin startup, <i>PluginManager</i> registers the plugin (name/ve= rsion/url/config), and creates/attaches the iframe to fetch plugin source p= age ansynchronously</li><li class=3D"MsoNormal" style=3D"color:black;mso-ma= rgin-top-alt:auto;margin-bottom:12.0pt;mso-list:l0 level1 lfo1"> <i>PluginSourcePageServlet</i> handles plugin source page request, resolves= the correct path [c] and just streams the file content back to client</li>= </ol> <p class=3D"MsoNormal" style=3D"margin-bottom:12.0pt"><span style=3D"color:= black">> 1. The plugin configuration files should probably have an= "enabled" field and an "apiVersion" field that should be examined to deter= mine whether or not to use the plugin.<br> <br> Sounds good, we can implement these later on :)<br> <br> > 2. I suspect the way I've modified PluginSourcePage makes it vul= nerable to directory climbing attacks.<br> <br> Yes, but we can defend against these, restricting access only to plugin's "= path" and its sub-directories.<br> <br> > 3. Is /usr/share/ovirt-engine the right place for the plugin con= fig files?<br> <br> I suppose you mean plugin definition files [a], cannot tell for sure, but w= e can change this anytime :)<br> <br> <br> Chris, please let me know what you think, and again - many thanks for sendi= ng the patch!<br> <br> <br> Regards,<br> Vojtech<br> <br> </span></p> <div class=3D"MsoNormal" style=3D"text-align:center" align=3D"center"><span= style=3D"color:black"> <hr id=3D"zwchr" size=3D"2" width=3D"100%" align=3D"center"> </span></div> <p class=3D"MsoNormal" style=3D"margin-bottom:12.0pt"><span style=3D"color:= black"><br> From: "Chris Frantz" <<a href=3D"mailto:Chris.Frantz@hp.com" target=3D"_= blank">Chris.Frantz@hp.com</a>><br> To: <a href=3D"mailto:vszocs@redhat.com" target=3D"_blank">vszocs@redhat.co= m</a><br> Sent: Wednesday, August 22, 2012 7:56:45 PM<br> Subject: UI Plugins configuration<br> <br> Vojtech,<br> <br> I decided to work on making the plugin patch a bit more configurable, follo= wing some of the ideas expressed by Itamar and others in the meeting yester= day. The attached patch is a simple first-attempt.<br> <br> Plugin configurations are stored in /usr/share/ovirt-engine/ui-plugins/*.js= on.<br> <br> Example:<br> {<br> "name": "test",<br> "version": "1.0",<br> "url": "/webadmin/webadmin/= plugin/test/foo.html",<br> "path": "/tmp",<br> "config": {"a":1, "b":2, "c= ": 3}<br> }<br> <br> The engine reads all of the *.json files in that directory to build the lis= t of known plugins and gives that list to the webadmin.<br> <br> When webadmin loads a plugin, it requests the URL given in the plugin confi= g file. The "plugin" URL is mapped to PluginSourcePage, which will tr= anslate the first part of the path ("test") into whatever path is stored in= pluginConfig ("/tmp") in this case, and then serve the static file (e.g. "/tmp/foo.html").<br> <br> I didn't use the renderPluginSourcePage() method in favor of just serving a= static file, but I have no strong opinion on the matter. However, a = plugin may want to store static resources at "path" and have the engine ser= ve those resources. By just serving files through PluginSourcePage, we don't need any other servlets to provid= e those resources.<br> <br> There is still a bit of work to do:<br> <br> 1. The plugin configuration files should probably have an "enabled" f= ield and an "apiVersion" field that should be examined to determine whether= or not to use the plugin.<br> <br> 2. I suspect the way I've modified PluginSourcePage makes it vulnerab= le to directory climbing attacks.<br> <br> 3. Is /usr/share/ovirt-engine the right place for the plugin config f= iles?<br> <br> Let me know what you think,<br> --Chris</span></p> </div> </div> </div><br></div></body></html> ------=_Part_14076039_700554763.1346074851578--

--_000_A24D665DC3ECC245A2EA0D9A958F80B62C4900E8G9W0745americas_ Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Vm9qdGVjaCwNCg0KWW91ciBhc3N1bXB0aW9uIGFib3V0IHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIHBs dWdpbkRlZmluaXRpb25zIG9iamVjdCBpcyBjb3JyZWN0LiAgSXTigJlzIG5vIGxvbmdlciBhIFN0 cmluZy0+U3RyaW5nIG1hcHBpbmcgLCBidXQgYSBTdHJpbmcgdG8gT2JqZWN0IG1hcHBpbmcuDQoN CkkgbGlrZWQgdGhlIG9yaWdpbmFsIElJRkUgYXBwcm9hY2gsIGV4Y2VwdCB0aGF0IGl0IHNlZW1l ZCB0aGF0IGhhdmluZyBhZGRpdGlvbmFsIHN0YXRpYyByZXNvdXJjZXMgKGpxdWVyeSwgaW1hZ2Vz LCBodG1sIHRlbXBsYXRlcywgZXRjKSB3YXMgZ29pbmcgdG8gYmUgbW9yZSBjdW1iZXJzb21lLiAg SSBkb27igJl0IHRoaW5rIGhhdmluZyB0aGUgcGx1Z2luIGF1dGhvciB3cml0ZSBhIGJhc2ljIHN0 YXJ0Lmh0bWwgaXMgdGhhdCBiaWcgb2YgYSBidXJkZW4gOikuDQoNCkkgYWdyZWUgdGhhdCB0aGUg cGx1Z2luIGNvbmZpZ3VyYXRpb24gd2FzIGFsd2F5cyBnb2luZyB0byBiZSBhIHJlc291cmNlIChw cm9iYWJseSBhIGxvY2FsIGZpbGUpIHRoYXQgdGhlIGVuZCB1c2VyIGNvdWxkIGN1c3RvbWl6ZS4g IEnigJltIG5vdCBzdXJlIGl0IEkgcmVhbGx5IG5lZWRzIHRvIGJlIHNlcGFyYXRlIGZyb20gdGhl IHBsdWdpbiBkZWZpbml0aW9uIGZpbGUgKC91c3Ivc2hhcmUvb3ZpcnQtZW5naW5lL3VpLXBsdWdp bnMvdGVzdC5qc29uKS4gIEkgc3VwcG9zZSBpdCBkZXBlbmRzIG9uIGhvdyBjb21wbGV4IHRoZSBj b25maWd1cmF0aW9uIGlzIGdvaW5nIHRvIGJlIGFuZCBvbiBzb21lIG9mIHRoZSBpbXBsZW1lbnRh dGlvbiBkZXRhaWxzIHN1cnJvdW5kaW5nIHRoZSBwbHVnaW4gZGVmaW5pdGlvbiBmaWxlLg0KDQpJ biBteSBwYXRjaCwgSSBzaW1wbHkgdXNlZCBKYWNrc29uIHRvIHBhcnNlIHRoZSBmaWxlIGludG8g YSB0cmVlIG9mIEpzb25Ob2Rlcy4gIFNob3VsZCB0aGUgcGx1Z2luIGRlZmluaXRpb24gYmUgYSBq YXZhIG9iamVjdCBvZiBzb21lIHNvcnQ/IChwbGVhc2UgcGxlYXNlIHBsZWFzZSBkb27igJl0IG1h a2UgbWUgbGVhcm4gYWJvdXQgamF2YSBiZWFuc+KApikuICBJIHN0dWNrIHdpdGggdGhlIEpzb25O b2RlcyBiZWNhdXNlIEphY2tzb24gbWFrZXMgdGhlbSBlYXN5IHRvIHdvcmsgd2l0aCBhbmQgdGhl eeKAmXJlIHJlYWxseSBlYXN5IHRvIHJlLXNlcmlhbGl6ZSBiYWNrIHRvIGpzb24gdG8gZ2l2ZSB0 byB0aGUgd2ViYWRtaW4uDQoNCldlIHNob3VsZCBwcm9iYWJseSB0dXJuIG9uIEpzb25QYXJzZXIu RmVhdHVyZS5BTExPV19DT01NRU5UUy4gIFRoZSBkZWZpbml0aW9uIGFuZCBjb25maWcgZmlsZXMg d2lsbCBkaWZmaWN1bHQgZm9yIGVuZC11c2VycyAob3IgZXZlbiBkZXZlbG9wZXJzKSB0byB1bmRl cnN0YW5kIHdpdGhvdXQgY29tbWVudHMuDQoNCldlIG5lZWQgdG8gZm9ybWFsaXplIHRoZSBzdHJ1 Y3R1cmUgb2YgdGhlIHBsdWdpbiBkZWZpbml0aW9uIGFuZCBkZWNpZGUgd2hpY2ggZmllbGRzIGFy ZSBtYW5kYXRvcnkgYW5kIHdoaWNoIGFyZSBvcHRpb25hbDoNCg0Kew0KICAjIE1hbmRhdG9yeSBm aWVsZHM6IG5hbWUsIGVuYWJsZWQsIHZlcnNpb24sIHVybCwgYXBpdmVyc2lvbiwgYXV0aG9yLCBs aWNlbnNlDQogICMgTmFtZSBvZiB0aGUgcGx1Z2luDQogICJuYW1lIjogInRlc3QiLA0KDQogICMg V2hldGhlciBvciBub3QgcGx1Z2luIGlzIGVuYWJlZA0KICAiZW5hYmxlZCI6IHRydWUsDQoNCiAg IyB2ZXJzaW9uIG9mIHRoZSBwbHVnaW4NCiAgInZlcnNpb24iOiAiMS4wIiwNCg0KICAjIEhvdyB0 byBsb2FkIHRoZSBwbHVnaW4NCiAgInVybCI6ICIvd2ViYWRtaW4vd2ViYWRtaW4vcGx1Z2luL3Rl c3Qvc3RhcnQuaHRtbCIsDQoNCiAgIyBXaGljaCB2ZXJzaW9uIG9mIGVuZ2luZSBwbHVnaW4gaXMg bWVhbnQgdG8gd29yayB3aXRoDQogICJhcGl2ZXJzaW9uIjogIjMuMS4wIiwNCg0KICAjIFdobyB3 cm90ZSB0aGUgcGx1Z2luIGFuZCBob3cgaXMgaXQgbGljZW5zZWQ/DQogICJhdXRob3IiOiAiU3Vw ZXJCaWcgQ29ycG9yYXRpb24iLA0KICAibGljZW5zZSI6ICJQcm9wcmlldGFyeSIsDQoNCiAgIyBP cHRpb25hbCBmaWVsZHMgcGF0aCwgY29uZmlnDQogICMgV2hlcmUgdG8gbG9jYXRlIHBsdWdpbiAo aWYgbG9hZGVkIGJ5IHdlYmFkbWluL3BsdWdpbikNCiAgInBhdGgiOiAiL3RtcCIsDQoNCiAgIyBQ bHVnaW4gY29uZmlndXJhdGlvbiBpbmZvcm1hdGlvbiAoaWYgYW55KQ0KICAiY29uZmlnIjogInRl c3QtY29uZmlnLmpzb24iLA0KfQ0KDQpJIGNhbiB3b3JrIG9uIHRoZSBwbHVnaW4gRGVmaW5pdGlv biBsb2FkZXIgc29tZSBtb3JlIGFuZCBtYWtlIGl0IGVuZm9yY2UgbWFuZGF0b3J5L29wdGlvbmFs IGZpZWxkcy4gIEnigJlsbCBhbHNvIGludmVzdGlnYXRlIHRoZSBkaXJlY3RvcnkgY2xpbWJpbmcg aXNzdWUgSSBtZW50aW9uZWQgaW4gbXkgcHJldmlvdXMgbWFpbC4NCg0KQWxzbywgSeKAmW0gY3Vy aW91cyBob3cgdGhpbmdzIGFyZSBnb2luZyB0byB3b3JrIHdoZW4gdGhlIOKAnHVybOKAnSBwb2lu dHMgdG8gYSBmb3JlaWduIHJlc291cmNlIGFzIHRoZSBwbHVnaW4gc3RhcnQgcGFnZS4gIEkgZG9u 4oCZdCB0aGluayB0aGUgcGx1Z2lu4oCZcyBpZnJhbWUgaXMgZ29pbmcgdG8gYmUgYWJsZSB0byBh Y2Nlc3MgcGFyZW50LnBsdWdpbkFwaS4gIFBlcmhhcHMgdGhlcmUgaXMgc29tZSBhc3BlY3Qgb2Yg Q09SUyB0aGF0IEkgZG9u4oCZdCB1bmRlcnN0YW5kPw0KDQpUaGFua3MsDQotLUNocmlzDQoNCg0K DQpGcm9tOiBWb2p0ZWNoIFN6b2NzIFttYWlsdG86dnN6b2NzQHJlZGhhdC5jb21dDQpTZW50OiBU aHVyc2RheSwgQXVndXN0IDIzLCAyMDEyIDc6MTQgQU0NClRvOiBGcmFudHosIENocmlzDQpDYzog ZW5naW5lLWRldmVsDQpTdWJqZWN0OiBSZTogVUkgUGx1Z2lucyBjb25maWd1cmF0aW9uDQoNCkhp IENocmlzLA0KDQp0aGFua3MgZm9yIHRha2luZyB0aGUgdGltZSB0byBtYWtlIHRoaXMgcGF0Y2gs IHRoZXNlIGFyZSBzb21lIGV4Y2VsbGVudCBpZGVhcyEgKENDJ2luZyBlbmdpbmUtZGV2ZWwgc28g dGhhdCB3ZSBjYW4gZGlzY3VzcyB0aGlzIHdpdGggb3RoZXIgZ3V5cyBhcyB3ZWxsKQ0KDQpGaXJz dCBvZiBhbGwsIEkgcmVhbGx5IGxpa2UgdGhlIHdheSB5b3UgZGVzaWduZWQgcGx1Z2luIHNvdXJj ZSBwYWdlIFVSTHMgKGdvaW5nIHRocm91Z2ggUGx1Z2luU291cmNlUGFnZVNlcnZsZXQpLCBlLmcu ICIvd2ViYWRtaW4vd2ViYWRtaW4vcGx1Z2luLzxwbHVnaW5OYW1lPi88cGx1Z2luU291cmNlUGFn ZT4uaHRtbCIsIHBsdXMgdGhlIGNvbmNlcHQgb2YgInBhdGgiIEpTT04gYXR0cmlidXRlLg0KDQpX ZWJhZG1pbkR5bmFtaWNIb3N0aW5nU2VydmxldCBsb2FkcyBhbmQgY2FjaGVzIGFsbCBwbHVnaW4g ZGVmaW5pdGlvbnMgKCouanNvbiBmaWxlcyksIGFuZCBkaXJlY3RseSBlbWJlZHMgdGhlbSBpbnRv IFdlYkFkbWluIGhvc3QgcGFnZSBhcyBwbHVnaW5EZWZpbml0aW9ucyBKYXZhU2NyaXB0IG9iamVj dC4gSSdtIGFzc3VtaW5nIHRoYXQgcGx1Z2luRGVmaW5pdGlvbnMgb2JqZWN0IHdpbGwgbm93IGxv b2sgbGlrZSB0aGlzOg0KDQp2YXIgcGx1Z2luRGVmaW5pdGlvbnMgPSB7DQogICJ0ZXN0Ijogew0K ICAgICJuYW1lIjogInRlc3QiLA0KICAgICJ2ZXJzaW9uIjogIjEuMCIsDQogICAgInVybCI6ICIv d2ViYWRtaW4vd2ViYWRtaW4vcGx1Z2luL3Rlc3QvZm9vLmh0bWwiLA0KICAgICJwYXRoIjogIi90 bXAiLA0KICAgICJjb25maWciOiB7ImEiOjEsICJiIjoyLCAiYyI6M30NCiAgfQ0KfQ0KDQpPcmln aW5hbGx5LCB0aGUgcGx1Z2luRGVmaW5pdGlvbnMgb2JqZWN0IGxvb2tlZCBsaWtlIHRoaXM6DQoN CnZhciBwbHVnaW5EZWZpbml0aW9ucyA9IHsNCiAgInRlc3QiOiAiL3dlYmFkbWluL3dlYmFkbWlu L3BsdWdpbi90ZXN0L2Zvby5odG1sIiAvLyBTaW1wbGUgcGx1Z2luTmFtZSAtPiBwbHVnaW5Tb3Vy Y2VQYWdlVXJsIG1hcHBpbmdzDQp9DQoNClRoaXMgaXMgYmVjYXVzZSBQbHVnaW5NYW5hZ2VyIChX ZWJBZG1pbikgb25seSBuZWVkcyBwbHVnaW5OYW1lICgibmFtZSIpIGFuZCBwbHVnaW5Tb3VyY2VQ YWdlVXJsICgidXJsIikgZHVyaW5nIHN0YXJ0dXAsIHdoZW4gY3JlYXRpbmcgcGx1Z2luIGlmcmFt ZS4gQnV0IHRoaXMgY2FuIGJlIGNoYW5nZWQgOikNCg0KUGx1Z2luICJ2ZXJzaW9uIiBtYWtlcyBz ZW5zZSwgcGx1cyB0aGUgcGx1Z2luIGNvbmZpZ3VyYXRpb24gb2JqZWN0ICgiY29uZmlnIikgY2Fu IGJlIHVzZWZ1bCBkaXJlY3RseSBvbiB0aGUgY2xpZW50LiBMZXQgbWUgZXhwbGFpbjoNCg0KT3Jp Z2luYWxseSwgcGx1Z2luIGNvbmZpZ3VyYXRpb24gd2FzIHN1cHBvc2VkIHRvIGJlIHBhc3NlZCB0 byBhY3R1YWwgcGx1Z2luIGNvZGUgKHRocm91Z2ggaW1tZWRpYXRlbHktaW52b2tlZC1mdW5jdGlv bi1leHByZXNzaW9uLCBvciBJSUZFKSwganVzdCBsaWtlIHRoaXM6DQoNCihmdW5jdGlvbiAocGx1 Z2luQXBpLCBwbHVnaW5Db25maWcpIHsgLy8gSmF2YVNjcmlwdCBJSUZFDQogIC8vIC4uLiBhY3R1 YWwgcGx1Z2luIGNvZGUgLi4uDQp9KSgNCiAgcGFyZW50LnBsdWdpbkFwaSwgLyogcmVmZXJlbmNl IHRvIGdsb2JhbCBwbHVnaW5BcGkgb2JqZWN0ICovDQogIHsiYSI6MSwgImIiOjIsICJjIjozfSAv KiBlbWJlZGRlZCBwbHVnaW4gY29uZmlndXJhdGlvbiBhcyBKYXZhU2NyaXB0IG9iamVjdCAqLw0K KTsNCg0KVGhlIHdob2xlIHB1cnBvc2Ugb2YgUGx1Z2luU291cmNlUGFnZVNlcnZsZXQgd2FzIHRv ICJ3cmFwIiBhY3R1YWwgcGx1Z2luIGNvZGUgaW50byBIVE1MLCBzbyB0aGF0IHVzZXJzIGRvbid0 IG5lZWQgdG8gd3JpdGUgSFRNTCBwYWdlcyBmb3IgdGhlaXIgcGx1Z2lucyBtYW51YWxseS4gUGx1 Z2luU291cmNlUGFnZVNlcnZsZXQgd291bGQgaGFuZGxlIGFueSBwbHVnaW4gZGVwZW5kZW5jaWVz IChwbGFjZWQgaW50byBIVE1MIGhlYWQpLCB3aXRoIGFjdHVhbCBwbHVnaW4gY29kZSBiZWluZyB3 cmFwcGVkIGludG8gSUlGRSwgYXMgc2hvd24gYWJvdmUuIFBsdWdpbiBjb25maWd1cmF0aW9uIHdh cyBtZWFudCB0byBiZSBzdG9yZWQgaW4gYSBzZXBhcmF0ZSBmaWxlLCBlLmcuIDxwbHVnaW5OYW1l Pi1jb25maWcuanNvbiwgc28gdGhhdCB1c2VycyBjb3VsZCBjaGFuZ2UgdGhlIGRlZmF1bHQgcGx1 Z2luIGNvbmZpZ3VyYXRpb24gdG8gc3VpdCB0aGVpciBuZWVkcy4NCg0KSW5zcGlyZWQgYnkgeW91 ciBwYXRjaCwgcmF0aGVyIHRoYW4gcmVhZGluZy9lbWJlZGRpbmcgcGx1Z2luIGNvbmZpZ3VyYXRp b24gd2hlbiBzZXJ2aW5nIHBsdWdpbiBIVE1MIHBhZ2UgKFBsdWdpblNvdXJjZVBhZ2VTZXJ2bGV0 KSwgaXQncyBldmVuIGJldHRlciB0byBoYXZlIHRoZSBwbHVnaW4gY29uZmlndXJhdGlvbiBlbWJl ZGRlZCBkaXJlY3RseSBpbnRvIFdlYkFkbWluIGhvc3QgcGFnZSwgYWxvbmcgd2l0aCBpbnRyb2R1 Y2luZyBuZXcgcGx1Z2luQXBpIGZ1bmN0aW9uIHRvIHJldHJpZXZlIHRoZSBwbHVnaW4gY29uZmln dXJhdGlvbiBvYmplY3QuDQoNCkJhc2VkIG9uIHRoaXMsIEkgc3VnZ2VzdCBmb2xsb3dpbmcgbW9k aWZpY2F0aW9ucyB0byB0aGUgb3JpZ2luYWwgY29uY2VwdDoNCg0KLSBtb2RpZnkgb3JpZ2luYWwg cGx1Z2luRGVmaW5pdGlvbnMgc3RydWN0dXJlLCBmcm9tIHBsdWdpbk5hbWUgLT4gcGx1Z2luU291 cmNlUGFnZVVybCwgdG8gcGx1Z2luTmFtZSAtPiBwbHVnaW5EZWZPYmplY3QNCi0gcGx1Z2luRGVm T2JqZWN0IGlzIGJhc2ljYWxseSBhIHN1YnNldCBvZiBwaHlzaWNhbCBwbHVnaW4gZGVmaW5pdGlv biAodGVzdC5qc29uLCBzZWUgYmVsb3cpLCBzdWl0YWJsZSBmb3IgdXNlIG9uIHRoZSBjbGllbnQN Ci0gYWRkIGZvbGxvd2luZyBhdHRyaWJ1dGVzIHRvIHBsdWdpbkRlZk9iamVjdDogdmVyc2lvbiwg dXJsLCBjb25maWcNCiAgKiBub3RlICMxOiBuYW1lIGlzIG5vdCBuZWVkZWQsIHNpbmNlIGl0J3Mg YWxyZWFkeSB0aGUga2V5IG9mIHBsdWdpbk5hbWUgLT4gcGx1Z2luRGVmT2JqZWN0IG1hcHBpbmcN CiAgKiBub3RlICMyOiBwYXRoIGlzIG5vdCBuZWVkZWQgb24gdGhlIGNsaWVudCAobW9yZSBvbiB0 aGlzIGJlbG93KQ0KLSBpbnRyb2R1Y2UgcGx1Z2luQXBpLmNvbmZpZyhwbHVnaW5OYW1lKSBmdW5j dGlvbiBmb3IgcGx1Z2lucyB0byByZXRyaWV2ZSB0aGVpciBjb25maWd1cmF0aW9uIG9iamVjdCwg YW5kIHJlbW92ZSBwbHVnaW5Db25maWcgcGFyYW1ldGVyIGZyb20gbWFpbiBJSUZFIChhcyBzaG93 biBhYm92ZSkNCg0KW2FdIFBoeXNpY2FsIHBsdWdpbiBkZWZpbml0aW9uIGZpbGUgKEpTT04pIG1p Z2h0IGJlIGxvY2F0ZWQgYXQgb1ZpcnQgIkRhdGFEaXIiLCBlLmcuIC91c3Ivc2hhcmUvb3ZpcnQt ZW5naW5lL3VpLXBsdWdpbnMvdGVzdC5qc29uLCBmb3IgZXhhbXBsZToNCg0Kew0KICAibmFtZSI6 ICJ0ZXN0IiwNCiAgInZlcnNpb24iOiAiMS4wIiwNCiAgInVybCI6ICIvd2ViYWRtaW4vd2ViYWRt aW4vcGx1Z2luL3Rlc3Qvc3RhcnQuaHRtbCIsDQogICJwYXRoIjogIi90bXAiLA0KICAiY29uZmln IjogInRlc3QtY29uZmlnLmpzb24iDQp9DQoNCltiXSBQbHVnaW4gY29uZmlndXJhdGlvbiBmaWxl IChKU09OKSBtaWdodCBiZSBsb2NhdGVkIGF0IG9WaXJ0ICJDb25maWdEaXIiLCBlLmcuIC9ldGMv b3ZpcnQtZW5naW5lL3VpLXBsdWdpbnMvdGVzdC1jb25maWcuanNvbiwgZm9yIGV4YW1wbGU6DQoN CnsNCiAgImEiOjEsICJiIjoyLCAiYyI6Mw0KfQ0KDQpbY10gRmluYWxseSwgcGx1Z2luIHN0YXRp YyByZXNvdXJjZXMgKHBsdWdpbiBzb3VyY2UgcGFnZSwgYWN0dWFsIHBsdWdpbiBjb2RlLCBwbHVn aW4gZGVwZW5kZW5jaWVzLCBDU1MvaW1hZ2VzLCBldGMuKSB3b3VsZCBiZSBsb2NhdGVkIGF0IC90 bXAgKGFzIHNob3duIGluIFthXSksIGZvciBleGFtcGxlOg0KDQovdG1wL3N0YXJ0Lmh0bWwgLT4g cGx1Z2luIHNvdXJjZSBwYWdlLCB1c2VkIHRvIGxvYWQgYWN0dWFsIHBsdWdpbiBjb2RlDQovdG1w L3Rlc3QuanMgLT4gYWN0dWFsIHBsdWdpbiBjb2RlDQovdG1wL2RlcHMvanF1ZXJ5LW1pbi5qcyAt PiBzaW11bGF0ZSAzcmQgcGFydHkgcGx1Z2luIGRlcGVuZGVuY3kNCg0KRm9yIGV4YW1wbGU6DQoi L3dlYmFkbWluL3dlYmFkbWluL3BsdWdpbi90ZXN0L3N0YXJ0Lmh0bWwiIHdpbGwgYmUgbWFwcGVk IHRvIC90bXAvc3RhcnQuaHRtbA0KIi93ZWJhZG1pbi93ZWJhZG1pbi9wbHVnaW4vdGVzdC9kZXBz L2pxdWVyeS1taW4uanMiIHdpbGwgYmUgbWFwcGVkIHRvIC90bXAvZGVwcy9qcXVlcnktbWluLmpz DQoNClRoaXMgYXBwcm9hY2ggaGFzIHNvbWUgcHJvcyBhbmQgY29uczoNCigrKSBwbHVnaW4gc3Rh dGljIHJlc291cmNlcyBjYW4gYmUgc2VydmVkIHRocm91Z2ggUGx1Z2luU291cmNlUGFnZVNlcnZs ZXQgKHByZXR0eSBtdWNoIGxpa2Ugb1ZpcnQgZG9jdW1lbnRhdGlvbiByZXNvdXJjZXMsIHNlcnZl ZCB0aHJvdWdoIG9WaXJ0IEVuZ2luZSByb290IHdhcidzIEZpbGVTZXJ2bGV0KQ0KKCspIHBsdWdp biBhdXRob3IgaGFzIGNvbXBsZXRlIGNvbnRyb2wgb3ZlciBwbHVnaW4gc291cmNlIHBhZ2UNCigt KSBwbHVnaW4gYXV0aG9yIGFjdHVhbGx5IG5lZWRzIHRvIHdyaXRlIHBsdWdpbiBzb3VyY2UgcGFn ZQ0KDQpPdmVyYWxsLCBJIHRoaW5rIHRoaXMgYXBwcm9hY2ggaXMgYmV0dGVyIHRoYW4gdGhlIHBy ZXZpb3VzIG9uZSAod2hlcmUgUGx1Z2luU291cmNlUGFnZVNlcnZsZXQgdG9vayBjYXJlIG9mIHJl bmRlcmluZyBwbHVnaW4gc291cmNlIHBhZ2UsIGJ1dCBzYWNyaWZpY2VkIHNvbWUgZmxleGliaWxp dHkpLg0KDQpCeSB0aGUgd2F5LCBoZXJlJ3Mgd2hhdCB3b3VsZCBoYXBwZW4gYmVoaW5kIHRoZSBz Y2VuZXM6DQoNCiAgMS4gIHVzZXIgcmVxdWVzdHMgV2ViQWRtaW4gaG9zdCBwYWdlLCBXZWJhZG1p bkR5bmFtaWNIb3N0aW5nU2VydmxldCBsb2FkcyBhbmQgY2FjaGVzIGFsbCBwbHVnaW4gZGVmaW5p dGlvbnMgW2FdICsgcGx1Z2luIGNvbmZpZ3VyYXRpb25zIFtiXSBhbmQgY29uc3RydWN0cy9lbWJl ZHMgYXBwcm9wcmlhdGUgcGx1Z2luRGVmaW5pdGlvbnMgSmF2YVNjcmlwdCBvYmplY3QNCiAgMi4g IGR1cmluZyBXZWJBZG1pbiBzdGFydHVwLCBQbHVnaW5NYW5hZ2VyIHJlZ2lzdGVycyB0aGUgcGx1 Z2luIChuYW1lL3ZlcnNpb24vdXJsL2NvbmZpZyksIGFuZCBjcmVhdGVzL2F0dGFjaGVzIHRoZSBp ZnJhbWUgdG8gZmV0Y2ggcGx1Z2luIHNvdXJjZSBwYWdlIGFuc3luY2hyb25vdXNseQ0KICAzLiAg UGx1Z2luU291cmNlUGFnZVNlcnZsZXQgaGFuZGxlcyBwbHVnaW4gc291cmNlIHBhZ2UgcmVxdWVz dCwgcmVzb2x2ZXMgdGhlIGNvcnJlY3QgcGF0aCBbY10gYW5kIGp1c3Qgc3RyZWFtcyB0aGUgZmls ZSBjb250ZW50IGJhY2sgdG8gY2xpZW50DQo+IDEuICBUaGUgcGx1Z2luIGNvbmZpZ3VyYXRpb24g ZmlsZXMgc2hvdWxkIHByb2JhYmx5IGhhdmUgYW4gImVuYWJsZWQiIGZpZWxkIGFuZCBhbiAiYXBp VmVyc2lvbiIgZmllbGQgdGhhdCBzaG91bGQgYmUgZXhhbWluZWQgdG8gZGV0ZXJtaW5lIHdoZXRo ZXIgb3Igbm90IHRvIHVzZSB0aGUgcGx1Z2luLg0KDQpTb3VuZHMgZ29vZCwgd2UgY2FuIGltcGxl bWVudCB0aGVzZSBsYXRlciBvbiA6KQ0KDQo+IDIuICBJIHN1c3BlY3QgdGhlIHdheSBJJ3ZlIG1v ZGlmaWVkIFBsdWdpblNvdXJjZVBhZ2UgbWFrZXMgaXQgdnVsbmVyYWJsZSB0byBkaXJlY3Rvcnkg Y2xpbWJpbmcgYXR0YWNrcy4NCg0KWWVzLCBidXQgd2UgY2FuIGRlZmVuZCBhZ2FpbnN0IHRoZXNl LCByZXN0cmljdGluZyBhY2Nlc3Mgb25seSB0byBwbHVnaW4ncyAicGF0aCIgYW5kIGl0cyBzdWIt ZGlyZWN0b3JpZXMuDQoNCj4gMy4gIElzIC91c3Ivc2hhcmUvb3ZpcnQtZW5naW5lIHRoZSByaWdo dCBwbGFjZSBmb3IgdGhlIHBsdWdpbiBjb25maWcgZmlsZXM/DQoNCkkgc3VwcG9zZSB5b3UgbWVh biBwbHVnaW4gZGVmaW5pdGlvbiBmaWxlcyBbYV0sIGNhbm5vdCB0ZWxsIGZvciBzdXJlLCBidXQg d2UgY2FuIGNoYW5nZSB0aGlzIGFueXRpbWUgOikNCg0KDQpDaHJpcywgcGxlYXNlIGxldCBtZSBr bm93IHdoYXQgeW91IHRoaW5rLCBhbmQgYWdhaW4gLSBtYW55IHRoYW5rcyBmb3Igc2VuZGluZyB0 aGUgcGF0Y2ghDQoNCg0KUmVnYXJkcywNClZvanRlY2gNCg0KX19fX19fX19fX19fX19fX19fX19f X19fX19fX19fX18NCg0KRnJvbTogIkNocmlzIEZyYW50eiIgPENocmlzLkZyYW50ekBocC5jb208 bWFpbHRvOkNocmlzLkZyYW50ekBocC5jb20+Pg0KVG86IHZzem9jc0ByZWRoYXQuY29tPG1haWx0 bzp2c3pvY3NAcmVkaGF0LmNvbT4NClNlbnQ6IFdlZG5lc2RheSwgQXVndXN0IDIyLCAyMDEyIDc6 NTY6NDUgUE0NClN1YmplY3Q6IFVJIFBsdWdpbnMgY29uZmlndXJhdGlvbg0KDQpWb2p0ZWNoLA0K DQpJIGRlY2lkZWQgdG8gd29yayBvbiBtYWtpbmcgdGhlIHBsdWdpbiBwYXRjaCBhIGJpdCBtb3Jl IGNvbmZpZ3VyYWJsZSwgZm9sbG93aW5nIHNvbWUgb2YgdGhlIGlkZWFzIGV4cHJlc3NlZCBieSBJ dGFtYXIgYW5kIG90aGVycyBpbiB0aGUgbWVldGluZyB5ZXN0ZXJkYXkuICBUaGUgYXR0YWNoZWQg cGF0Y2ggaXMgYSBzaW1wbGUgZmlyc3QtYXR0ZW1wdC4NCg0KUGx1Z2luIGNvbmZpZ3VyYXRpb25z IGFyZSBzdG9yZWQgaW4gL3Vzci9zaGFyZS9vdmlydC1lbmdpbmUvdWktcGx1Z2lucy8qLmpzb24u DQoNCkV4YW1wbGU6DQp7DQogICAgICAgICJuYW1lIjogInRlc3QiLA0KICAgICAgICAidmVyc2lv biI6ICIxLjAiLA0KICAgICAgICAidXJsIjogIi93ZWJhZG1pbi93ZWJhZG1pbi9wbHVnaW4vdGVz dC9mb28uaHRtbCIsDQogICAgICAgICJwYXRoIjogIi90bXAiLA0KICAgICAgICAiY29uZmlnIjog eyJhIjoxLCAiYiI6MiwgImMiOiAzfQ0KfQ0KDQpUaGUgZW5naW5lIHJlYWRzIGFsbCBvZiB0aGUg Ki5qc29uIGZpbGVzIGluIHRoYXQgZGlyZWN0b3J5IHRvIGJ1aWxkIHRoZSBsaXN0IG9mIGtub3du IHBsdWdpbnMgYW5kIGdpdmVzIHRoYXQgbGlzdCB0byB0aGUgd2ViYWRtaW4uDQoNCldoZW4gd2Vi YWRtaW4gbG9hZHMgYSBwbHVnaW4sIGl0IHJlcXVlc3RzIHRoZSBVUkwgZ2l2ZW4gaW4gdGhlIHBs dWdpbiBjb25maWcgZmlsZS4gIFRoZSAicGx1Z2luIiBVUkwgaXMgbWFwcGVkIHRvIFBsdWdpblNv dXJjZVBhZ2UsIHdoaWNoIHdpbGwgdHJhbnNsYXRlIHRoZSBmaXJzdCBwYXJ0IG9mIHRoZSBwYXRo ICgidGVzdCIpIGludG8gd2hhdGV2ZXIgcGF0aCBpcyBzdG9yZWQgaW4gcGx1Z2luQ29uZmlnICgi L3RtcCIpIGluIHRoaXMgY2FzZSwgYW5kIHRoZW4gc2VydmUgdGhlIHN0YXRpYyBmaWxlIChlLmcu ICIvdG1wL2Zvby5odG1sIikuDQoNCkkgZGlkbid0IHVzZSB0aGUgcmVuZGVyUGx1Z2luU291cmNl UGFnZSgpIG1ldGhvZCBpbiBmYXZvciBvZiBqdXN0IHNlcnZpbmcgYSBzdGF0aWMgZmlsZSwgYnV0 IEkgaGF2ZSBubyBzdHJvbmcgb3BpbmlvbiBvbiB0aGUgbWF0dGVyLiAgSG93ZXZlciwgYSBwbHVn aW4gbWF5IHdhbnQgdG8gc3RvcmUgc3RhdGljIHJlc291cmNlcyBhdCAicGF0aCIgYW5kIGhhdmUg dGhlIGVuZ2luZSBzZXJ2ZSB0aG9zZSByZXNvdXJjZXMuICBCeSBqdXN0IHNlcnZpbmcgZmlsZXMg dGhyb3VnaCBQbHVnaW5Tb3VyY2VQYWdlLCB3ZSBkb24ndCBuZWVkIGFueSBvdGhlciBzZXJ2bGV0 cyB0byBwcm92aWRlIHRob3NlIHJlc291cmNlcy4NCg0KVGhlcmUgaXMgc3RpbGwgYSBiaXQgb2Yg d29yayB0byBkbzoNCg0KMS4gIFRoZSBwbHVnaW4gY29uZmlndXJhdGlvbiBmaWxlcyBzaG91bGQg cHJvYmFibHkgaGF2ZSBhbiAiZW5hYmxlZCIgZmllbGQgYW5kIGFuICJhcGlWZXJzaW9uIiBmaWVs ZCB0aGF0IHNob3VsZCBiZSBleGFtaW5lZCB0byBkZXRlcm1pbmUgd2hldGhlciBvciBub3QgdG8g dXNlIHRoZSBwbHVnaW4uDQoNCjIuICBJIHN1c3BlY3QgdGhlIHdheSBJJ3ZlIG1vZGlmaWVkIFBs dWdpblNvdXJjZVBhZ2UgbWFrZXMgaXQgdnVsbmVyYWJsZSB0byBkaXJlY3RvcnkgY2xpbWJpbmcg YXR0YWNrcy4NCg0KMy4gIElzIC91c3Ivc2hhcmUvb3ZpcnQtZW5naW5lIHRoZSByaWdodCBwbGFj ZSBmb3IgdGhlIHBsdWdpbiBjb25maWcgZmlsZXM/DQoNCkxldCBtZSBrbm93IHdoYXQgeW91IHRo aW5rLA0KLS1DaHJpcw0K --_000_A24D665DC3ECC245A2EA0D9A958F80B62C4900E8G9W0745americas_ Content-Type: text/html; charset="utf-8" Content-Transfer-Encoding: base64 PGh0bWwgeG1sbnM6dj0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp2bWwiIHhtbG5zOm89InVy bjpzY2hlbWFzLW1pY3Jvc29mdC1jb206b2ZmaWNlOm9mZmljZSIgeG1sbnM6dz0idXJuOnNjaGVt YXMtbWljcm9zb2Z0LWNvbTpvZmZpY2U6d29yZCIgeG1sbnM6bT0iaHR0cDovL3NjaGVtYXMubWlj cm9zb2Z0LmNvbS9vZmZpY2UvMjAwNC8xMi9vbW1sIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv VFIvUkVDLWh0bWw0MCI+DQo8aGVhZD4NCjxtZXRhIGh0dHAtZXF1aXY9IkNvbnRlbnQtVHlwZSIg Y29udGVudD0idGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04Ij4NCjxtZXRhIG5hbWU9IkdlbmVyYXRv ciIgY29udGVudD0iTWljcm9zb2Z0IFdvcmQgMTIgKGZpbHRlcmVkIG1lZGl1bSkiPg0KPCEtLVtp ZiAhbXNvXT48c3R5bGU+dlw6KiB7YmVoYXZpb3I6dXJsKCNkZWZhdWx0I1ZNTCk7fQ0Kb1w6KiB7 YmVoYXZpb3I6dXJsKCNkZWZhdWx0I1ZNTCk7fQ0Kd1w6KiB7YmVoYXZpb3I6dXJsKCNkZWZhdWx0 I1ZNTCk7fQ0KLnNoYXBlIHtiZWhhdmlvcjp1cmwoI2RlZmF1bHQjVk1MKTt9DQo8L3N0eWxlPjwh W2VuZGlmXS0tPjxzdHlsZT48IS0tDQovKiBGb250IERlZmluaXRpb25zICovDQpAZm9udC1mYWNl DQoJe2ZvbnQtZmFtaWx5OiJDYW1icmlhIE1hdGgiOw0KCXBhbm9zZS0xOjIgNCA1IDMgNSA0IDYg MyAyIDQ7fQ0KQGZvbnQtZmFjZQ0KCXtmb250LWZhbWlseTpDYWxpYnJpOw0KCXBhbm9zZS0xOjIg MTUgNSAyIDIgMiA0IDMgMiA0O30NCkBmb250LWZhY2UNCgl7Zm9udC1mYW1pbHk6VGFob21hOw0K CXBhbm9zZS0xOjIgMTEgNiA0IDMgNSA0IDQgMiA0O30NCi8qIFN0eWxlIERlZmluaXRpb25zICov DQpwLk1zb05vcm1hbCwgbGkuTXNvTm9ybWFsLCBkaXYuTXNvTm9ybWFsDQoJe21hcmdpbjowaW47 DQoJbWFyZ2luLWJvdHRvbTouMDAwMXB0Ow0KCWZvbnQtc2l6ZToxMi4wcHQ7DQoJZm9udC1mYW1p bHk6IlRpbWVzIE5ldyBSb21hbiIsInNlcmlmIjt9DQphOmxpbmssIHNwYW4uTXNvSHlwZXJsaW5r DQoJe21zby1zdHlsZS1wcmlvcml0eTo5OTsNCgljb2xvcjpibHVlOw0KCXRleHQtZGVjb3JhdGlv bjp1bmRlcmxpbmU7fQ0KYTp2aXNpdGVkLCBzcGFuLk1zb0h5cGVybGlua0ZvbGxvd2VkDQoJe21z by1zdHlsZS1wcmlvcml0eTo5OTsNCgljb2xvcjpwdXJwbGU7DQoJdGV4dC1kZWNvcmF0aW9uOnVu ZGVybGluZTt9DQpwDQoJe21zby1zdHlsZS1wcmlvcml0eTo5OTsNCgltYXJnaW46MGluOw0KCW1h cmdpbi1ib3R0b206LjAwMDFwdDsNCglmb250LXNpemU6MTIuMHB0Ow0KCWZvbnQtZmFtaWx5OiJU aW1lcyBOZXcgUm9tYW4iLCJzZXJpZiI7fQ0Kc3Bhbi5FbWFpbFN0eWxlMTkNCgl7bXNvLXN0eWxl LXR5cGU6cGVyc29uYWwtcmVwbHk7DQoJZm9udC1mYW1pbHk6IkNhbGlicmkiLCJzYW5zLXNlcmlm IjsNCgljb2xvcjojMUY0OTdEO30NCi5Nc29DaHBEZWZhdWx0DQoJe21zby1zdHlsZS10eXBlOmV4 cG9ydC1vbmx5Ow0KCWZvbnQtc2l6ZToxMC4wcHQ7fQ0KQHBhZ2UgV29yZFNlY3Rpb24xDQoJe3Np emU6OC41aW4gMTEuMGluOw0KCW1hcmdpbjoxLjBpbiAxLjBpbiAxLjBpbiAxLjBpbjt9DQpkaXYu V29yZFNlY3Rpb24xDQoJe3BhZ2U6V29yZFNlY3Rpb24xO30NCi8qIExpc3QgRGVmaW5pdGlvbnMg Ki8NCkBsaXN0IGwwDQoJe21zby1saXN0LWlkOjEzNTM0NTczMDsNCgltc28tbGlzdC10ZW1wbGF0 ZS1pZHM6LTE1NDQyNjk1NjY7fQ0Kb2wNCgl7bWFyZ2luLWJvdHRvbTowaW47fQ0KdWwNCgl7bWFy Z2luLWJvdHRvbTowaW47fQ0KLS0+PC9zdHlsZT48IS0tW2lmIGd0ZSBtc28gOV0+PHhtbD4NCjxv OnNoYXBlZGVmYXVsdHMgdjpleHQ9ImVkaXQiIHNwaWRtYXg9IjEwMjYiIC8+DQo8L3htbD48IVtl bmRpZl0tLT48IS0tW2lmIGd0ZSBtc28gOV0+PHhtbD4NCjxvOnNoYXBlbGF5b3V0IHY6ZXh0PSJl ZGl0Ij4NCjxvOmlkbWFwIHY6ZXh0PSJlZGl0IiBkYXRhPSIxIiAvPg0KPC9vOnNoYXBlbGF5b3V0 PjwveG1sPjwhW2VuZGlmXS0tPg0KPC9oZWFkPg0KPGJvZHkgbGFuZz0iRU4tVVMiIGxpbms9ImJs dWUiIHZsaW5rPSJwdXJwbGUiPg0KPGRpdiBjbGFzcz0iV29yZFNlY3Rpb24xIj4NCjxwIGNsYXNz PSJNc29Ob3JtYWwiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTEuMHB0O2ZvbnQtZmFtaWx5OiZx dW90O0NhbGlicmkmcXVvdDssJnF1b3Q7c2Fucy1zZXJpZiZxdW90Oztjb2xvcjojMUY0OTdEIj5W b2p0ZWNoLDxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFu IHN0eWxlPSJmb250LXNpemU6MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGlicmkmcXVvdDss JnF1b3Q7c2Fucy1zZXJpZiZxdW90Oztjb2xvcjojMUY0OTdEIj48bzpwPiZuYnNwOzwvbzpwPjwv c3Bhbj48L3A+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjEx LjBwdDtmb250LWZhbWlseTomcXVvdDtDYWxpYnJpJnF1b3Q7LCZxdW90O3NhbnMtc2VyaWYmcXVv dDs7Y29sb3I6IzFGNDk3RCI+WW91ciBhc3N1bXB0aW9uIGFib3V0IHRoZSBzdHJ1Y3R1cmUgb2Yg dGhlIHBsdWdpbkRlZmluaXRpb25zIG9iamVjdCBpcyBjb3JyZWN0LiZuYnNwOyBJdOKAmXMgbm8g bG9uZ2VyIGEgU3RyaW5nLSZndDtTdHJpbmcgbWFwcGluZyAsIGJ1dCBhIFN0cmluZyB0byBPYmpl Y3QgbWFwcGluZy48bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48 c3BhbiBzdHlsZT0iZm9udC1zaXplOjExLjBwdDtmb250LWZhbWlseTomcXVvdDtDYWxpYnJpJnF1 b3Q7LCZxdW90O3NhbnMtc2VyaWYmcXVvdDs7Y29sb3I6IzFGNDk3RCI+PG86cD4mbmJzcDs8L286 cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNwYW4gc3R5bGU9ImZvbnQtc2l6 ZToxMS4wcHQ7Zm9udC1mYW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90OywmcXVvdDtzYW5zLXNlcmlm JnF1b3Q7O2NvbG9yOiMxRjQ5N0QiPkkgbGlrZWQgdGhlIG9yaWdpbmFsIElJRkUgYXBwcm9hY2gs IGV4Y2VwdCB0aGF0IGl0IHNlZW1lZCB0aGF0IGhhdmluZyBhZGRpdGlvbmFsIHN0YXRpYyByZXNv dXJjZXMgKGpxdWVyeSwgaW1hZ2VzLCBodG1sIHRlbXBsYXRlcywgZXRjKSB3YXMgZ29pbmcgdG8g YmUgbW9yZQ0KIGN1bWJlcnNvbWUuJm5ic3A7IEkgZG9u4oCZdCB0aGluayBoYXZpbmcgdGhlIHBs dWdpbiBhdXRob3Igd3JpdGUgYSBiYXNpYyBzdGFydC5odG1sIGlzIHRoYXQgYmlnIG9mIGEgYnVy ZGVuIDopLjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFu IHN0eWxlPSJmb250LXNpemU6MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGlicmkmcXVvdDss JnF1b3Q7c2Fucy1zZXJpZiZxdW90Oztjb2xvcjojMUY0OTdEIj48bzpwPiZuYnNwOzwvbzpwPjwv c3Bhbj48L3A+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjEx LjBwdDtmb250LWZhbWlseTomcXVvdDtDYWxpYnJpJnF1b3Q7LCZxdW90O3NhbnMtc2VyaWYmcXVv dDs7Y29sb3I6IzFGNDk3RCI+SSBhZ3JlZSB0aGF0IHRoZSBwbHVnaW4gY29uZmlndXJhdGlvbiB3 YXMgYWx3YXlzIGdvaW5nIHRvIGJlIGEgcmVzb3VyY2UgKHByb2JhYmx5IGEgbG9jYWwgZmlsZSkg dGhhdCB0aGUgZW5kIHVzZXIgY291bGQgY3VzdG9taXplLiZuYnNwOyBJ4oCZbSBub3Qgc3VyZSBp dCBJIHJlYWxseQ0KIG5lZWRzIHRvIGJlIHNlcGFyYXRlIGZyb20gdGhlIHBsdWdpbiBkZWZpbml0 aW9uIGZpbGUgKC91c3Ivc2hhcmUvb3ZpcnQtZW5naW5lL3VpLXBsdWdpbnMvdGVzdC5qc29uKS4m bmJzcDsgSSBzdXBwb3NlIGl0IGRlcGVuZHMgb24gaG93IGNvbXBsZXggdGhlIGNvbmZpZ3VyYXRp b24gaXMgZ29pbmcgdG8gYmUgYW5kIG9uIHNvbWUgb2YgdGhlIGltcGxlbWVudGF0aW9uIGRldGFp bHMgc3Vycm91bmRpbmcgdGhlIHBsdWdpbiBkZWZpbml0aW9uIGZpbGUuPG86cD48L286cD48L3Nw YW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMS4w cHQ7Zm9udC1mYW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90OywmcXVvdDtzYW5zLXNlcmlmJnF1b3Q7 O2NvbG9yOiMxRjQ5N0QiPjxvOnA+Jm5ic3A7PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJN c29Ob3JtYWwiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90 O0NhbGlicmkmcXVvdDssJnF1b3Q7c2Fucy1zZXJpZiZxdW90Oztjb2xvcjojMUY0OTdEIj5JbiBt eSBwYXRjaCwgSSBzaW1wbHkgdXNlZCBKYWNrc29uIHRvIHBhcnNlIHRoZSBmaWxlIGludG8gYSB0 cmVlIG9mIEpzb25Ob2Rlcy4gJm5ic3A7U2hvdWxkIHRoZSBwbHVnaW4gZGVmaW5pdGlvbiBiZSBh IGphdmEgb2JqZWN0IG9mIHNvbWUgc29ydD8gKHBsZWFzZSBwbGVhc2UgcGxlYXNlDQogZG9u4oCZ dCBtYWtlIG1lIGxlYXJuIGFib3V0IGphdmEgYmVhbnPigKYpLiZuYnNwOyBJIHN0dWNrIHdpdGgg dGhlIEpzb25Ob2RlcyBiZWNhdXNlIEphY2tzb24gbWFrZXMgdGhlbSBlYXN5IHRvIHdvcmsgd2l0 aCBhbmQgdGhleeKAmXJlIHJlYWxseSBlYXN5IHRvIHJlLXNlcmlhbGl6ZSBiYWNrIHRvIGpzb24g dG8gZ2l2ZSB0byB0aGUgd2ViYWRtaW4uPG86cD48L286cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9 Ik1zb05vcm1hbCI+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7Zm9udC1mYW1pbHk6JnF1 b3Q7Q2FsaWJyaSZxdW90OywmcXVvdDtzYW5zLXNlcmlmJnF1b3Q7O2NvbG9yOiMxRjQ5N0QiPjxv OnA+Jm5ic3A7PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFuIHN0 eWxlPSJmb250LXNpemU6MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGlicmkmcXVvdDssJnF1 b3Q7c2Fucy1zZXJpZiZxdW90Oztjb2xvcjojMUY0OTdEIj5XZSBzaG91bGQgcHJvYmFibHkgdHVy biBvbiBKc29uUGFyc2VyLkZlYXR1cmUuQUxMT1dfQ09NTUVOVFMuJm5ic3A7IFRoZSBkZWZpbml0 aW9uIGFuZCBjb25maWcgZmlsZXMgd2lsbCBkaWZmaWN1bHQgZm9yIGVuZC11c2VycyAob3IgZXZl biBkZXZlbG9wZXJzKSB0byB1bmRlcnN0YW5kDQogd2l0aG91dCBjb21tZW50cy48bzpwPjwvbzpw Pjwvc3Bhbj48L3A+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48c3BhbiBzdHlsZT0iZm9udC1zaXpl OjExLjBwdDtmb250LWZhbWlseTomcXVvdDtDYWxpYnJpJnF1b3Q7LCZxdW90O3NhbnMtc2VyaWYm cXVvdDs7Y29sb3I6IzFGNDk3RCI+PG86cD4mbmJzcDs8L286cD48L3NwYW4+PC9wPg0KPHAgY2xh c3M9Ik1zb05vcm1hbCI+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7Zm9udC1mYW1pbHk6 JnF1b3Q7Q2FsaWJyaSZxdW90OywmcXVvdDtzYW5zLXNlcmlmJnF1b3Q7O2NvbG9yOiMxRjQ5N0Qi PldlIG5lZWQgdG8gZm9ybWFsaXplIHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIHBsdWdpbiBkZWZpbml0 aW9uIGFuZCBkZWNpZGUgd2hpY2ggZmllbGRzIGFyZSBtYW5kYXRvcnkgYW5kIHdoaWNoIGFyZSBv cHRpb25hbDo8bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48c3Bh biBzdHlsZT0iZm9udC1zaXplOjExLjBwdDtmb250LWZhbWlseTomcXVvdDtDYWxpYnJpJnF1b3Q7 LCZxdW90O3NhbnMtc2VyaWYmcXVvdDs7Y29sb3I6IzFGNDk3RCI+PG86cD4mbmJzcDs8L286cD48 L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5 OiZxdW90O0NvdXJpZXIgTmV3JnF1b3Q7O2NvbG9yOmJsYWNrIj57PG86cD48L286cD48L3NwYW4+ PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiZxdW90 O0NvdXJpZXIgTmV3JnF1b3Q7O2NvbG9yOmJsYWNrIj4mbmJzcDsgIyBNYW5kYXRvcnkgZmllbGRz OiBuYW1lLCBlbmFibGVkLCB2ZXJzaW9uLCB1cmwsIGFwaXZlcnNpb24sIGF1dGhvciwgbGljZW5z ZTxicj4NCiZuYnNwOyAjIE5hbWUgb2YgdGhlIHBsdWdpbiZuYnNwOyA8bzpwPjwvbzpwPjwvc3Bh bj48L3A+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6JnF1 b3Q7Q291cmllciBOZXcmcXVvdDs7Y29sb3I6YmxhY2siPiZuYnNwOyZuYnNwOyZxdW90O25hbWUm cXVvdDs6ICZxdW90O3Rlc3QmcXVvdDssPGJyPg0KPGJyPg0KPG86cD48L286cD48L3NwYW4+PC9w Pg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiZxdW90O0Nv dXJpZXIgTmV3JnF1b3Q7O2NvbG9yOmJsYWNrIj4mbmJzcDsgIyBXaGV0aGVyIG9yIG5vdCBwbHVn aW4gaXMgZW5hYmVkPG86cD48L286cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+ PHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiZxdW90O0NvdXJpZXIgTmV3JnF1b3Q7O2NvbG9yOmJs YWNrIj4mbmJzcDsmbmJzcDsmcXVvdDtlbmFibGVkJnF1b3Q7OiB0cnVlLDxicj4NCjxicj4NCjxv OnA+PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFuIHN0eWxlPSJm b250LWZhbWlseTomcXVvdDtDb3VyaWVyIE5ldyZxdW90Oztjb2xvcjpibGFjayI+Jm5ic3A7ICMg dmVyc2lvbiBvZiB0aGUgcGx1Z2luPG86cD48L286cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1z b05vcm1hbCI+PHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiZxdW90O0NvdXJpZXIgTmV3JnF1b3Q7 O2NvbG9yOmJsYWNrIj4mbmJzcDsmbmJzcDsmcXVvdDt2ZXJzaW9uJnF1b3Q7OiAmcXVvdDsxLjAm cXVvdDssPGJyPg0KPGJyPg0KPG86cD48L286cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05v cm1hbCI+PHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiZxdW90O0NvdXJpZXIgTmV3JnF1b3Q7O2Nv bG9yOmJsYWNrIj4mbmJzcDsgIyBIb3cgdG8gbG9hZCB0aGUgcGx1Z2luPG86cD48L286cD48L3Nw YW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiZx dW90O0NvdXJpZXIgTmV3JnF1b3Q7O2NvbG9yOmJsYWNrIj4mbmJzcDsmbmJzcDsmcXVvdDt1cmwm cXVvdDs6ICZxdW90Oy93ZWJhZG1pbi93ZWJhZG1pbi9wbHVnaW4vdGVzdC9zdGFydC5odG1sJnF1 b3Q7LDxicj4NCjxicj4NCjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3Jt YWwiPjxzcGFuIHN0eWxlPSJmb250LWZhbWlseTomcXVvdDtDb3VyaWVyIE5ldyZxdW90Oztjb2xv cjpibGFjayI+Jm5ic3A7ICMgV2hpY2ggdmVyc2lvbiBvZiBlbmdpbmUgcGx1Z2luIGlzIG1lYW50 IHRvIHdvcmsgd2l0aDxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwi PjxzcGFuIHN0eWxlPSJmb250LWZhbWlseTomcXVvdDtDb3VyaWVyIE5ldyZxdW90Oztjb2xvcjpi bGFjayI+Jm5ic3A7Jm5ic3A7JnF1b3Q7YXBpdmVyc2lvbiZxdW90OzogJnF1b3Q7My4xLjAmcXVv dDssPGJyPg0KPGJyPg0KPG86cD48L286cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1h bCI+PHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiZxdW90O0NvdXJpZXIgTmV3JnF1b3Q7O2NvbG9y OmJsYWNrIj4mbmJzcDsgIyBXaG8gd3JvdGUgdGhlIHBsdWdpbiBhbmQgaG93IGlzIGl0IGxpY2Vu c2VkPzxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFuIHN0 eWxlPSJmb250LWZhbWlseTomcXVvdDtDb3VyaWVyIE5ldyZxdW90Oztjb2xvcjpibGFjayI+Jm5i c3A7ICZxdW90O2F1dGhvciZxdW90OzogJnF1b3Q7U3VwZXJCaWcgQ29ycG9yYXRpb24mcXVvdDss PGJyPg0KJm5ic3A7ICZxdW90O2xpY2Vuc2UmcXVvdDs6ICZxdW90O1Byb3ByaWV0YXJ5JnF1b3Q7 LDxicj4NCjxicj4NCjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwi PjxzcGFuIHN0eWxlPSJmb250LWZhbWlseTomcXVvdDtDb3VyaWVyIE5ldyZxdW90Oztjb2xvcjpi bGFjayI+Jm5ic3A7ICMgT3B0aW9uYWwgZmllbGRzIHBhdGgsIGNvbmZpZzxvOnA+PC9vOnA+PC9z cGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFuIHN0eWxlPSJmb250LWZhbWlseTom cXVvdDtDb3VyaWVyIE5ldyZxdW90Oztjb2xvcjpibGFjayI+Jm5ic3A7ICMgV2hlcmUgdG8gbG9j YXRlIHBsdWdpbiAoaWYgbG9hZGVkIGJ5IHdlYmFkbWluL3BsdWdpbik8bzpwPjwvbzpwPjwvc3Bh bj48L3A+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6JnF1 b3Q7Q291cmllciBOZXcmcXVvdDs7Y29sb3I6YmxhY2siPiZuYnNwOyZuYnNwOyZxdW90O3BhdGgm cXVvdDs6ICZxdW90Oy90bXAmcXVvdDssPG86cD48L286cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9 Ik1zb05vcm1hbCI+PHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiZxdW90O0NvdXJpZXIgTmV3JnF1 b3Q7O2NvbG9yOmJsYWNrIj48bzpwPiZuYnNwOzwvbzpwPjwvc3Bhbj48L3A+DQo8cCBjbGFzcz0i TXNvTm9ybWFsIj48c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6JnF1b3Q7Q291cmllciBOZXcmcXVv dDs7Y29sb3I6YmxhY2siPiZuYnNwOyAjIFBsdWdpbiBjb25maWd1cmF0aW9uIGluZm9ybWF0aW9u IChpZiBhbnkpPG86cD48L286cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNw YW4gc3R5bGU9ImZvbnQtZmFtaWx5OiZxdW90O0NvdXJpZXIgTmV3JnF1b3Q7O2NvbG9yOmJsYWNr Ij4mbmJzcDsmbmJzcDsmcXVvdDtjb25maWcmcXVvdDs6ICZxdW90O3Rlc3QtY29uZmlnLmpzb24m cXVvdDssPGJyPg0KfTwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6YmxhY2siPjxicj4NCjwvc3Bh bj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjExLjBwdDtmb250LWZhbWlseTomcXVvdDtDb3VyaWVy IE5ldyZxdW90Oztjb2xvcjojMUY0OTdEIj4mbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsNCjxvOnA+ PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFuIHN0eWxlPSJmb250 LXNpemU6MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGlicmkmcXVvdDssJnF1b3Q7c2Fucy1z ZXJpZiZxdW90Oztjb2xvcjojMUY0OTdEIj5JIGNhbiB3b3JrIG9uIHRoZSBwbHVnaW4gRGVmaW5p dGlvbiBsb2FkZXIgc29tZSBtb3JlIGFuZCBtYWtlIGl0IGVuZm9yY2UgbWFuZGF0b3J5L29wdGlv bmFsIGZpZWxkcy4gJm5ic3A7SeKAmWxsIGFsc28gaW52ZXN0aWdhdGUgdGhlIGRpcmVjdG9yeSBj bGltYmluZyBpc3N1ZSBJIG1lbnRpb25lZA0KIGluIG15IHByZXZpb3VzIG1haWwuPG86cD48L286 cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNwYW4gc3R5bGU9ImZvbnQtc2l6 ZToxMS4wcHQ7Zm9udC1mYW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90OywmcXVvdDtzYW5zLXNlcmlm JnF1b3Q7O2NvbG9yOiMxRjQ5N0QiPjxvOnA+Jm5ic3A7PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNs YXNzPSJNc29Ob3JtYWwiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTEuMHB0O2ZvbnQtZmFtaWx5 OiZxdW90O0NhbGlicmkmcXVvdDssJnF1b3Q7c2Fucy1zZXJpZiZxdW90Oztjb2xvcjojMUY0OTdE Ij5BbHNvLCBJ4oCZbSBjdXJpb3VzIGhvdyB0aGluZ3MgYXJlIGdvaW5nIHRvIHdvcmsgd2hlbiB0 aGUg4oCcdXJs4oCdIHBvaW50cyB0byBhIGZvcmVpZ24gcmVzb3VyY2UgYXMgdGhlIHBsdWdpbiBz dGFydCBwYWdlLiZuYnNwOyBJIGRvbuKAmXQgdGhpbmsgdGhlIHBsdWdpbuKAmXMgaWZyYW1lIGlz IGdvaW5nDQogdG8gYmUgYWJsZSB0byBhY2Nlc3MgcGFyZW50LnBsdWdpbkFwaS4mbmJzcDsgUGVy aGFwcyB0aGVyZSBpcyBzb21lIGFzcGVjdCBvZiBDT1JTIHRoYXQgSSBkb27igJl0IHVuZGVyc3Rh bmQ/PG86cD48L286cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNwYW4gc3R5 bGU9ImZvbnQtc2l6ZToxMS4wcHQ7Zm9udC1mYW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90OywmcXVv dDtzYW5zLXNlcmlmJnF1b3Q7O2NvbG9yOiMxRjQ5N0QiPjxvOnA+Jm5ic3A7PC9vOnA+PC9zcGFu PjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTEuMHB0 O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGlicmkmcXVvdDssJnF1b3Q7c2Fucy1zZXJpZiZxdW90Oztj b2xvcjojMUY0OTdEIj5UaGFua3MsPG86cD48L286cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1z b05vcm1hbCI+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7Zm9udC1mYW1pbHk6JnF1b3Q7 Q2FsaWJyaSZxdW90OywmcXVvdDtzYW5zLXNlcmlmJnF1b3Q7O2NvbG9yOiMxRjQ5N0QiPi0tQ2hy aXM8bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48c3BhbiBzdHls ZT0iZm9udC1zaXplOjExLjBwdDtmb250LWZhbWlseTomcXVvdDtDYWxpYnJpJnF1b3Q7LCZxdW90 O3NhbnMtc2VyaWYmcXVvdDs7Y29sb3I6IzFGNDk3RCI+PG86cD4mbmJzcDs8L286cD48L3NwYW4+ PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7 Zm9udC1mYW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90OywmcXVvdDtzYW5zLXNlcmlmJnF1b3Q7O2Nv bG9yOiMxRjQ5N0QiPjxvOnA+Jm5ic3A7PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29O b3JtYWwiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O0Nh bGlicmkmcXVvdDssJnF1b3Q7c2Fucy1zZXJpZiZxdW90Oztjb2xvcjojMUY0OTdEIj48bzpwPiZu YnNwOzwvbzpwPjwvc3Bhbj48L3A+DQo8ZGl2Pg0KPGRpdiBzdHlsZT0iYm9yZGVyOm5vbmU7Ym9y ZGVyLXRvcDpzb2xpZCAjQjVDNERGIDEuMHB0O3BhZGRpbmc6My4wcHQgMGluIDBpbiAwaW4iPg0K PHAgY2xhc3M9Ik1zb05vcm1hbCI+PGI+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMC4wcHQ7Zm9u dC1mYW1pbHk6JnF1b3Q7VGFob21hJnF1b3Q7LCZxdW90O3NhbnMtc2VyaWYmcXVvdDsiPkZyb206 PC9zcGFuPjwvYj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjEwLjBwdDtmb250LWZhbWlseTomcXVv dDtUYWhvbWEmcXVvdDssJnF1b3Q7c2Fucy1zZXJpZiZxdW90OyI+IFZvanRlY2ggU3pvY3MgW21h aWx0bzp2c3pvY3NAcmVkaGF0LmNvbV0NCjxicj4NCjxiPlNlbnQ6PC9iPiBUaHVyc2RheSwgQXVn dXN0IDIzLCAyMDEyIDc6MTQgQU08YnI+DQo8Yj5Ubzo8L2I+IEZyYW50eiwgQ2hyaXM8YnI+DQo8 Yj5DYzo8L2I+IGVuZ2luZS1kZXZlbDxicj4NCjxiPlN1YmplY3Q6PC9iPiBSZTogVUkgUGx1Z2lu cyBjb25maWd1cmF0aW9uPG86cD48L286cD48L3NwYW4+PC9wPg0KPC9kaXY+DQo8L2Rpdj4NCjxw IGNsYXNzPSJNc29Ob3JtYWwiPjxvOnA+Jm5ic3A7PC9vOnA+PC9wPg0KPGRpdj4NCjxwIGNsYXNz PSJNc29Ob3JtYWwiPjxzcGFuIHN0eWxlPSJjb2xvcjpibGFjayI+SGkgQ2hyaXMsPGJyPg0KPGJy Pg0KdGhhbmtzIGZvciB0YWtpbmcgdGhlIHRpbWUgdG8gbWFrZSB0aGlzIHBhdGNoLCB0aGVzZSBh cmUgc29tZSBleGNlbGxlbnQgaWRlYXMhIChDQydpbmcgZW5naW5lLWRldmVsIHNvIHRoYXQgd2Ug Y2FuIGRpc2N1c3MgdGhpcyB3aXRoIG90aGVyIGd1eXMgYXMgd2VsbCk8YnI+DQo8YnI+DQpGaXJz dCBvZiBhbGwsIEkgcmVhbGx5IGxpa2UgdGhlIHdheSB5b3UgZGVzaWduZWQgcGx1Z2luIHNvdXJj ZSBwYWdlIFVSTHMgKGdvaW5nIHRocm91Z2gNCjxlbT5QbHVnaW5Tb3VyY2VQYWdlU2VydmxldDwv ZW0+KSwgZS5nLiAmcXVvdDsvd2ViYWRtaW4vd2ViYWRtaW4vcGx1Z2luLyZsdDtwbHVnaW5OYW1l Jmd0Oy8mbHQ7cGx1Z2luU291cmNlUGFnZSZndDsuaHRtbCZxdW90OywgcGx1cyB0aGUgY29uY2Vw dCBvZiAmcXVvdDtwYXRoJnF1b3Q7IEpTT04gYXR0cmlidXRlLjxicj4NCjxicj4NCjxpPldlYmFk bWluRHluYW1pY0hvc3RpbmdTZXJ2bGV0PC9pPiBsb2FkcyBhbmQgY2FjaGVzIGFsbCBwbHVnaW4g ZGVmaW5pdGlvbnMgKDxpPiouanNvbjwvaT4gZmlsZXMpLCBhbmQgZGlyZWN0bHkgZW1iZWRzIHRo ZW0gaW50byBXZWJBZG1pbiBob3N0IHBhZ2UgYXMNCjxpPnBsdWdpbkRlZmluaXRpb25zPC9pPiBK YXZhU2NyaXB0IG9iamVjdC4gSSdtIGFzc3VtaW5nIHRoYXQgPGk+cGx1Z2luRGVmaW5pdGlvbnM8 L2k+IG9iamVjdCB3aWxsIG5vdyBsb29rIGxpa2UgdGhpczo8YnI+DQo8YnI+DQo8L3NwYW4+PHNw YW4gc3R5bGU9ImZvbnQtZmFtaWx5OiZxdW90O0NvdXJpZXIgTmV3JnF1b3Q7O2NvbG9yOmJsYWNr Ij52YXIgcGx1Z2luRGVmaW5pdGlvbnMgPSB7PGJyPg0KJm5ic3A7Jm5ic3A7JnF1b3Q7dGVzdCZx dW90Ozogezxicj4NCiZuYnNwOyZuYnNwOyAmbmJzcDsmcXVvdDtuYW1lJnF1b3Q7OiAmcXVvdDt0 ZXN0JnF1b3Q7LDxicj4NCiZuYnNwOyZuYnNwOyAmbmJzcDsmcXVvdDt2ZXJzaW9uJnF1b3Q7OiAm cXVvdDsxLjAmcXVvdDssPGJyPg0KJm5ic3A7Jm5ic3A7ICZuYnNwOyZxdW90O3VybCZxdW90Ozog JnF1b3Q7L3dlYmFkbWluL3dlYmFkbWluL3BsdWdpbi90ZXN0L2Zvby5odG1sJnF1b3Q7LDxicj4N CiZuYnNwOyZuYnNwOyAmbmJzcDsmcXVvdDtwYXRoJnF1b3Q7OiAmcXVvdDsvdG1wJnF1b3Q7LDxi cj4NCiZuYnNwOyZuYnNwOyAmbmJzcDsmcXVvdDtjb25maWcmcXVvdDs6IHsmcXVvdDthJnF1b3Q7 OjEsICZxdW90O2ImcXVvdDs6MiwgJnF1b3Q7YyZxdW90OzozfTxicj4NCiZuYnNwOyZuYnNwO308 YnI+DQp9PC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjpibGFjayI+PGJyPg0KPGJyPg0KT3JpZ2lu YWxseSwgdGhlIDxpPnBsdWdpbkRlZmluaXRpb25zPC9pPiBvYmplY3QgbG9va2VkIGxpa2UgdGhp czo8YnI+DQo8L3NwYW4+PHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiZxdW90O0NvdXJpZXIgTmV3 JnF1b3Q7O2NvbG9yOmJsYWNrIj48YnI+DQp2YXIgcGx1Z2luRGVmaW5pdGlvbnMgPSB7PGJyPg0K Jm5ic3A7Jm5ic3A7JnF1b3Q7dGVzdCZxdW90OzogJnF1b3Q7L3dlYmFkbWluL3dlYmFkbWluL3Bs dWdpbi90ZXN0L2Zvby5odG1sJnF1b3Q7IC8vIFNpbXBsZSBwbHVnaW5OYW1lIC0mZ3Q7IHBsdWdp blNvdXJjZVBhZ2VVcmwgbWFwcGluZ3M8YnI+DQp9PC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjpi bGFjayI+PGJyPg0KPGJyPg0KVGhpcyBpcyBiZWNhdXNlIFBsdWdpbk1hbmFnZXIgKFdlYkFkbWlu KSBvbmx5IG5lZWRzIDxpPnBsdWdpbk5hbWU8L2k+ICgmcXVvdDtuYW1lJnF1b3Q7KSBhbmQNCjxp PnBsdWdpblNvdXJjZVBhZ2VVcmw8L2k+ICgmcXVvdDt1cmwmcXVvdDspIGR1cmluZyBzdGFydHVw LCB3aGVuIGNyZWF0aW5nIHBsdWdpbiBpZnJhbWUuIEJ1dCB0aGlzIGNhbiBiZSBjaGFuZ2VkIDop PGJyPg0KPGJyPg0KUGx1Z2luICZxdW90O3ZlcnNpb24mcXVvdDsgbWFrZXMgc2Vuc2UsIHBsdXMg dGhlIHBsdWdpbiBjb25maWd1cmF0aW9uIG9iamVjdCAoJnF1b3Q7Y29uZmlnJnF1b3Q7KSBjYW4g YmUgdXNlZnVsIGRpcmVjdGx5IG9uIHRoZSBjbGllbnQuIExldCBtZSBleHBsYWluOjxicj4NCjxi cj4NCk9yaWdpbmFsbHksIHBsdWdpbiBjb25maWd1cmF0aW9uIHdhcyBzdXBwb3NlZCB0byBiZSBw YXNzZWQgdG8gYWN0dWFsIHBsdWdpbiBjb2RlICh0aHJvdWdoIGltbWVkaWF0ZWx5LWludm9rZWQt ZnVuY3Rpb24tZXhwcmVzc2lvbiwgb3IgSUlGRSksIGp1c3QgbGlrZSB0aGlzOjxicj4NCjwvc3Bh bj48c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6JnF1b3Q7Q291cmllciBOZXcmcXVvdDs7Y29sb3I6 YmxhY2siPjxicj4NCihmdW5jdGlvbiAocGx1Z2luQXBpLCBwbHVnaW5Db25maWcpIHsgLy8gSmF2 YVNjcmlwdCBJSUZFPGJyPg0KJm5ic3A7Jm5ic3A7Ly8gLi4uIGFjdHVhbCBwbHVnaW4gY29kZSAu Li48YnI+DQp9KSg8YnI+DQombmJzcDsmbmJzcDtwYXJlbnQucGx1Z2luQXBpLCAvKiByZWZlcmVu Y2UgdG8gZ2xvYmFsIHBsdWdpbkFwaSBvYmplY3QgKi88YnI+DQombmJzcDsmbmJzcDt7JnF1b3Q7 YSZxdW90OzoxLCAmcXVvdDtiJnF1b3Q7OjIsICZxdW90O2MmcXVvdDs6M30gLyogZW1iZWRkZWQg cGx1Z2luIGNvbmZpZ3VyYXRpb24gYXMgSmF2YVNjcmlwdCBvYmplY3QgKi88YnI+DQopOzwvc3Bh bj48c3BhbiBzdHlsZT0iY29sb3I6YmxhY2siPjxicj4NCjxicj4NClRoZSB3aG9sZSBwdXJwb3Nl IG9mIDxpPlBsdWdpblNvdXJjZVBhZ2VTZXJ2bGV0PC9pPiB3YXMgdG8gJnF1b3Q7d3JhcCZxdW90 OyBhY3R1YWwgcGx1Z2luIGNvZGUgaW50byBIVE1MLCBzbyB0aGF0IHVzZXJzIGRvbid0IG5lZWQg dG8gd3JpdGUgSFRNTCBwYWdlcyBmb3IgdGhlaXIgcGx1Z2lucyBtYW51YWxseS4NCjxpPlBsdWdp blNvdXJjZVBhZ2VTZXJ2bGV0PC9pPiB3b3VsZCBoYW5kbGUgYW55IHBsdWdpbiBkZXBlbmRlbmNp ZXMgKHBsYWNlZCBpbnRvIEhUTUwgaGVhZCksIHdpdGggYWN0dWFsIHBsdWdpbiBjb2RlIGJlaW5n IHdyYXBwZWQgaW50byBJSUZFLCBhcyBzaG93biBhYm92ZS4gUGx1Z2luIGNvbmZpZ3VyYXRpb24g d2FzIG1lYW50IHRvIGJlIHN0b3JlZCBpbiBhIHNlcGFyYXRlIGZpbGUsIGUuZy4NCjxpPiZsdDtw bHVnaW5OYW1lJmd0Oy1jb25maWcuanNvbjwvaT4sIHNvIHRoYXQgdXNlcnMgY291bGQgY2hhbmdl IHRoZSBkZWZhdWx0IHBsdWdpbiBjb25maWd1cmF0aW9uIHRvIHN1aXQgdGhlaXIgbmVlZHMuPGJy Pg0KPGJyPg0KSW5zcGlyZWQgYnkgeW91ciBwYXRjaCwgcmF0aGVyIHRoYW4gcmVhZGluZy9lbWJl ZGRpbmcgcGx1Z2luIGNvbmZpZ3VyYXRpb24gd2hlbiBzZXJ2aW5nIHBsdWdpbiBIVE1MIHBhZ2Ug KDxpPlBsdWdpblNvdXJjZVBhZ2VTZXJ2bGV0PC9pPiksIGl0J3MgZXZlbiBiZXR0ZXIgdG8gaGF2 ZSB0aGUgcGx1Z2luIGNvbmZpZ3VyYXRpb24gZW1iZWRkZWQgZGlyZWN0bHkgaW50byBXZWJBZG1p biBob3N0IHBhZ2UsIGFsb25nIHdpdGggaW50cm9kdWNpbmcgbmV3DQo8aT5wbHVnaW5BcGk8L2k+ IGZ1bmN0aW9uIHRvIHJldHJpZXZlIHRoZSBwbHVnaW4gY29uZmlndXJhdGlvbiBvYmplY3QuPGJy Pg0KPGJyPg0KQmFzZWQgb24gdGhpcywgSSBzdWdnZXN0IGZvbGxvd2luZyBtb2RpZmljYXRpb25z IHRvIHRoZSBvcmlnaW5hbCBjb25jZXB0Ojxicj4NCjxicj4NCi0gbW9kaWZ5IG9yaWdpbmFsIDxp PnBsdWdpbkRlZmluaXRpb25zPC9pPiBzdHJ1Y3R1cmUsIGZyb20gPGk+cGx1Z2luTmFtZSAtJmd0 OyBwbHVnaW5Tb3VyY2VQYWdlVXJsPC9pPiwgdG8NCjxpPnBsdWdpbk5hbWUgLSZndDsgcGx1Z2lu RGVmT2JqZWN0PC9pPjxicj4NCi0gPGk+cGx1Z2luRGVmT2JqZWN0PC9pPiBpcyBiYXNpY2FsbHkg YSBzdWJzZXQgb2YgcGh5c2ljYWwgcGx1Z2luIGRlZmluaXRpb24gKDxpPnRlc3QuanNvbjwvaT4s IHNlZSBiZWxvdyksIHN1aXRhYmxlIGZvciB1c2Ugb24gdGhlIGNsaWVudDxicj4NCi0gYWRkIGZv bGxvd2luZyBhdHRyaWJ1dGVzIHRvIDxpPnBsdWdpbkRlZk9iamVjdDwvaT46IDxpPnZlcnNpb248 L2k+LCA8aT51cmw8L2k+LA0KPGk+Y29uZmlnPC9pPjxicj4NCiZuYnNwOyZuYnNwOyogbm90ZSAj MTogPGk+bmFtZTwvaT4gaXMgbm90IG5lZWRlZCwgc2luY2UgaXQncyBhbHJlYWR5IHRoZSBrZXkg b2YgPGk+cGx1Z2luTmFtZSAtJmd0OyBwbHVnaW5EZWZPYmplY3Q8L2k+IG1hcHBpbmc8YnI+DQom bmJzcDsmbmJzcDsqIG5vdGUgIzI6IDxpPnBhdGg8L2k+IGlzIG5vdCBuZWVkZWQgb24gdGhlIGNs aWVudCAobW9yZSBvbiB0aGlzIGJlbG93KTxicj4NCi0gaW50cm9kdWNlIDxpPnBsdWdpbkFwaS5j b25maWcocGx1Z2luTmFtZSk8L2k+IGZ1bmN0aW9uIGZvciBwbHVnaW5zIHRvIHJldHJpZXZlIHRo ZWlyIGNvbmZpZ3VyYXRpb24gb2JqZWN0LCBhbmQgcmVtb3ZlDQo8aT5wbHVnaW5Db25maWc8L2k+ IHBhcmFtZXRlciBmcm9tIG1haW4gSUlGRSAoYXMgc2hvd24gYWJvdmUpPGJyPg0KPGJyPg0KW2Fd IFBoeXNpY2FsIHBsdWdpbiBkZWZpbml0aW9uIGZpbGUgKEpTT04pIG1pZ2h0IGJlIGxvY2F0ZWQg YXQgb1ZpcnQgJnF1b3Q7RGF0YURpciZxdW90OywgZS5nLg0KPGk+L3Vzci9zaGFyZS9vdmlydC1l bmdpbmUvdWktcGx1Z2lucy90ZXN0Lmpzb248L2k+LCBmb3IgZXhhbXBsZTo8YnI+DQo8L3NwYW4+ PHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiZxdW90O0NvdXJpZXIgTmV3JnF1b3Q7O2NvbG9yOmJs YWNrIj48YnI+DQp7PGJyPg0KJm5ic3A7Jm5ic3A7JnF1b3Q7bmFtZSZxdW90OzogJnF1b3Q7dGVz dCZxdW90Oyw8YnI+DQombmJzcDsmbmJzcDsmcXVvdDt2ZXJzaW9uJnF1b3Q7OiAmcXVvdDsxLjAm cXVvdDssPGJyPg0KJm5ic3A7Jm5ic3A7JnF1b3Q7dXJsJnF1b3Q7OiAmcXVvdDsvd2ViYWRtaW4v d2ViYWRtaW4vcGx1Z2luL3Rlc3Qvc3RhcnQuaHRtbCZxdW90Oyw8YnI+DQombmJzcDsmbmJzcDsm cXVvdDtwYXRoJnF1b3Q7OiAmcXVvdDsvdG1wJnF1b3Q7LDxicj4NCiZuYnNwOyZuYnNwOyZxdW90 O2NvbmZpZyZxdW90OzogJnF1b3Q7dGVzdC1jb25maWcuanNvbiZxdW90Ozxicj4NCn08L3NwYW4+ PHNwYW4gc3R5bGU9ImNvbG9yOmJsYWNrIj48YnI+DQo8YnI+DQpbYl0gUGx1Z2luIGNvbmZpZ3Vy YXRpb24gZmlsZSAoSlNPTikgbWlnaHQgYmUgbG9jYXRlZCBhdCBvVmlydCAmcXVvdDtDb25maWdE aXImcXVvdDssIGUuZy4gPGk+DQovZXRjL292aXJ0LWVuZ2luZS91aS1wbHVnaW5zL3Rlc3QtY29u ZmlnLmpzb248L2k+LCBmb3IgZXhhbXBsZTo8YnI+DQo8L3NwYW4+PHNwYW4gc3R5bGU9ImZvbnQt ZmFtaWx5OiZxdW90O0NvdXJpZXIgTmV3JnF1b3Q7O2NvbG9yOmJsYWNrIj48YnI+DQp7PGJyPg0K Jm5ic3A7Jm5ic3A7JnF1b3Q7YSZxdW90OzoxLCAmcXVvdDtiJnF1b3Q7OjIsICZxdW90O2MmcXVv dDs6Mzxicj4NCn08L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOmJsYWNrIj48YnI+DQo8YnI+DQpb Y10gRmluYWxseSwgcGx1Z2luIHN0YXRpYyByZXNvdXJjZXMgKHBsdWdpbiBzb3VyY2UgcGFnZSwg YWN0dWFsIHBsdWdpbiBjb2RlLCBwbHVnaW4gZGVwZW5kZW5jaWVzLCBDU1MvaW1hZ2VzLCBldGMu KSB3b3VsZCBiZSBsb2NhdGVkIGF0DQo8aT4vdG1wPC9pPiAoYXMgc2hvd24gaW4gW2FdKSwgZm9y IGV4YW1wbGU6PGJyPg0KPC9zcGFuPjxzcGFuIHN0eWxlPSJmb250LWZhbWlseTomcXVvdDtDb3Vy aWVyIE5ldyZxdW90Oztjb2xvcjpibGFjayI+PGJyPg0KL3RtcC9zdGFydC5odG1sIC0mZ3Q7IHBs dWdpbiBzb3VyY2UgcGFnZSwgdXNlZCB0byBsb2FkIGFjdHVhbCBwbHVnaW4gY29kZTxicj4NCi90 bXAvdGVzdC5qcyAtJmd0OyBhY3R1YWwgcGx1Z2luIGNvZGU8YnI+DQovdG1wL2RlcHMvanF1ZXJ5 LW1pbi5qcyAtJmd0OyBzaW11bGF0ZSAzcmQgcGFydHkgcGx1Z2luIGRlcGVuZGVuY3k8L3NwYW4+ PHNwYW4gc3R5bGU9ImNvbG9yOmJsYWNrIj48YnI+DQo8YnI+DQpGb3IgZXhhbXBsZTo8YnI+DQom cXVvdDsvd2ViYWRtaW4vd2ViYWRtaW4vcGx1Z2luL3Rlc3Qvc3RhcnQuaHRtbCZxdW90OyB3aWxs IGJlIG1hcHBlZCB0byA8aT4vdG1wL3N0YXJ0Lmh0bWw8L2k+PGJyPg0KJnF1b3Q7L3dlYmFkbWlu L3dlYmFkbWluL3BsdWdpbi90ZXN0L2RlcHMvanF1ZXJ5LW1pbi5qcyZxdW90OyB3aWxsIGJlIG1h cHBlZCB0byA8aT4vdG1wL2RlcHMvanF1ZXJ5LW1pbi5qczwvaT48YnI+DQo8YnI+DQpUaGlzIGFw cHJvYWNoIGhhcyBzb21lIHByb3MgYW5kIGNvbnM6PGJyPg0KKCYjNDM7KSBwbHVnaW4gc3RhdGlj IHJlc291cmNlcyBjYW4gYmUgc2VydmVkIHRocm91Z2ggPGk+UGx1Z2luU291cmNlUGFnZVNlcnZs ZXQ8L2k+IChwcmV0dHkgbXVjaCBsaWtlIG9WaXJ0IGRvY3VtZW50YXRpb24gcmVzb3VyY2VzLCBz ZXJ2ZWQgdGhyb3VnaCBvVmlydCBFbmdpbmUgcm9vdCB3YXIncw0KPGk+RmlsZVNlcnZsZXQ8L2k+ KTxicj4NCigmIzQzOykgcGx1Z2luIGF1dGhvciBoYXMgY29tcGxldGUgY29udHJvbCBvdmVyIHBs dWdpbiBzb3VyY2UgcGFnZTxicj4NCigtKSBwbHVnaW4gYXV0aG9yIGFjdHVhbGx5IG5lZWRzIHRv IHdyaXRlIHBsdWdpbiBzb3VyY2UgcGFnZTxicj4NCjxicj4NCk92ZXJhbGwsIEkgdGhpbmsgdGhp cyBhcHByb2FjaCBpcyBiZXR0ZXIgdGhhbiB0aGUgcHJldmlvdXMgb25lICh3aGVyZSA8aT5QbHVn aW5Tb3VyY2VQYWdlU2VydmxldDwvaT4gdG9vayBjYXJlIG9mIHJlbmRlcmluZyBwbHVnaW4gc291 cmNlIHBhZ2UsIGJ1dCBzYWNyaWZpY2VkIHNvbWUgZmxleGliaWxpdHkpLjxicj4NCjxicj4NCkJ5 IHRoZSB3YXksIGhlcmUncyB3aGF0IHdvdWxkIGhhcHBlbiBiZWhpbmQgdGhlIHNjZW5lczo8bzpw PjwvbzpwPjwvc3Bhbj48L3A+DQo8b2wgc3RhcnQ9IjEiIHR5cGU9IjEiPg0KPGxpIGNsYXNzPSJN c29Ob3JtYWwiIHN0eWxlPSJjb2xvcjpibGFjazttc28tbWFyZ2luLXRvcC1hbHQ6YXV0bzttYXJn aW4tYm90dG9tOjEyLjBwdDttc28tbGlzdDpsMCBsZXZlbDEgbGZvMSI+DQp1c2VyIHJlcXVlc3Rz IFdlYkFkbWluIGhvc3QgcGFnZSwgPGk+V2ViYWRtaW5EeW5hbWljSG9zdGluZ1NlcnZsZXQ8L2k+ IGxvYWRzIGFuZCBjYWNoZXMgYWxsIHBsdWdpbiBkZWZpbml0aW9ucyBbYV0gJiM0MzsgcGx1Z2lu IGNvbmZpZ3VyYXRpb25zIFtiXSBhbmQgY29uc3RydWN0cy9lbWJlZHMgYXBwcm9wcmlhdGUNCjxp PnBsdWdpbkRlZmluaXRpb25zPC9pPiBKYXZhU2NyaXB0IG9iamVjdDxvOnA+PC9vOnA+PC9saT48 bGkgY2xhc3M9Ik1zb05vcm1hbCIgc3R5bGU9ImNvbG9yOmJsYWNrO21zby1tYXJnaW4tdG9wLWFs dDphdXRvO21hcmdpbi1ib3R0b206MTIuMHB0O21zby1saXN0OmwwIGxldmVsMSBsZm8xIj4NCmR1 cmluZyBXZWJBZG1pbiBzdGFydHVwLCA8aT5QbHVnaW5NYW5hZ2VyPC9pPiByZWdpc3RlcnMgdGhl IHBsdWdpbiAobmFtZS92ZXJzaW9uL3VybC9jb25maWcpLCBhbmQgY3JlYXRlcy9hdHRhY2hlcyB0 aGUgaWZyYW1lIHRvIGZldGNoIHBsdWdpbiBzb3VyY2UgcGFnZSBhbnN5bmNocm9ub3VzbHk8bzpw PjwvbzpwPjwvbGk+PGxpIGNsYXNzPSJNc29Ob3JtYWwiIHN0eWxlPSJjb2xvcjpibGFjazttc28t bWFyZ2luLXRvcC1hbHQ6YXV0bzttYXJnaW4tYm90dG9tOjEyLjBwdDttc28tbGlzdDpsMCBsZXZl bDEgbGZvMSI+DQo8aT5QbHVnaW5Tb3VyY2VQYWdlU2VydmxldDwvaT4gaGFuZGxlcyBwbHVnaW4g c291cmNlIHBhZ2UgcmVxdWVzdCwgcmVzb2x2ZXMgdGhlIGNvcnJlY3QgcGF0aCBbY10gYW5kIGp1 c3Qgc3RyZWFtcyB0aGUgZmlsZSBjb250ZW50IGJhY2sgdG8gY2xpZW50PG86cD48L286cD48L2xp Pjwvb2w+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIiBzdHlsZT0ibWFyZ2luLWJvdHRvbToxMi4wcHQi PjxzcGFuIHN0eWxlPSJjb2xvcjpibGFjayI+Jmd0OyAxLiAmbmJzcDtUaGUgcGx1Z2luIGNvbmZp Z3VyYXRpb24gZmlsZXMgc2hvdWxkIHByb2JhYmx5IGhhdmUgYW4gJnF1b3Q7ZW5hYmxlZCZxdW90 OyBmaWVsZCBhbmQgYW4gJnF1b3Q7YXBpVmVyc2lvbiZxdW90OyBmaWVsZCB0aGF0IHNob3VsZCBi ZSBleGFtaW5lZCB0byBkZXRlcm1pbmUgd2hldGhlciBvciBub3QgdG8gdXNlIHRoZSBwbHVnaW4u PGJyPg0KPGJyPg0KU291bmRzIGdvb2QsIHdlIGNhbiBpbXBsZW1lbnQgdGhlc2UgbGF0ZXIgb24g Oik8YnI+DQo8YnI+DQomZ3Q7IDIuICZuYnNwO0kgc3VzcGVjdCB0aGUgd2F5IEkndmUgbW9kaWZp ZWQgUGx1Z2luU291cmNlUGFnZSBtYWtlcyBpdCB2dWxuZXJhYmxlIHRvIGRpcmVjdG9yeSBjbGlt YmluZyBhdHRhY2tzLjxicj4NCjxicj4NClllcywgYnV0IHdlIGNhbiBkZWZlbmQgYWdhaW5zdCB0 aGVzZSwgcmVzdHJpY3RpbmcgYWNjZXNzIG9ubHkgdG8gcGx1Z2luJ3MgJnF1b3Q7cGF0aCZxdW90 OyBhbmQgaXRzIHN1Yi1kaXJlY3Rvcmllcy48YnI+DQo8YnI+DQomZ3Q7IDMuICZuYnNwO0lzIC91 c3Ivc2hhcmUvb3ZpcnQtZW5naW5lIHRoZSByaWdodCBwbGFjZSBmb3IgdGhlIHBsdWdpbiBjb25m aWcgZmlsZXM/PGJyPg0KPGJyPg0KSSBzdXBwb3NlIHlvdSBtZWFuIHBsdWdpbiBkZWZpbml0aW9u IGZpbGVzIFthXSwgY2Fubm90IHRlbGwgZm9yIHN1cmUsIGJ1dCB3ZSBjYW4gY2hhbmdlIHRoaXMg YW55dGltZSA6KTxicj4NCjxicj4NCjxicj4NCkNocmlzLCBwbGVhc2UgbGV0IG1lIGtub3cgd2hh dCB5b3UgdGhpbmssIGFuZCBhZ2FpbiAtIG1hbnkgdGhhbmtzIGZvciBzZW5kaW5nIHRoZSBwYXRj aCE8YnI+DQo8YnI+DQo8YnI+DQpSZWdhcmRzLDxicj4NClZvanRlY2g8YnI+DQo8YnI+DQo8bzpw PjwvbzpwPjwvc3Bhbj48L3A+DQo8ZGl2IGNsYXNzPSJNc29Ob3JtYWwiIGFsaWduPSJjZW50ZXIi IHN0eWxlPSJ0ZXh0LWFsaWduOmNlbnRlciI+PHNwYW4gc3R5bGU9ImNvbG9yOmJsYWNrIj4NCjxo ciBzaXplPSIyIiB3aWR0aD0iMTAwJSIgYWxpZ249ImNlbnRlciIgaWQ9Inp3Y2hyIj4NCjwvc3Bh bj48L2Rpdj4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiIHN0eWxlPSJtYXJnaW4tYm90dG9tOjEyLjBw dCI+PHNwYW4gc3R5bGU9ImNvbG9yOmJsYWNrIj48YnI+DQpGcm9tOiAmcXVvdDtDaHJpcyBGcmFu dHomcXVvdDsgJmx0OzxhIGhyZWY9Im1haWx0bzpDaHJpcy5GcmFudHpAaHAuY29tIj5DaHJpcy5G cmFudHpAaHAuY29tPC9hPiZndDs8YnI+DQpUbzogPGEgaHJlZj0ibWFpbHRvOnZzem9jc0ByZWRo YXQuY29tIj52c3pvY3NAcmVkaGF0LmNvbTwvYT48YnI+DQpTZW50OiBXZWRuZXNkYXksIEF1Z3Vz dCAyMiwgMjAxMiA3OjU2OjQ1IFBNPGJyPg0KU3ViamVjdDogVUkgUGx1Z2lucyBjb25maWd1cmF0 aW9uPGJyPg0KPGJyPg0KVm9qdGVjaCw8YnI+DQo8YnI+DQpJIGRlY2lkZWQgdG8gd29yayBvbiBt YWtpbmcgdGhlIHBsdWdpbiBwYXRjaCBhIGJpdCBtb3JlIGNvbmZpZ3VyYWJsZSwgZm9sbG93aW5n IHNvbWUgb2YgdGhlIGlkZWFzIGV4cHJlc3NlZCBieSBJdGFtYXIgYW5kIG90aGVycyBpbiB0aGUg bWVldGluZyB5ZXN0ZXJkYXkuICZuYnNwO1RoZSBhdHRhY2hlZCBwYXRjaCBpcyBhIHNpbXBsZSBm aXJzdC1hdHRlbXB0Ljxicj4NCjxicj4NClBsdWdpbiBjb25maWd1cmF0aW9ucyBhcmUgc3RvcmVk IGluIC91c3Ivc2hhcmUvb3ZpcnQtZW5naW5lL3VpLXBsdWdpbnMvKi5qc29uLjxicj4NCjxicj4N CkV4YW1wbGU6PGJyPg0Kezxicj4NCiZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNw OyZuYnNwOyZuYnNwOyZxdW90O25hbWUmcXVvdDs6ICZxdW90O3Rlc3QmcXVvdDssPGJyPg0KJm5i c3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7JnF1b3Q7dmVyc2lv biZxdW90OzogJnF1b3Q7MS4wJnF1b3Q7LDxicj4NCiZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZu YnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZxdW90O3VybCZxdW90OzogJnF1b3Q7L3dlYmFkbWluL3dl YmFkbWluL3BsdWdpbi90ZXN0L2Zvby5odG1sJnF1b3Q7LDxicj4NCiZuYnNwOyZuYnNwOyZuYnNw OyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZxdW90O3BhdGgmcXVvdDs6ICZxdW90Oy90 bXAmcXVvdDssPGJyPg0KJm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7 Jm5ic3A7JnF1b3Q7Y29uZmlnJnF1b3Q7OiB7JnF1b3Q7YSZxdW90OzoxLCAmcXVvdDtiJnF1b3Q7 OjIsICZxdW90O2MmcXVvdDs6IDN9PGJyPg0KfTxicj4NCjxicj4NClRoZSBlbmdpbmUgcmVhZHMg YWxsIG9mIHRoZSAqLmpzb24gZmlsZXMgaW4gdGhhdCBkaXJlY3RvcnkgdG8gYnVpbGQgdGhlIGxp c3Qgb2Yga25vd24gcGx1Z2lucyBhbmQgZ2l2ZXMgdGhhdCBsaXN0IHRvIHRoZSB3ZWJhZG1pbi48 YnI+DQo8YnI+DQpXaGVuIHdlYmFkbWluIGxvYWRzIGEgcGx1Z2luLCBpdCByZXF1ZXN0cyB0aGUg VVJMIGdpdmVuIGluIHRoZSBwbHVnaW4gY29uZmlnIGZpbGUuICZuYnNwO1RoZSAmcXVvdDtwbHVn aW4mcXVvdDsgVVJMIGlzIG1hcHBlZCB0byBQbHVnaW5Tb3VyY2VQYWdlLCB3aGljaCB3aWxsIHRy YW5zbGF0ZSB0aGUgZmlyc3QgcGFydCBvZiB0aGUgcGF0aCAoJnF1b3Q7dGVzdCZxdW90OykgaW50 byB3aGF0ZXZlciBwYXRoIGlzIHN0b3JlZCBpbiBwbHVnaW5Db25maWcgKCZxdW90Oy90bXAmcXVv dDspIGluIHRoaXMgY2FzZSwNCiBhbmQgdGhlbiBzZXJ2ZSB0aGUgc3RhdGljIGZpbGUgKGUuZy4g JnF1b3Q7L3RtcC9mb28uaHRtbCZxdW90OykuPGJyPg0KPGJyPg0KSSBkaWRuJ3QgdXNlIHRoZSBy ZW5kZXJQbHVnaW5Tb3VyY2VQYWdlKCkgbWV0aG9kIGluIGZhdm9yIG9mIGp1c3Qgc2VydmluZyBh IHN0YXRpYyBmaWxlLCBidXQgSSBoYXZlIG5vIHN0cm9uZyBvcGluaW9uIG9uIHRoZSBtYXR0ZXIu ICZuYnNwO0hvd2V2ZXIsIGEgcGx1Z2luIG1heSB3YW50IHRvIHN0b3JlIHN0YXRpYyByZXNvdXJj ZXMgYXQgJnF1b3Q7cGF0aCZxdW90OyBhbmQgaGF2ZSB0aGUgZW5naW5lIHNlcnZlIHRob3NlIHJl c291cmNlcy4gJm5ic3A7QnkganVzdCBzZXJ2aW5nDQogZmlsZXMgdGhyb3VnaCBQbHVnaW5Tb3Vy Y2VQYWdlLCB3ZSBkb24ndCBuZWVkIGFueSBvdGhlciBzZXJ2bGV0cyB0byBwcm92aWRlIHRob3Nl IHJlc291cmNlcy48YnI+DQo8YnI+DQpUaGVyZSBpcyBzdGlsbCBhIGJpdCBvZiB3b3JrIHRvIGRv Ojxicj4NCjxicj4NCjEuICZuYnNwO1RoZSBwbHVnaW4gY29uZmlndXJhdGlvbiBmaWxlcyBzaG91 bGQgcHJvYmFibHkgaGF2ZSBhbiAmcXVvdDtlbmFibGVkJnF1b3Q7IGZpZWxkIGFuZCBhbiAmcXVv dDthcGlWZXJzaW9uJnF1b3Q7IGZpZWxkIHRoYXQgc2hvdWxkIGJlIGV4YW1pbmVkIHRvIGRldGVy bWluZSB3aGV0aGVyIG9yIG5vdCB0byB1c2UgdGhlIHBsdWdpbi48YnI+DQo8YnI+DQoyLiAmbmJz cDtJIHN1c3BlY3QgdGhlIHdheSBJJ3ZlIG1vZGlmaWVkIFBsdWdpblNvdXJjZVBhZ2UgbWFrZXMg aXQgdnVsbmVyYWJsZSB0byBkaXJlY3RvcnkgY2xpbWJpbmcgYXR0YWNrcy48YnI+DQo8YnI+DQoz LiAmbmJzcDtJcyAvdXNyL3NoYXJlL292aXJ0LWVuZ2luZSB0aGUgcmlnaHQgcGxhY2UgZm9yIHRo ZSBwbHVnaW4gY29uZmlnIGZpbGVzPzxicj4NCjxicj4NCkxldCBtZSBrbm93IHdoYXQgeW91IHRo aW5rLDxicj4NCi0tQ2hyaXM8bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQo8L2Rpdj4NCjwvZGl2Pg0K PC9ib2R5Pg0KPC9odG1sPg0K --_000_A24D665DC3ECC245A2EA0D9A958F80B62C4900E8G9W0745americas_--

On 08/23/2012 06:12 PM, Frantz, Chris wrote:
Vojtech,
Your assumption about the structure of the pluginDefinitions object is correct. It’s no longer a String->String mapping , but a String to Object mapping.
I liked the original IIFE approach, except that it seemed that having additional static resources (jquery, images, html templates, etc) was going to be more cumbersome. I don’t think having the plugin author write a basic start.html is that big of a burden :).
I agree that the plugin configuration was always going to be a resource (probably a local file) that the end user could customize. I’m not sure it I really needs to be separate from the plugin definition file (/usr/share/ovirt-engine/ui-plugins/test.json). I suppose it depends on how complex the configuration is going to be and on some of the implementation details surrounding the plugin definition file.
if we expect a user to "touch" it (change url of external service, etc.) it must be under /etc as a config file. so we should separate what we exepct admin to change (config) and what is part of the plugin itself ("definition"?) which would reside where the code lives.
In my patch, I simply used Jackson to parse the file into a tree of JsonNodes. Should the plugin definition be a java object of some sort? (please please please don’t make me learn about java beans…). I stuck with the JsonNodes because Jackson makes them easy to work with and they’re really easy to re-serialize back to json to give to the webadmin.
We should probably turn on JsonParser.Feature.ALLOW_COMMENTS. The definition and config files will difficult for end-users (or even developers) to understand without comments.
We need to formalize the structure of the plugin definition and decide which fields are mandatory and which are optional:
{
# Mandatory fields: name, enabled, version, url, apiversion, author, license # Name of the plugin
"name": "test",
# Whether or not plugin is enabed
"enabled": true,
# version of the plugin
"version": "1.0",
# How to load the plugin
"url": "/webadmin/webadmin/plugin/test/start.html",
# Which version of engine plugin is meant to work with
"apiversion": "3.1.0",
# Who wrote the plugin and how is it licensed?
"author": "SuperBig Corporation", "license": "Proprietary",
# Optional fields path, config
# Where to locate plugin (if loaded by webadmin/plugin)
"path": "/tmp",
# Plugin configuration information (if any)
"config": "test-config.json", }
I can work on the plugin Definition loader some more and make it enforce mandatory/optional fields. I’ll also investigate the directory climbing issue I mentioned in my previous mail.
Also, I’m curious how things are going to work when the “url” points to a foreign resource as the plugin start page. I don’t think the plugin’s iframe is going to be able to access parent.pluginApi. Perhaps there is some aspect of CORS that I don’t understand?
Thanks,
--Chris
*From:*Vojtech Szocs [mailto:vszocs@redhat.com] *Sent:* Thursday, August 23, 2012 7:14 AM *To:* Frantz, Chris *Cc:* engine-devel *Subject:* Re: UI Plugins configuration
Hi Chris,
thanks for taking the time to make this patch, these are some excellent ideas! (CC'ing engine-devel so that we can discuss this with other guys as well)
First of all, I really like the way you designed plugin source page URLs (going through /PluginSourcePageServlet/), e.g. "/webadmin/webadmin/plugin/<pluginName>/<pluginSourcePage>.html", plus the concept of "path" JSON attribute.
/WebadminDynamicHostingServlet/ loads and caches all plugin definitions (/*.json/ files), and directly embeds them into WebAdmin host page as /pluginDefinitions/ JavaScript object. I'm assuming that /pluginDefinitions/ object will now look like this:
var pluginDefinitions = { "test": { "name": "test", "version": "1.0", "url": "/webadmin/webadmin/plugin/test/foo.html", "path": "/tmp", "config": {"a":1, "b":2, "c":3} } }
Originally, the /pluginDefinitions/ object looked like this:
var pluginDefinitions = { "test": "/webadmin/webadmin/plugin/test/foo.html" // Simple pluginName -> pluginSourcePageUrl mappings }
This is because PluginManager (WebAdmin) only needs /pluginName/ ("name") and /pluginSourcePageUrl/ ("url") during startup, when creating plugin iframe. But this can be changed :)
Plugin "version" makes sense, plus the plugin configuration object ("config") can be useful directly on the client. Let me explain:
Originally, plugin configuration was supposed to be passed to actual plugin code (through immediately-invoked-function-expression, or IIFE), just like this:
(function (pluginApi, pluginConfig) { // JavaScript IIFE // ... actual plugin code ... })( parent.pluginApi, /* reference to global pluginApi object */ {"a":1, "b":2, "c":3} /* embedded plugin configuration as JavaScript object */ );
The whole purpose of /PluginSourcePageServlet/ was to "wrap" actual plugin code into HTML, so that users don't need to write HTML pages for their plugins manually. /PluginSourcePageServlet/ would handle any plugin dependencies (placed into HTML head), with actual plugin code being wrapped into IIFE, as shown above. Plugin configuration was meant to be stored in a separate file, e.g. /<pluginName>-config.json/, so that users could change the default plugin configuration to suit their needs.
Inspired by your patch, rather than reading/embedding plugin configuration when serving plugin HTML page (/PluginSourcePageServlet/), it's even better to have the plugin configuration embedded directly into WebAdmin host page, along with introducing new /pluginApi/ function to retrieve the plugin configuration object.
Based on this, I suggest following modifications to the original concept:
- modify original /pluginDefinitions/ structure, from /pluginName -> pluginSourcePageUrl/, to /pluginName -> pluginDefObject/ - /pluginDefObject/ is basically a subset of physical plugin definition (/test.json/, see below), suitable for use on the client - add following attributes to /pluginDefObject/: /version/, /url/, /config/ * note #1: /name/ is not needed, since it's already the key of /pluginName -> pluginDefObject/ mapping * note #2: /path/ is not needed on the client (more on this below) - introduce /pluginApi.config(pluginName)/ function for plugins to retrieve their configuration object, and remove /pluginConfig/ parameter from main IIFE (as shown above)
[a] Physical plugin definition file (JSON) might be located at oVirt "DataDir", e.g. //usr/share/ovirt-engine/ui-plugins/test.json/, for example:
{ "name": "test", "version": "1.0", "url": "/webadmin/webadmin/plugin/test/start.html", "path": "/tmp", "config": "test-config.json" }
[b] Plugin configuration file (JSON) might be located at oVirt "ConfigDir", e.g. //etc/ovirt-engine/ui-plugins/test-config.json/, for example:
{ "a":1, "b":2, "c":3 }
[c] Finally, plugin static resources (plugin source page, actual plugin code, plugin dependencies, CSS/images, etc.) would be located at //tmp/ (as shown in [a]), for example:
/tmp/start.html -> plugin source page, used to load actual plugin code /tmp/test.js -> actual plugin code /tmp/deps/jquery-min.js -> simulate 3rd party plugin dependency
For example: "/webadmin/webadmin/plugin/test/start.html" will be mapped to //tmp/start.html/ "/webadmin/webadmin/plugin/test/deps/jquery-min.js" will be mapped to //tmp/deps/jquery-min.js/
This approach has some pros and cons: (+) plugin static resources can be served through /PluginSourcePageServlet/ (pretty much like oVirt documentation resources, served through oVirt Engine root war's /FileServlet/) (+) plugin author has complete control over plugin source page (-) plugin author actually needs to write plugin source page
Overall, I think this approach is better than the previous one (where /PluginSourcePageServlet/ took care of rendering plugin source page, but sacrificed some flexibility).
By the way, here's what would happen behind the scenes:
1. user requests WebAdmin host page, /WebadminDynamicHostingServlet/ loads and caches all plugin definitions [a] + plugin configurations [b] and constructs/embeds appropriate /pluginDefinitions/ JavaScript object 2. during WebAdmin startup, /PluginManager/ registers the plugin (name/version/url/config), and creates/attaches the iframe to fetch plugin source page ansynchronously 3. /PluginSourcePageServlet/ handles plugin source page request, resolves the correct path [c] and just streams the file content back to client
1. The plugin configuration files should probably have an "enabled" field and an "apiVersion" field that should be examined to determine whether or not to use the plugin.
Sounds good, we can implement these later on :)
2. I suspect the way I've modified PluginSourcePage makes it vulnerable to directory climbing attacks.
Yes, but we can defend against these, restricting access only to plugin's "path" and its sub-directories.
3. Is /usr/share/ovirt-engine the right place for the plugin config files?
I suppose you mean plugin definition files [a], cannot tell for sure, but we can change this anytime :)
Chris, please let me know what you think, and again - many thanks for sending the patch!
Regards, Vojtech
------------------------------------------------------------------------
From: "Chris Frantz" <Chris.Frantz@hp.com <mailto:Chris.Frantz@hp.com>> To: vszocs@redhat.com <mailto:vszocs@redhat.com> Sent: Wednesday, August 22, 2012 7:56:45 PM Subject: UI Plugins configuration
Vojtech,
I decided to work on making the plugin patch a bit more configurable, following some of the ideas expressed by Itamar and others in the meeting yesterday. The attached patch is a simple first-attempt.
Plugin configurations are stored in /usr/share/ovirt-engine/ui-plugins/*.json.
Example: { "name": "test", "version": "1.0", "url": "/webadmin/webadmin/plugin/test/foo.html", "path": "/tmp", "config": {"a":1, "b":2, "c": 3} }
The engine reads all of the *.json files in that directory to build the list of known plugins and gives that list to the webadmin.
When webadmin loads a plugin, it requests the URL given in the plugin config file. The "plugin" URL is mapped to PluginSourcePage, which will translate the first part of the path ("test") into whatever path is stored in pluginConfig ("/tmp") in this case, and then serve the static file (e.g. "/tmp/foo.html").
I didn't use the renderPluginSourcePage() method in favor of just serving a static file, but I have no strong opinion on the matter. However, a plugin may want to store static resources at "path" and have the engine serve those resources. By just serving files through PluginSourcePage, we don't need any other servlets to provide those resources.
There is still a bit of work to do:
1. The plugin configuration files should probably have an "enabled" field and an "apiVersion" field that should be examined to determine whether or not to use the plugin.
2. I suspect the way I've modified PluginSourcePage makes it vulnerable to directory climbing attacks.
3. Is /usr/share/ovirt-engine the right place for the plugin config files?
Let me know what you think, --Chris
_______________________________________________ Engine-devel mailing list Engine-devel@ovirt.org http://lists.ovirt.org/mailman/listinfo/engine-devel

------=_Part_14115416_27862123.1346078924448 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Hi Chris,=20
Your assumption about the structure of the pluginDefinitions object is co= rrect. It=E2=80=99s no longer a String->String mapping , but a String to Ob= ject mapping.=20
Yes :) but maybe we could also formalize some terms, for example:=20 Plugin descriptor is the JSON file that contains important plugin meta-data= (including the plugin source page URL), e.g. /usr/share/ovirt-engine/ui-pl= ugins/test.json=20 Plugin definition is the JavaScript object representing plugin descriptor m= eta-data suitable for use on client (GWT WebAdmin). Plugin definition is em= bedded into WebAdmin host page within pluginDefinitions object, and read by= PluginManager during WebAdmin startup.=20 Plugin configuration is the JSON file that contains optional plugin configu= ration, e.g. /etc/ovirt-engine/ui-plugins/test-config.json=20 I think we can combine two things here:=20 1) allow plugin authors to define standard (fallback) configuration directl= y inside plugin descriptor=20 2) allow plugin users to override standard configuration by modifying dedic= ated plugin configuration file=20 Finally, plugin source page is the HTML page used to invoke actual plugin c= ode (this page is referenced by plugin descriptor's "url" attribute). Plugi= n source page can also load external resources required by the plugin, e.g.= 3rd party JavaScript libraries, CSS, images, etc.=20
I liked the original IIFE approach, except that it seemed that having add= itional static resources (jquery, images, html templates, etc) was going to= be more cumbersome. I don=E2=80=99t think having the plugin author write a= basic start.html is that big of a burden :).=20
I agree that the plugin configuration was always going to be a resource (=
You're right, for such additional plugin resources, even more configuration= /parsing/logic would be required. Even though plugin authors need to write = the plugin source page themselves, they have full control over it, which is= a good thing in general.=20 probably a local file) that the end user could customize. I=E2=80=99m not s= ure it I really needs to be separate from the plugin definition file (/usr/= share/ovirt-engine/ui-plugins/test.json). I suppose it depends on how compl= ex the configuration is going to be and on some of the implementation detai= ls surrounding the plugin definition file.=20 Yeah, let's make the concept of the plugin configuration file optional for = now (standard plugin configuration can be part of plugin descriptor).=20
In my patch, I simply used Jackson to parse the file into a tree of JsonN= odes. Should the plugin definition be a java object of some sort? (please p= lease please don=E2=80=99t make me learn about java beans=E2=80=A6). I stuc= k with the JsonNodes because Jackson makes them easy to work with and they= =E2=80=99re really easy to re-serialize back to json to give to the webadmi= n.=20
I think using Jackson's JSON representation in Java (JsonNode) is perfectly= suitable in this situation. No need to have separate Java bean for that :)= =20
We should probably turn on JsonParser.Feature.ALLOW_COMMENTS. The definit= ion and config files will difficult for end-users (or even developers) to u= nderstand without comments.=20
Agreed.=20
We need to formalize the structure of the plugin definition and decide wh= ich fields are mandatory and which are optional=20
Sounds good, but I'd skip some attributes for now (enabled, apiVersion, aut= hor, license) for the sake of simplicity.=20 As you wrote, when loading plugin descriptor, we should enforce mandatory a= ttributes (name, version, url) .=20 As for plugin configuration, there could be two different attributes:=20 - "config" for standard (fallback) plugin configuration (JSON object)=20 - "configFile" for external plugin configuration file (path to file, relati= ve to /etc/ovirt-engine/ui-plugins/ ) , that overrides the standard configu= ration=20 Note that when loading plugin descriptor, the loader should also "merge" th= e configuration together (custom config on top of standard config).=20
I can work on the plugin Definition loader some more and make it enforce = mandatory/optional fields. I=E2=80=99ll also investigate the directory clim= bing issue I mentioned in my previous mail.=20
Also, I=E2=80=99m curious how things are going to work when the =E2=80=9C= url=E2=80=9D points to a foreign resource as the plugin start page. I don= =E2=80=99t think the plugin=E2=80=99s iframe is going to be able to access =
Sounds good! I was planning to incorporate your original patch in next PoC = revision, but of course, you can work on the loader some more and send anot= her patch :)=20 For the directory climbing issue, see <OVIRT_ROOT>/backend/manager/modules/= root/src/main/java/org/ovirt/engine/core/FileServlet.java (there's a method= called isSane for dealing with such issue).=20 parent.pluginApi. Perhaps there is some aspect of CORS that I don=E2=80=99t= understand?=20 When the plugin iframe references a resource on different origin (protocol,= domain, port) than WebAdmin main page origin, JavaScript code running insi= de that iframe will not be able to access parent (top-level) pluginApi obje= ct. You're right, the statement "parent.pluginApi" will not work, because o= f Same-Origin Policy enforced by the browser.=20 CORS is just one alternative, see http://stackoverflow.com/questions/307641= 4/ways-to-circumvent-the-same-origin-policy for more. However, CORS needs t= o be supported by the browser (a special HTTP response header is used to te= ll that the iframe is allowed to access resources from another - WebAdmin m= ain page - origin). We need to investigate this a bit more I guess.=20 Regards,=20 Vojtech=20 ----- Original Message ----- From: "Chris Frantz" <Chris.Frantz@hp.com>=20 To: "Vojtech Szocs" <vszocs@redhat.com>=20 Cc: "engine-devel" <engine-devel@ovirt.org>=20 Sent: Thursday, August 23, 2012 5:12:02 PM=20 Subject: RE: UI Plugins configuration=20 Vojtech,=20 Your assumption about the structure of the pluginDefinitions object is corr= ect. It=E2=80=99s no longer a String->String mapping , but a String to Obje= ct mapping.=20 I liked the original IIFE approach, except that it seemed that having addit= ional static resources (jquery, images, html templates, etc) was going to b= e more cumbersome. I don=E2=80=99t think having the plugin author write a b= asic start.html is that big of a burden :).=20 I agree that the plugin configuration was always going to be a resource (pr= obably a local file) that the end user could customize. I=E2=80=99m not sur= e it I really needs to be separate from the plugin definition file (/usr/sh= are/ovirt-engine/ui-plugins/test.json). I suppose it depends on how complex= the configuration is going to be and on some of the implementation details= surrounding the plugin definition file.=20 In my patch, I simply used Jackson to parse the file into a tree of JsonNod= es. Should the plugin definition be a java object of some sort? (please ple= ase please don=E2=80=99t make me learn about java beans=E2=80=A6). I stuck = with the JsonNodes because Jackson makes them easy to work with and they=E2= =80=99re really easy to re-serialize back to json to give to the webadmin.= =20 We should probably turn on JsonParser.Feature.ALLOW_COMMENTS. The definitio= n and config files will difficult for end-users (or even developers) to und= erstand without comments.=20 We need to formalize the structure of the plugin definition and decide whic= h fields are mandatory and which are optional:=20 {=20 # Mandatory fields: name, enabled, version, url, apiversion, author, licens= e=20 # Name of the plugin=20 "name": "test",=20 # Whether or not plugin is enabed=20 "enabled": true,=20 # version of the plugin=20 "version": "1.0",=20 # How to load the plugin=20 "url": "/webadmin/webadmin/plugin/test/start.html",=20 # Which version of engine plugin is meant to work with=20 "apiversion": "3.1.0",=20 # Who wrote the plugin and how is it licensed?=20 "author": "SuperBig Corporation",=20 "license": "Proprietary",=20 # Optional fields path, config=20 # Where to locate plugin (if loaded by webadmin/plugin)=20 "path": "/tmp",=20 # Plugin configuration information (if any)=20 "config": "test-config.json",=20 }=20 I can work on the plugin Definition loader some more and make it enforce ma= ndatory/optional fields. I=E2=80=99ll also investigate the directory climbi= ng issue I mentioned in my previous mail.=20 Also, I=E2=80=99m curious how things are going to work when the =E2=80=9Cur= l=E2=80=9D points to a foreign resource as the plugin start page. I don=E2= =80=99t think the plugin=E2=80=99s iframe is going to be able to access par= ent.pluginApi. Perhaps there is some aspect of CORS that I don=E2=80=99t un= derstand?=20 Thanks,=20 --Chris=20 From: Vojtech Szocs [mailto:vszocs@redhat.com]=20 Sent: Thursday, August 23, 2012 7:14 AM=20 To: Frantz, Chris=20 Cc: engine-devel=20 Subject: Re: UI Plugins configuration=20 Hi Chris,=20 thanks for taking the time to make this patch, these are some excellent ide= as! (CC'ing engine-devel so that we can discuss this with other guys as wel= l)=20 First of all, I really like the way you designed plugin source page URLs (g= oing through PluginSourcePageServlet ), e.g. "/webadmin/webadmin/plugin/<pl= uginName>/<pluginSourcePage>.html", plus the concept of "path" JSON attribu= te.=20 WebadminDynamicHostingServlet loads and caches all plugin definitions ( *.j= son files), and directly embeds them into WebAdmin host page as pluginDefin= itions JavaScript object. I'm assuming that pluginDefinitions object will n= ow look like this:=20 var pluginDefinitions =3D {=20 "test": {=20 "name": "test",=20 "version": "1.0",=20 "url": "/webadmin/webadmin/plugin/test/foo.html",=20 "path": "/tmp",=20 "config": {"a":1, "b":2, "c":3}=20 }=20 }=20 Originally, the pluginDefinitions object looked like this:=20 var pluginDefinitions =3D {=20 "test": "/webadmin/webadmin/plugin/test/foo.html" // Simple pluginName -> p= luginSourcePageUrl mappings=20 }=20 This is because PluginManager (WebAdmin) only needs pluginName ("name") and= pluginSourcePageUrl ("url") during startup, when creating plugin iframe. B= ut this can be changed :)=20 Plugin "version" makes sense, plus the plugin configuration object ("config= ") can be useful directly on the client. Let me explain:=20 Originally, plugin configuration was supposed to be passed to actual plugin= code (through immediately-invoked-function-expression, or IIFE), just like= this:=20 (function (pluginApi, pluginConfig) { // JavaScript IIFE=20 // ... actual plugin code ...=20 })(=20 parent.pluginApi, /* reference to global pluginApi object */=20 {"a":1, "b":2, "c":3} /* embedded plugin configuration as JavaScript object= */=20 );=20 The whole purpose of PluginSourcePageServlet was to "wrap" actual plugin co= de into HTML, so that users don't need to write HTML pages for their plugin= s manually. PluginSourcePageServlet would handle any plugin dependencies (p= laced into HTML head), with actual plugin code being wrapped into IIFE, as = shown above. Plugin configuration was meant to be stored in a separate file= , e.g. <pluginName>-config.json , so that users could change the default pl= ugin configuration to suit their needs.=20 Inspired by your patch, rather than reading/embedding plugin configuration = when serving plugin HTML page ( PluginSourcePageServlet ), it's even better= to have the plugin configuration embedded directly into WebAdmin host page= , along with introducing new pluginApi function to retrieve the plugin conf= iguration object.=20 Based on this, I suggest following modifications to the original concept:= =20 - modify original pluginDefinitions structure, from pluginName -> pluginSou= rcePageUrl , to pluginName -> pluginDefObject=20 - pluginDefObject is basically a subset of physical plugin definition ( tes= t.json , see below), suitable for use on the client=20 - add following attributes to pluginDefObject : version , url , config=20 * note #1: name is not needed, since it's already the key of pluginName -> = pluginDefObject mapping=20 * note #2: path is not needed on the client (more on this below)=20 - introduce pluginApi.config(pluginName) function for plugins to retrieve t= heir configuration object, and remove pluginConfig parameter from main IIFE= (as shown above)=20 [a] Physical plugin definition file (JSON) might be located at oVirt "DataD= ir", e.g. /usr/share/ovirt-engine/ui-plugins/test.json , for example:=20 {=20 "name": "test",=20 "version": "1.0",=20 "url": "/webadmin/webadmin/plugin/test/start.html",=20 "path": "/tmp",=20 "config": "test-config.json"=20 }=20 [b] Plugin configuration file (JSON) might be located at oVirt "ConfigDir",= e.g. /etc/ovirt-engine/ui-plugins/test-config.json , for example:=20 {=20 "a":1, "b":2, "c":3=20 }=20 [c] Finally, plugin static resources (plugin source page, actual plugin cod= e, plugin dependencies, CSS/images, etc.) would be located at /tmp (as show= n in [a]), for example:=20 /tmp/start.html -> plugin source page, used to load actual plugin code=20 /tmp/test.js -> actual plugin code=20 /tmp/deps/jquery-min.js -> simulate 3rd party plugin dependency=20 For example:=20 "/webadmin/webadmin/plugin/test/start.html" will be mapped to /tmp/start.ht= ml=20 "/webadmin/webadmin/plugin/test/deps/jquery-min.js" will be mapped to /tmp/= deps/jquery-min.js=20 This approach has some pros and cons:=20 (+) plugin static resources can be served through PluginSourcePageServlet (= pretty much like oVirt documentation resources, served through oVirt Engine= root war's FileServlet )=20 (+) plugin author has complete control over plugin source page=20 (-) plugin author actually needs to write plugin source page=20 Overall, I think this approach is better than the previous one (where Plugi= nSourcePageServlet took care of rendering plugin source page, but sacrifice= d some flexibility).=20 By the way, here's what would happen behind the scenes:=20 1. user requests WebAdmin host page, WebadminDynamicHostingServlet load= s and caches all plugin definitions [a] + plugin configurations [b] and con= structs/embeds appropriate pluginDefinitions JavaScript object=20 2. during WebAdmin startup, PluginManager registers the plugin (name/ve= rsion/url/config), and creates/attaches the iframe to fetch plugin source p= age ansynchronously=20 3. PluginSourcePageServlet handles plugin source page request, resolves= the correct path [c] and just streams the file content back to client=20
1. The plugin configuration files should probably have an "enabled" field= and an "apiVersion" field that should be examined to determine whether or = not to use the plugin.=20
Sounds good, we can implement these later on :)=20
2. I suspect the way I've modified PluginSourcePage makes it vulnerable t= o directory climbing attacks.=20
Yes, but we can defend against these, restricting access only to plugin's "= path" and its sub-directories.=20
3. Is /usr/share/ovirt-engine the right place for the plugin config files= ?=20
- "config" for standard (fallback) plugin configuration (JSON object)<br>-= "configFile" for external plugin configuration file (path to file, relativ= e to <span style=3D"color:black">/etc/ovirt-engine/ui-plugins/)</span>, tha= t overrides the standard configuration<br><br>Note that when loading plugin= descriptor, the loader should also "merge" the configuration together (cus= tom config on top of standard config).<br><br><span style=3D"font-size:11.0=
I suppose you mean plugin definition files [a], cannot tell for sure, but w= e can change this anytime :)=20 Chris, please let me know what you think, and again - many thanks for sendi= ng the patch!=20 Regards,=20 Vojtech=20 ----- Original Message ----- From: "Chris Frantz" < Chris.Frantz@hp.com >=20 To: vszocs@redhat.com=20 Sent: Wednesday, August 22, 2012 7:56:45 PM=20 Subject: UI Plugins configuration=20 Vojtech,=20 I decided to work on making the plugin patch a bit more configurable, follo= wing some of the ideas expressed by Itamar and others in the meeting yester= day. The attached patch is a simple first-attempt.=20 Plugin configurations are stored in /usr/share/ovirt-engine/ui-plugins/*.js= on.=20 Example:=20 {=20 "name": "test",=20 "version": "1.0",=20 "url": "/webadmin/webadmin/plugin/test/foo.html",=20 "path": "/tmp",=20 "config": {"a":1, "b":2, "c": 3}=20 }=20 The engine reads all of the *.json files in that directory to build the lis= t of known plugins and gives that list to the webadmin.=20 When webadmin loads a plugin, it requests the URL given in the plugin confi= g file. The "plugin" URL is mapped to PluginSourcePage, which will translat= e the first part of the path ("test") into whatever path is stored in plugi= nConfig ("/tmp") in this case, and then serve the static file (e.g. "/tmp/f= oo.html").=20 I didn't use the renderPluginSourcePage() method in favor of just serving a= static file, but I have no strong opinion on the matter. However, a plugin= may want to store static resources at "path" and have the engine serve tho= se resources. By just serving files through PluginSourcePage, we don't need= any other servlets to provide those resources.=20 There is still a bit of work to do:=20 1. The plugin configuration files should probably have an "enabled" field a= nd an "apiVersion" field that should be examined to determine whether or no= t to use the plugin.=20 2. I suspect the way I've modified PluginSourcePage makes it vulnerable to = directory climbing attacks.=20 3. Is /usr/share/ovirt-engine the right place for the plugin config files?= =20 Let me know what you think,=20 --Chris=20 ------=_Part_14115416_27862123.1346078924448 Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable <html><head><style type=3D'text/css'>p { margin: 0; }</style></head><body><= div style=3D'font-family: times new roman,new york,times,serif; font-size: = 12pt; color: #000000'>Hi Chris,<br><br><span style=3D"font-size:11.0pt;font= -family:"Calibri","sans-serif";color:#1F497D">> Your assumption about the structure of the pluginDefinitions object is=20 correct. It=E2=80=99s no longer a String->String mapping , but a S= tring to=20 Object mapping.</span><br><br>Yes :) but maybe we could also formalize some= terms, for example:<br><br><em>Plugin descriptor</em> is the JSON file tha= t contains important plugin meta-data (including the plugin source page URL= ), e.g. <span style=3D"color: black;"><i>/usr/share/ovirt-engine/ui-plugins= /test.json<br><span style=3D"font-style: italic;"><span style=3D"font-style= : italic;"></span></span></i><br><span style=3D"font-style: italic;">Plugin= definition</span> is the JavaScript object representing plugin descriptor = meta-data suitable for use on client (GWT WebAdmin). Plugin definition is e= mbedded into WebAdmin host page within <span style=3D"font-style: italic;">= pluginDefinitions</span> object, and read by <span style=3D"font-style: ita= lic;">PluginManager</span> during WebAdmin startup.<br><i><span style=3D"fo= nt-style: italic;"><span style=3D"font-style: italic;"></span><br>Plugin co= nfiguration</span></i> is the JSON file that contains <strong>optional</str= ong> plugin configuration, e.g. </span><span style=3D"color:black"><i>/etc/= ovirt-engine/ui-plugins/test-config.json</i></span><br><span style=3D"color= : black;"><i><span style=3D"font-style: italic;"><br></span></i>I think we = can combine two things here:<br>1) allow plugin authors to define standard = (fallback) configuration directly inside plugin descriptor<br>2) allow plug= in users to override standard configuration by modifying dedicated plugin c= onfiguration file<br><br>Finally, <span style=3D"font-style: italic;">plugi= n source page</span> is the HTML page used to invoke actual plugin code (th= is page is referenced by plugin descriptor's "url" attribute). Plugin sourc= e page can also load external resources required by the plugin, e.g. 3rd pa= rty JavaScript libraries, CSS, images, etc.<br><br></span><span style=3D"fo= nt-size:11.0pt;font-family:"Calibri","sans-serif";color= :#1F497D">> I liked the original IIFE approach, except that it seemed that having=20 additional static resources (jquery, images, html templates, etc) was=20 going to be more cumbersome. I don=E2=80=99t think having the plugin author write a b= asic=20 start.html is that big of a burden :).</span><br><br>You're right, for such= additional plugin resources, even more configuration/parsing/logic would b= e required. Even though plugin authors need to write the plugin source page= themselves, they have full control over it, which is a good thing in gener= al.<br><br><span style=3D"font-size:11.0pt;font-family:"Calibri",= "sans-serif";color:#1F497D">> I agree that the plugin configuration was always going to be a resource=20 (probably a local file) that the end user could customize. I=E2=80=99= m not sure it I really needs to be separate from the plugin definition file=20 (/usr/share/ovirt-engine/ui-plugins/test.json). I suppose it depends = on how complex the configuration is going to be and on some of the=20 implementation details surrounding the plugin definition file.</span><br><b= r>Yeah, let's make the concept of the plugin configuration file optional fo= r now (standard plugin configuration can be part of plugin descriptor).<br>= <br><span style=3D"font-size:11.0pt;font-family:"Calibri","s= ans-serif";color:#1F497D">> In my patch, I simply used Jackson to parse the file into a tree of=20 JsonNodes. Should the plugin definition be a java object of some sort= ?=20 (please please please don=E2=80=99t make me learn about java beans=E2=80=A6). I stuck with= the JsonNodes=20 because Jackson makes them easy to work with and they=E2=80=99re really eas= y to=20 re-serialize back to json to give to the webadmin.</span><br><br>I think us= ing Jackson's JSON representation in Java (JsonNode) is perfectly suitable = in this situation. No need to have separate Java bean for that :)<br><br><s= pan style=3D"font-size:11.0pt;font-family:"Calibri","sans-se= rif";color:#1F497D">> We should probably turn on JsonParser.Feature.ALLOW_COMMENTS. The=20 definition and config files will difficult for end-users (or even=20 developers) to understand without comments.</span><br><br>Agreed.<br><br><span style=3D"font-size:11= .0pt;font-family:"Calibri","sans-serif";color:#1F497D">= > We need to formalize the structure of the plugin definition and decide= which fields are mandatory and which are optional</span><br><br>Sounds goo= d, but I'd skip some attributes for now (enabled, apiVersion, author, licen= se) for the sake of simplicity.<br><br>As you wrote, when loading plugin de= scriptor, we should enforce mandatory attributes (name, version, url).<br><= br>As for plugin configuration, there could be two different attributes:<br= pt;font-family:"Calibri","sans-serif";color:#1F497D">&g= t; I can work on the plugin Definition loader some more and make it enforce=20 mandatory/optional fields. I=E2=80=99ll also investigate the director= y climbing issue I mentioned in my previous mail.</span><br><br>Sounds good! I was planning to incorpor= ate your original patch in next PoC revision, but of course, you can work o= n the loader some more and send another patch :)<br><br>For the directory c= limbing issue, see <span style=3D"font-style: italic;"><OVIRT_ROOT>/b= ackend/manager/modules/root/src/main/java/org/ovirt/engine/core/FileServlet= .java</span> (there's a method called isSane for dealing with such issue).<= br><br><span style=3D"font-size:11.0pt;font-family:"Calibri",&quo= t;sans-serif";color:#1F497D">> Also, I=E2=80=99m curious how things are going to work when the =E2=80=9Curl=E2= =80=9D points to a=20 foreign resource as the plugin start page. I don=E2=80=99t think the = plugin=E2=80=99s=20 iframe is going to be able to access parent.pluginApi. Perhaps there is some aspect = of CORS that I don=E2=80=99t understand?</span><br><br>When the plugin iframe= references a resource on different origin (protocol, domain, port) than We= bAdmin main page origin, JavaScript code running inside that iframe will no= t be able to access parent (top-level) <span style=3D"font-style: italic;">= pluginApi</span> object. You're right, the statement "parent.pluginApi" wil= l not work, because of Same-Origin Policy enforced by the browser.<br><br>C= ORS is just one alternative, see http://stackoverflow.com/questions/3076414= /ways-to-circumvent-the-same-origin-policy for more. However, CORS needs to= be supported by the browser (a special HTTP response header is used to tel= l that the iframe is allowed to access resources from another - WebAdmin ma= in page - origin). We need to investigate this a bit more I guess.<br><br>R= egards,<br>Vojtech<br><br><br><hr id=3D"zwchr"><div style=3D"color:#000;fon= t-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetic= a,Arial,sans-serif;font-size:12pt;"><b>From: </b>"Chris Frantz" <Chris.F= rantz@hp.com><br><b>To: </b>"Vojtech Szocs" <vszocs@redhat.com><br=
<b>Cc: </b>"engine-devel" <engine-devel@ovirt.org><br><b>Sent: </b>T= hursday, August 23, 2012 5:12:02 PM<br><b>Subject: </b>RE: UI Plugins confi= guration<br><br>
<style><!-- @font-face =09{font-family:"Cambria Math"; =09panose-1:2 4 5 3 5 4 6 3 2 4;} @font-face =09{font-family:Calibri; =09panose-1:2 15 5 2 2 2 4 3 2 4;} @font-face =09{font-family:Tahoma; =09panose-1:2 11 6 4 3 5 4 4 2 4;} p.MsoNormal, li.MsoNormal, div.MsoNormal =09{margin:0in; =09margin-bottom:.0001pt; =09font-size:12.0pt; =09font-family:"Times New Roman","serif";} a:link, span.MsoHyperlink =09{mso-style-priority:99; =09color:blue; =09text-decoration:underline;} a:visited, span.MsoHyperlinkFollowed =09{mso-style-priority:99; =09color:purple; =09text-decoration:underline;} p =09{mso-style-priority:99; =09margin:0in; =09margin-bottom:.0001pt; =09font-size:12.0pt; =09font-family:"Times New Roman","serif";} span.EmailStyle19 =09{mso-style-type:personal-reply; =09font-family:"Calibri","sans-serif"; =09color:#1F497D;} .MsoChpDefault =09{mso-style-type:export-only; =09font-size:10.0pt;} @page WordSection1 =09{size:8.5in 11.0in; =09margin:1.0in 1.0in 1.0in 1.0in;} div.WordSection1 =09{page:WordSection1;} @list l0 =09{mso-list-id:135345730; =09mso-list-template-ids:-1544269566;} ol =09{margin-bottom:0in;} ul =09{margin-bottom:0in;} --></style> <div class=3D"WordSection1"> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D">Vojtech,</span></p> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D"> </span></p> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D">Your assumption about the= structure of the pluginDefinitions object is correct. It=E2=80=99s n= o longer a String->String mapping , but a String to Object mapping.</spa= n></p> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D"> </span></p> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D">I liked the original IIFE= approach, except that it seemed that having additional static resources (j= query, images, html templates, etc) was going to be more cumbersome. I don=E2=80=99t think having the plugin author write a b= asic start.html is that big of a burden :).</span></p> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D"> </span></p> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D">I agree that the plugin c= onfiguration was always going to be a resource (probably a local file) that= the end user could customize. I=E2=80=99m not sure it I really needs to be separate from the plugin definition file (/usr/share/ovirt-eng= ine/ui-plugins/test.json). I suppose it depends on how complex the co= nfiguration is going to be and on some of the implementation details surrou= nding the plugin definition file.</span></p> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D"> </span></p> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D">In my patch, I simply use= d Jackson to parse the file into a tree of JsonNodes. Should the plug= in definition be a java object of some sort? (please please please don=E2=80=99t make me learn about java beans=E2=80=A6). I stuck with= the JsonNodes because Jackson makes them easy to work with and they=E2=80= =99re really easy to re-serialize back to json to give to the webadmin.</sp= an></p> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D"> </span></p> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D">We should probably turn o= n JsonParser.Feature.ALLOW_COMMENTS. The definition and config files = will difficult for end-users (or even developers) to understand without comments.</span></p> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D"> </span></p> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D">We need to formalize the = structure of the plugin definition and decide which fields are mandatory an= d which are optional:</span></p> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D"> </span></p> <p class=3D"MsoNormal"><span style=3D"font-family:"Courier New";c= olor:black">{</span></p> <p class=3D"MsoNormal"><span style=3D"font-family:"Courier New";c= olor:black"> # Mandatory fields: name, enabled, version, url, apivers= ion, author, license<br> # Name of the plugin </span></p> <p class=3D"MsoNormal"><span style=3D"font-family:"Courier New";c= olor:black"> "name": "test",<br> <br> </span></p> <p class=3D"MsoNormal"><span style=3D"font-family:"Courier New";c= olor:black"> # Whether or not plugin is enabed</span></p> <p class=3D"MsoNormal"><span style=3D"font-family:"Courier New";c= olor:black"> "enabled": true,<br> <br> </span></p> <p class=3D"MsoNormal"><span style=3D"font-family:"Courier New";c= olor:black"> # version of the plugin</span></p> <p class=3D"MsoNormal"><span style=3D"font-family:"Courier New";c= olor:black"> "version": "1.0",<br> <br> </span></p> <p class=3D"MsoNormal"><span style=3D"font-family:"Courier New";c= olor:black"> # How to load the plugin</span></p> <p class=3D"MsoNormal"><span style=3D"font-family:"Courier New";c= olor:black"> "url": "/webadmin/webadmin/plugin/test/start.html",= <br> <br> </span></p> <p class=3D"MsoNormal"><span style=3D"font-family:"Courier New";c= olor:black"> # Which version of engine plugin is meant to work with</= span></p> <p class=3D"MsoNormal"><span style=3D"font-family:"Courier New";c= olor:black"> "apiversion": "3.1.0",<br> <br> </span></p> <p class=3D"MsoNormal"><span style=3D"font-family:"Courier New";c= olor:black"> # Who wrote the plugin and how is it licensed?</span></p=
<p class=3D"MsoNormal"><span style=3D"font-family:"Courier New";c= olor:black"> "author": "SuperBig Corporation",<br> "license": "Proprietary",<br> <br> </span></p> <p class=3D"MsoNormal"><span style=3D"font-family:"Courier New";c= olor:black"> # Optional fields path, config</span></p> <p class=3D"MsoNormal"><span style=3D"font-family:"Courier New";c= olor:black"> # Where to locate plugin (if loaded by webadmin/plugin)<= /span></p> <p class=3D"MsoNormal"><span style=3D"font-family:"Courier New";c= olor:black"> "path": "/tmp",</span></p> <p class=3D"MsoNormal"><span style=3D"font-family:"Courier New";c= olor:black"> </span></p> <p class=3D"MsoNormal"><span style=3D"font-family:"Courier New";c= olor:black"> # Plugin configuration information (if any)</span></p> <p class=3D"MsoNormal"><span style=3D"font-family:"Courier New";c= olor:black"> "config": "test-config.json",<br> }</span><span style=3D"color:black"><br> </span><span style=3D"font-size:11.0pt;font-family:"Courier New";= color:#1F497D"> </span></p> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D">I can work on the plugin = Definition loader some more and make it enforce mandatory/optional fields. = I=E2=80=99ll also investigate the directory climbing issue I mentione= d in my previous mail.</span></p> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D"> </span></p> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D">Also, I=E2=80=99m curious= how things are going to work when the =E2=80=9Curl=E2=80=9D points to a fo= reign resource as the plugin start page. I don=E2=80=99t think the pl= ugin=E2=80=99s iframe is going to be able to access parent.pluginApi. Perhaps there is some aspect = of CORS that I don=E2=80=99t understand?</span></p> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D"> </span></p> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D">Thanks,</span></p> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D">--Chris</span></p> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D"> </span></p> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D"> </span></p> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D"> </span></p> <div> <div style=3D"border:none;border-top:solid #B5C4DF 1.0pt;padding:3.0pt 0in = 0in 0in"> <p class=3D"MsoNormal"><b><span style=3D"font-size:10.0pt;font-family:"= ;Tahoma","sans-serif"">From:</span></b><span style=3D"font-s= ize:10.0pt;font-family:"Tahoma","sans-serif""> Vojtech = Szocs [mailto:vszocs@redhat.com] <br> <b>Sent:</b> Thursday, August 23, 2012 7:14 AM<br> <b>To:</b> Frantz, Chris<br> <b>Cc:</b> engine-devel<br> <b>Subject:</b> Re: UI Plugins configuration</span></p> </div> </div> <p class=3D"MsoNormal"> </p> <div> <p class=3D"MsoNormal"><span style=3D"color:black">Hi Chris,<br> <br> thanks for taking the time to make this patch, these are some excellent ide= as! (CC'ing engine-devel so that we can discuss this with other guys as wel= l)<br> <br> First of all, I really like the way you designed plugin source page URLs (g= oing through <em>PluginSourcePageServlet</em>), e.g. "/webadmin/webadmin/plugin/<plug= inName>/<pluginSourcePage>.html", plus the concept of "path" JSON = attribute.<br> <br> <i>WebadminDynamicHostingServlet</i> loads and caches all plugin definition= s (<i>*.json</i> files), and directly embeds them into WebAdmin host page a= s <i>pluginDefinitions</i> JavaScript object. I'm assuming that <i>pluginDefi= nitions</i> object will now look like this:<br> <br> </span><span style=3D"font-family:"Courier New";color:black">var = pluginDefinitions =3D {<br> "test": {<br> "name": "test",<br> "version": "1.0",<br> "url": "/webadmin/webadmin/plugin/test/foo.html",<br> "path": "/tmp",<br> "config": {"a":1, "b":2, "c":3}<br> }<br> }</span><span style=3D"color:black"><br> <br> Originally, the <i>pluginDefinitions</i> object looked like this:<br> </span><span style=3D"font-family:"Courier New";color:black"><br> var pluginDefinitions =3D {<br> "test": "/webadmin/webadmin/plugin/test/foo.html" // Simple plu= ginName -> pluginSourcePageUrl mappings<br> }</span><span style=3D"color:black"><br> <br> This is because PluginManager (WebAdmin) only needs <i>pluginName</i> ("nam= e") and <i>pluginSourcePageUrl</i> ("url") during startup, when creating plugin ifr= ame. But this can be changed :)<br> <br> Plugin "version" makes sense, plus the plugin configuration object ("config= ") can be useful directly on the client. Let me explain:<br> <br> Originally, plugin configuration was supposed to be passed to actual plugin= code (through immediately-invoked-function-expression, or IIFE), just like= this:<br> </span><span style=3D"font-family:"Courier New";color:black"><br> (function (pluginApi, pluginConfig) { // JavaScript IIFE<br> // ... actual plugin code ...<br> })(<br> parent.pluginApi, /* reference to global pluginApi object */<br=
{"a":1, "b":2, "c":3} /* embedded plugin configuration as JavaS= cript object */<br> );</span><span style=3D"color:black"><br> <br> The whole purpose of <i>PluginSourcePageServlet</i> was to "wrap" actual pl= ugin code into HTML, so that users don't need to write HTML pages for their= plugins manually. <i>PluginSourcePageServlet</i> would handle any plugin dependencies (placed= into HTML head), with actual plugin code being wrapped into IIFE, as shown= above. Plugin configuration was meant to be stored in a separate file, e.g= . <i><pluginName>-config.json</i>, so that users could change the defau= lt plugin configuration to suit their needs.<br> <br> Inspired by your patch, rather than reading/embedding plugin configuration = when serving plugin HTML page (<i>PluginSourcePageServlet</i>), it's even b= etter to have the plugin configuration embedded directly into WebAdmin host= page, along with introducing new <i>pluginApi</i> function to retrieve the plugin configuration object.<br> <br> Based on this, I suggest following modifications to the original concept:<b= r> <br> - modify original <i>pluginDefinitions</i> structure, from <i>pluginName -&= gt; pluginSourcePageUrl</i>, to <i>pluginName -> pluginDefObject</i><br> - <i>pluginDefObject</i> is basically a subset of physical plugin definitio= n (<i>test.json</i>, see below), suitable for use on the client<br> - add following attributes to <i>pluginDefObject</i>: <i>version</i>, <i>ur= l</i>, <i>config</i><br> * note #1: <i>name</i> is not needed, since it's already the ke= y of <i>pluginName -> pluginDefObject</i> mapping<br> * note #2: <i>path</i> is not needed on the client (more on thi= s below)<br> - introduce <i>pluginApi.config(pluginName)</i> function for plugins to ret= rieve their configuration object, and remove <i>pluginConfig</i> parameter from main IIFE (as shown above)<br> <br> [a] Physical plugin definition file (JSON) might be located at oVirt "DataD= ir", e.g. <i>/usr/share/ovirt-engine/ui-plugins/test.json</i>, for example:<br> </span><span style=3D"font-family:"Courier New";color:black"><br> {<br> "name": "test",<br> "version": "1.0",<br> "url": "/webadmin/webadmin/plugin/test/start.html",<br> "path": "/tmp",<br> "config": "test-config.json"<br> }</span><span style=3D"color:black"><br> <br> [b] Plugin configuration file (JSON) might be located at oVirt "ConfigDir",= e.g. <i> /etc/ovirt-engine/ui-plugins/test-config.json</i>, for example:<br> </span><span style=3D"font-family:"Courier New";color:black"><br> {<br> "a":1, "b":2, "c":3<br> }</span><span style=3D"color:black"><br> <br> [c] Finally, plugin static resources (plugin source page, actual plugin cod= e, plugin dependencies, CSS/images, etc.) would be located at <i>/tmp</i> (as shown in [a]), for example:<br> </span><span style=3D"font-family:"Courier New";color:black"><br> /tmp/start.html -> plugin source page, used to load actual plugin code<b= r> /tmp/test.js -> actual plugin code<br> /tmp/deps/jquery-min.js -> simulate 3rd party plugin dependency</span><s= pan style=3D"color:black"><br> <br> For example:<br> "/webadmin/webadmin/plugin/test/start.html" will be mapped to <i>/tmp/start= .html</i><br> "/webadmin/webadmin/plugin/test/deps/jquery-min.js" will be mapped to <i>/t= mp/deps/jquery-min.js</i><br> <br> This approach has some pros and cons:<br> (+) plugin static resources can be served through <i>PluginSourcePageServle= t</i> (pretty much like oVirt documentation resources, served through oVirt= Engine root war's <i>FileServlet</i>)<br> (+) plugin author has complete control over plugin source page<br> (-) plugin author actually needs to write plugin source page<br> <br> Overall, I think this approach is better than the previous one (where <i>Pl= uginSourcePageServlet</i> took care of rendering plugin source page, but sa= crificed some flexibility).<br> <br> By the way, here's what would happen behind the scenes:</span></p> <ol start=3D"1" type=3D"1"> <li class=3D"MsoNormal" style=3D"color:black;mso-margin-top-alt:auto;margin= -bottom:12.0pt;mso-list:l0 level1 lfo1"> user requests WebAdmin host page, <i>WebadminDynamicHostingServlet</i> load= s and caches all plugin definitions [a] + plugin configurations [b] and con= structs/embeds appropriate <i>pluginDefinitions</i> JavaScript object</li><li class=3D"MsoNormal" styl= e=3D"color:black;mso-margin-top-alt:auto;margin-bottom:12.0pt;mso-list:l0 l= evel1 lfo1"> during WebAdmin startup, <i>PluginManager</i> registers the plugin (name/ve= rsion/url/config), and creates/attaches the iframe to fetch plugin source p= age ansynchronously</li><li class=3D"MsoNormal" style=3D"color:black;mso-ma= rgin-top-alt:auto;margin-bottom:12.0pt;mso-list:l0 level1 lfo1"> <i>PluginSourcePageServlet</i> handles plugin source page request, resolves= the correct path [c] and just streams the file content back to client</li>= </ol> <p class=3D"MsoNormal" style=3D"margin-bottom:12.0pt"><span style=3D"color:= black">> 1. The plugin configuration files should probably have an= "enabled" field and an "apiVersion" field that should be examined to deter= mine whether or not to use the plugin.<br> <br> Sounds good, we can implement these later on :)<br> <br> > 2. I suspect the way I've modified PluginSourcePage makes it vul= nerable to directory climbing attacks.<br> <br> Yes, but we can defend against these, restricting access only to plugin's "= path" and its sub-directories.<br> <br> > 3. Is /usr/share/ovirt-engine the right place for the plugin con= fig files?<br> <br> I suppose you mean plugin definition files [a], cannot tell for sure, but w= e can change this anytime :)<br> <br> <br> Chris, please let me know what you think, and again - many thanks for sendi= ng the patch!<br> <br> <br> Regards,<br> Vojtech<br> <br> </span></p> <div class=3D"MsoNormal" style=3D"text-align:center" align=3D"center"><span= style=3D"color:black"> <hr id=3D"zwchr" size=3D"2" width=3D"100%" align=3D"center"> </span></div> <p class=3D"MsoNormal" style=3D"margin-bottom:12.0pt"><span style=3D"color:= black"><br> From: "Chris Frantz" <<a href=3D"mailto:Chris.Frantz@hp.com" target=3D"_= blank">Chris.Frantz@hp.com</a>><br> To: <a href=3D"mailto:vszocs@redhat.com" target=3D"_blank">vszocs@redhat.co= m</a><br> Sent: Wednesday, August 22, 2012 7:56:45 PM<br> Subject: UI Plugins configuration<br> <br> Vojtech,<br> <br> I decided to work on making the plugin patch a bit more configurable, follo= wing some of the ideas expressed by Itamar and others in the meeting yester= day. The attached patch is a simple first-attempt.<br> <br> Plugin configurations are stored in /usr/share/ovirt-engine/ui-plugins/*.js= on.<br> <br> Example:<br> {<br> "name": "test",<br> "version": "1.0",<br> "url": "/webadmin/webadmin/= plugin/test/foo.html",<br> "path": "/tmp",<br> "config": {"a":1, "b":2, "c= ": 3}<br> }<br> <br> The engine reads all of the *.json files in that directory to build the lis= t of known plugins and gives that list to the webadmin.<br> <br> When webadmin loads a plugin, it requests the URL given in the plugin confi= g file. The "plugin" URL is mapped to PluginSourcePage, which will tr= anslate the first part of the path ("test") into whatever path is stored in= pluginConfig ("/tmp") in this case, and then serve the static file (e.g. "/tmp/foo.html").<br> <br> I didn't use the renderPluginSourcePage() method in favor of just serving a= static file, but I have no strong opinion on the matter. However, a = plugin may want to store static resources at "path" and have the engine ser= ve those resources. By just serving files through PluginSourcePage, we don't need any other servlets to provid= e those resources.<br> <br> There is still a bit of work to do:<br> <br> 1. The plugin configuration files should probably have an "enabled" f= ield and an "apiVersion" field that should be examined to determine whether= or not to use the plugin.<br> <br> 2. I suspect the way I've modified PluginSourcePage makes it vulnerab= le to directory climbing attacks.<br> <br> 3. Is /usr/share/ovirt-engine the right place for the plugin config f= iles?<br> <br> Let me know what you think,<br> --Chris</span></p> </div> </div> </div><br></div></body></html> ------=_Part_14115416_27862123.1346078924448--

A couple of comments from the packaging point of view. On 08/27/2012 04:48 PM, Vojtech Szocs wrote:
Hi Chris,
Your assumption about the structure of the pluginDefinitions object is correct. It’s no longer a String->String mapping , but a String to Object mapping.
Yes :) but maybe we could also formalize some terms, for example:
Plugin descriptor is the JSON file that contains important plugin meta-data (including the plugin source page URL), e.g. /usr/share/ovirt-engine/ui-plugins/test.json
Note that the fact that this file goes in the /usr directory means that it is *not* intended to be modified. It means also that the packaging system (well, at least RPM) will *not* preserve it when updating the package that contains it, so any change made by the end user will be lost. So it is important to make clear for plugin developers and end users that these files are *not* to be modified after installation.
Plugin definition is the JavaScript object representing plugin descriptor meta-data suitable for use on client (GWT WebAdmin). Plugin definition is embedded into WebAdmin host page within pluginDefinitions object, and read by PluginManager during WebAdmin startup.
Plugin configuration is the JSON file that contains optional plugin configuration, e.g. /etc/ovirt-engine/ui-plugins/test-config.json
For files in the /etc directory the converse happens: they are intended to be modified by the end user, and usually (if marked properly) they are preserved when a new version of the package is installed.
I think we can combine two things here: 1) allow plugin authors to define standard (fallback) configuration directly inside plugin descriptor 2) allow plugin users to override standard configuration by modifying dedicated plugin configuration file
Finally, plugin source page is the HTML page used to invoke actual plugin code (this page is referenced by plugin descriptor's "url" attribute). Plugin source page can also load external resources required by the plugin, e.g. 3rd party JavaScript libraries, CSS, images, etc.
I liked the original IIFE approach, except that it seemed that having additional static resources (jquery, images, html templates, etc) was going to be more cumbersome. I don’t think having the plugin author write a basic start.html is that big of a burden :).
You're right, for such additional plugin resources, even more configuration/parsing/logic would be required. Even though plugin authors need to write the plugin source page themselves, they have full control over it, which is a good thing in general.
I agree that the plugin configuration was always going to be a resource (probably a local file) that the end user could customize. I’m not sure it I really needs to be separate from the plugin definition file (/usr/share/ovirt-engine/ui-plugins/test.json). I suppose it depends on how complex the configuration is going to be and on some of the implementation details surrounding the plugin definition file.
Yeah, let's make the concept of the plugin configuration file optional for now (standard plugin configuration can be part of plugin descriptor).
In my patch, I simply used Jackson to parse the file into a tree of JsonNodes. Should the plugin definition be a java object of some sort? (please please please don’t make me learn about java beans…). I stuck with the JsonNodes because Jackson makes them easy to work with and they’re really easy to re-serialize back to json to give to the webadmin.
I think using Jackson's JSON representation in Java (JsonNode) is perfectly suitable in this situation. No need to have separate Java bean for that :)
We should probably turn on JsonParser.Feature.ALLOW_COMMENTS. The definition and config files will difficult for end-users (or even developers) to understand without comments.
Agreed.
We need to formalize the structure of the plugin definition and decide which fields are mandatory and which are optional
Sounds good, but I'd skip some attributes for now (enabled, apiVersion, author, license) for the sake of simplicity.
As you wrote, when loading plugin descriptor, we should enforce mandatory attributes (name, version, url) .
As for plugin configuration, there could be two different attributes: - "config" for standard (fallback) plugin configuration (JSON object) - "configFile" for external plugin configuration file (path to file, relative to /etc/ovirt-engine/ui-plugins/ ) , that overrides the standard configuration
Note that when loading plugin descriptor, the loader should also "merge" the configuration together (custom config on top of standard config).
I can work on the plugin Definition loader some more and make it enforce mandatory/optional fields. I’ll also investigate the directory climbing issue I mentioned in my previous mail.
Sounds good! I was planning to incorporate your original patch in next PoC revision, but of course, you can work on the loader some more and send another patch :)
For the directory climbing issue, see <OVIRT_ROOT>/backend/manager/modules/root/src/main/java/org/ovirt/engine/core/FileServlet.java (there's a method called isSane for dealing with such issue).
Also, I’m curious how things are going to work when the “url” points to a foreign resource as the plugin start page. I don’t think the plugin’s iframe is going to be able to access parent.pluginApi. Perhaps there is some aspect of CORS that I don’t understand?
When the plugin iframe references a resource on different origin (protocol, domain, port) than WebAdmin main page origin, JavaScript code running inside that iframe will not be able to access parent (top-level) pluginApi object. You're right, the statement "parent.pluginApi" will not work, because of Same-Origin Policy enforced by the browser.
CORS is just one alternative, see http://stackoverflow.com/questions/3076414/ways-to-circumvent-the-same-origi... for more. However, CORS needs to be supported by the browser (a special HTTP response header is used to tell that the iframe is allowed to access resources from another - WebAdmin main page - origin). We need to investigate this a bit more I guess.
Regards, Vojtech
----- Original Message -----
From: "Chris Frantz" <Chris.Frantz@hp.com> To: "Vojtech Szocs" <vszocs@redhat.com> Cc: "engine-devel" <engine-devel@ovirt.org> Sent: Thursday, August 23, 2012 5:12:02 PM Subject: RE: UI Plugins configuration
Vojtech,
Your assumption about the structure of the pluginDefinitions object is correct. It’s no longer a String->String mapping , but a String to Object mapping.
I liked the original IIFE approach, except that it seemed that having additional static resources (jquery, images, html templates, etc) was going to be more cumbersome. I don’t think having the plugin author write a basic start.html is that big of a burden :).
I agree that the plugin configuration was always going to be a resource (probably a local file) that the end user could customize. I’m not sure it I really needs to be separate from the plugin definition file (/usr/share/ovirt-engine/ui-plugins/test.json). I suppose it depends on how complex the configuration is going to be and on some of the implementation details surrounding the plugin definition file.
In my patch, I simply used Jackson to parse the file into a tree of JsonNodes. Should the plugin definition be a java object of some sort? (please please please don’t make me learn about java beans…). I stuck with the JsonNodes because Jackson makes them easy to work with and they’re really easy to re-serialize back to json to give to the webadmin.
We should probably turn on JsonParser.Feature.ALLOW_COMMENTS. The definition and config files will difficult for end-users (or even developers) to understand without comments.
We need to formalize the structure of the plugin definition and decide which fields are mandatory and which are optional:
{ # Mandatory fields: name, enabled, version, url, apiversion, author, license # Name of the plugin "name": "test",
# Whether or not plugin is enabed "enabled": true,
# version of the plugin "version": "1.0",
# How to load the plugin "url": "/webadmin/webadmin/plugin/test/start.html",
# Which version of engine plugin is meant to work with "apiversion": "3.1.0",
# Who wrote the plugin and how is it licensed? "author": "SuperBig Corporation", "license": "Proprietary",
# Optional fields path, config # Where to locate plugin (if loaded by webadmin/plugin) "path": "/tmp",
# Plugin configuration information (if any) "config": "test-config.json", }
I can work on the plugin Definition loader some more and make it enforce mandatory/optional fields. I’ll also investigate the directory climbing issue I mentioned in my previous mail.
Also, I’m curious how things are going to work when the “url” points to a foreign resource as the plugin start page. I don’t think the plugin’s iframe is going to be able to access parent.pluginApi. Perhaps there is some aspect of CORS that I don’t understand?
Thanks, --Chris
From: Vojtech Szocs [mailto:vszocs@redhat.com] Sent: Thursday, August 23, 2012 7:14 AM To: Frantz, Chris Cc: engine-devel Subject: Re: UI Plugins configuration
Hi Chris,
thanks for taking the time to make this patch, these are some excellent ideas! (CC'ing engine-devel so that we can discuss this with other guys as well)
First of all, I really like the way you designed plugin source page URLs (going through PluginSourcePageServlet ), e.g. "/webadmin/webadmin/plugin/<pluginName>/<pluginSourcePage>.html", plus the concept of "path" JSON attribute.
WebadminDynamicHostingServlet loads and caches all plugin definitions ( *.json files), and directly embeds them into WebAdmin host page as pluginDefinitions JavaScript object. I'm assuming that pluginDefinitions object will now look like this:
var pluginDefinitions = { "test": { "name": "test", "version": "1.0", "url": "/webadmin/webadmin/plugin/test/foo.html", "path": "/tmp", "config": {"a":1, "b":2, "c":3} } }
Originally, the pluginDefinitions object looked like this:
var pluginDefinitions = { "test": "/webadmin/webadmin/plugin/test/foo.html" // Simple pluginName -> pluginSourcePageUrl mappings }
This is because PluginManager (WebAdmin) only needs pluginName ("name") and pluginSourcePageUrl ("url") during startup, when creating plugin iframe. But this can be changed :)
Plugin "version" makes sense, plus the plugin configuration object ("config") can be useful directly on the client. Let me explain:
Originally, plugin configuration was supposed to be passed to actual plugin code (through immediately-invoked-function-expression, or IIFE), just like this:
(function (pluginApi, pluginConfig) { // JavaScript IIFE // ... actual plugin code ... })( parent.pluginApi, /* reference to global pluginApi object */ {"a":1, "b":2, "c":3} /* embedded plugin configuration as JavaScript object */ );
The whole purpose of PluginSourcePageServlet was to "wrap" actual plugin code into HTML, so that users don't need to write HTML pages for their plugins manually. PluginSourcePageServlet would handle any plugin dependencies (placed into HTML head), with actual plugin code being wrapped into IIFE, as shown above. Plugin configuration was meant to be stored in a separate file, e.g. <pluginName>-config.json , so that users could change the default plugin configuration to suit their needs.
Inspired by your patch, rather than reading/embedding plugin configuration when serving plugin HTML page ( PluginSourcePageServlet ), it's even better to have the plugin configuration embedded directly into WebAdmin host page, along with introducing new pluginApi function to retrieve the plugin configuration object.
Based on this, I suggest following modifications to the original concept:
- modify original pluginDefinitions structure, from pluginName -> pluginSourcePageUrl , to pluginName -> pluginDefObject - pluginDefObject is basically a subset of physical plugin definition ( test.json , see below), suitable for use on the client - add following attributes to pluginDefObject : version , url , config * note #1: name is not needed, since it's already the key of pluginName -> pluginDefObject mapping * note #2: path is not needed on the client (more on this below) - introduce pluginApi.config(pluginName) function for plugins to retrieve their configuration object, and remove pluginConfig parameter from main IIFE (as shown above)
[a] Physical plugin definition file (JSON) might be located at oVirt "DataDir", e.g. /usr/share/ovirt-engine/ui-plugins/test.json , for example:
{ "name": "test", "version": "1.0", "url": "/webadmin/webadmin/plugin/test/start.html", "path": "/tmp", "config": "test-config.json" }
[b] Plugin configuration file (JSON) might be located at oVirt "ConfigDir", e.g. /etc/ovirt-engine/ui-plugins/test-config.json , for example:
{ "a":1, "b":2, "c":3 }
[c] Finally, plugin static resources (plugin source page, actual plugin code, plugin dependencies, CSS/images, etc.) would be located at /tmp (as shown in [a]), for example:
/tmp/start.html -> plugin source page, used to load actual plugin code /tmp/test.js -> actual plugin code /tmp/deps/jquery-min.js -> simulate 3rd party plugin dependency
For example: "/webadmin/webadmin/plugin/test/start.html" will be mapped to /tmp/start.html "/webadmin/webadmin/plugin/test/deps/jquery-min.js" will be mapped to /tmp/deps/jquery-min.js
This approach has some pros and cons: (+) plugin static resources can be served through PluginSourcePageServlet (pretty much like oVirt documentation resources, served through oVirt Engine root war's FileServlet ) (+) plugin author has complete control over plugin source page (-) plugin author actually needs to write plugin source page
Overall, I think this approach is better than the previous one (where PluginSourcePageServlet took care of rendering plugin source page, but sacrificed some flexibility).
By the way, here's what would happen behind the scenes:
1. user requests WebAdmin host page, WebadminDynamicHostingServlet loads and caches all plugin definitions [a] + plugin configurations [b] and constructs/embeds appropriate pluginDefinitions JavaScript object 2. during WebAdmin startup, PluginManager registers the plugin (name/version/url/config), and creates/attaches the iframe to fetch plugin source page ansynchronously 3. PluginSourcePageServlet handles plugin source page request, resolves the correct path [c] and just streams the file content back to client
1. The plugin configuration files should probably have an "enabled" field and an "apiVersion" field that should be examined to determine whether or not to use the plugin.
Sounds good, we can implement these later on :)
2. I suspect the way I've modified PluginSourcePage makes it vulnerable to directory climbing attacks.
Yes, but we can defend against these, restricting access only to plugin's "path" and its sub-directories.
3. Is /usr/share/ovirt-engine the right place for the plugin config files?
I suppose you mean plugin definition files [a], cannot tell for sure, but we can change this anytime :)
Chris, please let me know what you think, and again - many thanks for sending the patch!
Regards, Vojtech
----- Original Message -----
From: "Chris Frantz" < Chris.Frantz@hp.com > To: vszocs@redhat.com Sent: Wednesday, August 22, 2012 7:56:45 PM Subject: UI Plugins configuration
Vojtech,
I decided to work on making the plugin patch a bit more configurable, following some of the ideas expressed by Itamar and others in the meeting yesterday. The attached patch is a simple first-attempt.
Plugin configurations are stored in /usr/share/ovirt-engine/ui-plugins/*.json.
Example: { "name": "test", "version": "1.0", "url": "/webadmin/webadmin/plugin/test/foo.html", "path": "/tmp", "config": {"a":1, "b":2, "c": 3} }
The engine reads all of the *.json files in that directory to build the list of known plugins and gives that list to the webadmin.
When webadmin loads a plugin, it requests the URL given in the plugin config file. The "plugin" URL is mapped to PluginSourcePage, which will translate the first part of the path ("test") into whatever path is stored in pluginConfig ("/tmp") in this case, and then serve the static file (e.g. "/tmp/foo.html").
I didn't use the renderPluginSourcePage() method in favor of just serving a static file, but I have no strong opinion on the matter. However, a plugin may want to store static resources at "path" and have the engine serve those resources. By just serving files through PluginSourcePage, we don't need any other servlets to provide those resources.
There is still a bit of work to do:
1. The plugin configuration files should probably have an "enabled" field and an "apiVersion" field that should be examined to determine whether or not to use the plugin.
2. I suspect the way I've modified PluginSourcePage makes it vulnerable to directory climbing attacks.
3. Is /usr/share/ovirt-engine the right place for the plugin config files?
Let me know what you think, --Chris
_______________________________________________ Engine-devel mailing list Engine-devel@ovirt.org http://lists.ovirt.org/mailman/listinfo/engine-devel
-- Dirección Comercial: C/Jose Bardasano Baos, 9, Edif. Gorbea 3, planta 3ºD, 28016 Madrid, Spain Inscrita en el Reg. Mercantil de Madrid – C.I.F. B82657941 - Red Hat S.L.

Hi Juan, thanks for your comments! Indeed, plugin descriptors have the attributes as you described for files under /usr/share/ovirt-engine (oVirt DataDir): - they are NOT intended to be modified by end users - they are NOT intended to be preserved after package upgrade - packaging system takes care of creating/updating/removing them (Each plugin descriptor provides mandatory meta-data for a specific version of the given plugin.) Indeed as well, plugin configuration files have also the attributes as you described for files under /etc/ovirt-engine (oVirt ConfigDir): - they are intended to be modified by end users - they are intended to be preserved after package upgrade - their presence is optional, therefore they are NOT part of the relevant package (Plugin configuration files are used to override default plugin configuration as necessary.) Thanks for bringing up these points, we should indeed mention these in oVirt plugin wiki page. Regards, Vojtech ----- Original Message ----- From: "Juan Hernandez" <jhernand@redhat.com> To: "Vojtech Szocs" <vszocs@redhat.com> Cc: "Chris Frantz" <Chris.Frantz@hp.com>, "engine-devel" <engine-devel@ovirt.org> Sent: Tuesday, August 28, 2012 8:07:40 PM Subject: Re: [Engine-devel] UI Plugins configuration A couple of comments from the packaging point of view. On 08/27/2012 04:48 PM, Vojtech Szocs wrote:
Hi Chris,
Your assumption about the structure of the pluginDefinitions object is correct. It’s no longer a String->String mapping , but a String to Object mapping.
Yes :) but maybe we could also formalize some terms, for example:
Plugin descriptor is the JSON file that contains important plugin meta-data (including the plugin source page URL), e.g. /usr/share/ovirt-engine/ui-plugins/test.json
Note that the fact that this file goes in the /usr directory means that it is *not* intended to be modified. It means also that the packaging system (well, at least RPM) will *not* preserve it when updating the package that contains it, so any change made by the end user will be lost. So it is important to make clear for plugin developers and end users that these files are *not* to be modified after installation.
Plugin definition is the JavaScript object representing plugin descriptor meta-data suitable for use on client (GWT WebAdmin). Plugin definition is embedded into WebAdmin host page within pluginDefinitions object, and read by PluginManager during WebAdmin startup.
Plugin configuration is the JSON file that contains optional plugin configuration, e.g. /etc/ovirt-engine/ui-plugins/test-config.json
For files in the /etc directory the converse happens: they are intended to be modified by the end user, and usually (if marked properly) they are preserved when a new version of the package is installed.
I think we can combine two things here: 1) allow plugin authors to define standard (fallback) configuration directly inside plugin descriptor 2) allow plugin users to override standard configuration by modifying dedicated plugin configuration file
Finally, plugin source page is the HTML page used to invoke actual plugin code (this page is referenced by plugin descriptor's "url" attribute). Plugin source page can also load external resources required by the plugin, e.g. 3rd party JavaScript libraries, CSS, images, etc.
I liked the original IIFE approach, except that it seemed that having additional static resources (jquery, images, html templates, etc) was going to be more cumbersome. I don’t think having the plugin author write a basic start.html is that big of a burden :).
You're right, for such additional plugin resources, even more configuration/parsing/logic would be required. Even though plugin authors need to write the plugin source page themselves, they have full control over it, which is a good thing in general.
I agree that the plugin configuration was always going to be a resource (probably a local file) that the end user could customize. I’m not sure it I really needs to be separate from the plugin definition file (/usr/share/ovirt-engine/ui-plugins/test.json). I suppose it depends on how complex the configuration is going to be and on some of the implementation details surrounding the plugin definition file.
Yeah, let's make the concept of the plugin configuration file optional for now (standard plugin configuration can be part of plugin descriptor).
In my patch, I simply used Jackson to parse the file into a tree of JsonNodes. Should the plugin definition be a java object of some sort? (please please please don’t make me learn about java beans…). I stuck with the JsonNodes because Jackson makes them easy to work with and they’re really easy to re-serialize back to json to give to the webadmin.
I think using Jackson's JSON representation in Java (JsonNode) is perfectly suitable in this situation. No need to have separate Java bean for that :)
We should probably turn on JsonParser.Feature.ALLOW_COMMENTS. The definition and config files will difficult for end-users (or even developers) to understand without comments.
Agreed.
We need to formalize the structure of the plugin definition and decide which fields are mandatory and which are optional
Sounds good, but I'd skip some attributes for now (enabled, apiVersion, author, license) for the sake of simplicity.
As you wrote, when loading plugin descriptor, we should enforce mandatory attributes (name, version, url) .
As for plugin configuration, there could be two different attributes: - "config" for standard (fallback) plugin configuration (JSON object) - "configFile" for external plugin configuration file (path to file, relative to /etc/ovirt-engine/ui-plugins/ ) , that overrides the standard configuration
Note that when loading plugin descriptor, the loader should also "merge" the configuration together (custom config on top of standard config).
I can work on the plugin Definition loader some more and make it enforce mandatory/optional fields. I’ll also investigate the directory climbing issue I mentioned in my previous mail.
Sounds good! I was planning to incorporate your original patch in next PoC revision, but of course, you can work on the loader some more and send another patch :)
For the directory climbing issue, see <OVIRT_ROOT>/backend/manager/modules/root/src/main/java/org/ovirt/engine/core/FileServlet.java (there's a method called isSane for dealing with such issue).
Also, I’m curious how things are going to work when the “url” points to a foreign resource as the plugin start page. I don’t think the plugin’s iframe is going to be able to access parent.pluginApi. Perhaps there is some aspect of CORS that I don’t understand?
When the plugin iframe references a resource on different origin (protocol, domain, port) than WebAdmin main page origin, JavaScript code running inside that iframe will not be able to access parent (top-level) pluginApi object. You're right, the statement "parent.pluginApi" will not work, because of Same-Origin Policy enforced by the browser.
CORS is just one alternative, see http://stackoverflow.com/questions/3076414/ways-to-circumvent-the-same-origi... for more. However, CORS needs to be supported by the browser (a special HTTP response header is used to tell that the iframe is allowed to access resources from another - WebAdmin main page - origin). We need to investigate this a bit more I guess.
Regards, Vojtech
----- Original Message -----
From: "Chris Frantz" <Chris.Frantz@hp.com> To: "Vojtech Szocs" <vszocs@redhat.com> Cc: "engine-devel" <engine-devel@ovirt.org> Sent: Thursday, August 23, 2012 5:12:02 PM Subject: RE: UI Plugins configuration
Vojtech,
Your assumption about the structure of the pluginDefinitions object is correct. It’s no longer a String->String mapping , but a String to Object mapping.
I liked the original IIFE approach, except that it seemed that having additional static resources (jquery, images, html templates, etc) was going to be more cumbersome. I don’t think having the plugin author write a basic start.html is that big of a burden :).
I agree that the plugin configuration was always going to be a resource (probably a local file) that the end user could customize. I’m not sure it I really needs to be separate from the plugin definition file (/usr/share/ovirt-engine/ui-plugins/test.json). I suppose it depends on how complex the configuration is going to be and on some of the implementation details surrounding the plugin definition file.
In my patch, I simply used Jackson to parse the file into a tree of JsonNodes. Should the plugin definition be a java object of some sort? (please please please don’t make me learn about java beans…). I stuck with the JsonNodes because Jackson makes them easy to work with and they’re really easy to re-serialize back to json to give to the webadmin.
We should probably turn on JsonParser.Feature.ALLOW_COMMENTS. The definition and config files will difficult for end-users (or even developers) to understand without comments.
We need to formalize the structure of the plugin definition and decide which fields are mandatory and which are optional:
{ # Mandatory fields: name, enabled, version, url, apiversion, author, license # Name of the plugin "name": "test",
# Whether or not plugin is enabed "enabled": true,
# version of the plugin "version": "1.0",
# How to load the plugin "url": "/webadmin/webadmin/plugin/test/start.html",
# Which version of engine plugin is meant to work with "apiversion": "3.1.0",
# Who wrote the plugin and how is it licensed? "author": "SuperBig Corporation", "license": "Proprietary",
# Optional fields path, config # Where to locate plugin (if loaded by webadmin/plugin) "path": "/tmp",
# Plugin configuration information (if any) "config": "test-config.json", }
I can work on the plugin Definition loader some more and make it enforce mandatory/optional fields. I’ll also investigate the directory climbing issue I mentioned in my previous mail.
Also, I’m curious how things are going to work when the “url” points to a foreign resource as the plugin start page. I don’t think the plugin’s iframe is going to be able to access parent.pluginApi. Perhaps there is some aspect of CORS that I don’t understand?
Thanks, --Chris
From: Vojtech Szocs [mailto:vszocs@redhat.com] Sent: Thursday, August 23, 2012 7:14 AM To: Frantz, Chris Cc: engine-devel Subject: Re: UI Plugins configuration
Hi Chris,
thanks for taking the time to make this patch, these are some excellent ideas! (CC'ing engine-devel so that we can discuss this with other guys as well)
First of all, I really like the way you designed plugin source page URLs (going through PluginSourcePageServlet ), e.g. "/webadmin/webadmin/plugin/<pluginName>/<pluginSourcePage>.html", plus the concept of "path" JSON attribute.
WebadminDynamicHostingServlet loads and caches all plugin definitions ( *.json files), and directly embeds them into WebAdmin host page as pluginDefinitions JavaScript object. I'm assuming that pluginDefinitions object will now look like this:
var pluginDefinitions = { "test": { "name": "test", "version": "1.0", "url": "/webadmin/webadmin/plugin/test/foo.html", "path": "/tmp", "config": {"a":1, "b":2, "c":3} } }
Originally, the pluginDefinitions object looked like this:
var pluginDefinitions = { "test": "/webadmin/webadmin/plugin/test/foo.html" // Simple pluginName -> pluginSourcePageUrl mappings }
This is because PluginManager (WebAdmin) only needs pluginName ("name") and pluginSourcePageUrl ("url") during startup, when creating plugin iframe. But this can be changed :)
Plugin "version" makes sense, plus the plugin configuration object ("config") can be useful directly on the client. Let me explain:
Originally, plugin configuration was supposed to be passed to actual plugin code (through immediately-invoked-function-expression, or IIFE), just like this:
(function (pluginApi, pluginConfig) { // JavaScript IIFE // ... actual plugin code ... })( parent.pluginApi, /* reference to global pluginApi object */ {"a":1, "b":2, "c":3} /* embedded plugin configuration as JavaScript object */ );
The whole purpose of PluginSourcePageServlet was to "wrap" actual plugin code into HTML, so that users don't need to write HTML pages for their plugins manually. PluginSourcePageServlet would handle any plugin dependencies (placed into HTML head), with actual plugin code being wrapped into IIFE, as shown above. Plugin configuration was meant to be stored in a separate file, e.g. <pluginName>-config.json , so that users could change the default plugin configuration to suit their needs.
Inspired by your patch, rather than reading/embedding plugin configuration when serving plugin HTML page ( PluginSourcePageServlet ), it's even better to have the plugin configuration embedded directly into WebAdmin host page, along with introducing new pluginApi function to retrieve the plugin configuration object.
Based on this, I suggest following modifications to the original concept:
- modify original pluginDefinitions structure, from pluginName -> pluginSourcePageUrl , to pluginName -> pluginDefObject - pluginDefObject is basically a subset of physical plugin definition ( test.json , see below), suitable for use on the client - add following attributes to pluginDefObject : version , url , config * note #1: name is not needed, since it's already the key of pluginName -> pluginDefObject mapping * note #2: path is not needed on the client (more on this below) - introduce pluginApi.config(pluginName) function for plugins to retrieve their configuration object, and remove pluginConfig parameter from main IIFE (as shown above)
[a] Physical plugin definition file (JSON) might be located at oVirt "DataDir", e.g. /usr/share/ovirt-engine/ui-plugins/test.json , for example:
{ "name": "test", "version": "1.0", "url": "/webadmin/webadmin/plugin/test/start.html", "path": "/tmp", "config": "test-config.json" }
[b] Plugin configuration file (JSON) might be located at oVirt "ConfigDir", e.g. /etc/ovirt-engine/ui-plugins/test-config.json , for example:
{ "a":1, "b":2, "c":3 }
[c] Finally, plugin static resources (plugin source page, actual plugin code, plugin dependencies, CSS/images, etc.) would be located at /tmp (as shown in [a]), for example:
/tmp/start.html -> plugin source page, used to load actual plugin code /tmp/test.js -> actual plugin code /tmp/deps/jquery-min.js -> simulate 3rd party plugin dependency
For example: "/webadmin/webadmin/plugin/test/start.html" will be mapped to /tmp/start.html "/webadmin/webadmin/plugin/test/deps/jquery-min.js" will be mapped to /tmp/deps/jquery-min.js
This approach has some pros and cons: (+) plugin static resources can be served through PluginSourcePageServlet (pretty much like oVirt documentation resources, served through oVirt Engine root war's FileServlet ) (+) plugin author has complete control over plugin source page (-) plugin author actually needs to write plugin source page
Overall, I think this approach is better than the previous one (where PluginSourcePageServlet took care of rendering plugin source page, but sacrificed some flexibility).
By the way, here's what would happen behind the scenes:
1. user requests WebAdmin host page, WebadminDynamicHostingServlet loads and caches all plugin definitions [a] + plugin configurations [b] and constructs/embeds appropriate pluginDefinitions JavaScript object 2. during WebAdmin startup, PluginManager registers the plugin (name/version/url/config), and creates/attaches the iframe to fetch plugin source page ansynchronously 3. PluginSourcePageServlet handles plugin source page request, resolves the correct path [c] and just streams the file content back to client
1. The plugin configuration files should probably have an "enabled" field and an "apiVersion" field that should be examined to determine whether or not to use the plugin.
Sounds good, we can implement these later on :)
2. I suspect the way I've modified PluginSourcePage makes it vulnerable to directory climbing attacks.
Yes, but we can defend against these, restricting access only to plugin's "path" and its sub-directories.
3. Is /usr/share/ovirt-engine the right place for the plugin config files?
I suppose you mean plugin definition files [a], cannot tell for sure, but we can change this anytime :)
Chris, please let me know what you think, and again - many thanks for sending the patch!
Regards, Vojtech
----- Original Message -----
From: "Chris Frantz" < Chris.Frantz@hp.com > To: vszocs@redhat.com Sent: Wednesday, August 22, 2012 7:56:45 PM Subject: UI Plugins configuration
Vojtech,
I decided to work on making the plugin patch a bit more configurable, following some of the ideas expressed by Itamar and others in the meeting yesterday. The attached patch is a simple first-attempt.
Plugin configurations are stored in /usr/share/ovirt-engine/ui-plugins/*.json.
Example: { "name": "test", "version": "1.0", "url": "/webadmin/webadmin/plugin/test/foo.html", "path": "/tmp", "config": {"a":1, "b":2, "c": 3} }
The engine reads all of the *.json files in that directory to build the list of known plugins and gives that list to the webadmin.
When webadmin loads a plugin, it requests the URL given in the plugin config file. The "plugin" URL is mapped to PluginSourcePage, which will translate the first part of the path ("test") into whatever path is stored in pluginConfig ("/tmp") in this case, and then serve the static file (e.g. "/tmp/foo.html").
I didn't use the renderPluginSourcePage() method in favor of just serving a static file, but I have no strong opinion on the matter. However, a plugin may want to store static resources at "path" and have the engine serve those resources. By just serving files through PluginSourcePage, we don't need any other servlets to provide those resources.
There is still a bit of work to do:
1. The plugin configuration files should probably have an "enabled" field and an "apiVersion" field that should be examined to determine whether or not to use the plugin.
2. I suspect the way I've modified PluginSourcePage makes it vulnerable to directory climbing attacks.
3. Is /usr/share/ovirt-engine the right place for the plugin config files?
Let me know what you think, --Chris
_______________________________________________ Engine-devel mailing list Engine-devel@ovirt.org http://lists.ovirt.org/mailman/listinfo/engine-devel
-- Dirección Comercial: C/Jose Bardasano Baos, 9, Edif. Gorbea 3, planta 3ºD, 28016 Madrid, Spain Inscrita en el Reg. Mercantil de Madrid – C.I.F. B82657941 - Red Hat S.L.

--_005_A24D665DC3ECC245A2EA0D9A958F80B62C49123BG9W0745americas_ Content-Type: multipart/alternative; boundary="_000_A24D665DC3ECC245A2EA0D9A958F80B62C49123BG9W0745americas_" --_000_A24D665DC3ECC245A2EA0D9A958F80B62C49123BG9W0745americas_ Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Vm9qdGVjaCwNCg0KSSBhZ3JlZSB3aXRoIHlvdXIgZm9ybWFsaXplZCBuYW1lczoNCg0KUGx1Z2lu IERlc2NyaXB0b3IgaXMgdGhlIEpTT04gZmlsZSBjb250YWluaW5nIHBsdWdpbiBtZXRhLWRhdGEu IFRoZSBwbHVnaW4gZGVzY3JpcHRvciBtYXkgYWxzbyBjb250YWluIHRoZSBkZWZhdWx0IGNvbmZp Z3VyYXRpb24gZGF0YS4gICBJdCBpcyBsb2NhdGVkIGluICREQVRBRElSL3VpLXBsdWdpbnMuDQoN ClBsdWdpbiBDb25maWd1cmF0aW9uIGlzIHRoZSBKU09OIGZpbGUgY29udGFpbmluZyBvcHRpb25h bCBwbHVnaW4gY29uZmlndXJhdGlvbiBpbmZvLiAgSXQgaXMgbG9jYXRlZCBpbiAkQ09ORklHRElS L3VpLXBsdWdpbnMgKHVubGVzcyB0aGUgUGx1Z2luIERlc2NyaXB0b3IgY29udGFpbnMgYW4gYWJz b2x1dGUgcGF0aCkuDQoNClBsdWdpbiBEZWZpbml0aW9uIGlzIHRoZSBKYXZhU2NyaXB0IG9iamVj dCB1c2VkIGJ5IFdlYkFkbWluLiAgSW4gdGhlIGN1cnJlbnQgaW1wbGVtZW50YXRpb24sIHRoZSBQ bHVnaW4gRGVmaW5pdGlvbiBjb250YWlucyBib3RoIHRoZSBQbHVnaW4gRGVzY3JpcHRvciBhbmQg dGhlIFBsdWdpbiBDb25maWd1cmFpb24uDQoNClBsdWdpbiBTb3VyY2UgUGFnZSBpcyB0aGUgSFRN TCBwYWdlIHVzZWQgdG8gaW52b2tlIHRoZSBwbHVnaW4gY29kZSBhbmQgc2hhbGwgYmUgcmVmZXJl bmNlZCBieSB0aGUgcGx1Z2luIGRlc2NyaXB0b3LigJlzIOKAnHVybOKAnSBhdHRyaWJ1dGUuDQoN CknigJl2ZSBpbXBsZW1lbnRlZCB0aGUgY29uZmlnIG1lcmdpbmcgeW914oCZdmUgc3VnZ2VzdGVk OiAgdGhlIHN0cnVjdHVyZSBpbiBjb25maWdGaWxlIGdldHMgbWVyZ2VkIHdpdGggdGhlIHN0cnVj dHVyZSBvZiDigJxjb25maWfigJ0sIHdpdGggdGhlIGRhdGEgaW4gY29uZmlnRmlsZSB3aW5uaW5n IGluIHRoZSBjYXNlIG9mIGR1cGxpY2F0ZSBrZXkgbmFtZXMuDQoNCkJUVywgdGhlIHBhdGNoIGlz IGFnYWluc3Qgb3ZpcnQtZW5naW5lICsgMDAwMS1XSVAtVUktUGx1Z2lucy1Qb0MtcmV2aXNpb24t Mi4NCg0KTGV0IG1lIGtub3cgd2hhdCB5b3UgdGhpbmssDQotLUNocmlzDQoNCg0KDQoNCkZyb206 IFZvanRlY2ggU3pvY3MgW21haWx0bzp2c3pvY3NAcmVkaGF0LmNvbV0NClNlbnQ6IE1vbmRheSwg QXVndXN0IDI3LCAyMDEyIDk6NDkgQU0NClRvOiBGcmFudHosIENocmlzDQpDYzogZW5naW5lLWRl dmVsDQpTdWJqZWN0OiBSZTogVUkgUGx1Z2lucyBjb25maWd1cmF0aW9uDQoNCkhpIENocmlzLA0K DQo+IFlvdXIgYXNzdW1wdGlvbiBhYm91dCB0aGUgc3RydWN0dXJlIG9mIHRoZSBwbHVnaW5EZWZp bml0aW9ucyBvYmplY3QgaXMgY29ycmVjdC4gIEl04oCZcyBubyBsb25nZXIgYSBTdHJpbmctPlN0 cmluZyBtYXBwaW5nICwgYnV0IGEgU3RyaW5nIHRvIE9iamVjdCBtYXBwaW5nLg0KDQpZZXMgOikg YnV0IG1heWJlIHdlIGNvdWxkIGFsc28gZm9ybWFsaXplIHNvbWUgdGVybXMsIGZvciBleGFtcGxl Og0KDQpQbHVnaW4gZGVzY3JpcHRvciBpcyB0aGUgSlNPTiBmaWxlIHRoYXQgY29udGFpbnMgaW1w b3J0YW50IHBsdWdpbiBtZXRhLWRhdGEgKGluY2x1ZGluZyB0aGUgcGx1Z2luIHNvdXJjZSBwYWdl IFVSTCksIGUuZy4gL3Vzci9zaGFyZS9vdmlydC1lbmdpbmUvdWktcGx1Z2lucy90ZXN0Lmpzb24N Cg0KUGx1Z2luIGRlZmluaXRpb24gaXMgdGhlIEphdmFTY3JpcHQgb2JqZWN0IHJlcHJlc2VudGlu ZyBwbHVnaW4gZGVzY3JpcHRvciBtZXRhLWRhdGEgc3VpdGFibGUgZm9yIHVzZSBvbiBjbGllbnQg KEdXVCBXZWJBZG1pbikuIFBsdWdpbiBkZWZpbml0aW9uIGlzIGVtYmVkZGVkIGludG8gV2ViQWRt aW4gaG9zdCBwYWdlIHdpdGhpbiBwbHVnaW5EZWZpbml0aW9ucyBvYmplY3QsIGFuZCByZWFkIGJ5 IFBsdWdpbk1hbmFnZXIgZHVyaW5nIFdlYkFkbWluIHN0YXJ0dXAuDQoNClBsdWdpbiBjb25maWd1 cmF0aW9uIGlzIHRoZSBKU09OIGZpbGUgdGhhdCBjb250YWlucyBvcHRpb25hbCBwbHVnaW4gY29u ZmlndXJhdGlvbiwgZS5nLiAvZXRjL292aXJ0LWVuZ2luZS91aS1wbHVnaW5zL3Rlc3QtY29uZmln Lmpzb24NCg0KSSB0aGluayB3ZSBjYW4gY29tYmluZSB0d28gdGhpbmdzIGhlcmU6DQoxKSBhbGxv dyBwbHVnaW4gYXV0aG9ycyB0byBkZWZpbmUgc3RhbmRhcmQgKGZhbGxiYWNrKSBjb25maWd1cmF0 aW9uIGRpcmVjdGx5IGluc2lkZSBwbHVnaW4gZGVzY3JpcHRvcg0KMikgYWxsb3cgcGx1Z2luIHVz ZXJzIHRvIG92ZXJyaWRlIHN0YW5kYXJkIGNvbmZpZ3VyYXRpb24gYnkgbW9kaWZ5aW5nIGRlZGlj YXRlZCBwbHVnaW4gY29uZmlndXJhdGlvbiBmaWxlDQoNCkZpbmFsbHksIHBsdWdpbiBzb3VyY2Ug cGFnZSBpcyB0aGUgSFRNTCBwYWdlIHVzZWQgdG8gaW52b2tlIGFjdHVhbCBwbHVnaW4gY29kZSAo dGhpcyBwYWdlIGlzIHJlZmVyZW5jZWQgYnkgcGx1Z2luIGRlc2NyaXB0b3IncyAidXJsIiBhdHRy aWJ1dGUpLiBQbHVnaW4gc291cmNlIHBhZ2UgY2FuIGFsc28gbG9hZCBleHRlcm5hbCByZXNvdXJj ZXMgcmVxdWlyZWQgYnkgdGhlIHBsdWdpbiwgZS5nLiAzcmQgcGFydHkgSmF2YVNjcmlwdCBsaWJy YXJpZXMsIENTUywgaW1hZ2VzLCBldGMuDQoNCj4gSSBsaWtlZCB0aGUgb3JpZ2luYWwgSUlGRSBh cHByb2FjaCwgZXhjZXB0IHRoYXQgaXQgc2VlbWVkIHRoYXQgaGF2aW5nIGFkZGl0aW9uYWwgc3Rh dGljIHJlc291cmNlcyAoanF1ZXJ5LCBpbWFnZXMsIGh0bWwgdGVtcGxhdGVzLCBldGMpIHdhcyBn b2luZyB0byBiZSBtb3JlIGN1bWJlcnNvbWUuICBJIGRvbuKAmXQgdGhpbmsgaGF2aW5nIHRoZSBw bHVnaW4gYXV0aG9yIHdyaXRlIGEgYmFzaWMgc3RhcnQuaHRtbCBpcyB0aGF0IGJpZyBvZiBhIGJ1 cmRlbiA6KS4NCg0KWW91J3JlIHJpZ2h0LCBmb3Igc3VjaCBhZGRpdGlvbmFsIHBsdWdpbiByZXNv dXJjZXMsIGV2ZW4gbW9yZSBjb25maWd1cmF0aW9uL3BhcnNpbmcvbG9naWMgd291bGQgYmUgcmVx dWlyZWQuIEV2ZW4gdGhvdWdoIHBsdWdpbiBhdXRob3JzIG5lZWQgdG8gd3JpdGUgdGhlIHBsdWdp biBzb3VyY2UgcGFnZSB0aGVtc2VsdmVzLCB0aGV5IGhhdmUgZnVsbCBjb250cm9sIG92ZXIgaXQs IHdoaWNoIGlzIGEgZ29vZCB0aGluZyBpbiBnZW5lcmFsLg0KDQo+IEkgYWdyZWUgdGhhdCB0aGUg cGx1Z2luIGNvbmZpZ3VyYXRpb24gd2FzIGFsd2F5cyBnb2luZyB0byBiZSBhIHJlc291cmNlIChw cm9iYWJseSBhIGxvY2FsIGZpbGUpIHRoYXQgdGhlIGVuZCB1c2VyIGNvdWxkIGN1c3RvbWl6ZS4g IEnigJltIG5vdCBzdXJlIGl0IEkgcmVhbGx5IG5lZWRzIHRvIGJlIHNlcGFyYXRlIGZyb20gdGhl IHBsdWdpbiBkZWZpbml0aW9uIGZpbGUgKC91c3Ivc2hhcmUvb3ZpcnQtZW5naW5lL3VpLXBsdWdp bnMvdGVzdC5qc29uKS4gIEkgc3VwcG9zZSBpdCBkZXBlbmRzIG9uIGhvdyBjb21wbGV4IHRoZSBj b25maWd1cmF0aW9uIGlzIGdvaW5nIHRvIGJlIGFuZCBvbiBzb21lIG9mIHRoZSBpbXBsZW1lbnRh dGlvbiBkZXRhaWxzIHN1cnJvdW5kaW5nIHRoZSBwbHVnaW4gZGVmaW5pdGlvbiBmaWxlLg0KDQpZ ZWFoLCBsZXQncyBtYWtlIHRoZSBjb25jZXB0IG9mIHRoZSBwbHVnaW4gY29uZmlndXJhdGlvbiBm aWxlIG9wdGlvbmFsIGZvciBub3cgKHN0YW5kYXJkIHBsdWdpbiBjb25maWd1cmF0aW9uIGNhbiBi ZSBwYXJ0IG9mIHBsdWdpbiBkZXNjcmlwdG9yKS4NCg0KPiBJbiBteSBwYXRjaCwgSSBzaW1wbHkg dXNlZCBKYWNrc29uIHRvIHBhcnNlIHRoZSBmaWxlIGludG8gYSB0cmVlIG9mIEpzb25Ob2Rlcy4g IFNob3VsZCB0aGUgcGx1Z2luIGRlZmluaXRpb24gYmUgYSBqYXZhIG9iamVjdCBvZiBzb21lIHNv cnQ/IChwbGVhc2UgcGxlYXNlIHBsZWFzZSBkb27igJl0IG1ha2UgbWUgbGVhcm4gYWJvdXQgamF2 YSBiZWFuc+KApikuICBJIHN0dWNrIHdpdGggdGhlIEpzb25Ob2RlcyBiZWNhdXNlIEphY2tzb24g bWFrZXMgdGhlbSBlYXN5IHRvIHdvcmsgd2l0aCBhbmQgdGhleeKAmXJlIHJlYWxseSBlYXN5IHRv IHJlLXNlcmlhbGl6ZSBiYWNrIHRvIGpzb24gdG8gZ2l2ZSB0byB0aGUgd2ViYWRtaW4uDQoNCkkg dGhpbmsgdXNpbmcgSmFja3NvbidzIEpTT04gcmVwcmVzZW50YXRpb24gaW4gSmF2YSAoSnNvbk5v ZGUpIGlzIHBlcmZlY3RseSBzdWl0YWJsZSBpbiB0aGlzIHNpdHVhdGlvbi4gTm8gbmVlZCB0byBo YXZlIHNlcGFyYXRlIEphdmEgYmVhbiBmb3IgdGhhdCA6KQ0KDQo+IFdlIHNob3VsZCBwcm9iYWJs eSB0dXJuIG9uIEpzb25QYXJzZXIuRmVhdHVyZS5BTExPV19DT01NRU5UUy4gIFRoZSBkZWZpbml0 aW9uIGFuZCBjb25maWcgZmlsZXMgd2lsbCBkaWZmaWN1bHQgZm9yIGVuZC11c2VycyAob3IgZXZl biBkZXZlbG9wZXJzKSB0byB1bmRlcnN0YW5kIHdpdGhvdXQgY29tbWVudHMuDQoNCkFncmVlZC4N Cg0KPiBXZSBuZWVkIHRvIGZvcm1hbGl6ZSB0aGUgc3RydWN0dXJlIG9mIHRoZSBwbHVnaW4gZGVm aW5pdGlvbiBhbmQgZGVjaWRlIHdoaWNoIGZpZWxkcyBhcmUgbWFuZGF0b3J5IGFuZCB3aGljaCBh cmUgb3B0aW9uYWwNCg0KU291bmRzIGdvb2QsIGJ1dCBJJ2Qgc2tpcCBzb21lIGF0dHJpYnV0ZXMg Zm9yIG5vdyAoZW5hYmxlZCwgYXBpVmVyc2lvbiwgYXV0aG9yLCBsaWNlbnNlKSBmb3IgdGhlIHNh a2Ugb2Ygc2ltcGxpY2l0eS4NCg0KQXMgeW91IHdyb3RlLCB3aGVuIGxvYWRpbmcgcGx1Z2luIGRl c2NyaXB0b3IsIHdlIHNob3VsZCBlbmZvcmNlIG1hbmRhdG9yeSBhdHRyaWJ1dGVzIChuYW1lLCB2 ZXJzaW9uLCB1cmwpLg0KDQpBcyBmb3IgcGx1Z2luIGNvbmZpZ3VyYXRpb24sIHRoZXJlIGNvdWxk IGJlIHR3byBkaWZmZXJlbnQgYXR0cmlidXRlczoNCi0gImNvbmZpZyIgZm9yIHN0YW5kYXJkIChm YWxsYmFjaykgcGx1Z2luIGNvbmZpZ3VyYXRpb24gKEpTT04gb2JqZWN0KQ0KLSAiY29uZmlnRmls ZSIgZm9yIGV4dGVybmFsIHBsdWdpbiBjb25maWd1cmF0aW9uIGZpbGUgKHBhdGggdG8gZmlsZSwg cmVsYXRpdmUgdG8gL2V0Yy9vdmlydC1lbmdpbmUvdWktcGx1Z2lucy8pLCB0aGF0IG92ZXJyaWRl cyB0aGUgc3RhbmRhcmQgY29uZmlndXJhdGlvbg0KDQpOb3RlIHRoYXQgd2hlbiBsb2FkaW5nIHBs dWdpbiBkZXNjcmlwdG9yLCB0aGUgbG9hZGVyIHNob3VsZCBhbHNvICJtZXJnZSIgdGhlIGNvbmZp Z3VyYXRpb24gdG9nZXRoZXIgKGN1c3RvbSBjb25maWcgb24gdG9wIG9mIHN0YW5kYXJkIGNvbmZp ZykuDQoNCj4gSSBjYW4gd29yayBvbiB0aGUgcGx1Z2luIERlZmluaXRpb24gbG9hZGVyIHNvbWUg bW9yZSBhbmQgbWFrZSBpdCBlbmZvcmNlIG1hbmRhdG9yeS9vcHRpb25hbCBmaWVsZHMuICBJ4oCZ bGwgYWxzbyBpbnZlc3RpZ2F0ZSB0aGUgZGlyZWN0b3J5IGNsaW1iaW5nIGlzc3VlIEkgbWVudGlv bmVkIGluIG15IHByZXZpb3VzIG1haWwuDQoNClNvdW5kcyBnb29kISBJIHdhcyBwbGFubmluZyB0 byBpbmNvcnBvcmF0ZSB5b3VyIG9yaWdpbmFsIHBhdGNoIGluIG5leHQgUG9DIHJldmlzaW9uLCBi dXQgb2YgY291cnNlLCB5b3UgY2FuIHdvcmsgb24gdGhlIGxvYWRlciBzb21lIG1vcmUgYW5kIHNl bmQgYW5vdGhlciBwYXRjaCA6KQ0KDQpGb3IgdGhlIGRpcmVjdG9yeSBjbGltYmluZyBpc3N1ZSwg c2VlIDxPVklSVF9ST09UPi9iYWNrZW5kL21hbmFnZXIvbW9kdWxlcy9yb290L3NyYy9tYWluL2ph dmEvb3JnL292aXJ0L2VuZ2luZS9jb3JlL0ZpbGVTZXJ2bGV0LmphdmEgKHRoZXJlJ3MgYSBtZXRo b2QgY2FsbGVkIGlzU2FuZSBmb3IgZGVhbGluZyB3aXRoIHN1Y2ggaXNzdWUpLg0KDQo+IEFsc28s IEnigJltIGN1cmlvdXMgaG93IHRoaW5ncyBhcmUgZ29pbmcgdG8gd29yayB3aGVuIHRoZSDigJx1 cmzigJ0gcG9pbnRzIHRvIGEgZm9yZWlnbiByZXNvdXJjZSBhcyB0aGUgcGx1Z2luIHN0YXJ0IHBh Z2UuICBJIGRvbuKAmXQgdGhpbmsgdGhlIHBsdWdpbuKAmXMgaWZyYW1lIGlzIGdvaW5nIHRvIGJl IGFibGUgdG8gYWNjZXNzIHBhcmVudC5wbHVnaW5BcGkuICBQZXJoYXBzIHRoZXJlIGlzIHNvbWUg YXNwZWN0IG9mIENPUlMgdGhhdCBJIGRvbuKAmXQgdW5kZXJzdGFuZD8NCg0KV2hlbiB0aGUgcGx1 Z2luIGlmcmFtZSByZWZlcmVuY2VzIGEgcmVzb3VyY2Ugb24gZGlmZmVyZW50IG9yaWdpbiAocHJv dG9jb2wsIGRvbWFpbiwgcG9ydCkgdGhhbiBXZWJBZG1pbiBtYWluIHBhZ2Ugb3JpZ2luLCBKYXZh U2NyaXB0IGNvZGUgcnVubmluZyBpbnNpZGUgdGhhdCBpZnJhbWUgd2lsbCBub3QgYmUgYWJsZSB0 byBhY2Nlc3MgcGFyZW50ICh0b3AtbGV2ZWwpIHBsdWdpbkFwaSBvYmplY3QuIFlvdSdyZSByaWdo dCwgdGhlIHN0YXRlbWVudCAicGFyZW50LnBsdWdpbkFwaSIgd2lsbCBub3Qgd29yaywgYmVjYXVz ZSBvZiBTYW1lLU9yaWdpbiBQb2xpY3kgZW5mb3JjZWQgYnkgdGhlIGJyb3dzZXIuDQoNCkNPUlMg aXMganVzdCBvbmUgYWx0ZXJuYXRpdmUsIHNlZSBodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVl c3Rpb25zLzMwNzY0MTQvd2F5cy10by1jaXJjdW12ZW50LXRoZS1zYW1lLW9yaWdpbi1wb2xpY3kg Zm9yIG1vcmUuIEhvd2V2ZXIsIENPUlMgbmVlZHMgdG8gYmUgc3VwcG9ydGVkIGJ5IHRoZSBicm93 c2VyIChhIHNwZWNpYWwgSFRUUCByZXNwb25zZSBoZWFkZXIgaXMgdXNlZCB0byB0ZWxsIHRoYXQg dGhlIGlmcmFtZSBpcyBhbGxvd2VkIHRvIGFjY2VzcyByZXNvdXJjZXMgZnJvbSBhbm90aGVyIC0g V2ViQWRtaW4gbWFpbiBwYWdlIC0gb3JpZ2luKS4gV2UgbmVlZCB0byBpbnZlc3RpZ2F0ZSB0aGlz IGEgYml0IG1vcmUgSSBndWVzcy4NCg0KUmVnYXJkcywNClZvanRlY2gNCg0KX19fX19fX19fX19f X19fX19fX19fX19fX19fX19fX18NCkZyb206ICJDaHJpcyBGcmFudHoiIDxDaHJpcy5GcmFudHpA aHAuY29tPG1haWx0bzpDaHJpcy5GcmFudHpAaHAuY29tPj4NClRvOiAiVm9qdGVjaCBTem9jcyIg PHZzem9jc0ByZWRoYXQuY29tPG1haWx0bzp2c3pvY3NAcmVkaGF0LmNvbT4+DQpDYzogImVuZ2lu ZS1kZXZlbCIgPGVuZ2luZS1kZXZlbEBvdmlydC5vcmc8bWFpbHRvOmVuZ2luZS1kZXZlbEBvdmly dC5vcmc+Pg0KU2VudDogVGh1cnNkYXksIEF1Z3VzdCAyMywgMjAxMiA1OjEyOjAyIFBNDQpTdWJq ZWN0OiBSRTogVUkgUGx1Z2lucyBjb25maWd1cmF0aW9uDQpWb2p0ZWNoLA0KDQpZb3VyIGFzc3Vt cHRpb24gYWJvdXQgdGhlIHN0cnVjdHVyZSBvZiB0aGUgcGx1Z2luRGVmaW5pdGlvbnMgb2JqZWN0 IGlzIGNvcnJlY3QuICBJdOKAmXMgbm8gbG9uZ2VyIGEgU3RyaW5nLT5TdHJpbmcgbWFwcGluZyAs IGJ1dCBhIFN0cmluZyB0byBPYmplY3QgbWFwcGluZy4NCg0KSSBsaWtlZCB0aGUgb3JpZ2luYWwg SUlGRSBhcHByb2FjaCwgZXhjZXB0IHRoYXQgaXQgc2VlbWVkIHRoYXQgaGF2aW5nIGFkZGl0aW9u YWwgc3RhdGljIHJlc291cmNlcyAoanF1ZXJ5LCBpbWFnZXMsIGh0bWwgdGVtcGxhdGVzLCBldGMp IHdhcyBnb2luZyB0byBiZSBtb3JlIGN1bWJlcnNvbWUuICBJIGRvbuKAmXQgdGhpbmsgaGF2aW5n IHRoZSBwbHVnaW4gYXV0aG9yIHdyaXRlIGEgYmFzaWMgc3RhcnQuaHRtbCBpcyB0aGF0IGJpZyBv ZiBhIGJ1cmRlbiA6KS4NCg0KSSBhZ3JlZSB0aGF0IHRoZSBwbHVnaW4gY29uZmlndXJhdGlvbiB3 YXMgYWx3YXlzIGdvaW5nIHRvIGJlIGEgcmVzb3VyY2UgKHByb2JhYmx5IGEgbG9jYWwgZmlsZSkg dGhhdCB0aGUgZW5kIHVzZXIgY291bGQgY3VzdG9taXplLiAgSeKAmW0gbm90IHN1cmUgaXQgSSBy ZWFsbHkgbmVlZHMgdG8gYmUgc2VwYXJhdGUgZnJvbSB0aGUgcGx1Z2luIGRlZmluaXRpb24gZmls ZSAoL3Vzci9zaGFyZS9vdmlydC1lbmdpbmUvdWktcGx1Z2lucy90ZXN0Lmpzb24pLiAgSSBzdXBw b3NlIGl0IGRlcGVuZHMgb24gaG93IGNvbXBsZXggdGhlIGNvbmZpZ3VyYXRpb24gaXMgZ29pbmcg dG8gYmUgYW5kIG9uIHNvbWUgb2YgdGhlIGltcGxlbWVudGF0aW9uIGRldGFpbHMgc3Vycm91bmRp bmcgdGhlIHBsdWdpbiBkZWZpbml0aW9uIGZpbGUuDQoNCkluIG15IHBhdGNoLCBJIHNpbXBseSB1 c2VkIEphY2tzb24gdG8gcGFyc2UgdGhlIGZpbGUgaW50byBhIHRyZWUgb2YgSnNvbk5vZGVzLiAg U2hvdWxkIHRoZSBwbHVnaW4gZGVmaW5pdGlvbiBiZSBhIGphdmEgb2JqZWN0IG9mIHNvbWUgc29y dD8gKHBsZWFzZSBwbGVhc2UgcGxlYXNlIGRvbuKAmXQgbWFrZSBtZSBsZWFybiBhYm91dCBqYXZh IGJlYW5z4oCmKS4gIEkgc3R1Y2sgd2l0aCB0aGUgSnNvbk5vZGVzIGJlY2F1c2UgSmFja3NvbiBt YWtlcyB0aGVtIGVhc3kgdG8gd29yayB3aXRoIGFuZCB0aGV54oCZcmUgcmVhbGx5IGVhc3kgdG8g cmUtc2VyaWFsaXplIGJhY2sgdG8ganNvbiB0byBnaXZlIHRvIHRoZSB3ZWJhZG1pbi4NCg0KV2Ug c2hvdWxkIHByb2JhYmx5IHR1cm4gb24gSnNvblBhcnNlci5GZWF0dXJlLkFMTE9XX0NPTU1FTlRT LiAgVGhlIGRlZmluaXRpb24gYW5kIGNvbmZpZyBmaWxlcyB3aWxsIGRpZmZpY3VsdCBmb3IgZW5k LXVzZXJzIChvciBldmVuIGRldmVsb3BlcnMpIHRvIHVuZGVyc3RhbmQgd2l0aG91dCBjb21tZW50 cy4NCg0KV2UgbmVlZCB0byBmb3JtYWxpemUgdGhlIHN0cnVjdHVyZSBvZiB0aGUgcGx1Z2luIGRl ZmluaXRpb24gYW5kIGRlY2lkZSB3aGljaCBmaWVsZHMgYXJlIG1hbmRhdG9yeSBhbmQgd2hpY2gg YXJlIG9wdGlvbmFsOg0KDQp7DQogICMgTWFuZGF0b3J5IGZpZWxkczogbmFtZSwgZW5hYmxlZCwg dmVyc2lvbiwgdXJsLCBhcGl2ZXJzaW9uLCBhdXRob3IsIGxpY2Vuc2UNCiAgIyBOYW1lIG9mIHRo ZSBwbHVnaW4NCiAgIm5hbWUiOiAidGVzdCIsDQogICMgV2hldGhlciBvciBub3QgcGx1Z2luIGlz IGVuYWJlZA0KICAiZW5hYmxlZCI6IHRydWUsDQogICMgdmVyc2lvbiBvZiB0aGUgcGx1Z2luDQog ICJ2ZXJzaW9uIjogIjEuMCIsDQogICMgSG93IHRvIGxvYWQgdGhlIHBsdWdpbg0KICAidXJsIjog Ii93ZWJhZG1pbi93ZWJhZG1pbi9wbHVnaW4vdGVzdC9zdGFydC5odG1sIiwNCiAgIyBXaGljaCB2 ZXJzaW9uIG9mIGVuZ2luZSBwbHVnaW4gaXMgbWVhbnQgdG8gd29yayB3aXRoDQogICJhcGl2ZXJz aW9uIjogIjMuMS4wIiwNCiAgIyBXaG8gd3JvdGUgdGhlIHBsdWdpbiBhbmQgaG93IGlzIGl0IGxp Y2Vuc2VkPw0KICAiYXV0aG9yIjogIlN1cGVyQmlnIENvcnBvcmF0aW9uIiwNCiAgImxpY2Vuc2Ui OiAiUHJvcHJpZXRhcnkiLA0KICAjIE9wdGlvbmFsIGZpZWxkcyBwYXRoLCBjb25maWcNCiAgIyBX aGVyZSB0byBsb2NhdGUgcGx1Z2luIChpZiBsb2FkZWQgYnkgd2ViYWRtaW4vcGx1Z2luKQ0KICAi cGF0aCI6ICIvdG1wIiwNCg0KICAjIFBsdWdpbiBjb25maWd1cmF0aW9uIGluZm9ybWF0aW9uIChp ZiBhbnkpDQogICJjb25maWciOiAidGVzdC1jb25maWcuanNvbiIsDQp9DQoNCkkgY2FuIHdvcmsg b24gdGhlIHBsdWdpbiBEZWZpbml0aW9uIGxvYWRlciBzb21lIG1vcmUgYW5kIG1ha2UgaXQgZW5m b3JjZSBtYW5kYXRvcnkvb3B0aW9uYWwgZmllbGRzLiAgSeKAmWxsIGFsc28gaW52ZXN0aWdhdGUg dGhlIGRpcmVjdG9yeSBjbGltYmluZyBpc3N1ZSBJIG1lbnRpb25lZCBpbiBteSBwcmV2aW91cyBt YWlsLg0KDQpBbHNvLCBJ4oCZbSBjdXJpb3VzIGhvdyB0aGluZ3MgYXJlIGdvaW5nIHRvIHdvcmsg d2hlbiB0aGUg4oCcdXJs4oCdIHBvaW50cyB0byBhIGZvcmVpZ24gcmVzb3VyY2UgYXMgdGhlIHBs dWdpbiBzdGFydCBwYWdlLiAgSSBkb27igJl0IHRoaW5rIHRoZSBwbHVnaW7igJlzIGlmcmFtZSBp cyBnb2luZyB0byBiZSBhYmxlIHRvIGFjY2VzcyBwYXJlbnQucGx1Z2luQXBpLiAgUGVyaGFwcyB0 aGVyZSBpcyBzb21lIGFzcGVjdCBvZiBDT1JTIHRoYXQgSSBkb27igJl0IHVuZGVyc3RhbmQ/DQoN ClRoYW5rcywNCi0tQ2hyaXMNCg0KDQoNCkZyb206IFZvanRlY2ggU3pvY3MgW21haWx0bzp2c3pv Y3NAcmVkaGF0LmNvbV0NClNlbnQ6IFRodXJzZGF5LCBBdWd1c3QgMjMsIDIwMTIgNzoxNCBBTQ0K VG86IEZyYW50eiwgQ2hyaXMNCkNjOiBlbmdpbmUtZGV2ZWwNClN1YmplY3Q6IFJlOiBVSSBQbHVn aW5zIGNvbmZpZ3VyYXRpb24NCg0KSGkgQ2hyaXMsDQoNCnRoYW5rcyBmb3IgdGFraW5nIHRoZSB0 aW1lIHRvIG1ha2UgdGhpcyBwYXRjaCwgdGhlc2UgYXJlIHNvbWUgZXhjZWxsZW50IGlkZWFzISAo Q0MnaW5nIGVuZ2luZS1kZXZlbCBzbyB0aGF0IHdlIGNhbiBkaXNjdXNzIHRoaXMgd2l0aCBvdGhl ciBndXlzIGFzIHdlbGwpDQoNCkZpcnN0IG9mIGFsbCwgSSByZWFsbHkgbGlrZSB0aGUgd2F5IHlv dSBkZXNpZ25lZCBwbHVnaW4gc291cmNlIHBhZ2UgVVJMcyAoZ29pbmcgdGhyb3VnaCBQbHVnaW5T b3VyY2VQYWdlU2VydmxldCksIGUuZy4gIi93ZWJhZG1pbi93ZWJhZG1pbi9wbHVnaW4vPHBsdWdp bk5hbWU+LzxwbHVnaW5Tb3VyY2VQYWdlPi5odG1sIiwgcGx1cyB0aGUgY29uY2VwdCBvZiAicGF0 aCIgSlNPTiBhdHRyaWJ1dGUuDQoNCldlYmFkbWluRHluYW1pY0hvc3RpbmdTZXJ2bGV0IGxvYWRz IGFuZCBjYWNoZXMgYWxsIHBsdWdpbiBkZWZpbml0aW9ucyAoKi5qc29uIGZpbGVzKSwgYW5kIGRp cmVjdGx5IGVtYmVkcyB0aGVtIGludG8gV2ViQWRtaW4gaG9zdCBwYWdlIGFzIHBsdWdpbkRlZmlu aXRpb25zIEphdmFTY3JpcHQgb2JqZWN0LiBJJ20gYXNzdW1pbmcgdGhhdCBwbHVnaW5EZWZpbml0 aW9ucyBvYmplY3Qgd2lsbCBub3cgbG9vayBsaWtlIHRoaXM6DQoNCnZhciBwbHVnaW5EZWZpbml0 aW9ucyA9IHsNCiAgInRlc3QiOiB7DQogICAgIm5hbWUiOiAidGVzdCIsDQogICAgInZlcnNpb24i OiAiMS4wIiwNCiAgICAidXJsIjogIi93ZWJhZG1pbi93ZWJhZG1pbi9wbHVnaW4vdGVzdC9mb28u aHRtbCIsDQogICAgInBhdGgiOiAiL3RtcCIsDQogICAgImNvbmZpZyI6IHsiYSI6MSwgImIiOjIs ICJjIjozfQ0KICB9DQp9DQoNCk9yaWdpbmFsbHksIHRoZSBwbHVnaW5EZWZpbml0aW9ucyBvYmpl Y3QgbG9va2VkIGxpa2UgdGhpczoNCg0KdmFyIHBsdWdpbkRlZmluaXRpb25zID0gew0KICAidGVz dCI6ICIvd2ViYWRtaW4vd2ViYWRtaW4vcGx1Z2luL3Rlc3QvZm9vLmh0bWwiIC8vIFNpbXBsZSBw bHVnaW5OYW1lIC0+IHBsdWdpblNvdXJjZVBhZ2VVcmwgbWFwcGluZ3MNCn0NCg0KVGhpcyBpcyBi ZWNhdXNlIFBsdWdpbk1hbmFnZXIgKFdlYkFkbWluKSBvbmx5IG5lZWRzIHBsdWdpbk5hbWUgKCJu YW1lIikgYW5kIHBsdWdpblNvdXJjZVBhZ2VVcmwgKCJ1cmwiKSBkdXJpbmcgc3RhcnR1cCwgd2hl biBjcmVhdGluZyBwbHVnaW4gaWZyYW1lLiBCdXQgdGhpcyBjYW4gYmUgY2hhbmdlZCA6KQ0KDQpQ bHVnaW4gInZlcnNpb24iIG1ha2VzIHNlbnNlLCBwbHVzIHRoZSBwbHVnaW4gY29uZmlndXJhdGlv biBvYmplY3QgKCJjb25maWciKSBjYW4gYmUgdXNlZnVsIGRpcmVjdGx5IG9uIHRoZSBjbGllbnQu IExldCBtZSBleHBsYWluOg0KDQpPcmlnaW5hbGx5LCBwbHVnaW4gY29uZmlndXJhdGlvbiB3YXMg c3VwcG9zZWQgdG8gYmUgcGFzc2VkIHRvIGFjdHVhbCBwbHVnaW4gY29kZSAodGhyb3VnaCBpbW1l ZGlhdGVseS1pbnZva2VkLWZ1bmN0aW9uLWV4cHJlc3Npb24sIG9yIElJRkUpLCBqdXN0IGxpa2Ug dGhpczoNCg0KKGZ1bmN0aW9uIChwbHVnaW5BcGksIHBsdWdpbkNvbmZpZykgeyAvLyBKYXZhU2Ny aXB0IElJRkUNCiAgLy8gLi4uIGFjdHVhbCBwbHVnaW4gY29kZSAuLi4NCn0pKA0KICBwYXJlbnQu cGx1Z2luQXBpLCAvKiByZWZlcmVuY2UgdG8gZ2xvYmFsIHBsdWdpbkFwaSBvYmplY3QgKi8NCiAg eyJhIjoxLCAiYiI6MiwgImMiOjN9IC8qIGVtYmVkZGVkIHBsdWdpbiBjb25maWd1cmF0aW9uIGFz IEphdmFTY3JpcHQgb2JqZWN0ICovDQopOw0KDQpUaGUgd2hvbGUgcHVycG9zZSBvZiBQbHVnaW5T b3VyY2VQYWdlU2VydmxldCB3YXMgdG8gIndyYXAiIGFjdHVhbCBwbHVnaW4gY29kZSBpbnRvIEhU TUwsIHNvIHRoYXQgdXNlcnMgZG9uJ3QgbmVlZCB0byB3cml0ZSBIVE1MIHBhZ2VzIGZvciB0aGVp ciBwbHVnaW5zIG1hbnVhbGx5LiBQbHVnaW5Tb3VyY2VQYWdlU2VydmxldCB3b3VsZCBoYW5kbGUg YW55IHBsdWdpbiBkZXBlbmRlbmNpZXMgKHBsYWNlZCBpbnRvIEhUTUwgaGVhZCksIHdpdGggYWN0 dWFsIHBsdWdpbiBjb2RlIGJlaW5nIHdyYXBwZWQgaW50byBJSUZFLCBhcyBzaG93biBhYm92ZS4g UGx1Z2luIGNvbmZpZ3VyYXRpb24gd2FzIG1lYW50IHRvIGJlIHN0b3JlZCBpbiBhIHNlcGFyYXRl IGZpbGUsIGUuZy4gPHBsdWdpbk5hbWU+LWNvbmZpZy5qc29uLCBzbyB0aGF0IHVzZXJzIGNvdWxk IGNoYW5nZSB0aGUgZGVmYXVsdCBwbHVnaW4gY29uZmlndXJhdGlvbiB0byBzdWl0IHRoZWlyIG5l ZWRzLg0KDQpJbnNwaXJlZCBieSB5b3VyIHBhdGNoLCByYXRoZXIgdGhhbiByZWFkaW5nL2VtYmVk ZGluZyBwbHVnaW4gY29uZmlndXJhdGlvbiB3aGVuIHNlcnZpbmcgcGx1Z2luIEhUTUwgcGFnZSAo UGx1Z2luU291cmNlUGFnZVNlcnZsZXQpLCBpdCdzIGV2ZW4gYmV0dGVyIHRvIGhhdmUgdGhlIHBs dWdpbiBjb25maWd1cmF0aW9uIGVtYmVkZGVkIGRpcmVjdGx5IGludG8gV2ViQWRtaW4gaG9zdCBw YWdlLCBhbG9uZyB3aXRoIGludHJvZHVjaW5nIG5ldyBwbHVnaW5BcGkgZnVuY3Rpb24gdG8gcmV0 cmlldmUgdGhlIHBsdWdpbiBjb25maWd1cmF0aW9uIG9iamVjdC4NCg0KQmFzZWQgb24gdGhpcywg SSBzdWdnZXN0IGZvbGxvd2luZyBtb2RpZmljYXRpb25zIHRvIHRoZSBvcmlnaW5hbCBjb25jZXB0 Og0KDQotIG1vZGlmeSBvcmlnaW5hbCBwbHVnaW5EZWZpbml0aW9ucyBzdHJ1Y3R1cmUsIGZyb20g cGx1Z2luTmFtZSAtPiBwbHVnaW5Tb3VyY2VQYWdlVXJsLCB0byBwbHVnaW5OYW1lIC0+IHBsdWdp bkRlZk9iamVjdA0KLSBwbHVnaW5EZWZPYmplY3QgaXMgYmFzaWNhbGx5IGEgc3Vic2V0IG9mIHBo eXNpY2FsIHBsdWdpbiBkZWZpbml0aW9uICh0ZXN0Lmpzb24sIHNlZSBiZWxvdyksIHN1aXRhYmxl IGZvciB1c2Ugb24gdGhlIGNsaWVudA0KLSBhZGQgZm9sbG93aW5nIGF0dHJpYnV0ZXMgdG8gcGx1 Z2luRGVmT2JqZWN0OiB2ZXJzaW9uLCB1cmwsIGNvbmZpZw0KICAqIG5vdGUgIzE6IG5hbWUgaXMg bm90IG5lZWRlZCwgc2luY2UgaXQncyBhbHJlYWR5IHRoZSBrZXkgb2YgcGx1Z2luTmFtZSAtPiBw bHVnaW5EZWZPYmplY3QgbWFwcGluZw0KICAqIG5vdGUgIzI6IHBhdGggaXMgbm90IG5lZWRlZCBv biB0aGUgY2xpZW50IChtb3JlIG9uIHRoaXMgYmVsb3cpDQotIGludHJvZHVjZSBwbHVnaW5BcGku Y29uZmlnKHBsdWdpbk5hbWUpIGZ1bmN0aW9uIGZvciBwbHVnaW5zIHRvIHJldHJpZXZlIHRoZWly IGNvbmZpZ3VyYXRpb24gb2JqZWN0LCBhbmQgcmVtb3ZlIHBsdWdpbkNvbmZpZyBwYXJhbWV0ZXIg ZnJvbSBtYWluIElJRkUgKGFzIHNob3duIGFib3ZlKQ0KDQpbYV0gUGh5c2ljYWwgcGx1Z2luIGRl ZmluaXRpb24gZmlsZSAoSlNPTikgbWlnaHQgYmUgbG9jYXRlZCBhdCBvVmlydCAiRGF0YURpciIs IGUuZy4gL3Vzci9zaGFyZS9vdmlydC1lbmdpbmUvdWktcGx1Z2lucy90ZXN0Lmpzb24sIGZvciBl eGFtcGxlOg0KDQp7DQogICJuYW1lIjogInRlc3QiLA0KICAidmVyc2lvbiI6ICIxLjAiLA0KICAi dXJsIjogIi93ZWJhZG1pbi93ZWJhZG1pbi9wbHVnaW4vdGVzdC9zdGFydC5odG1sIiwNCiAgInBh dGgiOiAiL3RtcCIsDQogICJjb25maWciOiAidGVzdC1jb25maWcuanNvbiINCn0NCg0KW2JdIFBs dWdpbiBjb25maWd1cmF0aW9uIGZpbGUgKEpTT04pIG1pZ2h0IGJlIGxvY2F0ZWQgYXQgb1ZpcnQg IkNvbmZpZ0RpciIsIGUuZy4gL2V0Yy9vdmlydC1lbmdpbmUvdWktcGx1Z2lucy90ZXN0LWNvbmZp Zy5qc29uLCBmb3IgZXhhbXBsZToNCg0Kew0KICAiYSI6MSwgImIiOjIsICJjIjozDQp9DQoNCltj XSBGaW5hbGx5LCBwbHVnaW4gc3RhdGljIHJlc291cmNlcyAocGx1Z2luIHNvdXJjZSBwYWdlLCBh Y3R1YWwgcGx1Z2luIGNvZGUsIHBsdWdpbiBkZXBlbmRlbmNpZXMsIENTUy9pbWFnZXMsIGV0Yy4p IHdvdWxkIGJlIGxvY2F0ZWQgYXQgL3RtcCAoYXMgc2hvd24gaW4gW2FdKSwgZm9yIGV4YW1wbGU6 DQoNCi90bXAvc3RhcnQuaHRtbCAtPiBwbHVnaW4gc291cmNlIHBhZ2UsIHVzZWQgdG8gbG9hZCBh Y3R1YWwgcGx1Z2luIGNvZGUNCi90bXAvdGVzdC5qcyAtPiBhY3R1YWwgcGx1Z2luIGNvZGUNCi90 bXAvZGVwcy9qcXVlcnktbWluLmpzIC0+IHNpbXVsYXRlIDNyZCBwYXJ0eSBwbHVnaW4gZGVwZW5k ZW5jeQ0KDQpGb3IgZXhhbXBsZToNCiIvd2ViYWRtaW4vd2ViYWRtaW4vcGx1Z2luL3Rlc3Qvc3Rh cnQuaHRtbCIgd2lsbCBiZSBtYXBwZWQgdG8gL3RtcC9zdGFydC5odG1sDQoiL3dlYmFkbWluL3dl YmFkbWluL3BsdWdpbi90ZXN0L2RlcHMvanF1ZXJ5LW1pbi5qcyIgd2lsbCBiZSBtYXBwZWQgdG8g L3RtcC9kZXBzL2pxdWVyeS1taW4uanMNCg0KVGhpcyBhcHByb2FjaCBoYXMgc29tZSBwcm9zIGFu ZCBjb25zOg0KKCspIHBsdWdpbiBzdGF0aWMgcmVzb3VyY2VzIGNhbiBiZSBzZXJ2ZWQgdGhyb3Vn aCBQbHVnaW5Tb3VyY2VQYWdlU2VydmxldCAocHJldHR5IG11Y2ggbGlrZSBvVmlydCBkb2N1bWVu dGF0aW9uIHJlc291cmNlcywgc2VydmVkIHRocm91Z2ggb1ZpcnQgRW5naW5lIHJvb3Qgd2FyJ3Mg RmlsZVNlcnZsZXQpDQooKykgcGx1Z2luIGF1dGhvciBoYXMgY29tcGxldGUgY29udHJvbCBvdmVy IHBsdWdpbiBzb3VyY2UgcGFnZQ0KKC0pIHBsdWdpbiBhdXRob3IgYWN0dWFsbHkgbmVlZHMgdG8g d3JpdGUgcGx1Z2luIHNvdXJjZSBwYWdlDQoNCk92ZXJhbGwsIEkgdGhpbmsgdGhpcyBhcHByb2Fj aCBpcyBiZXR0ZXIgdGhhbiB0aGUgcHJldmlvdXMgb25lICh3aGVyZSBQbHVnaW5Tb3VyY2VQYWdl U2VydmxldCB0b29rIGNhcmUgb2YgcmVuZGVyaW5nIHBsdWdpbiBzb3VyY2UgcGFnZSwgYnV0IHNh Y3JpZmljZWQgc29tZSBmbGV4aWJpbGl0eSkuDQoNCkJ5IHRoZSB3YXksIGhlcmUncyB3aGF0IHdv dWxkIGhhcHBlbiBiZWhpbmQgdGhlIHNjZW5lczoNCg0KICAxLiAgdXNlciByZXF1ZXN0cyBXZWJB ZG1pbiBob3N0IHBhZ2UsIFdlYmFkbWluRHluYW1pY0hvc3RpbmdTZXJ2bGV0IGxvYWRzIGFuZCBj YWNoZXMgYWxsIHBsdWdpbiBkZWZpbml0aW9ucyBbYV0gKyBwbHVnaW4gY29uZmlndXJhdGlvbnMg W2JdIGFuZCBjb25zdHJ1Y3RzL2VtYmVkcyBhcHByb3ByaWF0ZSBwbHVnaW5EZWZpbml0aW9ucyBK YXZhU2NyaXB0IG9iamVjdA0KICAyLiAgZHVyaW5nIFdlYkFkbWluIHN0YXJ0dXAsIFBsdWdpbk1h bmFnZXIgcmVnaXN0ZXJzIHRoZSBwbHVnaW4gKG5hbWUvdmVyc2lvbi91cmwvY29uZmlnKSwgYW5k IGNyZWF0ZXMvYXR0YWNoZXMgdGhlIGlmcmFtZSB0byBmZXRjaCBwbHVnaW4gc291cmNlIHBhZ2Ug YW5zeW5jaHJvbm91c2x5DQogIDMuICBQbHVnaW5Tb3VyY2VQYWdlU2VydmxldCBoYW5kbGVzIHBs dWdpbiBzb3VyY2UgcGFnZSByZXF1ZXN0LCByZXNvbHZlcyB0aGUgY29ycmVjdCBwYXRoIFtjXSBh bmQganVzdCBzdHJlYW1zIHRoZSBmaWxlIGNvbnRlbnQgYmFjayB0byBjbGllbnQNCj4gMS4gIFRo ZSBwbHVnaW4gY29uZmlndXJhdGlvbiBmaWxlcyBzaG91bGQgcHJvYmFibHkgaGF2ZSBhbiAiZW5h YmxlZCIgZmllbGQgYW5kIGFuICJhcGlWZXJzaW9uIiBmaWVsZCB0aGF0IHNob3VsZCBiZSBleGFt aW5lZCB0byBkZXRlcm1pbmUgd2hldGhlciBvciBub3QgdG8gdXNlIHRoZSBwbHVnaW4uDQoNClNv dW5kcyBnb29kLCB3ZSBjYW4gaW1wbGVtZW50IHRoZXNlIGxhdGVyIG9uIDopDQoNCj4gMi4gIEkg c3VzcGVjdCB0aGUgd2F5IEkndmUgbW9kaWZpZWQgUGx1Z2luU291cmNlUGFnZSBtYWtlcyBpdCB2 dWxuZXJhYmxlIHRvIGRpcmVjdG9yeSBjbGltYmluZyBhdHRhY2tzLg0KDQpZZXMsIGJ1dCB3ZSBj YW4gZGVmZW5kIGFnYWluc3QgdGhlc2UsIHJlc3RyaWN0aW5nIGFjY2VzcyBvbmx5IHRvIHBsdWdp bidzICJwYXRoIiBhbmQgaXRzIHN1Yi1kaXJlY3Rvcmllcy4NCg0KPiAzLiAgSXMgL3Vzci9zaGFy ZS9vdmlydC1lbmdpbmUgdGhlIHJpZ2h0IHBsYWNlIGZvciB0aGUgcGx1Z2luIGNvbmZpZyBmaWxl cz8NCg0KSSBzdXBwb3NlIHlvdSBtZWFuIHBsdWdpbiBkZWZpbml0aW9uIGZpbGVzIFthXSwgY2Fu bm90IHRlbGwgZm9yIHN1cmUsIGJ1dCB3ZSBjYW4gY2hhbmdlIHRoaXMgYW55dGltZSA6KQ0KDQoN CkNocmlzLCBwbGVhc2UgbGV0IG1lIGtub3cgd2hhdCB5b3UgdGhpbmssIGFuZCBhZ2FpbiAtIG1h bnkgdGhhbmtzIGZvciBzZW5kaW5nIHRoZSBwYXRjaCENCg0KDQpSZWdhcmRzLA0KVm9qdGVjaA0K X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCg0KRnJvbTogIkNocmlzIEZyYW50eiIg PENocmlzLkZyYW50ekBocC5jb208bWFpbHRvOkNocmlzLkZyYW50ekBocC5jb20+Pg0KVG86IHZz em9jc0ByZWRoYXQuY29tPG1haWx0bzp2c3pvY3NAcmVkaGF0LmNvbT4NClNlbnQ6IFdlZG5lc2Rh eSwgQXVndXN0IDIyLCAyMDEyIDc6NTY6NDUgUE0NClN1YmplY3Q6IFVJIFBsdWdpbnMgY29uZmln dXJhdGlvbg0KDQpWb2p0ZWNoLA0KDQpJIGRlY2lkZWQgdG8gd29yayBvbiBtYWtpbmcgdGhlIHBs dWdpbiBwYXRjaCBhIGJpdCBtb3JlIGNvbmZpZ3VyYWJsZSwgZm9sbG93aW5nIHNvbWUgb2YgdGhl IGlkZWFzIGV4cHJlc3NlZCBieSBJdGFtYXIgYW5kIG90aGVycyBpbiB0aGUgbWVldGluZyB5ZXN0 ZXJkYXkuICBUaGUgYXR0YWNoZWQgcGF0Y2ggaXMgYSBzaW1wbGUgZmlyc3QtYXR0ZW1wdC4NCg0K UGx1Z2luIGNvbmZpZ3VyYXRpb25zIGFyZSBzdG9yZWQgaW4gL3Vzci9zaGFyZS9vdmlydC1lbmdp bmUvdWktcGx1Z2lucy8qLmpzb24uDQoNCkV4YW1wbGU6DQp7DQogICAgICAgICJuYW1lIjogInRl c3QiLA0KICAgICAgICAidmVyc2lvbiI6ICIxLjAiLA0KICAgICAgICAidXJsIjogIi93ZWJhZG1p bi93ZWJhZG1pbi9wbHVnaW4vdGVzdC9mb28uaHRtbCIsDQogICAgICAgICJwYXRoIjogIi90bXAi LA0KICAgICAgICAiY29uZmlnIjogeyJhIjoxLCAiYiI6MiwgImMiOiAzfQ0KfQ0KDQpUaGUgZW5n aW5lIHJlYWRzIGFsbCBvZiB0aGUgKi5qc29uIGZpbGVzIGluIHRoYXQgZGlyZWN0b3J5IHRvIGJ1 aWxkIHRoZSBsaXN0IG9mIGtub3duIHBsdWdpbnMgYW5kIGdpdmVzIHRoYXQgbGlzdCB0byB0aGUg d2ViYWRtaW4uDQoNCldoZW4gd2ViYWRtaW4gbG9hZHMgYSBwbHVnaW4sIGl0IHJlcXVlc3RzIHRo ZSBVUkwgZ2l2ZW4gaW4gdGhlIHBsdWdpbiBjb25maWcgZmlsZS4gIFRoZSAicGx1Z2luIiBVUkwg aXMgbWFwcGVkIHRvIFBsdWdpblNvdXJjZVBhZ2UsIHdoaWNoIHdpbGwgdHJhbnNsYXRlIHRoZSBm aXJzdCBwYXJ0IG9mIHRoZSBwYXRoICgidGVzdCIpIGludG8gd2hhdGV2ZXIgcGF0aCBpcyBzdG9y ZWQgaW4gcGx1Z2luQ29uZmlnICgiL3RtcCIpIGluIHRoaXMgY2FzZSwgYW5kIHRoZW4gc2VydmUg dGhlIHN0YXRpYyBmaWxlIChlLmcuICIvdG1wL2Zvby5odG1sIikuDQoNCkkgZGlkbid0IHVzZSB0 aGUgcmVuZGVyUGx1Z2luU291cmNlUGFnZSgpIG1ldGhvZCBpbiBmYXZvciBvZiBqdXN0IHNlcnZp bmcgYSBzdGF0aWMgZmlsZSwgYnV0IEkgaGF2ZSBubyBzdHJvbmcgb3BpbmlvbiBvbiB0aGUgbWF0 dGVyLiAgSG93ZXZlciwgYSBwbHVnaW4gbWF5IHdhbnQgdG8gc3RvcmUgc3RhdGljIHJlc291cmNl cyBhdCAicGF0aCIgYW5kIGhhdmUgdGhlIGVuZ2luZSBzZXJ2ZSB0aG9zZSByZXNvdXJjZXMuICBC eSBqdXN0IHNlcnZpbmcgZmlsZXMgdGhyb3VnaCBQbHVnaW5Tb3VyY2VQYWdlLCB3ZSBkb24ndCBu ZWVkIGFueSBvdGhlciBzZXJ2bGV0cyB0byBwcm92aWRlIHRob3NlIHJlc291cmNlcy4NCg0KVGhl cmUgaXMgc3RpbGwgYSBiaXQgb2Ygd29yayB0byBkbzoNCg0KMS4gIFRoZSBwbHVnaW4gY29uZmln dXJhdGlvbiBmaWxlcyBzaG91bGQgcHJvYmFibHkgaGF2ZSBhbiAiZW5hYmxlZCIgZmllbGQgYW5k IGFuICJhcGlWZXJzaW9uIiBmaWVsZCB0aGF0IHNob3VsZCBiZSBleGFtaW5lZCB0byBkZXRlcm1p bmUgd2hldGhlciBvciBub3QgdG8gdXNlIHRoZSBwbHVnaW4uDQoNCjIuICBJIHN1c3BlY3QgdGhl IHdheSBJJ3ZlIG1vZGlmaWVkIFBsdWdpblNvdXJjZVBhZ2UgbWFrZXMgaXQgdnVsbmVyYWJsZSB0 byBkaXJlY3RvcnkgY2xpbWJpbmcgYXR0YWNrcy4NCg0KMy4gIElzIC91c3Ivc2hhcmUvb3ZpcnQt ZW5naW5lIHRoZSByaWdodCBwbGFjZSBmb3IgdGhlIHBsdWdpbiBjb25maWcgZmlsZXM/DQoNCkxl dCBtZSBrbm93IHdoYXQgeW91IHRoaW5rLA0KLS1DaHJpcw0KDQo= --_000_A24D665DC3ECC245A2EA0D9A958F80B62C49123BG9W0745americas_ Content-Type: text/html; charset="utf-8" Content-Transfer-Encoding: base64 PGh0bWwgeG1sbnM6dj0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp2bWwiIHhtbG5zOm89InVy bjpzY2hlbWFzLW1pY3Jvc29mdC1jb206b2ZmaWNlOm9mZmljZSIgeG1sbnM6dz0idXJuOnNjaGVt YXMtbWljcm9zb2Z0LWNvbTpvZmZpY2U6d29yZCIgeG1sbnM6bT0iaHR0cDovL3NjaGVtYXMubWlj cm9zb2Z0LmNvbS9vZmZpY2UvMjAwNC8xMi9vbW1sIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv VFIvUkVDLWh0bWw0MCI+DQo8aGVhZD4NCjxtZXRhIGh0dHAtZXF1aXY9IkNvbnRlbnQtVHlwZSIg Y29udGVudD0idGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04Ij4NCjxtZXRhIG5hbWU9IkdlbmVyYXRv ciIgY29udGVudD0iTWljcm9zb2Z0IFdvcmQgMTIgKGZpbHRlcmVkIG1lZGl1bSkiPg0KPCEtLVtp ZiAhbXNvXT48c3R5bGU+dlw6KiB7YmVoYXZpb3I6dXJsKCNkZWZhdWx0I1ZNTCk7fQ0Kb1w6KiB7 YmVoYXZpb3I6dXJsKCNkZWZhdWx0I1ZNTCk7fQ0Kd1w6KiB7YmVoYXZpb3I6dXJsKCNkZWZhdWx0 I1ZNTCk7fQ0KLnNoYXBlIHtiZWhhdmlvcjp1cmwoI2RlZmF1bHQjVk1MKTt9DQo8L3N0eWxlPjwh W2VuZGlmXS0tPjxzdHlsZT48IS0tDQovKiBGb250IERlZmluaXRpb25zICovDQpAZm9udC1mYWNl DQoJe2ZvbnQtZmFtaWx5OkhlbHZldGljYTsNCglwYW5vc2UtMToyIDExIDYgNCAyIDIgMiAyIDIg NDt9DQpAZm9udC1mYWNlDQoJe2ZvbnQtZmFtaWx5OiJDYW1icmlhIE1hdGgiOw0KCXBhbm9zZS0x OjIgNCA1IDMgNSA0IDYgMyAyIDQ7fQ0KQGZvbnQtZmFjZQ0KCXtmb250LWZhbWlseTpDYWxpYnJp Ow0KCXBhbm9zZS0xOjIgMTUgNSAyIDIgMiA0IDMgMiA0O30NCkBmb250LWZhY2UNCgl7Zm9udC1m YW1pbHk6VGFob21hOw0KCXBhbm9zZS0xOjIgMTEgNiA0IDMgNSA0IDQgMiA0O30NCi8qIFN0eWxl IERlZmluaXRpb25zICovDQpwLk1zb05vcm1hbCwgbGkuTXNvTm9ybWFsLCBkaXYuTXNvTm9ybWFs DQoJe21hcmdpbjowaW47DQoJbWFyZ2luLWJvdHRvbTouMDAwMXB0Ow0KCWZvbnQtc2l6ZToxMi4w cHQ7DQoJZm9udC1mYW1pbHk6IlRpbWVzIE5ldyBSb21hbiIsInNlcmlmIjt9DQphOmxpbmssIHNw YW4uTXNvSHlwZXJsaW5rDQoJe21zby1zdHlsZS1wcmlvcml0eTo5OTsNCgljb2xvcjpibHVlOw0K CXRleHQtZGVjb3JhdGlvbjp1bmRlcmxpbmU7fQ0KYTp2aXNpdGVkLCBzcGFuLk1zb0h5cGVybGlu a0ZvbGxvd2VkDQoJe21zby1zdHlsZS1wcmlvcml0eTo5OTsNCgljb2xvcjpwdXJwbGU7DQoJdGV4 dC1kZWNvcmF0aW9uOnVuZGVybGluZTt9DQpwDQoJe21zby1zdHlsZS1wcmlvcml0eTo5OTsNCglt YXJnaW46MGluOw0KCW1hcmdpbi1ib3R0b206LjAwMDFwdDsNCglmb250LXNpemU6MTIuMHB0Ow0K CWZvbnQtZmFtaWx5OiJUaW1lcyBOZXcgUm9tYW4iLCJzZXJpZiI7fQ0KcC5Nc29BY2V0YXRlLCBs aS5Nc29BY2V0YXRlLCBkaXYuTXNvQWNldGF0ZQ0KCXttc28tc3R5bGUtcHJpb3JpdHk6OTk7DQoJ bXNvLXN0eWxlLWxpbms6IkJhbGxvb24gVGV4dCBDaGFyIjsNCgltYXJnaW46MGluOw0KCW1hcmdp bi1ib3R0b206LjAwMDFwdDsNCglmb250LXNpemU6OC4wcHQ7DQoJZm9udC1mYW1pbHk6IlRhaG9t YSIsInNhbnMtc2VyaWYiO30NCnNwYW4uRW1haWxTdHlsZTIwDQoJe21zby1zdHlsZS10eXBlOnBl cnNvbmFsOw0KCWZvbnQtZmFtaWx5OiJDYWxpYnJpIiwic2Fucy1zZXJpZiI7DQoJY29sb3I6IzFG NDk3RDt9DQpzcGFuLkJhbGxvb25UZXh0Q2hhcg0KCXttc28tc3R5bGUtbmFtZToiQmFsbG9vbiBU ZXh0IENoYXIiOw0KCW1zby1zdHlsZS1wcmlvcml0eTo5OTsNCgltc28tc3R5bGUtbGluazoiQmFs bG9vbiBUZXh0IjsNCglmb250LWZhbWlseToiVGFob21hIiwic2Fucy1zZXJpZiI7fQ0Kc3Bhbi5F bWFpbFN0eWxlMjMNCgl7bXNvLXN0eWxlLXR5cGU6cGVyc29uYWwtcmVwbHk7DQoJZm9udC1mYW1p bHk6IkNhbGlicmkiLCJzYW5zLXNlcmlmIjsNCgljb2xvcjojMUY0OTdEO30NCi5Nc29DaHBEZWZh dWx0DQoJe21zby1zdHlsZS10eXBlOmV4cG9ydC1vbmx5Ow0KCWZvbnQtc2l6ZToxMC4wcHQ7fQ0K QHBhZ2UgV29yZFNlY3Rpb24xDQoJe3NpemU6OC41aW4gMTEuMGluOw0KCW1hcmdpbjoxLjBpbiAx LjBpbiAxLjBpbiAxLjBpbjt9DQpkaXYuV29yZFNlY3Rpb24xDQoJe3BhZ2U6V29yZFNlY3Rpb24x O30NCi8qIExpc3QgRGVmaW5pdGlvbnMgKi8NCkBsaXN0IGwwDQoJe21zby1saXN0LWlkOjE4OTg4 MjU2MDsNCgltc28tbGlzdC10ZW1wbGF0ZS1pZHM6LTE3NDU2MzQ3Njt9DQpAbGlzdCBsMDpsZXZl bDENCgl7bXNvLWxldmVsLXRhYi1zdG9wOi41aW47DQoJbXNvLWxldmVsLW51bWJlci1wb3NpdGlv bjpsZWZ0Ow0KCXRleHQtaW5kZW50Oi0uMjVpbjt9DQpvbA0KCXttYXJnaW4tYm90dG9tOjBpbjt9 DQp1bA0KCXttYXJnaW4tYm90dG9tOjBpbjt9DQotLT48L3N0eWxlPjwhLS1baWYgZ3RlIG1zbyA5 XT48eG1sPg0KPG86c2hhcGVkZWZhdWx0cyB2OmV4dD0iZWRpdCIgc3BpZG1heD0iMTAyNiIgLz4N CjwveG1sPjwhW2VuZGlmXS0tPjwhLS1baWYgZ3RlIG1zbyA5XT48eG1sPg0KPG86c2hhcGVsYXlv dXQgdjpleHQ9ImVkaXQiPg0KPG86aWRtYXAgdjpleHQ9ImVkaXQiIGRhdGE9IjEiIC8+DQo8L286 c2hhcGVsYXlvdXQ+PC94bWw+PCFbZW5kaWZdLS0+DQo8L2hlYWQ+DQo8Ym9keSBsYW5nPSJFTi1V UyIgbGluaz0iYmx1ZSIgdmxpbms9InB1cnBsZSI+DQo8ZGl2IGNsYXNzPSJXb3JkU2VjdGlvbjEi Pg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7Zm9u dC1mYW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90OywmcXVvdDtzYW5zLXNlcmlmJnF1b3Q7O2NvbG9y OiMxRjQ5N0QiPlZvanRlY2gsPG86cD48L286cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05v cm1hbCI+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7Zm9udC1mYW1pbHk6JnF1b3Q7Q2Fs aWJyaSZxdW90OywmcXVvdDtzYW5zLXNlcmlmJnF1b3Q7O2NvbG9yOiMxRjQ5N0QiPjxvOnA+Jm5i c3A7PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFuIHN0eWxlPSJm b250LXNpemU6MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGlicmkmcXVvdDssJnF1b3Q7c2Fu cy1zZXJpZiZxdW90Oztjb2xvcjojMUY0OTdEIj5JIGFncmVlIHdpdGggeW91ciBmb3JtYWxpemVk IG5hbWVzOjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFu IHN0eWxlPSJmb250LXNpemU6MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGlicmkmcXVvdDss JnF1b3Q7c2Fucy1zZXJpZiZxdW90Oztjb2xvcjojMUY0OTdEIj48bzpwPiZuYnNwOzwvbzpwPjwv c3Bhbj48L3A+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48aT48c3BhbiBzdHlsZT0iZm9udC1zaXpl OjExLjBwdDtmb250LWZhbWlseTomcXVvdDtDYWxpYnJpJnF1b3Q7LCZxdW90O3NhbnMtc2VyaWYm cXVvdDs7Y29sb3I6IzFGNDk3RCI+UGx1Z2luIERlc2NyaXB0b3I8L3NwYW4+PC9pPjxzcGFuIHN0 eWxlPSJmb250LXNpemU6MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGlicmkmcXVvdDssJnF1 b3Q7c2Fucy1zZXJpZiZxdW90Oztjb2xvcjojMUY0OTdEIj4gaXMgdGhlIEpTT04gZmlsZSBjb250 YWluaW5nIHBsdWdpbiBtZXRhLWRhdGEuDQogVGhlIHBsdWdpbiBkZXNjcmlwdG9yIG1heSBhbHNv IGNvbnRhaW4gdGhlIGRlZmF1bHQgY29uZmlndXJhdGlvbiBkYXRhLiZuYnNwOyAmbmJzcDtJdCBp cyBsb2NhdGVkIGluICREQVRBRElSL3VpLXBsdWdpbnMuPG86cD48L286cD48L3NwYW4+PC9wPg0K PHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7Zm9udC1m YW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90OywmcXVvdDtzYW5zLXNlcmlmJnF1b3Q7O2NvbG9yOiMx RjQ5N0QiPjxvOnA+Jm5ic3A7PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwi PjxpPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGli cmkmcXVvdDssJnF1b3Q7c2Fucy1zZXJpZiZxdW90Oztjb2xvcjojMUY0OTdEIj5QbHVnaW4gQ29u ZmlndXJhdGlvbjwvc3Bhbj48L2k+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7Zm9udC1m YW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90OywmcXVvdDtzYW5zLXNlcmlmJnF1b3Q7O2NvbG9yOiMx RjQ5N0QiPiBpcyB0aGUgSlNPTiBmaWxlIGNvbnRhaW5pbmcgb3B0aW9uYWwgcGx1Z2luDQogY29u ZmlndXJhdGlvbiBpbmZvLiZuYnNwOyBJdCBpcyBsb2NhdGVkIGluICRDT05GSUdESVIvdWktcGx1 Z2lucyAodW5sZXNzIHRoZSBQbHVnaW4gRGVzY3JpcHRvciBjb250YWlucyBhbiBhYnNvbHV0ZSBw YXRoKS48bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48aT48c3Bh biBzdHlsZT0iZm9udC1zaXplOjExLjBwdDtmb250LWZhbWlseTomcXVvdDtDYWxpYnJpJnF1b3Q7 LCZxdW90O3NhbnMtc2VyaWYmcXVvdDs7Y29sb3I6IzFGNDk3RCI+PG86cD4mbmJzcDs8L286cD48 L3NwYW4+PC9pPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxpPjxzcGFuIHN0eWxlPSJmb250 LXNpemU6MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGlicmkmcXVvdDssJnF1b3Q7c2Fucy1z ZXJpZiZxdW90Oztjb2xvcjojMUY0OTdEIj5QbHVnaW4gRGVmaW5pdGlvbjwvc3Bhbj48L2k+PHNw YW4gc3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7Zm9udC1mYW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90 OywmcXVvdDtzYW5zLXNlcmlmJnF1b3Q7O2NvbG9yOiMxRjQ5N0QiPiBpcyB0aGUgSmF2YVNjcmlw dCBvYmplY3QgdXNlZCBieSBXZWJBZG1pbi4mbmJzcDsNCiBJbiB0aGUgY3VycmVudCBpbXBsZW1l bnRhdGlvbiwgdGhlIFBsdWdpbiBEZWZpbml0aW9uIGNvbnRhaW5zIGJvdGggdGhlIFBsdWdpbiBE ZXNjcmlwdG9yIGFuZCB0aGUgUGx1Z2luIENvbmZpZ3VyYWlvbi48bzpwPjwvbzpwPjwvc3Bhbj48 L3A+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjExLjBwdDtm b250LWZhbWlseTomcXVvdDtDYWxpYnJpJnF1b3Q7LCZxdW90O3NhbnMtc2VyaWYmcXVvdDs7Y29s b3I6IzFGNDk3RCI+PG86cD4mbmJzcDs8L286cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05v cm1hbCI+PGk+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7Zm9udC1mYW1pbHk6JnF1b3Q7 Q2FsaWJyaSZxdW90OywmcXVvdDtzYW5zLXNlcmlmJnF1b3Q7O2NvbG9yOiMxRjQ5N0QiPlBsdWdp biBTb3VyY2UgUGFnZTwvc3Bhbj48L2k+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7Zm9u dC1mYW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90OywmcXVvdDtzYW5zLXNlcmlmJnF1b3Q7O2NvbG9y OiMxRjQ5N0QiPiBpcyB0aGUgSFRNTCBwYWdlIHVzZWQgdG8gaW52b2tlIHRoZSBwbHVnaW4NCiBj b2RlIGFuZCBzaGFsbCBiZSByZWZlcmVuY2VkIGJ5IHRoZSBwbHVnaW4gZGVzY3JpcHRvcuKAmXMg 4oCcdXJs4oCdIGF0dHJpYnV0ZS48bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQo8cCBjbGFzcz0iTXNv Tm9ybWFsIj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjExLjBwdDtmb250LWZhbWlseTomcXVvdDtD YWxpYnJpJnF1b3Q7LCZxdW90O3NhbnMtc2VyaWYmcXVvdDs7Y29sb3I6IzFGNDk3RCI+PG86cD4m bmJzcDs8L286cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNwYW4gc3R5bGU9 ImZvbnQtc2l6ZToxMS4wcHQ7Zm9udC1mYW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90OywmcXVvdDtz YW5zLXNlcmlmJnF1b3Q7O2NvbG9yOiMxRjQ5N0QiPknigJl2ZSBpbXBsZW1lbnRlZCB0aGUgY29u ZmlnIG1lcmdpbmcgeW914oCZdmUgc3VnZ2VzdGVkOiZuYnNwOyB0aGUgc3RydWN0dXJlIGluIGNv bmZpZ0ZpbGUgZ2V0cyBtZXJnZWQgd2l0aCB0aGUgc3RydWN0dXJlIG9mIOKAnGNvbmZpZ+KAnSwg d2l0aCB0aGUgZGF0YSBpbiBjb25maWdGaWxlIHdpbm5pbmcNCiBpbiB0aGUgY2FzZSBvZiBkdXBs aWNhdGUga2V5IG5hbWVzLjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3Jt YWwiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGli cmkmcXVvdDssJnF1b3Q7c2Fucy1zZXJpZiZxdW90Oztjb2xvcjojMUY0OTdEIj48bzpwPiZuYnNw OzwvbzpwPjwvc3Bhbj48L3A+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48c3BhbiBzdHlsZT0iZm9u dC1zaXplOjExLjBwdDtmb250LWZhbWlseTomcXVvdDtDYWxpYnJpJnF1b3Q7LCZxdW90O3NhbnMt c2VyaWYmcXVvdDs7Y29sb3I6IzFGNDk3RCI+QlRXLCB0aGUgcGF0Y2ggaXMgYWdhaW5zdCBvdmly dC1lbmdpbmUgJiM0MzsgMDAwMS1XSVAtVUktUGx1Z2lucy1Qb0MtcmV2aXNpb24tMi48bzpwPjwv bzpwPjwvc3Bhbj48L3A+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48c3BhbiBzdHlsZT0iZm9udC1z aXplOjExLjBwdDtmb250LWZhbWlseTomcXVvdDtDYWxpYnJpJnF1b3Q7LCZxdW90O3NhbnMtc2Vy aWYmcXVvdDs7Y29sb3I6IzFGNDk3RCI+PG86cD4mbmJzcDs8L286cD48L3NwYW4+PC9wPg0KPHAg Y2xhc3M9Ik1zb05vcm1hbCI+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7Zm9udC1mYW1p bHk6JnF1b3Q7Q2FsaWJyaSZxdW90OywmcXVvdDtzYW5zLXNlcmlmJnF1b3Q7O2NvbG9yOiMxRjQ5 N0QiPkxldCBtZSBrbm93IHdoYXQgeW91IHRoaW5rLDxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCjxw IGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTEuMHB0O2ZvbnQtZmFt aWx5OiZxdW90O0NhbGlicmkmcXVvdDssJnF1b3Q7c2Fucy1zZXJpZiZxdW90Oztjb2xvcjojMUY0 OTdEIj4tLUNocmlzPG86cD48L286cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+ PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7Zm9udC1mYW1pbHk6JnF1b3Q7Q2FsaWJyaSZx dW90OywmcXVvdDtzYW5zLXNlcmlmJnF1b3Q7O2NvbG9yOiMxRjQ5N0QiPjxvOnA+Jm5ic3A7PC9v OnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFuIHN0eWxlPSJmb250LXNp emU6MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGlicmkmcXVvdDssJnF1b3Q7c2Fucy1zZXJp ZiZxdW90Oztjb2xvcjojMUY0OTdEIj48bzpwPiZuYnNwOzwvbzpwPjwvc3Bhbj48L3A+DQo8cCBj bGFzcz0iTXNvTm9ybWFsIj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjExLjBwdDtmb250LWZhbWls eTomcXVvdDtDYWxpYnJpJnF1b3Q7LCZxdW90O3NhbnMtc2VyaWYmcXVvdDs7Y29sb3I6IzFGNDk3 RCI+PG86cD4mbmJzcDs8L286cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNw YW4gc3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7Zm9udC1mYW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90 OywmcXVvdDtzYW5zLXNlcmlmJnF1b3Q7O2NvbG9yOiMxRjQ5N0QiPjxvOnA+Jm5ic3A7PC9vOnA+ PC9zcGFuPjwvcD4NCjxkaXY+DQo8ZGl2IHN0eWxlPSJib3JkZXI6bm9uZTtib3JkZXItdG9wOnNv bGlkICNCNUM0REYgMS4wcHQ7cGFkZGluZzozLjBwdCAwaW4gMGluIDBpbiI+DQo8cCBjbGFzcz0i TXNvTm9ybWFsIj48Yj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjEwLjBwdDtmb250LWZhbWlseTom cXVvdDtUYWhvbWEmcXVvdDssJnF1b3Q7c2Fucy1zZXJpZiZxdW90OyI+RnJvbTo8L3NwYW4+PC9i PjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTAuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O1RhaG9tYSZx dW90OywmcXVvdDtzYW5zLXNlcmlmJnF1b3Q7Ij4gVm9qdGVjaCBTem9jcyBbbWFpbHRvOnZzem9j c0ByZWRoYXQuY29tXQ0KPGJyPg0KPGI+U2VudDo8L2I+IE1vbmRheSwgQXVndXN0IDI3LCAyMDEy IDk6NDkgQU08YnI+DQo8Yj5Ubzo8L2I+IEZyYW50eiwgQ2hyaXM8YnI+DQo8Yj5DYzo8L2I+IGVu Z2luZS1kZXZlbDxicj4NCjxiPlN1YmplY3Q6PC9iPiBSZTogVUkgUGx1Z2lucyBjb25maWd1cmF0 aW9uPG86cD48L286cD48L3NwYW4+PC9wPg0KPC9kaXY+DQo8L2Rpdj4NCjxwIGNsYXNzPSJNc29O b3JtYWwiPjxvOnA+Jm5ic3A7PC9vOnA+PC9wPg0KPGRpdj4NCjxwIGNsYXNzPSJNc29Ob3JtYWwi IHN0eWxlPSJtYXJnaW4tYm90dG9tOjEyLjBwdCI+PHNwYW4gc3R5bGU9ImNvbG9yOmJsYWNrIj5I aSBDaHJpcyw8YnI+DQo8YnI+DQo8L3NwYW4+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7 Zm9udC1mYW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90OywmcXVvdDtzYW5zLXNlcmlmJnF1b3Q7O2Nv bG9yOiMxRjQ5N0QiPiZndDsgWW91ciBhc3N1bXB0aW9uIGFib3V0IHRoZSBzdHJ1Y3R1cmUgb2Yg dGhlIHBsdWdpbkRlZmluaXRpb25zIG9iamVjdCBpcyBjb3JyZWN0LiZuYnNwOyBJdOKAmXMgbm8g bG9uZ2VyIGEgU3RyaW5nLSZndDtTdHJpbmcgbWFwcGluZyAsIGJ1dCBhIFN0cmluZyB0byBPYmpl Y3QgbWFwcGluZy48L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOmJsYWNrIj48YnI+DQo8YnI+DQpZ ZXMgOikgYnV0IG1heWJlIHdlIGNvdWxkIGFsc28gZm9ybWFsaXplIHNvbWUgdGVybXMsIGZvciBl eGFtcGxlOjxicj4NCjxicj4NCjxlbT5QbHVnaW4gZGVzY3JpcHRvcjwvZW0+IGlzIHRoZSBKU09O IGZpbGUgdGhhdCBjb250YWlucyBpbXBvcnRhbnQgcGx1Z2luIG1ldGEtZGF0YSAoaW5jbHVkaW5n IHRoZSBwbHVnaW4gc291cmNlIHBhZ2UgVVJMKSwgZS5nLg0KPGk+L3Vzci9zaGFyZS9vdmlydC1l bmdpbmUvdWktcGx1Z2lucy90ZXN0Lmpzb248YnI+DQo8L2k+PGJyPg0KPGk+UGx1Z2luIGRlZmlu aXRpb248L2k+IGlzIHRoZSBKYXZhU2NyaXB0IG9iamVjdCByZXByZXNlbnRpbmcgcGx1Z2luIGRl c2NyaXB0b3IgbWV0YS1kYXRhIHN1aXRhYmxlIGZvciB1c2Ugb24gY2xpZW50IChHV1QgV2ViQWRt aW4pLiBQbHVnaW4gZGVmaW5pdGlvbiBpcyBlbWJlZGRlZCBpbnRvIFdlYkFkbWluIGhvc3QgcGFn ZSB3aXRoaW4NCjxpPnBsdWdpbkRlZmluaXRpb25zPC9pPiBvYmplY3QsIGFuZCByZWFkIGJ5IDxp PlBsdWdpbk1hbmFnZXI8L2k+IGR1cmluZyBXZWJBZG1pbiBzdGFydHVwLjxicj4NCjxpPjxicj4N ClBsdWdpbiBjb25maWd1cmF0aW9uPC9pPiBpcyB0aGUgSlNPTiBmaWxlIHRoYXQgY29udGFpbnMg PHN0cm9uZz5vcHRpb25hbDwvc3Ryb25nPiBwbHVnaW4gY29uZmlndXJhdGlvbiwgZS5nLg0KPGk+ L2V0Yy9vdmlydC1lbmdpbmUvdWktcGx1Z2lucy90ZXN0LWNvbmZpZy5qc29uPC9pPjxicj4NCjxp Pjxicj4NCjwvaT5JIHRoaW5rIHdlIGNhbiBjb21iaW5lIHR3byB0aGluZ3MgaGVyZTo8YnI+DQox KSBhbGxvdyBwbHVnaW4gYXV0aG9ycyB0byBkZWZpbmUgc3RhbmRhcmQgKGZhbGxiYWNrKSBjb25m aWd1cmF0aW9uIGRpcmVjdGx5IGluc2lkZSBwbHVnaW4gZGVzY3JpcHRvcjxicj4NCjIpIGFsbG93 IHBsdWdpbiB1c2VycyB0byBvdmVycmlkZSBzdGFuZGFyZCBjb25maWd1cmF0aW9uIGJ5IG1vZGlm eWluZyBkZWRpY2F0ZWQgcGx1Z2luIGNvbmZpZ3VyYXRpb24gZmlsZTxicj4NCjxicj4NCkZpbmFs bHksIDxpPnBsdWdpbiBzb3VyY2UgcGFnZTwvaT4gaXMgdGhlIEhUTUwgcGFnZSB1c2VkIHRvIGlu dm9rZSBhY3R1YWwgcGx1Z2luIGNvZGUgKHRoaXMgcGFnZSBpcyByZWZlcmVuY2VkIGJ5IHBsdWdp biBkZXNjcmlwdG9yJ3MgJnF1b3Q7dXJsJnF1b3Q7IGF0dHJpYnV0ZSkuIFBsdWdpbiBzb3VyY2Ug cGFnZSBjYW4gYWxzbyBsb2FkIGV4dGVybmFsIHJlc291cmNlcyByZXF1aXJlZCBieSB0aGUgcGx1 Z2luLCBlLmcuIDNyZCBwYXJ0eSBKYXZhU2NyaXB0IGxpYnJhcmllcywNCiBDU1MsIGltYWdlcywg ZXRjLjxicj4NCjxicj4NCjwvc3Bhbj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjExLjBwdDtmb250 LWZhbWlseTomcXVvdDtDYWxpYnJpJnF1b3Q7LCZxdW90O3NhbnMtc2VyaWYmcXVvdDs7Y29sb3I6 IzFGNDk3RCI+Jmd0OyBJIGxpa2VkIHRoZSBvcmlnaW5hbCBJSUZFIGFwcHJvYWNoLCBleGNlcHQg dGhhdCBpdCBzZWVtZWQgdGhhdCBoYXZpbmcgYWRkaXRpb25hbCBzdGF0aWMgcmVzb3VyY2VzIChq cXVlcnksIGltYWdlcywgaHRtbCB0ZW1wbGF0ZXMsIGV0Yykgd2FzIGdvaW5nIHRvIGJlIG1vcmUg Y3VtYmVyc29tZS4mbmJzcDsNCiBJIGRvbuKAmXQgdGhpbmsgaGF2aW5nIHRoZSBwbHVnaW4gYXV0 aG9yIHdyaXRlIGEgYmFzaWMgc3RhcnQuaHRtbCBpcyB0aGF0IGJpZyBvZiBhIGJ1cmRlbiA6KS48 L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOmJsYWNrIj48YnI+DQo8YnI+DQpZb3UncmUgcmlnaHQs IGZvciBzdWNoIGFkZGl0aW9uYWwgcGx1Z2luIHJlc291cmNlcywgZXZlbiBtb3JlIGNvbmZpZ3Vy YXRpb24vcGFyc2luZy9sb2dpYyB3b3VsZCBiZSByZXF1aXJlZC4gRXZlbiB0aG91Z2ggcGx1Z2lu IGF1dGhvcnMgbmVlZCB0byB3cml0ZSB0aGUgcGx1Z2luIHNvdXJjZSBwYWdlIHRoZW1zZWx2ZXMs IHRoZXkgaGF2ZSBmdWxsIGNvbnRyb2wgb3ZlciBpdCwgd2hpY2ggaXMgYSBnb29kIHRoaW5nIGlu IGdlbmVyYWwuPGJyPg0KPGJyPg0KPC9zcGFuPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTEuMHB0 O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGlicmkmcXVvdDssJnF1b3Q7c2Fucy1zZXJpZiZxdW90Oztj b2xvcjojMUY0OTdEIj4mZ3Q7IEkgYWdyZWUgdGhhdCB0aGUgcGx1Z2luIGNvbmZpZ3VyYXRpb24g d2FzIGFsd2F5cyBnb2luZyB0byBiZSBhIHJlc291cmNlIChwcm9iYWJseSBhIGxvY2FsIGZpbGUp IHRoYXQgdGhlIGVuZCB1c2VyIGNvdWxkIGN1c3RvbWl6ZS4mbmJzcDsgSeKAmW0gbm90IHN1cmUg aXQgSSByZWFsbHkgbmVlZHMgdG8gYmUNCiBzZXBhcmF0ZSBmcm9tIHRoZSBwbHVnaW4gZGVmaW5p dGlvbiBmaWxlICgvdXNyL3NoYXJlL292aXJ0LWVuZ2luZS91aS1wbHVnaW5zL3Rlc3QuanNvbiku Jm5ic3A7IEkgc3VwcG9zZSBpdCBkZXBlbmRzIG9uIGhvdyBjb21wbGV4IHRoZSBjb25maWd1cmF0 aW9uIGlzIGdvaW5nIHRvIGJlIGFuZCBvbiBzb21lIG9mIHRoZSBpbXBsZW1lbnRhdGlvbiBkZXRh aWxzIHN1cnJvdW5kaW5nIHRoZSBwbHVnaW4gZGVmaW5pdGlvbiBmaWxlLjwvc3Bhbj48c3BhbiBz dHlsZT0iY29sb3I6YmxhY2siPjxicj4NCjxicj4NClllYWgsIGxldCdzIG1ha2UgdGhlIGNvbmNl cHQgb2YgdGhlIHBsdWdpbiBjb25maWd1cmF0aW9uIGZpbGUgb3B0aW9uYWwgZm9yIG5vdyAoc3Rh bmRhcmQgcGx1Z2luIGNvbmZpZ3VyYXRpb24gY2FuIGJlIHBhcnQgb2YgcGx1Z2luIGRlc2NyaXB0 b3IpLjxicj4NCjxicj4NCjwvc3Bhbj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjExLjBwdDtmb250 LWZhbWlseTomcXVvdDtDYWxpYnJpJnF1b3Q7LCZxdW90O3NhbnMtc2VyaWYmcXVvdDs7Y29sb3I6 IzFGNDk3RCI+Jmd0OyBJbiBteSBwYXRjaCwgSSBzaW1wbHkgdXNlZCBKYWNrc29uIHRvIHBhcnNl IHRoZSBmaWxlIGludG8gYSB0cmVlIG9mIEpzb25Ob2Rlcy4gJm5ic3A7U2hvdWxkIHRoZSBwbHVn aW4gZGVmaW5pdGlvbiBiZSBhIGphdmEgb2JqZWN0IG9mIHNvbWUgc29ydD8gKHBsZWFzZSBwbGVh c2UgcGxlYXNlIGRvbuKAmXQNCiBtYWtlIG1lIGxlYXJuIGFib3V0IGphdmEgYmVhbnPigKYpLiZu YnNwOyBJIHN0dWNrIHdpdGggdGhlIEpzb25Ob2RlcyBiZWNhdXNlIEphY2tzb24gbWFrZXMgdGhl bSBlYXN5IHRvIHdvcmsgd2l0aCBhbmQgdGhleeKAmXJlIHJlYWxseSBlYXN5IHRvIHJlLXNlcmlh bGl6ZSBiYWNrIHRvIGpzb24gdG8gZ2l2ZSB0byB0aGUgd2ViYWRtaW4uPC9zcGFuPjxzcGFuIHN0 eWxlPSJjb2xvcjpibGFjayI+PGJyPg0KPGJyPg0KSSB0aGluayB1c2luZyBKYWNrc29uJ3MgSlNP TiByZXByZXNlbnRhdGlvbiBpbiBKYXZhIChKc29uTm9kZSkgaXMgcGVyZmVjdGx5IHN1aXRhYmxl IGluIHRoaXMgc2l0dWF0aW9uLiBObyBuZWVkIHRvIGhhdmUgc2VwYXJhdGUgSmF2YSBiZWFuIGZv ciB0aGF0IDopPGJyPg0KPGJyPg0KPC9zcGFuPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTEuMHB0 O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGlicmkmcXVvdDssJnF1b3Q7c2Fucy1zZXJpZiZxdW90Oztj b2xvcjojMUY0OTdEIj4mZ3Q7IFdlIHNob3VsZCBwcm9iYWJseSB0dXJuIG9uIEpzb25QYXJzZXIu RmVhdHVyZS5BTExPV19DT01NRU5UUy4mbmJzcDsgVGhlIGRlZmluaXRpb24gYW5kIGNvbmZpZyBm aWxlcyB3aWxsIGRpZmZpY3VsdCBmb3IgZW5kLXVzZXJzIChvciBldmVuIGRldmVsb3BlcnMpIHRv IHVuZGVyc3RhbmQgd2l0aG91dCBjb21tZW50cy48L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOmJs YWNrIj48YnI+DQo8YnI+DQpBZ3JlZWQuPGJyPg0KPGJyPg0KPC9zcGFuPjxzcGFuIHN0eWxlPSJm b250LXNpemU6MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGlicmkmcXVvdDssJnF1b3Q7c2Fu cy1zZXJpZiZxdW90Oztjb2xvcjojMUY0OTdEIj4mZ3Q7IFdlIG5lZWQgdG8gZm9ybWFsaXplIHRo ZSBzdHJ1Y3R1cmUgb2YgdGhlIHBsdWdpbiBkZWZpbml0aW9uIGFuZCBkZWNpZGUgd2hpY2ggZmll bGRzIGFyZSBtYW5kYXRvcnkgYW5kIHdoaWNoIGFyZSBvcHRpb25hbDwvc3Bhbj48c3BhbiBzdHls ZT0iY29sb3I6YmxhY2siPjxicj4NCjxicj4NClNvdW5kcyBnb29kLCBidXQgSSdkIHNraXAgc29t ZSBhdHRyaWJ1dGVzIGZvciBub3cgKGVuYWJsZWQsIGFwaVZlcnNpb24sIGF1dGhvciwgbGljZW5z ZSkgZm9yIHRoZSBzYWtlIG9mIHNpbXBsaWNpdHkuPGJyPg0KPGJyPg0KQXMgeW91IHdyb3RlLCB3 aGVuIGxvYWRpbmcgcGx1Z2luIGRlc2NyaXB0b3IsIHdlIHNob3VsZCBlbmZvcmNlIG1hbmRhdG9y eSBhdHRyaWJ1dGVzIChuYW1lLCB2ZXJzaW9uLCB1cmwpLjxicj4NCjxicj4NCkFzIGZvciBwbHVn aW4gY29uZmlndXJhdGlvbiwgdGhlcmUgY291bGQgYmUgdHdvIGRpZmZlcmVudCBhdHRyaWJ1dGVz Ojxicj4NCi0gJnF1b3Q7Y29uZmlnJnF1b3Q7IGZvciBzdGFuZGFyZCAoZmFsbGJhY2spIHBsdWdp biBjb25maWd1cmF0aW9uIChKU09OIG9iamVjdCk8YnI+DQotICZxdW90O2NvbmZpZ0ZpbGUmcXVv dDsgZm9yIGV4dGVybmFsIHBsdWdpbiBjb25maWd1cmF0aW9uIGZpbGUgKHBhdGggdG8gZmlsZSwg cmVsYXRpdmUgdG8gL2V0Yy9vdmlydC1lbmdpbmUvdWktcGx1Z2lucy8pLCB0aGF0IG92ZXJyaWRl cyB0aGUgc3RhbmRhcmQgY29uZmlndXJhdGlvbjxicj4NCjxicj4NCk5vdGUgdGhhdCB3aGVuIGxv YWRpbmcgcGx1Z2luIGRlc2NyaXB0b3IsIHRoZSBsb2FkZXIgc2hvdWxkIGFsc28gJnF1b3Q7bWVy Z2UmcXVvdDsgdGhlIGNvbmZpZ3VyYXRpb24gdG9nZXRoZXIgKGN1c3RvbSBjb25maWcgb24gdG9w IG9mIHN0YW5kYXJkIGNvbmZpZykuPGJyPg0KPGJyPg0KPC9zcGFuPjxzcGFuIHN0eWxlPSJmb250 LXNpemU6MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGlicmkmcXVvdDssJnF1b3Q7c2Fucy1z ZXJpZiZxdW90Oztjb2xvcjojMUY0OTdEIj4mZ3Q7IEkgY2FuIHdvcmsgb24gdGhlIHBsdWdpbiBE ZWZpbml0aW9uIGxvYWRlciBzb21lIG1vcmUgYW5kIG1ha2UgaXQgZW5mb3JjZSBtYW5kYXRvcnkv b3B0aW9uYWwgZmllbGRzLiAmbmJzcDtJ4oCZbGwgYWxzbyBpbnZlc3RpZ2F0ZSB0aGUgZGlyZWN0 b3J5IGNsaW1iaW5nIGlzc3VlIEkgbWVudGlvbmVkIGluIG15DQogcHJldmlvdXMgbWFpbC48L3Nw YW4+PHNwYW4gc3R5bGU9ImNvbG9yOmJsYWNrIj48YnI+DQo8YnI+DQpTb3VuZHMgZ29vZCEgSSB3 YXMgcGxhbm5pbmcgdG8gaW5jb3Jwb3JhdGUgeW91ciBvcmlnaW5hbCBwYXRjaCBpbiBuZXh0IFBv QyByZXZpc2lvbiwgYnV0IG9mIGNvdXJzZSwgeW91IGNhbiB3b3JrIG9uIHRoZSBsb2FkZXIgc29t ZSBtb3JlIGFuZCBzZW5kIGFub3RoZXIgcGF0Y2ggOik8YnI+DQo8YnI+DQpGb3IgdGhlIGRpcmVj dG9yeSBjbGltYmluZyBpc3N1ZSwgc2VlIDxpPiZsdDtPVklSVF9ST09UJmd0Oy9iYWNrZW5kL21h bmFnZXIvbW9kdWxlcy9yb290L3NyYy9tYWluL2phdmEvb3JnL292aXJ0L2VuZ2luZS9jb3JlL0Zp bGVTZXJ2bGV0LmphdmE8L2k+ICh0aGVyZSdzIGEgbWV0aG9kIGNhbGxlZCBpc1NhbmUgZm9yIGRl YWxpbmcgd2l0aCBzdWNoIGlzc3VlKS48YnI+DQo8YnI+DQo8L3NwYW4+PHNwYW4gc3R5bGU9ImZv bnQtc2l6ZToxMS4wcHQ7Zm9udC1mYW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90OywmcXVvdDtzYW5z LXNlcmlmJnF1b3Q7O2NvbG9yOiMxRjQ5N0QiPiZndDsgQWxzbywgSeKAmW0gY3VyaW91cyBob3cg dGhpbmdzIGFyZSBnb2luZyB0byB3b3JrIHdoZW4gdGhlIOKAnHVybOKAnSBwb2ludHMgdG8gYSBm b3JlaWduIHJlc291cmNlIGFzIHRoZSBwbHVnaW4gc3RhcnQgcGFnZS4mbmJzcDsgSSBkb27igJl0 IHRoaW5rIHRoZSBwbHVnaW7igJlzIGlmcmFtZSBpcyBnb2luZyB0byBiZSBhYmxlDQogdG8gYWNj ZXNzIHBhcmVudC5wbHVnaW5BcGkuJm5ic3A7IFBlcmhhcHMgdGhlcmUgaXMgc29tZSBhc3BlY3Qg b2YgQ09SUyB0aGF0IEkgZG9u4oCZdCB1bmRlcnN0YW5kPzwvc3Bhbj48c3BhbiBzdHlsZT0iY29s b3I6YmxhY2siPjxicj4NCjxicj4NCldoZW4gdGhlIHBsdWdpbiBpZnJhbWUgcmVmZXJlbmNlcyBh IHJlc291cmNlIG9uIGRpZmZlcmVudCBvcmlnaW4gKHByb3RvY29sLCBkb21haW4sIHBvcnQpIHRo YW4gV2ViQWRtaW4gbWFpbiBwYWdlIG9yaWdpbiwgSmF2YVNjcmlwdCBjb2RlIHJ1bm5pbmcgaW5z aWRlIHRoYXQgaWZyYW1lIHdpbGwgbm90IGJlIGFibGUgdG8gYWNjZXNzIHBhcmVudCAodG9wLWxl dmVsKQ0KPGk+cGx1Z2luQXBpPC9pPiBvYmplY3QuIFlvdSdyZSByaWdodCwgdGhlIHN0YXRlbWVu dCAmcXVvdDtwYXJlbnQucGx1Z2luQXBpJnF1b3Q7IHdpbGwgbm90IHdvcmssIGJlY2F1c2Ugb2Yg U2FtZS1PcmlnaW4gUG9saWN5IGVuZm9yY2VkIGJ5IHRoZSBicm93c2VyLjxicj4NCjxicj4NCkNP UlMgaXMganVzdCBvbmUgYWx0ZXJuYXRpdmUsIHNlZSA8YSBocmVmPSJodHRwOi8vc3RhY2tvdmVy Zmxvdy5jb20vcXVlc3Rpb25zLzMwNzY0MTQvd2F5cy10by1jaXJjdW12ZW50LXRoZS1zYW1lLW9y aWdpbi1wb2xpY3kiPg0KaHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy8zMDc2NDE0 L3dheXMtdG8tY2lyY3VtdmVudC10aGUtc2FtZS1vcmlnaW4tcG9saWN5PC9hPiBmb3IgbW9yZS4g SG93ZXZlciwgQ09SUyBuZWVkcyB0byBiZSBzdXBwb3J0ZWQgYnkgdGhlIGJyb3dzZXIgKGEgc3Bl Y2lhbCBIVFRQIHJlc3BvbnNlIGhlYWRlciBpcyB1c2VkIHRvIHRlbGwgdGhhdCB0aGUgaWZyYW1l IGlzIGFsbG93ZWQgdG8gYWNjZXNzIHJlc291cmNlcyBmcm9tIGFub3RoZXINCiAtIFdlYkFkbWlu IG1haW4gcGFnZSAtIG9yaWdpbikuIFdlIG5lZWQgdG8gaW52ZXN0aWdhdGUgdGhpcyBhIGJpdCBt b3JlIEkgZ3Vlc3MuPGJyPg0KPGJyPg0KUmVnYXJkcyw8YnI+DQpWb2p0ZWNoPGJyPg0KPGJyPg0K PG86cD48L286cD48L3NwYW4+PC9wPg0KPGRpdiBjbGFzcz0iTXNvTm9ybWFsIiBhbGlnbj0iY2Vu dGVyIiBzdHlsZT0idGV4dC1hbGlnbjpjZW50ZXIiPjxzcGFuIHN0eWxlPSJjb2xvcjpibGFjayI+ DQo8aHIgc2l6ZT0iMiIgd2lkdGg9IjEwMCUiIGFsaWduPSJjZW50ZXIiIGlkPSJ6d2NociI+DQo8 L3NwYW4+PC9kaXY+DQo8ZGl2Pg0KPHAgY2xhc3M9Ik1zb05vcm1hbCIgc3R5bGU9Im1hcmdpbi1i b3R0b206MTIuMHB0Ij48Yj48c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6JnF1b3Q7SGVsdmV0aWNh JnF1b3Q7LCZxdW90O3NhbnMtc2VyaWYmcXVvdDs7Y29sb3I6YmxhY2siPkZyb206DQo8L3NwYW4+ PC9iPjxzcGFuIHN0eWxlPSJmb250LWZhbWlseTomcXVvdDtIZWx2ZXRpY2EmcXVvdDssJnF1b3Q7 c2Fucy1zZXJpZiZxdW90Oztjb2xvcjpibGFjayI+JnF1b3Q7Q2hyaXMgRnJhbnR6JnF1b3Q7ICZs dDs8YSBocmVmPSJtYWlsdG86Q2hyaXMuRnJhbnR6QGhwLmNvbSI+Q2hyaXMuRnJhbnR6QGhwLmNv bTwvYT4mZ3Q7PGJyPg0KPGI+VG86IDwvYj4mcXVvdDtWb2p0ZWNoIFN6b2NzJnF1b3Q7ICZsdDs8 YSBocmVmPSJtYWlsdG86dnN6b2NzQHJlZGhhdC5jb20iPnZzem9jc0ByZWRoYXQuY29tPC9hPiZn dDs8YnI+DQo8Yj5DYzogPC9iPiZxdW90O2VuZ2luZS1kZXZlbCZxdW90OyAmbHQ7PGEgaHJlZj0i bWFpbHRvOmVuZ2luZS1kZXZlbEBvdmlydC5vcmciPmVuZ2luZS1kZXZlbEBvdmlydC5vcmc8L2E+ Jmd0Ozxicj4NCjxiPlNlbnQ6IDwvYj5UaHVyc2RheSwgQXVndXN0IDIzLCAyMDEyIDU6MTI6MDIg UE08YnI+DQo8Yj5TdWJqZWN0OiA8L2I+UkU6IFVJIFBsdWdpbnMgY29uZmlndXJhdGlvbjxvOnA+ PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFuIHN0eWxlPSJmb250 LXNpemU6MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGlicmkmcXVvdDssJnF1b3Q7c2Fucy1z ZXJpZiZxdW90Oztjb2xvcjojMUY0OTdEIj5Wb2p0ZWNoLDwvc3Bhbj48c3BhbiBzdHlsZT0iY29s b3I6YmxhY2siPjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxz cGFuIHN0eWxlPSJmb250LXNpemU6MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGlicmkmcXVv dDssJnF1b3Q7c2Fucy1zZXJpZiZxdW90Oztjb2xvcjojMUY0OTdEIj4mbmJzcDs8L3NwYW4+PHNw YW4gc3R5bGU9ImNvbG9yOmJsYWNrIj48bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQo8cCBjbGFzcz0i TXNvTm9ybWFsIj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjExLjBwdDtmb250LWZhbWlseTomcXVv dDtDYWxpYnJpJnF1b3Q7LCZxdW90O3NhbnMtc2VyaWYmcXVvdDs7Y29sb3I6IzFGNDk3RCI+WW91 ciBhc3N1bXB0aW9uIGFib3V0IHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIHBsdWdpbkRlZmluaXRpb25z IG9iamVjdCBpcyBjb3JyZWN0LiZuYnNwOyBJdOKAmXMgbm8gbG9uZ2VyIGEgU3RyaW5nLSZndDtT dHJpbmcgbWFwcGluZyAsIGJ1dCBhIFN0cmluZyB0byBPYmplY3QgbWFwcGluZy48L3NwYW4+PHNw YW4gc3R5bGU9ImNvbG9yOmJsYWNrIj48bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQo8cCBjbGFzcz0i TXNvTm9ybWFsIj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjExLjBwdDtmb250LWZhbWlseTomcXVv dDtDYWxpYnJpJnF1b3Q7LCZxdW90O3NhbnMtc2VyaWYmcXVvdDs7Y29sb3I6IzFGNDk3RCI+Jm5i c3A7PC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjpibGFjayI+PG86cD48L286cD48L3NwYW4+PC9w Pg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7Zm9u dC1mYW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90OywmcXVvdDtzYW5zLXNlcmlmJnF1b3Q7O2NvbG9y OiMxRjQ5N0QiPkkgbGlrZWQgdGhlIG9yaWdpbmFsIElJRkUgYXBwcm9hY2gsIGV4Y2VwdCB0aGF0 IGl0IHNlZW1lZCB0aGF0IGhhdmluZyBhZGRpdGlvbmFsIHN0YXRpYyByZXNvdXJjZXMgKGpxdWVy eSwgaW1hZ2VzLCBodG1sIHRlbXBsYXRlcywgZXRjKSB3YXMgZ29pbmcgdG8gYmUgbW9yZQ0KIGN1 bWJlcnNvbWUuJm5ic3A7IEkgZG9u4oCZdCB0aGluayBoYXZpbmcgdGhlIHBsdWdpbiBhdXRob3Ig d3JpdGUgYSBiYXNpYyBzdGFydC5odG1sIGlzIHRoYXQgYmlnIG9mIGEgYnVyZGVuIDopLjwvc3Bh bj48c3BhbiBzdHlsZT0iY29sb3I6YmxhY2siPjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNs YXNzPSJNc29Ob3JtYWwiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTEuMHB0O2ZvbnQtZmFtaWx5 OiZxdW90O0NhbGlicmkmcXVvdDssJnF1b3Q7c2Fucy1zZXJpZiZxdW90Oztjb2xvcjojMUY0OTdE Ij4mbmJzcDs8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOmJsYWNrIj48bzpwPjwvbzpwPjwvc3Bh bj48L3A+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjExLjBw dDtmb250LWZhbWlseTomcXVvdDtDYWxpYnJpJnF1b3Q7LCZxdW90O3NhbnMtc2VyaWYmcXVvdDs7 Y29sb3I6IzFGNDk3RCI+SSBhZ3JlZSB0aGF0IHRoZSBwbHVnaW4gY29uZmlndXJhdGlvbiB3YXMg YWx3YXlzIGdvaW5nIHRvIGJlIGEgcmVzb3VyY2UgKHByb2JhYmx5IGEgbG9jYWwgZmlsZSkgdGhh dCB0aGUgZW5kIHVzZXIgY291bGQgY3VzdG9taXplLiZuYnNwOyBJ4oCZbSBub3Qgc3VyZSBpdCBJ IHJlYWxseQ0KIG5lZWRzIHRvIGJlIHNlcGFyYXRlIGZyb20gdGhlIHBsdWdpbiBkZWZpbml0aW9u IGZpbGUgKC91c3Ivc2hhcmUvb3ZpcnQtZW5naW5lL3VpLXBsdWdpbnMvdGVzdC5qc29uKS4mbmJz cDsgSSBzdXBwb3NlIGl0IGRlcGVuZHMgb24gaG93IGNvbXBsZXggdGhlIGNvbmZpZ3VyYXRpb24g aXMgZ29pbmcgdG8gYmUgYW5kIG9uIHNvbWUgb2YgdGhlIGltcGxlbWVudGF0aW9uIGRldGFpbHMg c3Vycm91bmRpbmcgdGhlIHBsdWdpbiBkZWZpbml0aW9uIGZpbGUuPC9zcGFuPjxzcGFuIHN0eWxl PSJjb2xvcjpibGFjayI+PG86cD48L286cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1h bCI+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7Zm9udC1mYW1pbHk6JnF1b3Q7Q2FsaWJy aSZxdW90OywmcXVvdDtzYW5zLXNlcmlmJnF1b3Q7O2NvbG9yOiMxRjQ5N0QiPiZuYnNwOzwvc3Bh bj48c3BhbiBzdHlsZT0iY29sb3I6YmxhY2siPjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNs YXNzPSJNc29Ob3JtYWwiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTEuMHB0O2ZvbnQtZmFtaWx5 OiZxdW90O0NhbGlicmkmcXVvdDssJnF1b3Q7c2Fucy1zZXJpZiZxdW90Oztjb2xvcjojMUY0OTdE Ij5JbiBteSBwYXRjaCwgSSBzaW1wbHkgdXNlZCBKYWNrc29uIHRvIHBhcnNlIHRoZSBmaWxlIGlu dG8gYSB0cmVlIG9mIEpzb25Ob2Rlcy4gJm5ic3A7U2hvdWxkIHRoZSBwbHVnaW4gZGVmaW5pdGlv biBiZSBhIGphdmEgb2JqZWN0IG9mIHNvbWUgc29ydD8gKHBsZWFzZSBwbGVhc2UgcGxlYXNlDQog ZG9u4oCZdCBtYWtlIG1lIGxlYXJuIGFib3V0IGphdmEgYmVhbnPigKYpLiZuYnNwOyBJIHN0dWNr IHdpdGggdGhlIEpzb25Ob2RlcyBiZWNhdXNlIEphY2tzb24gbWFrZXMgdGhlbSBlYXN5IHRvIHdv cmsgd2l0aCBhbmQgdGhleeKAmXJlIHJlYWxseSBlYXN5IHRvIHJlLXNlcmlhbGl6ZSBiYWNrIHRv IGpzb24gdG8gZ2l2ZSB0byB0aGUgd2ViYWRtaW4uPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjpi bGFjayI+PG86cD48L286cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNwYW4g c3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7Zm9udC1mYW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90Oywm cXVvdDtzYW5zLXNlcmlmJnF1b3Q7O2NvbG9yOiMxRjQ5N0QiPiZuYnNwOzwvc3Bhbj48c3BhbiBz dHlsZT0iY29sb3I6YmxhY2siPjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29O b3JtYWwiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O0Nh bGlicmkmcXVvdDssJnF1b3Q7c2Fucy1zZXJpZiZxdW90Oztjb2xvcjojMUY0OTdEIj5XZSBzaG91 bGQgcHJvYmFibHkgdHVybiBvbiBKc29uUGFyc2VyLkZlYXR1cmUuQUxMT1dfQ09NTUVOVFMuJm5i c3A7IFRoZSBkZWZpbml0aW9uIGFuZCBjb25maWcgZmlsZXMgd2lsbCBkaWZmaWN1bHQgZm9yIGVu ZC11c2VycyAob3IgZXZlbiBkZXZlbG9wZXJzKSB0byB1bmRlcnN0YW5kDQogd2l0aG91dCBjb21t ZW50cy48L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOmJsYWNrIj48bzpwPjwvbzpwPjwvc3Bhbj48 L3A+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjExLjBwdDtm b250LWZhbWlseTomcXVvdDtDYWxpYnJpJnF1b3Q7LCZxdW90O3NhbnMtc2VyaWYmcXVvdDs7Y29s b3I6IzFGNDk3RCI+Jm5ic3A7PC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjpibGFjayI+PG86cD48 L286cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNwYW4gc3R5bGU9ImZvbnQt c2l6ZToxMS4wcHQ7Zm9udC1mYW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90OywmcXVvdDtzYW5zLXNl cmlmJnF1b3Q7O2NvbG9yOiMxRjQ5N0QiPldlIG5lZWQgdG8gZm9ybWFsaXplIHRoZSBzdHJ1Y3R1 cmUgb2YgdGhlIHBsdWdpbiBkZWZpbml0aW9uIGFuZCBkZWNpZGUgd2hpY2ggZmllbGRzIGFyZSBt YW5kYXRvcnkgYW5kIHdoaWNoIGFyZSBvcHRpb25hbDo8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9y OmJsYWNrIj48bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48c3Bh biBzdHlsZT0iZm9udC1zaXplOjExLjBwdDtmb250LWZhbWlseTomcXVvdDtDYWxpYnJpJnF1b3Q7 LCZxdW90O3NhbnMtc2VyaWYmcXVvdDs7Y29sb3I6IzFGNDk3RCI+Jm5ic3A7PC9zcGFuPjxzcGFu IHN0eWxlPSJjb2xvcjpibGFjayI+PG86cD48L286cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1z b05vcm1hbCI+PHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiZxdW90O0NvdXJpZXIgTmV3JnF1b3Q7 O2NvbG9yOmJsYWNrIj57PC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjpibGFjayI+PG86cD48L286 cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNwYW4gc3R5bGU9ImZvbnQtZmFt aWx5OiZxdW90O0NvdXJpZXIgTmV3JnF1b3Q7O2NvbG9yOmJsYWNrIj4mbmJzcDsgIyBNYW5kYXRv cnkgZmllbGRzOiBuYW1lLCBlbmFibGVkLCB2ZXJzaW9uLCB1cmwsIGFwaXZlcnNpb24sIGF1dGhv ciwgbGljZW5zZTxicj4NCiZuYnNwOyAjIE5hbWUgb2YgdGhlIHBsdWdpbiZuYnNwOyA8L3NwYW4+ PHNwYW4gc3R5bGU9ImNvbG9yOmJsYWNrIj48bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQo8cCBjbGFz cz0iTXNvTm9ybWFsIiBzdHlsZT0ibWFyZ2luLWJvdHRvbToxMi4wcHQiPjxzcGFuIHN0eWxlPSJm b250LWZhbWlseTomcXVvdDtDb3VyaWVyIE5ldyZxdW90Oztjb2xvcjpibGFjayI+Jm5ic3A7Jm5i c3A7JnF1b3Q7bmFtZSZxdW90OzogJnF1b3Q7dGVzdCZxdW90Oyw8L3NwYW4+PHNwYW4gc3R5bGU9 ImNvbG9yOmJsYWNrIj48bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQo8cCBjbGFzcz0iTXNvTm9ybWFs Ij48c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6JnF1b3Q7Q291cmllciBOZXcmcXVvdDs7Y29sb3I6 YmxhY2siPiZuYnNwOyAjIFdoZXRoZXIgb3Igbm90IHBsdWdpbiBpcyBlbmFiZWQ8L3NwYW4+PHNw YW4gc3R5bGU9ImNvbG9yOmJsYWNrIj48bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQo8cCBjbGFzcz0i TXNvTm9ybWFsIiBzdHlsZT0ibWFyZ2luLWJvdHRvbToxMi4wcHQiPjxzcGFuIHN0eWxlPSJmb250 LWZhbWlseTomcXVvdDtDb3VyaWVyIE5ldyZxdW90Oztjb2xvcjpibGFjayI+Jm5ic3A7Jm5ic3A7 JnF1b3Q7ZW5hYmxlZCZxdW90OzogdHJ1ZSw8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOmJsYWNr Ij48bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48c3BhbiBzdHls ZT0iZm9udC1mYW1pbHk6JnF1b3Q7Q291cmllciBOZXcmcXVvdDs7Y29sb3I6YmxhY2siPiZuYnNw OyAjIHZlcnNpb24gb2YgdGhlIHBsdWdpbjwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6YmxhY2si PjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiIHN0eWxlPSJtYXJn aW4tYm90dG9tOjEyLjBwdCI+PHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiZxdW90O0NvdXJpZXIg TmV3JnF1b3Q7O2NvbG9yOmJsYWNrIj4mbmJzcDsmbmJzcDsmcXVvdDt2ZXJzaW9uJnF1b3Q7OiAm cXVvdDsxLjAmcXVvdDssPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjpibGFjayI+PG86cD48L286 cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNwYW4gc3R5bGU9ImZvbnQtZmFt aWx5OiZxdW90O0NvdXJpZXIgTmV3JnF1b3Q7O2NvbG9yOmJsYWNrIj4mbmJzcDsgIyBIb3cgdG8g bG9hZCB0aGUgcGx1Z2luPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjpibGFjayI+PG86cD48L286 cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCIgc3R5bGU9Im1hcmdpbi1ib3R0b206 MTIuMHB0Ij48c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6JnF1b3Q7Q291cmllciBOZXcmcXVvdDs7 Y29sb3I6YmxhY2siPiZuYnNwOyZuYnNwOyZxdW90O3VybCZxdW90OzogJnF1b3Q7L3dlYmFkbWlu L3dlYmFkbWluL3BsdWdpbi90ZXN0L3N0YXJ0Lmh0bWwmcXVvdDssPC9zcGFuPjxzcGFuIHN0eWxl PSJjb2xvcjpibGFjayI+PG86cD48L286cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1h bCI+PHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiZxdW90O0NvdXJpZXIgTmV3JnF1b3Q7O2NvbG9y OmJsYWNrIj4mbmJzcDsgIyBXaGljaCB2ZXJzaW9uIG9mIGVuZ2luZSBwbHVnaW4gaXMgbWVhbnQg dG8gd29yayB3aXRoPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjpibGFjayI+PG86cD48L286cD48 L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCIgc3R5bGU9Im1hcmdpbi1ib3R0b206MTIu MHB0Ij48c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6JnF1b3Q7Q291cmllciBOZXcmcXVvdDs7Y29s b3I6YmxhY2siPiZuYnNwOyZuYnNwOyZxdW90O2FwaXZlcnNpb24mcXVvdDs6ICZxdW90OzMuMS4w JnF1b3Q7LDwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6YmxhY2siPjxvOnA+PC9vOnA+PC9zcGFu PjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFuIHN0eWxlPSJmb250LWZhbWlseTomcXVv dDtDb3VyaWVyIE5ldyZxdW90Oztjb2xvcjpibGFjayI+Jm5ic3A7ICMgV2hvIHdyb3RlIHRoZSBw bHVnaW4gYW5kIGhvdyBpcyBpdCBsaWNlbnNlZD88L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOmJs YWNrIj48bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIiBzdHlsZT0i bWFyZ2luLWJvdHRvbToxMi4wcHQiPjxzcGFuIHN0eWxlPSJmb250LWZhbWlseTomcXVvdDtDb3Vy aWVyIE5ldyZxdW90Oztjb2xvcjpibGFjayI+Jm5ic3A7ICZxdW90O2F1dGhvciZxdW90OzogJnF1 b3Q7U3VwZXJCaWcgQ29ycG9yYXRpb24mcXVvdDssPGJyPg0KJm5ic3A7ICZxdW90O2xpY2Vuc2Um cXVvdDs6ICZxdW90O1Byb3ByaWV0YXJ5JnF1b3Q7LDwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6 YmxhY2siPjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFu IHN0eWxlPSJmb250LWZhbWlseTomcXVvdDtDb3VyaWVyIE5ldyZxdW90Oztjb2xvcjpibGFjayI+ Jm5ic3A7ICMgT3B0aW9uYWwgZmllbGRzIHBhdGgsIGNvbmZpZzwvc3Bhbj48c3BhbiBzdHlsZT0i Y29sb3I6YmxhY2siPjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwi PjxzcGFuIHN0eWxlPSJmb250LWZhbWlseTomcXVvdDtDb3VyaWVyIE5ldyZxdW90Oztjb2xvcjpi bGFjayI+Jm5ic3A7ICMgV2hlcmUgdG8gbG9jYXRlIHBsdWdpbiAoaWYgbG9hZGVkIGJ5IHdlYmFk bWluL3BsdWdpbik8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOmJsYWNrIj48bzpwPjwvbzpwPjwv c3Bhbj48L3A+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6 JnF1b3Q7Q291cmllciBOZXcmcXVvdDs7Y29sb3I6YmxhY2siPiZuYnNwOyZuYnNwOyZxdW90O3Bh dGgmcXVvdDs6ICZxdW90Oy90bXAmcXVvdDssPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjpibGFj ayI+PG86cD48L286cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNwYW4gc3R5 bGU9ImZvbnQtZmFtaWx5OiZxdW90O0NvdXJpZXIgTmV3JnF1b3Q7O2NvbG9yOmJsYWNrIj4mbmJz cDs8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOmJsYWNrIj48bzpwPjwvbzpwPjwvc3Bhbj48L3A+ DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6JnF1b3Q7Q291 cmllciBOZXcmcXVvdDs7Y29sb3I6YmxhY2siPiZuYnNwOyAjIFBsdWdpbiBjb25maWd1cmF0aW9u IGluZm9ybWF0aW9uIChpZiBhbnkpPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjpibGFjayI+PG86 cD48L286cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNwYW4gc3R5bGU9ImZv bnQtZmFtaWx5OiZxdW90O0NvdXJpZXIgTmV3JnF1b3Q7O2NvbG9yOmJsYWNrIj4mbmJzcDsmbmJz cDsmcXVvdDtjb25maWcmcXVvdDs6ICZxdW90O3Rlc3QtY29uZmlnLmpzb24mcXVvdDssPGJyPg0K fTwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6YmxhY2siPjxicj4NCjwvc3Bhbj48c3BhbiBzdHls ZT0iZm9udC1zaXplOjExLjBwdDtmb250LWZhbWlseTomcXVvdDtDb3VyaWVyIE5ldyZxdW90Oztj b2xvcjojMUY0OTdEIj4mbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsNCjwvc3Bhbj48c3BhbiBzdHls ZT0iY29sb3I6YmxhY2siPjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3Jt YWwiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGli cmkmcXVvdDssJnF1b3Q7c2Fucy1zZXJpZiZxdW90Oztjb2xvcjojMUY0OTdEIj5JIGNhbiB3b3Jr IG9uIHRoZSBwbHVnaW4gRGVmaW5pdGlvbiBsb2FkZXIgc29tZSBtb3JlIGFuZCBtYWtlIGl0IGVu Zm9yY2UgbWFuZGF0b3J5L29wdGlvbmFsIGZpZWxkcy4gJm5ic3A7SeKAmWxsIGFsc28gaW52ZXN0 aWdhdGUgdGhlIGRpcmVjdG9yeSBjbGltYmluZyBpc3N1ZSBJIG1lbnRpb25lZA0KIGluIG15IHBy ZXZpb3VzIG1haWwuPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjpibGFjayI+PG86cD48L286cD48 L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZTox MS4wcHQ7Zm9udC1mYW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90OywmcXVvdDtzYW5zLXNlcmlmJnF1 b3Q7O2NvbG9yOiMxRjQ5N0QiPiZuYnNwOzwvc3Bhbj48c3BhbiBzdHlsZT0iY29sb3I6YmxhY2si PjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFuIHN0eWxl PSJmb250LXNpemU6MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGlicmkmcXVvdDssJnF1b3Q7 c2Fucy1zZXJpZiZxdW90Oztjb2xvcjojMUY0OTdEIj5BbHNvLCBJ4oCZbSBjdXJpb3VzIGhvdyB0 aGluZ3MgYXJlIGdvaW5nIHRvIHdvcmsgd2hlbiB0aGUg4oCcdXJs4oCdIHBvaW50cyB0byBhIGZv cmVpZ24gcmVzb3VyY2UgYXMgdGhlIHBsdWdpbiBzdGFydCBwYWdlLiZuYnNwOyBJIGRvbuKAmXQg dGhpbmsgdGhlIHBsdWdpbuKAmXMgaWZyYW1lIGlzIGdvaW5nDQogdG8gYmUgYWJsZSB0byBhY2Nl c3MgcGFyZW50LnBsdWdpbkFwaS4mbmJzcDsgUGVyaGFwcyB0aGVyZSBpcyBzb21lIGFzcGVjdCBv ZiBDT1JTIHRoYXQgSSBkb27igJl0IHVuZGVyc3RhbmQ/PC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xv cjpibGFjayI+PG86cD48L286cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNw YW4gc3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7Zm9udC1mYW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90 OywmcXVvdDtzYW5zLXNlcmlmJnF1b3Q7O2NvbG9yOiMxRjQ5N0QiPiZuYnNwOzwvc3Bhbj48c3Bh biBzdHlsZT0iY29sb3I6YmxhY2siPjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJN c29Ob3JtYWwiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90 O0NhbGlicmkmcXVvdDssJnF1b3Q7c2Fucy1zZXJpZiZxdW90Oztjb2xvcjojMUY0OTdEIj5UaGFu a3MsPC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjpibGFjayI+PG86cD48L286cD48L3NwYW4+PC9w Pg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7Zm9u dC1mYW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90OywmcXVvdDtzYW5zLXNlcmlmJnF1b3Q7O2NvbG9y OiMxRjQ5N0QiPi0tQ2hyaXM8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOmJsYWNrIj48bzpwPjwv bzpwPjwvc3Bhbj48L3A+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48c3BhbiBzdHlsZT0iZm9udC1z aXplOjExLjBwdDtmb250LWZhbWlseTomcXVvdDtDYWxpYnJpJnF1b3Q7LCZxdW90O3NhbnMtc2Vy aWYmcXVvdDs7Y29sb3I6IzFGNDk3RCI+Jm5ic3A7PC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjpi bGFjayI+PG86cD48L286cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNwYW4g c3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7Zm9udC1mYW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90Oywm cXVvdDtzYW5zLXNlcmlmJnF1b3Q7O2NvbG9yOiMxRjQ5N0QiPiZuYnNwOzwvc3Bhbj48c3BhbiBz dHlsZT0iY29sb3I6YmxhY2siPjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29O b3JtYWwiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O0Nh bGlicmkmcXVvdDssJnF1b3Q7c2Fucy1zZXJpZiZxdW90Oztjb2xvcjojMUY0OTdEIj4mbmJzcDs8 L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOmJsYWNrIj48bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQo8 ZGl2Pg0KPGRpdiBzdHlsZT0iYm9yZGVyOm5vbmU7Ym9yZGVyLXRvcDpzb2xpZCAjQjVDNERGIDEu MHB0O3BhZGRpbmc6My4wcHQgMGluIDBpbiAwaW4iPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PGI+ PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMC4wcHQ7Zm9udC1mYW1pbHk6JnF1b3Q7VGFob21hJnF1 b3Q7LCZxdW90O3NhbnMtc2VyaWYmcXVvdDs7Y29sb3I6YmxhY2siPkZyb206PC9zcGFuPjwvYj48 c3BhbiBzdHlsZT0iZm9udC1zaXplOjEwLjBwdDtmb250LWZhbWlseTomcXVvdDtUYWhvbWEmcXVv dDssJnF1b3Q7c2Fucy1zZXJpZiZxdW90Oztjb2xvcjpibGFjayI+IFZvanRlY2ggU3pvY3MgWzxh IGhyZWY9Im1haWx0bzp2c3pvY3NAcmVkaGF0LmNvbSI+bWFpbHRvOnZzem9jc0ByZWRoYXQuY29t PC9hPl0NCjxicj4NCjxiPlNlbnQ6PC9iPiBUaHVyc2RheSwgQXVndXN0IDIzLCAyMDEyIDc6MTQg QU08YnI+DQo8Yj5Ubzo8L2I+IEZyYW50eiwgQ2hyaXM8YnI+DQo8Yj5DYzo8L2I+IGVuZ2luZS1k ZXZlbDxicj4NCjxiPlN1YmplY3Q6PC9iPiBSZTogVUkgUGx1Z2lucyBjb25maWd1cmF0aW9uPC9z cGFuPjxzcGFuIHN0eWxlPSJjb2xvcjpibGFjayI+PG86cD48L286cD48L3NwYW4+PC9wPg0KPC9k aXY+DQo8L2Rpdj4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFuIHN0eWxlPSJjb2xvcjpibGFj ayI+Jm5ic3A7PG86cD48L286cD48L3NwYW4+PC9wPg0KPGRpdj4NCjxwIGNsYXNzPSJNc29Ob3Jt YWwiPjxzcGFuIHN0eWxlPSJjb2xvcjpibGFjayI+SGkgQ2hyaXMsPGJyPg0KPGJyPg0KdGhhbmtz IGZvciB0YWtpbmcgdGhlIHRpbWUgdG8gbWFrZSB0aGlzIHBhdGNoLCB0aGVzZSBhcmUgc29tZSBl eGNlbGxlbnQgaWRlYXMhIChDQydpbmcgZW5naW5lLWRldmVsIHNvIHRoYXQgd2UgY2FuIGRpc2N1 c3MgdGhpcyB3aXRoIG90aGVyIGd1eXMgYXMgd2VsbCk8YnI+DQo8YnI+DQpGaXJzdCBvZiBhbGws IEkgcmVhbGx5IGxpa2UgdGhlIHdheSB5b3UgZGVzaWduZWQgcGx1Z2luIHNvdXJjZSBwYWdlIFVS THMgKGdvaW5nIHRocm91Z2gNCjxlbT5QbHVnaW5Tb3VyY2VQYWdlU2VydmxldDwvZW0+KSwgZS5n LiAmcXVvdDsvd2ViYWRtaW4vd2ViYWRtaW4vcGx1Z2luLyZsdDtwbHVnaW5OYW1lJmd0Oy8mbHQ7 cGx1Z2luU291cmNlUGFnZSZndDsuaHRtbCZxdW90OywgcGx1cyB0aGUgY29uY2VwdCBvZiAmcXVv dDtwYXRoJnF1b3Q7IEpTT04gYXR0cmlidXRlLjxicj4NCjxicj4NCjxpPldlYmFkbWluRHluYW1p Y0hvc3RpbmdTZXJ2bGV0PC9pPiBsb2FkcyBhbmQgY2FjaGVzIGFsbCBwbHVnaW4gZGVmaW5pdGlv bnMgKDxpPiouanNvbjwvaT4gZmlsZXMpLCBhbmQgZGlyZWN0bHkgZW1iZWRzIHRoZW0gaW50byBX ZWJBZG1pbiBob3N0IHBhZ2UgYXMNCjxpPnBsdWdpbkRlZmluaXRpb25zPC9pPiBKYXZhU2NyaXB0 IG9iamVjdC4gSSdtIGFzc3VtaW5nIHRoYXQgPGk+cGx1Z2luRGVmaW5pdGlvbnM8L2k+IG9iamVj dCB3aWxsIG5vdyBsb29rIGxpa2UgdGhpczo8YnI+DQo8YnI+DQo8L3NwYW4+PHNwYW4gc3R5bGU9 ImZvbnQtZmFtaWx5OiZxdW90O0NvdXJpZXIgTmV3JnF1b3Q7O2NvbG9yOmJsYWNrIj52YXIgcGx1 Z2luRGVmaW5pdGlvbnMgPSB7PGJyPg0KJm5ic3A7Jm5ic3A7JnF1b3Q7dGVzdCZxdW90Ozogezxi cj4NCiZuYnNwOyZuYnNwOyAmbmJzcDsmcXVvdDtuYW1lJnF1b3Q7OiAmcXVvdDt0ZXN0JnF1b3Q7 LDxicj4NCiZuYnNwOyZuYnNwOyAmbmJzcDsmcXVvdDt2ZXJzaW9uJnF1b3Q7OiAmcXVvdDsxLjAm cXVvdDssPGJyPg0KJm5ic3A7Jm5ic3A7ICZuYnNwOyZxdW90O3VybCZxdW90OzogJnF1b3Q7L3dl YmFkbWluL3dlYmFkbWluL3BsdWdpbi90ZXN0L2Zvby5odG1sJnF1b3Q7LDxicj4NCiZuYnNwOyZu YnNwOyAmbmJzcDsmcXVvdDtwYXRoJnF1b3Q7OiAmcXVvdDsvdG1wJnF1b3Q7LDxicj4NCiZuYnNw OyZuYnNwOyAmbmJzcDsmcXVvdDtjb25maWcmcXVvdDs6IHsmcXVvdDthJnF1b3Q7OjEsICZxdW90 O2ImcXVvdDs6MiwgJnF1b3Q7YyZxdW90OzozfTxicj4NCiZuYnNwOyZuYnNwO308YnI+DQp9PC9z cGFuPjxzcGFuIHN0eWxlPSJjb2xvcjpibGFjayI+PGJyPg0KPGJyPg0KT3JpZ2luYWxseSwgdGhl IDxpPnBsdWdpbkRlZmluaXRpb25zPC9pPiBvYmplY3QgbG9va2VkIGxpa2UgdGhpczo8YnI+DQo8 L3NwYW4+PHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiZxdW90O0NvdXJpZXIgTmV3JnF1b3Q7O2Nv bG9yOmJsYWNrIj48YnI+DQp2YXIgcGx1Z2luRGVmaW5pdGlvbnMgPSB7PGJyPg0KJm5ic3A7Jm5i c3A7JnF1b3Q7dGVzdCZxdW90OzogJnF1b3Q7L3dlYmFkbWluL3dlYmFkbWluL3BsdWdpbi90ZXN0 L2Zvby5odG1sJnF1b3Q7IC8vIFNpbXBsZSBwbHVnaW5OYW1lIC0mZ3Q7IHBsdWdpblNvdXJjZVBh Z2VVcmwgbWFwcGluZ3M8YnI+DQp9PC9zcGFuPjxzcGFuIHN0eWxlPSJjb2xvcjpibGFjayI+PGJy Pg0KPGJyPg0KVGhpcyBpcyBiZWNhdXNlIFBsdWdpbk1hbmFnZXIgKFdlYkFkbWluKSBvbmx5IG5l ZWRzIDxpPnBsdWdpbk5hbWU8L2k+ICgmcXVvdDtuYW1lJnF1b3Q7KSBhbmQNCjxpPnBsdWdpblNv dXJjZVBhZ2VVcmw8L2k+ICgmcXVvdDt1cmwmcXVvdDspIGR1cmluZyBzdGFydHVwLCB3aGVuIGNy ZWF0aW5nIHBsdWdpbiBpZnJhbWUuIEJ1dCB0aGlzIGNhbiBiZSBjaGFuZ2VkIDopPGJyPg0KPGJy Pg0KUGx1Z2luICZxdW90O3ZlcnNpb24mcXVvdDsgbWFrZXMgc2Vuc2UsIHBsdXMgdGhlIHBsdWdp biBjb25maWd1cmF0aW9uIG9iamVjdCAoJnF1b3Q7Y29uZmlnJnF1b3Q7KSBjYW4gYmUgdXNlZnVs IGRpcmVjdGx5IG9uIHRoZSBjbGllbnQuIExldCBtZSBleHBsYWluOjxicj4NCjxicj4NCk9yaWdp bmFsbHksIHBsdWdpbiBjb25maWd1cmF0aW9uIHdhcyBzdXBwb3NlZCB0byBiZSBwYXNzZWQgdG8g YWN0dWFsIHBsdWdpbiBjb2RlICh0aHJvdWdoIGltbWVkaWF0ZWx5LWludm9rZWQtZnVuY3Rpb24t ZXhwcmVzc2lvbiwgb3IgSUlGRSksIGp1c3QgbGlrZSB0aGlzOjxicj4NCjwvc3Bhbj48c3BhbiBz dHlsZT0iZm9udC1mYW1pbHk6JnF1b3Q7Q291cmllciBOZXcmcXVvdDs7Y29sb3I6YmxhY2siPjxi cj4NCihmdW5jdGlvbiAocGx1Z2luQXBpLCBwbHVnaW5Db25maWcpIHsgLy8gSmF2YVNjcmlwdCBJ SUZFPGJyPg0KJm5ic3A7Jm5ic3A7Ly8gLi4uIGFjdHVhbCBwbHVnaW4gY29kZSAuLi48YnI+DQp9 KSg8YnI+DQombmJzcDsmbmJzcDtwYXJlbnQucGx1Z2luQXBpLCAvKiByZWZlcmVuY2UgdG8gZ2xv YmFsIHBsdWdpbkFwaSBvYmplY3QgKi88YnI+DQombmJzcDsmbmJzcDt7JnF1b3Q7YSZxdW90Ozox LCAmcXVvdDtiJnF1b3Q7OjIsICZxdW90O2MmcXVvdDs6M30gLyogZW1iZWRkZWQgcGx1Z2luIGNv bmZpZ3VyYXRpb24gYXMgSmF2YVNjcmlwdCBvYmplY3QgKi88YnI+DQopOzwvc3Bhbj48c3BhbiBz dHlsZT0iY29sb3I6YmxhY2siPjxicj4NCjxicj4NClRoZSB3aG9sZSBwdXJwb3NlIG9mIDxpPlBs dWdpblNvdXJjZVBhZ2VTZXJ2bGV0PC9pPiB3YXMgdG8gJnF1b3Q7d3JhcCZxdW90OyBhY3R1YWwg cGx1Z2luIGNvZGUgaW50byBIVE1MLCBzbyB0aGF0IHVzZXJzIGRvbid0IG5lZWQgdG8gd3JpdGUg SFRNTCBwYWdlcyBmb3IgdGhlaXIgcGx1Z2lucyBtYW51YWxseS4NCjxpPlBsdWdpblNvdXJjZVBh Z2VTZXJ2bGV0PC9pPiB3b3VsZCBoYW5kbGUgYW55IHBsdWdpbiBkZXBlbmRlbmNpZXMgKHBsYWNl ZCBpbnRvIEhUTUwgaGVhZCksIHdpdGggYWN0dWFsIHBsdWdpbiBjb2RlIGJlaW5nIHdyYXBwZWQg aW50byBJSUZFLCBhcyBzaG93biBhYm92ZS4gUGx1Z2luIGNvbmZpZ3VyYXRpb24gd2FzIG1lYW50 IHRvIGJlIHN0b3JlZCBpbiBhIHNlcGFyYXRlIGZpbGUsIGUuZy4NCjxpPiZsdDtwbHVnaW5OYW1l Jmd0Oy1jb25maWcuanNvbjwvaT4sIHNvIHRoYXQgdXNlcnMgY291bGQgY2hhbmdlIHRoZSBkZWZh dWx0IHBsdWdpbiBjb25maWd1cmF0aW9uIHRvIHN1aXQgdGhlaXIgbmVlZHMuPGJyPg0KPGJyPg0K SW5zcGlyZWQgYnkgeW91ciBwYXRjaCwgcmF0aGVyIHRoYW4gcmVhZGluZy9lbWJlZGRpbmcgcGx1 Z2luIGNvbmZpZ3VyYXRpb24gd2hlbiBzZXJ2aW5nIHBsdWdpbiBIVE1MIHBhZ2UgKDxpPlBsdWdp blNvdXJjZVBhZ2VTZXJ2bGV0PC9pPiksIGl0J3MgZXZlbiBiZXR0ZXIgdG8gaGF2ZSB0aGUgcGx1 Z2luIGNvbmZpZ3VyYXRpb24gZW1iZWRkZWQgZGlyZWN0bHkgaW50byBXZWJBZG1pbiBob3N0IHBh Z2UsIGFsb25nIHdpdGggaW50cm9kdWNpbmcgbmV3DQo8aT5wbHVnaW5BcGk8L2k+IGZ1bmN0aW9u IHRvIHJldHJpZXZlIHRoZSBwbHVnaW4gY29uZmlndXJhdGlvbiBvYmplY3QuPGJyPg0KPGJyPg0K QmFzZWQgb24gdGhpcywgSSBzdWdnZXN0IGZvbGxvd2luZyBtb2RpZmljYXRpb25zIHRvIHRoZSBv cmlnaW5hbCBjb25jZXB0Ojxicj4NCjxicj4NCi0gbW9kaWZ5IG9yaWdpbmFsIDxpPnBsdWdpbkRl ZmluaXRpb25zPC9pPiBzdHJ1Y3R1cmUsIGZyb20gPGk+cGx1Z2luTmFtZSAtJmd0OyBwbHVnaW5T b3VyY2VQYWdlVXJsPC9pPiwgdG8NCjxpPnBsdWdpbk5hbWUgLSZndDsgcGx1Z2luRGVmT2JqZWN0 PC9pPjxicj4NCi0gPGk+cGx1Z2luRGVmT2JqZWN0PC9pPiBpcyBiYXNpY2FsbHkgYSBzdWJzZXQg b2YgcGh5c2ljYWwgcGx1Z2luIGRlZmluaXRpb24gKDxpPnRlc3QuanNvbjwvaT4sIHNlZSBiZWxv dyksIHN1aXRhYmxlIGZvciB1c2Ugb24gdGhlIGNsaWVudDxicj4NCi0gYWRkIGZvbGxvd2luZyBh dHRyaWJ1dGVzIHRvIDxpPnBsdWdpbkRlZk9iamVjdDwvaT46IDxpPnZlcnNpb248L2k+LCA8aT51 cmw8L2k+LA0KPGk+Y29uZmlnPC9pPjxicj4NCiZuYnNwOyZuYnNwOyogbm90ZSAjMTogPGk+bmFt ZTwvaT4gaXMgbm90IG5lZWRlZCwgc2luY2UgaXQncyBhbHJlYWR5IHRoZSBrZXkgb2YgPGk+cGx1 Z2luTmFtZSAtJmd0OyBwbHVnaW5EZWZPYmplY3Q8L2k+IG1hcHBpbmc8YnI+DQombmJzcDsmbmJz cDsqIG5vdGUgIzI6IDxpPnBhdGg8L2k+IGlzIG5vdCBuZWVkZWQgb24gdGhlIGNsaWVudCAobW9y ZSBvbiB0aGlzIGJlbG93KTxicj4NCi0gaW50cm9kdWNlIDxpPnBsdWdpbkFwaS5jb25maWcocGx1 Z2luTmFtZSk8L2k+IGZ1bmN0aW9uIGZvciBwbHVnaW5zIHRvIHJldHJpZXZlIHRoZWlyIGNvbmZp Z3VyYXRpb24gb2JqZWN0LCBhbmQgcmVtb3ZlDQo8aT5wbHVnaW5Db25maWc8L2k+IHBhcmFtZXRl ciBmcm9tIG1haW4gSUlGRSAoYXMgc2hvd24gYWJvdmUpPGJyPg0KPGJyPg0KW2FdIFBoeXNpY2Fs IHBsdWdpbiBkZWZpbml0aW9uIGZpbGUgKEpTT04pIG1pZ2h0IGJlIGxvY2F0ZWQgYXQgb1ZpcnQg JnF1b3Q7RGF0YURpciZxdW90OywgZS5nLg0KPGk+L3Vzci9zaGFyZS9vdmlydC1lbmdpbmUvdWkt cGx1Z2lucy90ZXN0Lmpzb248L2k+LCBmb3IgZXhhbXBsZTo8YnI+DQo8L3NwYW4+PHNwYW4gc3R5 bGU9ImZvbnQtZmFtaWx5OiZxdW90O0NvdXJpZXIgTmV3JnF1b3Q7O2NvbG9yOmJsYWNrIj48YnI+ DQp7PGJyPg0KJm5ic3A7Jm5ic3A7JnF1b3Q7bmFtZSZxdW90OzogJnF1b3Q7dGVzdCZxdW90Oyw8 YnI+DQombmJzcDsmbmJzcDsmcXVvdDt2ZXJzaW9uJnF1b3Q7OiAmcXVvdDsxLjAmcXVvdDssPGJy Pg0KJm5ic3A7Jm5ic3A7JnF1b3Q7dXJsJnF1b3Q7OiAmcXVvdDsvd2ViYWRtaW4vd2ViYWRtaW4v cGx1Z2luL3Rlc3Qvc3RhcnQuaHRtbCZxdW90Oyw8YnI+DQombmJzcDsmbmJzcDsmcXVvdDtwYXRo JnF1b3Q7OiAmcXVvdDsvdG1wJnF1b3Q7LDxicj4NCiZuYnNwOyZuYnNwOyZxdW90O2NvbmZpZyZx dW90OzogJnF1b3Q7dGVzdC1jb25maWcuanNvbiZxdW90Ozxicj4NCn08L3NwYW4+PHNwYW4gc3R5 bGU9ImNvbG9yOmJsYWNrIj48YnI+DQo8YnI+DQpbYl0gUGx1Z2luIGNvbmZpZ3VyYXRpb24gZmls ZSAoSlNPTikgbWlnaHQgYmUgbG9jYXRlZCBhdCBvVmlydCAmcXVvdDtDb25maWdEaXImcXVvdDss IGUuZy4gPGk+DQovZXRjL292aXJ0LWVuZ2luZS91aS1wbHVnaW5zL3Rlc3QtY29uZmlnLmpzb248 L2k+LCBmb3IgZXhhbXBsZTo8YnI+DQo8L3NwYW4+PHNwYW4gc3R5bGU9ImZvbnQtZmFtaWx5OiZx dW90O0NvdXJpZXIgTmV3JnF1b3Q7O2NvbG9yOmJsYWNrIj48YnI+DQp7PGJyPg0KJm5ic3A7Jm5i c3A7JnF1b3Q7YSZxdW90OzoxLCAmcXVvdDtiJnF1b3Q7OjIsICZxdW90O2MmcXVvdDs6Mzxicj4N Cn08L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOmJsYWNrIj48YnI+DQo8YnI+DQpbY10gRmluYWxs eSwgcGx1Z2luIHN0YXRpYyByZXNvdXJjZXMgKHBsdWdpbiBzb3VyY2UgcGFnZSwgYWN0dWFsIHBs dWdpbiBjb2RlLCBwbHVnaW4gZGVwZW5kZW5jaWVzLCBDU1MvaW1hZ2VzLCBldGMuKSB3b3VsZCBi ZSBsb2NhdGVkIGF0DQo8aT4vdG1wPC9pPiAoYXMgc2hvd24gaW4gW2FdKSwgZm9yIGV4YW1wbGU6 PGJyPg0KPC9zcGFuPjxzcGFuIHN0eWxlPSJmb250LWZhbWlseTomcXVvdDtDb3VyaWVyIE5ldyZx dW90Oztjb2xvcjpibGFjayI+PGJyPg0KL3RtcC9zdGFydC5odG1sIC0mZ3Q7IHBsdWdpbiBzb3Vy Y2UgcGFnZSwgdXNlZCB0byBsb2FkIGFjdHVhbCBwbHVnaW4gY29kZTxicj4NCi90bXAvdGVzdC5q cyAtJmd0OyBhY3R1YWwgcGx1Z2luIGNvZGU8YnI+DQovdG1wL2RlcHMvanF1ZXJ5LW1pbi5qcyAt Jmd0OyBzaW11bGF0ZSAzcmQgcGFydHkgcGx1Z2luIGRlcGVuZGVuY3k8L3NwYW4+PHNwYW4gc3R5 bGU9ImNvbG9yOmJsYWNrIj48YnI+DQo8YnI+DQpGb3IgZXhhbXBsZTo8YnI+DQomcXVvdDsvd2Vi YWRtaW4vd2ViYWRtaW4vcGx1Z2luL3Rlc3Qvc3RhcnQuaHRtbCZxdW90OyB3aWxsIGJlIG1hcHBl ZCB0byA8aT4vdG1wL3N0YXJ0Lmh0bWw8L2k+PGJyPg0KJnF1b3Q7L3dlYmFkbWluL3dlYmFkbWlu L3BsdWdpbi90ZXN0L2RlcHMvanF1ZXJ5LW1pbi5qcyZxdW90OyB3aWxsIGJlIG1hcHBlZCB0byA8 aT4vdG1wL2RlcHMvanF1ZXJ5LW1pbi5qczwvaT48YnI+DQo8YnI+DQpUaGlzIGFwcHJvYWNoIGhh cyBzb21lIHByb3MgYW5kIGNvbnM6PGJyPg0KKCYjNDM7KSBwbHVnaW4gc3RhdGljIHJlc291cmNl cyBjYW4gYmUgc2VydmVkIHRocm91Z2ggPGk+UGx1Z2luU291cmNlUGFnZVNlcnZsZXQ8L2k+IChw cmV0dHkgbXVjaCBsaWtlIG9WaXJ0IGRvY3VtZW50YXRpb24gcmVzb3VyY2VzLCBzZXJ2ZWQgdGhy b3VnaCBvVmlydCBFbmdpbmUgcm9vdCB3YXIncw0KPGk+RmlsZVNlcnZsZXQ8L2k+KTxicj4NCigm IzQzOykgcGx1Z2luIGF1dGhvciBoYXMgY29tcGxldGUgY29udHJvbCBvdmVyIHBsdWdpbiBzb3Vy Y2UgcGFnZTxicj4NCigtKSBwbHVnaW4gYXV0aG9yIGFjdHVhbGx5IG5lZWRzIHRvIHdyaXRlIHBs dWdpbiBzb3VyY2UgcGFnZTxicj4NCjxicj4NCk92ZXJhbGwsIEkgdGhpbmsgdGhpcyBhcHByb2Fj aCBpcyBiZXR0ZXIgdGhhbiB0aGUgcHJldmlvdXMgb25lICh3aGVyZSA8aT5QbHVnaW5Tb3VyY2VQ YWdlU2VydmxldDwvaT4gdG9vayBjYXJlIG9mIHJlbmRlcmluZyBwbHVnaW4gc291cmNlIHBhZ2Us IGJ1dCBzYWNyaWZpY2VkIHNvbWUgZmxleGliaWxpdHkpLjxicj4NCjxicj4NCkJ5IHRoZSB3YXks IGhlcmUncyB3aGF0IHdvdWxkIGhhcHBlbiBiZWhpbmQgdGhlIHNjZW5lczo8bzpwPjwvbzpwPjwv c3Bhbj48L3A+DQo8b2wgc3RhcnQ9IjEiIHR5cGU9IjEiPg0KPGxpIGNsYXNzPSJNc29Ob3JtYWwi IHN0eWxlPSJjb2xvcjpibGFjazttc28tbWFyZ2luLXRvcC1hbHQ6YXV0bzttYXJnaW4tYm90dG9t OjEyLjBwdDttc28tbGlzdDpsMCBsZXZlbDEgbGZvMSI+DQp1c2VyIHJlcXVlc3RzIFdlYkFkbWlu IGhvc3QgcGFnZSwgPGk+V2ViYWRtaW5EeW5hbWljSG9zdGluZ1NlcnZsZXQ8L2k+IGxvYWRzIGFu ZCBjYWNoZXMgYWxsIHBsdWdpbiBkZWZpbml0aW9ucyBbYV0gJiM0MzsgcGx1Z2luIGNvbmZpZ3Vy YXRpb25zIFtiXSBhbmQgY29uc3RydWN0cy9lbWJlZHMgYXBwcm9wcmlhdGUNCjxpPnBsdWdpbkRl ZmluaXRpb25zPC9pPiBKYXZhU2NyaXB0IG9iamVjdDxvOnA+PC9vOnA+PC9saT48bGkgY2xhc3M9 Ik1zb05vcm1hbCIgc3R5bGU9ImNvbG9yOmJsYWNrO21zby1tYXJnaW4tdG9wLWFsdDphdXRvO21h cmdpbi1ib3R0b206MTIuMHB0O21zby1saXN0OmwwIGxldmVsMSBsZm8xIj4NCmR1cmluZyBXZWJB ZG1pbiBzdGFydHVwLCA8aT5QbHVnaW5NYW5hZ2VyPC9pPiByZWdpc3RlcnMgdGhlIHBsdWdpbiAo bmFtZS92ZXJzaW9uL3VybC9jb25maWcpLCBhbmQgY3JlYXRlcy9hdHRhY2hlcyB0aGUgaWZyYW1l IHRvIGZldGNoIHBsdWdpbiBzb3VyY2UgcGFnZSBhbnN5bmNocm9ub3VzbHk8bzpwPjwvbzpwPjwv bGk+PGxpIGNsYXNzPSJNc29Ob3JtYWwiIHN0eWxlPSJjb2xvcjpibGFjazttc28tbWFyZ2luLXRv cC1hbHQ6YXV0bzttYXJnaW4tYm90dG9tOjEyLjBwdDttc28tbGlzdDpsMCBsZXZlbDEgbGZvMSI+ DQo8aT5QbHVnaW5Tb3VyY2VQYWdlU2VydmxldDwvaT4gaGFuZGxlcyBwbHVnaW4gc291cmNlIHBh Z2UgcmVxdWVzdCwgcmVzb2x2ZXMgdGhlIGNvcnJlY3QgcGF0aCBbY10gYW5kIGp1c3Qgc3RyZWFt cyB0aGUgZmlsZSBjb250ZW50IGJhY2sgdG8gY2xpZW50PG86cD48L286cD48L2xpPjwvb2w+DQo8 cCBjbGFzcz0iTXNvTm9ybWFsIiBzdHlsZT0ibWFyZ2luLWJvdHRvbToxMi4wcHQiPjxzcGFuIHN0 eWxlPSJjb2xvcjpibGFjayI+Jmd0OyAxLiAmbmJzcDtUaGUgcGx1Z2luIGNvbmZpZ3VyYXRpb24g ZmlsZXMgc2hvdWxkIHByb2JhYmx5IGhhdmUgYW4gJnF1b3Q7ZW5hYmxlZCZxdW90OyBmaWVsZCBh bmQgYW4gJnF1b3Q7YXBpVmVyc2lvbiZxdW90OyBmaWVsZCB0aGF0IHNob3VsZCBiZSBleGFtaW5l ZCB0byBkZXRlcm1pbmUgd2hldGhlciBvciBub3QgdG8gdXNlIHRoZSBwbHVnaW4uPGJyPg0KPGJy Pg0KU291bmRzIGdvb2QsIHdlIGNhbiBpbXBsZW1lbnQgdGhlc2UgbGF0ZXIgb24gOik8YnI+DQo8 YnI+DQomZ3Q7IDIuICZuYnNwO0kgc3VzcGVjdCB0aGUgd2F5IEkndmUgbW9kaWZpZWQgUGx1Z2lu U291cmNlUGFnZSBtYWtlcyBpdCB2dWxuZXJhYmxlIHRvIGRpcmVjdG9yeSBjbGltYmluZyBhdHRh Y2tzLjxicj4NCjxicj4NClllcywgYnV0IHdlIGNhbiBkZWZlbmQgYWdhaW5zdCB0aGVzZSwgcmVz dHJpY3RpbmcgYWNjZXNzIG9ubHkgdG8gcGx1Z2luJ3MgJnF1b3Q7cGF0aCZxdW90OyBhbmQgaXRz IHN1Yi1kaXJlY3Rvcmllcy48YnI+DQo8YnI+DQomZ3Q7IDMuICZuYnNwO0lzIC91c3Ivc2hhcmUv b3ZpcnQtZW5naW5lIHRoZSByaWdodCBwbGFjZSBmb3IgdGhlIHBsdWdpbiBjb25maWcgZmlsZXM/ PGJyPg0KPGJyPg0KSSBzdXBwb3NlIHlvdSBtZWFuIHBsdWdpbiBkZWZpbml0aW9uIGZpbGVzIFth XSwgY2Fubm90IHRlbGwgZm9yIHN1cmUsIGJ1dCB3ZSBjYW4gY2hhbmdlIHRoaXMgYW55dGltZSA6 KTxicj4NCjxicj4NCjxicj4NCkNocmlzLCBwbGVhc2UgbGV0IG1lIGtub3cgd2hhdCB5b3UgdGhp bmssIGFuZCBhZ2FpbiAtIG1hbnkgdGhhbmtzIGZvciBzZW5kaW5nIHRoZSBwYXRjaCE8YnI+DQo8 YnI+DQo8YnI+DQpSZWdhcmRzLDxicj4NClZvanRlY2g8bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQo8 ZGl2IGNsYXNzPSJNc29Ob3JtYWwiIGFsaWduPSJjZW50ZXIiIHN0eWxlPSJ0ZXh0LWFsaWduOmNl bnRlciI+PHNwYW4gc3R5bGU9ImNvbG9yOmJsYWNrIj4NCjxociBzaXplPSIyIiB3aWR0aD0iMTAw JSIgYWxpZ249ImNlbnRlciI+DQo8L3NwYW4+PC9kaXY+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIiBz dHlsZT0ibWFyZ2luLWJvdHRvbToxMi4wcHQiPjxzcGFuIHN0eWxlPSJjb2xvcjpibGFjayI+PGJy Pg0KRnJvbTogJnF1b3Q7Q2hyaXMgRnJhbnR6JnF1b3Q7ICZsdDs8YSBocmVmPSJtYWlsdG86Q2hy aXMuRnJhbnR6QGhwLmNvbSIgdGFyZ2V0PSJfYmxhbmsiPkNocmlzLkZyYW50ekBocC5jb208L2E+ Jmd0Ozxicj4NClRvOiA8YSBocmVmPSJtYWlsdG86dnN6b2NzQHJlZGhhdC5jb20iIHRhcmdldD0i X2JsYW5rIj52c3pvY3NAcmVkaGF0LmNvbTwvYT48YnI+DQpTZW50OiBXZWRuZXNkYXksIEF1Z3Vz dCAyMiwgMjAxMiA3OjU2OjQ1IFBNPGJyPg0KU3ViamVjdDogVUkgUGx1Z2lucyBjb25maWd1cmF0 aW9uPGJyPg0KPGJyPg0KVm9qdGVjaCw8YnI+DQo8YnI+DQpJIGRlY2lkZWQgdG8gd29yayBvbiBt YWtpbmcgdGhlIHBsdWdpbiBwYXRjaCBhIGJpdCBtb3JlIGNvbmZpZ3VyYWJsZSwgZm9sbG93aW5n IHNvbWUgb2YgdGhlIGlkZWFzIGV4cHJlc3NlZCBieSBJdGFtYXIgYW5kIG90aGVycyBpbiB0aGUg bWVldGluZyB5ZXN0ZXJkYXkuICZuYnNwO1RoZSBhdHRhY2hlZCBwYXRjaCBpcyBhIHNpbXBsZSBm aXJzdC1hdHRlbXB0Ljxicj4NCjxicj4NClBsdWdpbiBjb25maWd1cmF0aW9ucyBhcmUgc3RvcmVk IGluIC91c3Ivc2hhcmUvb3ZpcnQtZW5naW5lL3VpLXBsdWdpbnMvKi5qc29uLjxicj4NCjxicj4N CkV4YW1wbGU6PGJyPg0Kezxicj4NCiZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNw OyZuYnNwOyZuYnNwOyZxdW90O25hbWUmcXVvdDs6ICZxdW90O3Rlc3QmcXVvdDssPGJyPg0KJm5i c3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7JnF1b3Q7dmVyc2lv biZxdW90OzogJnF1b3Q7MS4wJnF1b3Q7LDxicj4NCiZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZu YnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZxdW90O3VybCZxdW90OzogJnF1b3Q7L3dlYmFkbWluL3dl YmFkbWluL3BsdWdpbi90ZXN0L2Zvby5odG1sJnF1b3Q7LDxicj4NCiZuYnNwOyZuYnNwOyZuYnNw OyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZxdW90O3BhdGgmcXVvdDs6ICZxdW90Oy90 bXAmcXVvdDssPGJyPg0KJm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7 Jm5ic3A7JnF1b3Q7Y29uZmlnJnF1b3Q7OiB7JnF1b3Q7YSZxdW90OzoxLCAmcXVvdDtiJnF1b3Q7 OjIsICZxdW90O2MmcXVvdDs6IDN9PGJyPg0KfTxicj4NCjxicj4NClRoZSBlbmdpbmUgcmVhZHMg YWxsIG9mIHRoZSAqLmpzb24gZmlsZXMgaW4gdGhhdCBkaXJlY3RvcnkgdG8gYnVpbGQgdGhlIGxp c3Qgb2Yga25vd24gcGx1Z2lucyBhbmQgZ2l2ZXMgdGhhdCBsaXN0IHRvIHRoZSB3ZWJhZG1pbi48 YnI+DQo8YnI+DQpXaGVuIHdlYmFkbWluIGxvYWRzIGEgcGx1Z2luLCBpdCByZXF1ZXN0cyB0aGUg VVJMIGdpdmVuIGluIHRoZSBwbHVnaW4gY29uZmlnIGZpbGUuICZuYnNwO1RoZSAmcXVvdDtwbHVn aW4mcXVvdDsgVVJMIGlzIG1hcHBlZCB0byBQbHVnaW5Tb3VyY2VQYWdlLCB3aGljaCB3aWxsIHRy YW5zbGF0ZSB0aGUgZmlyc3QgcGFydCBvZiB0aGUgcGF0aCAoJnF1b3Q7dGVzdCZxdW90OykgaW50 byB3aGF0ZXZlciBwYXRoIGlzIHN0b3JlZCBpbiBwbHVnaW5Db25maWcgKCZxdW90Oy90bXAmcXVv dDspIGluIHRoaXMgY2FzZSwNCiBhbmQgdGhlbiBzZXJ2ZSB0aGUgc3RhdGljIGZpbGUgKGUuZy4g JnF1b3Q7L3RtcC9mb28uaHRtbCZxdW90OykuPGJyPg0KPGJyPg0KSSBkaWRuJ3QgdXNlIHRoZSBy ZW5kZXJQbHVnaW5Tb3VyY2VQYWdlKCkgbWV0aG9kIGluIGZhdm9yIG9mIGp1c3Qgc2VydmluZyBh IHN0YXRpYyBmaWxlLCBidXQgSSBoYXZlIG5vIHN0cm9uZyBvcGluaW9uIG9uIHRoZSBtYXR0ZXIu ICZuYnNwO0hvd2V2ZXIsIGEgcGx1Z2luIG1heSB3YW50IHRvIHN0b3JlIHN0YXRpYyByZXNvdXJj ZXMgYXQgJnF1b3Q7cGF0aCZxdW90OyBhbmQgaGF2ZSB0aGUgZW5naW5lIHNlcnZlIHRob3NlIHJl c291cmNlcy4gJm5ic3A7QnkganVzdCBzZXJ2aW5nDQogZmlsZXMgdGhyb3VnaCBQbHVnaW5Tb3Vy Y2VQYWdlLCB3ZSBkb24ndCBuZWVkIGFueSBvdGhlciBzZXJ2bGV0cyB0byBwcm92aWRlIHRob3Nl IHJlc291cmNlcy48YnI+DQo8YnI+DQpUaGVyZSBpcyBzdGlsbCBhIGJpdCBvZiB3b3JrIHRvIGRv Ojxicj4NCjxicj4NCjEuICZuYnNwO1RoZSBwbHVnaW4gY29uZmlndXJhdGlvbiBmaWxlcyBzaG91 bGQgcHJvYmFibHkgaGF2ZSBhbiAmcXVvdDtlbmFibGVkJnF1b3Q7IGZpZWxkIGFuZCBhbiAmcXVv dDthcGlWZXJzaW9uJnF1b3Q7IGZpZWxkIHRoYXQgc2hvdWxkIGJlIGV4YW1pbmVkIHRvIGRldGVy bWluZSB3aGV0aGVyIG9yIG5vdCB0byB1c2UgdGhlIHBsdWdpbi48YnI+DQo8YnI+DQoyLiAmbmJz cDtJIHN1c3BlY3QgdGhlIHdheSBJJ3ZlIG1vZGlmaWVkIFBsdWdpblNvdXJjZVBhZ2UgbWFrZXMg aXQgdnVsbmVyYWJsZSB0byBkaXJlY3RvcnkgY2xpbWJpbmcgYXR0YWNrcy48YnI+DQo8YnI+DQoz LiAmbmJzcDtJcyAvdXNyL3NoYXJlL292aXJ0LWVuZ2luZSB0aGUgcmlnaHQgcGxhY2UgZm9yIHRo ZSBwbHVnaW4gY29uZmlnIGZpbGVzPzxicj4NCjxicj4NCkxldCBtZSBrbm93IHdoYXQgeW91IHRo aW5rLDxicj4NCi0tQ2hyaXM8bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQo8L2Rpdj4NCjwvZGl2Pg0K PHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNwYW4gc3R5bGU9ImNvbG9yOmJsYWNrIj48bzpwPiZuYnNw OzwvbzpwPjwvc3Bhbj48L3A+DQo8L2Rpdj4NCjwvZGl2Pg0KPC9ib2R5Pg0KPC9odG1sPg0K --_000_A24D665DC3ECC245A2EA0D9A958F80B62C49123BG9W0745americas_-- --_005_A24D665DC3ECC245A2EA0D9A958F80B62C49123BG9W0745americas_ Content-Type: application/x-gzip; name="sample.tar.gz" Content-Description: sample.tar.gz Content-Disposition: attachment; filename="sample.tar.gz"; size=1096; creation-date="Thu, 30 Aug 2012 18:03:12 GMT"; modification-date="Thu, 30 Aug 2012 18:03:12 GMT" Content-Transfer-Encoding: base64 H4sIANKqP1AAA+1X224bNxDVq/Yr6H2oJMTaiyRLhW0ZCJIWSBHYQZMiaA0/0LsjLR2K3JBcyUrg f++QlCK1TW3EaBME4IEhcoecC4fk4bjRKtUVVZDKJVOmD2LOBKQN69e8wa5ODWiT3GgpWo9FhhiP Rq5F/L3N81HeygdZPpnkg/Fw2MoGWTYatEj2aI9fgEYbqghpKSnNffMeGv9O8TEiiDQlr9x2k3O6 ACeKBfbiYxLb/Y8PvWwJSjMprDhPMpRutRvFia6hYDMGmlRyRYwkXNKSmAqIP0rEZtqQms43HlDJ WkpXcE3LBRO7jldwRy91WkllFnzPX01NtedwVYECEu+pxUQB5XxNOFuC9v6sknMoa5NWdaoqWC42 53zP9huMuIQZbbjZRl5IMWPzRlGDq/fGvAjN+Qx6B1IZlOSD4ehwT1opql0qzzEvTLuUGLYAMpOK YJBkLmVJFiBs0gqJA9jaSZSVRM5slykcaIRRawy0Hc+VbGqNJi9jG+3bSsaHxHWfS6n09uNXyTkT c/LaSAFO+hJK8gfUNaA8JlcuyLvd0l/6HcMYZ4yjf1HaeK6REQgzZMUw6duF72fhZ5y8PSp9L3KM EUd30bc+4AH3AkxxL/Pvb+djfTzA/9lwMNryfzYcjS3/59gE/v8K+Bi18d5fILErVsKG6BJLZP+g taPx5MfDz093DIe8tKM6Sz/vG1a8I9dKrgRS3S25aRY18o9EbUdvnH5Yk1LOLfdas0/LklAiYLWx i5wDC2sVHwBWcPCEVyuJdGbJDDgY5bsCGte9igLlfBE+8xTuvbj/jQ93/8fu/ueTo2y/dfXfcDxw 9/9okA+H40kry8e2DPy697+YKSrMh3+d99D4d4rTg+cXz978/uonYvf7LDrdNkBLbA76/ajfJ89k w0u8qtt6qIQaRAmisMUX1VjpFa7Y0qCWeMMVaNmoAusu1D3VhWK1IWZdwxRLhFuT3tAl9dKYaFVM HyoBb943oNZ9FOM7FJ+dpl75DM1jjNuPFROlXCWUgzLdzguxlO9s8UML01C+q+RKOOj0TqLurBGF LedI1w89rVkPi7n2Eo8DMg5dkKlbl52TaKCqqBLdXGujunkv0TVn6OUHa8qpbChrSkTDOcqwtuta OZtmJ4SdOosJx0fWVPj95Inz5Z2hkhu+ZFeo2GYzDCnBxcDtxazb8Yannd50mnml9idfv7y+OE9Q V0O3wQqvoDWg6ibKSa9ng2vfRfgXtT+tMtm875cdm9zOFdqxVr3R481CkOjbv7EXgpljss1Ud+P+ r4l+K2Ul5SHxs23ZXVRQuhz7ULXkkHA573rLPia0f3eyHxTqleuuDwmn3PW6uC4QJtntzkkU7bb+ NN0dUbJki2Ni9HSE/2O43xX+wG2NBayh18f+nKT+aH/rGxcQEBAQEBAQEBAQEBAQEBAQEBAQEBAQ EPD/4k8TG/ezACgAAA== --_005_A24D665DC3ECC245A2EA0D9A958F80B62C49123BG9W0745americas_ Content-Type: application/octet-stream; name="UI-Plugins-Config-2.patch" Content-Description: UI-Plugins-Config-2.patch Content-Disposition: attachment; filename="UI-Plugins-Config-2.patch"; size=16835; creation-date="Thu, 30 Aug 2012 15:12:27 GMT"; modification-date="Thu, 30 Aug 2012 18:03:03 GMT" Content-Transfer-Encoding: base64 ZGlmZiAtLWdpdCBhL2JhY2tlbmQvbWFuYWdlci9tb2R1bGVzL2NvbW1vbi9zcmMvbWFpbi9qYXZh L29yZy9vdmlydC9lbmdpbmUvY29yZS9jb21tb24vY29uZmlnL0NvbmZpZy5qYXZhIGIvYmFja2Vu ZC9tYW5hZ2VyL21vZHVsZXMvY29tbW9uL3NyYy9tYWluL2phdmEvb3JnL292aXJ0L2VuZ2luZS9j b3JlL2NvbW1vbi9jb25maWcvQ29uZmlnLmphdmEKaW5kZXggZDY4MjVjNy4uNTA2NDg1MCAxMDA2 NDQKLS0tIGEvYmFja2VuZC9tYW5hZ2VyL21vZHVsZXMvY29tbW9uL3NyYy9tYWluL2phdmEvb3Jn L292aXJ0L2VuZ2luZS9jb3JlL2NvbW1vbi9jb25maWcvQ29uZmlnLmphdmEKKysrIGIvYmFja2Vu ZC9tYW5hZ2VyL21vZHVsZXMvY29tbW9uL3NyYy9tYWluL2phdmEvb3JnL292aXJ0L2VuZ2luZS9j b3JlL2NvbW1vbi9jb25maWcvQ29uZmlnLmphdmEKQEAgLTk2LDQgKzk2LDI1IEBAIHB1YmxpYyBm aW5hbCBjbGFzcyBDb25maWcgewogICAgICAgICByZXR1cm4gQ29uZmlnVXRpbC5yZXNvbHZlUGF0 aChyZXNvbHZlQ0FCYXNlUGF0aCgpLCBDb25maWcuPFN0cmluZz4gR2V0VmFsdWUoQ29uZmlnVmFs dWVzLlRydXN0c3RvcmVVcmwpKTsKICAgICB9CiAKKyAgICAvKioKKyAgICAgKiBGZXRjaCB0aGUg b1ZpcnRVaVBsdWdpbnNQYXRoIGNvbmZpZ3VyYXRpb24gdmFsdWUgYW5kLCBpZiBpdCBpcyBub3Qg YW4gYWJzb2x1dGUgcGF0aCwgcmVzb2x2ZSBpdCByZWxhdGl2ZSB0bworICAgICAqIHRoZSBEYXRh RGlyIGNvbmZpZ3VyYXRpb24gdmFsdWUuCisgICAgICoKKyAgICAgKiBAcmV0dXJuIGFuIGFic29s dXRlIHBhdGggZm9yIG9WaXJ0VWlQbHVnaW5zUGF0aAorICAgICAqLworICAgIHB1YmxpYyBzdGF0 aWMgU3RyaW5nIHJlc29sdmVPVmlydFVpUGx1Z2luc1BhdGgoKSB7CisgICAgICAgIHJldHVybiBD b25maWdVdGlsLnJlc29sdmVQYXRoKENvbmZpZy48U3RyaW5nPiBHZXRWYWx1ZShDb25maWdWYWx1 ZXMuRGF0YURpciksCisgICAgICAgICAgICAgICAgQ29uZmlnLjxTdHJpbmc+IEdldFZhbHVlKENv bmZpZ1ZhbHVlcy5VaVBsdWdpbnNQYXRoKSk7CisgICAgfQorCisgICAgLyoqCisgICAgICogRXhh bWluZSB0aGUgZ2l2ZW4gZmlsZW5hbWUgYW5kIGlmIGl0IGlzIG5vdCBhbiBhYnNvbHV0ZSBwYXRo LCByZXNvbHZlIGl0IHJlbGF0aXZlIHRvIHRoZSBvVmlydFVpUGx1Z2luc1BhdGgKKyAgICAgKgor ICAgICAqIEByZXR1cm4gYW4gYWJzb2x1dGUgcGF0aCBmb3IgdGhlIFVpUGx1Z2luQ29uZmlnRmls ZQorICAgICAqLworICAgIHB1YmxpYyBzdGF0aWMgU3RyaW5nIHJlc29sdmVPVmlydFVpUGx1Z2lu Q29uZmlnRmlsZShTdHJpbmcgZmlsZW5hbWUpIHsKKyAgICAgICAgU3RyaW5nIHBhdGggPSBDb25m aWdVdGlsLnJlc29sdmVQYXRoKENvbmZpZy48U3RyaW5nPiBHZXRWYWx1ZShDb25maWdWYWx1ZXMu Q29uZmlnRGlyKSwKKyAgICAgICAgICAgICAgICBDb25maWcuPFN0cmluZz4gR2V0VmFsdWUoQ29u ZmlnVmFsdWVzLlVpUGx1Z2luc1BhdGgpKTsKKyAgICAgICAgcmV0dXJuIENvbmZpZ1V0aWwucmVz b2x2ZVBhdGgocGF0aCwgZmlsZW5hbWUpOworICAgIH0KIH0KZGlmZiAtLWdpdCBhL2JhY2tlbmQv bWFuYWdlci9tb2R1bGVzL2NvbW1vbi9zcmMvbWFpbi9qYXZhL29yZy9vdmlydC9lbmdpbmUvY29y ZS9jb21tb24vY29uZmlnL0NvbmZpZ1ZhbHVlcy5qYXZhIGIvYmFja2VuZC9tYW5hZ2VyL21vZHVs ZXMvY29tbW9uL3NyYy9tYWluL2phdmEvb3JnL292aXJ0L2VuZ2luZS9jb3JlL2NvbW1vbi9jb25m aWcvQ29uZmlnVmFsdWVzLmphdmEKaW5kZXggNDk0YWM3MS4uNWM2ODVkOCAxMDA2NDQKLS0tIGEv YmFja2VuZC9tYW5hZ2VyL21vZHVsZXMvY29tbW9uL3NyYy9tYWluL2phdmEvb3JnL292aXJ0L2Vu Z2luZS9jb3JlL2NvbW1vbi9jb25maWcvQ29uZmlnVmFsdWVzLmphdmEKKysrIGIvYmFja2VuZC9t YW5hZ2VyL21vZHVsZXMvY29tbW9uL3NyYy9tYWluL2phdmEvb3JnL292aXJ0L2VuZ2luZS9jb3Jl L2NvbW1vbi9jb25maWcvQ29uZmlnVmFsdWVzLmphdmEKQEAgLTE0NDIsNiArMTQ0MiwxMCBAQCBw dWJsaWMgZW51bSBDb25maWdWYWx1ZXMgewogICAgIEBEZWZhdWx0VmFsdWVBdHRyaWJ1dGUoIm92 aXJ0LWVuZ2luZSIpCiAgICAgU1NIS2V5QWxpYXMoMzc3KSwKIAorICAgIEBUeXBlQ29udmVydGVy QXR0cmlidXRlKFN0cmluZy5jbGFzcykKKyAgICBARGVmYXVsdFZhbHVlQXR0cmlidXRlKCJ1aS1w bHVnaW5zIikKKyAgICBVaVBsdWdpbnNQYXRoKDM3OCksCisKICAgICBJbnZhbGlkKDY1NTM1KTsK IAogICAgIHByaXZhdGUgaW50IGludFZhbHVlOwpkaWZmIC0tZ2l0IGEvZnJvbnRlbmQvd2ViYWRt aW4vbW9kdWxlcy9mcm9udGVuZC9zcmMvbWFpbi9qYXZhL29yZy9vdmlydC9lbmdpbmUvdWkvZnJv bnRlbmQvc2VydmVyL2d3dC9QbHVnaW5Tb3VyY2VQYWdlU2VydmxldC5qYXZhIGIvZnJvbnRlbmQv d2ViYWRtaW4vbW9kdWxlcy9mcm9udGVuZC9zcmMvbWFpbi9qYXZhL29yZy9vdmlydC9lbmdpbmUv dWkvZnJvbnRlbmQvc2VydmVyL2d3dC9QbHVnaW5Tb3VyY2VQYWdlU2VydmxldC5qYXZhCmluZGV4 IGIwMzQyYTguLjU5YTRlMTcgMTAwNjQ0Ci0tLSBhL2Zyb250ZW5kL3dlYmFkbWluL21vZHVsZXMv ZnJvbnRlbmQvc3JjL21haW4vamF2YS9vcmcvb3ZpcnQvZW5naW5lL3VpL2Zyb250ZW5kL3NlcnZl ci9nd3QvUGx1Z2luU291cmNlUGFnZVNlcnZsZXQuamF2YQorKysgYi9mcm9udGVuZC93ZWJhZG1p bi9tb2R1bGVzL2Zyb250ZW5kL3NyYy9tYWluL2phdmEvb3JnL292aXJ0L2VuZ2luZS91aS9mcm9u dGVuZC9zZXJ2ZXIvZ3d0L1BsdWdpblNvdXJjZVBhZ2VTZXJ2bGV0LmphdmEKQEAgLTksMTUgKzks MTcgQEAgaW1wb3J0IGphdmEuaW8uSW5wdXRTdHJlYW1SZWFkZXI7CiBpbXBvcnQgamF2YS5pby5P dXRwdXRTdHJlYW1Xcml0ZXI7CiBpbXBvcnQgamF2YS5pby5SZWFkZXI7CiBpbXBvcnQgamF2YS5p by5Xcml0ZXI7Ci1pbXBvcnQgamF2YS51dGlsLkFycmF5czsKKy8vaW1wb3J0IGphdmEudXRpbC5B cnJheXM7CiBpbXBvcnQgamF2YS51dGlsLkxpc3Q7CiAKIGltcG9ydCBqYXZheC5zZXJ2bGV0Lmh0 dHAuSHR0cFNlcnZsZXQ7CiBpbXBvcnQgamF2YXguc2VydmxldC5odHRwLkh0dHBTZXJ2bGV0UmVx dWVzdDsKIGltcG9ydCBqYXZheC5zZXJ2bGV0Lmh0dHAuSHR0cFNlcnZsZXRSZXNwb25zZTsKIAor aW1wb3J0IG9yZy5jb2RlaGF1cy5qYWNrc29uLkpzb25Ob2RlOwogaW1wb3J0IG9yZy5hcGFjaGUu Y29tbW9ucy5sb2dnaW5nLkxvZzsKIGltcG9ydCBvcmcuYXBhY2hlLmNvbW1vbnMubG9nZ2luZy5M b2dGYWN0b3J5OworLy9pbXBvcnQgb3JnLm92aXJ0LmVuZ2luZS51aS5mcm9udGVuZC5zZXJ2ZXIu Z3d0LldlYmFkbWluRHluYW1pY0hvc3RpbmdTZXJ2bGV0OwogCiAvKioKICAqIFJlbmRlcnMgdGhl IEhUTUwgc291cmNlIHBhZ2UgZm9yIHRoZSBnaXZlbiBVSSBwbHVnaW4uCkBAIC0yNSwzNiArMjcs NDggQEAgaW1wb3J0IG9yZy5hcGFjaGUuY29tbW9ucy5sb2dnaW5nLkxvZ0ZhY3Rvcnk7CiBwdWJs aWMgY2xhc3MgUGx1Z2luU291cmNlUGFnZVNlcnZsZXQgZXh0ZW5kcyBIdHRwU2VydmxldCB7CiAK ICAgICBwcml2YXRlIHN0YXRpYyBmaW5hbCBsb25nIHNlcmlhbFZlcnNpb25VSUQgPSAxTDsKKyAg ICBwcml2YXRlIHN0YXRpYyBmaW5hbCBsb25nIFBBVEhfTUFYID0gNTEyOwogCiAgICAgcHJpdmF0 ZSBzdGF0aWMgTG9nIGxvZ2dlciA9IExvZ0ZhY3RvcnkuZ2V0TG9nKFBsdWdpblNvdXJjZVBhZ2VT ZXJ2bGV0LmNsYXNzKTsKIAogICAgIEBPdmVycmlkZQogICAgIHByb3RlY3RlZCB2b2lkIGRvR2V0 KEh0dHBTZXJ2bGV0UmVxdWVzdCByZXF1ZXN0LCBIdHRwU2VydmxldFJlc3BvbnNlIHJlc3BvbnNl KSB0aHJvd3MgSU9FeGNlcHRpb24gewogICAgICAgICAvLyBSZWFkIHBsdWdpbiBuYW1lIGFzIEhU VFAgcmVxdWVzdCBwYXJhbWV0ZXIKLSAgICAgICAgU3RyaW5nIHBsdWdpbk5hbWUgPSByZXF1ZXN0 LmdldFBhcmFtZXRlcigicGx1Z2luIik7IC8vJE5PTi1OTFMtMSQKLSAgICAgICAgaWYgKHBsdWdp bk5hbWUgPT0gbnVsbCkgeworICAgICAgICBTdHJpbmcgcGF0aEluZm8gPSByZXF1ZXN0LmdldFBh dGhJbmZvKCk7CisgICAgICAgIFN0cmluZyBwYXRoW10gPSBudWxsOworICAgICAgICBsb2dnZXIu ZGVidWcoIkdvdCBwbHVnaW4gcmVxdWVzdCAiK3BhdGhJbmZvKTsgLy8kTk9OLU5MUy0xJAorCisg ICAgICAgIHRyeSB7CisgICAgICAgICAgICBwYXRoID0gcGF0aEluZm8uc3BsaXQoIi8iLCAzKTsg Ly8kTk9OLU5MUy0xJAorICAgICAgICB9IGNhdGNoKEV4Y2VwdGlvbiBleCkge30KKworICAgICAg ICBpZiAocGF0aCA9PSBudWxsIHx8IHBhdGgubGVuZ3RoIDwgMikgeworICAgICAgICAgICAgbG9n Z2VyLmVycm9yKCJNaXNzaW5nIHBsdWdpbiBuYW1lIHJlcXVlc3QgcGFyYW1ldGVyIik7IC8vJE5P Ti1OTFMtMSQKKyAgICAgICAgICAgIHJlc3BvbnNlLnNlbmRFcnJvcihIdHRwU2VydmxldFJlc3Bv bnNlLlNDX0JBRF9SRVFVRVNUKTsKKyAgICAgICAgICAgIHJldHVybjsKKyAgICAgICAgfQorCisg ICAgICAgIEpzb25Ob2RlIHBpbmZvID0gV2ViYWRtaW5EeW5hbWljSG9zdGluZ1NlcnZsZXQuZ2V0 UGx1Z2luRGVmaW5pdGlvbihwYXRoWzFdKTsKKyAgICAgICAgaWYgKHBpbmZvID09IG51bGwpIHsK ICAgICAgICAgICAgIGxvZ2dlci5lcnJvcigiTWlzc2luZyBwbHVnaW4gbmFtZSByZXF1ZXN0IHBh cmFtZXRlciIpOyAvLyROT04tTkxTLTEkCiAgICAgICAgICAgICByZXNwb25zZS5zZW5kRXJyb3Io SHR0cFNlcnZsZXRSZXNwb25zZS5TQ19CQURfUkVRVUVTVCk7CiAgICAgICAgICAgICByZXR1cm47 CiAgICAgICAgIH0KIAogICAgICAgICAvLyBMb2NhdGUgcGx1Z2luIGNvZGUgaW4gbG9jYWwgZmls ZSBzeXN0ZW0KLSAgICAgICAgLy8gVE9ETyBoYXJkLWNvZGVkIHBsdWdpbiBsb2NhdGlvbgotICAg ICAgICBGaWxlIHBsdWdpbkNvZGVMb2NhdGlvbiA9IG5ldyBGaWxlKCIvaG9tZS92c3pvY3MvRG93 bmxvYWRzIik7IC8vJE5PTi1OTFMtMSQKLSAgICAgICAgRmlsZSBwbHVnaW5Db2RlRmlsZSA9IG5l dyBGaWxlKHBsdWdpbkNvZGVMb2NhdGlvbiwgcGx1Z2luTmFtZSArICIuanMiKTsgLy8kTk9OLU5M Uy0xJAorICAgICAgICBTdHJpbmcgbG9jYWxmaWxlID0gcGluZm8ucGF0aCgicGF0aCIpLmdldFRl eHRWYWx1ZSgpICsgRmlsZS5zZXBhcmF0b3IgKyBwYXRoWzJdOyAvLyROT04tTkxTLTEkCisgICAg ICAgIGlmICghaXNTYW5lKGxvY2FsZmlsZSkpIHsKKyAgICAgICAgICAgIHJlc3BvbnNlLnNlbmRF cnJvcihIdHRwU2VydmxldFJlc3BvbnNlLlNDX05PVF9GT1VORCk7CisgICAgICAgICAgICByZXR1 cm47CisgICAgICAgIH0KKworICAgICAgICBGaWxlIHBsdWdpbkNvZGVGaWxlID0gbmV3IEZpbGUo bG9jYWxmaWxlKTsKICAgICAgICAgaWYgKCFwbHVnaW5Db2RlRmlsZS5pc0ZpbGUoKSB8fCAhcGx1 Z2luQ29kZUZpbGUuY2FuUmVhZCgpKSB7CiAgICAgICAgICAgICBsb2dnZXIuZXJyb3IoIkNhbm5v dCByZWFkIHBsdWdpbiBjb2RlOiAiICsgcGx1Z2luQ29kZUZpbGUuZ2V0QWJzb2x1dGVQYXRoKCkp OyAvLyROT04tTkxTLTEkCiAgICAgICAgICAgICByZXNwb25zZS5zZW5kRXJyb3IoSHR0cFNlcnZs ZXRSZXNwb25zZS5TQ19OT1RfRk9VTkQpOwogICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICB9 CiAKLSAgICAgICAgLy8gVE9ETyBzaW11bGF0ZSBwbHVnaW4gZGVwZW5kZW5jaWVzCi0gICAgICAg IExpc3Q8U3RyaW5nPiBwbHVnaW5EZXBlbmRlbmN5TGlzdCA9Ci0gICAgICAgICAgICAgICAgQXJy YXlzLmFzTGlzdCgiaHR0cHM6Ly9hamF4Lmdvb2dsZWFwaXMuY29tL2FqYXgvbGlicy9qcXVlcnkv MS43LjIvanF1ZXJ5Lm1pbi5qcyIpOyAvLyROT04tTkxTLTEkCi0KLSAgICAgICAgLy8gVE9ETyBz aW11bGF0ZSBwbHVnaW4gY29uZmlndXJhdGlvbgotICAgICAgICBTdHJpbmcgcGx1Z2luQ29uZmln dXJhdGlvbk9iamVjdCA9ICJ7IFwiZm9vXCI6IDEyMyB9IjsgLy8kTk9OLU5MUy0xJAotCiAgICAg ICAgIC8vIFJlbmRlciBIVE1MIHNvdXJjZSBwYWdlIHRvIHRoZSBvdXRwdXQKICAgICAgICAgcmVz cG9uc2Uuc2V0Q29udGVudFR5cGUoInRleHQvaHRtbDsgY2hhcnNldD1VVEYtOCIpOyAvLyROT04t TkxTLTEkCiAgICAgICAgIHJlc3BvbnNlLnNldEhlYWRlcigiQ2FjaGUtQ29udHJvbCIsICJuby1j YWNoZSIpOyAvLyROT04tTkxTLTEkIC8vJE5PTi1OTFMtMiQKQEAgLTY2LDcgKzgwLDcgQEAgcHVi bGljIGNsYXNzIFBsdWdpblNvdXJjZVBhZ2VTZXJ2bGV0IGV4dGVuZHMgSHR0cFNlcnZsZXQgewog ICAgICAgICAgICAgaW4gPSBuZXcgQnVmZmVyZWRSZWFkZXIobmV3IElucHV0U3RyZWFtUmVhZGVy KG5ldyBGaWxlSW5wdXRTdHJlYW0ocGx1Z2luQ29kZUZpbGUpLCAiVVRGLTgiKSk7IC8vJE5PTi1O TFMtMSQKICAgICAgICAgICAgIG91dCA9IG5ldyBCdWZmZXJlZFdyaXRlcihuZXcgT3V0cHV0U3Ry ZWFtV3JpdGVyKHJlc3BvbnNlLmdldE91dHB1dFN0cmVhbSgpLCAiVVRGLTgiKSk7IC8vJE5PTi1O TFMtMSQKIAotICAgICAgICAgICAgcmVuZGVyUGx1Z2luU291cmNlUGFnZShpbiwgcGx1Z2luRGVw ZW5kZW5jeUxpc3QsIHBsdWdpbkNvbmZpZ3VyYXRpb25PYmplY3QsIG91dCk7CisgICAgICAgICAg ICBjb3B5Q2hhcnMoaW4sIG91dCk7CiAgICAgICAgICAgICBvdXQuZmx1c2goKTsKICAgICAgICAg fSBmaW5hbGx5IHsKICAgICAgICAgICAgIGlmIChpbiAhPSBudWxsKSB7CkBAIC0xMDgsNCArMTIy LDI1IEBAIHB1YmxpYyBjbGFzcyBQbHVnaW5Tb3VyY2VQYWdlU2VydmxldCBleHRlbmRzIEh0dHBT ZXJ2bGV0IHsKICAgICAgICAgfQogICAgIH0KIAorICAgIHByaXZhdGUgc3RhdGljIGJvb2xlYW4g aXNTYW5lKFN0cmluZyBwYXRoKSB7CisgICAgICAgIC8vIENoZWNrIHRoYXQgdGhlIHBhdGggaXMg bm90IHRvbyBsb25nOgorICAgICAgICBmaW5hbCBpbnQgbGVuZ3RoID0gcGF0aC5sZW5ndGgoKTsK KyAgICAgICAgaWYgKGxlbmd0aCA+IFBBVEhfTUFYKSB7CisgICAgICAgICAgICBsb2dnZXIuZXJy b3IoIlRoZSBwYXRoIGlzICIgKyBsZW5ndGggKyAiIGNoYXJhY3RlcnMgbG9uZywgd2hpY2ggaXMg bG9uZ2VyIHRoYW4gdGhlIG1heGltdW0gYWxsb3dlZCAiICsgUEFUSF9NQVggKyAiLiIpOyAvLyRO T04tTkxTLTEkIC8vJE5PTi1OTFMtMiQgLy8kTk9OLU5MUy0zJAorICAgICAgICAgICAgcmV0dXJu IGZhbHNlOworICAgICAgICB9CisKKyAgICAgICAgLy8gQ2hlY2sgdGhhdCB0aGVyZSBhcmVuJ3Qg cG90ZW50aWFsbHkgZGFuZ2Vyb3VzIGRpcmVjdG9yeSBuYXZpZ2F0aW9uIHNlcXVlbmNlczoKKyAg ICAgICAgaWYgKHBhdGguY29udGFpbnMoIi4uIikgfHwgcGF0aC5jb250YWlucygiLy8iKSB8fCBw YXRoLmNvbnRhaW5zKCIuLyIpKSB7IC8vJE5PTi1OTFMtMSQgLy8kTk9OLU5MUy0yJCAvLyROT04t TkxTLTMkCisgICAgICAgICAgICBsb2dnZXIuZXJyb3IoIlRoZSBwYXRoIGNvbnRhaW5zIHBvdGVu dGlhbGx5IGRhbmdlcm91cyBkaXJlY3RvcnkgbmF2aWdhdGlvbiBzZXF1ZW5jZXMuIik7IC8vJE5P Ti1OTFMtMSQKKyAgICAgICAgICAgIHJldHVybiBmYWxzZTsKKyAgICAgICAgfQorCisgICAgICAg IC8vIEFsbCBjaGVja3MgcGFzc2VkLCB0aGUgcGF0aCBpcyBzYW5lOgorICAgICAgICByZXR1cm4g dHJ1ZTsKKyAgICB9CisKKwogfQorCisvLyB2aW06IHRzPTQgc3RzPTQgc3c9NCBleHBhbmR0YWI6 CmRpZmYgLS1naXQgYS9mcm9udGVuZC93ZWJhZG1pbi9tb2R1bGVzL2Zyb250ZW5kL3NyYy9tYWlu L2phdmEvb3JnL292aXJ0L2VuZ2luZS91aS9mcm9udGVuZC9zZXJ2ZXIvZ3d0L1dlYmFkbWluRHlu YW1pY0hvc3RpbmdTZXJ2bGV0LmphdmEgYi9mcm9udGVuZC93ZWJhZG1pbi9tb2R1bGVzL2Zyb250 ZW5kL3NyYy9tYWluL2phdmEvb3JnL292aXJ0L2VuZ2luZS91aS9mcm9udGVuZC9zZXJ2ZXIvZ3d0 L1dlYmFkbWluRHluYW1pY0hvc3RpbmdTZXJ2bGV0LmphdmEKaW5kZXggZGNhZjQ5YS4uNTAxYzdm NSAxMDA2NDQKLS0tIGEvZnJvbnRlbmQvd2ViYWRtaW4vbW9kdWxlcy9mcm9udGVuZC9zcmMvbWFp bi9qYXZhL29yZy9vdmlydC9lbmdpbmUvdWkvZnJvbnRlbmQvc2VydmVyL2d3dC9XZWJhZG1pbkR5 bmFtaWNIb3N0aW5nU2VydmxldC5qYXZhCisrKyBiL2Zyb250ZW5kL3dlYmFkbWluL21vZHVsZXMv ZnJvbnRlbmQvc3JjL21haW4vamF2YS9vcmcvb3ZpcnQvZW5naW5lL3VpL2Zyb250ZW5kL3NlcnZl ci9nd3QvV2ViYWRtaW5EeW5hbWljSG9zdGluZ1NlcnZsZXQuamF2YQpAQCAtMSwxMCArMSwyMSBA QAogcGFja2FnZSBvcmcub3ZpcnQuZW5naW5lLnVpLmZyb250ZW5kLnNlcnZlci5nd3Q7CiAKIGlt cG9ydCBqYXZhLmlvLlByaW50V3JpdGVyOworaW1wb3J0IGphdmEuaW8uRmlsZTsKK2ltcG9ydCBq YXZhLmlvLklPRXhjZXB0aW9uOwogaW1wb3J0IGphdmEudXRpbC5IYXNoTWFwOwogaW1wb3J0IGph dmEudXRpbC5NYXA7CitpbXBvcnQgamF2YS51dGlsLk1hcC5FbnRyeTsKK2ltcG9ydCBqYXZhLnV0 aWwuSXRlcmF0b3I7CitpbXBvcnQgb3JnLmFwYWNoZS5jb21tb25zLmxvZ2dpbmcuTG9nOworaW1w b3J0IG9yZy5hcGFjaGUuY29tbW9ucy5sb2dnaW5nLkxvZ0ZhY3Rvcnk7CisKIAogaW1wb3J0IGph dmF4LnNlcnZsZXQuaHR0cC5IdHRwU2VydmxldFJlcXVlc3Q7CitpbXBvcnQgb3JnLmNvZGVoYXVz LmphY2tzb24uSnNvblBhcnNlcjsKK2ltcG9ydCBvcmcuY29kZWhhdXMuamFja3Nvbi5Kc29uTm9k ZTsKK2ltcG9ydCBvcmcuY29kZWhhdXMuamFja3Nvbi5ub2RlLk9iamVjdE5vZGU7CitpbXBvcnQg b3JnLmNvZGVoYXVzLmphY2tzb24ubWFwLk9iamVjdE1hcHBlcjsKIAogaW1wb3J0IG9yZy5vdmly dC5lbmdpbmUuY29yZS5jb21tb24uY29uZmlnLkNvbmZpZzsKIGltcG9ydCBvcmcub3ZpcnQuZW5n aW5lLmNvcmUuY29tbW9uLnF1ZXJpZXMuQ29uZmlndXJhdGlvblZhbHVlczsKQEAgLTE5LDYgKzMw LDggQEAgaW1wb3J0IG9yZy5vdmlydC5lbmdpbmUuY29yZS5jb21tb24ucXVlcmllcy5WZGNRdWVy eVR5cGU7CiBwdWJsaWMgY2xhc3MgV2ViYWRtaW5EeW5hbWljSG9zdGluZ1NlcnZsZXQgZXh0ZW5k cyBHd3REeW5hbWljSG9zdFBhZ2VTZXJ2bGV0IHsKIAogICAgIHByaXZhdGUgc3RhdGljIGZpbmFs IGxvbmcgc2VyaWFsVmVyc2lvblVJRCA9IDFMOworICAgIHByaXZhdGUgc3RhdGljIE1hcDxTdHJp bmcsIEpzb25Ob2RlPiBwbHVnaW5EZWZpbml0aW9uczsKKyAgICBwcml2YXRlIHN0YXRpYyBMb2cg bG9nZ2VyID0gTG9nRmFjdG9yeS5nZXRMb2coV2ViYWRtaW5EeW5hbWljSG9zdGluZ1NlcnZsZXQu Y2xhc3MpOwogCiAgICAgQE92ZXJyaWRlCiAgICAgcHJvdGVjdGVkIFN0cmluZyBnZXRTZWxlY3Rv clNjcmlwdE5hbWUoKSB7CkBAIC0zNyw5ICs1MCwxMyBAQCBwdWJsaWMgY2xhc3MgV2ViYWRtaW5E eW5hbWljSG9zdGluZ1NlcnZsZXQgZXh0ZW5kcyBHd3REeW5hbWljSG9zdFBhZ2VTZXJ2bGV0IHsK ICAgICAgICAgICAgIHdyaXRlSnNPYmplY3Qod3JpdGVyLCAiYXBwbGljYXRpb25Nb2RlIiwgYXBw TW9kZURhdGEpOyAvLyROT04tTkxTLTEkCiAgICAgICAgIH0KIAotICAgICAgICBNYXA8U3RyaW5n LCBTdHJpbmc+IHBsdWdpbkRlZmluaXRpb25zID0gbmV3IEhhc2hNYXA8U3RyaW5nLCBTdHJpbmc+ KCk7Ci0gICAgICAgIHBsdWdpbkRlZmluaXRpb25zLnB1dCgibXlQbHVnaW4iLCAiL3dlYmFkbWlu L3dlYmFkbWluL1BsdWdpblNvdXJjZVBhZ2U/cGx1Z2luPW15UGx1Z2luIik7IC8vJE5PTi1OTFMt MSQgLy8kTk9OLU5MUy0yJAotICAgICAgICB3cml0ZUpzT2JqZWN0KHdyaXRlciwgInBsdWdpbkRl ZmluaXRpb25zIiwgcGx1Z2luRGVmaW5pdGlvbnMpOyAvLyROT04tTkxTLTEkCisgICAgICAgIC8v IEZJWE1FOiBkbyB3ZSBsb2FkIHRoaXMgZXZlcnl0aW1lLCBvciBqdXN0IG9uY2U/CisgICAgICAg IGlmICh0cnVlKSB7IC8qKnBsdWdpbkRlZmluaXRpb25zID09IG51bGwpIHsqKi8KKyAgICAgICAg ICAgIGxvZ2dlci5kZWJ1ZygiZ2V0UGx1Z2luRGVmaW5pdGlvbnM6IExvYWRpbmcgcGx1Z2luIGRl ZmluaXRpb25zIik7IC8vJE5PTi1OTFMtMSQKKyAgICAgICAgICAgIHBsdWdpbkRlZmluaXRpb25z ID0gZ2V0UGx1Z2luRGVmaW5pdGlvbnMoKTsKKyAgICAgICAgfQorCisgICAgICAgIHdyaXRlSnNv bk9iamVjdCh3cml0ZXIsICJwbHVnaW5EZWZpbml0aW9ucyIsIHBsdWdpbkRlZmluaXRpb25zKTsg Ly8kTk9OLU5MUy0xJAogICAgIH0KIAogICAgIHByaXZhdGUgSW50ZWdlciBnZXRBcHBsaWNhdGlv bk1vZGUoSHR0cFNlcnZsZXRSZXF1ZXN0IHJlcXVlc3QpIHsKQEAgLTQ4LDQgKzY1LDEwMCBAQCBw dWJsaWMgY2xhc3MgV2ViYWRtaW5EeW5hbWljSG9zdGluZ1NlcnZsZXQgZXh0ZW5kcyBHd3REeW5h bWljSG9zdFBhZ2VTZXJ2bGV0IHsKICAgICAgICAgICAgICAgICBDb25maWcuRGVmYXVsdENvbmZp Z3VyYXRpb25WZXJzaW9uKSwgcmVxdWVzdCk7CiAgICAgfQogCisgICAgcHJpdmF0ZSBib29sZWFu IGNoZWNrUGx1Z2luRGVmaW5pdGlvbihTdHJpbmcgZmlsZW5hbWUsIEpzb25Ob2RlIGRlZikgewor ICAgICAgICBTdHJpbmcgdXJsLCBjZmc7CisKKyAgICAgICAgaWYgKCFkZWYucGF0aCgibmFtZSIp LmlzVGV4dHVhbCgpKSB7IC8vJE5PTi1OTFMtMSQKKyAgICAgICAgICAgIGxvZ2dlci5lcnJvcihm aWxlbmFtZSsiOiAgVGhlICduYW1lJyBmaWVsZCBtdXN0IGJlIHByZXNlbnQgYW5kIG11c3QgYmUg YSBzdHJpbmcuIik7IC8vJE5PTi1OTFMtMSQKKyAgICAgICAgICAgIHJldHVybiBmYWxzZTsKKyAg ICAgICAgfQorICAgICAgICBpZiAoIWRlZi5wYXRoKCJ1cmwiKS5pc1RleHR1YWwoKSkgeyAvLyRO T04tTkxTLTEkCisgICAgICAgICAgICBsb2dnZXIuZXJyb3IoZmlsZW5hbWUrIjogIFRoZSAndXJs JyBmaWVsZCBtdXN0IGJlIHByZXNlbnQgYW5kIG11c3QgYmUgYSBzdHJpbmcuIik7IC8vJE5PTi1O TFMtMSQKKyAgICAgICAgICAgIHJldHVybiBmYWxzZTsKKyAgICAgICAgfQorICAgICAgICB1cmwg PSBkZWYucGF0aCgidXJsIikuZ2V0VmFsdWVBc1RleHQoKTsgLy8kTk9OLU5MUy0xJAorICAgICAg ICBpZiAodXJsLnN0YXJ0c1dpdGgoIi93ZWJhZG1pbiIpKSB7IC8vJE5PTi1OTFMtMSQKKyAgICAg ICAgICAgIGlmICghZGVmLnBhdGgoInBhdGgiKS5pc1RleHR1YWwoKSkgeyAvLyROT04tTkxTLTEk CisgICAgICAgICAgICAgICAgbG9nZ2VyLmVycm9yKGZpbGVuYW1lKyI6ICBUaGUgJ3BhdGgnIGZp ZWxkIG11c3QgYmUgcHJlc2VudCB3aGVuIHRoZSAndXJsJyBpcyBsb2NhbCBhbmQgbXVzdCBiZSBh IHN0cmluZy4iKTsgLy8kTk9OLU5MUy0xJAorICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsK KyAgICAgICAgICAgIH0KKyAgICAgICAgfQorICAgICAgICByZXR1cm4gdHJ1ZTsKKyAgICB9CisK KyAgICBwcml2YXRlIE1hcDxTdHJpbmcsIEpzb25Ob2RlPiBnZXRQbHVnaW5EZWZpbml0aW9ucygp IHsKKyAgICAgICAgTWFwPFN0cmluZywgSnNvbk5vZGU+IGRlZnMgPSBuZXcgSGFzaE1hcDxTdHJp bmcsIEpzb25Ob2RlPigpOworICAgICAgICBGaWxlIGRpcmVjdG9yeTsKKyAgICAgICAgRmlsZVtd IGZpbGVzOworCisgICAgICAgIGxvZ2dlci5kZWJ1ZygiZ2V0UGx1Z2luRGVmaW5pdGlvbnM6IENo ZWNraW5nIHBhdGggIitDb25maWcucmVzb2x2ZU9WaXJ0VWlQbHVnaW5zUGF0aCgpKTsgLy8kTk9O LU5MUy0xJAorICAgICAgICBkaXJlY3RvcnkgPSBuZXcgRmlsZShDb25maWcucmVzb2x2ZU9WaXJ0 VWlQbHVnaW5zUGF0aCgpKTsKKyAgICAgICAgZmlsZXMgPSBkaXJlY3RvcnkubGlzdEZpbGVzKCk7 CisKKyAgICAgICAgSnNvbk5vZGUgcm9vdDsKKyAgICAgICAgT2JqZWN0TWFwcGVyIG1hcHBlciA9 IG5ldyBPYmplY3RNYXBwZXIoKTsKKyAgICAgICAgbWFwcGVyLmNvbmZpZ3VyZShKc29uUGFyc2Vy LkZlYXR1cmUuQUxMT1dfQ09NTUVOVFMsIHRydWUpOworICAgICAgICAvLyBGSVhNRTogSWYgSkFD S1NPTi02MTggaXMgcmVzb2x2ZWQgKEFMTE9XX1RSQUlMSU5HX0NPTU1BKSwgdXNlIGl0LgorCisg ICAgICAgIGZvcihpbnQgaT0wOyBpPGZpbGVzLmxlbmd0aDsgaSsrKSB7CisgICAgICAgICAgICBT dHJpbmcgZmlsZW5hbWUgPSBmaWxlc1tpXS5nZXROYW1lKCk7CisgICAgICAgICAgICBsb2dnZXIu ZGVidWcoImdldFBsdWdpbkRlZmluaXRpb25zOiBDaGVja2luZyBmaWxlICIrZmlsZW5hbWUpOyAv LyROT04tTkxTLTEkCisgICAgICAgICAgICBpZiAoIWZpbGVuYW1lLmVuZHNXaXRoKCIuanNvbiIp KSAvLyROT04tTkxTLTEkCisgICAgICAgICAgICAgICAgY29udGludWU7CisKKyAgICAgICAgICAg IHRyeSB7CisgICAgICAgICAgICAgICAgcm9vdCA9IG1hcHBlci5yZWFkVmFsdWUoZmlsZXNbaV0s IEpzb25Ob2RlLmNsYXNzKTsKKyAgICAgICAgICAgIH0gY2F0Y2goSU9FeGNlcHRpb24gZXgpIHsK KyAgICAgICAgICAgICAgICBsb2dnZXIuZXJyb3IoImdldFBsdWdpbkRlZmluaXRpb25zOiBFcnJv ciByZWFkaW5nICIrZmlsZW5hbWUrIjogIitleCk7IC8vJE5PTi1OTFMtMSQgLy8kTk9OLU5MUy0y JAorICAgICAgICAgICAgICAgIGNvbnRpbnVlOworICAgICAgICAgICAgfQorICAgICAgICAgICAg aWYgKGNoZWNrUGx1Z2luRGVmaW5pdGlvbihmaWxlc1tpXS5nZXRBYnNvbHV0ZVBhdGgoKSwgcm9v dCkpIHsKKyAgICAgICAgICAgICAgICBTdHJpbmcgbmFtZSA9IHJvb3QucGF0aCgibmFtZSIpLmdl dFZhbHVlQXNUZXh0KCk7IC8vJE5PTi1OTFMtMSQKKyAgICAgICAgICAgICAgICBTdHJpbmcgY2Zn ID0gcm9vdC5wYXRoKCJjb25maWdGaWxlIikuZ2V0VmFsdWVBc1RleHQoKTsgLy8kTk9OLU5MUy0x JAorICAgICAgICAgICAgICAgIGlmIChjZmcgIT0gbnVsbCkgeworICAgICAgICAgICAgICAgICAg ICBjZmcgPSBDb25maWcucmVzb2x2ZU9WaXJ0VWlQbHVnaW5Db25maWdGaWxlKGNmZyk7CisgICAg ICAgICAgICAgICAgICAgIHRyeSB7CisgICAgICAgICAgICAgICAgICAgICAgICBKc29uTm9kZSBj b25maWcgPSBtYXBwZXIucmVhZFZhbHVlKG5ldyBGaWxlKGNmZyksIEpzb25Ob2RlLmNsYXNzKTsK KyAgICAgICAgICAgICAgICAgICAgICAgIE9iamVjdE5vZGUgb24gPSAoT2JqZWN0Tm9kZSlyb290 LndpdGgoImNvbmZpZyIpOyAvLyROT04tTkxTLTEkCisgICAgICAgICAgICAgICAgICAgICAgICBm b3IoSXRlcmF0b3I8RW50cnk8U3RyaW5nLEpzb25Ob2RlPj4gaXQ9Y29uZmlnLmdldEZpZWxkcygp OyBpdC5oYXNOZXh0KCk7KSB7CisgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50cnk8U3Ry aW5nLEpzb25Ob2RlPiBlID0gaXQubmV4dCgpOworICAgICAgICAgICAgICAgICAgICAgICAgICAg IG9uLnB1dChlLmdldEtleSgpLCBlLmdldFZhbHVlKCkpOworICAgICAgICAgICAgICAgICAgICAg ICAgfQorICAgICAgICAgICAgICAgICAgICB9IGNhdGNoKEV4Y2VwdGlvbiBleCkgeworICAgICAg ICAgICAgICAgICAgICAgICAgbG9nZ2VyLmVycm9yKGZpbGVuYW1lKyI6ICBFcnJvciByZWFkaW5n IHRoZSBwbHVnaW4gY29uZmlndXJhdGlvbiBmcm9tICIrY2ZnKyIuICBFeGNlcHRpb24gd2FzOiAi K2V4KTsgLy8kTk9OLU5MUy0xJCAvLyROT04tTkxTLTIkCisgICAgICAgICAgICAgICAgICAgIH0K KyAgICAgICAgICAgICAgICB9CisgICAgICAgICAgICAgICAgZGVmcy5wdXQobmFtZSwgcm9vdCk7 CisgICAgICAgICAgICB9CisgICAgICAgIH0KKyAgICAgICAgcmV0dXJuIGRlZnM7CisgICAgfQor CisgICAgLyoqCisgICAgICogUmV0dXJuIGEgc2luZ2xlIHBsdWdpbiBkZWZpbml0aW9uIGdpdmVu IGEgcGx1Z2luIG5hbWUKKyAgICAgKi8KKyAgICBwdWJsaWMgc3RhdGljIEpzb25Ob2RlIGdldFBs dWdpbkRlZmluaXRpb24oU3RyaW5nIG5hbWUpIHsKKyAgICAgICAgSnNvbk5vZGUgcmV0ID0gbnVs bDsKKyAgICAgICAgaWYgKHBsdWdpbkRlZmluaXRpb25zICE9IG51bGwpIHsKKyAgICAgICAgICAg IHJldCA9IHBsdWdpbkRlZmluaXRpb25zLmdldChuYW1lKTsKKyAgICAgICAgfQorICAgICAgICBy ZXR1cm4gcmV0OworICAgIH0KKworICAgIC8qKgorICAgICAqIFdyaXRlcyBhIHN0cmluZyByZXBy ZXNlbnRpbmcgSmF2YVNjcmlwdCBvYmplY3QgbGl0ZXJhbCBjb250YWluaW5nIGdpdmVuIGF0dHJp YnV0ZXMuCisgICAgICovCisgICAgcHJvdGVjdGVkIHZvaWQgd3JpdGVKc29uT2JqZWN0KFByaW50 V3JpdGVyIHdyaXRlciwgU3RyaW5nIG9iamVjdE5hbWUsIE1hcDxTdHJpbmcsIEpzb25Ob2RlPiBh dHRyaWJ1dGVzKSB7CisgICAgICAgIFN0cmluZ0J1aWxkZXIgc2IgPSBuZXcgU3RyaW5nQnVpbGRl cigpOworICAgICAgICBPYmplY3RNYXBwZXIgbWFwcGVyID0gbmV3IE9iamVjdE1hcHBlcigpOwor ICAgICAgICBzYi5hcHBlbmQoIiB2YXIgIikuYXBwZW5kKG9iamVjdE5hbWUpLmFwcGVuZCgiID0g Iik7IC8vJE5PTi1OTFMtMSQgLy8kTk9OLU5MUy0yJAorICAgICAgICB0cnkgeworICAgICAgICAg ICAgc2IuYXBwZW5kKG1hcHBlci53cml0ZVZhbHVlQXNTdHJpbmcoYXR0cmlidXRlcykpOworICAg ICAgICB9IGNhdGNoKEV4Y2VwdGlvbiBleCkgeyB9CisgICAgICAgIHNiLmFwcGVuZCgiOyIpOyAv LyROT04tTkxTLTEkCisgICAgICAgIHdyaXRlci5hcHBlbmQoc2IudG9TdHJpbmcoKSk7CisgICAg fQorCisKIH0KKy8vIHZpbTogdHM9NCBzdHM9NCBzdz00IGV4cGFuZHRhYjoKZGlmZiAtLWdpdCBh L2Zyb250ZW5kL3dlYmFkbWluL21vZHVsZXMvd2ViYWRtaW4vc3JjL21haW4vamF2YS9vcmcvb3Zp cnQvZW5naW5lL3VpL3dlYmFkbWluL3BsdWdpbi9QbHVnaW5EZWZpbml0aW9ucy5qYXZhIGIvZnJv bnRlbmQvd2ViYWRtaW4vbW9kdWxlcy93ZWJhZG1pbi9zcmMvbWFpbi9qYXZhL29yZy9vdmlydC9l bmdpbmUvdWkvd2ViYWRtaW4vcGx1Z2luL1BsdWdpbkRlZmluaXRpb25zLmphdmEKaW5kZXggZDEx MThjYi4uYjBhMjA1YyAxMDA2NDQKLS0tIGEvZnJvbnRlbmQvd2ViYWRtaW4vbW9kdWxlcy93ZWJh ZG1pbi9zcmMvbWFpbi9qYXZhL29yZy9vdmlydC9lbmdpbmUvdWkvd2ViYWRtaW4vcGx1Z2luL1Bs dWdpbkRlZmluaXRpb25zLmphdmEKKysrIGIvZnJvbnRlbmQvd2ViYWRtaW4vbW9kdWxlcy93ZWJh ZG1pbi9zcmMvbWFpbi9qYXZhL29yZy9vdmlydC9lbmdpbmUvdWkvd2ViYWRtaW4vcGx1Z2luL1Bs dWdpbkRlZmluaXRpb25zLmphdmEKQEAgLTI0LDcgKzI0LDggQEAgcHVibGljIGZpbmFsIGNsYXNz IFBsdWdpbkRlZmluaXRpb25zIGV4dGVuZHMgSmF2YVNjcmlwdE9iamVjdCB7CiAgICAgfS0qLzsK IAogICAgIHB1YmxpYyBuYXRpdmUgU3RyaW5nIGdldFBsdWdpblNvdXJjZVBhZ2VVcmwoU3RyaW5n IHBsdWdpbk5hbWUpIC8qLXsKLSAgICAgICAgcmV0dXJuIHRoaXNbcGx1Z2luTmFtZV07CisgICAg ICAgIHZhciBjZmcgPSBKU09OLnN0cmluZ2lmeSh0aGlzW3BsdWdpbk5hbWVdWyJjb25maWciXSk7 CisgICAgICAgIHJldHVybiB0aGlzW3BsdWdpbk5hbWVdWyJ1cmwiXSArICI/Y29uZmlnPSIrY2Zn OwogICAgIH0tKi87CiAKIH0KZGlmZiAtLWdpdCBhL2Zyb250ZW5kL3dlYmFkbWluL21vZHVsZXMv d2ViYWRtaW4vc3JjL21haW4vamF2YS9vcmcvb3ZpcnQvZW5naW5lL3VpL3dlYmFkbWluL3BsdWdp bi9QbHVnaW5FdmVudEhhbmRsZXIuamF2YSBiL2Zyb250ZW5kL3dlYmFkbWluL21vZHVsZXMvd2Vi YWRtaW4vc3JjL21haW4vamF2YS9vcmcvb3ZpcnQvZW5naW5lL3VpL3dlYmFkbWluL3BsdWdpbi9Q bHVnaW5FdmVudEhhbmRsZXIuamF2YQppbmRleCBjYmFmYjJmLi40NjZiODkxIDEwMDY0NAotLS0g YS9mcm9udGVuZC93ZWJhZG1pbi9tb2R1bGVzL3dlYmFkbWluL3NyYy9tYWluL2phdmEvb3JnL292 aXJ0L2VuZ2luZS91aS93ZWJhZG1pbi9wbHVnaW4vUGx1Z2luRXZlbnRIYW5kbGVyLmphdmEKKysr IGIvZnJvbnRlbmQvd2ViYWRtaW4vbW9kdWxlcy93ZWJhZG1pbi9zcmMvbWFpbi9qYXZhL29yZy9v dmlydC9lbmdpbmUvdWkvd2ViYWRtaW4vcGx1Z2luL1BsdWdpbkV2ZW50SGFuZGxlci5qYXZhCkBA IC0xOSw1ICsxOSw0IEBAIHB1YmxpYyBjbGFzcyBQbHVnaW5FdmVudEhhbmRsZXIgewogLy8gICAg ICAgICAgICB9CiAvLyAgICAgICAgfSk7CiAgICAgfQotCiB9CmRpZmYgLS1naXQgYS9mcm9udGVu ZC93ZWJhZG1pbi9tb2R1bGVzL3dlYmFkbWluL3NyYy9tYWluL3dlYmFwcC9XRUItSU5GL3dlYi54 bWwgYi9mcm9udGVuZC93ZWJhZG1pbi9tb2R1bGVzL3dlYmFkbWluL3NyYy9tYWluL3dlYmFwcC9X RUItSU5GL3dlYi54bWwKaW5kZXggZGJmOTNhMi4uMGVkNGNlOCAxMDA2NDQKLS0tIGEvZnJvbnRl bmQvd2ViYWRtaW4vbW9kdWxlcy93ZWJhZG1pbi9zcmMvbWFpbi93ZWJhcHAvV0VCLUlORi93ZWIu eG1sCisrKyBiL2Zyb250ZW5kL3dlYmFkbWluL21vZHVsZXMvd2ViYWRtaW4vc3JjL21haW4vd2Vi YXBwL1dFQi1JTkYvd2ViLnhtbApAQCAtMzIsNiArMzIsMTAgQEAKIAkJPHNlcnZsZXQtbmFtZT5Q bHVnaW5Tb3VyY2VQYWdlPC9zZXJ2bGV0LW5hbWU+CiAJCTx1cmwtcGF0dGVybj4vd2ViYWRtaW4v UGx1Z2luU291cmNlUGFnZTwvdXJsLXBhdHRlcm4+CiAJPC9zZXJ2bGV0LW1hcHBpbmc+CisJPHNl cnZsZXQtbWFwcGluZz4KKwkJPHNlcnZsZXQtbmFtZT5QbHVnaW5Tb3VyY2VQYWdlPC9zZXJ2bGV0 LW5hbWU+CisJCTx1cmwtcGF0dGVybj4vd2ViYWRtaW4vcGx1Z2luLyo8L3VybC1wYXR0ZXJuPgor CTwvc2VydmxldC1tYXBwaW5nPgogCiAJPCEtLSBEZWZhdWx0IHBhZ2UgdG8gc2VydmUgLS0+CiAJ PHdlbGNvbWUtZmlsZS1saXN0Pgo= --_005_A24D665DC3ECC245A2EA0D9A958F80B62C49123BG9W0745americas_--

--_005_A24D665DC3ECC245A2EA0D9A958F80B62C491334G9W0745americas_ Content-Type: multipart/alternative; boundary="_000_A24D665DC3ECC245A2EA0D9A958F80B62C491334G9W0745americas_" --_000_A24D665DC3ECC245A2EA0D9A958F80B62C491334G9W0745americas_ Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Vm9qdGVjaCwNCg0KSGVyZSBpcyBteSBwYXRjaCBhZ2FpbnN0IFdJUC1VSS1QbHVnaW5zLVBvQy1y ZXZpc2lvbi00LiAgSeKAmXZlIGFsc28gaW5jbHVkZWQgMiBkdW1teSBwbHVnaW5zIGluIHNhbXBs ZS50YXIuZ3ouDQoNCi0tQ2hyaXMNCg0KDQpGcm9tOiBlbmdpbmUtZGV2ZWwtYm91bmNlc0Bvdmly dC5vcmcgW21haWx0bzplbmdpbmUtZGV2ZWwtYm91bmNlc0BvdmlydC5vcmddIE9uIEJlaGFsZiBP ZiBGcmFudHosIENocmlzDQpTZW50OiBUaHVyc2RheSwgQXVndXN0IDMwLCAyMDEyIDE6MDYgUE0N ClRvOiBWb2p0ZWNoIFN6b2NzDQpDYzogZW5naW5lLWRldmVsDQpTdWJqZWN0OiBSZTogW0VuZ2lu ZS1kZXZlbF0gVUkgUGx1Z2lucyBjb25maWd1cmF0aW9uDQoNClZvanRlY2gsDQoNCkkgYWdyZWUg d2l0aCB5b3VyIGZvcm1hbGl6ZWQgbmFtZXM6DQoNClBsdWdpbiBEZXNjcmlwdG9yIGlzIHRoZSBK U09OIGZpbGUgY29udGFpbmluZyBwbHVnaW4gbWV0YS1kYXRhLiBUaGUgcGx1Z2luIGRlc2NyaXB0 b3IgbWF5IGFsc28gY29udGFpbiB0aGUgZGVmYXVsdCBjb25maWd1cmF0aW9uIGRhdGEuICAgSXQg aXMgbG9jYXRlZCBpbiAkREFUQURJUi91aS1wbHVnaW5zLg0KDQpQbHVnaW4gQ29uZmlndXJhdGlv biBpcyB0aGUgSlNPTiBmaWxlIGNvbnRhaW5pbmcgb3B0aW9uYWwgcGx1Z2luIGNvbmZpZ3VyYXRp b24gaW5mby4gIEl0IGlzIGxvY2F0ZWQgaW4gJENPTkZJR0RJUi91aS1wbHVnaW5zICh1bmxlc3Mg dGhlIFBsdWdpbiBEZXNjcmlwdG9yIGNvbnRhaW5zIGFuIGFic29sdXRlIHBhdGgpLg0KDQpQbHVn aW4gRGVmaW5pdGlvbiBpcyB0aGUgSmF2YVNjcmlwdCBvYmplY3QgdXNlZCBieSBXZWJBZG1pbi4g IEluIHRoZSBjdXJyZW50IGltcGxlbWVudGF0aW9uLCB0aGUgUGx1Z2luIERlZmluaXRpb24gY29u dGFpbnMgYm90aCB0aGUgUGx1Z2luIERlc2NyaXB0b3IgYW5kIHRoZSBQbHVnaW4gQ29uZmlndXJh aW9uLg0KDQpQbHVnaW4gU291cmNlIFBhZ2UgaXMgdGhlIEhUTUwgcGFnZSB1c2VkIHRvIGludm9r ZSB0aGUgcGx1Z2luIGNvZGUgYW5kIHNoYWxsIGJlIHJlZmVyZW5jZWQgYnkgdGhlIHBsdWdpbiBk ZXNjcmlwdG9y4oCZcyDigJx1cmzigJ0gYXR0cmlidXRlLg0KDQpJ4oCZdmUgaW1wbGVtZW50ZWQg dGhlIGNvbmZpZyBtZXJnaW5nIHlvdeKAmXZlIHN1Z2dlc3RlZDogIHRoZSBzdHJ1Y3R1cmUgaW4g Y29uZmlnRmlsZSBnZXRzIG1lcmdlZCB3aXRoIHRoZSBzdHJ1Y3R1cmUgb2Yg4oCcY29uZmln4oCd LCB3aXRoIHRoZSBkYXRhIGluIGNvbmZpZ0ZpbGUgd2lubmluZyBpbiB0aGUgY2FzZSBvZiBkdXBs aWNhdGUga2V5IG5hbWVzLg0KDQpCVFcsIHRoZSBwYXRjaCBpcyBhZ2FpbnN0IG92aXJ0LWVuZ2lu ZSArIDAwMDEtV0lQLVVJLVBsdWdpbnMtUG9DLXJldmlzaW9uLTIuDQoNCkxldCBtZSBrbm93IHdo YXQgeW91IHRoaW5rLA0KLS1DaHJpcw0KDQo= --_000_A24D665DC3ECC245A2EA0D9A958F80B62C491334G9W0745americas_ Content-Type: text/html; charset="utf-8" Content-Transfer-Encoding: base64 PGh0bWwgeG1sbnM6dj0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp2bWwiIHhtbG5zOm89InVy bjpzY2hlbWFzLW1pY3Jvc29mdC1jb206b2ZmaWNlOm9mZmljZSIgeG1sbnM6dz0idXJuOnNjaGVt YXMtbWljcm9zb2Z0LWNvbTpvZmZpY2U6d29yZCIgeG1sbnM6bT0iaHR0cDovL3NjaGVtYXMubWlj cm9zb2Z0LmNvbS9vZmZpY2UvMjAwNC8xMi9vbW1sIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv VFIvUkVDLWh0bWw0MCI+DQo8aGVhZD4NCjxtZXRhIGh0dHAtZXF1aXY9IkNvbnRlbnQtVHlwZSIg Y29udGVudD0idGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04Ij4NCjxtZXRhIG5hbWU9IkdlbmVyYXRv ciIgY29udGVudD0iTWljcm9zb2Z0IFdvcmQgMTIgKGZpbHRlcmVkIG1lZGl1bSkiPg0KPHN0eWxl PjwhLS0NCi8qIEZvbnQgRGVmaW5pdGlvbnMgKi8NCkBmb250LWZhY2UNCgl7Zm9udC1mYW1pbHk6 IkNhbWJyaWEgTWF0aCI7DQoJcGFub3NlLTE6MiA0IDUgMyA1IDQgNiAzIDIgNDt9DQpAZm9udC1m YWNlDQoJe2ZvbnQtZmFtaWx5OkNhbGlicmk7DQoJcGFub3NlLTE6MiAxNSA1IDIgMiAyIDQgMyAy IDQ7fQ0KQGZvbnQtZmFjZQ0KCXtmb250LWZhbWlseTpUYWhvbWE7DQoJcGFub3NlLTE6MiAxMSA2 IDQgMyA1IDQgNCAyIDQ7fQ0KLyogU3R5bGUgRGVmaW5pdGlvbnMgKi8NCnAuTXNvTm9ybWFsLCBs aS5Nc29Ob3JtYWwsIGRpdi5Nc29Ob3JtYWwNCgl7bWFyZ2luOjBpbjsNCgltYXJnaW4tYm90dG9t Oi4wMDAxcHQ7DQoJZm9udC1zaXplOjEyLjBwdDsNCglmb250LWZhbWlseToiVGltZXMgTmV3IFJv bWFuIiwic2VyaWYiO30NCmE6bGluaywgc3Bhbi5Nc29IeXBlcmxpbmsNCgl7bXNvLXN0eWxlLXBy aW9yaXR5Ojk5Ow0KCWNvbG9yOmJsdWU7DQoJdGV4dC1kZWNvcmF0aW9uOnVuZGVybGluZTt9DQph OnZpc2l0ZWQsIHNwYW4uTXNvSHlwZXJsaW5rRm9sbG93ZWQNCgl7bXNvLXN0eWxlLXByaW9yaXR5 Ojk5Ow0KCWNvbG9yOnB1cnBsZTsNCgl0ZXh0LWRlY29yYXRpb246dW5kZXJsaW5lO30NCnANCgl7 bXNvLXN0eWxlLXByaW9yaXR5Ojk5Ow0KCW1hcmdpbjowaW47DQoJbWFyZ2luLWJvdHRvbTouMDAw MXB0Ow0KCWZvbnQtc2l6ZToxMi4wcHQ7DQoJZm9udC1mYW1pbHk6IlRpbWVzIE5ldyBSb21hbiIs InNlcmlmIjt9DQpwLk1zb0FjZXRhdGUsIGxpLk1zb0FjZXRhdGUsIGRpdi5Nc29BY2V0YXRlDQoJ e21zby1zdHlsZS1wcmlvcml0eTo5OTsNCgltc28tc3R5bGUtbGluazoiQmFsbG9vbiBUZXh0IENo YXIiOw0KCW1hcmdpbjowaW47DQoJbWFyZ2luLWJvdHRvbTouMDAwMXB0Ow0KCWZvbnQtc2l6ZTo4 LjBwdDsNCglmb250LWZhbWlseToiVGFob21hIiwic2Fucy1zZXJpZiI7fQ0Kc3Bhbi5CYWxsb29u VGV4dENoYXINCgl7bXNvLXN0eWxlLW5hbWU6IkJhbGxvb24gVGV4dCBDaGFyIjsNCgltc28tc3R5 bGUtcHJpb3JpdHk6OTk7DQoJbXNvLXN0eWxlLWxpbms6IkJhbGxvb24gVGV4dCI7DQoJZm9udC1m YW1pbHk6IlRhaG9tYSIsInNhbnMtc2VyaWYiO30NCnNwYW4uRW1haWxTdHlsZTIwDQoJe21zby1z dHlsZS10eXBlOnBlcnNvbmFsOw0KCWZvbnQtZmFtaWx5OiJDYWxpYnJpIiwic2Fucy1zZXJpZiI7 DQoJY29sb3I6IzFGNDk3RDt9DQpzcGFuLkVtYWlsU3R5bGUyMQ0KCXttc28tc3R5bGUtdHlwZTpw ZXJzb25hbDsNCglmb250LWZhbWlseToiQ2FsaWJyaSIsInNhbnMtc2VyaWYiOw0KCWNvbG9yOiMx RjQ5N0Q7fQ0Kc3Bhbi5FbWFpbFN0eWxlMjQNCgl7bXNvLXN0eWxlLXR5cGU6cGVyc29uYWwtcmVw bHk7DQoJZm9udC1mYW1pbHk6IkNhbGlicmkiLCJzYW5zLXNlcmlmIjsNCgljb2xvcjojMUY0OTdE O30NCi5Nc29DaHBEZWZhdWx0DQoJe21zby1zdHlsZS10eXBlOmV4cG9ydC1vbmx5Ow0KCWZvbnQt c2l6ZToxMC4wcHQ7fQ0KQHBhZ2UgV29yZFNlY3Rpb24xDQoJe3NpemU6OC41aW4gMTEuMGluOw0K CW1hcmdpbjoxLjBpbiAxLjBpbiAxLjBpbiAxLjBpbjt9DQpkaXYuV29yZFNlY3Rpb24xDQoJe3Bh Z2U6V29yZFNlY3Rpb24xO30NCi8qIExpc3QgRGVmaW5pdGlvbnMgKi8NCkBsaXN0IGwwDQoJe21z by1saXN0LWlkOjE4OTg4MjU2MDsNCgltc28tbGlzdC10ZW1wbGF0ZS1pZHM6LTE3NDU2MzQ3Njt9 DQpAbGlzdCBsMDpsZXZlbDENCgl7bXNvLWxldmVsLXRhYi1zdG9wOi41aW47DQoJbXNvLWxldmVs LW51bWJlci1wb3NpdGlvbjpsZWZ0Ow0KCXRleHQtaW5kZW50Oi0uMjVpbjt9DQpAbGlzdCBsMDps ZXZlbDINCgl7bXNvLWxldmVsLXRhYi1zdG9wOjEuMGluOw0KCW1zby1sZXZlbC1udW1iZXItcG9z aXRpb246bGVmdDsNCgl0ZXh0LWluZGVudDotLjI1aW47fQ0KQGxpc3QgbDA6bGV2ZWwzDQoJe21z by1sZXZlbC10YWItc3RvcDoxLjVpbjsNCgltc28tbGV2ZWwtbnVtYmVyLXBvc2l0aW9uOmxlZnQ7 DQoJdGV4dC1pbmRlbnQ6LS4yNWluO30NCkBsaXN0IGwwOmxldmVsNA0KCXttc28tbGV2ZWwtdGFi LXN0b3A6Mi4waW47DQoJbXNvLWxldmVsLW51bWJlci1wb3NpdGlvbjpsZWZ0Ow0KCXRleHQtaW5k ZW50Oi0uMjVpbjt9DQpAbGlzdCBsMDpsZXZlbDUNCgl7bXNvLWxldmVsLXRhYi1zdG9wOjIuNWlu Ow0KCW1zby1sZXZlbC1udW1iZXItcG9zaXRpb246bGVmdDsNCgl0ZXh0LWluZGVudDotLjI1aW47 fQ0KQGxpc3QgbDA6bGV2ZWw2DQoJe21zby1sZXZlbC10YWItc3RvcDozLjBpbjsNCgltc28tbGV2 ZWwtbnVtYmVyLXBvc2l0aW9uOmxlZnQ7DQoJdGV4dC1pbmRlbnQ6LS4yNWluO30NCkBsaXN0IGww OmxldmVsNw0KCXttc28tbGV2ZWwtdGFiLXN0b3A6My41aW47DQoJbXNvLWxldmVsLW51bWJlci1w b3NpdGlvbjpsZWZ0Ow0KCXRleHQtaW5kZW50Oi0uMjVpbjt9DQpAbGlzdCBsMDpsZXZlbDgNCgl7 bXNvLWxldmVsLXRhYi1zdG9wOjQuMGluOw0KCW1zby1sZXZlbC1udW1iZXItcG9zaXRpb246bGVm dDsNCgl0ZXh0LWluZGVudDotLjI1aW47fQ0KQGxpc3QgbDA6bGV2ZWw5DQoJe21zby1sZXZlbC10 YWItc3RvcDo0LjVpbjsNCgltc28tbGV2ZWwtbnVtYmVyLXBvc2l0aW9uOmxlZnQ7DQoJdGV4dC1p bmRlbnQ6LS4yNWluO30NCkBsaXN0IGwxDQoJe21zby1saXN0LWlkOjQxMjgyNDQ5ODsNCgltc28t bGlzdC10ZW1wbGF0ZS1pZHM6LTc0NTEwNTE3NDt9DQpvbA0KCXttYXJnaW4tYm90dG9tOjBpbjt9 DQp1bA0KCXttYXJnaW4tYm90dG9tOjBpbjt9DQotLT48L3N0eWxlPjwhLS1baWYgZ3RlIG1zbyA5 XT48eG1sPg0KPG86c2hhcGVkZWZhdWx0cyB2OmV4dD0iZWRpdCIgc3BpZG1heD0iMTAyNiIgLz4N CjwveG1sPjwhW2VuZGlmXS0tPjwhLS1baWYgZ3RlIG1zbyA5XT48eG1sPg0KPG86c2hhcGVsYXlv dXQgdjpleHQ9ImVkaXQiPg0KPG86aWRtYXAgdjpleHQ9ImVkaXQiIGRhdGE9IjEiIC8+DQo8L286 c2hhcGVsYXlvdXQ+PC94bWw+PCFbZW5kaWZdLS0+DQo8L2hlYWQ+DQo8Ym9keSBsYW5nPSJFTi1V UyIgbGluaz0iYmx1ZSIgdmxpbms9InB1cnBsZSI+DQo8ZGl2IGNsYXNzPSJXb3JkU2VjdGlvbjEi Pg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7Zm9u dC1mYW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90OywmcXVvdDtzYW5zLXNlcmlmJnF1b3Q7O2NvbG9y OiMxRjQ5N0QiPlZvanRlY2gsPG86cD48L286cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05v cm1hbCI+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7Zm9udC1mYW1pbHk6JnF1b3Q7Q2Fs aWJyaSZxdW90OywmcXVvdDtzYW5zLXNlcmlmJnF1b3Q7O2NvbG9yOiMxRjQ5N0QiPjxvOnA+Jm5i c3A7PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFuIHN0eWxlPSJm b250LXNpemU6MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGlicmkmcXVvdDssJnF1b3Q7c2Fu cy1zZXJpZiZxdW90Oztjb2xvcjojMUY0OTdEIj5IZXJlIGlzIG15IHBhdGNoIGFnYWluc3QgV0lQ LVVJLVBsdWdpbnMtUG9DLXJldmlzaW9uLTQuJm5ic3A7IEnigJl2ZSBhbHNvIGluY2x1ZGVkIDIg ZHVtbXkgcGx1Z2lucyBpbiBzYW1wbGUudGFyLmd6LjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCjxw IGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTEuMHB0O2ZvbnQtZmFt aWx5OiZxdW90O0NhbGlicmkmcXVvdDssJnF1b3Q7c2Fucy1zZXJpZiZxdW90Oztjb2xvcjojMUY0 OTdEIj48bzpwPiZuYnNwOzwvbzpwPjwvc3Bhbj48L3A+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48 c3BhbiBzdHlsZT0iZm9udC1zaXplOjExLjBwdDtmb250LWZhbWlseTomcXVvdDtDYWxpYnJpJnF1 b3Q7LCZxdW90O3NhbnMtc2VyaWYmcXVvdDs7Y29sb3I6IzFGNDk3RCI+LS1DaHJpczxvOnA+PC9v OnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFuIHN0eWxlPSJmb250LXNp emU6MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGlicmkmcXVvdDssJnF1b3Q7c2Fucy1zZXJp ZiZxdW90Oztjb2xvcjojMUY0OTdEIj48bzpwPiZuYnNwOzwvbzpwPjwvc3Bhbj48L3A+DQo8cCBj bGFzcz0iTXNvTm9ybWFsIj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjExLjBwdDtmb250LWZhbWls eTomcXVvdDtDYWxpYnJpJnF1b3Q7LCZxdW90O3NhbnMtc2VyaWYmcXVvdDs7Y29sb3I6IzFGNDk3 RCI+PG86cD4mbmJzcDs8L286cD48L3NwYW4+PC9wPg0KPGRpdj4NCjxkaXYgc3R5bGU9ImJvcmRl cjpub25lO2JvcmRlci10b3A6c29saWQgI0I1QzRERiAxLjBwdDtwYWRkaW5nOjMuMHB0IDBpbiAw aW4gMGluIj4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6 MTAuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O1RhaG9tYSZxdW90OywmcXVvdDtzYW5zLXNlcmlmJnF1 b3Q7Ij5Gcm9tOjwvc3Bhbj48L2I+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMC4wcHQ7Zm9udC1m YW1pbHk6JnF1b3Q7VGFob21hJnF1b3Q7LCZxdW90O3NhbnMtc2VyaWYmcXVvdDsiPiBlbmdpbmUt ZGV2ZWwtYm91bmNlc0BvdmlydC5vcmcgW21haWx0bzplbmdpbmUtZGV2ZWwtYm91bmNlc0Bvdmly dC5vcmddDQo8Yj5PbiBCZWhhbGYgT2YgPC9iPkZyYW50eiwgQ2hyaXM8YnI+DQo8Yj5TZW50Ojwv Yj4gVGh1cnNkYXksIEF1Z3VzdCAzMCwgMjAxMiAxOjA2IFBNPGJyPg0KPGI+VG86PC9iPiBWb2p0 ZWNoIFN6b2NzPGJyPg0KPGI+Q2M6PC9iPiBlbmdpbmUtZGV2ZWw8YnI+DQo8Yj5TdWJqZWN0Ojwv Yj4gUmU6IFtFbmdpbmUtZGV2ZWxdIFVJIFBsdWdpbnMgY29uZmlndXJhdGlvbjxvOnA+PC9vOnA+ PC9zcGFuPjwvcD4NCjwvZGl2Pg0KPC9kaXY+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48bzpwPiZu YnNwOzwvbzpwPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFuIHN0eWxlPSJmb250LXNp emU6MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGlicmkmcXVvdDssJnF1b3Q7c2Fucy1zZXJp ZiZxdW90Oztjb2xvcjojMUY0OTdEIj5Wb2p0ZWNoLDxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCjxw IGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTEuMHB0O2ZvbnQtZmFt aWx5OiZxdW90O0NhbGlicmkmcXVvdDssJnF1b3Q7c2Fucy1zZXJpZiZxdW90Oztjb2xvcjojMUY0 OTdEIj48bzpwPiZuYnNwOzwvbzpwPjwvc3Bhbj48L3A+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48 c3BhbiBzdHlsZT0iZm9udC1zaXplOjExLjBwdDtmb250LWZhbWlseTomcXVvdDtDYWxpYnJpJnF1 b3Q7LCZxdW90O3NhbnMtc2VyaWYmcXVvdDs7Y29sb3I6IzFGNDk3RCI+SSBhZ3JlZSB3aXRoIHlv dXIgZm9ybWFsaXplZCBuYW1lczo8bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQo8cCBjbGFzcz0iTXNv Tm9ybWFsIj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjExLjBwdDtmb250LWZhbWlseTomcXVvdDtD YWxpYnJpJnF1b3Q7LCZxdW90O3NhbnMtc2VyaWYmcXVvdDs7Y29sb3I6IzFGNDk3RCI+PG86cD4m bmJzcDs8L286cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PGk+PHNwYW4gc3R5 bGU9ImZvbnQtc2l6ZToxMS4wcHQ7Zm9udC1mYW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90OywmcXVv dDtzYW5zLXNlcmlmJnF1b3Q7O2NvbG9yOiMxRjQ5N0QiPlBsdWdpbiBEZXNjcmlwdG9yPC9zcGFu PjwvaT48c3BhbiBzdHlsZT0iZm9udC1zaXplOjExLjBwdDtmb250LWZhbWlseTomcXVvdDtDYWxp YnJpJnF1b3Q7LCZxdW90O3NhbnMtc2VyaWYmcXVvdDs7Y29sb3I6IzFGNDk3RCI+IGlzIHRoZSBK U09OIGZpbGUgY29udGFpbmluZyBwbHVnaW4gbWV0YS1kYXRhLg0KIFRoZSBwbHVnaW4gZGVzY3Jp cHRvciBtYXkgYWxzbyBjb250YWluIHRoZSBkZWZhdWx0IGNvbmZpZ3VyYXRpb24gZGF0YS4mbmJz cDsgJm5ic3A7SXQgaXMgbG9jYXRlZCBpbiAkREFUQURJUi91aS1wbHVnaW5zLjxvOnA+PC9vOnA+ PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6 MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGlicmkmcXVvdDssJnF1b3Q7c2Fucy1zZXJpZiZx dW90Oztjb2xvcjojMUY0OTdEIj48bzpwPiZuYnNwOzwvbzpwPjwvc3Bhbj48L3A+DQo8cCBjbGFz cz0iTXNvTm9ybWFsIj48aT48c3BhbiBzdHlsZT0iZm9udC1zaXplOjExLjBwdDtmb250LWZhbWls eTomcXVvdDtDYWxpYnJpJnF1b3Q7LCZxdW90O3NhbnMtc2VyaWYmcXVvdDs7Y29sb3I6IzFGNDk3 RCI+UGx1Z2luIENvbmZpZ3VyYXRpb248L3NwYW4+PC9pPjxzcGFuIHN0eWxlPSJmb250LXNpemU6 MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGlicmkmcXVvdDssJnF1b3Q7c2Fucy1zZXJpZiZx dW90Oztjb2xvcjojMUY0OTdEIj4gaXMgdGhlIEpTT04gZmlsZSBjb250YWluaW5nIG9wdGlvbmFs IHBsdWdpbg0KIGNvbmZpZ3VyYXRpb24gaW5mby4mbmJzcDsgSXQgaXMgbG9jYXRlZCBpbiAkQ09O RklHRElSL3VpLXBsdWdpbnMgKHVubGVzcyB0aGUgUGx1Z2luIERlc2NyaXB0b3IgY29udGFpbnMg YW4gYWJzb2x1dGUgcGF0aCkuPG86cD48L286cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05v cm1hbCI+PGk+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7Zm9udC1mYW1pbHk6JnF1b3Q7 Q2FsaWJyaSZxdW90OywmcXVvdDtzYW5zLXNlcmlmJnF1b3Q7O2NvbG9yOiMxRjQ5N0QiPjxvOnA+ Jm5ic3A7PC9vOnA+PC9zcGFuPjwvaT48L3A+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48aT48c3Bh biBzdHlsZT0iZm9udC1zaXplOjExLjBwdDtmb250LWZhbWlseTomcXVvdDtDYWxpYnJpJnF1b3Q7 LCZxdW90O3NhbnMtc2VyaWYmcXVvdDs7Y29sb3I6IzFGNDk3RCI+UGx1Z2luIERlZmluaXRpb248 L3NwYW4+PC9pPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90 O0NhbGlicmkmcXVvdDssJnF1b3Q7c2Fucy1zZXJpZiZxdW90Oztjb2xvcjojMUY0OTdEIj4gaXMg dGhlIEphdmFTY3JpcHQgb2JqZWN0IHVzZWQgYnkgV2ViQWRtaW4uJm5ic3A7DQogSW4gdGhlIGN1 cnJlbnQgaW1wbGVtZW50YXRpb24sIHRoZSBQbHVnaW4gRGVmaW5pdGlvbiBjb250YWlucyBib3Ro IHRoZSBQbHVnaW4gRGVzY3JpcHRvciBhbmQgdGhlIFBsdWdpbiBDb25maWd1cmFpb24uPG86cD48 L286cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNwYW4gc3R5bGU9ImZvbnQt c2l6ZToxMS4wcHQ7Zm9udC1mYW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90OywmcXVvdDtzYW5zLXNl cmlmJnF1b3Q7O2NvbG9yOiMxRjQ5N0QiPjxvOnA+Jm5ic3A7PC9vOnA+PC9zcGFuPjwvcD4NCjxw IGNsYXNzPSJNc29Ob3JtYWwiPjxpPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTEuMHB0O2ZvbnQt ZmFtaWx5OiZxdW90O0NhbGlicmkmcXVvdDssJnF1b3Q7c2Fucy1zZXJpZiZxdW90Oztjb2xvcjoj MUY0OTdEIj5QbHVnaW4gU291cmNlIFBhZ2U8L3NwYW4+PC9pPjxzcGFuIHN0eWxlPSJmb250LXNp emU6MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGlicmkmcXVvdDssJnF1b3Q7c2Fucy1zZXJp ZiZxdW90Oztjb2xvcjojMUY0OTdEIj4gaXMgdGhlIEhUTUwgcGFnZSB1c2VkIHRvIGludm9rZSB0 aGUgcGx1Z2luDQogY29kZSBhbmQgc2hhbGwgYmUgcmVmZXJlbmNlZCBieSB0aGUgcGx1Z2luIGRl c2NyaXB0b3LigJlzIOKAnHVybOKAnSBhdHRyaWJ1dGUuPG86cD48L286cD48L3NwYW4+PC9wPg0K PHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7Zm9udC1m YW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90OywmcXVvdDtzYW5zLXNlcmlmJnF1b3Q7O2NvbG9yOiMx RjQ5N0QiPjxvOnA+Jm5ic3A7PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwi PjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTEuMHB0O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGlicmkm cXVvdDssJnF1b3Q7c2Fucy1zZXJpZiZxdW90Oztjb2xvcjojMUY0OTdEIj5J4oCZdmUgaW1wbGVt ZW50ZWQgdGhlIGNvbmZpZyBtZXJnaW5nIHlvdeKAmXZlIHN1Z2dlc3RlZDombmJzcDsgdGhlIHN0 cnVjdHVyZSBpbiBjb25maWdGaWxlIGdldHMgbWVyZ2VkIHdpdGggdGhlIHN0cnVjdHVyZSBvZiDi gJxjb25maWfigJ0sIHdpdGggdGhlIGRhdGEgaW4gY29uZmlnRmlsZSB3aW5uaW5nDQogaW4gdGhl IGNhc2Ugb2YgZHVwbGljYXRlIGtleSBuYW1lcy48bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQo8cCBj bGFzcz0iTXNvTm9ybWFsIj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjExLjBwdDtmb250LWZhbWls eTomcXVvdDtDYWxpYnJpJnF1b3Q7LCZxdW90O3NhbnMtc2VyaWYmcXVvdDs7Y29sb3I6IzFGNDk3 RCI+PG86cD4mbmJzcDs8L286cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNw YW4gc3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7Zm9udC1mYW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90 OywmcXVvdDtzYW5zLXNlcmlmJnF1b3Q7O2NvbG9yOiMxRjQ5N0QiPkJUVywgdGhlIHBhdGNoIGlz IGFnYWluc3Qgb3ZpcnQtZW5naW5lICYjNDM7IDAwMDEtV0lQLVVJLVBsdWdpbnMtUG9DLXJldmlz aW9uLTIuPG86cD48L286cD48L3NwYW4+PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNwYW4g c3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7Zm9udC1mYW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90Oywm cXVvdDtzYW5zLXNlcmlmJnF1b3Q7O2NvbG9yOiMxRjQ5N0QiPjxvOnA+Jm5ic3A7PC9vOnA+PC9z cGFuPjwvcD4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTEu MHB0O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGlicmkmcXVvdDssJnF1b3Q7c2Fucy1zZXJpZiZxdW90 Oztjb2xvcjojMUY0OTdEIj5MZXQgbWUga25vdyB3aGF0IHlvdSB0aGluayw8bzpwPjwvbzpwPjwv c3Bhbj48L3A+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48c3BhbiBzdHlsZT0iZm9udC1zaXplOjEx LjBwdDtmb250LWZhbWlseTomcXVvdDtDYWxpYnJpJnF1b3Q7LCZxdW90O3NhbnMtc2VyaWYmcXVv dDs7Y29sb3I6IzFGNDk3RCI+LS1DaHJpczxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCjxkaXY+DQo8 cCBjbGFzcz0iTXNvTm9ybWFsIj48c3BhbiBzdHlsZT0iY29sb3I6YmxhY2siPjxvOnA+Jm5ic3A7 PC9vOnA+PC9zcGFuPjwvcD4NCjwvZGl2Pg0KPC9kaXY+DQo8L2JvZHk+DQo8L2h0bWw+DQo= --_000_A24D665DC3ECC245A2EA0D9A958F80B62C491334G9W0745americas_-- --_005_A24D665DC3ECC245A2EA0D9A958F80B62C491334G9W0745americas_ Content-Type: application/x-gzip; name="sample.tar.gz" Content-Description: sample.tar.gz Content-Disposition: attachment; filename="sample.tar.gz"; size=1250; creation-date="Thu, 30 Aug 2012 18:03:12 GMT"; modification-date="Thu, 30 Aug 2012 20:01:28 GMT" Content-Transfer-Encoding: base64 H4sIAJzGP1AAA+2ZW2/bNhTH8xp/ihO92AFsS7J8Gby4QNGuQIGuKdYUwzb0gZFoi6ksqiRlxy36 3XcoybGbSx03ibN25/dg0ke8WYc5/0Mm18rVMVPclTOhTIunE5FyNxetLMmxqt29O+Mhg16vKJHL ZVH3O54/GHQ7nW53z/P7/qC7B727T72ZXBumAPaUlOZb7TY9/0HJN/rfcG3aZ1qm3z2HdXDf+vV6 //t+EHzt/47nYQHePf7OG/mf+/9zDRDXhTeFu+E1m/LC5KRYc4bgWP87zdI240oLmVqz3/bQuuyd qwR0xkMxFlxDLOdgJCSSRWBiDuVWAvumDWRsUs2AnexI7pyfsmgq0lWl7FBsPbfo1Y7NNFmbL2Mm XptwHnPFwVnr5oDiLEkWkIgZ1+V8tlMxocyMG2euivlsWu3ztbFPcMURH7M8McuVhzIdi0mumMFf Xw5WmnC48g2WE0hl0OJ3gm5zzRorpotX+Rrfi9DFKzFiymEsFeAiYSJlBFOe2pcWSnyApW3ERARy bKtC4YM8NWqBC913JkrmmcYh/3Hsav+MpdOEovpcSqWXX/6QSSLSCbw1MuWF9RWP4G+eZRztDrxf W6XmTIXxu9IlsTHZ0HXn83l7wWIp27gq1ykaf2mu//4XIrnYJK3SVMQKp/al9thbm7gFm+P/GN1/ p/C/Mf57fX8Z//2ezRP8Qb9H8X8nbI7/6P9HCv848wNGfxydYv+WsZ+i+s8GN+EDnvxKtjj/eUHP nv96XkDnv53wLf9fTuq+d44N+u8Fg97X/sd6r0/6vws+1/ZR9o5R2ZWIeCV2bStmV6St1x/80ry+ eaFyqE0rubMS9DEX4Qc4VXKeotydw1k+zVCDJPYuJC5hnxYQyYnVXzvs0ygCBimfV+OCMHxqR8UU QIQJL0UvUxIlzQoaT7hRZTXleVF9b4e6Uc9QaycJrwSNtMxSJUMPOscW8d/vBj7Gfw8PABT/d8E1 VyH3vhm28H/gewH6P+iiify/A67z/+rMdT9zFPrfL/TfH/S89bK8/+34l/zf73c6O9b/cKxYaj7d 2G7T8x+Uo4Pnx89O/nrzG1h/P6kdLQvOIiwOWq1aqwXPZJ5EKNXLM3HEM55GPA3t8ZtpPOqHxXFb czVDhVdcy1yFePLGvkc6VCIzYBYZHzmGnxv3jM1YaXVAq3C06Qr47GPO1aKFZsxDnSdHbtn5CQ6P a1x+mYs0kvM2S7gyjfrLdCY/2AMwC03OktVpHtOWhh21shwe1A9/rc1wD0wX1R3ICDDj4Klply2e ZqJRtz3qh0W7KjkZXXRol5bj0zMemgaOVrt4ovhEaMNVA/Osd+JlKswQxnka2ruExiGgdf+ibS7a LIp+ZyI9YaeN+tsiiQGs15tQZ4y1TFGtcq6LHAfn299Ho5aY2iRy0iguY4dQTteu2o+cZU/bHg/y WKytkkULu/DVmz1yVzsAZmI6BKNHXdDl5xw/+HnG0gjXNCzd4JY757E3NLEVVy7DHiAV3EL/O4OO zf8Crzsg/d8FV/1/3+p/C/33g0v+72NJ+r8L/uv6b/8HcM/yfwANHHUp/7dSf2y/W/F/gQuslN/+ ad5W+bHtSvhJ+QmCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAiCIAjiJ+NfD8RevgBQAAA= --_005_A24D665DC3ECC245A2EA0D9A958F80B62C491334G9W0745americas_ Content-Type: application/octet-stream; name="UI-Plugins-Config-4.patch" Content-Description: UI-Plugins-Config-4.patch Content-Disposition: attachment; filename="UI-Plugins-Config-4.patch"; size=17270; creation-date="Thu, 30 Aug 2012 19:41:16 GMT"; modification-date="Thu, 30 Aug 2012 19:41:16 GMT" Content-Transfer-Encoding: base64 ZGlmZiAtLWdpdCBhL2JhY2tlbmQvbWFuYWdlci9tb2R1bGVzL2NvbW1vbi9zcmMvbWFpbi9qYXZh L29yZy9vdmlydC9lbmdpbmUvY29yZS9jb21tb24vY29uZmlnL0NvbmZpZy5qYXZhIGIvYmFja2Vu ZC9tYW5hZ2VyL21vZHVsZXMvY29tbW9uL3NyYy9tYWluL2phdmEvb3JnL292aXJ0L2VuZ2luZS9j b3JlL2NvbW1vbi9jb25maWcvQ29uZmlnLmphdmEKaW5kZXggZDY4MjVjNy4uNTA2NDg1MCAxMDA2 NDQKLS0tIGEvYmFja2VuZC9tYW5hZ2VyL21vZHVsZXMvY29tbW9uL3NyYy9tYWluL2phdmEvb3Jn L292aXJ0L2VuZ2luZS9jb3JlL2NvbW1vbi9jb25maWcvQ29uZmlnLmphdmEKKysrIGIvYmFja2Vu ZC9tYW5hZ2VyL21vZHVsZXMvY29tbW9uL3NyYy9tYWluL2phdmEvb3JnL292aXJ0L2VuZ2luZS9j b3JlL2NvbW1vbi9jb25maWcvQ29uZmlnLmphdmEKQEAgLTk2LDQgKzk2LDI1IEBAIHB1YmxpYyBm aW5hbCBjbGFzcyBDb25maWcgewogICAgICAgICByZXR1cm4gQ29uZmlnVXRpbC5yZXNvbHZlUGF0 aChyZXNvbHZlQ0FCYXNlUGF0aCgpLCBDb25maWcuPFN0cmluZz4gR2V0VmFsdWUoQ29uZmlnVmFs dWVzLlRydXN0c3RvcmVVcmwpKTsKICAgICB9CiAKKyAgICAvKioKKyAgICAgKiBGZXRjaCB0aGUg b1ZpcnRVaVBsdWdpbnNQYXRoIGNvbmZpZ3VyYXRpb24gdmFsdWUgYW5kLCBpZiBpdCBpcyBub3Qg YW4gYWJzb2x1dGUgcGF0aCwgcmVzb2x2ZSBpdCByZWxhdGl2ZSB0bworICAgICAqIHRoZSBEYXRh RGlyIGNvbmZpZ3VyYXRpb24gdmFsdWUuCisgICAgICoKKyAgICAgKiBAcmV0dXJuIGFuIGFic29s dXRlIHBhdGggZm9yIG9WaXJ0VWlQbHVnaW5zUGF0aAorICAgICAqLworICAgIHB1YmxpYyBzdGF0 aWMgU3RyaW5nIHJlc29sdmVPVmlydFVpUGx1Z2luc1BhdGgoKSB7CisgICAgICAgIHJldHVybiBD b25maWdVdGlsLnJlc29sdmVQYXRoKENvbmZpZy48U3RyaW5nPiBHZXRWYWx1ZShDb25maWdWYWx1 ZXMuRGF0YURpciksCisgICAgICAgICAgICAgICAgQ29uZmlnLjxTdHJpbmc+IEdldFZhbHVlKENv bmZpZ1ZhbHVlcy5VaVBsdWdpbnNQYXRoKSk7CisgICAgfQorCisgICAgLyoqCisgICAgICogRXhh bWluZSB0aGUgZ2l2ZW4gZmlsZW5hbWUgYW5kIGlmIGl0IGlzIG5vdCBhbiBhYnNvbHV0ZSBwYXRo LCByZXNvbHZlIGl0IHJlbGF0aXZlIHRvIHRoZSBvVmlydFVpUGx1Z2luc1BhdGgKKyAgICAgKgor ICAgICAqIEByZXR1cm4gYW4gYWJzb2x1dGUgcGF0aCBmb3IgdGhlIFVpUGx1Z2luQ29uZmlnRmls ZQorICAgICAqLworICAgIHB1YmxpYyBzdGF0aWMgU3RyaW5nIHJlc29sdmVPVmlydFVpUGx1Z2lu Q29uZmlnRmlsZShTdHJpbmcgZmlsZW5hbWUpIHsKKyAgICAgICAgU3RyaW5nIHBhdGggPSBDb25m aWdVdGlsLnJlc29sdmVQYXRoKENvbmZpZy48U3RyaW5nPiBHZXRWYWx1ZShDb25maWdWYWx1ZXMu Q29uZmlnRGlyKSwKKyAgICAgICAgICAgICAgICBDb25maWcuPFN0cmluZz4gR2V0VmFsdWUoQ29u ZmlnVmFsdWVzLlVpUGx1Z2luc1BhdGgpKTsKKyAgICAgICAgcmV0dXJuIENvbmZpZ1V0aWwucmVz b2x2ZVBhdGgocGF0aCwgZmlsZW5hbWUpOworICAgIH0KIH0KZGlmZiAtLWdpdCBhL2JhY2tlbmQv bWFuYWdlci9tb2R1bGVzL2NvbW1vbi9zcmMvbWFpbi9qYXZhL29yZy9vdmlydC9lbmdpbmUvY29y ZS9jb21tb24vY29uZmlnL0NvbmZpZ1ZhbHVlcy5qYXZhIGIvYmFja2VuZC9tYW5hZ2VyL21vZHVs ZXMvY29tbW9uL3NyYy9tYWluL2phdmEvb3JnL292aXJ0L2VuZ2luZS9jb3JlL2NvbW1vbi9jb25m aWcvQ29uZmlnVmFsdWVzLmphdmEKaW5kZXggNDk0YWM3MS4uNWM2ODVkOCAxMDA2NDQKLS0tIGEv YmFja2VuZC9tYW5hZ2VyL21vZHVsZXMvY29tbW9uL3NyYy9tYWluL2phdmEvb3JnL292aXJ0L2Vu Z2luZS9jb3JlL2NvbW1vbi9jb25maWcvQ29uZmlnVmFsdWVzLmphdmEKKysrIGIvYmFja2VuZC9t YW5hZ2VyL21vZHVsZXMvY29tbW9uL3NyYy9tYWluL2phdmEvb3JnL292aXJ0L2VuZ2luZS9jb3Jl L2NvbW1vbi9jb25maWcvQ29uZmlnVmFsdWVzLmphdmEKQEAgLTE0NDIsNiArMTQ0MiwxMCBAQCBw dWJsaWMgZW51bSBDb25maWdWYWx1ZXMgewogICAgIEBEZWZhdWx0VmFsdWVBdHRyaWJ1dGUoIm92 aXJ0LWVuZ2luZSIpCiAgICAgU1NIS2V5QWxpYXMoMzc3KSwKIAorICAgIEBUeXBlQ29udmVydGVy QXR0cmlidXRlKFN0cmluZy5jbGFzcykKKyAgICBARGVmYXVsdFZhbHVlQXR0cmlidXRlKCJ1aS1w bHVnaW5zIikKKyAgICBVaVBsdWdpbnNQYXRoKDM3OCksCisKICAgICBJbnZhbGlkKDY1NTM1KTsK IAogICAgIHByaXZhdGUgaW50IGludFZhbHVlOwpkaWZmIC0tZ2l0IGEvZnJvbnRlbmQvd2ViYWRt aW4vbW9kdWxlcy9mcm9udGVuZC9zcmMvbWFpbi9qYXZhL29yZy9vdmlydC9lbmdpbmUvdWkvZnJv bnRlbmQvc2VydmVyL2d3dC9QbHVnaW5Tb3VyY2VQYWdlU2VydmxldC5qYXZhIGIvZnJvbnRlbmQv d2ViYWRtaW4vbW9kdWxlcy9mcm9udGVuZC9zcmMvbWFpbi9qYXZhL29yZy9vdmlydC9lbmdpbmUv dWkvZnJvbnRlbmQvc2VydmVyL2d3dC9QbHVnaW5Tb3VyY2VQYWdlU2VydmxldC5qYXZhCmluZGV4 IDE1OWZhZDguLmUzNGZiYTQgMTAwNjQ0Ci0tLSBhL2Zyb250ZW5kL3dlYmFkbWluL21vZHVsZXMv ZnJvbnRlbmQvc3JjL21haW4vamF2YS9vcmcvb3ZpcnQvZW5naW5lL3VpL2Zyb250ZW5kL3NlcnZl ci9nd3QvUGx1Z2luU291cmNlUGFnZVNlcnZsZXQuamF2YQorKysgYi9mcm9udGVuZC93ZWJhZG1p bi9tb2R1bGVzL2Zyb250ZW5kL3NyYy9tYWluL2phdmEvb3JnL292aXJ0L2VuZ2luZS91aS9mcm9u dGVuZC9zZXJ2ZXIvZ3d0L1BsdWdpblNvdXJjZVBhZ2VTZXJ2bGV0LmphdmEKQEAgLTksMTUgKzks MTUgQEAgaW1wb3J0IGphdmEuaW8uSW5wdXRTdHJlYW1SZWFkZXI7CiBpbXBvcnQgamF2YS5pby5P dXRwdXRTdHJlYW1Xcml0ZXI7CiBpbXBvcnQgamF2YS5pby5SZWFkZXI7CiBpbXBvcnQgamF2YS5p by5Xcml0ZXI7Ci1pbXBvcnQgamF2YS51dGlsLkFycmF5czsKLWltcG9ydCBqYXZhLnV0aWwuTGlz dDsKIAogaW1wb3J0IGphdmF4LnNlcnZsZXQuaHR0cC5IdHRwU2VydmxldDsKIGltcG9ydCBqYXZh eC5zZXJ2bGV0Lmh0dHAuSHR0cFNlcnZsZXRSZXF1ZXN0OwogaW1wb3J0IGphdmF4LnNlcnZsZXQu aHR0cC5IdHRwU2VydmxldFJlc3BvbnNlOwogCitpbXBvcnQgb3JnLmNvZGVoYXVzLmphY2tzb24u SnNvbk5vZGU7CiBpbXBvcnQgb3JnLmFwYWNoZS5jb21tb25zLmxvZ2dpbmcuTG9nOwogaW1wb3J0 IG9yZy5hcGFjaGUuY29tbW9ucy5sb2dnaW5nLkxvZ0ZhY3Rvcnk7CisvL2ltcG9ydCBvcmcub3Zp cnQuZW5naW5lLnVpLmZyb250ZW5kLnNlcnZlci5nd3QuV2ViYWRtaW5EeW5hbWljSG9zdGluZ1Nl cnZsZXQ7CiAKIC8qKgogICogUmVuZGVycyB0aGUgSFRNTCBzb3VyY2UgcGFnZSBmb3IgdGhlIGdp dmVuIFVJIHBsdWdpbi4KQEAgLTI1LDM0ICsyNSw0OCBAQCBpbXBvcnQgb3JnLmFwYWNoZS5jb21t b25zLmxvZ2dpbmcuTG9nRmFjdG9yeTsKIHB1YmxpYyBjbGFzcyBQbHVnaW5Tb3VyY2VQYWdlU2Vy dmxldCBleHRlbmRzIEh0dHBTZXJ2bGV0IHsKIAogICAgIHByaXZhdGUgc3RhdGljIGZpbmFsIGxv bmcgc2VyaWFsVmVyc2lvblVJRCA9IDFMOworICAgIHByaXZhdGUgc3RhdGljIGZpbmFsIGxvbmcg UEFUSF9NQVggPSA1MTI7CiAKICAgICBwcml2YXRlIHN0YXRpYyBMb2cgbG9nZ2VyID0gTG9nRmFj dG9yeS5nZXRMb2coUGx1Z2luU291cmNlUGFnZVNlcnZsZXQuY2xhc3MpOwogCiAgICAgQE92ZXJy aWRlCiAgICAgcHJvdGVjdGVkIHZvaWQgZG9HZXQoSHR0cFNlcnZsZXRSZXF1ZXN0IHJlcXVlc3Qs IEh0dHBTZXJ2bGV0UmVzcG9uc2UgcmVzcG9uc2UpIHRocm93cyBJT0V4Y2VwdGlvbiB7CiAgICAg ICAgIC8vIFJlYWQgcGx1Z2luIG5hbWUgYXMgSFRUUCByZXF1ZXN0IHBhcmFtZXRlcgotICAgICAg ICBTdHJpbmcgcGx1Z2luTmFtZSA9IHJlcXVlc3QuZ2V0UGFyYW1ldGVyKCJwbHVnaW4iKTsgLy8k Tk9OLU5MUy0xJAotICAgICAgICBpZiAocGx1Z2luTmFtZSA9PSBudWxsKSB7CisgICAgICAgIFN0 cmluZyBwYXRoSW5mbyA9IHJlcXVlc3QuZ2V0UGF0aEluZm8oKTsKKyAgICAgICAgU3RyaW5nIHBh dGhbXSA9IG51bGw7CisgICAgICAgIGxvZ2dlci5kZWJ1ZygiR290IHBsdWdpbiByZXF1ZXN0ICIr cGF0aEluZm8pOyAvLyROT04tTkxTLTEkCisKKyAgICAgICAgdHJ5IHsKKyAgICAgICAgICAgIHBh dGggPSBwYXRoSW5mby5zcGxpdCgiLyIsIDMpOyAvLyROT04tTkxTLTEkCisgICAgICAgIH0gY2F0 Y2goRXhjZXB0aW9uIGV4KSB7fQorCisgICAgICAgIGlmIChwYXRoID09IG51bGwgfHwgcGF0aC5s ZW5ndGggPCAyKSB7CisgICAgICAgICAgICBsb2dnZXIuZXJyb3IoIk1pc3NpbmcgcGx1Z2luIG5h bWUgcmVxdWVzdCBwYXJhbWV0ZXIiKTsgLy8kTk9OLU5MUy0xJAorICAgICAgICAgICAgcmVzcG9u c2Uuc2VuZEVycm9yKEh0dHBTZXJ2bGV0UmVzcG9uc2UuU0NfQkFEX1JFUVVFU1QpOworICAgICAg ICAgICAgcmV0dXJuOworICAgICAgICB9CisKKyAgICAgICAgSnNvbk5vZGUgcGluZm8gPSBXZWJh ZG1pbkR5bmFtaWNIb3N0aW5nU2VydmxldC5nZXRQbHVnaW5EZWZpbml0aW9uKHBhdGhbMV0pOwor ICAgICAgICBpZiAocGluZm8gPT0gbnVsbCkgewogICAgICAgICAgICAgbG9nZ2VyLmVycm9yKCJN aXNzaW5nIHBsdWdpbiBuYW1lIHJlcXVlc3QgcGFyYW1ldGVyIik7IC8vJE5PTi1OTFMtMSQKICAg ICAgICAgICAgIHJlc3BvbnNlLnNlbmRFcnJvcihIdHRwU2VydmxldFJlc3BvbnNlLlNDX0JBRF9S RVFVRVNUKTsKICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgfQogCiAgICAgICAgIC8vIExv Y2F0ZSBwbHVnaW4gY29kZSBpbiBsb2NhbCBmaWxlIHN5c3RlbQotICAgICAgICAvLyBUT0RPIGhh cmQtY29kZWQgcGx1Z2luIGxvY2F0aW9uCi0gICAgICAgIEZpbGUgcGx1Z2luQ29kZUxvY2F0aW9u ID0gbmV3IEZpbGUoIi9ob21lL3Zzem9jcy9Eb3dubG9hZHMiKTsgLy8kTk9OLU5MUy0xJAotICAg ICAgICBGaWxlIHBsdWdpbkNvZGVGaWxlID0gbmV3IEZpbGUocGx1Z2luQ29kZUxvY2F0aW9uLCBw bHVnaW5OYW1lICsgIi5qcyIpOyAvLyROT04tTkxTLTEkCisgICAgICAgIFN0cmluZyBsb2NhbGZp bGUgPSBwaW5mby5wYXRoKCJwYXRoIikuZ2V0VGV4dFZhbHVlKCkgKyBGaWxlLnNlcGFyYXRvciAr IHBhdGhbMl07IC8vJE5PTi1OTFMtMSQKKyAgICAgICAgaWYgKCFpc1NhbmUobG9jYWxmaWxlKSkg eworICAgICAgICAgICAgcmVzcG9uc2Uuc2VuZEVycm9yKEh0dHBTZXJ2bGV0UmVzcG9uc2UuU0Nf Tk9UX0ZPVU5EKTsKKyAgICAgICAgICAgIHJldHVybjsKKyAgICAgICAgfQorCisgICAgICAgIEZp bGUgcGx1Z2luQ29kZUZpbGUgPSBuZXcgRmlsZShsb2NhbGZpbGUpOwogICAgICAgICBpZiAoIXBs dWdpbkNvZGVGaWxlLmlzRmlsZSgpIHx8ICFwbHVnaW5Db2RlRmlsZS5jYW5SZWFkKCkpIHsKICAg ICAgICAgICAgIGxvZ2dlci5lcnJvcigiQ2Fubm90IHJlYWQgcGx1Z2luIGNvZGU6ICIgKyBwbHVn aW5Db2RlRmlsZS5nZXRBYnNvbHV0ZVBhdGgoKSk7IC8vJE5PTi1OTFMtMSQKICAgICAgICAgICAg IHJlc3BvbnNlLnNlbmRFcnJvcihIdHRwU2VydmxldFJlc3BvbnNlLlNDX05PVF9GT1VORCk7CiAg ICAgICAgICAgICByZXR1cm47CiAgICAgICAgIH0KIAotICAgICAgICAvLyBUT0RPIHNpbXVsYXRl IHBsdWdpbiBkZXBlbmRlbmNpZXMKLSAgICAgICAgTGlzdDxTdHJpbmc+IHBsdWdpbkRlcGVuZGVu Y3lMaXN0ID0KLSAgICAgICAgICAgICAgICBBcnJheXMuYXNMaXN0KCJodHRwczovL2FqYXguZ29v Z2xlYXBpcy5jb20vYWpheC9saWJzL2pxdWVyeS8xLjcuMi9qcXVlcnkubWluLmpzIik7IC8vJE5P Ti1OTFMtMSQKLQotICAgICAgICAvLyBSZW5kZXIgSFRNTCBzb3VyY2UgcGFnZSB0byB0aGUgb3V0 cHV0CiAgICAgICAgIHJlc3BvbnNlLnNldENvbnRlbnRUeXBlKCJ0ZXh0L2h0bWw7IGNoYXJzZXQ9 VVRGLTgiKTsgLy8kTk9OLU5MUy0xJAogICAgICAgICByZXNwb25zZS5zZXRIZWFkZXIoIkNhY2hl LUNvbnRyb2wiLCAibm8tY2FjaGUiKTsgLy8kTk9OLU5MUy0xJCAvLyROT04tTkxTLTIkCiAKQEAg LTYzLDcgKzc3LDcgQEAgcHVibGljIGNsYXNzIFBsdWdpblNvdXJjZVBhZ2VTZXJ2bGV0IGV4dGVu ZHMgSHR0cFNlcnZsZXQgewogICAgICAgICAgICAgaW4gPSBuZXcgQnVmZmVyZWRSZWFkZXIobmV3 IElucHV0U3RyZWFtUmVhZGVyKG5ldyBGaWxlSW5wdXRTdHJlYW0ocGx1Z2luQ29kZUZpbGUpLCAi VVRGLTgiKSk7IC8vJE5PTi1OTFMtMSQKICAgICAgICAgICAgIG91dCA9IG5ldyBCdWZmZXJlZFdy aXRlcihuZXcgT3V0cHV0U3RyZWFtV3JpdGVyKHJlc3BvbnNlLmdldE91dHB1dFN0cmVhbSgpLCAi VVRGLTgiKSk7IC8vJE5PTi1OTFMtMSQKIAotICAgICAgICAgICAgcmVuZGVyUGx1Z2luU291cmNl UGFnZShpbiwgcGx1Z2luRGVwZW5kZW5jeUxpc3QsIG91dCk7CisgICAgICAgICAgICBjb3B5Q2hh cnMoaW4sIG91dCk7CiAgICAgICAgICAgICBvdXQuZmx1c2goKTsKICAgICAgICAgfSBmaW5hbGx5 IHsKICAgICAgICAgICAgIGlmIChpbiAhPSBudWxsKSB7CkBAIC03MiwyOCArODYsNiBAQCBwdWJs aWMgY2xhc3MgUGx1Z2luU291cmNlUGFnZVNlcnZsZXQgZXh0ZW5kcyBIdHRwU2VydmxldCB7CiAg ICAgICAgIH0KICAgICB9CiAKLSAgICB2b2lkIHJlbmRlclBsdWdpblNvdXJjZVBhZ2UoUmVhZGVy IHBsdWdpbkNvZGVJbnB1dCwgTGlzdDxTdHJpbmc+IHBsdWdpbkRlcGVuZGVuY3lMaXN0LCBXcml0 ZXIgb3V0cHV0KQotICAgICAgICAgICAgdGhyb3dzIElPRXhjZXB0aW9uIHsKLSAgICAgICAgb3V0 cHV0LndyaXRlKCI8IURPQ1RZUEUgaHRtbD48aHRtbD48aGVhZD4iKTsgLy8kTk9OLU5MUy0xJAot ICAgICAgICBvdXRwdXQud3JpdGUoIjxtZXRhIGh0dHAtZXF1aXY9XCJjb250ZW50LXR5cGVcIiBj b250ZW50PVwidGV4dC9odG1sOyBjaGFyc2V0PVVURi04XCI+Iik7IC8vJE5PTi1OTFMtMSQKLQot ICAgICAgICBmb3IgKFN0cmluZyBkZXBlbmRlbmN5IDogcGx1Z2luRGVwZW5kZW5jeUxpc3QpIHsK LSAgICAgICAgICAgIG91dHB1dC53cml0ZSgiPHNjcmlwdCB0eXBlPVwidGV4dC9qYXZhc2NyaXB0 XCIgc3JjPVwiIik7IC8vJE5PTi1OTFMtMSQKLSAgICAgICAgICAgIG91dHB1dC53cml0ZShkZXBl bmRlbmN5KTsKLSAgICAgICAgICAgIG91dHB1dC53cml0ZSgiXCI+PC9zY3JpcHQ+Iik7IC8vJE5P Ti1OTFMtMSQKLSAgICAgICAgfQotCi0gICAgICAgIG91dHB1dC53cml0ZSgiPC9oZWFkPjxib2R5 PiIpOyAvLyROT04tTkxTLTEkCi0gICAgICAgIG91dHB1dC53cml0ZSgiPHNjcmlwdCB0eXBlPVwi dGV4dC9qYXZhc2NyaXB0XCI+Iik7IC8vJE5PTi1OTFMtMSQKLSAgICAgICAgb3V0cHV0LndyaXRl KCIoZnVuY3Rpb24oIHBsdWdpbkFwaSApIHsiKTsgLy8kTk9OLU5MUy0xJAotCi0gICAgICAgIGNv cHlDaGFycyhwbHVnaW5Db2RlSW5wdXQsIG91dHB1dCk7Ci0KLSAgICAgICAgb3V0cHV0LndyaXRl KCJ9KSAoIHBhcmVudC5wbHVnaW5BcGkgKTsiKTsgLy8kTk9OLU5MUy0xJAotICAgICAgICBvdXRw dXQud3JpdGUoIjwvc2NyaXB0PiIpOyAvLyROT04tTkxTLTEkCi0gICAgICAgIG91dHB1dC53cml0 ZSgiPC9ib2R5PjwvaHRtbD4iKTsgLy8kTk9OLU5MUy0xJAotICAgIH0KLQogICAgIHZvaWQgY29w eUNoYXJzKFJlYWRlciBpbiwgV3JpdGVyIG91dCkgdGhyb3dzIElPRXhjZXB0aW9uIHsKICAgICAg ICAgY2hhcltdIGJ1ZmZlciA9IG5ldyBjaGFyWzQgKiAxMDI0XTsgLy8gVXNlIDQga0IgYnVmZmVy CiAgICAgICAgIGludCBudW1SZWFkID0gMDsKQEAgLTEwMyw0ICs5NSwyMyBAQCBwdWJsaWMgY2xh c3MgUGx1Z2luU291cmNlUGFnZVNlcnZsZXQgZXh0ZW5kcyBIdHRwU2VydmxldCB7CiAgICAgICAg IH0KICAgICB9CiAKKyAgICBwcml2YXRlIHN0YXRpYyBib29sZWFuIGlzU2FuZShTdHJpbmcgcGF0 aCkgeworICAgICAgICAvLyBDaGVjayB0aGF0IHRoZSBwYXRoIGlzIG5vdCB0b28gbG9uZzoKKyAg ICAgICAgZmluYWwgaW50IGxlbmd0aCA9IHBhdGgubGVuZ3RoKCk7CisgICAgICAgIGlmIChsZW5n dGggPiBQQVRIX01BWCkgeworICAgICAgICAgICAgbG9nZ2VyLmVycm9yKCJUaGUgcGF0aCBpcyAi ICsgbGVuZ3RoICsgIiBjaGFyYWN0ZXJzIGxvbmcsIHdoaWNoIGlzIGxvbmdlciB0aGFuIHRoZSBt YXhpbXVtIGFsbG93ZWQgIiArIFBBVEhfTUFYICsgIi4iKTsgLy8kTk9OLU5MUy0xJCAvLyROT04t TkxTLTIkIC8vJE5PTi1OTFMtMyQKKyAgICAgICAgICAgIHJldHVybiBmYWxzZTsKKyAgICAgICAg fQorCisgICAgICAgIC8vIENoZWNrIHRoYXQgdGhlcmUgYXJlbid0IHBvdGVudGlhbGx5IGRhbmdl cm91cyBkaXJlY3RvcnkgbmF2aWdhdGlvbiBzZXF1ZW5jZXM6CisgICAgICAgIGlmIChwYXRoLmNv bnRhaW5zKCIuLiIpIHx8IHBhdGguY29udGFpbnMoIi8vIikgfHwgcGF0aC5jb250YWlucygiLi8i KSkgeyAvLyROT04tTkxTLTEkIC8vJE5PTi1OTFMtMiQgLy8kTk9OLU5MUy0zJAorICAgICAgICAg ICAgbG9nZ2VyLmVycm9yKCJUaGUgcGF0aCBjb250YWlucyBwb3RlbnRpYWxseSBkYW5nZXJvdXMg ZGlyZWN0b3J5IG5hdmlnYXRpb24gc2VxdWVuY2VzLiIpOyAvLyROT04tTkxTLTEkCisgICAgICAg ICAgICByZXR1cm4gZmFsc2U7CisgICAgICAgIH0KKworICAgICAgICAvLyBBbGwgY2hlY2tzIHBh c3NlZCwgdGhlIHBhdGggaXMgc2FuZToKKyAgICAgICAgcmV0dXJuIHRydWU7CisgICAgfQogfQor CisvLyB2aW06IHRzPTQgc3RzPTQgc3c9NCBleHBhbmR0YWI6CmRpZmYgLS1naXQgYS9mcm9udGVu ZC93ZWJhZG1pbi9tb2R1bGVzL2Zyb250ZW5kL3NyYy9tYWluL2phdmEvb3JnL292aXJ0L2VuZ2lu ZS91aS9mcm9udGVuZC9zZXJ2ZXIvZ3d0L1dlYmFkbWluRHluYW1pY0hvc3RpbmdTZXJ2bGV0Lmph dmEgYi9mcm9udGVuZC93ZWJhZG1pbi9tb2R1bGVzL2Zyb250ZW5kL3NyYy9tYWluL2phdmEvb3Jn L292aXJ0L2VuZ2luZS91aS9mcm9udGVuZC9zZXJ2ZXIvZ3d0L1dlYmFkbWluRHluYW1pY0hvc3Rp bmdTZXJ2bGV0LmphdmEKaW5kZXggNjgzY2I2OC4uMWQ0OTI5NyAxMDA2NDQKLS0tIGEvZnJvbnRl bmQvd2ViYWRtaW4vbW9kdWxlcy9mcm9udGVuZC9zcmMvbWFpbi9qYXZhL29yZy9vdmlydC9lbmdp bmUvdWkvZnJvbnRlbmQvc2VydmVyL2d3dC9XZWJhZG1pbkR5bmFtaWNIb3N0aW5nU2VydmxldC5q YXZhCisrKyBiL2Zyb250ZW5kL3dlYmFkbWluL21vZHVsZXMvZnJvbnRlbmQvc3JjL21haW4vamF2 YS9vcmcvb3ZpcnQvZW5naW5lL3VpL2Zyb250ZW5kL3NlcnZlci9nd3QvV2ViYWRtaW5EeW5hbWlj SG9zdGluZ1NlcnZsZXQuamF2YQpAQCAtMSwxMCArMSwyMSBAQAogcGFja2FnZSBvcmcub3ZpcnQu ZW5naW5lLnVpLmZyb250ZW5kLnNlcnZlci5nd3Q7CiAKIGltcG9ydCBqYXZhLmlvLlByaW50V3Jp dGVyOworaW1wb3J0IGphdmEuaW8uRmlsZTsKK2ltcG9ydCBqYXZhLmlvLklPRXhjZXB0aW9uOwog aW1wb3J0IGphdmEudXRpbC5IYXNoTWFwOwogaW1wb3J0IGphdmEudXRpbC5NYXA7CitpbXBvcnQg amF2YS51dGlsLk1hcC5FbnRyeTsKK2ltcG9ydCBqYXZhLnV0aWwuSXRlcmF0b3I7CitpbXBvcnQg b3JnLmFwYWNoZS5jb21tb25zLmxvZ2dpbmcuTG9nOworaW1wb3J0IG9yZy5hcGFjaGUuY29tbW9u cy5sb2dnaW5nLkxvZ0ZhY3Rvcnk7CisKIAogaW1wb3J0IGphdmF4LnNlcnZsZXQuaHR0cC5IdHRw U2VydmxldFJlcXVlc3Q7CitpbXBvcnQgb3JnLmNvZGVoYXVzLmphY2tzb24uSnNvblBhcnNlcjsK K2ltcG9ydCBvcmcuY29kZWhhdXMuamFja3Nvbi5Kc29uTm9kZTsKK2ltcG9ydCBvcmcuY29kZWhh dXMuamFja3Nvbi5ub2RlLk9iamVjdE5vZGU7CitpbXBvcnQgb3JnLmNvZGVoYXVzLmphY2tzb24u bWFwLk9iamVjdE1hcHBlcjsKIAogaW1wb3J0IG9yZy5vdmlydC5lbmdpbmUuY29yZS5jb21tb24u Y29uZmlnLkNvbmZpZzsKIGltcG9ydCBvcmcub3ZpcnQuZW5naW5lLmNvcmUuY29tbW9uLnF1ZXJp ZXMuQ29uZmlndXJhdGlvblZhbHVlczsKQEAgLTE5LDYgKzMwLDggQEAgaW1wb3J0IG9yZy5vdmly dC5lbmdpbmUuY29yZS5jb21tb24ucXVlcmllcy5WZGNRdWVyeVR5cGU7CiBwdWJsaWMgY2xhc3Mg V2ViYWRtaW5EeW5hbWljSG9zdGluZ1NlcnZsZXQgZXh0ZW5kcyBHd3REeW5hbWljSG9zdFBhZ2VT ZXJ2bGV0IHsKIAogICAgIHByaXZhdGUgc3RhdGljIGZpbmFsIGxvbmcgc2VyaWFsVmVyc2lvblVJ RCA9IDFMOworICAgIHByaXZhdGUgc3RhdGljIE1hcDxTdHJpbmcsIEpzb25Ob2RlPiBwbHVnaW5E ZWZpbml0aW9uczsKKyAgICBwcml2YXRlIHN0YXRpYyBMb2cgbG9nZ2VyID0gTG9nRmFjdG9yeS5n ZXRMb2coV2ViYWRtaW5EeW5hbWljSG9zdGluZ1NlcnZsZXQuY2xhc3MpOwogCiAgICAgQE92ZXJy aWRlCiAgICAgcHJvdGVjdGVkIFN0cmluZyBnZXRTZWxlY3RvclNjcmlwdE5hbWUoKSB7CkBAIC0z NiwxMCArNDksMTQgQEAgcHVibGljIGNsYXNzIFdlYmFkbWluRHluYW1pY0hvc3RpbmdTZXJ2bGV0 IGV4dGVuZHMgR3d0RHluYW1pY0hvc3RQYWdlU2VydmxldCB7CiAgICAgICAgICAgICB3cml0ZUpz T2JqZWN0KHdyaXRlciwgImFwcGxpY2F0aW9uTW9kZSIsIGFwcE1vZGVEYXRhKTsgLy8kTk9OLU5M Uy0xJAogICAgICAgICB9CiAKLSAgICAgICAgU3RyaW5nQnVpbGRlciBwbHVnaW5EZWZpbml0aW9u cyA9IG5ldyBTdHJpbmdCdWlsZGVyKCIgdmFyIHBsdWdpbkRlZmluaXRpb25zID0gWyAiKTsgLy8k Tk9OLU5MUy0xJAotICAgICAgICBwbHVnaW5EZWZpbml0aW9ucy5hcHBlbmQoInsgbmFtZTogXCJt eVBsdWdpblwiLCB1cmw6IFwiL3dlYmFkbWluL3dlYmFkbWluL1BsdWdpblNvdXJjZVBhZ2U/cGx1 Z2luPW15UGx1Z2luXCIsIGNvbmZpZzogeyBcImZvb1wiOiAxIH0gfSIpOyAvLyROT04tTkxTLTEk Ci0gICAgICAgIHBsdWdpbkRlZmluaXRpb25zLmFwcGVuZCgiIF07ICIpOyAvLyROT04tTkxTLTEk Ci0gICAgICAgIHdyaXRlci5hcHBlbmQocGx1Z2luRGVmaW5pdGlvbnMudG9TdHJpbmcoKSk7Cisg ICAgICAgIC8vIEZJWE1FOiBkbyB3ZSBsb2FkIHRoaXMgZXZlcnl0aW1lLCBvciBqdXN0IG9uY2U/ CisgICAgICAgIGlmICh0cnVlKSB7IC8qKnBsdWdpbkRlZmluaXRpb25zID09IG51bGwpIHsqKi8K KyAgICAgICAgICAgIGxvZ2dlci5kZWJ1ZygiZ2V0UGx1Z2luRGVmaW5pdGlvbnM6IExvYWRpbmcg cGx1Z2luIGRlZmluaXRpb25zIik7IC8vJE5PTi1OTFMtMSQKKyAgICAgICAgICAgIHBsdWdpbkRl ZmluaXRpb25zID0gZ2V0UGx1Z2luRGVmaW5pdGlvbnMoKTsKKyAgICAgICAgfQorCisgICAgICAg IHdyaXRlSnNvbk9iamVjdCh3cml0ZXIsICJwbHVnaW5EZWZpbml0aW9ucyIsIHBsdWdpbkRlZmlu aXRpb25zLnZhbHVlcygpKTsgLy8kTk9OLU5MUy0xJAorCiAgICAgfQogCiAgICAgcHJpdmF0ZSBJ bnRlZ2VyIGdldEFwcGxpY2F0aW9uTW9kZShIdHRwU2VydmxldFJlcXVlc3QgcmVxdWVzdCkgewpA QCAtNDgsNCArNjUsMTAwIEBAIHB1YmxpYyBjbGFzcyBXZWJhZG1pbkR5bmFtaWNIb3N0aW5nU2Vy dmxldCBleHRlbmRzIEd3dER5bmFtaWNIb3N0UGFnZVNlcnZsZXQgewogICAgICAgICAgICAgICAg ICAgICAgICAgQ29uZmlnLkRlZmF1bHRDb25maWd1cmF0aW9uVmVyc2lvbiksIHJlcXVlc3QpOwog ICAgIH0KIAorICAgIHByaXZhdGUgYm9vbGVhbiBjaGVja1BsdWdpbkRlZmluaXRpb24oU3RyaW5n IGZpbGVuYW1lLCBKc29uTm9kZSBkZWYpIHsKKyAgICAgICAgU3RyaW5nIHVybCwgY2ZnOworCisg ICAgICAgIGlmICghZGVmLnBhdGgoIm5hbWUiKS5pc1RleHR1YWwoKSkgeyAvLyROT04tTkxTLTEk CisgICAgICAgICAgICBsb2dnZXIuZXJyb3IoZmlsZW5hbWUrIjogIFRoZSAnbmFtZScgZmllbGQg bXVzdCBiZSBwcmVzZW50IGFuZCBtdXN0IGJlIGEgc3RyaW5nLiIpOyAvLyROT04tTkxTLTEkCisg ICAgICAgICAgICByZXR1cm4gZmFsc2U7CisgICAgICAgIH0KKyAgICAgICAgaWYgKCFkZWYucGF0 aCgidXJsIikuaXNUZXh0dWFsKCkpIHsgLy8kTk9OLU5MUy0xJAorICAgICAgICAgICAgbG9nZ2Vy LmVycm9yKGZpbGVuYW1lKyI6ICBUaGUgJ3VybCcgZmllbGQgbXVzdCBiZSBwcmVzZW50IGFuZCBt dXN0IGJlIGEgc3RyaW5nLiIpOyAvLyROT04tTkxTLTEkCisgICAgICAgICAgICByZXR1cm4gZmFs c2U7CisgICAgICAgIH0KKyAgICAgICAgdXJsID0gZGVmLnBhdGgoInVybCIpLmdldFZhbHVlQXNU ZXh0KCk7IC8vJE5PTi1OTFMtMSQKKyAgICAgICAgaWYgKHVybC5zdGFydHNXaXRoKCIvd2ViYWRt aW4iKSkgeyAvLyROT04tTkxTLTEkCisgICAgICAgICAgICBpZiAoIWRlZi5wYXRoKCJwYXRoIiku aXNUZXh0dWFsKCkpIHsgLy8kTk9OLU5MUy0xJAorICAgICAgICAgICAgICAgIGxvZ2dlci5lcnJv cihmaWxlbmFtZSsiOiAgVGhlICdwYXRoJyBmaWVsZCBtdXN0IGJlIHByZXNlbnQgd2hlbiB0aGUg J3VybCcgaXMgbG9jYWwgYW5kIG11c3QgYmUgYSBzdHJpbmcuIik7IC8vJE5PTi1OTFMtMSQKKyAg ICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7CisgICAgICAgICAgICB9CisgICAgICAgIH0KKyAg ICAgICAgcmV0dXJuIHRydWU7CisgICAgfQorCisgICAgcHJpdmF0ZSBNYXA8U3RyaW5nLCBKc29u Tm9kZT4gZ2V0UGx1Z2luRGVmaW5pdGlvbnMoKSB7CisgICAgICAgIE1hcDxTdHJpbmcsIEpzb25O b2RlPiBkZWZzID0gbmV3IEhhc2hNYXA8U3RyaW5nLCBKc29uTm9kZT4oKTsKKyAgICAgICAgRmls ZSBkaXJlY3Rvcnk7CisgICAgICAgIEZpbGVbXSBmaWxlczsKKworICAgICAgICBsb2dnZXIuZGVi dWcoImdldFBsdWdpbkRlZmluaXRpb25zOiBDaGVja2luZyBwYXRoICIrQ29uZmlnLnJlc29sdmVP VmlydFVpUGx1Z2luc1BhdGgoKSk7IC8vJE5PTi1OTFMtMSQKKyAgICAgICAgZGlyZWN0b3J5ID0g bmV3IEZpbGUoQ29uZmlnLnJlc29sdmVPVmlydFVpUGx1Z2luc1BhdGgoKSk7CisgICAgICAgIGZp bGVzID0gZGlyZWN0b3J5Lmxpc3RGaWxlcygpOworCisgICAgICAgIEpzb25Ob2RlIHJvb3Q7Cisg ICAgICAgIE9iamVjdE1hcHBlciBtYXBwZXIgPSBuZXcgT2JqZWN0TWFwcGVyKCk7CisgICAgICAg IG1hcHBlci5jb25maWd1cmUoSnNvblBhcnNlci5GZWF0dXJlLkFMTE9XX0NPTU1FTlRTLCB0cnVl KTsKKyAgICAgICAgLy8gRklYTUU6IElmIEpBQ0tTT04tNjE4IGlzIHJlc29sdmVkIChBTExPV19U UkFJTElOR19DT01NQSksIHVzZSBpdC4KKworICAgICAgICBmb3IoaW50IGk9MDsgaTxmaWxlcy5s ZW5ndGg7IGkrKykgeworICAgICAgICAgICAgU3RyaW5nIGZpbGVuYW1lID0gZmlsZXNbaV0uZ2V0 TmFtZSgpOworICAgICAgICAgICAgbG9nZ2VyLmRlYnVnKCJnZXRQbHVnaW5EZWZpbml0aW9uczog Q2hlY2tpbmcgZmlsZSAiK2ZpbGVuYW1lKTsgLy8kTk9OLU5MUy0xJAorICAgICAgICAgICAgaWYg KCFmaWxlbmFtZS5lbmRzV2l0aCgiLmpzb24iKSkgLy8kTk9OLU5MUy0xJAorICAgICAgICAgICAg ICAgIGNvbnRpbnVlOworCisgICAgICAgICAgICB0cnkgeworICAgICAgICAgICAgICAgIHJvb3Qg PSBtYXBwZXIucmVhZFZhbHVlKGZpbGVzW2ldLCBKc29uTm9kZS5jbGFzcyk7CisgICAgICAgICAg ICB9IGNhdGNoKElPRXhjZXB0aW9uIGV4KSB7CisgICAgICAgICAgICAgICAgbG9nZ2VyLmVycm9y KCJnZXRQbHVnaW5EZWZpbml0aW9uczogRXJyb3IgcmVhZGluZyAiK2ZpbGVuYW1lKyI6ICIrZXgp OyAvLyROT04tTkxTLTEkIC8vJE5PTi1OTFMtMiQKKyAgICAgICAgICAgICAgICBjb250aW51ZTsK KyAgICAgICAgICAgIH0KKyAgICAgICAgICAgIGlmIChjaGVja1BsdWdpbkRlZmluaXRpb24oZmls ZXNbaV0uZ2V0QWJzb2x1dGVQYXRoKCksIHJvb3QpKSB7CisgICAgICAgICAgICAgICAgU3RyaW5n IG5hbWUgPSByb290LnBhdGgoIm5hbWUiKS5nZXRWYWx1ZUFzVGV4dCgpOyAvLyROT04tTkxTLTEk CisgICAgICAgICAgICAgICAgU3RyaW5nIGNmZyA9IHJvb3QucGF0aCgiY29uZmlnRmlsZSIpLmdl dFZhbHVlQXNUZXh0KCk7IC8vJE5PTi1OTFMtMSQKKyAgICAgICAgICAgICAgICBpZiAoY2ZnICE9 IG51bGwpIHsKKyAgICAgICAgICAgICAgICAgICAgY2ZnID0gQ29uZmlnLnJlc29sdmVPVmlydFVp UGx1Z2luQ29uZmlnRmlsZShjZmcpOworICAgICAgICAgICAgICAgICAgICB0cnkgeworICAgICAg ICAgICAgICAgICAgICAgICAgSnNvbk5vZGUgY29uZmlnID0gbWFwcGVyLnJlYWRWYWx1ZShuZXcg RmlsZShjZmcpLCBKc29uTm9kZS5jbGFzcyk7CisgICAgICAgICAgICAgICAgICAgICAgICBPYmpl Y3ROb2RlIG9uID0gKE9iamVjdE5vZGUpcm9vdC53aXRoKCJjb25maWciKTsgLy8kTk9OLU5MUy0x JAorICAgICAgICAgICAgICAgICAgICAgICAgZm9yKEl0ZXJhdG9yPEVudHJ5PFN0cmluZyxKc29u Tm9kZT4+IGl0PWNvbmZpZy5nZXRGaWVsZHMoKTsgaXQuaGFzTmV4dCgpOykgeworICAgICAgICAg ICAgICAgICAgICAgICAgICAgIEVudHJ5PFN0cmluZyxKc29uTm9kZT4gZSA9IGl0Lm5leHQoKTsK KyAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbi5wdXQoZS5nZXRLZXkoKSwgZS5nZXRWYWx1 ZSgpKTsKKyAgICAgICAgICAgICAgICAgICAgICAgIH0KKyAgICAgICAgICAgICAgICAgICAgfSBj YXRjaChFeGNlcHRpb24gZXgpIHsKKyAgICAgICAgICAgICAgICAgICAgICAgIGxvZ2dlci5lcnJv cihmaWxlbmFtZSsiOiAgRXJyb3IgcmVhZGluZyB0aGUgcGx1Z2luIGNvbmZpZ3VyYXRpb24gZnJv bSAiK2NmZysiLiAgRXhjZXB0aW9uIHdhczogIitleCk7IC8vJE5PTi1OTFMtMSQgLy8kTk9OLU5M Uy0yJAorICAgICAgICAgICAgICAgICAgICB9CisgICAgICAgICAgICAgICAgfQorICAgICAgICAg ICAgICAgIGRlZnMucHV0KG5hbWUsIHJvb3QpOworICAgICAgICAgICAgfQorICAgICAgICB9Cisg ICAgICAgIHJldHVybiBkZWZzOworICAgIH0KKworICAgIC8qKgorICAgICAqIFJldHVybiBhIHNp bmdsZSBwbHVnaW4gZGVmaW5pdGlvbiBnaXZlbiBhIHBsdWdpbiBuYW1lCisgICAgICovCisgICAg cHVibGljIHN0YXRpYyBKc29uTm9kZSBnZXRQbHVnaW5EZWZpbml0aW9uKFN0cmluZyBuYW1lKSB7 CisgICAgICAgIEpzb25Ob2RlIHJldCA9IG51bGw7CisgICAgICAgIGlmIChwbHVnaW5EZWZpbml0 aW9ucyAhPSBudWxsKSB7CisgICAgICAgICAgICByZXQgPSBwbHVnaW5EZWZpbml0aW9ucy5nZXQo bmFtZSk7CisgICAgICAgIH0KKyAgICAgICAgcmV0dXJuIHJldDsKKyAgICB9CisKKyAgICAvKioK KyAgICAgKiBXcml0ZXMgYSBzdHJpbmcgcmVwcmVzZW50aW5nIEphdmFTY3JpcHQgb2JqZWN0IGxp dGVyYWwgY29udGFpbmluZyBnaXZlbiBhdHRyaWJ1dGVzLgorICAgICAqLworICAgIHByb3RlY3Rl ZCB2b2lkIHdyaXRlSnNvbk9iamVjdChQcmludFdyaXRlciB3cml0ZXIsIFN0cmluZyBvYmplY3RO YW1lLCBPYmplY3Qgb2JqKSB7CisgICAgICAgIFN0cmluZ0J1aWxkZXIgc2IgPSBuZXcgU3RyaW5n QnVpbGRlcigpOworICAgICAgICBPYmplY3RNYXBwZXIgbWFwcGVyID0gbmV3IE9iamVjdE1hcHBl cigpOworICAgICAgICBzYi5hcHBlbmQoIiB2YXIgIikuYXBwZW5kKG9iamVjdE5hbWUpLmFwcGVu ZCgiID0gIik7IC8vJE5PTi1OTFMtMSQgLy8kTk9OLU5MUy0yJAorICAgICAgICB0cnkgeworICAg ICAgICAgICAgc2IuYXBwZW5kKG1hcHBlci53cml0ZVZhbHVlQXNTdHJpbmcob2JqKSk7CisgICAg ICAgIH0gY2F0Y2goRXhjZXB0aW9uIGV4KSB7IH0KKyAgICAgICAgc2IuYXBwZW5kKCI7Iik7IC8v JE5PTi1OTFMtMSQKKyAgICAgICAgd3JpdGVyLmFwcGVuZChzYi50b1N0cmluZygpKTsKKyAgICB9 CisKKwogfQorLy8gdmltOiB0cz00IHN0cz00IHN3PTQgZXhwYW5kdGFiOgpkaWZmIC0tZ2l0IGEv ZnJvbnRlbmQvd2ViYWRtaW4vbW9kdWxlcy93ZWJhZG1pbi9zcmMvbWFpbi9qYXZhL29yZy9vdmly dC9lbmdpbmUvdWkvd2ViYWRtaW4vcGx1Z2luL1BsdWdpbkV2ZW50SGFuZGxlci5qYXZhIGIvZnJv bnRlbmQvd2ViYWRtaW4vbW9kdWxlcy93ZWJhZG1pbi9zcmMvbWFpbi9qYXZhL29yZy9vdmlydC9l bmdpbmUvdWkvd2ViYWRtaW4vcGx1Z2luL1BsdWdpbkV2ZW50SGFuZGxlci5qYXZhCmluZGV4IGEy NWZjNzUuLjY4N2U4MDEgMTAwNjQ0Ci0tLSBhL2Zyb250ZW5kL3dlYmFkbWluL21vZHVsZXMvd2Vi YWRtaW4vc3JjL21haW4vamF2YS9vcmcvb3ZpcnQvZW5naW5lL3VpL3dlYmFkbWluL3BsdWdpbi9Q bHVnaW5FdmVudEhhbmRsZXIuamF2YQorKysgYi9mcm9udGVuZC93ZWJhZG1pbi9tb2R1bGVzL3dl YmFkbWluL3NyYy9tYWluL2phdmEvb3JnL292aXJ0L2VuZ2luZS91aS93ZWJhZG1pbi9wbHVnaW4v UGx1Z2luRXZlbnRIYW5kbGVyLmphdmEKQEAgLTE1LDUgKzE1LDQgQEAgcHVibGljIGNsYXNzIFBs dWdpbkV2ZW50SGFuZGxlciB7CiAgICAgICAgIC8vIFRPRE8gY2FsbCBFdmVudEJ1cy5hZGRIYW5k bGVyIGZvciBlYWNoIGV4dGVuc2lvbiBwb2ludCAoZXZlbnQpLAogICAgICAgICAvLyB3aXRoIHRo ZSBoYW5kbGVyIGltcGxlbWVudGF0aW9uIHVzaW5nIFBsdWdpbk1hbmFnZXIgdG8gY2FsbCBwbHVn aW5zCiAgICAgfQotCiB9CmRpZmYgLS1naXQgYS9mcm9udGVuZC93ZWJhZG1pbi9tb2R1bGVzL3dl YmFkbWluL3NyYy9tYWluL3dlYmFwcC9XRUItSU5GL3dlYi54bWwgYi9mcm9udGVuZC93ZWJhZG1p bi9tb2R1bGVzL3dlYmFkbWluL3NyYy9tYWluL3dlYmFwcC9XRUItSU5GL3dlYi54bWwKaW5kZXgg ZGJmOTNhMi4uMGVkNGNlOCAxMDA2NDQKLS0tIGEvZnJvbnRlbmQvd2ViYWRtaW4vbW9kdWxlcy93 ZWJhZG1pbi9zcmMvbWFpbi93ZWJhcHAvV0VCLUlORi93ZWIueG1sCisrKyBiL2Zyb250ZW5kL3dl YmFkbWluL21vZHVsZXMvd2ViYWRtaW4vc3JjL21haW4vd2ViYXBwL1dFQi1JTkYvd2ViLnhtbApA QCAtMzIsNiArMzIsMTAgQEAKIAkJPHNlcnZsZXQtbmFtZT5QbHVnaW5Tb3VyY2VQYWdlPC9zZXJ2 bGV0LW5hbWU+CiAJCTx1cmwtcGF0dGVybj4vd2ViYWRtaW4vUGx1Z2luU291cmNlUGFnZTwvdXJs LXBhdHRlcm4+CiAJPC9zZXJ2bGV0LW1hcHBpbmc+CisJPHNlcnZsZXQtbWFwcGluZz4KKwkJPHNl cnZsZXQtbmFtZT5QbHVnaW5Tb3VyY2VQYWdlPC9zZXJ2bGV0LW5hbWU+CisJCTx1cmwtcGF0dGVy bj4vd2ViYWRtaW4vcGx1Z2luLyo8L3VybC1wYXR0ZXJuPgorCTwvc2VydmxldC1tYXBwaW5nPgog CiAJPCEtLSBEZWZhdWx0IHBhZ2UgdG8gc2VydmUgLS0+CiAJPHdlbGNvbWUtZmlsZS1saXN0Pgo= --_005_A24D665DC3ECC245A2EA0D9A958F80B62C491334G9W0745americas_--

Thank you Chris :) I'd like to incorporate your ideas into upcoming PoC patch, which will be focused on server-side components of UI plugin infrastructure: 1) servlet that serves plugin-related static resources (plugin host page, actual plugin code, any 3rd party JavaScript libraries, CSS, etc.) from local filesystem 2) class responsible for parsing/validating/caching plugin descriptor information from local filesystem Regarding the comment in WebadminDynamicHostingServlet that says "FIXME: do we load this everytime, or just once?": maybe we could use the same approach as in servlet containers, which use 'date last modified' attribute of JSP files to trigger recompilation of corresponding servlets. For example, each time WebAdmin host page gets requested through WebadminDynamicHostingServlet, we could iterate over plugin descriptor files (in /usr/share/ovirt-engine/ui-plugins), looking at 'date last modified' attribute, parsing/validating plugin meta-data, and caching it using pluginName + dateLastModified (compound cache key). We also need to synchronize the access to plugin meta-data. What do you think? After the upcoming PoC patch (focused on server-side components) gets released, UI plugin infrastructure should be pretty much stable and we can focus on adding particular features, such as: * adding custom sub-tabs * adding custom context-menu items * making REST API calls through plugin API * investigating cross-origin plugin scenario (plugin gets loaded from page sitting on different origin than Engine JBoss instance) Let me know what you think. Cheers, Vojtech ----- Original Message ----- From: "Chris Frantz" <Chris.Frantz@hp.com> To: "Vojtech Szocs" <vszocs@redhat.com> Cc: "engine-devel" <engine-devel@ovirt.org> Sent: Thursday, August 30, 2012 10:03:02 PM Subject: RE: UI Plugins configuration Vojtech, Here is my patch against WIP-UI-Plugins-PoC-revision-4. I’ve also included 2 dummy plugins in sample.tar.gz. --Chris From: engine-devel-bounces@ovirt.org [mailto:engine-devel-bounces@ovirt.org] On Behalf Of Frantz, Chris Sent: Thursday, August 30, 2012 1:06 PM To: Vojtech Szocs Cc: engine-devel Subject: Re: [Engine-devel] UI Plugins configuration Vojtech, I agree with your formalized names: Plugin Descriptor is the JSON file containing plugin meta-data. The plugin descriptor may also contain the default configuration data. It is located in $DATADIR/ui-plugins. Plugin Configuration is the JSON file containing optional plugin configuration info. It is located in $CONFIGDIR/ui-plugins (unless the Plugin Descriptor contains an absolute path). Plugin Definition is the JavaScript object used by WebAdmin. In the current implementation, the Plugin Definition contains both the Plugin Descriptor and the Plugin Configuraion. Plugin Source Page is the HTML page used to invoke the plugin code and shall be referenced by the plugin descriptor’s “url” attribute. I’ve implemented the config merging you’ve suggested: the structure in configFile gets merged with the structure of “config”, with the data in configFile winning in the case of duplicate key names. BTW, the patch is against ovirt-engine + 0001-WIP-UI-Plugins-PoC-revision-2. Let me know what you think, --Chris

Vojtech, Please go ahead and include my ideas and/or code into your next patch. With regards to the FIXME, I think using the 'date last modified' is a good idea. However, the plugin descriptor file can also reference the plugin config file (via the configFile property). I imagine that adding, removing or reconfiguring plugins will be a relatively rare event, so maybe there is a simpler method: Remember the newest timestamp of ($DATADIR/ui-plugins/*, $CONFIGDIR/ui-plugins/*) and reload the plugin descriptors and configurations if the newest timestamp changes. As far as synchronization goes, the current code's getPluginDefinitions() loads all of the plugin descriptors and configurations into a new HashMap and then assigns that hashmap to WebadminDynamicHostingServlet.pluginDefinitions. As long as the JsonNode trees in pluginDefinitions aren't modified after being put into pluginDefinitions, I don't see a synchronization issue. Successive calls to get data from the pluginDefinitions hashmap may see different data, but they'll never see inconsistent data (e.g. a partially constructed plugin descriptor). However, if we want to add calls to modify the pluginDefinitions at runtime (such as a element in the GUI that disables certain plugins), then we will need synchronization. We'll also have to concern ourselves with whether any such modifications need to be saved back to the files on disk. --Chris -----Original Message----- From: Vojtech Szocs [mailto:vszocs@redhat.com] Sent: Tuesday, September 04, 2012 7:46 AM To: Frantz, Chris Cc: engine-devel Subject: Re: UI Plugins configuration Thank you Chris :) I'd like to incorporate your ideas into upcoming PoC patch, which will be focused on server-side components of UI plugin infrastructure: 1) servlet that serves plugin-related static resources (plugin host page, actual plugin code, any 3rd party JavaScript libraries, CSS, etc.) from local filesystem 2) class responsible for parsing/validating/caching plugin descriptor information from local filesystem Regarding the comment in WebadminDynamicHostingServlet that says "FIXME: do we load this everytime, or just once?": maybe we could use the same approach as in servlet containers, which use 'date last modified' attribute of JSP files to trigger recompilation of corresponding servlets. For example, each time WebAdmin host page gets requested through WebadminDynamicHostingServlet, we could iterate over plugin descriptor files (in /usr/share/ovirt-engine/ui-plugins), looking at 'date last modified' attribute, parsing/validating plugin meta-data, and caching it using pluginName + dateLastModified (compound cache key). We also need to synchronize the access to plugin meta-data. What do you think? After the upcoming PoC patch (focused on server-side components) gets released, UI plugin infrastructure should be pretty much stable and we can focus on adding particular features, such as: * adding custom sub-tabs * adding custom context-menu items * making REST API calls through plugin API * investigating cross-origin plugin scenario (plugin gets loaded from page sitting on different origin than Engine JBoss instance) Let me know what you think. Cheers, Vojtech ----- Original Message ----- From: "Chris Frantz" <Chris.Frantz@hp.com> To: "Vojtech Szocs" <vszocs@redhat.com> Cc: "engine-devel" <engine-devel@ovirt.org> Sent: Thursday, August 30, 2012 10:03:02 PM Subject: RE: UI Plugins configuration Vojtech, Here is my patch against WIP-UI-Plugins-PoC-revision-4. I’ve also included 2 dummy plugins in sample.tar.gz. --Chris From: engine-devel-bounces@ovirt.org [mailto:engine-devel-bounces@ovirt.org] On Behalf Of Frantz, Chris Sent: Thursday, August 30, 2012 1:06 PM To: Vojtech Szocs Cc: engine-devel Subject: Re: [Engine-devel] UI Plugins configuration Vojtech, I agree with your formalized names: Plugin Descriptor is the JSON file containing plugin meta-data. The plugin descriptor may also contain the default configuration data. It is located in $DATADIR/ui-plugins. Plugin Configuration is the JSON file containing optional plugin configuration info. It is located in $CONFIGDIR/ui-plugins (unless the Plugin Descriptor contains an absolute path). Plugin Definition is the JavaScript object used by WebAdmin. In the current implementation, the Plugin Definition contains both the Plugin Descriptor and the Plugin Configuraion. Plugin Source Page is the HTML page used to invoke the plugin code and shall be referenced by the plugin descriptor’s “url” attribute. I’ve implemented the config merging you’ve suggested: the structure in configFile gets merged with the structure of “config”, with the data in configFile winning in the case of duplicate key names. BTW, the patch is against ovirt-engine + 0001-WIP-UI-Plugins-PoC-revision-2. Let me know what you think, --Chris

Hi Chris, sorry for my late response, I'm working on PoC patch rev.5 this week, and was thinking about your ideas, and came up with some modifications. Please let me know what you think. Regarding 'configFile' property in plugin descriptor, maybe we could remove it, in favor of introducing configuration file naming convention '<descriptorFileName>-config.json': (+) there would be a standard plugin configuration file naming convention [making it simpler for plugin end users] (+) Engine (WebAdmin servlet) wouldn't have to parse plugin descriptor just to determine configuration file name This way, reloading plugin descriptors/configuration could work like this: a, iterate through plugin descriptor [*.json] files in $DATADIR/ui-plugins/ directory, remember 'dateLastModified' value b, iterate through plugin configuration [<descriptorFileName>-config.json] files in $CONFIGDIR/ui-plugins/ directory, remember 'dateLastModified' value c, for each plugin descriptor: c1, if (descriptorFileNameNotInCache || currentDescriptorDateLastModified > cachedDescriptorDateLastModified) { goto c3; } c2, else if (currentConfigDateLastModified > cachedConfigDateLastModified) { goto c4; } c3, reload (parse/validate/cache) plugin descriptor c4, reload plugin configuration This is based on following assumptions: 1. plugin descriptor [$DATADIR/ui-plugins/<descriptorFileName>.json] is NOT intended to be modified by end users [packaging system handles this] -> we don't expect plugin descriptor data to change too often 2. plugin configuration [$CONFIGDIR/ui-plugins/<descriptorFileName>-config.json] is intended to be modified by end users -> we expect plugin configuration data to change more frequently This is why I proposed the above mentioned reloading process, in favor of reloading everything when any timestamp (descriptor/configuration) changes to a newer value. Let me know what you think.
As far as synchronization goes, the current code's getPluginDefinitions() loads all of the plugin descriptors and configurations into a new HashMap and then assigns that hashmap to WebadminDynamicHostingServlet.pluginDefinitions. As long as the JsonNode trees in pluginDefinitions aren't modified after being put into pluginDefinitions, I don't see a synchronization issue. Successive calls to get data from the pluginDefinitions hashmap may see different data, but they'll never see inconsistent data (e.g. a partially constructed plugin descriptor).
This is correct. 'pluginDefinitions' HashMap state is not expected to be modified, at least for now (e.g. using Collections.unmodifiableMap). But consider following use-case when invoking WebadminDynamicHostingServlet: [thread #1] nothing needs to be reloaded, writes plugin meta-data into WebAdmin HTML page, writes data for 'plugin1' (1/2 plugins) [thread #2] both 'plugin1' and 'plugin2' descriptor/configuration has changed, reloads them, writes plugin meta-data into WebAdmin HTML page (both plugins), request finished [thread #1] writes data for 'plugin2', request finished As you can see, thread #1 will produce plugin meta-data with 'old' data for 'plugin1', and 'new' data for 'plugin2'. I guess a more appropriate behavior would be that thread #1 will produce 'old' data for both plugins, since nothing new was detected at time when thread #1 checked for changes ("nothing needs to be reloaded"). What do you think?
However, if we want to add calls to modify the pluginDefinitions at runtime (such as a element in the GUI that disables certain plugins), then we will need synchronization. We'll also have to concern ourselves with whether any such modifications need to be saved back to the files on disk.
I'd like to avoid such synchronization. Plugin descriptor/configuration data, after being loaded, should be treated as immutable for the given timestamp. For example, if the user wants to disable pluginX across multiple WebAdmin runs, he can do so via WebAdmin GUI, with "disable pluginX" information persisted in HTML5 local storage (through WebAdmin's ClientStorage abstraction, using HTML5 if possible, falling back to cookies when not available). What do you think? Regarding GUI -> plugin file changes, I'd also like to avoid it, we could use above mentioned HTML5 local storage for any changes on top of descriptor/configuration data. Cheers, Vojtech ----- Original Message ----- From: "Chris Frantz" <Chris.Frantz@hp.com> To: "Vojtech Szocs" <vszocs@redhat.com> Cc: "engine-devel" <engine-devel@ovirt.org> Sent: Wednesday, September 5, 2012 8:52:28 PM Subject: RE: UI Plugins configuration Vojtech, Please go ahead and include my ideas and/or code into your next patch. With regards to the FIXME, I think using the 'date last modified' is a good idea. However, the plugin descriptor file can also reference the plugin config file (via the configFile property). I imagine that adding, removing or reconfiguring plugins will be a relatively rare event, so maybe there is a simpler method: Remember the newest timestamp of ($DATADIR/ui-plugins/*, $CONFIGDIR/ui-plugins/*) and reload the plugin descriptors and configurations if the newest timestamp changes. As far as synchronization goes, the current code's getPluginDefinitions() loads all of the plugin descriptors and configurations into a new HashMap and then assigns that hashmap to WebadminDynamicHostingServlet.pluginDefinitions. As long as the JsonNode trees in pluginDefinitions aren't modified after being put into pluginDefinitions, I don't see a synchronization issue. Successive calls to get data from the pluginDefinitions hashmap may see different data, but they'll never see inconsistent data (e.g. a partially constructed plugin descriptor). However, if we want to add calls to modify the pluginDefinitions at runtime (such as a element in the GUI that disables certain plugins), then we will need synchronization. We'll also have to concern ourselves with whether any such modifications need to be saved back to the files on disk. --Chris -----Original Message----- From: Vojtech Szocs [mailto:vszocs@redhat.com] Sent: Tuesday, September 04, 2012 7:46 AM To: Frantz, Chris Cc: engine-devel Subject: Re: UI Plugins configuration Thank you Chris :) I'd like to incorporate your ideas into upcoming PoC patch, which will be focused on server-side components of UI plugin infrastructure: 1) servlet that serves plugin-related static resources (plugin host page, actual plugin code, any 3rd party JavaScript libraries, CSS, etc.) from local filesystem 2) class responsible for parsing/validating/caching plugin descriptor information from local filesystem Regarding the comment in WebadminDynamicHostingServlet that says "FIXME: do we load this everytime, or just once?": maybe we could use the same approach as in servlet containers, which use 'date last modified' attribute of JSP files to trigger recompilation of corresponding servlets. For example, each time WebAdmin host page gets requested through WebadminDynamicHostingServlet, we could iterate over plugin descriptor files (in /usr/share/ovirt-engine/ui-plugins), looking at 'date last modified' attribute, parsing/validating plugin meta-data, and caching it using pluginName + dateLastModified (compound cache key). We also need to synchronize the access to plugin meta-data. What do you think? After the upcoming PoC patch (focused on server-side components) gets released, UI plugin infrastructure should be pretty much stable and we can focus on adding particular features, such as: * adding custom sub-tabs * adding custom context-menu items * making REST API calls through plugin API * investigating cross-origin plugin scenario (plugin gets loaded from page sitting on different origin than Engine JBoss instance) Let me know what you think. Cheers, Vojtech ----- Original Message ----- From: "Chris Frantz" <Chris.Frantz@hp.com> To: "Vojtech Szocs" <vszocs@redhat.com> Cc: "engine-devel" <engine-devel@ovirt.org> Sent: Thursday, August 30, 2012 10:03:02 PM Subject: RE: UI Plugins configuration Vojtech, Here is my patch against WIP-UI-Plugins-PoC-revision-4. I’ve also included 2 dummy plugins in sample.tar.gz. --Chris From: engine-devel-bounces@ovirt.org [mailto:engine-devel-bounces@ovirt.org] On Behalf Of Frantz, Chris Sent: Thursday, August 30, 2012 1:06 PM To: Vojtech Szocs Cc: engine-devel Subject: Re: [Engine-devel] UI Plugins configuration Vojtech, I agree with your formalized names: Plugin Descriptor is the JSON file containing plugin meta-data. The plugin descriptor may also contain the default configuration data. It is located in $DATADIR/ui-plugins. Plugin Configuration is the JSON file containing optional plugin configuration info. It is located in $CONFIGDIR/ui-plugins (unless the Plugin Descriptor contains an absolute path). Plugin Definition is the JavaScript object used by WebAdmin. In the current implementation, the Plugin Definition contains both the Plugin Descriptor and the Plugin Configuraion. Plugin Source Page is the HTML page used to invoke the plugin code and shall be referenced by the plugin descriptor’s “url” attribute. I’ve implemented the config merging you’ve suggested: the structure in configFile gets merged with the structure of “config”, with the data in configFile winning in the case of duplicate key names. BTW, the patch is against ovirt-engine + 0001-WIP-UI-Plugins-PoC-revision-2. Let me know what you think, --Chris

Hi,
This is correct. 'pluginDefinitions' HashMap state is not expected to be modified, at least for now (e.g. using Collections.unmodifiableMap).
forgot about changing JsonNode values themselves, within the HashMap :) we should treat them as immutable for now. Vojtech ----- Original Message ----- From: "Vojtech Szocs" <vszocs@redhat.com> To: "Chris Frantz" <Chris.Frantz@hp.com> Cc: "engine-devel" <engine-devel@ovirt.org> Sent: Tuesday, September 11, 2012 2:38:47 PM Subject: Re: [Engine-devel] UI Plugins configuration Hi Chris, sorry for my late response, I'm working on PoC patch rev.5 this week, and was thinking about your ideas, and came up with some modifications. Please let me know what you think. Regarding 'configFile' property in plugin descriptor, maybe we could remove it, in favor of introducing configuration file naming convention '<descriptorFileName>-config.json': (+) there would be a standard plugin configuration file naming convention [making it simpler for plugin end users] (+) Engine (WebAdmin servlet) wouldn't have to parse plugin descriptor just to determine configuration file name This way, reloading plugin descriptors/configuration could work like this: a, iterate through plugin descriptor [*.json] files in $DATADIR/ui-plugins/ directory, remember 'dateLastModified' value b, iterate through plugin configuration [<descriptorFileName>-config.json] files in $CONFIGDIR/ui-plugins/ directory, remember 'dateLastModified' value c, for each plugin descriptor: c1, if (descriptorFileNameNotInCache || currentDescriptorDateLastModified > cachedDescriptorDateLastModified) { goto c3; } c2, else if (currentConfigDateLastModified > cachedConfigDateLastModified) { goto c4; } c3, reload (parse/validate/cache) plugin descriptor c4, reload plugin configuration This is based on following assumptions: 1. plugin descriptor [$DATADIR/ui-plugins/<descriptorFileName>.json] is NOT intended to be modified by end users [packaging system handles this] -> we don't expect plugin descriptor data to change too often 2. plugin configuration [$CONFIGDIR/ui-plugins/<descriptorFileName>-config.json] is intended to be modified by end users -> we expect plugin configuration data to change more frequently This is why I proposed the above mentioned reloading process, in favor of reloading everything when any timestamp (descriptor/configuration) changes to a newer value. Let me know what you think.
As far as synchronization goes, the current code's getPluginDefinitions() loads all of the plugin descriptors and configurations into a new HashMap and then assigns that hashmap to WebadminDynamicHostingServlet.pluginDefinitions. As long as the JsonNode trees in pluginDefinitions aren't modified after being put into pluginDefinitions, I don't see a synchronization issue. Successive calls to get data from the pluginDefinitions hashmap may see different data, but they'll never see inconsistent data (e.g. a partially constructed plugin descriptor).
This is correct. 'pluginDefinitions' HashMap state is not expected to be modified, at least for now (e.g. using Collections.unmodifiableMap). But consider following use-case when invoking WebadminDynamicHostingServlet: [thread #1] nothing needs to be reloaded, writes plugin meta-data into WebAdmin HTML page, writes data for 'plugin1' (1/2 plugins) [thread #2] both 'plugin1' and 'plugin2' descriptor/configuration has changed, reloads them, writes plugin meta-data into WebAdmin HTML page (both plugins), request finished [thread #1] writes data for 'plugin2', request finished As you can see, thread #1 will produce plugin meta-data with 'old' data for 'plugin1', and 'new' data for 'plugin2'. I guess a more appropriate behavior would be that thread #1 will produce 'old' data for both plugins, since nothing new was detected at time when thread #1 checked for changes ("nothing needs to be reloaded"). What do you think?
However, if we want to add calls to modify the pluginDefinitions at runtime (such as a element in the GUI that disables certain plugins), then we will need synchronization. We'll also have to concern ourselves with whether any such modifications need to be saved back to the files on disk.
I'd like to avoid such synchronization. Plugin descriptor/configuration data, after being loaded, should be treated as immutable for the given timestamp. For example, if the user wants to disable pluginX across multiple WebAdmin runs, he can do so via WebAdmin GUI, with "disable pluginX" information persisted in HTML5 local storage (through WebAdmin's ClientStorage abstraction, using HTML5 if possible, falling back to cookies when not available). What do you think? Regarding GUI -> plugin file changes, I'd also like to avoid it, we could use above mentioned HTML5 local storage for any changes on top of descriptor/configuration data. Cheers, Vojtech ----- Original Message ----- From: "Chris Frantz" <Chris.Frantz@hp.com> To: "Vojtech Szocs" <vszocs@redhat.com> Cc: "engine-devel" <engine-devel@ovirt.org> Sent: Wednesday, September 5, 2012 8:52:28 PM Subject: RE: UI Plugins configuration Vojtech, Please go ahead and include my ideas and/or code into your next patch. With regards to the FIXME, I think using the 'date last modified' is a good idea. However, the plugin descriptor file can also reference the plugin config file (via the configFile property). I imagine that adding, removing or reconfiguring plugins will be a relatively rare event, so maybe there is a simpler method: Remember the newest timestamp of ($DATADIR/ui-plugins/*, $CONFIGDIR/ui-plugins/*) and reload the plugin descriptors and configurations if the newest timestamp changes. As far as synchronization goes, the current code's getPluginDefinitions() loads all of the plugin descriptors and configurations into a new HashMap and then assigns that hashmap to WebadminDynamicHostingServlet.pluginDefinitions. As long as the JsonNode trees in pluginDefinitions aren't modified after being put into pluginDefinitions, I don't see a synchronization issue. Successive calls to get data from the pluginDefinitions hashmap may see different data, but they'll never see inconsistent data (e.g. a partially constructed plugin descriptor). However, if we want to add calls to modify the pluginDefinitions at runtime (such as a element in the GUI that disables certain plugins), then we will need synchronization. We'll also have to concern ourselves with whether any such modifications need to be saved back to the files on disk. --Chris -----Original Message----- From: Vojtech Szocs [mailto:vszocs@redhat.com] Sent: Tuesday, September 04, 2012 7:46 AM To: Frantz, Chris Cc: engine-devel Subject: Re: UI Plugins configuration Thank you Chris :) I'd like to incorporate your ideas into upcoming PoC patch, which will be focused on server-side components of UI plugin infrastructure: 1) servlet that serves plugin-related static resources (plugin host page, actual plugin code, any 3rd party JavaScript libraries, CSS, etc.) from local filesystem 2) class responsible for parsing/validating/caching plugin descriptor information from local filesystem Regarding the comment in WebadminDynamicHostingServlet that says "FIXME: do we load this everytime, or just once?": maybe we could use the same approach as in servlet containers, which use 'date last modified' attribute of JSP files to trigger recompilation of corresponding servlets. For example, each time WebAdmin host page gets requested through WebadminDynamicHostingServlet, we could iterate over plugin descriptor files (in /usr/share/ovirt-engine/ui-plugins), looking at 'date last modified' attribute, parsing/validating plugin meta-data, and caching it using pluginName + dateLastModified (compound cache key). We also need to synchronize the access to plugin meta-data. What do you think? After the upcoming PoC patch (focused on server-side components) gets released, UI plugin infrastructure should be pretty much stable and we can focus on adding particular features, such as: * adding custom sub-tabs * adding custom context-menu items * making REST API calls through plugin API * investigating cross-origin plugin scenario (plugin gets loaded from page sitting on different origin than Engine JBoss instance) Let me know what you think. Cheers, Vojtech ----- Original Message ----- From: "Chris Frantz" <Chris.Frantz@hp.com> To: "Vojtech Szocs" <vszocs@redhat.com> Cc: "engine-devel" <engine-devel@ovirt.org> Sent: Thursday, August 30, 2012 10:03:02 PM Subject: RE: UI Plugins configuration Vojtech, Here is my patch against WIP-UI-Plugins-PoC-revision-4. I’ve also included 2 dummy plugins in sample.tar.gz. --Chris From: engine-devel-bounces@ovirt.org [mailto:engine-devel-bounces@ovirt.org] On Behalf Of Frantz, Chris Sent: Thursday, August 30, 2012 1:06 PM To: Vojtech Szocs Cc: engine-devel Subject: Re: [Engine-devel] UI Plugins configuration Vojtech, I agree with your formalized names: Plugin Descriptor is the JSON file containing plugin meta-data. The plugin descriptor may also contain the default configuration data. It is located in $DATADIR/ui-plugins. Plugin Configuration is the JSON file containing optional plugin configuration info. It is located in $CONFIGDIR/ui-plugins (unless the Plugin Descriptor contains an absolute path). Plugin Definition is the JavaScript object used by WebAdmin. In the current implementation, the Plugin Definition contains both the Plugin Descriptor and the Plugin Configuraion. Plugin Source Page is the HTML page used to invoke the plugin code and shall be referenced by the plugin descriptor’s “url” attribute. I’ve implemented the config merging you’ve suggested: the structure in configFile gets merged with the structure of “config”, with the data in configFile winning in the case of duplicate key names. BTW, the patch is against ovirt-engine + 0001-WIP-UI-Plugins-PoC-revision-2. Let me know what you think, --Chris _______________________________________________ Engine-devel mailing list Engine-devel@ovirt.org http://lists.ovirt.org/mailman/listinfo/engine-devel
participants (5)
-
Costea, George
-
Frantz, Chris
-
Itamar Heim
-
Juan Hernandez
-
Vojtech Szocs