
------=_Part_3896354_1791016925.1349203611679 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Hi Chris,=20 many thanks for your feedback and suggestions :)=20 Adding context-sensitive button with corresponding menu item sounds good! I= n fact, this is the proper way how context menu items should be handled, si= nce WebAdmin data grids work with context-sensitive "action buttons" which = are reflected within the context menu. I agree that this is a very useful f= eature to have in plugin API, it should be implemented as part of next majo= r PoC revision.=20 I have a question though: when the user clicks the custom button or corresp= onding context menu item, will your plugin handle common dialog UI (everyth= ing except actual content) on its own, or do you prefer to have some kind o= f "dialog UI" API to create the standard-looking dialog frame for you? I li= ke the idea of using iframe to present custom content though :)=20 As for grouping multiple context-sensitive buttons and corresponding contex= t menu items, this makes sense and we have something like this already impl= emented in WebAdmin (in Host main tab, Power Management drop-down group but= ton, but this is defined not to appear in context menu though). I think thi= s should be part of "custom context-sensitive button / menu item" plugin AP= I feature.=20
If needed we can help work on an implementation for the dialog popup plug= in framework as we=E2=80=99d like to get it in relatively quickly so we can= move forward on the content side of our plugin.=20
If I understand correctly, this is about providing "dialog UI" API to creat= e the standard-looking dialog frame + custom content iframe. I'd like to he= lp with this as well, but you can play with the code and propose a patch on= top of PoC rev.5 [http://gerrit.ovirt.org/8120].=20
For the reverse proxy, would it be easier from a customer standpoint to j= ust include a reverse proxy servlet such as this one?=20
Actually, I was under the impression that oVirt Engine (3.1) package (ovirt= -engine) takes care of setting up Apache web server, which redirects all tr= affic to Engine JBoss AS by default (but maybe I am wrong here). However, i= f this is the case, an efficient way to work around same-origin policy (cro= ss-origin issues) is to configure Apache's reverese proxy module (mod_proxy= ), as discussed in another thread on engine-devel: http://lists.ovirt.org/p= ipermail/engine-devel/2012-September/002511.html=20 This way, you could use Apache to bring Engine and arbitrary (local or remo= te) web services on same origin. What do you think?=20 On the other hand, using a special-purpose reverse proxy servlet directly i= n Engine, not sure if that's a good idea though.. (I'd prefer configuring "= front-end" web server, such as Apache, for this purpose)=20 I'm also sending a couple of updates:=20 UI Plugins Follow-Up Meeting: scheduled for Tuesday, October 9 at 4pm GMT+1= (I'll send a meeting invitation soon, also planning to re-write oVirt UI P= lugins wiki soon after that)=20 PoC rev.5 patch update: many thanks to Juan and Doron for reviewing the rec= ent patch [http://gerrit.ovirt.org/8120]! I'll update the patch accordingly= as revision 5.1=20 Planned items to be included in PoC revision 6:=20 * adding custom context-sensitive button (either separately or within a= button group), along with corresponding context menu item representation= =20 * update custom main tab to show the actual content (iframe) from the g= iven URL=20 * adding custom sub tab that shows content from the given URL=20 More items to consider having in PoC revision 6:=20 * "dialog UI" API to create the standard-looking dialog frame + custom = content iframe=20 * Engine REST API exposed through plugin API=20 * integration with Tasks pane to provide visual feedback on custom oper= ations=20 * extending existing dialogs (e.g. Edit Cluster Policy - custom propert= ies)=20 Let me know what you think.=20 Regards,=20 Vojtech=20 ----- Original Message ----- From: "Christopher Morrissey" <Christopher.Morrissey@netapp.com>=20 To: vszocs@redhat.com=20 Cc: "George Costea" <George.Costea@netapp.com>, "Dustin Schoenbrun" <Dustin= .Schoenbrun@netapp.com>, engine-devel@ovirt.org=20 Sent: Tuesday, October 2, 2012 6:15:34 PM=20 Subject: RE: [Engine-devel] UI Plugins: PoC patch revision 5 is here=20 Hi Vojtech,=20 The patch is great and has cleared up some questions I had about the implem= entation. I=E2=80=99ve been able to get the sample plugins working and wade= d through the code changes, so feel like I have a good understanding of wha= t was delivered. Thanks a lot for putting this all together. I do have a fe= w questions and suggestions for you, though.=20 Will there eventually be a way to add one or more buttons to the context se= nsitive buttons and menus throughout the interface? For example, we=E2=80= =99d like to allow a button to provision a datastore when a data center, cl= uster, or host is selected. When the button is clicked, it would open a dia= log with an iframe in which we would load our interface to perform the asso= ciated action. Some contexts would have several buttons, such as a storage = domain (provision, resize, dedupe management, destroy) so it would probably= make sense for a drop down menu to be available as well so that the number= of buttons above the table doesn=E2=80=99t get too cluttered. We=E2=80=99d= also like to add these same actions to the menus that popup when a context= ual object is right clicked.=20 If needed we can help work on an implementation for the dialog popup plugin= framework as we=E2=80=99d like to get it in relatively quickly so we can m= ove forward on the content side of our plugin.=20 For the reverse proxy, would it be easier from a customer standpoint to jus= t include a reverse proxy servlet such as this one? http://sourceforge.net/= projects/j2ep/=20 I=E2=80=99m just thinking that setting up and managing a plugin for the HTT= P server may be more complex than including one internally that would be tr= ansparent to a customer.=20 Thanks,=20 Chris=20 From: Vojtech Szocs < vszocs@redhat.com >=20 Date: September 21, 2012 4:37:31 PM EDT=20 To: engine-devel < engine-devel@ovirt.org >=20 Subject: [Engine-devel] UI Plugins: PoC patch revision 5 is here=20 <blockquote> Hi guys,=20 it's been a while but here comes the latest revision of UI Plugins proof-of= -concept patch (please find it attached).=20 This revision was originally meant to focus solely on server-side component= s of the plugin infrastructure. However, I ended up implementing all the ma= jor concepts and ideas as discussed on engine-devel mailing list, impacting= both client-side and server-side parts of the plugin infrastructure. As a = result, UI plugin infrastructure should be pretty much complete now, so we = can focus on specific plugin API features in upcoming PoC revisions.=20 There's a whole bunch of changes and improvements in this revision, so I'll= try to cover all the relevant parts step by step. If you have any comments= , questions or ideas, please let me know!=20 So here we go... (or if you just want to get the patch, find the link at th= e end of this message)=20 0. Added new Engine configuration values=20 UI plugin data path is represented by ConfigValues.UIPluginDataPath enum op= tion ("UIPluginDataPath" in vdc_options table), and resolved relative to Co= nfigValues.DataDir if possible. Following (default) values:=20 * UIPluginDataPath =3D ui-plugins=20 * DataDir =3D /usr/share/ovirt-engine=20 result in UI plugin data path: /usr/share/ovirt-engine/ui-plugins=20 UI plugin config path is represented by ConfigValues.UIPluginConfigPath enu= m option ("UIPluginConfigPath" in vdc_options table), and resolved relative= to ConfigValues.ConfigDir if possible. Following (default) values:=20 * UIPluginConfigPath =3D ui-plugins=20 * ConfigDir =3D /etc/ovirt-engine=20 result in UI plugin config path: /etc/ovirt-engine/ui-plugins=20 1. Processing UI plugin data on the server=20 PluginDataManager is the class responsible for reading, validating and cach= ing UI plugin descriptor/configuration data on the server (Engine). It has = two main responsibilities:=20 * return a snapshot of currently valid plugin data ( getCurrentData met= hod)=20 * reload plugin data from local file system if necessary ( reloadData m= ethod)=20 The reloadData method doesn't modify "live" plugin data directly. Instead, = it creates a local working copy of current plugin data, updates this copy a= s it reads/validates plugin descriptor and configuration files, and attempt= s to update "live" plugin data through conditional reference re-assignment = (using java.util.concurrent.atomic.AtomicReference.compareAndSet method).= =20 In other words, reloadData method makes no attempts with regard to Java loc= k-based synchronization, in favor of dealing with "live" data through Atomi= cReference (reference that involves atomic volatile reads and writes):=20 * In the best case, a thread will succeed in updating "live" data ( Ato= micReference.compareAndSet =3D=3D true), which means that "live" data remai= ned unchanged since this thread acquired a reference of current plugin data= .=20 * In the worst case, a thread will NOT succeed in updating "live" data = ( AtomicReference.compareAndSet =3D=3D false), which means that "live" data= was already changed by another thread since this thread acquired a referen= ce of current plugin data.=20 In my opinion, when dealing with external resources like the local file sys= tem, this is a good compromise between performance and up-to-date data. Whi= le we might not get "completely-up-to-date" data at the given point in time= ( reloadData + getCurrentData ), we are guaranteed to get "recently-up-to-= date" and consistent data. In other words, the requirement of "completely-u= p-to-date" data would involve synchronized statements that would hurt perfo= rmance. In my (very humble) opinion, the benefit of having "completely-up-t= o-date" data, at the cost of reduced performance, is not really worth it, e= specially in our case when the user can just hit refresh (F5) to reload Web= Admin and its plugin data.=20 Plugin descriptor files are expected to be placed in UI plugin data path, f= or example: /usr/share/ovirt-engine/ui-plugins/foo.json=20 Following descriptor file attributes are implemented and recognized by the = plugin infrastructure:=20 * name : A name that uniquely identifies the plugin (required attribute= ).=20 * url : URL of plugin host page that invokes the plugin code (required = attribute).=20 * config : Default configuration object associated with the plugin (opt= ional attribute).=20 * resourcePath : Path to plugin static resources, relative to UI plugin= data path (optional attribute). This is used when serving plugin files thr= ough Engine PluginResourceServlet (more on this below).=20 Plugin configuration files are expected to be placed in UI plugin config pa= th, for example: /etc/engine/ui-plugins/foo-config.json=20 Note that plugin configuration files follow the "<descriptorFileName>-confi= g.json" convention.=20 Following configuration file attributes are implemented and recognized by t= he plugin infrastructure:=20 * config : Custom configuration object associated with the plugin (opti= onal attribute). This overrides the default plugin descriptor configuration= , if any.=20 * enabled : Indicates whether the plugin should be loaded on WebAdmin s= tartup (optional attribute). Default value is 'true'.=20 * order : Defines the relative order in which the plugin will be loaded= on WebAdmin startup (optional attribute). Default value is Integer.MAX_VAL= UE (lowest order).=20 The concept of merging custom configuration ( config attribute in foo-confi= g.json ), if any, on top of default configuration ( config attribute in foo= .json ), if any, remains unchanged. This makes the plugin configuration qui= te flexible - in my opinion, the added complexity of handling/merging such = configuration is definitely worth the effort.=20 The enabled attribute is straight-forward, allowing users to turn the given= plugin off, if necessary. In future, users should still be able to load su= ch plugins through WebAdmin GUI.=20 The order attribute controls the order in which plugins are loaded on WebAd= min startup. Since plugin resources are fetched asynchronously by the brows= er, this is basically a way of imposing some degree of determinism in the "= generally-non-deterministic" plugin environment, which is helpful when trou= bleshooting problems with multiple plugins. This attribute is also helpful = due to file listing methods in java.io.File giving no guarantees that files= would be listed in any particular order (otherwise we could just go for th= e "NN-<descriptorFileName>.json" convention, with NN being the order number= ).=20 2. Modified behavior of WebadminDynamicHostingServlet=20 WebadminDynamicHostingServlet is the servlet used to serve WebAdmin applica= tion host page (HTML page that bootstraps WebAdmin JavaScript code).=20 In addition to its former behavior, as part of handling the given request, = WebadminDynamicHostingServlet :=20 * reloads descriptor/configuration data from local file system if neces= sary, and obtains a snapshot of currently valid plugin data ( PluginDataMan= ager.reloadAndGetCurrentData )=20 * embeds all plugin meta-data, suitable for use in client-side plugin i= nfrastructure, into WebAdmin host page as "pluginDefinitions" JavaScript ar= ray ( PluginDefinitions )=20 As a result, reloading UI plugin descriptor/configuration data is as simple= as refreshing (F5) WebAdmin application in the browser (no need to restart= Engine).=20 3. Added servlet for serving plugin static resources=20 PluginResourceServlet is the servlet used to serve UI plugin static files (= plugin host page, 3rd party JavaScript, etc.) from the local file system.= =20 For example, requesting URL:=20 * http://<EngineManagerHost>:8700/webadmin/webadmin/plugin/foo/content/= start.html=20 will send the content of:=20 * /usr/share/ovirt-engine/ui-plugins/<resourcePath>/content/start.html= =20 to the client.=20 As shown in the above example:=20 * /webadmin/webadmin/plugin/ is the servlet root path for PluginResourc= eServlet=20 * in the extra path beyond the servlet root path ( /foo/content/start.h= tml ):=20 * /foo represents the name of the plugin=20 * /content/start.html represents the path to requested resource, re= lative to "UIPluginDataPath / <resourcePath>"=20 Note that each plugin using PluginResourceServlet to serve its static files= must declare non-empty resourcePath attribute in within the plugin descrip= tor.=20 Also note that PluginResourceServlet , unlike WebadminDynamicHostingServlet= , does NOT reload descriptor/configuration data from local file system as = part of handling the given request. In other words, it's assumed that plugi= n data has already been (re)loaded when serving WebAdmin application host p= age, with subsequent requests to PluginResourceServlet reading the current = plugin information.=20 Until we solve the cross-origin issue in a clean way, PluginResourceServlet= should be used to serve all plugin resources from local file system.=20 4. Plugin lifecycle improved to deal with misbehaving plugins=20 PluginState enum has been modified to deal with plugins that allow uncaught= exceptions to escape from plugin event handler functions (e.g. "UiInit"):= =20 * removed state INITIALIZED=20 * added state INITIALIZING : The plugin is (currently) being initialize= d by calling UiInit event handler function.=20 * added state IN_USE : Plugin's UiInit event handler function has compl= eted successfully, we can now call other event handler functions as necessa= ry. The plugin is in use now.=20 * added state FAILED : An uncaught exception escaped while calling an e= vent handler function, which indicates internal error within the plugin cod= e. The plugin is removed from service.=20 I've attached a simple state diagram that illustrates different states and = transitions between them (green color is initial state, red color is end st= ate).=20 Uncaught exceptions in plugin event handler functions will be caught and ha= ndled by the plugin infrastructure. This prevents a misbehaving plugin from= breaking WebAdmin application, since WebAdmin is the caller (initiator) of= the function call. In such case, the plugin will be removed from service.= =20 Update on cross-origin issue (consequence of same-origin policy)=20 In order for the plugin to access WebAdmin plugin API, plugin host page (e.= g. start.html ) must be served from URL on same origin as Engine origin. Ot= herwise, plugin code running in the context of an iframe'd host page will f= ail to evaluate "parent.pluginApi" expression, with "parent" being top-leve= l (WebAdmin) window, and "pluginApi" being the global plugin API object exp= osed by WebAdmin.=20 This is why PluginResourceServlet , available on Engine origin, should be u= sed to serve all plugin resources from local file system.=20 There's only one issue that remains to be solved: cross-origin "plugin vs. = remote service" communication, with "remote service" being anything other t= han Engine (REST API). In future, we'll address this with Apache reverse pr= oxy configuration, so that users can configure Apache server (placed in fro= nt of Engine JBoss AS) to put arbitrary (local or remote non-Engine) servic= es on same origin. However, this requires a change in current Apache config= uration. Until then, users can manually edit the Engine Apache configuratio= n file ( /etc/httpd/conf.d/ovirt-engine.conf ).=20 I've attached some sample plugin files for you to experiment with. Instead = of attaching actual patch file (92 kB) to this email, I've submitted the pa= tch to oVirt Gerrit: http://gerrit.ovirt.org/8120=20 Let me know what you think!=20 Cheers,=20 Vojtech=20 </blockquote> <blockquote> <ui-plugin-sample-files.tar.gz>=20 </blockquote> <blockquote> <ui-plugin-lifecycle.png>=20 </blockquote> <blockquote> _______________________________________________=20 Engine-devel mailing list=20 Engine-devel@ovirt.org=20 http://lists.ovirt.org/mailman/listinfo/engine-devel=20 </blockquote> ------=_Part_3896354_1791016925.1349203611679 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>many thanks for your feedback and su= ggestions :)<br><br>Adding context-sensitive button with corresponding menu= item sounds good! In fact, this is the proper way how context menu items s= hould be handled, since WebAdmin data grids work with context-sensitive "ac= tion buttons" which are reflected within the context menu. I agree that thi= s is a very useful feature to have in plugin API, it should be implemented = as part of next major PoC revision.<br><br>I have a question though: when t= he user clicks the custom button or corresponding context menu item, will y= our plugin handle common dialog UI (everything except actual content) on it= s own, or do you prefer to have some kind of "dialog UI" API to create the = standard-looking dialog frame for you? I like the idea of using iframe to p= resent custom content though :)<br><br>As for grouping multiple context-sen= sitive buttons and corresponding context menu items, this makes sense and w= e have something like this already implemented in WebAdmin (in Host main ta= b, Power Management drop-down group button, but this is defined not to appe= ar in context menu though). I think this should be part of "custom context-= sensitive button / menu item" plugin API feature.<br><br>> <span style= =3D"font-size:11.0pt;font-family:"Calibri","sans-serif"= ;color:#1F497D">If needed we can help work on an implementation for the dialog popup=20 plugin framework as we=E2=80=99d like to get it in relatively quickly so we= can=20 move forward on the content side of our plugin.</span><br><br>If I understand correctly, t= his is about providing "dialog UI" API to create the standard-looking dialo= g frame + custom content iframe. I'd like to help with this as well, = but you can play with the code and propose a patch on top of PoC rev.5 [htt= p://gerrit.ovirt.org/8120].<br><br>> <span style=3D"font-size:11.0pt;fon= t-family:"Calibri","sans-serif";color:#1F497D">For the = reverse proxy, would it be easier from a customer standpoint to just includ= e a reverse proxy servlet such as this one?<br></span><br>Actually, I was u= nder the impression that oVirt Engine (3.1) package (ovirt-engine) takes ca= re of setting up Apache web server, which redirects all traffic to Engine J= Boss AS by default (but maybe I am wrong here). However, if this is the cas= e, an efficient way to work around same-origin policy (cross-origin issues)= is to configure Apache's reverese proxy module (mod_proxy), as discussed i= n another thread on engine-devel: http://lists.ovirt.org/pipermail/engine-d= evel/2012-September/002511.html<br><br>This way, you could use Apache to br= ing Engine and arbitrary (local or remote) web services on same origin. Wha= t do you think?<br><br>On the other hand, using a special-purpose reverse p= roxy servlet directly in Engine, not sure if that's a good idea though.. (I= 'd prefer configuring "front-end" web server, such as Apache, for this purp= ose)<br><br>I'm also sending a couple of updates:<br><br><strong>UI Plugins= Follow-Up Meeting:</strong> scheduled for Tuesday, October 9 at 4pm GMT+1 = (I'll send a meeting invitation soon, also planning to re-write oVirt UI Pl= ugins wiki soon after that)<br><br><span style=3D"font-weight: bold;">PoC r= ev.5 patch update:</span> many thanks to Juan and Doron for reviewing the r= ecent patch [http://gerrit.ovirt.org/8120]! I'll update the patch according= ly as revision 5.1<br><br><span style=3D"font-weight: bold;">Planned items = to be included in PoC revision 6:</span><br><ul><li>adding custom context-s= ensitive button (either separately or within a button group), along with co= rresponding context menu item representation</li><li>update custom main tab= to show the actual content (iframe) from the given URL</li><li>adding cust= om sub tab that shows content from the given URL</li></ul><p><br></p><p><sp= an style=3D"font-weight: bold;">More items to consider having in PoC revisi= on 6:</span><br></p><ul><li>"dialog UI" API to create the standard-looking = dialog frame + custom content iframe</li><li>Engine REST API exposed throug= h plugin API</li><li>integration with Tasks pane to provide visual feedback= on custom operations</li><li>extending existing dialogs (e.g. Edit Cluster= Policy - custom properties)<br></li></ul><p><br></p><p>Let me know what yo= u think.<br></p><p><br></p><p></p>Regards,<br>Vojtech<br><br><br><hr id=3D"= zwchr"><div style=3D"color:#000;font-weight:normal;font-style:normal;text-d= ecoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;"><b>F= rom: </b>"Christopher Morrissey" <Christopher.Morrissey@netapp.com><b= r><b>To: </b>vszocs@redhat.com<br><b>Cc: </b>"George Costea" <George.Cos= tea@netapp.com>, "Dustin Schoenbrun" <Dustin.Schoenbrun@netapp.com>= ;, engine-devel@ovirt.org<br><b>Sent: </b>Tuesday, October 2, 2012 6:15:34 = PM<br><b>Subject: </b>RE: [Engine-devel] UI Plugins: PoC patch revision 5 i= s here<br><br> <style><!-- @font-face =09{font-family:Wingdings; =09panose-1:5 0 0 0 0 0 0 0 0 0;} @font-face =09{font-family:Wingdings; =09panose-1:5 0 0 0 0 0 0 0 0 0;} @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; =09mso-margin-top-alt:auto; =09margin-right:0in; =09mso-margin-bottom-alt:auto; =09margin-left:0in; =09font-size:12.0pt; =09font-family:"Times New Roman","serif";} p.MsoAcetate, li.MsoAcetate, div.MsoAcetate =09{mso-style-priority:99; =09mso-style-link:"Balloon Text Char"; =09margin:0in; =09margin-bottom:.0001pt; =09font-size:8.0pt; =09font-family:"Tahoma","sans-serif";} span.BalloonTextChar =09{mso-style-name:"Balloon Text Char"; =09mso-style-priority:99; =09mso-style-link:"Balloon Text"; =09font-family:"Tahoma","sans-serif";} span.EmailStyle20 =09{mso-style-type:personal; =09font-family:"Calibri","sans-serif"; =09color:#1F497D;} span.EmailStyle23 =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:180434570; =09mso-list-template-ids:-282402880;} @list l0:level1 =09{mso-level-number-format:bullet; =09mso-level-text:\F0B7; =09mso-level-tab-stop:.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Symbol;} @list l0:level2 =09{mso-level-number-format:bullet; =09mso-level-text:o; =09mso-level-tab-stop:1.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:"Courier New"; =09mso-bidi-font-family:"Times New Roman";} @list l0:level3 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:1.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l0:level4 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:2.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l0:level5 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:2.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l0:level6 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:3.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l0:level7 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:3.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l0:level8 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:4.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l0:level9 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:4.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l1 =09{mso-list-id:259874230; =09mso-list-template-ids:-1105409970;} @list l1:level1 =09{mso-level-number-format:bullet; =09mso-level-text:\F0B7; =09mso-level-tab-stop:.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Symbol;} @list l1:level2 =09{mso-level-number-format:bullet; =09mso-level-text:o; =09mso-level-tab-stop:1.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:"Courier New"; =09mso-bidi-font-family:"Times New Roman";} @list l1:level3 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:1.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l1:level4 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:2.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l1:level5 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:2.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l1:level6 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:3.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l1:level7 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:3.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l1:level8 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:4.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l1:level9 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:4.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l2 =09{mso-list-id:580258439; =09mso-list-template-ids:-6366690;} @list l2:level1 =09{mso-level-number-format:bullet; =09mso-level-text:\F0B7; =09mso-level-tab-stop:.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Symbol;} @list l2:level2 =09{mso-level-number-format:bullet; =09mso-level-text:o; =09mso-level-tab-stop:1.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:"Courier New"; =09mso-bidi-font-family:"Times New Roman";} @list l2:level3 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:1.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l2:level4 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:2.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l2:level5 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:2.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l2:level6 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:3.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l2:level7 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:3.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l2:level8 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:4.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l2:level9 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:4.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l3 =09{mso-list-id:713581435; =09mso-list-template-ids:2069783976;} @list l3:level1 =09{mso-level-number-format:bullet; =09mso-level-text:\F0B7; =09mso-level-tab-stop:.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Symbol;} @list l3:level2 =09{mso-level-number-format:bullet; =09mso-level-text:o; =09mso-level-tab-stop:1.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:"Courier New"; =09mso-bidi-font-family:"Times New Roman";} @list l3:level3 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:1.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l3:level4 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:2.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l3:level5 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:2.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l3:level6 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:3.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l3:level7 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:3.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l3:level8 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:4.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l3:level9 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:4.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l4 =09{mso-list-id:765921994; =09mso-list-template-ids:400719310;} @list l4:level1 =09{mso-level-number-format:bullet; =09mso-level-text:\F0B7; =09mso-level-tab-stop:.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Symbol;} @list l4:level2 =09{mso-level-number-format:bullet; =09mso-level-text:o; =09mso-level-tab-stop:1.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:"Courier New"; =09mso-bidi-font-family:"Times New Roman";} @list l4:level3 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:1.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l4:level4 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:2.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l4:level5 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:2.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l4:level6 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:3.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l4:level7 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:3.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l4:level8 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:4.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l4:level9 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:4.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l5 =09{mso-list-id:843908114; =09mso-list-template-ids:-1243547606;} @list l5:level1 =09{mso-level-number-format:bullet; =09mso-level-text:\F0B7; =09mso-level-tab-stop:.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Symbol;} @list l5:level2 =09{mso-level-number-format:bullet; =09mso-level-text:o; =09mso-level-tab-stop:1.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:"Courier New"; =09mso-bidi-font-family:"Times New Roman";} @list l5:level3 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:1.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l5:level4 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:2.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l5:level5 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:2.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l5:level6 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:3.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l5:level7 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:3.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l5:level8 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:4.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l5:level9 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:4.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l6 =09{mso-list-id:964771435; =09mso-list-template-ids:-2000783132;} @list l6:level1 =09{mso-level-number-format:bullet; =09mso-level-text:\F0B7; =09mso-level-tab-stop:.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Symbol;} @list l6:level2 =09{mso-level-number-format:bullet; =09mso-level-text:o; =09mso-level-tab-stop:1.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:"Courier New"; =09mso-bidi-font-family:"Times New Roman";} @list l6:level3 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:1.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l6:level4 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:2.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l6:level5 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:2.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l6:level6 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:3.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l6:level7 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:3.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l6:level8 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:4.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l6:level9 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:4.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l7 =09{mso-list-id:1176848642; =09mso-list-template-ids:1223565722;} @list l7:level1 =09{mso-level-number-format:bullet; =09mso-level-text:\F0B7; =09mso-level-tab-stop:.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Symbol;} @list l7:level2 =09{mso-level-number-format:bullet; =09mso-level-text:o; =09mso-level-tab-stop:1.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:"Courier New"; =09mso-bidi-font-family:"Times New Roman";} @list l7:level3 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:1.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l7:level4 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:2.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l7:level5 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:2.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l7:level6 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:3.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l7:level7 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:3.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l7:level8 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:4.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l7:level9 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:4.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l8 =09{mso-list-id:1311206220; =09mso-list-template-ids:314224160;} @list l8:level1 =09{mso-level-number-format:bullet; =09mso-level-text:\F0B7; =09mso-level-tab-stop:.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Symbol;} @list l8:level2 =09{mso-level-number-format:bullet; =09mso-level-text:o; =09mso-level-tab-stop:1.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:"Courier New"; =09mso-bidi-font-family:"Times New Roman";} @list l8:level3 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:1.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l8:level4 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:2.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l8:level5 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:2.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l8:level6 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:3.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l8:level7 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:3.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l8:level8 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:4.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l8:level9 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:4.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l9 =09{mso-list-id:1434012829; =09mso-list-template-ids:-690447050;} @list l9:level1 =09{mso-level-number-format:bullet; =09mso-level-text:\F0B7; =09mso-level-tab-stop:.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Symbol;} @list l9:level2 =09{mso-level-number-format:bullet; =09mso-level-text:o; =09mso-level-tab-stop:1.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:"Courier New"; =09mso-bidi-font-family:"Times New Roman";} @list l9:level3 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:1.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l9:level4 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:2.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l9:level5 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:2.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l9:level6 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:3.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l9:level7 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:3.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l9:level8 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:4.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l9:level9 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:4.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l10 =09{mso-list-id:2135564416; =09mso-list-template-ids:728504136;} @list l10:level1 =09{mso-level-number-format:bullet; =09mso-level-text:\F0B7; =09mso-level-tab-stop:.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Symbol;} @list l10:level2 =09{mso-level-number-format:bullet; =09mso-level-text:o; =09mso-level-tab-stop:1.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:"Courier New"; =09mso-bidi-font-family:"Times New Roman";} @list l10:level3 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:1.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l10:level4 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:2.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l10:level5 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:2.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l10:level6 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:3.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l10:level7 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:3.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l10:level8 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:4.0in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} @list l10:level9 =09{mso-level-number-format:bullet; =09mso-level-text:\F0A7; =09mso-level-tab-stop:4.5in; =09mso-level-number-position:left; =09text-indent:-.25in; =09mso-ansi-font-size:10.0pt; =09font-family:Wingdings;} 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">Hi 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">The patch is great and ha= s cleared up some questions I had about the implementation. I=E2=80=99ve be= en able to get the sample plugins working and waded through the code changes, so feel like I have a good understanding of what was deliver= ed. Thanks a lot for putting this all together. I do have a few questions a= nd suggestions for you, though.</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">Will there eventually be = a way to add one or more buttons to the context sensitive buttons and menus= throughout the interface? For example, we=E2=80=99d like to allow a button to provision a datastore when a data center, cluster, or host is = selected. When the button is clicked, it would open a dialog with an iframe= in which we would load our interface to perform the associated action. Som= e contexts would have several buttons, such as a storage domain (provision, resize, dedupe management, destroy) s= o it would probably make sense for a drop down menu to be available as well= so that the number of buttons above the table doesn=E2=80=99t get too clut= tered. We=E2=80=99d also like to add these same actions to the menus that popup when a contextual object is right clicked.= </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 needed we can help wor= k on an implementation for the dialog popup plugin framework as we=E2=80=99= d like to get it in relatively quickly so we can move forward on the content side of our plugin.</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">For the reverse proxy, wo= uld it be easier from a customer standpoint to just include a reverse proxy= servlet such as this one? </span><a href=3D"http://sourceforge.net/p= rojects/j2ep/" target=3D"_blank">http://sourceforge.net/projects/j2ep/</a> </p> <p class=3D"MsoNormal"><span style=3D"font-size:11.0pt;font-family:"Ca= libri","sans-serif";color:#1F497D">I=E2=80=99m just thinking= that setting up and managing a plugin for the HTTP server may be more comp= lex than including one internally that would be transparent to a customer.</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> <blockquote style=3D"margin-top:5.0pt;margin-bottom:5.0pt"> <div> <p class=3D"MsoNormal" style=3D"margin-bottom:12.0pt"><b>From:</b> Vojtech = Szocs <<a href=3D"mailto:vszocs@redhat.com" target=3D"_blank">vszocs@red= hat.com</a>><br> <b>Date:</b> September 21, 2012 4:37:31 PM EDT<br> <b>To:</b> engine-devel <<a href=3D"mailto:engine-devel@ovirt.org" targe= t=3D"_blank">engine-devel@ovirt.org</a>><br> <b>Subject:</b> <b>[Engine-devel] UI Plugins: PoC patch revision 5 is here<= /b></p> </div> </blockquote> <blockquote style=3D"margin-top:5.0pt;margin-bottom:5.0pt"> <div> <div> <p class=3D"MsoNormal" style=3D"margin-bottom:12.0pt"><span style=3D"color:= black">Hi guys,<br> <br> it's been a while but here comes the latest revision of UI Plugins proof-of= -concept patch (please find it attached).<br> <br> This revision was originally meant to focus solely on server-side component= s of the plugin infrastructure. However, I ended up implementing all the ma= jor concepts and ideas as discussed on engine-devel mailing list, impacting= both client-side and server-side parts of the plugin infrastructure. As a result, UI plugin infrastructure = should be pretty much complete now, so we can focus on specific plugin API = features in upcoming PoC revisions.<br> <br> There's a whole bunch of changes and improvements in this revision, so I'll= try to cover all the relevant parts step by step. If you have any comments= , questions or ideas, please let me know!<br> <br> So here we go... (or if you just want to get the patch, find the link at th= e end of this message)</span></p> <div class=3D"MsoNormal" style=3D"text-align:center" align=3D"center"><span= style=3D"color:black"> <hr align=3D"center" size=3D"2" width=3D"100%"> </span></div> <p class=3D"MsoNormal"><span style=3D"color:black"><br> <strong>0. Added new Engine configuration values</strong><b><br> </b><br> <u>UI plugin data path</u> is represented by <em>ConfigValues.UIPluginDataP= ath</em> enum option ("UIPluginDataPath" in <i>vdc_options</i> table), and resolved relative to <i>ConfigValues.DataDir= </i> if possible. Following (default) values:</span></p> <ul type=3D"disc"> <li class=3D"MsoNormal" style=3D"color:black;mso-margin-top-alt:auto;mso-ma= rgin-bottom-alt:auto;mso-list:l0 level1 lfo1"> <i>UIPluginDataPath =3D ui-plugins</i></li><li class=3D"MsoNormal" style=3D= "color:black;mso-margin-top-alt:auto;mso-margin-bottom-alt:auto;mso-list:l0= level1 lfo1"> <i>DataDir =3D /usr/share/ovirt-engine</i></li></ul> <p class=3D"MsoNormal"><span style=3D"color:black">result in UI plugin data= path: <i> /usr/share/ovirt-engine/ui-plugins</i><br> <br> <u>UI plugin config path</u> is represented by <i>ConfigValues.UIPluginConf= igPath</i> enum option ("UIPluginConfigPath" in <i>vdc_options</i> table), and resolved relative to <i>ConfigValues.ConfigD= ir</i> if possible. Following (default) values:</span></p> <ul type=3D"disc"> <li class=3D"MsoNormal" style=3D"color:black;mso-margin-top-alt:auto;mso-ma= rgin-bottom-alt:auto;mso-list:l3 level1 lfo2"> <i>UIPluginConfigPath =3D ui-plugins</i></li><li class=3D"MsoNormal" style= =3D"color:black;mso-margin-top-alt:auto;mso-margin-bottom-alt:auto;mso-list= :l3 level1 lfo2"> <i>ConfigDir =3D /etc/ovirt-engine</i></li></ul> <p><span style=3D"color:black">result in UI plugin config path: <i>/etc/ovi= rt-engine/ui-plugins</i></span></p> <p class=3D"MsoNormal"><span style=3D"color:black"><br> <b>1. Processing UI plugin data on the server<br> </b><br> <i>PluginDataManager</i> is the class responsible for reading, validating a= nd caching UI plugin descriptor/configuration data on the server (Engine). = It has two main responsibilities:</span></p> <ul type=3D"disc"> <li class=3D"MsoNormal" style=3D"color:black;mso-margin-top-alt:auto;mso-ma= rgin-bottom-alt:auto;mso-list:l2 level1 lfo3"> return a snapshot of currently valid plugin data (<i>getCurrentData</i> met= hod)</li><li class=3D"MsoNormal" style=3D"color:black;mso-margin-top-alt:au= to;mso-margin-bottom-alt:auto;mso-list:l2 level1 lfo3"> reload plugin data from local file system if necessary (<i>reloadData</i> m= ethod)</li></ul> <p><span style=3D"color:black">The <i>reloadData</i> method doesn't modify = "live" plugin data directly. Instead, it creates a local working copy of cu= rrent plugin data, updates this copy as it reads/validates plugin descripto= r and configuration files, and attempts to update "live" plugin data through conditional reference re-assignment (= using <i> java.util.concurrent.atomic.AtomicReference.compareAndSet</i> method).</spa= n></p> <p><span style=3D"color:black"> </span></p> <p><span style=3D"color:black">In other words, <i>reloadData</i> method mak= es no attempts with regard to Java lock-based synchronization, in favor of = dealing with "live" data through <i>AtomicReference</i> (reference that involves atomic <i>volatile</i> read= s and writes):</span></p> <ul type=3D"disc"> <li class=3D"MsoNormal" style=3D"color:black;mso-margin-top-alt:auto;mso-ma= rgin-bottom-alt:auto;mso-list:l4 level1 lfo4"> In the best case, a thread will succeed in updating "live" data (<i>AtomicR= eference.compareAndSet</i> =3D=3D true), which means that "live" data remai= ned unchanged since this thread acquired a reference of current plugin data= .</li><li class=3D"MsoNormal" style=3D"color:black;mso-margin-top-alt:auto;= mso-margin-bottom-alt:auto;mso-list:l4 level1 lfo4"> In the worst case, a thread will NOT succeed in updating "live" data (<i>At= omicReference.compareAndSet</i> =3D=3D false), which means that "live" data= was already changed by another thread since this thread acquired a referen= ce of current plugin data.</li></ul> <p><span style=3D"color:black">In my opinion, when dealing with external re= sources like the local file system, this is a good compromise between perfo= rmance and up-to-date data. While we might not get "completely-up-to-date" = data at the given point in time (<i>reloadData + getCurrentData</i>), we are guaranteed to get "recently-up-to-date" and = consistent data. In other words, the requirement of "completely-up-to-date"= data would involve <i>synchronized</i> statements that would hurt performance. In my (very hum= ble) opinion, the benefit of having "completely-up-to-date" data, at the co= st of reduced performance, is not really worth it, especially in our case w= hen the user can just hit refresh (F5) to reload WebAdmin and its plugin data.</span></p> <p><span style=3D"color:black"> </span></p> <p><u><span style=3D"color:black">Plugin descriptor files</span></u><span s= tyle=3D"color:black"> are expected to be placed in UI plugin data path, for= example: <i>/usr/share/ovirt-engine/ui-plugins/foo.json</i></span></p> <p><span style=3D"color:black"> </span></p> <p><span style=3D"color:black">Following descriptor file attributes are imp= lemented and recognized by the plugin infrastructure:</span></p> <ul type=3D"disc"> <li class=3D"MsoNormal" style=3D"color:black;mso-margin-top-alt:auto;mso-ma= rgin-bottom-alt:auto;mso-list:l9 level1 lfo5"> <i>name</i>: A name that uniquely identifies the plugin (required attribute= ).</li><li class=3D"MsoNormal" style=3D"color:black;mso-margin-top-alt:auto= ;mso-margin-bottom-alt:auto;mso-list:l9 level1 lfo5"> <i>url</i>: URL of plugin host page that invokes the plugin code (required = attribute).</li><li class=3D"MsoNormal" style=3D"color:black;mso-margin-top= -alt:auto;mso-margin-bottom-alt:auto;mso-list:l9 level1 lfo5"> <i>config</i>: Default configuration object associated with the plugin (opt= ional attribute).</li><li class=3D"MsoNormal" style=3D"color:black;mso-marg= in-top-alt:auto;mso-margin-bottom-alt:auto;mso-list:l9 level1 lfo5"> <i>resourcePath</i>: Path to plugin static resources, relative to UI plugin= data path (optional attribute). This is used when serving plugin files thr= ough Engine <i>PluginResourceServlet</i> (more on this below).</li></ul> <p><u><span style=3D"color:black">Plugin configuration files</span></u><spa= n style=3D"color:black"> are expected to be placed in UI plugin config path= , for example: <i>/etc/engine/ui-plugins/foo-config.json</i></span></p> <p><span style=3D"color:black"> </span></p> <p><span style=3D"color:black">Note that plugin configuration files follow = the "<descriptorFileName>-config.json" convention.</span></p> <p><span style=3D"color:black"> </span></p> <p><span style=3D"color:black">Following configuration file attributes are = implemented and recognized by the plugin infrastructure:</span></p> <ul type=3D"disc"> <li class=3D"MsoNormal" style=3D"color:black;mso-margin-top-alt:auto;mso-ma= rgin-bottom-alt:auto;mso-list:l8 level1 lfo6"> <i>config</i>: Custom configuration object associated with the plugin (opti= onal attribute). This overrides the default plugin descriptor configuration= , if any.</li><li class=3D"MsoNormal" style=3D"color:black;mso-margin-top-a= lt:auto;mso-margin-bottom-alt:auto;mso-list:l8 level1 lfo6"> <i>enabled</i>: Indicates whether the plugin should be loaded on WebAdmin s= tartup (optional attribute). Default value is 'true'.</li><li class=3D"MsoN= ormal" style=3D"color:black;mso-margin-top-alt:auto;mso-margin-bottom-alt:a= uto;mso-list:l8 level1 lfo6"> <i>order</i>: Defines the relative order in which the plugin will be loaded= on WebAdmin startup (optional attribute). Default value is <i>Integer.MAX_VALUE</i> (lowest order).</li></ul> <p><span style=3D"color:black">The concept of merging custom configuration = (<i>config</i> attribute in <i>foo-config.json</i>), if any, on top of default configuration (<i>config= </i> attribute in <i>foo.json</i>), if any, remains unchanged. This makes the plugin configur= ation quite flexible - in my opinion, the added complexity of handling/merg= ing such configuration is definitely worth the effort.</span></p> <p><span style=3D"color:black"> </span></p> <p><span style=3D"color:black">The <i>enabled</i> attribute is straight-for= ward, allowing users to turn the given plugin off, if necessary. In future,= users should still be able to load such plugins through WebAdmin GUI.</spa= n></p> <p><span style=3D"color:black"> </span></p> <p><span style=3D"color:black">The <i>order</i> attribute controls the orde= r in which plugins are loaded on WebAdmin startup. Since plugin resources a= re fetched asynchronously by the browser, this is basically a way of imposi= ng some degree of determinism in the "generally-non-deterministic" plugin environment, which is helpful when tr= oubleshooting problems with multiple plugins. This attribute is also helpfu= l due to file listing methods in <i>java.io.File</i> giving no guarantees that files would be listed in any = particular order (otherwise we could just go for the "NN-<descriptorFile= Name>.json" convention, with NN being the order number).</span></p> <p class=3D"MsoNormal"><span style=3D"color:black"><br> <b>2. Modified behavior of WebadminDynamicHostingServlet<br> </b><br> <i>WebadminDynamicHostingServlet</i> is the servlet used to serve WebAdmin = application host page (HTML page that bootstraps WebAdmin JavaScript code).= <br> <br> In addition to its former behavior, as part of handling the given request, = <i>WebadminDynamicHostingServlet</i>:</span></p> <ul type=3D"disc"> <li class=3D"MsoNormal" style=3D"color:black;mso-margin-top-alt:auto;mso-ma= rgin-bottom-alt:auto;mso-list:l7 level1 lfo7"> reloads descriptor/configuration data from local file system if necessary, = and obtains a snapshot of currently valid plugin data (<i>PluginDataManager= .reloadAndGetCurrentData</i>)</li><li class=3D"MsoNormal" style=3D"color:bl= ack;mso-margin-top-alt:auto;mso-margin-bottom-alt:auto;mso-list:l7 level1 l= fo7"> embeds all plugin meta-data, suitable for use in client-side plugin infrast= ructure, into WebAdmin host page as "pluginDefinitions" JavaScript array (<= i>PluginDefinitions</i>)</li></ul> <p class=3D"MsoNormal"><span style=3D"color:black">As a result, reloading U= I plugin descriptor/configuration data is as simple as refreshing (F5) WebA= dmin application in the browser (no need to restart Engine).<br> <br> <b>3. Added servlet for serving plugin static resources<br> </b><br> <i>PluginResourceServlet</i> is the servlet used to serve UI plugin static = files (plugin host page, 3rd party JavaScript, etc.) from the local file sy= stem.<br> <br> For example, requesting URL:</span></p> <ul type=3D"disc"> <li class=3D"MsoNormal" style=3D"color:black;mso-margin-top-alt:auto;mso-ma= rgin-bottom-alt:auto;mso-list:l5 level1 lfo8"> <i><a>http://<EngineManagerHost>:8700/webadmin/webadmin/plugin/foo/co= ntent/start.html</a></i></li></ul> <p><span style=3D"color:black">will send the content of:</span></p> <ul type=3D"disc"> <li class=3D"MsoNormal" style=3D"color:black;mso-margin-top-alt:auto;mso-ma= rgin-bottom-alt:auto;mso-list:l1 level1 lfo9"> <i>/usr/share/ovirt-engine/ui-plugins/<resourcePath>/content/start.ht= ml</i></li></ul> <p><span style=3D"color:black">to the client.</span></p> <p><span style=3D"color:black"> </span></p> <p><span style=3D"color:black">As shown in the above example:</span></p> <ul type=3D"disc"> <li class=3D"MsoNormal" style=3D"color:black;mso-margin-top-alt:auto;mso-ma= rgin-bottom-alt:auto;mso-list:l10 level1 lfo10"> <i>/webadmin/webadmin/plugin/</i> is the servlet root path for <i>PluginRes= ourceServlet</i></li><li class=3D"MsoNormal" style=3D"color:black;mso-margi= n-top-alt:auto;mso-margin-bottom-alt:auto;mso-list:l10 level1 lfo10"> in the extra path beyond the servlet root path (<i>/foo/content/start.html<= /i>):</li></ul> <ul type=3D"disc"> <ul type=3D"circle"> <li class=3D"MsoNormal" style=3D"color:black;mso-margin-top-alt:auto;mso-ma= rgin-bottom-alt:auto;mso-list:l10 level2 lfo10"> <i>/foo</i> represents the name of the plugin</li><li class=3D"MsoNormal" s= tyle=3D"color:black;mso-margin-top-alt:auto;mso-margin-bottom-alt:auto;mso-= list:l10 level2 lfo10"> <i>/content/start.html</i> represents the path to requested resource, relat= ive to "UIPluginDataPath / <resourcePath>"</li></ul> </ul> <p class=3D"MsoNormal"><span style=3D"color:black">Note that each plugin us= ing <i>PluginResourceServlet</i> to serve its static files must declare non= -empty <i>resourcePath</i> attribute in within the plugin descriptor.<br> <br> Also note that <i>PluginResourceServlet</i>, unlike <i>WebadminDynamicHosti= ngServlet</i>, does NOT reload descriptor/configuration data from local fil= e system as part of handling the given request. In other words, it's assume= d that plugin data has already been (re)loaded when serving WebAdmin application host page, with subsequent re= quests to <i>PluginResourceServlet</i> reading the current plugin information.<br> <br> Until we solve the cross-origin issue in a clean way, <i>PluginResourceServ= let</i> should be used to serve all plugin resources from local file system= .<br> <br> <b>4. Plugin lifecycle improved to deal with misbehaving plugins</b><br> <br> <i>PluginState</i> enum has been modified to deal with plugins that allow u= ncaught exceptions to escape from plugin event handler functions (e.g. "UiI= nit"):</span></p> <ul type=3D"disc"> <li class=3D"MsoNormal" style=3D"color:black;mso-margin-top-alt:auto;mso-ma= rgin-bottom-alt:auto;mso-list:l6 level1 lfo11"> removed state <i>INITIALIZED</i></li><li class=3D"MsoNormal" style=3D"color= :black;mso-margin-top-alt:auto;mso-margin-bottom-alt:auto;mso-list:l6 level= 1 lfo11"> added state <i>INITIALIZING</i>: The plugin is (currently) being initialize= d by calling UiInit event handler function.</li><li class=3D"MsoNormal" sty= le=3D"color:black;mso-margin-top-alt:auto;mso-margin-bottom-alt:auto;mso-li= st:l6 level1 lfo11"> added state <i>IN_USE</i>: Plugin's UiInit event handler function has compl= eted successfully, we can now call other event handler functions as necessa= ry. The plugin is in use now.</li><li class=3D"MsoNormal" style=3D"color:bl= ack;mso-margin-top-alt:auto;mso-margin-bottom-alt:auto;mso-list:l6 level1 l= fo11"> added state <i>FAILED</i>: An uncaught exception escaped while calling an e= vent handler function, which indicates internal error within the plugin cod= e. The plugin is removed from service.</li></ul> <p class=3D"MsoNormal" style=3D"margin-bottom:12.0pt"><span style=3D"color:= black">I've attached a simple state diagram that illustrates different stat= es and transitions between them (green color is initial state, red color is= end state).<br> <br> Uncaught exceptions in plugin event handler functions will be caught and ha= ndled by the plugin infrastructure. This prevents a misbehaving plugin from= breaking WebAdmin application, since WebAdmin is the caller (initiator) of= the function call. In such case, the plugin will be removed from service.<br> <br> <b>Update on cross-origin issue (consequence of same-origin policy)</b><br> <br> In order for the plugin to access WebAdmin plugin API, plugin host page (e.= g. <i> start.html</i>) must be served from URL on same origin as Engine origin. Ot= herwise, plugin code running in the context of an iframe'd host page will f= ail to evaluate "parent.pluginApi" expression, with "parent" being top-leve= l (WebAdmin) window, and "pluginApi" being the global plugin API object exposed by WebAdmin.<br> <br> This is why <i>PluginResourceServlet</i>, available on Engine origin, shoul= d be used to serve all plugin resources from local file system.<br> <br> There's only one issue that remains to be solved: cross-origin "plugin vs. = remote service" communication, with "remote service" being anything other t= han Engine (REST API). In future, we'll address this with Apache reverse pr= oxy configuration, so that users can configure Apache server (placed in front of Engine JBoss AS) to put ar= bitrary (local or remote non-Engine) services on same origin. However, this= requires a change in current Apache configuration. Until then, users can m= anually edit the Engine Apache configuration file (<i>/etc/httpd/conf.d/ovirt-engine.conf</i>).</span></p> <div class=3D"MsoNormal" style=3D"text-align:center" align=3D"center"><span= style=3D"color:black"> <hr align=3D"center" size=3D"2" width=3D"100%"> </span></div> <p class=3D"MsoNormal" style=3D"margin-bottom:12.0pt"><span style=3D"color:= black"><br> I've attached some sample plugin files for you to experiment with. Instead = of attaching actual patch file (92 kB) to this email, I've submitted the pa= tch to oVirt Gerrit: <a href=3D"http://gerrit.ovirt.org/8120" target=3D"_blank">http://gerrit.ov= irt.org/8120</a><br> <br> Let me know what you think!<br> <br> Cheers,<br> Vojtech</span></p> </div> </div> </blockquote> <blockquote style=3D"margin-top:5.0pt;margin-bottom:5.0pt"> <div> <p class=3D"MsoNormal"><ui-plugin-sample-files.tar.gz></p> </div> </blockquote> <blockquote style=3D"margin-top:5.0pt;margin-bottom:5.0pt"> <div> <p class=3D"MsoNormal"><ui-plugin-lifecycle.png></p> </div> </blockquote> <blockquote style=3D"margin-top:5.0pt;margin-bottom:5.0pt"> <div> <p class=3D"MsoNormal">_______________________________________________<br> Engine-devel mailing list<br> <a href=3D"mailto:Engine-devel@ovirt.org" target=3D"_blank">Engine-devel@ov= irt.org</a><br> <a href=3D"http://lists.ovirt.org/mailman/listinfo/engine-devel" target=3D"= _blank">http://lists.ovirt.org/mailman/listinfo/engine-devel</a></p> </div> </blockquote> </div> </div><br></div></body></html> ------=_Part_3896354_1791016925.1349203611679--