From slinabery at gmail.com Thu May 1 00:42:30 2008 From: slinabery at gmail.com (steve linabery) Date: Wed, 30 Apr 2008 19:42:30 -0500 Subject: [Ovirt-devel] PATCH: constrain storage_pool to avoid duplicate targets Message-ID: <769584de0804301742q74c60aa1s8f77e1b165896fcc@mail.gmail.com> Hi Ovirt, This little patch attempts to do the following: 0) Add a flash notice when storage pool creation fails and redirect to storage/show 1) Use validates_uniqueness_of in isci and nfs storage pool classes 2) Add a "FIXME" to storage/new.rhtml and storage/new2.rhtml so that the tip will stop breaking my page flow :) I think 1) is sufficient for avoiding both duplicate storage pool targets as well as duplicate storage volumes, since afaict volumes are only detected/created after pools. Hope this helps, Steve Linabery -------------- next part -------------- A non-text attachment was scrubbed... Name: storage_pools.patch Type: text/x-patch Size: 2900 bytes Desc: not available URL: From hbrock at redhat.com Thu May 1 13:05:59 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Thu, 1 May 2008 09:05:59 -0400 Subject: [Ovirt-devel] PATCH: constrain storage_pool to avoid duplicate targets In-Reply-To: <769584de0804301742q74c60aa1s8f77e1b165896fcc@mail.gmail.com> References: <769584de0804301742q74c60aa1s8f77e1b165896fcc@mail.gmail.com> Message-ID: <20080501130559.GI23162@redhat.com> On Wed, Apr 30, 2008 at 07:42:30PM -0500, steve linabery wrote: > Hi Ovirt, > > This little patch attempts to do the following: > 0) Add a flash notice when storage pool creation fails and redirect to > storage/show > 1) Use validates_uniqueness_of in isci and nfs storage pool classes > 2) Add a "FIXME" to storage/new.rhtml and storage/new2.rhtml so that > the tip will stop breaking my page flow :) > > I think 1) is sufficient for avoiding both duplicate storage pool > targets as well as duplicate storage volumes, since afaict volumes are > only detected/created after pools. Looks good... but what's the "FIXME" for below? --H > diff --git a/wui/src/app/controllers/storage_controller.rb b/wui/src/app/controllers/storage_controller.rb > index c977fcb..4784581 100644 > --- a/wui/src/app/controllers/storage_controller.rb > +++ b/wui/src/app/controllers/storage_controller.rb > @@ -104,6 +104,9 @@ class StorageController < ApplicationController > else > render :action => 'new' > end > + else > + flash[:notice] = 'Storage Pool creation failed.' > + redirect_to :controller => @storage_pool.hardware_pool.get_controller, :action => 'show', :id => @storage_pool.hardware_pool_id > end > end > > diff --git a/wui/src/app/models/iscsi_storage_pool.rb b/wui/src/app/models/iscsi_storage_pool.rb > index 8164e7c..9cc104d 100644 > --- a/wui/src/app/models/iscsi_storage_pool.rb > +++ b/wui/src/app/models/iscsi_storage_pool.rb > @@ -18,6 +18,9 @@ > # also available at http://www.gnu.org/copyleft/gpl.html. > > class IscsiStoragePool < StoragePool > + > + validates_uniqueness_of :ip_addr, :scope => [:port, :target] > + > def label_components > "#{target}" > end > diff --git a/wui/src/app/models/nfs_storage_pool.rb b/wui/src/app/models/nfs_storage_pool.rb > index 30608cd..3704cc0 100644 > --- a/wui/src/app/models/nfs_storage_pool.rb > +++ b/wui/src/app/models/nfs_storage_pool.rb > @@ -18,6 +18,9 @@ > # also available at http://www.gnu.org/copyleft/gpl.html. > > class NfsStoragePool < StoragePool > + > + validates_uniqueness_of :ip_addr, :scope => :export_path > + > def label_components > "#{export_path}" > end > diff --git a/wui/src/app/views/storage/new.rhtml b/wui/src/app/views/storage/new.rhtml > index 9dbc240..80d4941 100644 > --- a/wui/src/app/views/storage/new.rhtml > +++ b/wui/src/app/views/storage/new.rhtml > @@ -22,7 +22,9 @@ > > >
> - Choose From Storage in <%= @hardware_pool.parent.name %> > +FIX ME: hardware_pool parent attribute > + What are we missing here? Thanks, --Hugh From slinabery at gmail.com Thu May 1 13:23:51 2008 From: slinabery at gmail.com (steve linabery) Date: Thu, 1 May 2008 08:23:51 -0500 Subject: [Ovirt-devel] PATCH: constrain storage_pool to avoid duplicate targets In-Reply-To: <20080501130559.GI23162@redhat.com> References: <769584de0804301742q74c60aa1s8f77e1b165896fcc@mail.gmail.com> <20080501130559.GI23162@redhat.com> Message-ID: <769584de0805010623j345736c6p338cb35adfe40c3b@mail.gmail.com> On Thu, May 1, 2008 at 8:05 AM, Hugh O. Brock wrote: > > On Wed, Apr 30, 2008 at 07:42:30PM -0500, steve linabery wrote: > > Hi Ovirt, > > > > This little patch attempts to do the following: > > 0) Add a flash notice when storage pool creation fails and redirect to > > storage/show > > 1) Use validates_uniqueness_of in isci and nfs storage pool classes > > 2) Add a "FIXME" to storage/new.rhtml and storage/new2.rhtml so that > > the tip will stop breaking my page flow :) > > > > I think 1) is sufficient for avoiding both duplicate storage pool > > targets as well as duplicate storage volumes, since afaict volumes are > > only detected/created after pools. > > Looks good... but what's the "FIXME" for below? > --H > > > diff --git a/wui/src/app/controllers/storage_controller.rb b/wui/src/app/controllers/storage_controller.rb > > index c977fcb..4784581 100644 > > --- a/wui/src/app/controllers/storage_controller.rb > > +++ b/wui/src/app/controllers/storage_controller.rb > > @@ -104,6 +104,9 @@ class StorageController < ApplicationController > > else > > render :action => 'new' > > end > > + else > > + flash[:notice] = 'Storage Pool creation failed.' > > + redirect_to :controller => @storage_pool.hardware_pool.get_controller, :action => 'show', :id => @storage_pool.hardware_pool_id > > end > > end > > > > diff --git a/wui/src/app/models/iscsi_storage_pool.rb b/wui/src/app/models/iscsi_storage_pool.rb > > index 8164e7c..9cc104d 100644 > > --- a/wui/src/app/models/iscsi_storage_pool.rb > > +++ b/wui/src/app/models/iscsi_storage_pool.rb > > @@ -18,6 +18,9 @@ > > # also available at http://www.gnu.org/copyleft/gpl.html. > > > > class IscsiStoragePool < StoragePool > > + > > + validates_uniqueness_of :ip_addr, :scope => [:port, :target] > > + > > def label_components > > "#{target}" > > end > > diff --git a/wui/src/app/models/nfs_storage_pool.rb b/wui/src/app/models/nfs_storage_pool.rb > > index 30608cd..3704cc0 100644 > > --- a/wui/src/app/models/nfs_storage_pool.rb > > +++ b/wui/src/app/models/nfs_storage_pool.rb > > @@ -18,6 +18,9 @@ > > # also available at http://www.gnu.org/copyleft/gpl.html. > > > > class NfsStoragePool < StoragePool > > + > > + validates_uniqueness_of :ip_addr, :scope => :export_path > > + > > def label_components > > "#{export_path}" > > end > > diff --git a/wui/src/app/views/storage/new.rhtml b/wui/src/app/views/storage/new.rhtml > > index 9dbc240..80d4941 100644 > > --- a/wui/src/app/views/storage/new.rhtml > > +++ b/wui/src/app/views/storage/new.rhtml > > @@ -22,7 +22,9 @@ > >
> > > >
> > - Choose From Storage in <%= @hardware_pool.parent.name %> > > +FIX ME: hardware_pool parent attribute > > + > > What are we missing here? > > Thanks, > --Hugh > The 'FIXME' allows storage/new.rhtml and storage/new2.rhtml to be served. Those pages are currently broken because they are referencing an attribute called 'parent' in the HardwarePool object that does not exist. Since I don't know how where the model is headed on this particular point, I thought it best to just put a FIXME placeholder in those rhtml files to allow mongrel to serve them. I should have split this out into a different patch, I guess, since it doesn't have anything to do with the uniqueness constraint issue, no? Hope this answers your question. Thanks Steve From hbrock at redhat.com Thu May 1 13:39:41 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Thu, 1 May 2008 09:39:41 -0400 Subject: [Ovirt-devel] PATCH: constrain storage_pool to avoid duplicate targets In-Reply-To: <769584de0805010623j345736c6p338cb35adfe40c3b@mail.gmail.com> References: <769584de0804301742q74c60aa1s8f77e1b165896fcc@mail.gmail.com> <20080501130559.GI23162@redhat.com> <769584de0805010623j345736c6p338cb35adfe40c3b@mail.gmail.com> Message-ID: <20080501133941.GJ23162@redhat.com> On Thu, May 01, 2008 at 08:23:51AM -0500, steve linabery wrote: > On Thu, May 1, 2008 at 8:05 AM, Hugh O. Brock wrote: > > > > >
> > > - Choose From Storage in <%= @hardware_pool.parent.name %> > > > +FIX ME: hardware_pool parent attribute > > > + > > > > What are we missing here? > > > > Thanks, > > --Hugh > > > > The 'FIXME' allows storage/new.rhtml and storage/new2.rhtml to be > served. Those pages are currently broken because they are referencing > an attribute called 'parent' in the HardwarePool object that does not > exist. > > Since I don't know how where the model is headed on this particular > point, I thought it best to just put a FIXME placeholder in those > rhtml files to allow mongrel to serve them. > > I should have split this out into a different patch, I guess, since it > doesn't have anything to do with the uniqueness constraint issue, no? > > Hope this answers your question. > No, that seems fine, thanks! ACK --Hugh From imain at redhat.com Thu May 1 21:10:42 2008 From: imain at redhat.com (Ian Main) Date: Thu, 1 May 2008 14:10:42 -0700 Subject: [Ovirt-devel] [PATCH] Use ruby rails 2.0.1 or greater Message-ID: <20080501141042.28e6d861@tp.mains.net> This patch gets rid of the ruby rails version being specified as 2.0.1. The Fedora 8 repo now uses 2.0.2 and so any new wui vms being built won't work. With this patch we can use anything 2.0.1 or above. This should be applied against tip and 0.4, and new 0.4 rpms should be put on the ovirt site. Signed-off-by: Ian Main diff --git a/wui/conf/ovirt-wui b/wui/conf/ovirt-wui index 07d7acc..f31b32d 100644 --- a/wui/conf/ovirt-wui +++ b/wui/conf/ovirt-wui @@ -15,7 +15,6 @@ RAILS_ENVIRONMENT=production USER=ovirt GROUP=ovirt PREFIX=/ovirt -export RAILS_GEM_VERSION=2.0.1 RETVAL=0 diff --git a/wui/ovirt-wui.spec b/wui/ovirt-wui.spec index 05d915a..f707faa 100644 --- a/wui/ovirt-wui.spec +++ b/wui/ovirt-wui.spec @@ -13,7 +13,7 @@ License: GPL and MIT Group: Applications/System Requires: ruby >= 1.8.1 Requires: ruby(abi) = 1.8 -Requires: rubygem(rails) = 2.0.1 +Requires: rubygem(rails) >= 2.0.1 Requires: rubygem(mongrel) >= 1.0.1 Requires: rubygem(kerberos) >= 0.4 Requires: ruby-gettext-package diff --git a/wui/src/config/environment.rb b/wui/src/config/environment.rb index 8f69bef..379dcf4 100644 --- a/wui/src/config/environment.rb +++ b/wui/src/config/environment.rb @@ -23,10 +23,6 @@ # you don't control web/app server and can't set it the proper way # ENV['RAILS_ENV'] ||= 'production' -# Specifies gem version of Rails to use when vendor/rails is not present -RAILS_GEM_VERSION = ENV['RAILS_GEM_VERSION'] -RAILS_GEM_VERSION = '2.0.1' unless RAILS_GEM_VERSION - # Bootstrap the Rails environment, frameworks, and default configuration require File.join(File.dirname(__FILE__), 'boot') From imain at redhat.com Thu May 1 21:36:46 2008 From: imain at redhat.com (Ian Main) Date: Thu, 1 May 2008 14:36:46 -0700 Subject: [Ovirt-devel] ovirt rpm versions Message-ID: <20080501143646.508650c2@tp.mains.net> Heya guys, So when building these new developer wui appliances, at first I was using the 0.4 ks file on the ovirt.org website. Once that was installed I'd git clone the src tree and install the new rpms. However, the rpm version in tip is the same as 0.4 and so this seems to cause rpm some confusion.. it doesn't delete any of the old files in db/migrate causing any new db setup to fail. I'm thinking that we should bump the major rev on the rpm to 0.5 and that can be our "development" version or what have you. Really this should be done any time we do a release imo. Ian From slinabery at gmail.com Thu May 1 22:37:04 2008 From: slinabery at gmail.com (steve linabery) Date: Thu, 1 May 2008 17:37:04 -0500 Subject: [Ovirt-devel] [PATCH] wrappers for taskomatic.rb and host-status.rb Message-ID: <769584de0805011537h22491b71qeccca30360e6b52c@mail.gmail.com> Hi Ovirt! taskomatic.rb and host-status.rb were becoming daemons by using "Daemons.daemonize". This had the unfortunate effect of detaching them from any controlling terminal, and so using killproc in /etc/init.d/ovirt-wui was *not* killing them. I noticed that after repeated 'service ovirt-wui restart', I had many stray taskomatic & host-status processes, all making connections to postgresql, and sending my appliance way into swap. So this patch: 0) renames taskomatic.rb and host-status.rb to taskomatic_.rb and host-status_.rb, respectively. 1) replaces taskomatic.rb and host-status.rb with wrapper scripts for taskomatic_.rb and host-status_.rb. The wrappers use the "Daemons.run(script,options)" method instead of Daemons.daemonize. 2) edits /etc/init.d/ovirt-wui to invoke 'taskomatic.rb start' and 'taskomatic.rb stop' (same for host-status.rb) instead of the initscript functions daemon and killproc. Please note that the original scripts accepted some command line arguments; that code is still present in taskomatic_.rb and host-status_.rb, but I did not provide a mechanism for passing command line options via the wrapper scripts. Thanks for your consideration, Steve Linabery -------------- next part -------------- A non-text attachment was scrubbed... Name: daemons.patch Type: text/x-patch Size: 15970 bytes Desc: not available URL: From hbrock at redhat.com Thu May 1 22:48:58 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Thu, 1 May 2008 18:48:58 -0400 Subject: [Ovirt-devel] [PATCH] Use ruby rails 2.0.1 or greater In-Reply-To: <20080501141042.28e6d861@tp.mains.net> References: <20080501141042.28e6d861@tp.mains.net> Message-ID: <20080501224858.GO23162@redhat.com> On Thu, May 01, 2008 at 02:10:42PM -0700, Ian Main wrote: > > This patch gets rid of the ruby rails version being specified as 2.0.1. The Fedora 8 repo now uses 2.0.2 and so any new wui vms being built won't work. With this patch we can use anything 2.0.1 or above. > > This should be applied against tip and 0.4, and new 0.4 rpms should be put on the ovirt site. > > Signed-off-by: Ian Main > > diff --git a/wui/conf/ovirt-wui b/wui/conf/ovirt-wui > index 07d7acc..f31b32d 100644 > --- a/wui/conf/ovirt-wui > +++ b/wui/conf/ovirt-wui > @@ -15,7 +15,6 @@ RAILS_ENVIRONMENT=production > USER=ovirt > GROUP=ovirt > PREFIX=/ovirt > -export RAILS_GEM_VERSION=2.0.1 > > RETVAL=0 > > diff --git a/wui/ovirt-wui.spec b/wui/ovirt-wui.spec > index 05d915a..f707faa 100644 > --- a/wui/ovirt-wui.spec > +++ b/wui/ovirt-wui.spec > @@ -13,7 +13,7 @@ License: GPL and MIT > Group: Applications/System > Requires: ruby >= 1.8.1 > Requires: ruby(abi) = 1.8 > -Requires: rubygem(rails) = 2.0.1 > +Requires: rubygem(rails) >= 2.0.1 > Requires: rubygem(mongrel) >= 1.0.1 > Requires: rubygem(kerberos) >= 0.4 > Requires: ruby-gettext-package > diff --git a/wui/src/config/environment.rb b/wui/src/config/environment.rb > index 8f69bef..379dcf4 100644 > --- a/wui/src/config/environment.rb > +++ b/wui/src/config/environment.rb > @@ -23,10 +23,6 @@ > # you don't control web/app server and can't set it the proper way > # ENV['RAILS_ENV'] ||= 'production' > > -# Specifies gem version of Rails to use when vendor/rails is not present > -RAILS_GEM_VERSION = ENV['RAILS_GEM_VERSION'] > -RAILS_GEM_VERSION = '2.0.1' unless RAILS_GEM_VERSION > - > # Bootstrap the Rails environment, frameworks, and default configuration > require File.join(File.dirname(__FILE__), 'boot') > ACK Go ahead and commit this, please... --H From hbrock at redhat.com Thu May 1 22:55:16 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Thu, 1 May 2008 18:55:16 -0400 Subject: [Ovirt-devel] [PATCH] wrappers for taskomatic.rb and host-status.rb In-Reply-To: <769584de0805011537h22491b71qeccca30360e6b52c@mail.gmail.com> References: <769584de0805011537h22491b71qeccca30360e6b52c@mail.gmail.com> Message-ID: <20080501225515.GP23162@redhat.com> On Thu, May 01, 2008 at 05:37:04PM -0500, steve linabery wrote: > Hi Ovirt! > > taskomatic.rb and host-status.rb were becoming daemons by using > "Daemons.daemonize". > > This had the unfortunate effect of detaching them from any controlling > terminal, and so using killproc in /etc/init.d/ovirt-wui was *not* > killing them. I noticed that after repeated 'service ovirt-wui > restart', I had many stray taskomatic & host-status processes, all > making connections to postgresql, and sending my appliance way into > swap. > > So this patch: > 0) renames taskomatic.rb and host-status.rb to taskomatic_.rb and > host-status_.rb, respectively. > 1) replaces taskomatic.rb and host-status.rb with wrapper scripts for > taskomatic_.rb and host-status_.rb. The wrappers use the > "Daemons.run(script,options)" method instead of Daemons.daemonize. > 2) edits /etc/init.d/ovirt-wui to invoke 'taskomatic.rb start' and > 'taskomatic.rb stop' (same for host-status.rb) instead of the > initscript functions daemon and killproc. > > Please note that the original scripts accepted some command line > arguments; that code is still present in taskomatic_.rb and > host-status_.rb, but I did not provide a mechanism for passing command > line options via the wrapper scripts. > > Thanks for your consideration, > Steve Linabery [snip] Patch looks fine. Git experts: Is it cleaner to "move" taskomatic.rb to taskomatic_.rb in the git repo, thereby preserving the changelog for the file even while renaming? With that caveat, ACK --Hugh From berrange at redhat.com Thu May 1 22:56:38 2008 From: berrange at redhat.com (Daniel P. Berrange) Date: Thu, 1 May 2008 23:56:38 +0100 Subject: [Ovirt-devel] [PATCH] wrappers for taskomatic.rb and host-status.rb In-Reply-To: <769584de0805011537h22491b71qeccca30360e6b52c@mail.gmail.com> References: <769584de0805011537h22491b71qeccca30360e6b52c@mail.gmail.com> Message-ID: <20080501225638.GB21047@redhat.com> On Thu, May 01, 2008 at 05:37:04PM -0500, steve linabery wrote: > Hi Ovirt! > > taskomatic.rb and host-status.rb were becoming daemons by using > "Daemons.daemonize". > > This had the unfortunate effect of detaching them from any controlling > terminal, and so using killproc in /etc/init.d/ovirt-wui was *not* > killing them. I noticed that after repeated 'service ovirt-wui > restart', I had many stray taskomatic & host-status processes, all > making connections to postgresql, and sending my appliance way into > swap. > > So this patch: > 0) renames taskomatic.rb and host-status.rb to taskomatic_.rb and > host-status_.rb, respectively. > 1) replaces taskomatic.rb and host-status.rb with wrapper scripts for > taskomatic_.rb and host-status_.rb. The wrappers use the > "Daemons.run(script,options)" method instead of Daemons.daemonize. > 2) edits /etc/init.d/ovirt-wui to invoke 'taskomatic.rb start' and > 'taskomatic.rb stop' (same for host-status.rb) instead of the > initscript functions daemon and killproc. This is not really a good idea. The decision about how/if to daemonize belows to the initscripts. In SysV init this is daemon/killproc. In the new Upstart world, it doesn't daemonize at all - it keeps ownership of the process so it can detect death & restart. Xen used to follow the approach of your patch too and we just spent time ripping out all that code and making it used daemon/killproc correctly in the initscripts in F10. The simpler way around this problem would have just been to change the existing initscript to pass '-n' when starting the programs so that the Daemons.daemonize() call was skipped - it was redundant when running the program via the 'daemon' shell command. And figuring out whatever is needed to make killproc work correctly. The existing initscript also really needs to be split up so that there is one initscript per daemon that ovirt has. Dan. -- |: Red Hat, Engineering, Boston -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :| From hbrock at redhat.com Thu May 1 23:09:57 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Thu, 1 May 2008 19:09:57 -0400 Subject: [Ovirt-devel] [PATCH] wrappers for taskomatic.rb and host-status.rb In-Reply-To: <20080501225638.GB21047@redhat.com> References: <769584de0805011537h22491b71qeccca30360e6b52c@mail.gmail.com> <20080501225638.GB21047@redhat.com> Message-ID: <20080501230957.GQ23162@redhat.com> On Thu, May 01, 2008 at 11:56:38PM +0100, Daniel P. Berrange wrote: > On Thu, May 01, 2008 at 05:37:04PM -0500, steve linabery wrote: > > This is not really a good idea. > > The decision about how/if to daemonize belows to the initscripts. In > SysV init this is daemon/killproc. In the new Upstart world, it doesn't > daemonize at all - it keeps ownership of the process so it can detect > death & restart. > > Xen used to follow the approach of your patch too and we just spent > time ripping out all that code and making it used daemon/killproc > correctly in the initscripts in F10. > > The simpler way around this problem would have just been to change the > existing initscript to pass '-n' when starting the programs so that > the Daemons.daemonize() call was skipped - it was redundant when running > the program via the 'daemon' shell command. And figuring out whatever is > needed to make killproc work correctly. > > The existing initscript also really needs to be split up so that there is > one initscript per daemon that ovirt has. > > Dan. Whups... guess I shouldna acked it then. Steve, care to try again along the lines above? --Hugh From slinabery at gmail.com Thu May 1 23:13:40 2008 From: slinabery at gmail.com (steve linabery) Date: Thu, 1 May 2008 18:13:40 -0500 Subject: [Ovirt-devel] [PATCH] wrappers for taskomatic.rb and host-status.rb In-Reply-To: <20080501230957.GQ23162@redhat.com> References: <769584de0805011537h22491b71qeccca30360e6b52c@mail.gmail.com> <20080501225638.GB21047@redhat.com> <20080501230957.GQ23162@redhat.com> Message-ID: <769584de0805011613r57ef60e9x212226c0fd2bee80@mail.gmail.com> On Thu, May 1, 2008 at 6:09 PM, Hugh O. Brock wrote: > On Thu, May 01, 2008 at 11:56:38PM +0100, Daniel P. Berrange wrote: > > On Thu, May 01, 2008 at 05:37:04PM -0500, steve linabery wrote: > > > > > This is not really a good idea. > > > > The decision about how/if to daemonize belows to the initscripts. In > > SysV init this is daemon/killproc. In the new Upstart world, it doesn't > > daemonize at all - it keeps ownership of the process so it can detect > > death & restart. > > > > Xen used to follow the approach of your patch too and we just spent > > time ripping out all that code and making it used daemon/killproc > > correctly in the initscripts in F10. > > > > The simpler way around this problem would have just been to change the > > existing initscript to pass '-n' when starting the programs so that > > the Daemons.daemonize() call was skipped - it was redundant when running > > the program via the 'daemon' shell command. And figuring out whatever is > > needed to make killproc work correctly. > > > > The existing initscript also really needs to be split up so that there is > > one initscript per daemon that ovirt has. > > > > Dan. > > Whups... guess I shouldna acked it then. > > Steve, care to try again along the lines above? > > --Hugh > No problem, I'll fix it tomorrow or over the weekend. I wasn't thinking about the SysV init conventions, unfortunately. Was just looking at the ruby docs for Daemons and they suggested the wrapper scripts. So it's their fault...yeah, that's the ticket! ;) Steve From imain at redhat.com Thu May 1 23:21:33 2008 From: imain at redhat.com (Ian Main) Date: Thu, 1 May 2008 16:21:33 -0700 Subject: [Ovirt-devel] [PATCH] A few specfile tweaks Message-ID: <20080501162133.47b2b10e@tp.mains.net> This patch ups the ovirt rpm version to 0.5 to avoid file conflicts with the 0.4 release. It also makes ovirt-wui-install install into /usr/sbin instead of /usr/bin. We should really be upping the version every time a file changes. diff --git a/wui/ovirt-wui.spec b/wui/ovirt-wui.spec index 74ee4ba..c8f84a3 100644 --- a/wui/ovirt-wui.spec +++ b/wui/ovirt-wui.spec @@ -87,7 +87,7 @@ touch %{buildroot}%{_localstatedir}/log/%{name}/host-status.log %{__rm} -f %{buildroot}%{app_root}/task-omatic/.gitignore %{__cp} -a %{pbuild}/scripts/ovirt-add-host %{buildroot}%{_bindir} -%{__cp} -a %{pbuild}/scripts/ovirt-wui-install %{buildroot}%{_bindir} +%{__cp} -a %{pbuild}/scripts/ovirt-wui-install %{buildroot}%{_sbindir} %{__cp} -a %{pbuild}/scripts/ovirt-fix-ipa %{buildroot}%{_bindir} %{__rm} -rf %{buildroot}%{app_root}/tmp %{__mkdir} %{buildroot}%{_localstatedir}/lib/%{name}/tmp @@ -99,7 +99,7 @@ rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root,0755) -%{_bindir}/ovirt-wui-install +%{_sbindir}/ovirt-wui-install %{_bindir}/ovirt-add-host %{_bindir}/ovirt-fix-ipa %{_initrddir}/%{name} diff --git a/wui/version b/wui/version index 6848c9e..d4480df 100644 --- a/wui/version +++ b/wui/version @@ -1 +1 @@ -0.0.4 1 +0.0.5 1 From imain at redhat.com Fri May 2 03:39:10 2008 From: imain at redhat.com (Ian Main) Date: Thu, 1 May 2008 20:39:10 -0700 Subject: [Ovirt-devel] [PATCH] A few specfile tweaks In-Reply-To: <20080501162133.47b2b10e@tp.mains.net> References: <20080501162133.47b2b10e@tp.mains.net> Message-ID: <20080501203910.68127b11@tp.mains.net> D'oh, need this too.. Consider it an addendum :) diff --git a/wui-appliance/common-post.ks b/wui-appliance/common-post.ks index 3bd6b4d..d50436a 100644 --- a/wui-appliance/common-post.ks +++ b/wui-appliance/common-post.ks @@ -34,7 +34,7 @@ cat > /etc/init.d/ovirt-wui-first-run << \EOF start() { echo -n "Starting ovirt-wui-first-run: " - /usr/bin/ovirt-wui-install > /var/log/ovirt-wui-first-run.log 2>&1 + /usr/sbin/ovirt-wui-install > /var/log/ovirt-wui-first-run.log 2>&1 RETVAL=$? if [ $RETVAL -eq 0 ]; then From clalance at redhat.com Fri May 2 14:19:24 2008 From: clalance at redhat.com (Chris Lalancette) Date: Fri, 02 May 2008 10:19:24 -0400 Subject: [Ovirt-devel] [PATCH] A few specfile tweaks In-Reply-To: <20080501162133.47b2b10e@tp.mains.net> References: <20080501162133.47b2b10e@tp.mains.net> Message-ID: <481B22EC.3070900@redhat.com> Ian Main wrote: > This patch ups the ovirt rpm version to 0.5 to avoid file conflicts with the 0.4 release. It also makes ovirt-wui-install install into /usr/sbin instead of /usr/bin. > > We should really be upping the version every time a file changes. ACK for this change, but I don't think we should bump the version every time. The reason is that we want the version number to match up with the next release. What we should probably do is just bump the release number during a development cycle, and then bump the version at the end; that seems to work pretty well for me. Chris Lalancette From berrange at redhat.com Fri May 2 14:31:44 2008 From: berrange at redhat.com (Daniel P. Berrange) Date: Fri, 2 May 2008 15:31:44 +0100 Subject: [Ovirt-devel] [PATCH] A few specfile tweaks In-Reply-To: <481B22EC.3070900@redhat.com> References: <20080501162133.47b2b10e@tp.mains.net> <481B22EC.3070900@redhat.com> Message-ID: <20080502143144.GG5681@redhat.com> On Fri, May 02, 2008 at 10:19:24AM -0400, Chris Lalancette wrote: > Ian Main wrote: > > This patch ups the ovirt rpm version to 0.5 to avoid file conflicts with the 0.4 release. It also makes ovirt-wui-install install into /usr/sbin instead of /usr/bin. > > > > We should really be upping the version every time a file changes. > > ACK for this change, but I don't think we should bump the version every time. > The reason is that we want the version number to match up with the next release. > What we should probably do is just bump the release number during a development > cycle, and then bump the version at the end; that seems to work pretty well for me. It is important to distinguish the dev snapshots from the previous stable release by version number. Merely bumping the release during development does not really achieve this. IMHO the way to deal with this is to - Immediately after a release: - Bump the version number - Reset the release number to '0.git1' - When making changes - Bump the last digit in the release number, eg '0.git2', '0.git3' - At time of release - Bump the release to '1' This ensures that the RPM has a newer version number to indicate it is functionality different from the previous stable release, and using the leading '0' in Release: is following Fedora guidlines for pre-release software release numbering scheme. Dan. -- |: Red Hat, Engineering, Boston -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :| From hbrock at redhat.com Fri May 2 14:40:50 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Fri, 2 May 2008 10:40:50 -0400 Subject: [Ovirt-devel] [PATCH] A few specfile tweaks In-Reply-To: <20080502143144.GG5681@redhat.com> References: <20080501162133.47b2b10e@tp.mains.net> <481B22EC.3070900@redhat.com> <20080502143144.GG5681@redhat.com> Message-ID: <20080502144050.GS23162@redhat.com> On Fri, May 02, 2008 at 03:31:44PM +0100, Daniel P. Berrange wrote: > On Fri, May 02, 2008 at 10:19:24AM -0400, Chris Lalancette wrote: > > Ian Main wrote: > > > This patch ups the ovirt rpm version to 0.5 to avoid file conflicts with the 0.4 release. It also makes ovirt-wui-install install into /usr/sbin instead of /usr/bin. > > > > > > We should really be upping the version every time a file changes. > > > > ACK for this change, but I don't think we should bump the version every time. > > The reason is that we want the version number to match up with the next release. > > What we should probably do is just bump the release number during a development > > cycle, and then bump the version at the end; that seems to work pretty well for me. > > It is important to distinguish the dev snapshots from the previous stable > release by version number. Merely bumping the release during development > does not really achieve this. > > IMHO the way to deal with this is to > > - Immediately after a release: > - Bump the version number > - Reset the release number to '0.git1' > - When making changes > - Bump the last digit in the release number, eg '0.git2', '0.git3' > - At time of release > - Bump the release to '1' > > This ensures that the RPM has a newer version number to indicate it is > functionality different from the previous stable release, and using the > leading '0' in Release: is following Fedora guidlines for pre-release > software release numbering scheme. Yes, this is what I was thinking as well... does that imply incrementing the release number on every commit, though? And if so is it easier to use e.g. a changeset number in the release number to avoid having to manually increment the release number? --H From berrange at redhat.com Fri May 2 14:55:56 2008 From: berrange at redhat.com (Daniel P. Berrange) Date: Fri, 2 May 2008 15:55:56 +0100 Subject: [Ovirt-devel] [PATCH] A few specfile tweaks In-Reply-To: <20080502144050.GS23162@redhat.com> References: <20080501162133.47b2b10e@tp.mains.net> <481B22EC.3070900@redhat.com> <20080502143144.GG5681@redhat.com> <20080502144050.GS23162@redhat.com> Message-ID: <20080502145556.GA25838@redhat.com> On Fri, May 02, 2008 at 10:40:50AM -0400, Hugh O. Brock wrote: > On Fri, May 02, 2008 at 03:31:44PM +0100, Daniel P. Berrange wrote: > > On Fri, May 02, 2008 at 10:19:24AM -0400, Chris Lalancette wrote: > > It is important to distinguish the dev snapshots from the previous stable > > release by version number. Merely bumping the release during development > > does not really achieve this. > > > > IMHO the way to deal with this is to > > > > - Immediately after a release: > > - Bump the version number > > - Reset the release number to '0.git1' > > - When making changes > > - Bump the last digit in the release number, eg '0.git2', '0.git3' > > - At time of release > > - Bump the release to '1' > > > > This ensures that the RPM has a newer version number to indicate it is > > functionality different from the previous stable release, and using the > > leading '0' in Release: is following Fedora guidlines for pre-release > > software release numbering scheme. > > Yes, this is what I was thinking as well... does that imply > incrementing the release number on every commit, though? And if so is > it easier to use e.g. a changeset number in the release number to > avoid having to manually increment the release number? There is no linear increasing changeset number you can use with GIT really. It is probably best to have the release number set at time of build rather than manually changed by commits. eg, when we add an automated build script I'd recommend the following be used in the autobuild.sh script: if [ -n "$AUTOBUILD_COUNTER" ]; then EXTRA_RELEASE=".auto$AUTOBUILD_COUNTER" else NOW=`date +"%s"` EXTRA_RELEASE=".$USER$NOW" fi rpmbuild --define "extra_release $EXTRA_RELEASE" \ -ta --clean foo.tar.gz And in the specfile: %define _extra_release %{?dist:%{dist}}%{!?dist:%{?extra_release:%{extra_release}}} Release: 0%{_extra_release} So if a developer wanted to build an RPM from the current checkout just running 'autobuild.sh' would then 'do the right thing' and create a RPM with a release field newer than any previous build. And if the automated build runs, it'll get tagged with the build counter Dan. -- |: Red Hat, Engineering, Boston -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :| From hbrock at redhat.com Fri May 2 15:05:50 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Fri, 2 May 2008 11:05:50 -0400 Subject: [Ovirt-devel] [PATCH] A few specfile tweaks In-Reply-To: <20080502145556.GA25838@redhat.com> References: <20080501162133.47b2b10e@tp.mains.net> <481B22EC.3070900@redhat.com> <20080502143144.GG5681@redhat.com> <20080502144050.GS23162@redhat.com> <20080502145556.GA25838@redhat.com> Message-ID: <20080502150550.GT23162@redhat.com> On Fri, May 02, 2008 at 03:55:56PM +0100, Daniel P. Berrange wrote: > On Fri, May 02, 2008 at 10:40:50AM -0400, Hugh O. Brock wrote: > > On Fri, May 02, 2008 at 03:31:44PM +0100, Daniel P. Berrange wrote: > > > On Fri, May 02, 2008 at 10:19:24AM -0400, Chris Lalancette wrote: > There is no linear increasing changeset number you can use with GIT really. > > It is probably best to have the release number set at time of build rather > than manually changed by commits. eg, when we add an automated build script > I'd recommend the following be used in the autobuild.sh script: > > if [ -n "$AUTOBUILD_COUNTER" ]; then > EXTRA_RELEASE=".auto$AUTOBUILD_COUNTER" > else > NOW=`date +"%s"` > EXTRA_RELEASE=".$USER$NOW" > fi > rpmbuild --define "extra_release $EXTRA_RELEASE" \ > -ta --clean foo.tar.gz > > And in the specfile: > > %define _extra_release %{?dist:%{dist}}%{!?dist:%{?extra_release:%{extra_release}}} > Release: 0%{_extra_release} > > So if a developer wanted to build an RPM from the current checkout just > running 'autobuild.sh' would then 'do the right thing' and create a RPM > with a release field newer than any previous build. And if the automated > build runs, it'll get tagged with the build counter > Yeah this is what I was thinking. Ian or Mo, can you make the above happen? --Hugh From slinabery at gmail.com Fri May 2 17:41:02 2008 From: slinabery at gmail.com (steve linabery) Date: Fri, 2 May 2008 12:41:02 -0500 Subject: [Ovirt-devel] [PATCH] wrappers for taskomatic.rb and host-status.rb In-Reply-To: <20080501230957.GQ23162@redhat.com> References: <769584de0805011537h22491b71qeccca30360e6b52c@mail.gmail.com> <20080501225638.GB21047@redhat.com> <20080501230957.GQ23162@redhat.com> Message-ID: <769584de0805021041g370ac7a3yd6ec0d24bdbe02a1@mail.gmail.com> On Thu, May 1, 2008 at 6:09 PM, Hugh O. Brock wrote: > On Thu, May 01, 2008 at 11:56:38PM +0100, Daniel P. Berrange wrote: > > On Thu, May 01, 2008 at 05:37:04PM -0500, steve linabery wrote: > > > > > This is not really a good idea. > > > > The decision about how/if to daemonize belows to the initscripts. In > > SysV init this is daemon/killproc. In the new Upstart world, it doesn't > > daemonize at all - it keeps ownership of the process so it can detect > > death & restart. > > > > Xen used to follow the approach of your patch too and we just spent > > time ripping out all that code and making it used daemon/killproc > > correctly in the initscripts in F10. > > > > The simpler way around this problem would have just been to change the > > existing initscript to pass '-n' when starting the programs so that > > the Daemons.daemonize() call was skipped - it was redundant when running > > the program via the 'daemon' shell command. And figuring out whatever is > > needed to make killproc work correctly. > > > > The existing initscript also really needs to be split up so that there is > > one initscript per daemon that ovirt has. > > > > Dan. > > Whups... guess I shouldna acked it then. > > Steve, care to try again along the lines above? > > --Hugh > Hi Hugh and ovirt, Well, it turns out it is even simpler than that. All I really needed to do was look at host-keyadd, which cooperates well with daemon & killproc by doing 'include Daemonize' and calling 'daemonize', as you'll see in the attached patch. Patch adjusts taskomatic.rb and host-status.rb accordingly, and now they play nice with /etc/init.d/ovirt-wui script. Good day, Steve Linabery -------------- next part -------------- A non-text attachment was scrubbed... Name: daemons.patch Type: text/x-patch Size: 1086 bytes Desc: not available URL: From jim at meyering.net Fri May 2 19:17:57 2008 From: jim at meyering.net (Jim Meyering) Date: Fri, 02 May 2008 21:17:57 +0200 Subject: [Ovirt-devel] [PATCH] A few specfile tweaks In-Reply-To: <20080502145556.GA25838@redhat.com> (Daniel P. Berrange's message of "Fri, 2 May 2008 15:55:56 +0100") References: <20080501162133.47b2b10e@tp.mains.net> <481B22EC.3070900@redhat.com> <20080502143144.GG5681@redhat.com> <20080502144050.GS23162@redhat.com> <20080502145556.GA25838@redhat.com> Message-ID: <87hcdgo6qi.fsf@rho.meyering.net> "Daniel P. Berrange" wrote: > On Fri, May 02, 2008 at 10:40:50AM -0400, Hugh O. Brock wrote: >> On Fri, May 02, 2008 at 03:31:44PM +0100, Daniel P. Berrange wrote: >> > On Fri, May 02, 2008 at 10:19:24AM -0400, Chris Lalancette wrote: >> > It is important to distinguish the dev snapshots from the previous stable >> > release by version number. Merely bumping the release during development >> > does not really achieve this. >> > >> > IMHO the way to deal with this is to >> > >> > - Immediately after a release: >> > - Bump the version number >> > - Reset the release number to '0.git1' >> > - When making changes >> > - Bump the last digit in the release number, eg '0.git2', '0.git3' >> > - At time of release >> > - Bump the release to '1' >> > >> > This ensures that the RPM has a newer version number to indicate it is >> > functionality different from the previous stable release, and using the >> > leading '0' in Release: is following Fedora guidlines for pre-release >> > software release numbering scheme. >> >> Yes, this is what I was thinking as well... does that imply >> incrementing the release number on every commit, though? And if so is >> it easier to use e.g. a changeset number in the release number to >> avoid having to manually increment the release number? Yeah, I hate having to do things like that manually. If it's manual, it will eventually be done wrong. > There is no linear increasing changeset number you can use with GIT really. Actually there is, if you arrange your development model a certain way, and if you count change-sets in a centralized repository. Run "git describe" in the ovirt repo. Currently on master, it prints this: demo-2008-02-22-166-g7450ebc That says we're on the 166'th change-set since the most recent preceding (reachable) signed tag, "demo-2008-02-22". Of course, that doesn't help if you're interested in the 0.4 branch. Hmm... even from the release-0.4 branch, there is no 0.4 tag. Maybe the tip is it? If the head of that branch is it, Chris might want to tag it like this: git checkout release-0.4 git tag -m 'oVirt 0.4' -s v0.4 HEAD This mechanism to count change sets is most useful if you keep the trunk "golden" (like git.git does) and do development on branches, merging changes onto the trunk when they're sufficiently well tested. Then most release tags are reachable from the head of "master". For a project like git itself, since there's a v1.5.5.1 tag for that release, git describe shows HEAD is 116 change-sets past that release: v1.5.5.1-116-ge4b9c36 It wouldn't take much to make this work for ovirt. Just create a place-holder signed tag on master, e.g., git tag -m 'oVirt 0.4.1 -- not a real release' -s v0.4.1 HEAD and add infrastructure to propagate git change-set numbers to whatever tools need it. For example, with any snapshot build of coreutils, I get a version string like this: $ cat --version|head -1 cat (GNU coreutils) 6.11.43-d26e6 [that's 43 change-sets past the 6.11 release tag] For a release, it'd be the usual: $ cat --version|head -1 cat (GNU coreutils) 6.11 If you're interested in the development model, a good summary of how git.git does it (using three main branches, in addition to "master") is described in http://members.cox.net/junkio/. From jim at meyering.net Fri May 2 19:24:14 2008 From: jim at meyering.net (Jim Meyering) Date: Fri, 02 May 2008 21:24:14 +0200 Subject: [Ovirt-devel] [PATCH] A few specfile tweaks In-Reply-To: <20080501203910.68127b11@tp.mains.net> (Ian Main's message of "Thu, 1 May 2008 20:39:10 -0700") References: <20080501162133.47b2b10e@tp.mains.net> <20080501203910.68127b11@tp.mains.net> Message-ID: <87bq3oo6g1.fsf@rho.meyering.net> Ian Main wrote: > D'oh, need this too.. Consider it an addendum :) > > diff --git a/wui-appliance/common-post.ks b/wui-appliance/common-post.ks > index 3bd6b4d..d50436a 100644 > --- a/wui-appliance/common-post.ks > +++ b/wui-appliance/common-post.ks > @@ -34,7 +34,7 @@ cat > /etc/init.d/ovirt-wui-first-run << \EOF > start() { > echo -n "Starting ovirt-wui-first-run: " > > - /usr/bin/ovirt-wui-install > /var/log/ovirt-wui-first-run.log 2>&1 > + /usr/sbin/ovirt-wui-install > /var/log/ovirt-wui-first-run.log 2>&1 Hi Ian, You could also just drop the leading "/usr/sbin/", since the PATH is set via the preceding ". /etc/init.d/functions" line. This is another good reason to avoid those absolute prefixes when possible. Speaking of that, I still have a patch that removes a whole bunch of them. I'll rebase it and post on Monday. From clalance at redhat.com Sat May 3 14:01:35 2008 From: clalance at redhat.com (Chris Lalancette) Date: Sat, 03 May 2008 10:01:35 -0400 Subject: [Ovirt-devel] [PATCH] wrappers for taskomatic.rb and host-status.rb In-Reply-To: <769584de0805021041g370ac7a3yd6ec0d24bdbe02a1@mail.gmail.com> References: <769584de0805011537h22491b71qeccca30360e6b52c@mail.gmail.com> <20080501225638.GB21047@redhat.com> <20080501230957.GQ23162@redhat.com> <769584de0805021041g370ac7a3yd6ec0d24bdbe02a1@mail.gmail.com> Message-ID: <481C703F.5050308@redhat.com> steve linabery wrote: > Hi Hugh and ovirt, > > Well, it turns out it is even simpler than that. All I really needed > to do was look at host-keyadd, which cooperates well with daemon & > killproc by doing 'include Daemonize' and calling 'daemonize', as > you'll see in the attached patch. > > Patch adjusts taskomatic.rb and host-status.rb accordingly, and now > they play nice with /etc/init.d/ovirt-wui script. Steve, OK, this could just be my weak understanding of Ruby, but isn't this patch essentially the same as what it was before? That is, isn't: require 'daemons' Daemons.daemonize equivalent to require 'daemons' include Daemonize daemonize ? If it works, I'm totally cool with the patch; I'd just like to understand the difference between the two code snippets. Chris Lalancette From slinabery at gmail.com Sat May 3 22:38:26 2008 From: slinabery at gmail.com (steve linabery) Date: Sat, 3 May 2008 17:38:26 -0500 Subject: [Ovirt-devel] [PATCH] wrappers for taskomatic.rb and host-status.rb In-Reply-To: <481C703F.5050308@redhat.com> References: <769584de0805011537h22491b71qeccca30360e6b52c@mail.gmail.com> <20080501225638.GB21047@redhat.com> <20080501230957.GQ23162@redhat.com> <769584de0805021041g370ac7a3yd6ec0d24bdbe02a1@mail.gmail.com> <481C703F.5050308@redhat.com> Message-ID: <769584de0805031538x7bc90174vc65c081cf224a560@mail.gmail.com> On Sat, May 3, 2008 at 9:01 AM, Chris Lalancette wrote: > steve linabery wrote: > > Hi Hugh and ovirt, > > > > Well, it turns out it is even simpler than that. All I really needed > > to do was look at host-keyadd, which cooperates well with daemon & > > killproc by doing 'include Daemonize' and calling 'daemonize', as > > you'll see in the attached patch. > > > > Patch adjusts taskomatic.rb and host-status.rb accordingly, and now > > they play nice with /etc/init.d/ovirt-wui script. > > Steve, > OK, this could just be my weak understanding of Ruby, but isn't this patch > essentially the same as what it was before? That is, isn't: > > require 'daemons' > Daemons.daemonize > > equivalent to > > require 'daemons' > include Daemonize > daemonize > > ? If it works, I'm totally cool with the patch; I'd just like to understand the > difference between the two code snippets. > > Chris Lalancette > Hi Chris, I believe the difference is that you used 'include Daemonize', although I don't know exactly what the difference is. 'include' seems to make the methods of the included module part of the class that calls include. So I think there is a difference between calling Daemons.daemonize (where the code presumably executes "in" the Daemons class?) and daemonize after the include. I think there may also be some slight difference between using the daemonize method in Daemons versus that in Daemonize...even though if you look at the source for Daemons.daemonize(options) it looks like it might be a wrapper for Daemonize.daemonize. I haven't read enough about how ruby's Process to know exactly how ruby is interacting with the unix environment and how Daemonize might differ from Daemons. I defer to a greater ruby master than myself on this topic and merely note that "it works". Have a good weekend, Steve From meyering at redhat.com Mon May 5 19:07:46 2008 From: meyering at redhat.com (Jim Meyering) Date: Mon, 05 May 2008 21:07:46 +0200 Subject: [Ovirt-devel] [PATCH] A few specfile tweaks In-Reply-To: <87bq3oo6g1.fsf@rho.meyering.net> (Jim Meyering's message of "Fri, 02 May 2008 21:24:14 +0200") References: <20080501162133.47b2b10e@tp.mains.net> <20080501203910.68127b11@tp.mains.net> <87bq3oo6g1.fsf@rho.meyering.net> Message-ID: <87wsm8fu2l.fsf@rho.meyering.net> Jim Meyering wrote: > Ian Main wrote: >> D'oh, need this too.. Consider it an addendum :) >> >> diff --git a/wui-appliance/common-post.ks b/wui-appliance/common-post.ks >> index 3bd6b4d..d50436a 100644 >> --- a/wui-appliance/common-post.ks >> +++ b/wui-appliance/common-post.ks >> @@ -34,7 +34,7 @@ cat > /etc/init.d/ovirt-wui-first-run << \EOF >> start() { >> echo -n "Starting ovirt-wui-first-run: " >> >> - /usr/bin/ovirt-wui-install > /var/log/ovirt-wui-first-run.log 2>&1 >> + /usr/sbin/ovirt-wui-install > /var/log/ovirt-wui-first-run.log 2>&1 > > Hi Ian, > > You could also just drop the leading "/usr/sbin/", since the PATH > is set via the preceding ". /etc/init.d/functions" line. > > This is another good reason to avoid those absolute prefixes when possible. > > Speaking of that, I still have a patch that removes a whole bunch of them. > I'll rebase it and post on Monday. I've been doing this little by little over the last month or two... If you're interested only in some parts, tell me which and I'll extract them: - factor out some duplication - split long lines - remove /usr/sbin, /usr/bin, etc. prefixes - a couple misc things like use printf rather than echo -e Until today, the middle change-set accidentally removed some trailing blanks (not good to mix that sort of change with a "real" one), so today after the main rebase (git rebase master) I ran "git rebase -i master" from my topic branch, selected the middle change-set and actually re-added those trailing blanks. Avoiding this sort of extra work is one of the reasons I'd like to remove all trailing blanks. What sort of testing would you like? Jim ------------------- From meyering at redhat.com Mon May 5 19:27:21 2008 From: meyering at redhat.com (Jim Meyering) Date: Mon, 05 May 2008 21:27:21 +0200 Subject: [Ovirt-devel] [PATCH] A few specfile tweaks In-Reply-To: <87wsm8fu2l.fsf@rho.meyering.net> (Jim Meyering's message of "Mon, 05 May 2008 21:07:46 +0200") References: <20080501162133.47b2b10e@tp.mains.net> <20080501203910.68127b11@tp.mains.net> <87bq3oo6g1.fsf@rho.meyering.net> <87wsm8fu2l.fsf@rho.meyering.net> Message-ID: <87r6cgft5y.fsf@rho.meyering.net> Jim Meyering wrote: > Jim Meyering wrote: >> Ian Main wrote: >>> D'oh, need this too.. Consider it an addendum :) >>> >>> diff --git a/wui-appliance/common-post.ks b/wui-appliance/common-post.ks >>> index 3bd6b4d..d50436a 100644 >>> --- a/wui-appliance/common-post.ks >>> +++ b/wui-appliance/common-post.ks >>> @@ -34,7 +34,7 @@ cat > /etc/init.d/ovirt-wui-first-run << \EOF >>> start() { >>> echo -n "Starting ovirt-wui-first-run: " >>> >>> - /usr/bin/ovirt-wui-install > /var/log/ovirt-wui-first-run.log 2>&1 >>> + /usr/sbin/ovirt-wui-install > /var/log/ovirt-wui-first-run.log 2>&1 >> >> Hi Ian, >> >> You could also just drop the leading "/usr/sbin/", since the PATH >> is set via the preceding ". /etc/init.d/functions" line. >> >> This is another good reason to avoid those absolute prefixes when possible. >> >> Speaking of that, I still have a patch that removes a whole bunch of them. >> I'll rebase it and post on Monday. > > I've been doing this little by little over the last month or two... > If you're interested only in some parts, tell me which and I'll extract them: > > - factor out some duplication > - split long lines > - remove /usr/sbin, /usr/bin, etc. prefixes > - a couple misc things like use printf rather than echo -e > > Until today, the middle change-set accidentally removed some > trailing blanks (not good to mix that sort of change with a "real" one), > so today after the main rebase (git rebase master) I ran > "git rebase -i master" from my topic branch, selected the middle > change-set and actually re-added those trailing blanks. > > Avoiding this sort of extra work is one of the reasons I'd like > to remove all trailing blanks. > > What sort of testing would you like? FYI, I really did send the three change sets, but our old version of mailman ate them. Here they are again, but with the "From " lines '>'-escaped. >From 1d2927b089219e90e6e073d5a2c299f25d94955d Mon Sep 17 00:00:00 2001 Date: Thu, 13 Mar 2008 13:41:32 +0100 Subject: [PATCH] Don't specify absolute names for programs. /etc/init.d/functions ensures that PATH is reasonable: PATH="/sbin:/usr/sbin:/bin:/usr/bin" Signed-off-by: Jim Meyering --- ovirt-host-creator/common-post.ks | 20 ++++++++++---------- ovirt-host-creator/ovirt-common.sh | 7 +++++-- ovirt-host-creator/ovirt-flash-static.sh | 4 ++-- ovirt-host-creator/ovirt-flash.sh | 6 +++--- ovirt-host-creator/ovirt-pxe.sh | 3 +-- 5 files changed, 21 insertions(+), 19 deletions(-) diff --git a/ovirt-host-creator/common-post.ks b/ovirt-host-creator/common-post.ks index 18ab8d8..64fe0ee 100644 --- a/ovirt-host-creator/common-post.ks +++ b/ovirt-host-creator/common-post.ks @@ -63,11 +63,11 @@ start() { BLOCKDEVS=`ls /dev/sd? /dev/hd? 2>/dev/null` # now LVM partitions - LVMDEVS="$DEVICES `/usr/sbin/lvscan | awk '{print $2}' | tr -d \"'\"`" + LVMDEVS="$DEVICES `lvscan | awk '{print $2}' | tr -d \"'\"`" SWAPDEVS="$LVMDEVS" for dev in $BLOCKDEVS; do - SWAPDEVS="$SWAPDEVS `/sbin/fdisk -l $dev 2>/dev/null | tr '*' ' ' \ + SWAPDEVS="$SWAPDEVS `fdisk -l $dev 2>/dev/null | tr '*' ' ' \ | awk '$5 ~ /82/ {print $1}'`" done @@ -76,7 +76,7 @@ start() { sig=`dd if=$device bs=1 count=10 skip=$(( $PAGESIZE - 10 )) \ 2>/dev/null` if [ "$sig" = "SWAPSPACE2" ]; then - /sbin/swapon $device + swapon $device fi done } @@ -92,7 +92,7 @@ esac EOF chmod +x /etc/init.d/ovirt-early -/sbin/chkconfig ovirt-early on +chkconfig ovirt-early on # just to get a boot warning to shut up touch /etc/resolv.conf @@ -131,7 +131,7 @@ start() { # then give up tries=0 while [ "$VAL" != "SUCCESS" -a $tries -lt 5 ]; do - VAL=`echo "KERB" | /usr/bin/nc $SRV_HOST 6666` + VAL=`echo "KERB" | nc $SRV_HOST 6666` if [ "$VAL" == "SUCCESS" ]; then break fi @@ -193,9 +193,9 @@ echo "Setting up bridged networking" cat > /etc/kvm-ifup << \EOF #!/bin/sh -switch=$(/sbin/ip route list | awk '/^default / { print $NF }') -/sbin/ifconfig $1 0.0.0.0 up -/usr/sbin/brctl addif ${switch} $1 +switch=$(ip route list | awk '/^default / { print $NF }') +ifconfig $1 0.0.0.0 up +brctl addif ${switch} $1 EOF chmod +x /etc/kvm-ifup @@ -270,8 +270,8 @@ rm -f /etc/krb5.conf echo "Creating shadow files" # because we aren't installing authconfig, we aren't setting up shadow # and gshadow properly. Do it by hand here -/usr/sbin/pwconv -/usr/sbin/grpconv +pwconv +grpconv echo "Re-creating cracklib dicts" # cracklib-dicts is 8MB. We probably don't need to have strict password diff --git a/ovirt-host-creator/ovirt-common.sh b/ovirt-host-creator/ovirt-common.sh index 2ada16e..1680a2c 100644 --- a/ovirt-host-creator/ovirt-common.sh +++ b/ovirt-host-creator/ovirt-common.sh @@ -1,11 +1,14 @@ +PATH=/sbin:/bin:/usr/bin +export PATH + create_iso() { KICKSTART=ovirt-`uname -i`.ks if [ $# -eq 0 ]; then LABEL=ovirt-`date +%Y%m%d%H%M` - /usr/bin/livecd-creator --skip-minimize -c $KICKSTART -f $LABEL 1>&2 && + livecd-creator --skip-minimize -c $KICKSTART -f $LABEL 1>&2 && echo $LABEL.iso elif [ $# -eq 1 ]; then - /usr/bin/livecd-creator --skip-minimize -c $KICKSTART -b $1 1>&2 && + livecd-creator --skip-minimize -c $KICKSTART -b $1 1>&2 && echo $1 else return 1 diff --git a/ovirt-host-creator/ovirt-flash-static.sh b/ovirt-host-creator/ovirt-flash-static.sh index f31fc02..12e3d14 100755 --- a/ovirt-host-creator/ovirt-flash-static.sh +++ b/ovirt-host-creator/ovirt-flash-static.sh @@ -47,7 +47,7 @@ mount -o loop $IMGTMP/LiveOS/squashfs.img $SQUASHTMP # clear out the old partition table dd if=/dev/zero of=$USBDEVICE bs=4096 count=1 -echo -e 'n\np\n1\n\n\nt\n83\na\n1\nw\n' | /sbin/fdisk $USBDEVICE +printf 'n\np\n1\n\n\nt\n83\na\n1\nw\n' | fdisk $USBDEVICE cat /usr/lib/syslinux/mbr.bin > $USBDEVICE dd if=$SQUASHTMP/LiveOS/ext3fs.img of=${USBDEVICE}1 @@ -62,7 +62,7 @@ mv $USBTMP/isolinux.cfg $USBTMP/extlinux.conf LABEL=`echo $ISO | cut -d'.' -f1 | cut -c-16` sed -i -e "s/ *append.*/ append initrd=initrd.img root=LABEL=$LABEL ro/" $USBTMP/extlinux.conf -/sbin/extlinux -i $USBTMP +extlinux -i $USBTMP umount $USBTMP umount $SQUASHTMP diff --git a/ovirt-host-creator/ovirt-flash.sh b/ovirt-host-creator/ovirt-flash.sh index bb0ca45..621972c 100755 --- a/ovirt-host-creator/ovirt-flash.sh +++ b/ovirt-host-creator/ovirt-flash.sh @@ -39,7 +39,7 @@ ISO=`create_iso $ISO` || exit 1 # clear out the old partition table dd if=/dev/zero of=$USBDEVICE bs=4096 count=1 -echo -e 'n\np\n1\n\n\nt\n6\na\n1\nw\n' | /sbin/fdisk $USBDEVICE -/sbin/mkdosfs -n ovirt ${USBDEVICE}1 +printf 'n\np\n1\n\n\nt\n6\na\n1\nw\n' | fdisk $USBDEVICE +mkdosfs -n ovirt ${USBDEVICE}1 cat /usr/lib/syslinux/mbr.bin > $USBDEVICE -/usr/bin/livecd-iso-to-disk $ISO ${USBDEVICE}1 +livecd-iso-to-disk $ISO ${USBDEVICE}1 diff --git a/ovirt-host-creator/ovirt-pxe.sh b/ovirt-host-creator/ovirt-pxe.sh index 1581e15..632ec5d 100755 --- a/ovirt-host-creator/ovirt-pxe.sh +++ b/ovirt-host-creator/ovirt-pxe.sh @@ -30,5 +30,4 @@ fi ISO=`create_iso $ISO` || exit 1 -/usr/bin/livecd-iso-to-pxeboot $ISO - +livecd-iso-to-pxeboot $ISO -- 1.5.5.1.126.g02179 >From 20404b532b69c851910773ae67c794e3e1e39034 Mon Sep 17 00:00:00 2001 Date: Thu, 20 Mar 2008 08:59:41 +0100 Subject: [PATCH] remove abs names, split long lines, factor out some duplication Signed-off-by: Jim Meyering --- wui-appliance/wui-devel-x86_64.ks | 71 ++++++++++++++++++++++--------------- 1 files changed, 42 insertions(+), 29 deletions(-) diff --git a/wui-appliance/wui-devel-x86_64.ks b/wui-appliance/wui-devel-x86_64.ks index c7ccdd7..f28ed27 100644 --- a/wui-appliance/wui-devel-x86_64.ks +++ b/wui-appliance/wui-devel-x86_64.ks @@ -23,7 +23,8 @@ repo --name=ovirt-management --baseurl=http://ovirt.et.redhat.com/repos/ovirt-ma %include common-post.ks # make sure our "hostname" resolves to management.priv.ovirt.org -sed -i -e 's/^HOSTNAME.*/HOSTNAME=management.priv.ovirt.org/' /etc/sysconfig/network +sed -i -e 's/^HOSTNAME.*/HOSTNAME=management.priv.ovirt.org/' \ + /etc/sysconfig/network # make sure to update the /etc/hosts with the list of all possible DHCP # addresses we can hand out; dnsmasq uses this @@ -32,31 +33,38 @@ for i in `seq 3 252` ; do echo "192.168.50.$i node$i.priv.ovirt.org" >> /etc/hosts done +principal=ovirtadmin at PRIV.OVIRT.ORG +cron_file=/etc/cron.hourly/ovirtadmin.cron +ktab_file=/usr/share/ovirt-wui/ovirtadmin.tab + # automatically refresh the kerberos ticket every hour (we'll create the # principal on first-boot) -cat > /etc/cron.hourly/ovirtadmin.cron << \EOF +cat > $cron_file << EOF #!/bin/bash -/usr/kerberos/bin/kdestroy -/usr/kerberos/bin/kinit -k -t /usr/share/ovirt-wui/ovirtadmin.tab ovirtadmin at PRIV.OVIRT.ORG +export PATH=/usr/kerberos/bin:$PATH +kdestroy +kinit -k -t $ktab_file $principal EOF -chmod 755 /etc/cron.hourly/ovirtadmin.cron +chmod 755 $cron_file + +ff_profile_dir=uxssq4qb.ovirtadmin # for firefox, we need to make some subdirs and add some preferences -mkdir -p /root/.mozilla/firefox/uxssq4qb.ovirtadmin -cat >> /root/.mozilla/firefox/uxssq4qb.ovirtadmin/prefs.js << \EOF +mkdir -p /root/.mozilla/firefox/$ff_profile_dir +cat >> /root/.mozilla/firefox/$ff_profile_dir/prefs.js << \EOF user_pref("network.negotiate-auth.delegation-uris", "priv.ovirt.org"); user_pref("network.negotiate-auth.trusted-uris", "priv.ovirt.org"); user_pref("browser.startup.homepage", "http://management.priv.ovirt.org/ovirt"); EOF -cat >> /root/.mozilla/firefox/profiles.ini << \EOF +cat >> /root/.mozilla/firefox/profiles.ini << EOF [General] StartWithLastProfile=1 [Profile0] Name=ovirtadmin IsRelative=1 -Path=uxssq4qb.ovirtadmin +Path=$ff_profile_dir EOF # make sure we don't mount the "fake" iSCSI LUNs, since they are meant to @@ -79,7 +87,7 @@ EOF chmod +x /etc/dhclient-exit-hooks # make sure that we get a kerberos principal on every boot -echo "/etc/cron.hourly/ovirtadmin.cron" >> /etc/rc.d/rc.local +echo "$cron_file" >> /etc/rc.d/rc.local # make collectd.conf. cat > /etc/collectd.conf << \EOF @@ -105,7 +113,11 @@ LoadPlugin rrdtool EOF -cat > /etc/init.d/ovirt-wui-dev-first-run << \EOF +first_run_file=/etc/init.d/ovirt-wui-dev-first-run +sed -e "s, at cron_file@,$cron_file," \ + -e "s, at principal@,$principal," \ + -e "s, at ktab_file@,$ktab_file," \ + > $first_run_file << \EOF #!/bin/bash # # ovirt-wui-dev-first-run First run configuration for Ovirt WUI Dev appliance @@ -123,12 +135,13 @@ start() { echo -n "Starting ovirt-dev-wui-first-run: " ( # set up freeipa - /usr/sbin/ipa-server-install -r PRIV.OVIRT.ORG -p ovirt -P ovirt -a ovirtwui --hostname management.priv.ovirt.org -u dirsrv -U + ipa-server-install -r PRIV.OVIRT.ORG -p ovirt -P ovirt -a ovirtwui \ + --hostname management.priv.ovirt.org -u dirsrv -U # now create the ovirtadmin user - $KADMIN -q 'addprinc -randkey ovirtadmin at PRIV.OVIRT.ORG' - $KADMIN -q 'ktadd -k /usr/share/ovirt-wui/ovirtadmin.tab ovirtadmin at PRIV.OVIRT.ORG' - /etc/cron.hourly/ovirtadmin.cron + $KADMIN -q 'addprinc -randkey @principal@' + $KADMIN -q 'ktadd -k @ktab_file@ @principal@' + @cron_file@ ) > /var/log/ovirt-wui-dev-first-run.log 2>&1 RETVAL=$? @@ -149,9 +162,9 @@ case "$1" in exit 2 esac -/sbin/chkconfig ovirt-wui-dev-first-run off +chkconfig ovirt-wui-dev-first-run off EOF -chmod +x /etc/init.d/ovirt-wui-dev-first-run +chmod +x $first_run_file /sbin/chkconfig ovirt-wui-dev-first-run on cat > /etc/init.d/ovirt-wui-dev << \EOF @@ -168,7 +181,7 @@ cat > /etc/init.d/ovirt-wui-dev << \EOF start() { echo -n "Starting ovirt-wui-dev: " - /usr/sbin/dnsmasq -i eth1 -F 192.168.50.6,192.168.50.252 \ + dnsmasq -i eth1 -F 192.168.50.6,192.168.50.252 \ -G 00:16:3e:12:34:57,192.168.50.3 -G 00:16:3e:12:34:58,192.168.50.4 \ -G 00:16:3e:12:34:59,192.168.50.5 \ -s priv.ovirt.org \ @@ -181,23 +194,23 @@ start() { -R -S 192.168.122.1 # Set up the fake iscsi target - /usr/sbin/tgtadm --lld iscsi --op new --mode target --tid 1 \ + tgtadm --lld iscsi --op new --mode target --tid 1 \ -T ovirtpriv:storage # # Now associate them to the LVs # - /usr/sbin/tgtadm --lld iscsi --op new --mode logicalunit --tid 1 \ + tgtadm --lld iscsi --op new --mode logicalunit --tid 1 \ --lun 1 -b /dev/VolGroup00/iSCSI3 - /usr/sbin/tgtadm --lld iscsi --op new --mode logicalunit --tid 1 \ + tgtadm --lld iscsi --op new --mode logicalunit --tid 1 \ --lun 2 -b /dev/VolGroup00/iSCSI4 - /usr/sbin/tgtadm --lld iscsi --op new --mode logicalunit --tid 1 \ + tgtadm --lld iscsi --op new --mode logicalunit --tid 1 \ --lun 3 -b /dev/VolGroup00/iSCSI5 - + # # Now make them available # - /usr/sbin/tgtadm --lld iscsi --op bind --mode target --tid 1 -I ALL + tgtadm --lld iscsi --op bind --mode target --tid 1 -I ALL echo_success echo @@ -207,15 +220,15 @@ stop() { echo -n "Stopping ovirt-wui-dev: " # stop access to the iscsi target - /usr/sbin/tgtadm --lld iscsi --op unbind --mode target --tid 1 -I ALL + tgtadm --lld iscsi --op unbind --mode target --tid 1 -I ALL # unbind the LUNs - /usr/sbin/tgtadm --lld iscsi --op delete --mode logicalunit --tid 1 --lun 3 - /usr/sbin/tgtadm --lld iscsi --op delete --mode logicalunit --tid 1 --lun 2 - /usr/sbin/tgtadm --lld iscsi --op delete --mode logicalunit --tid 1 --lun 1 + tgtadm --lld iscsi --op delete --mode logicalunit --tid 1 --lun 3 + tgtadm --lld iscsi --op delete --mode logicalunit --tid 1 --lun 2 + tgtadm --lld iscsi --op delete --mode logicalunit --tid 1 --lun 1 # shutdown the target - /usr/sbin/tgtadm --lld iscsi --op delete --mode target --tid 1 + tgtadm --lld iscsi --op delete --mode target --tid 1 kill $(cat /var/run/dnsmasq.pid) -- 1.5.5.1.126.g02179 >From 7d6e35a711f104482dc9939fa0ba2936153947f3 Mon Sep 17 00:00:00 2001 Date: Fri, 11 Apr 2008 19:14:20 +0200 Subject: [PATCH] * ovirt-host-creator/common-post.ks: Add explicit PATH= setting, ... so it's obviously ok to remove all absolute path prefixes. * wui-appliance/common-post.ks: Likewise. Signed-off-by: Jim Meyering --- ovirt-host-creator/common-post.ks | 6 ++++-- wui-appliance/common-post.ks | 9 ++++++--- wui-appliance/wui-devel-x86_64.ks | 4 ++-- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/ovirt-host-creator/common-post.ks b/ovirt-host-creator/common-post.ks index 64fe0ee..17291b4 100644 --- a/ovirt-host-creator/common-post.ks +++ b/ovirt-host-creator/common-post.ks @@ -1,4 +1,6 @@ echo "Starting Kickstart Post" +PATH=/sbin:/usr/sbin:/bin:/usr/bin +export PATH echo "Setting up Networking" cat > /etc/sysconfig/iptables << \EOF @@ -183,7 +185,7 @@ esac EOF chmod +x /etc/init.d/ovirt -/sbin/chkconfig ovirt on +chkconfig ovirt on echo "Setting up libvirt interfaces" # make libvirtd listen on the external interfaces @@ -278,7 +280,7 @@ echo "Re-creating cracklib dicts" # checking on the ovirt host # unfortunately we can't create an empty cracklib dict, so we create it # with a single entry "1" -echo 1 | /usr/sbin/packer >& /dev/null +echo 1 | packer >& /dev/null echo "Forcing C locale" # force logins (via ssh, etc) to use C locale, since we remove locales diff --git a/wui-appliance/common-post.ks b/wui-appliance/common-post.ks index 3bd6b4d..3dee5bb 100644 --- a/wui-appliance/common-post.ks +++ b/wui-appliance/common-post.ks @@ -1,3 +1,6 @@ +PATH=/sbin:/usr/sbin:/bin:/usr/bin +export PATH + # pretty login screen.. g=$(printf '\33[1m\33[32m') # similar to g=$(tput bold; tput setaf 2) n=$(printf '\33[m') # similar to n=$(tput sgr0) @@ -34,7 +37,7 @@ cat > /etc/init.d/ovirt-wui-first-run << \EOF start() { echo -n "Starting ovirt-wui-first-run: " - /usr/bin/ovirt-wui-install > /var/log/ovirt-wui-first-run.log 2>&1 + ovirt-wui-install > /var/log/ovirt-wui-first-run.log 2>&1 RETVAL=$? if [ $RETVAL -eq 0 ]; then @@ -54,10 +57,10 @@ case "$1" in exit 2 esac -/sbin/chkconfig ovirt-wui-first-run off +chkconfig ovirt-wui-first-run off EOF chmod +x /etc/init.d/ovirt-wui-first-run -/sbin/chkconfig ovirt-wui-first-run on +chkconfig ovirt-wui-first-run on cat > /etc/yum.repos.d/ovirt-management.repo << \EOF [ovirt-management] diff --git a/wui-appliance/wui-devel-x86_64.ks b/wui-appliance/wui-devel-x86_64.ks index f28ed27..67172ba 100644 --- a/wui-appliance/wui-devel-x86_64.ks +++ b/wui-appliance/wui-devel-x86_64.ks @@ -165,7 +165,7 @@ esac chkconfig ovirt-wui-dev-first-run off EOF chmod +x $first_run_file -/sbin/chkconfig ovirt-wui-dev-first-run on +chkconfig ovirt-wui-dev-first-run on cat > /etc/init.d/ovirt-wui-dev << \EOF #!/bin/bash @@ -253,7 +253,7 @@ case "$1" in esac EOF chmod +x /etc/init.d/ovirt-wui-dev -/sbin/chkconfig ovirt-wui-dev on +chkconfig ovirt-wui-dev on # get the PXE boot image; this can take a while PXE_URL=http://ovirt.org/download -- 1.5.5.1.126.g02179 From hbrock at redhat.com Mon May 5 19:37:43 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Mon, 5 May 2008 15:37:43 -0400 Subject: [Ovirt-devel] [PATCH] A few specfile tweaks In-Reply-To: <87r6cgft5y.fsf@rho.meyering.net> References: <20080501162133.47b2b10e@tp.mains.net> <20080501203910.68127b11@tp.mains.net> <87bq3oo6g1.fsf@rho.meyering.net> <87wsm8fu2l.fsf@rho.meyering.net> <87r6cgft5y.fsf@rho.meyering.net> Message-ID: <20080505193742.GB16435@redhat.com> On Mon, May 05, 2008 at 09:27:21PM +0200, Jim Meyering wrote: > Jim Meyering wrote: > > > Jim Meyering wrote: > >> Ian Main wrote: > >>> D'oh, need this too.. Consider it an addendum :) > >>> > >>> diff --git a/wui-appliance/common-post.ks b/wui-appliance/common-post.ks > >>> index 3bd6b4d..d50436a 100644 > >>> --- a/wui-appliance/common-post.ks > >>> +++ b/wui-appliance/common-post.ks > >>> @@ -34,7 +34,7 @@ cat > /etc/init.d/ovirt-wui-first-run << \EOF > >>> start() { > >>> echo -n "Starting ovirt-wui-first-run: " > >>> > >>> - /usr/bin/ovirt-wui-install > /var/log/ovirt-wui-first-run.log 2>&1 > >>> + /usr/sbin/ovirt-wui-install > /var/log/ovirt-wui-first-run.log 2>&1 > >> > >> Hi Ian, > >> > >> You could also just drop the leading "/usr/sbin/", since the PATH > >> is set via the preceding ". /etc/init.d/functions" line. > >> > >> This is another good reason to avoid those absolute prefixes when possible. > >> > >> Speaking of that, I still have a patch that removes a whole bunch of them. > >> I'll rebase it and post on Monday. > > > > I've been doing this little by little over the last month or two... > > If you're interested only in some parts, tell me which and I'll extract them: > > > > - factor out some duplication > > - split long lines > > - remove /usr/sbin, /usr/bin, etc. prefixes > > - a couple misc things like use printf rather than echo -e > > > > Until today, the middle change-set accidentally removed some > > trailing blanks (not good to mix that sort of change with a "real" one), > > so today after the main rebase (git rebase master) I ran > > "git rebase -i master" from my topic branch, selected the middle > > change-set and actually re-added those trailing blanks. > > > > Avoiding this sort of extra work is one of the reasons I'd like > > to remove all trailing blanks. > > > > What sort of testing would you like? > > FYI, I really did send the three change sets, but our > old version of mailman ate them. > > Here they are again, but with the "From " lines '>'-escaped. > > >From 1d2927b089219e90e6e073d5a2c299f25d94955d Mon Sep 17 00:00:00 2001 > Date: Thu, 13 Mar 2008 13:41:32 +0100 > Subject: [PATCH] Don't specify absolute names for programs. > > /etc/init.d/functions ensures that PATH is reasonable: > PATH="/sbin:/usr/sbin:/bin:/usr/bin" > > Signed-off-by: Jim Meyering > --- > ovirt-host-creator/common-post.ks | 20 ++++++++++---------- > ovirt-host-creator/ovirt-common.sh | 7 +++++-- > ovirt-host-creator/ovirt-flash-static.sh | 4 ++-- > ovirt-host-creator/ovirt-flash.sh | 6 +++--- > ovirt-host-creator/ovirt-pxe.sh | 3 +-- > 5 files changed, 21 insertions(+), 19 deletions(-) > > diff --git a/ovirt-host-creator/common-post.ks b/ovirt-host-creator/common-post.ks > index 18ab8d8..64fe0ee 100644 > --- a/ovirt-host-creator/common-post.ks > +++ b/ovirt-host-creator/common-post.ks > @@ -63,11 +63,11 @@ start() { > BLOCKDEVS=`ls /dev/sd? /dev/hd? 2>/dev/null` > > # now LVM partitions > - LVMDEVS="$DEVICES `/usr/sbin/lvscan | awk '{print $2}' | tr -d \"'\"`" > + LVMDEVS="$DEVICES `lvscan | awk '{print $2}' | tr -d \"'\"`" > > SWAPDEVS="$LVMDEVS" > for dev in $BLOCKDEVS; do > - SWAPDEVS="$SWAPDEVS `/sbin/fdisk -l $dev 2>/dev/null | tr '*' ' ' \ > + SWAPDEVS="$SWAPDEVS `fdisk -l $dev 2>/dev/null | tr '*' ' ' \ > | awk '$5 ~ /82/ {print $1}'`" > done > > @@ -76,7 +76,7 @@ start() { > sig=`dd if=$device bs=1 count=10 skip=$(( $PAGESIZE - 10 )) \ > 2>/dev/null` > if [ "$sig" = "SWAPSPACE2" ]; then > - /sbin/swapon $device > + swapon $device > fi > done > } > @@ -92,7 +92,7 @@ esac > EOF > > chmod +x /etc/init.d/ovirt-early > -/sbin/chkconfig ovirt-early on > +chkconfig ovirt-early on > > # just to get a boot warning to shut up > touch /etc/resolv.conf > @@ -131,7 +131,7 @@ start() { > # then give up > tries=0 > while [ "$VAL" != "SUCCESS" -a $tries -lt 5 ]; do > - VAL=`echo "KERB" | /usr/bin/nc $SRV_HOST 6666` > + VAL=`echo "KERB" | nc $SRV_HOST 6666` > if [ "$VAL" == "SUCCESS" ]; then > break > fi > @@ -193,9 +193,9 @@ echo "Setting up bridged networking" > cat > /etc/kvm-ifup << \EOF > #!/bin/sh > > -switch=$(/sbin/ip route list | awk '/^default / { print $NF }') > -/sbin/ifconfig $1 0.0.0.0 up > -/usr/sbin/brctl addif ${switch} $1 > +switch=$(ip route list | awk '/^default / { print $NF }') > +ifconfig $1 0.0.0.0 up > +brctl addif ${switch} $1 > EOF > > chmod +x /etc/kvm-ifup > @@ -270,8 +270,8 @@ rm -f /etc/krb5.conf > echo "Creating shadow files" > # because we aren't installing authconfig, we aren't setting up shadow > # and gshadow properly. Do it by hand here > -/usr/sbin/pwconv > -/usr/sbin/grpconv > +pwconv > +grpconv > > echo "Re-creating cracklib dicts" > # cracklib-dicts is 8MB. We probably don't need to have strict password > diff --git a/ovirt-host-creator/ovirt-common.sh b/ovirt-host-creator/ovirt-common.sh > index 2ada16e..1680a2c 100644 > --- a/ovirt-host-creator/ovirt-common.sh > +++ b/ovirt-host-creator/ovirt-common.sh > @@ -1,11 +1,14 @@ > +PATH=/sbin:/bin:/usr/bin > +export PATH > + > create_iso() { > KICKSTART=ovirt-`uname -i`.ks > if [ $# -eq 0 ]; then > LABEL=ovirt-`date +%Y%m%d%H%M` > - /usr/bin/livecd-creator --skip-minimize -c $KICKSTART -f $LABEL 1>&2 && > + livecd-creator --skip-minimize -c $KICKSTART -f $LABEL 1>&2 && > echo $LABEL.iso > elif [ $# -eq 1 ]; then > - /usr/bin/livecd-creator --skip-minimize -c $KICKSTART -b $1 1>&2 && > + livecd-creator --skip-minimize -c $KICKSTART -b $1 1>&2 && > echo $1 > else > return 1 > diff --git a/ovirt-host-creator/ovirt-flash-static.sh b/ovirt-host-creator/ovirt-flash-static.sh > index f31fc02..12e3d14 100755 > --- a/ovirt-host-creator/ovirt-flash-static.sh > +++ b/ovirt-host-creator/ovirt-flash-static.sh > @@ -47,7 +47,7 @@ mount -o loop $IMGTMP/LiveOS/squashfs.img $SQUASHTMP > > # clear out the old partition table > dd if=/dev/zero of=$USBDEVICE bs=4096 count=1 > -echo -e 'n\np\n1\n\n\nt\n83\na\n1\nw\n' | /sbin/fdisk $USBDEVICE > +printf 'n\np\n1\n\n\nt\n83\na\n1\nw\n' | fdisk $USBDEVICE > > cat /usr/lib/syslinux/mbr.bin > $USBDEVICE > dd if=$SQUASHTMP/LiveOS/ext3fs.img of=${USBDEVICE}1 > @@ -62,7 +62,7 @@ mv $USBTMP/isolinux.cfg $USBTMP/extlinux.conf > LABEL=`echo $ISO | cut -d'.' -f1 | cut -c-16` > sed -i -e "s/ *append.*/ append initrd=initrd.img root=LABEL=$LABEL ro/" $USBTMP/extlinux.conf > > -/sbin/extlinux -i $USBTMP > +extlinux -i $USBTMP > > umount $USBTMP > umount $SQUASHTMP > diff --git a/ovirt-host-creator/ovirt-flash.sh b/ovirt-host-creator/ovirt-flash.sh > index bb0ca45..621972c 100755 > --- a/ovirt-host-creator/ovirt-flash.sh > +++ b/ovirt-host-creator/ovirt-flash.sh > @@ -39,7 +39,7 @@ ISO=`create_iso $ISO` || exit 1 > > # clear out the old partition table > dd if=/dev/zero of=$USBDEVICE bs=4096 count=1 > -echo -e 'n\np\n1\n\n\nt\n6\na\n1\nw\n' | /sbin/fdisk $USBDEVICE > -/sbin/mkdosfs -n ovirt ${USBDEVICE}1 > +printf 'n\np\n1\n\n\nt\n6\na\n1\nw\n' | fdisk $USBDEVICE > +mkdosfs -n ovirt ${USBDEVICE}1 > cat /usr/lib/syslinux/mbr.bin > $USBDEVICE > -/usr/bin/livecd-iso-to-disk $ISO ${USBDEVICE}1 > +livecd-iso-to-disk $ISO ${USBDEVICE}1 > diff --git a/ovirt-host-creator/ovirt-pxe.sh b/ovirt-host-creator/ovirt-pxe.sh > index 1581e15..632ec5d 100755 > --- a/ovirt-host-creator/ovirt-pxe.sh > +++ b/ovirt-host-creator/ovirt-pxe.sh > @@ -30,5 +30,4 @@ fi > > ISO=`create_iso $ISO` || exit 1 > > -/usr/bin/livecd-iso-to-pxeboot $ISO > - > +livecd-iso-to-pxeboot $ISO > -- > 1.5.5.1.126.g02179 > > > >From 20404b532b69c851910773ae67c794e3e1e39034 Mon Sep 17 00:00:00 2001 > Date: Thu, 20 Mar 2008 08:59:41 +0100 > Subject: [PATCH] remove abs names, split long lines, factor out some duplication > > > Signed-off-by: Jim Meyering > --- > wui-appliance/wui-devel-x86_64.ks | 71 ++++++++++++++++++++++--------------- > 1 files changed, 42 insertions(+), 29 deletions(-) > > diff --git a/wui-appliance/wui-devel-x86_64.ks b/wui-appliance/wui-devel-x86_64.ks > index c7ccdd7..f28ed27 100644 > --- a/wui-appliance/wui-devel-x86_64.ks > +++ b/wui-appliance/wui-devel-x86_64.ks > @@ -23,7 +23,8 @@ repo --name=ovirt-management --baseurl=http://ovirt.et.redhat.com/repos/ovirt-ma > %include common-post.ks > > # make sure our "hostname" resolves to management.priv.ovirt.org > -sed -i -e 's/^HOSTNAME.*/HOSTNAME=management.priv.ovirt.org/' /etc/sysconfig/network > +sed -i -e 's/^HOSTNAME.*/HOSTNAME=management.priv.ovirt.org/' \ > + /etc/sysconfig/network > > # make sure to update the /etc/hosts with the list of all possible DHCP > # addresses we can hand out; dnsmasq uses this > @@ -32,31 +33,38 @@ for i in `seq 3 252` ; do > echo "192.168.50.$i node$i.priv.ovirt.org" >> /etc/hosts > done > > +principal=ovirtadmin at PRIV.OVIRT.ORG > +cron_file=/etc/cron.hourly/ovirtadmin.cron > +ktab_file=/usr/share/ovirt-wui/ovirtadmin.tab > + > # automatically refresh the kerberos ticket every hour (we'll create the > # principal on first-boot) > -cat > /etc/cron.hourly/ovirtadmin.cron << \EOF > +cat > $cron_file << EOF > #!/bin/bash > -/usr/kerberos/bin/kdestroy > -/usr/kerberos/bin/kinit -k -t /usr/share/ovirt-wui/ovirtadmin.tab ovirtadmin at PRIV.OVIRT.ORG > +export PATH=/usr/kerberos/bin:$PATH > +kdestroy > +kinit -k -t $ktab_file $principal > EOF > -chmod 755 /etc/cron.hourly/ovirtadmin.cron > +chmod 755 $cron_file > + > +ff_profile_dir=uxssq4qb.ovirtadmin > > # for firefox, we need to make some subdirs and add some preferences > -mkdir -p /root/.mozilla/firefox/uxssq4qb.ovirtadmin > -cat >> /root/.mozilla/firefox/uxssq4qb.ovirtadmin/prefs.js << \EOF > +mkdir -p /root/.mozilla/firefox/$ff_profile_dir > +cat >> /root/.mozilla/firefox/$ff_profile_dir/prefs.js << \EOF > user_pref("network.negotiate-auth.delegation-uris", "priv.ovirt.org"); > user_pref("network.negotiate-auth.trusted-uris", "priv.ovirt.org"); > user_pref("browser.startup.homepage", "http://management.priv.ovirt.org/ovirt"); > EOF > > -cat >> /root/.mozilla/firefox/profiles.ini << \EOF > +cat >> /root/.mozilla/firefox/profiles.ini << EOF > [General] > StartWithLastProfile=1 > > [Profile0] > Name=ovirtadmin > IsRelative=1 > -Path=uxssq4qb.ovirtadmin > +Path=$ff_profile_dir > EOF > > # make sure we don't mount the "fake" iSCSI LUNs, since they are meant to > @@ -79,7 +87,7 @@ EOF > chmod +x /etc/dhclient-exit-hooks > > # make sure that we get a kerberos principal on every boot > -echo "/etc/cron.hourly/ovirtadmin.cron" >> /etc/rc.d/rc.local > +echo "$cron_file" >> /etc/rc.d/rc.local > > # make collectd.conf. > cat > /etc/collectd.conf << \EOF > @@ -105,7 +113,11 @@ LoadPlugin rrdtool > EOF > > > -cat > /etc/init.d/ovirt-wui-dev-first-run << \EOF > +first_run_file=/etc/init.d/ovirt-wui-dev-first-run > +sed -e "s, at cron_file@,$cron_file," \ > + -e "s, at principal@,$principal," \ > + -e "s, at ktab_file@,$ktab_file," \ > + > $first_run_file << \EOF > #!/bin/bash > # > # ovirt-wui-dev-first-run First run configuration for Ovirt WUI Dev appliance > @@ -123,12 +135,13 @@ start() { > echo -n "Starting ovirt-dev-wui-first-run: " > ( > # set up freeipa > - /usr/sbin/ipa-server-install -r PRIV.OVIRT.ORG -p ovirt -P ovirt -a ovirtwui --hostname management.priv.ovirt.org -u dirsrv -U > + ipa-server-install -r PRIV.OVIRT.ORG -p ovirt -P ovirt -a ovirtwui \ > + --hostname management.priv.ovirt.org -u dirsrv -U > > # now create the ovirtadmin user > - $KADMIN -q 'addprinc -randkey ovirtadmin at PRIV.OVIRT.ORG' > - $KADMIN -q 'ktadd -k /usr/share/ovirt-wui/ovirtadmin.tab ovirtadmin at PRIV.OVIRT.ORG' > - /etc/cron.hourly/ovirtadmin.cron > + $KADMIN -q 'addprinc -randkey @principal@' > + $KADMIN -q 'ktadd -k @ktab_file@ @principal@' > + @cron_file@ > > ) > /var/log/ovirt-wui-dev-first-run.log 2>&1 > RETVAL=$? > @@ -149,9 +162,9 @@ case "$1" in > exit 2 > esac > > -/sbin/chkconfig ovirt-wui-dev-first-run off > +chkconfig ovirt-wui-dev-first-run off > EOF > -chmod +x /etc/init.d/ovirt-wui-dev-first-run > +chmod +x $first_run_file > /sbin/chkconfig ovirt-wui-dev-first-run on > > cat > /etc/init.d/ovirt-wui-dev << \EOF > @@ -168,7 +181,7 @@ cat > /etc/init.d/ovirt-wui-dev << \EOF > > start() { > echo -n "Starting ovirt-wui-dev: " > - /usr/sbin/dnsmasq -i eth1 -F 192.168.50.6,192.168.50.252 \ > + dnsmasq -i eth1 -F 192.168.50.6,192.168.50.252 \ > -G 00:16:3e:12:34:57,192.168.50.3 -G 00:16:3e:12:34:58,192.168.50.4 \ > -G 00:16:3e:12:34:59,192.168.50.5 \ > -s priv.ovirt.org \ > @@ -181,23 +194,23 @@ start() { > -R -S 192.168.122.1 > > # Set up the fake iscsi target > - /usr/sbin/tgtadm --lld iscsi --op new --mode target --tid 1 \ > + tgtadm --lld iscsi --op new --mode target --tid 1 \ > -T ovirtpriv:storage > > # > # Now associate them to the LVs > # > - /usr/sbin/tgtadm --lld iscsi --op new --mode logicalunit --tid 1 \ > + tgtadm --lld iscsi --op new --mode logicalunit --tid 1 \ > --lun 1 -b /dev/VolGroup00/iSCSI3 > - /usr/sbin/tgtadm --lld iscsi --op new --mode logicalunit --tid 1 \ > + tgtadm --lld iscsi --op new --mode logicalunit --tid 1 \ > --lun 2 -b /dev/VolGroup00/iSCSI4 > - /usr/sbin/tgtadm --lld iscsi --op new --mode logicalunit --tid 1 \ > + tgtadm --lld iscsi --op new --mode logicalunit --tid 1 \ > --lun 3 -b /dev/VolGroup00/iSCSI5 > - > + > # > # Now make them available > # > - /usr/sbin/tgtadm --lld iscsi --op bind --mode target --tid 1 -I ALL > + tgtadm --lld iscsi --op bind --mode target --tid 1 -I ALL > > echo_success > echo > @@ -207,15 +220,15 @@ stop() { > echo -n "Stopping ovirt-wui-dev: " > > # stop access to the iscsi target > - /usr/sbin/tgtadm --lld iscsi --op unbind --mode target --tid 1 -I ALL > + tgtadm --lld iscsi --op unbind --mode target --tid 1 -I ALL > > # unbind the LUNs > - /usr/sbin/tgtadm --lld iscsi --op delete --mode logicalunit --tid 1 --lun 3 > - /usr/sbin/tgtadm --lld iscsi --op delete --mode logicalunit --tid 1 --lun 2 > - /usr/sbin/tgtadm --lld iscsi --op delete --mode logicalunit --tid 1 --lun 1 > + tgtadm --lld iscsi --op delete --mode logicalunit --tid 1 --lun 3 > + tgtadm --lld iscsi --op delete --mode logicalunit --tid 1 --lun 2 > + tgtadm --lld iscsi --op delete --mode logicalunit --tid 1 --lun 1 > > # shutdown the target > - /usr/sbin/tgtadm --lld iscsi --op delete --mode target --tid 1 > + tgtadm --lld iscsi --op delete --mode target --tid 1 > > kill $(cat /var/run/dnsmasq.pid) > > -- > 1.5.5.1.126.g02179 > > > >From 7d6e35a711f104482dc9939fa0ba2936153947f3 Mon Sep 17 00:00:00 2001 > Date: Fri, 11 Apr 2008 19:14:20 +0200 > Subject: [PATCH] * ovirt-host-creator/common-post.ks: Add explicit PATH= setting, ... > > so it's obviously ok to remove all absolute path prefixes. > * wui-appliance/common-post.ks: Likewise. > > Signed-off-by: Jim Meyering > --- > ovirt-host-creator/common-post.ks | 6 ++++-- > wui-appliance/common-post.ks | 9 ++++++--- > wui-appliance/wui-devel-x86_64.ks | 4 ++-- > 3 files changed, 12 insertions(+), 7 deletions(-) > > diff --git a/ovirt-host-creator/common-post.ks b/ovirt-host-creator/common-post.ks > index 64fe0ee..17291b4 100644 > --- a/ovirt-host-creator/common-post.ks > +++ b/ovirt-host-creator/common-post.ks > @@ -1,4 +1,6 @@ > echo "Starting Kickstart Post" > +PATH=/sbin:/usr/sbin:/bin:/usr/bin > +export PATH > > echo "Setting up Networking" > cat > /etc/sysconfig/iptables << \EOF > @@ -183,7 +185,7 @@ esac > EOF > > chmod +x /etc/init.d/ovirt > -/sbin/chkconfig ovirt on > +chkconfig ovirt on > > echo "Setting up libvirt interfaces" > # make libvirtd listen on the external interfaces > @@ -278,7 +280,7 @@ echo "Re-creating cracklib dicts" > # checking on the ovirt host > # unfortunately we can't create an empty cracklib dict, so we create it > # with a single entry "1" > -echo 1 | /usr/sbin/packer >& /dev/null > +echo 1 | packer >& /dev/null > > echo "Forcing C locale" > # force logins (via ssh, etc) to use C locale, since we remove locales > diff --git a/wui-appliance/common-post.ks b/wui-appliance/common-post.ks > index 3bd6b4d..3dee5bb 100644 > --- a/wui-appliance/common-post.ks > +++ b/wui-appliance/common-post.ks > @@ -1,3 +1,6 @@ > +PATH=/sbin:/usr/sbin:/bin:/usr/bin > +export PATH > + > # pretty login screen.. > g=$(printf '\33[1m\33[32m') # similar to g=$(tput bold; tput setaf 2) > n=$(printf '\33[m') # similar to n=$(tput sgr0) > @@ -34,7 +37,7 @@ cat > /etc/init.d/ovirt-wui-first-run << \EOF > start() { > echo -n "Starting ovirt-wui-first-run: " > > - /usr/bin/ovirt-wui-install > /var/log/ovirt-wui-first-run.log 2>&1 > + ovirt-wui-install > /var/log/ovirt-wui-first-run.log 2>&1 > > RETVAL=$? > if [ $RETVAL -eq 0 ]; then > @@ -54,10 +57,10 @@ case "$1" in > exit 2 > esac > > -/sbin/chkconfig ovirt-wui-first-run off > +chkconfig ovirt-wui-first-run off > EOF > chmod +x /etc/init.d/ovirt-wui-first-run > -/sbin/chkconfig ovirt-wui-first-run on > +chkconfig ovirt-wui-first-run on > > cat > /etc/yum.repos.d/ovirt-management.repo << \EOF > [ovirt-management] > diff --git a/wui-appliance/wui-devel-x86_64.ks b/wui-appliance/wui-devel-x86_64.ks > index f28ed27..67172ba 100644 > --- a/wui-appliance/wui-devel-x86_64.ks > +++ b/wui-appliance/wui-devel-x86_64.ks > @@ -165,7 +165,7 @@ esac > chkconfig ovirt-wui-dev-first-run off > EOF > chmod +x $first_run_file > -/sbin/chkconfig ovirt-wui-dev-first-run on > +chkconfig ovirt-wui-dev-first-run on > > cat > /etc/init.d/ovirt-wui-dev << \EOF > #!/bin/bash > @@ -253,7 +253,7 @@ case "$1" in > esac > EOF > chmod +x /etc/init.d/ovirt-wui-dev > -/sbin/chkconfig ovirt-wui-dev on > +chkconfig ovirt-wui-dev on > > # get the PXE boot image; this can take a while > PXE_URL=http://ovirt.org/download > -- > 1.5.5.1.126.g02179 ACK. If no one else has objections, I say go ahead and commit. Thanks, Jim. --Hugh From hbrock at redhat.com Mon May 5 19:42:05 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Mon, 5 May 2008 15:42:05 -0400 Subject: [Ovirt-devel] [PATCH] wrappers for taskomatic.rb and host-status.rb In-Reply-To: <769584de0805021041g370ac7a3yd6ec0d24bdbe02a1@mail.gmail.com> References: <769584de0805011537h22491b71qeccca30360e6b52c@mail.gmail.com> <20080501225638.GB21047@redhat.com> <20080501230957.GQ23162@redhat.com> <769584de0805021041g370ac7a3yd6ec0d24bdbe02a1@mail.gmail.com> Message-ID: <20080505194205.GC16435@redhat.com> On Fri, May 02, 2008 at 12:41:02PM -0500, steve linabery wrote: > > Hi Hugh and ovirt, > > Well, it turns out it is even simpler than that. All I really needed > to do was look at host-keyadd, which cooperates well with daemon & > killproc by doing 'include Daemonize' and calling 'daemonize', as > you'll see in the attached patch. > > Patch adjusts taskomatic.rb and host-status.rb accordingly, and now > they play nice with /etc/init.d/ovirt-wui script. > > Good day, > Steve Linabery > diff --git a/wui/src/host-status/host-status.rb b/wui/src/host-status/host-status.rb > index b6672cf..5063197 100755 > --- a/wui/src/host-status/host-status.rb > +++ b/wui/src/host-status/host-status.rb > @@ -24,6 +24,7 @@ require 'rubygems' > require 'libvirt' > require 'optparse' > require 'daemons' > +include Daemonize > > $logfile = '/var/log/ovirt-wui/host-status.log' > > @@ -49,7 +50,7 @@ rescue OptionParser::InvalidOption > end > > if do_daemon > - Daemons.daemonize > + daemonize > STDOUT.reopen $logfile, 'a' > STDERR.reopen STDOUT > end > diff --git a/wui/src/task-omatic/taskomatic.rb b/wui/src/task-omatic/taskomatic.rb > index d74f430..c112909 100755 > --- a/wui/src/task-omatic/taskomatic.rb > +++ b/wui/src/task-omatic/taskomatic.rb > @@ -24,6 +24,7 @@ $: << File.join(File.dirname(__FILE__), ".") > require 'rubygems' > require 'optparse' > require 'daemons' > +include Daemonize > > $logfile = '/var/log/ovirt-wui/taskomatic.log' > > @@ -49,7 +50,7 @@ rescue OptionParser::InvalidOption > end > > if do_daemon > - Daemons.daemonize > + daemonize > STDOUT.reopen $logfile, 'a' > STDERR.reopen STDOUT > end ACK, indeed much nicer. --Hugh From jguiditt at redhat.com Mon May 5 21:30:38 2008 From: jguiditt at redhat.com (Jason Guiditta) Date: Mon, 05 May 2008 17:30:38 -0400 Subject: [Ovirt-devel] [PATCH] Updates to treenav Message-ID: <1210023038.3909.6.camel@localhost.localdomain> * Got the 'You are here' bit working in the tree. As always with both ruby and jquery, this was much simpler than it seemed. The biggest thing we were missing was that we were not passing back an 'expanded' value in the json, which the async.js looks for. That plus a little work to determine properly what params to pass in were the main things. * Merged in some new css from Tim, so it should look much closer to the mockups, though I am not sure what we are doing for the links css-wise, but that is easy enough to fix later. * Still trying to figure out where to put the hook so the animation doesn't happen until the data is received back from the server. I have a pretty good idea, just haven't quite pulled it together yet. In the interim, I cleaned it up so it doesn't show the placeholder, and instead just have it opening w/o the animation. I'll add it back in as soon as I figure out the correct way to do it. -------------- next part -------------- A non-text attachment was scrubbed... Name: tree_update.patch Type: text/x-patch Size: 6259 bytes Desc: not available URL: From apevec at redhat.com Mon May 5 22:02:08 2008 From: apevec at redhat.com (Alan Pevec) Date: Tue, 06 May 2008 00:02:08 +0200 Subject: [Ovirt-devel] obsolete content to remove from ovirt.org website In-Reply-To: <4818D0E7.7080104@redhat.com> References: <4818D0E7.7080104@redhat.com> Message-ID: <481F83E0.5030907@redhat.com> Alan Pevec wrote: > Proposed removal list, please review: done, obsolete files are for now moved to .attic/ folders, in case s/b still needs them: http://ovirt.org/download/.attic/ http://ovirt.org/repos/ovirt-management-repo/.attic/ From sseago at redhat.com Tue May 6 04:11:29 2008 From: sseago at redhat.com (Scott Seago) Date: Tue, 06 May 2008 00:11:29 -0400 Subject: [Ovirt-devel] [PATCH] Updates to treenav In-Reply-To: <1210023038.3909.6.camel@localhost.localdomain> References: <1210023038.3909.6.camel@localhost.localdomain> Message-ID: <481FDA71.7060409@redhat.com> Jason Guiditta wrote: > * Got the 'You are here' bit working in the tree. As always with both > ruby and jquery, this was much simpler than it seemed. The biggest > thing we were missing was that we were not passing back an 'expanded' > value in the json, which the async.js looks for. That plus a little > work to determine properly what params to pass in were the main things. > * Merged in some new css from Tim, so it should look much closer to the > mockups, though I am not sure what we are doing for the links css-wise, > but that is easy enough to fix later. > * Still trying to figure out where to put the hook so the animation > doesn't happen until the data is received back from the server. I have > a pretty good idea, just haven't quite pulled it together yet. In the > interim, I cleaned it up so it doesn't show the placeholder, and instead > just have it opening w/o the animation. I'll add it back in as soon as > I figure out the correct way to do it. > Looks fine to me ACK Scott From mmorsi at redhat.com Tue May 6 15:04:37 2008 From: mmorsi at redhat.com (Mohammed Morsi) Date: Tue, 06 May 2008 11:04:37 -0400 Subject: [Ovirt-devel] [patch] oVirt WUI Tests Message-ID: <48207385.9070103@redhat.com> This patch includes * a complete set of test fixtures, all valid with the current application * many, many changes to the functional tests, these all work now (and since the unit tests aren't in place yet, 'rake test' now yields no errors) * changes to the controllers tested by the functional tests, to fix small things up (a lot of controllers were still referring to their "list" methods which don't exist) * initial autobuild.sh script which just runs the test suite * initial setup for the unit tests, none of them are done yet, but I have a strategy of how to approach this, when I start working on the test system again (whenever that will be) Enjoy! Mo -------------- next part -------------- A non-text attachment was scrubbed... Name: initialtests.patch Type: text/x-patch Size: 46795 bytes Desc: not available URL: From hbrock at redhat.com Tue May 6 15:56:15 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Tue, 6 May 2008 11:56:15 -0400 Subject: [Ovirt-devel] [PATCH] wrappers for taskomatic.rb and host-status.rb In-Reply-To: <769584de0805021041g370ac7a3yd6ec0d24bdbe02a1@mail.gmail.com> References: <769584de0805011537h22491b71qeccca30360e6b52c@mail.gmail.com> <20080501225638.GB21047@redhat.com> <20080501230957.GQ23162@redhat.com> <769584de0805021041g370ac7a3yd6ec0d24bdbe02a1@mail.gmail.com> Message-ID: <20080506155615.GF16435@redhat.com> On Fri, May 02, 2008 at 12:41:02PM -0500, steve linabery wrote: > > Hi Hugh and ovirt, > > Well, it turns out it is even simpler than that. All I really needed > to do was look at host-keyadd, which cooperates well with daemon & > killproc by doing 'include Daemonize' and calling 'daemonize', as > you'll see in the attached patch. > > Patch adjusts taskomatic.rb and host-status.rb accordingly, and now > they play nice with /etc/init.d/ovirt-wui script. > > Good day, > Steve Linabery > diff --git a/wui/src/host-status/host-status.rb b/wui/src/host-status/host-status.rb > index b6672cf..5063197 100755 > --- a/wui/src/host-status/host-status.rb > +++ b/wui/src/host-status/host-status.rb > @@ -24,6 +24,7 @@ require 'rubygems' > require 'libvirt' > require 'optparse' > require 'daemons' > +include Daemonize > > $logfile = '/var/log/ovirt-wui/host-status.log' > > @@ -49,7 +50,7 @@ rescue OptionParser::InvalidOption > end > > if do_daemon > - Daemons.daemonize > + daemonize > STDOUT.reopen $logfile, 'a' > STDERR.reopen STDOUT > end > diff --git a/wui/src/task-omatic/taskomatic.rb b/wui/src/task-omatic/taskomatic.rb > index d74f430..c112909 100755 > --- a/wui/src/task-omatic/taskomatic.rb > +++ b/wui/src/task-omatic/taskomatic.rb > @@ -24,6 +24,7 @@ $: << File.join(File.dirname(__FILE__), ".") > require 'rubygems' > require 'optparse' > require 'daemons' > +include Daemonize > > $logfile = '/var/log/ovirt-wui/taskomatic.log' > > @@ -49,7 +50,7 @@ rescue OptionParser::InvalidOption > end > > if do_daemon > - Daemons.daemonize > + daemonize > STDOUT.reopen $logfile, 'a' > STDERR.reopen STDOUT > end I have committed this, thanks! --Hugh From mmorsi at redhat.com Tue May 6 19:51:17 2008 From: mmorsi at redhat.com (Mohammed Morsi) Date: Tue, 06 May 2008 15:51:17 -0400 Subject: [Ovirt-devel] [patch] oVirt WUI Tests In-Reply-To: <48207385.9070103@redhat.com> References: <48207385.9070103@redhat.com> Message-ID: <4820B6B5.3040707@redhat.com> Mohammed Morsi wrote: > This patch includes > > * a complete set of test fixtures, all valid with the current application > * many, many changes to the functional tests, these all work now (and > since the unit tests aren't in place yet, 'rake test' now yields no > errors) > * changes to the controllers tested by the functional tests, to fix > small things up (a lot of controllers were still referring to their > "list" methods which don't exist) > * initial autobuild.sh script which just runs the test suite > * initial setup for the unit tests, none of them are done yet, but I > have a strategy of how to approach this, when I start working on the > test system again (whenever that will be) > > Enjoy! > Mo Updated to include Scott's feedback on fixture corrections. -Mo -------------- next part -------------- A non-text attachment was scrubbed... Name: initialtests.patch Type: text/x-patch Size: 46867 bytes Desc: not available URL: From apevec at redhat.com Tue May 6 21:54:11 2008 From: apevec at redhat.com (Alan Pevec) Date: Tue, 06 May 2008 23:54:11 +0200 Subject: [Ovirt-devel] Rebased - [PATCH] get host networking configuration from ovirt server In-Reply-To: <48111901.8010105@redhat.com> References: <48111901.8010105@redhat.com> Message-ID: <4820D383.5010409@redhat.com> commit cddbecff92d0d1af74a281bfd353f9faac89e9c1 Author: Alan Pevec Date: Tue May 6 23:15:41 2008 +0200 get host networking configuration from oVirt server PXE-boot interface[1] is temporarily setup early in the boot sequence (init.d/ovirt-early) and configuration[2] is retrieved from oVirt server. hostname is put in the requested URL to allow per host configuration, but for now all hosts get the same config: eth0 bridged to ovirtbr0 bridge [1] IPAPPEND 2 in pxelinux config appends MAC of the PXE-booted NIC to the kernel cmdln e.g. BOOTIF=01-00-16-3e-12-34-57 [2] current implementation is a list of augtool commands, see http://augeas.net/tour.html diff --git a/ovirt-host-creator/common-pkgs.ks b/ovirt-host-creator/common-pkgs.ks index 18db4ee..618a73a 100644 --- a/ovirt-host-creator/common-pkgs.ks +++ b/ovirt-host-creator/common-pkgs.ks @@ -22,6 +22,7 @@ cyrus-sasl-lib collectd collectd-virt tftp +augeas nc bind-utils -policycoreutils diff --git a/ovirt-host-creator/common-post.ks b/ovirt-host-creator/common-post.ks index 17291b4..6c503b4 100644 --- a/ovirt-host-creator/common-post.ks +++ b/ovirt-host-creator/common-post.ks @@ -42,19 +42,60 @@ cat > /etc/init.d/ovirt-early << \EOF # Source functions library . /etc/init.d/functions +. /etc/init.d/ovirt-functions -start() { +configure_from_network() { + DEVICE=$1 + if [ $DEVICE ]; then + echo -n "." + # setup temporary interface to retrieve configuration + echo "network --device $DEVICE --bootproto dhcp" | nash + if [ $? -eq 0 ]; then + echo -n "." + # from network-scripts/ifup-post + IPADDR=$(LANG=C ip -o -4 addr ls dev ${DEVICE} | awk '{ print $4 ; exit }') + eval $(ipcalc --silent --hostname ${IPADDR} ; echo "status=$?") + if [ "$status" = "0" ]; then + hostname $HOSTNAME + # retrieve remote config + find_srv ovirt tcp + echo -n "." + if [ $SRV_HOST -a $SRV_PORT ]; then + curl -s http://$SRV_HOST:$SRV_PORT/ovirt/cfgdb/$(hostname) \ + | augtool > /dev/null 2>&1 + if [ $? -eq 0 ]; then + return + fi + fi + fi + fi + fi + # default oVirt network configuration: + # bridge each ethernet device in the system + ETHDEVS=$(cd /sys/class/net && ls -d eth*) + for eth in $ETHDEVS; do + BRIDGE=ovirtbr`echo $eth | cut -b4-` + printf '%s\n' "DEVICE=$eth" ONBOOT=yes "BRIDGE=$BRIDGE" \ + > /etc/sysconfig/network-scripts/ifcfg-$eth + printf '%s\n' "DEVICE=$BRIDGE" BOOTPROTO=dhcp \ + ONBOOT=yes TYPE=Bridge PEERNTP=yes \ + > /etc/sysconfig/network-scripts/ifcfg-$BRIDGE + done +} - # find all of the ethernet devices in the system - ETHDEVS=$(cd /sys/class/net && ls -d eth*) - for eth in $ETHDEVS; do - BRIDGE=ovirtbr`echo $eth | cut -b4-` - printf '%s\n' "DEVICE=$eth" ONBOOT=yes "BRIDGE=$BRIDGE" \ - > /etc/sysconfig/network-scripts/ifcfg-$eth - printf '%s\n' "DEVICE=$BRIDGE" BOOTPROTO=dhcp \ - ONBOOT=yes TYPE=Bridge PEERNTP=yes \ - > /etc/sysconfig/network-scripts/ifcfg-$BRIDGE +start() { + # find boot interface from cmdline + # IPAPPEND 2 in pxelinux.cfg appends e.g. BOOTIF=01-00-16-3e-12-34-57 + BOOTIF= + for i in $(cat /proc/cmdline); do + case $i in + BOOTIF=*) + BOOTMAC=$(echo $i | cut -d- -f2- | sed 's/-/:/g') + BOOTIF=$(grep -l $BOOTMAC /sys/class/net/eth*/address|rev|cut -d/ -f2|rev) + ;; + esac done + configure_from_network $BOOTIF # find all of the partitions on the system diff --git a/ovirt-host-creator/ovirt-pxe.sh b/ovirt-host-creator/ovirt-pxe.sh index 632ec5d..a586e87 100755 --- a/ovirt-host-creator/ovirt-pxe.sh +++ b/ovirt-host-creator/ovirt-pxe.sh @@ -31,3 +31,11 @@ fi ISO=`create_iso $ISO` || exit 1 livecd-iso-to-pxeboot $ISO + +# append BOOTIF with PXE MAC info +grep -q 'IPAPPEND 2' tftpboot/pxelinux.cfg/default +found=$? +if [ $found -ne 0 ]; then + sed -i -e '/KERNEL/a \ \tIPAPPEND 2' tftpboot/pxelinux.cfg/default +fi + diff --git a/wui-appliance/common-post.ks b/wui-appliance/common-post.ks index 3dee5bb..67a885b 100644 --- a/wui-appliance/common-post.ks +++ b/wui-appliance/common-post.ks @@ -69,3 +69,19 @@ baseurl=http://ovirt.et.redhat.com/repos/ovirt-management-repo/$basearch/ enabled=1 gpgcheck=0 EOF + +# XXX default configuration db +cat > /var/www/html/ovirt-cfgdb << \EOF +rm /files/etc/sysconfig/network-scripts/ifcfg-eth0 +set /files/etc/sysconfig/network-scripts/ifcfg-eth0/DEVICE eth0 +set /files/etc/sysconfig/network-scripts/ifcfg-eth0/ONBOOT yes +set /files/etc/sysconfig/network-scripts/ifcfg-eth0/BRIDGE ovirtbr0 +rm /files/etc/sysconfig/network-scripts/ifcfg-ovirtbr0 +set /files/etc/sysconfig/network-scripts/ifcfg-ovirtbr0/DEVICE ovirtbr0 +set /files/etc/sysconfig/network-scripts/ifcfg-ovirtbr0/BOOTPROTO dhcp +set /files/etc/sysconfig/network-scripts/ifcfg-ovirtbr0/ONBOOT y +set /files/etc/sysconfig/network-scripts/ifcfg-ovirtbr0/TYPE Bridge +set /files/etc/sysconfig/network-scripts/ifcfg-ovirtbr0/PEERNTP yes +save +EOF + diff --git a/wui/conf/ovirt-wui.conf b/wui/conf/ovirt-wui.conf index 3e7115a..022e6e4 100644 --- a/wui/conf/ovirt-wui.conf +++ b/wui/conf/ovirt-wui.conf @@ -46,4 +46,6 @@ ProxyPassReverse /ovirt/images ! ProxyPassReverse /ovirt/stylesheets ! ProxyPassReverse /ovirt/errors ! +# XXX default configuration db, all hosts get the same config +RewriteRule ^/ovirt/cfgdb /var/www/html/ovirt-cfgdb From bogus@does.not.exist.com Mon May 5 19:07:53 2008 From: bogus@does.not.exist.com () Date: Mon, 05 May 2008 19:07:53 -0000 Subject: [Ovirt-devel] [PATCH] Don't specify absolute names for programs. Message-ID: /etc/init.d/functions ensures that PATH is reasonable: PATH="/sbin:/usr/sbin:/bin:/usr/bin" Signed-off-by: Jim Meyering --- ovirt-host-creator/common-post.ks | 20 ++++++++++---------- ovirt-host-creator/ovirt-common.sh | 7 +++++-- ovirt-host-creator/ovirt-flash-static.sh | 4 ++-- ovirt-host-creator/ovirt-flash.sh | 6 +++--- ovirt-host-creator/ovirt-pxe.sh | 3 +-- 5 files changed, 21 insertions(+), 19 deletions(-) diff --git a/ovirt-host-creator/common-post.ks b/ovirt-host-creator/common-post.ks index 18ab8d8..64fe0ee 100644 --- a/ovirt-host-creator/common-post.ks +++ b/ovirt-host-creator/common-post.ks @@ -63,11 +63,11 @@ start() { BLOCKDEVS=`ls /dev/sd? /dev/hd? 2>/dev/null` # now LVM partitions - LVMDEVS="$DEVICES `/usr/sbin/lvscan | awk '{print $2}' | tr -d \"'\"`" + LVMDEVS="$DEVICES `lvscan | awk '{print $2}' | tr -d \"'\"`" SWAPDEVS="$LVMDEVS" for dev in $BLOCKDEVS; do - SWAPDEVS="$SWAPDEVS `/sbin/fdisk -l $dev 2>/dev/null | tr '*' ' ' \ + SWAPDEVS="$SWAPDEVS `fdisk -l $dev 2>/dev/null | tr '*' ' ' \ | awk '$5 ~ /82/ {print $1}'`" done @@ -76,7 +76,7 @@ start() { sig=`dd if=$device bs=1 count=10 skip=$(( $PAGESIZE - 10 )) \ 2>/dev/null` if [ "$sig" = "SWAPSPACE2" ]; then - /sbin/swapon $device + swapon $device fi done } @@ -92,7 +92,7 @@ esac EOF chmod +x /etc/init.d/ovirt-early -/sbin/chkconfig ovirt-early on +chkconfig ovirt-early on # just to get a boot warning to shut up touch /etc/resolv.conf @@ -131,7 +131,7 @@ start() { # then give up tries=0 while [ "$VAL" != "SUCCESS" -a $tries -lt 5 ]; do - VAL=`echo "KERB" | /usr/bin/nc $SRV_HOST 6666` + VAL=`echo "KERB" | nc $SRV_HOST 6666` if [ "$VAL" == "SUCCESS" ]; then break fi @@ -193,9 +193,9 @@ echo "Setting up bridged networking" cat > /etc/kvm-ifup << \EOF #!/bin/sh -switch=$(/sbin/ip route list | awk '/^default / { print $NF }') -/sbin/ifconfig $1 0.0.0.0 up -/usr/sbin/brctl addif ${switch} $1 +switch=$(ip route list | awk '/^default / { print $NF }') +ifconfig $1 0.0.0.0 up +brctl addif ${switch} $1 EOF chmod +x /etc/kvm-ifup @@ -270,8 +270,8 @@ rm -f /etc/krb5.conf echo "Creating shadow files" # because we aren't installing authconfig, we aren't setting up shadow # and gshadow properly. Do it by hand here -/usr/sbin/pwconv -/usr/sbin/grpconv +pwconv +grpconv echo "Re-creating cracklib dicts" # cracklib-dicts is 8MB. We probably don't need to have strict password diff --git a/ovirt-host-creator/ovirt-common.sh b/ovirt-host-creator/ovirt-common.sh index 2ada16e..1680a2c 100644 --- a/ovirt-host-creator/ovirt-common.sh +++ b/ovirt-host-creator/ovirt-common.sh @@ -1,11 +1,14 @@ +PATH=/sbin:/bin:/usr/bin +export PATH + create_iso() { KICKSTART=ovirt-`uname -i`.ks if [ $# -eq 0 ]; then LABEL=ovirt-`date +%Y%m%d%H%M` - /usr/bin/livecd-creator --skip-minimize -c $KICKSTART -f $LABEL 1>&2 && + livecd-creator --skip-minimize -c $KICKSTART -f $LABEL 1>&2 && echo $LABEL.iso elif [ $# -eq 1 ]; then - /usr/bin/livecd-creator --skip-minimize -c $KICKSTART -b $1 1>&2 && + livecd-creator --skip-minimize -c $KICKSTART -b $1 1>&2 && echo $1 else return 1 diff --git a/ovirt-host-creator/ovirt-flash-static.sh b/ovirt-host-creator/ovirt-flash-static.sh index f31fc02..12e3d14 100755 --- a/ovirt-host-creator/ovirt-flash-static.sh +++ b/ovirt-host-creator/ovirt-flash-static.sh @@ -47,7 +47,7 @@ mount -o loop $IMGTMP/LiveOS/squashfs.img $SQUASHTMP # clear out the old partition table dd if=/dev/zero of=$USBDEVICE bs=4096 count=1 -echo -e 'n\np\n1\n\n\nt\n83\na\n1\nw\n' | /sbin/fdisk $USBDEVICE +printf 'n\np\n1\n\n\nt\n83\na\n1\nw\n' | fdisk $USBDEVICE cat /usr/lib/syslinux/mbr.bin > $USBDEVICE dd if=$SQUASHTMP/LiveOS/ext3fs.img of=${USBDEVICE}1 @@ -62,7 +62,7 @@ mv $USBTMP/isolinux.cfg $USBTMP/extlinux.conf LABEL=`echo $ISO | cut -d'.' -f1 | cut -c-16` sed -i -e "s/ *append.*/ append initrd=initrd.img root=LABEL=$LABEL ro/" $USBTMP/extlinux.conf -/sbin/extlinux -i $USBTMP +extlinux -i $USBTMP umount $USBTMP umount $SQUASHTMP diff --git a/ovirt-host-creator/ovirt-flash.sh b/ovirt-host-creator/ovirt-flash.sh index bb0ca45..621972c 100755 --- a/ovirt-host-creator/ovirt-flash.sh +++ b/ovirt-host-creator/ovirt-flash.sh @@ -39,7 +39,7 @@ ISO=`create_iso $ISO` || exit 1 # clear out the old partition table dd if=/dev/zero of=$USBDEVICE bs=4096 count=1 -echo -e 'n\np\n1\n\n\nt\n6\na\n1\nw\n' | /sbin/fdisk $USBDEVICE -/sbin/mkdosfs -n ovirt ${USBDEVICE}1 +printf 'n\np\n1\n\n\nt\n6\na\n1\nw\n' | fdisk $USBDEVICE +mkdosfs -n ovirt ${USBDEVICE}1 cat /usr/lib/syslinux/mbr.bin > $USBDEVICE -/usr/bin/livecd-iso-to-disk $ISO ${USBDEVICE}1 +livecd-iso-to-disk $ISO ${USBDEVICE}1 diff --git a/ovirt-host-creator/ovirt-pxe.sh b/ovirt-host-creator/ovirt-pxe.sh index 1581e15..632ec5d 100755 --- a/ovirt-host-creator/ovirt-pxe.sh +++ b/ovirt-host-creator/ovirt-pxe.sh @@ -30,5 +30,4 @@ fi ISO=`create_iso $ISO` || exit 1 -/usr/bin/livecd-iso-to-pxeboot $ISO - +livecd-iso-to-pxeboot $ISO -- 1.5.5.1.126.g02179 From bogus@does.not.exist.com Mon May 5 19:07:53 2008 From: bogus@does.not.exist.com () Date: Mon, 05 May 2008 19:07:53 -0000 Subject: [Ovirt-devel] [PATCH] remove abs names, split long lines, factor out some duplication Message-ID: Signed-off-by: Jim Meyering --- wui-appliance/wui-devel-x86_64.ks | 71 ++++++++++++++++++++++--------------- 1 files changed, 42 insertions(+), 29 deletions(-) diff --git a/wui-appliance/wui-devel-x86_64.ks b/wui-appliance/wui-devel-x86_64.ks index c7ccdd7..f28ed27 100644 --- a/wui-appliance/wui-devel-x86_64.ks +++ b/wui-appliance/wui-devel-x86_64.ks @@ -23,7 +23,8 @@ repo --name=ovirt-management --baseurl=http://ovirt.et.redhat.com/repos/ovirt-ma %include common-post.ks # make sure our "hostname" resolves to management.priv.ovirt.org -sed -i -e 's/^HOSTNAME.*/HOSTNAME=management.priv.ovirt.org/' /etc/sysconfig/network +sed -i -e 's/^HOSTNAME.*/HOSTNAME=management.priv.ovirt.org/' \ + /etc/sysconfig/network # make sure to update the /etc/hosts with the list of all possible DHCP # addresses we can hand out; dnsmasq uses this @@ -32,31 +33,38 @@ for i in `seq 3 252` ; do echo "192.168.50.$i node$i.priv.ovirt.org" >> /etc/hosts done +principal=ovirtadmin at PRIV.OVIRT.ORG +cron_file=/etc/cron.hourly/ovirtadmin.cron +ktab_file=/usr/share/ovirt-wui/ovirtadmin.tab + # automatically refresh the kerberos ticket every hour (we'll create the # principal on first-boot) -cat > /etc/cron.hourly/ovirtadmin.cron << \EOF +cat > $cron_file << EOF #!/bin/bash -/usr/kerberos/bin/kdestroy -/usr/kerberos/bin/kinit -k -t /usr/share/ovirt-wui/ovirtadmin.tab ovirtadmin at PRIV.OVIRT.ORG +export PATH=/usr/kerberos/bin:$PATH +kdestroy +kinit -k -t $ktab_file $principal EOF -chmod 755 /etc/cron.hourly/ovirtadmin.cron +chmod 755 $cron_file + +ff_profile_dir=uxssq4qb.ovirtadmin # for firefox, we need to make some subdirs and add some preferences -mkdir -p /root/.mozilla/firefox/uxssq4qb.ovirtadmin -cat >> /root/.mozilla/firefox/uxssq4qb.ovirtadmin/prefs.js << \EOF +mkdir -p /root/.mozilla/firefox/$ff_profile_dir +cat >> /root/.mozilla/firefox/$ff_profile_dir/prefs.js << \EOF user_pref("network.negotiate-auth.delegation-uris", "priv.ovirt.org"); user_pref("network.negotiate-auth.trusted-uris", "priv.ovirt.org"); user_pref("browser.startup.homepage", "http://management.priv.ovirt.org/ovirt"); EOF -cat >> /root/.mozilla/firefox/profiles.ini << \EOF +cat >> /root/.mozilla/firefox/profiles.ini << EOF [General] StartWithLastProfile=1 [Profile0] Name=ovirtadmin IsRelative=1 -Path=uxssq4qb.ovirtadmin +Path=$ff_profile_dir EOF # make sure we don't mount the "fake" iSCSI LUNs, since they are meant to @@ -79,7 +87,7 @@ EOF chmod +x /etc/dhclient-exit-hooks # make sure that we get a kerberos principal on every boot -echo "/etc/cron.hourly/ovirtadmin.cron" >> /etc/rc.d/rc.local +echo "$cron_file" >> /etc/rc.d/rc.local # make collectd.conf. cat > /etc/collectd.conf << \EOF @@ -105,7 +113,11 @@ LoadPlugin rrdtool EOF -cat > /etc/init.d/ovirt-wui-dev-first-run << \EOF +first_run_file=/etc/init.d/ovirt-wui-dev-first-run +sed -e "s, at cron_file@,$cron_file," \ + -e "s, at principal@,$principal," \ + -e "s, at ktab_file@,$ktab_file," \ + > $first_run_file << \EOF #!/bin/bash # # ovirt-wui-dev-first-run First run configuration for Ovirt WUI Dev appliance @@ -123,12 +135,13 @@ start() { echo -n "Starting ovirt-dev-wui-first-run: " ( # set up freeipa - /usr/sbin/ipa-server-install -r PRIV.OVIRT.ORG -p ovirt -P ovirt -a ovirtwui --hostname management.priv.ovirt.org -u dirsrv -U + ipa-server-install -r PRIV.OVIRT.ORG -p ovirt -P ovirt -a ovirtwui \ + --hostname management.priv.ovirt.org -u dirsrv -U # now create the ovirtadmin user - $KADMIN -q 'addprinc -randkey ovirtadmin at PRIV.OVIRT.ORG' - $KADMIN -q 'ktadd -k /usr/share/ovirt-wui/ovirtadmin.tab ovirtadmin at PRIV.OVIRT.ORG' - /etc/cron.hourly/ovirtadmin.cron + $KADMIN -q 'addprinc -randkey @principal@' + $KADMIN -q 'ktadd -k @ktab_file@ @principal@' + @cron_file@ ) > /var/log/ovirt-wui-dev-first-run.log 2>&1 RETVAL=$? @@ -149,9 +162,9 @@ case "$1" in exit 2 esac -/sbin/chkconfig ovirt-wui-dev-first-run off +chkconfig ovirt-wui-dev-first-run off EOF -chmod +x /etc/init.d/ovirt-wui-dev-first-run +chmod +x $first_run_file /sbin/chkconfig ovirt-wui-dev-first-run on cat > /etc/init.d/ovirt-wui-dev << \EOF @@ -168,7 +181,7 @@ cat > /etc/init.d/ovirt-wui-dev << \EOF start() { echo -n "Starting ovirt-wui-dev: " - /usr/sbin/dnsmasq -i eth1 -F 192.168.50.6,192.168.50.252 \ + dnsmasq -i eth1 -F 192.168.50.6,192.168.50.252 \ -G 00:16:3e:12:34:57,192.168.50.3 -G 00:16:3e:12:34:58,192.168.50.4 \ -G 00:16:3e:12:34:59,192.168.50.5 \ -s priv.ovirt.org \ @@ -181,23 +194,23 @@ start() { -R -S 192.168.122.1 # Set up the fake iscsi target - /usr/sbin/tgtadm --lld iscsi --op new --mode target --tid 1 \ + tgtadm --lld iscsi --op new --mode target --tid 1 \ -T ovirtpriv:storage # # Now associate them to the LVs # - /usr/sbin/tgtadm --lld iscsi --op new --mode logicalunit --tid 1 \ + tgtadm --lld iscsi --op new --mode logicalunit --tid 1 \ --lun 1 -b /dev/VolGroup00/iSCSI3 - /usr/sbin/tgtadm --lld iscsi --op new --mode logicalunit --tid 1 \ + tgtadm --lld iscsi --op new --mode logicalunit --tid 1 \ --lun 2 -b /dev/VolGroup00/iSCSI4 - /usr/sbin/tgtadm --lld iscsi --op new --mode logicalunit --tid 1 \ + tgtadm --lld iscsi --op new --mode logicalunit --tid 1 \ --lun 3 -b /dev/VolGroup00/iSCSI5 - + # # Now make them available # - /usr/sbin/tgtadm --lld iscsi --op bind --mode target --tid 1 -I ALL + tgtadm --lld iscsi --op bind --mode target --tid 1 -I ALL echo_success echo @@ -207,15 +220,15 @@ stop() { echo -n "Stopping ovirt-wui-dev: " # stop access to the iscsi target - /usr/sbin/tgtadm --lld iscsi --op unbind --mode target --tid 1 -I ALL + tgtadm --lld iscsi --op unbind --mode target --tid 1 -I ALL # unbind the LUNs - /usr/sbin/tgtadm --lld iscsi --op delete --mode logicalunit --tid 1 --lun 3 - /usr/sbin/tgtadm --lld iscsi --op delete --mode logicalunit --tid 1 --lun 2 - /usr/sbin/tgtadm --lld iscsi --op delete --mode logicalunit --tid 1 --lun 1 + tgtadm --lld iscsi --op delete --mode logicalunit --tid 1 --lun 3 + tgtadm --lld iscsi --op delete --mode logicalunit --tid 1 --lun 2 + tgtadm --lld iscsi --op delete --mode logicalunit --tid 1 --lun 1 # shutdown the target - /usr/sbin/tgtadm --lld iscsi --op delete --mode target --tid 1 + tgtadm --lld iscsi --op delete --mode target --tid 1 kill $(cat /var/run/dnsmasq.pid) -- 1.5.5.1.126.g02179 From bogus@does.not.exist.com Mon May 5 19:07:53 2008 From: bogus@does.not.exist.com () Date: Mon, 05 May 2008 19:07:53 -0000 Subject: [Ovirt-devel] [PATCH] * ovirt-host-creator/common-post.ks: Add explicit PATH= setting, ... Message-ID: so it's obviously ok to remove all absolute path prefixes. * wui-appliance/common-post.ks: Likewise. Signed-off-by: Jim Meyering --- ovirt-host-creator/common-post.ks | 6 ++++-- wui-appliance/common-post.ks | 9 ++++++--- wui-appliance/wui-devel-x86_64.ks | 4 ++-- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/ovirt-host-creator/common-post.ks b/ovirt-host-creator/common-post.ks index 64fe0ee..17291b4 100644 --- a/ovirt-host-creator/common-post.ks +++ b/ovirt-host-creator/common-post.ks @@ -1,4 +1,6 @@ echo "Starting Kickstart Post" +PATH=/sbin:/usr/sbin:/bin:/usr/bin +export PATH echo "Setting up Networking" cat > /etc/sysconfig/iptables << \EOF @@ -183,7 +185,7 @@ esac EOF chmod +x /etc/init.d/ovirt -/sbin/chkconfig ovirt on +chkconfig ovirt on echo "Setting up libvirt interfaces" # make libvirtd listen on the external interfaces @@ -278,7 +280,7 @@ echo "Re-creating cracklib dicts" # checking on the ovirt host # unfortunately we can't create an empty cracklib dict, so we create it # with a single entry "1" -echo 1 | /usr/sbin/packer >& /dev/null +echo 1 | packer >& /dev/null echo "Forcing C locale" # force logins (via ssh, etc) to use C locale, since we remove locales diff --git a/wui-appliance/common-post.ks b/wui-appliance/common-post.ks index 3bd6b4d..3dee5bb 100644 --- a/wui-appliance/common-post.ks +++ b/wui-appliance/common-post.ks @@ -1,3 +1,6 @@ +PATH=/sbin:/usr/sbin:/bin:/usr/bin +export PATH + # pretty login screen.. g=$(printf '\33[1m\33[32m') # similar to g=$(tput bold; tput setaf 2) n=$(printf '\33[m') # similar to n=$(tput sgr0) @@ -34,7 +37,7 @@ cat > /etc/init.d/ovirt-wui-first-run << \EOF start() { echo -n "Starting ovirt-wui-first-run: " - /usr/bin/ovirt-wui-install > /var/log/ovirt-wui-first-run.log 2>&1 + ovirt-wui-install > /var/log/ovirt-wui-first-run.log 2>&1 RETVAL=$? if [ $RETVAL -eq 0 ]; then @@ -54,10 +57,10 @@ case "$1" in exit 2 esac -/sbin/chkconfig ovirt-wui-first-run off +chkconfig ovirt-wui-first-run off EOF chmod +x /etc/init.d/ovirt-wui-first-run -/sbin/chkconfig ovirt-wui-first-run on +chkconfig ovirt-wui-first-run on cat > /etc/yum.repos.d/ovirt-management.repo << \EOF [ovirt-management] diff --git a/wui-appliance/wui-devel-x86_64.ks b/wui-appliance/wui-devel-x86_64.ks index f28ed27..67172ba 100644 --- a/wui-appliance/wui-devel-x86_64.ks +++ b/wui-appliance/wui-devel-x86_64.ks @@ -165,7 +165,7 @@ esac chkconfig ovirt-wui-dev-first-run off EOF chmod +x $first_run_file -/sbin/chkconfig ovirt-wui-dev-first-run on +chkconfig ovirt-wui-dev-first-run on cat > /etc/init.d/ovirt-wui-dev << \EOF #!/bin/bash @@ -253,7 +253,7 @@ case "$1" in esac EOF chmod +x /etc/init.d/ovirt-wui-dev -/sbin/chkconfig ovirt-wui-dev on +chkconfig ovirt-wui-dev on # get the PXE boot image; this can take a while PXE_URL=http://ovirt.org/download -- 1.5.5.1.126.g02179 From slinabery at gmail.com Wed May 7 20:44:21 2008 From: slinabery at gmail.com (steve linabery) Date: Wed, 7 May 2008 15:44:21 -0500 Subject: [Ovirt-devel] [PATCH] split ovirt-wui into separate scripts Message-ID: <769584de0805071344y39bbae52xc671660f9baae2f8@mail.gmail.com> Hi ovirt, The attached patch attempts to split the ovirt-wui initrd script into 5 separate scripts, one for each ovirt daemon. Bullet points: 0) names scripts ovirt-host-browser, ovirt-host-keyadd, ... , ovirt-taskomatic 1) adds 'status' option for init scripts 2) %post section of rpm spec now removes legacy /etc/init.d/ovirt-wui script if present 3) edited rpm spec to handle 5 scripts instead of one where appropriate 4) added new service names to the ENABLE_SVCS list in the ovirt-wui-install script The new rpm specfile assumes that the install is a fresh install (i.e. it doesn't attempt to deal with any legacy issues from this patch), with the exception of the convenience removal of the previous ovirt-wui script. Thanks for all you do, Steve -------------- next part -------------- A non-text attachment was scrubbed... Name: daemonsplit.patch Type: text/x-patch Size: 10574 bytes Desc: not available URL: From dpierce at redhat.com Wed May 7 21:03:33 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 7 May 2008 17:03:33 -0400 Subject: [Ovirt-devel] [PATCH 4/4] Finished the LDAP connector. In-Reply-To: <1210194213-13382-3-git-send-email-dpierce@redhat.com> References: <1210194213-13382-1-git-send-email-dpierce@redhat.com> <1210194213-13382-2-git-send-email-dpierce@redhat.com> <1210194213-13382-3-git-send-email-dpierce@redhat.com> Message-ID: <1210194213-13382-4-git-send-email-dpierce@redhat.com> --- wui/src/app/helpers/ldap_connection.rb | 17 +++++++++++------ wui/src/config/ldap.yml | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/wui/src/app/helpers/ldap_connection.rb b/wui/src/app/helpers/ldap_connection.rb index 623c02a..af8b41b 100644 --- a/wui/src/app/helpers/ldap_connection.rb +++ b/wui/src/app/helpers/ldap_connection.rb @@ -21,23 +21,28 @@ # connections with an LDAP server. # class LDAPConnection - @@config = YAML.load(File.open("#{RAILS_ROOT}/config/ldap.yml")) - - # Connects the LDAP server. - def LDAPConnection.connect(base,host,port) + + @@config = YAML::load(File.open("#{RAILS_ROOT}/config/ldap.yml")) + + # Connects the specified LDAP server. + def self.connect(base = nil, host = nil, port = nil) + base = @@config[ENV['RAILS_ENV']]["base"] if base == nil + host = @@config[ENV['RAILS_ENV']]["host"] if host == nil + port = @@config[ENV['RAILS_ENV']]["port"] if port == nil + ActiveLdap::Base.establish_connection(:host => host, :port => port, :base => base) if LDAPConnection.connected? == false end # Returns whether a connection already exists to the LDAP server. - def LDAPConnection.connected? + def self.connected? return ActiveLdap::Base.connected? end # Disconnects from the LDAP server. - def LDAPConnection.disconnect + def self.disconnect ActiveLdap::Base.remove_connection if LDAPConnection.connected? end diff --git a/wui/src/config/ldap.yml b/wui/src/config/ldap.yml index c8b167e..5f8383f 100644 --- a/wui/src/config/ldap.yml +++ b/wui/src/config/ldap.yml @@ -1,4 +1,4 @@ development: - hostname: ldap.rdu.redhat.com + host: ldap.rdu.redhat.com port: 389 base: dc=redhat,dc=com -- 1.5.4.1 From dpierce at redhat.com Wed May 7 21:03:31 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 7 May 2008 17:03:31 -0400 Subject: [Ovirt-devel] [PATCH 2/4] A basically working LDAP base is started. In-Reply-To: <1210194213-13382-1-git-send-email-dpierce@redhat.com> References: <1210194213-13382-1-git-send-email-dpierce@redhat.com> Message-ID: <1210194213-13382-2-git-send-email-dpierce@redhat.com> --- wui/src/config/ldap.yml | 4 +++ .../scaffold_active_ldap/templates/ldap.yml | 21 ++++++++++++++++++++ wui/src/vendor/plugins/active_ldap/init.rb | 2 +- 3 files changed, 26 insertions(+), 1 deletions(-) create mode 100644 wui/src/config/ldap.yml create mode 100644 wui/src/vendor/plugins/active_ldap/generators/scaffold_active_ldap/templates/ldap.yml diff --git a/wui/src/config/ldap.yml b/wui/src/config/ldap.yml new file mode 100644 index 0000000..c8b167e --- /dev/null +++ b/wui/src/config/ldap.yml @@ -0,0 +1,4 @@ +development: + hostname: ldap.rdu.redhat.com + port: 389 + base: dc=redhat,dc=com diff --git a/wui/src/vendor/plugins/active_ldap/generators/scaffold_active_ldap/templates/ldap.yml b/wui/src/vendor/plugins/active_ldap/generators/scaffold_active_ldap/templates/ldap.yml new file mode 100644 index 0000000..720ec39 --- /dev/null +++ b/wui/src/vendor/plugins/active_ldap/generators/scaffold_active_ldap/templates/ldap.yml @@ -0,0 +1,21 @@ +development: + host: 127.0.0.1 + port: 389 + base: dc=devel,dc=local,dc=net + bind_dn: cn=admin,dc=local,dc=net + password: secret + +test: + host: 127.0.0.1 + port: 389 + base: dc=test,dc=local,dc=net + bind_dn: cn=admin,dc=local,dc=net + password: secret + +production: + host: 127.0.0.1 + port: 389 + method: :tls + base: dc=production,dc=local,dc=net + bind_dn: cn=admin,dc=local,dc=net + password: secret diff --git a/wui/src/vendor/plugins/active_ldap/init.rb b/wui/src/vendor/plugins/active_ldap/init.rb index 35e19d4..fa1484a 100644 --- a/wui/src/vendor/plugins/active_ldap/init.rb +++ b/wui/src/vendor/plugins/active_ldap/init.rb @@ -1,7 +1,7 @@ require_library_or_gem 'active_ldap' ActiveLdap::Base.logger ||= RAILS_DEFAULT_LOGGER -required_version = ["0", "9", "1"] +required_version = ["0", "10", "0"] if (ActiveLdap::VERSION.split(".") <=> required_version) < 0 ActiveLdap::Base.class_eval do format = _("You need ActiveLdap %s or later") -- 1.5.4.1 From dpierce at redhat.com Wed May 7 21:03:32 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 7 May 2008 17:03:32 -0400 Subject: [Ovirt-devel] [PATCH 3/4] Updated the account class. In-Reply-To: <1210194213-13382-2-git-send-email-dpierce@redhat.com> References: <1210194213-13382-1-git-send-email-dpierce@redhat.com> <1210194213-13382-2-git-send-email-dpierce@redhat.com> Message-ID: <1210194213-13382-3-git-send-email-dpierce@redhat.com> --- wui/src/app/helpers/ldap_connection.rb | 18 ++++++++---------- wui/src/app/models/account.rb | 19 ++++++++++++++++++- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/wui/src/app/helpers/ldap_connection.rb b/wui/src/app/helpers/ldap_connection.rb index 53256fa..623c02a 100644 --- a/wui/src/app/helpers/ldap_connection.rb +++ b/wui/src/app/helpers/ldap_connection.rb @@ -21,16 +21,14 @@ # connections with an LDAP server. # class LDAPConnection - @@hostname = nil - @@port = 389 - + @@config = YAML.load(File.open("#{RAILS_ROOT}/config/ldap.yml")) + # Connects the LDAP server. - def LDAPConnection.connect( - base, - hostname = LDAPConnection.hostname, - port = LDAPConnection.port - ) - ActiveLdap::Base.establish_connection(:host => hostname + def LDAPConnection.connect(base,host,port) + + ActiveLdap::Base.establish_connection(:host => host, + :port => port, + :base => base) if LDAPConnection.connected? == false end # Returns whether a connection already exists to the LDAP server. @@ -39,7 +37,7 @@ class LDAPConnection end # Disconnects from the LDAP server. - def LDAPConnection.disconnected + def LDAPConnection.disconnect ActiveLdap::Base.remove_connection if LDAPConnection.connected? end diff --git a/wui/src/app/models/account.rb b/wui/src/app/models/account.rb index 94c3bb6..2664f18 100644 --- a/wui/src/app/models/account.rb +++ b/wui/src/app/models/account.rb @@ -20,5 +20,22 @@ # +Account+ represents a single user's account from the LDAP server. # class Account < ActiveLdap::Base - ldap_mapping :dn_attribute => 'uid', :classes => ['person', 'posixAccount'] + ldap_mapping :dn_attribute => 'cn', :prefix => 'ou=Users', :scope => :one + + # +query+ returns the set of all accounts that contain the given search value. + # + # This API requires that a previous connection be made using + # +LDAPConnection.connect+. + # + def Account.query(value) + + @users = Account.find(:all, value) + + if block_given? + @users.each { |user| yield(user) } + end + + return @users + + end end -- 1.5.4.1 From dpierce at redhat.com Wed May 7 21:03:30 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 7 May 2008 17:03:30 -0400 Subject: [Ovirt-devel] [PATCH 1/4] Added to enable LDAP support via the ActiveLdap gem. Message-ID: <1210194213-13382-1-git-send-email-dpierce@redhat.com> --- wui/src/app/helpers/ldap_connection.rb | 46 +++++++++++++ wui/src/app/models/account.rb | 24 +++++++ wui/src/vendor/plugins/active_ldap/README | 54 +++++++++++++++ .../active_ldap/generators/model_active_ldap/USAGE | 17 +++++ .../model_active_ldap_generator.rb | 70 ++++++++++++++++++++ .../model_active_ldap/templates/fixtures.yml | 11 +++ .../templates/model_active_ldap.rb | 3 + .../model_active_ldap/templates/unit_test.rb | 10 +++ .../scaffold_active_ldap_generator.rb | 7 ++ .../scaffold_al/scaffold_al_generator.rb | 20 ++++++ wui/src/vendor/plugins/active_ldap/init.rb | 64 ++++++++++++++++++ 11 files changed, 326 insertions(+), 0 deletions(-) create mode 100644 wui/src/app/helpers/ldap_connection.rb create mode 100644 wui/src/app/models/account.rb create mode 100644 wui/src/vendor/plugins/active_ldap/README create mode 100644 wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/USAGE create mode 100644 wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/model_active_ldap_generator.rb create mode 100644 wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/templates/fixtures.yml create mode 100644 wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/templates/model_active_ldap.rb create mode 100644 wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/templates/unit_test.rb create mode 100644 wui/src/vendor/plugins/active_ldap/generators/scaffold_active_ldap/scaffold_active_ldap_generator.rb create mode 100644 wui/src/vendor/plugins/active_ldap/generators/scaffold_al/scaffold_al_generator.rb create mode 100644 wui/src/vendor/plugins/active_ldap/init.rb diff --git a/wui/src/app/helpers/ldap_connection.rb b/wui/src/app/helpers/ldap_connection.rb new file mode 100644 index 0000000..53256fa --- /dev/null +++ b/wui/src/app/helpers/ldap_connection.rb @@ -0,0 +1,46 @@ +# +# Copyright (C) 2008 Red Hat, Inc. +# Written by Darryl L. Pierce +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + +# +LDAPConnection+ handles establishing, returning and closing +# connections with an LDAP server. +# +class LDAPConnection + @@hostname = nil + @@port = 389 + + # Connects the LDAP server. + def LDAPConnection.connect( + base, + hostname = LDAPConnection.hostname, + port = LDAPConnection.port + ) + ActiveLdap::Base.establish_connection(:host => hostname + end + + # Returns whether a connection already exists to the LDAP server. + def LDAPConnection.connected? + return ActiveLdap::Base.connected? + end + + # Disconnects from the LDAP server. + def LDAPConnection.disconnected + ActiveLdap::Base.remove_connection if LDAPConnection.connected? + end + +end diff --git a/wui/src/app/models/account.rb b/wui/src/app/models/account.rb new file mode 100644 index 0000000..94c3bb6 --- /dev/null +++ b/wui/src/app/models/account.rb @@ -0,0 +1,24 @@ +# +# Copyright (C) 2008 Red Hat, Inc. +# Written by Darryl L. Pierce +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + +# +Account+ represents a single user's account from the LDAP server. +# +class Account < ActiveLdap::Base + ldap_mapping :dn_attribute => 'uid', :classes => ['person', 'posixAccount'] +end diff --git a/wui/src/vendor/plugins/active_ldap/README b/wui/src/vendor/plugins/active_ldap/README new file mode 100644 index 0000000..8e40086 --- /dev/null +++ b/wui/src/vendor/plugins/active_ldap/README @@ -0,0 +1,54 @@ += ActiveLdap plugin for Ruby on Rails + +== Setup + +You need to write RAILS_ROOT/config/ldap.yml like the following: + + development: + host: 127.0.0.1 + port: 389 + base: dc=devel,dc=local,dc=net + bind_dn: cn=admin,dc=local,dc=net + password: secret + + test: + host: 127.0.0.1 + port: 389 + base: dc=test,dc=local,dc=net + bind_dn: cn=admin,dc=local,dc=net + password: secret + + production: + host: 127.0.0.1 + port: 389 + base: dc=production,dc=local,dc=net + bind_dn: cn=admin,dc=local,dc=net + password: secret + +== Model + +Here is some examples. + +app/model/member.rb: + class Member < ActiveLdap::Base + ldap_mapping :dn_attribute => 'uid', + :classes => ['person', 'posixAccount'] + belongs_to :primary_group, :class => "Group", + :foreign_key => "gidNumber", :primary_key => "gidNumber" + belongs_to :groups, :many => 'memberUid' + end + +app/model/group.rb: + class Group < ActiveLdap::Base + ldap_mapping :dn_attribute => "cn", :classes => ['posixGroup'] + has_many :members, :wrap => "memberUid" + has_many :primary_members, + :foreign_key => 'gidNumber', + :primary_key => 'gidNumber' + end + +app/model/ou.rb: + class Ou < ActiveLdap::Base + ldap_mapping :prefix => "", + :classes => ["top", "organizationalUnit"] + end diff --git a/wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/USAGE b/wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/USAGE new file mode 100644 index 0000000..a86c5dd --- /dev/null +++ b/wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/USAGE @@ -0,0 +1,17 @@ +Description: + The model_activeldap generator creates stubs for a new model. + + The generator takes a model name as its argument. The model name may be given in CamelCase or under_score and + should not be suffixed with 'Model'. + + The generator creates a model class in app/models, a test suite in test/unit, and test fixtures in + test/fixtures/singular_name.yml. It will not create a migration. + +Examples: + ./script/generate model_activeldap user + + This will create a User model: + Model: app/models/user.rb + Test: test/unit/user_test.rb + Fixtures: test/fixtures/users.yml + diff --git a/wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/model_active_ldap_generator.rb b/wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/model_active_ldap_generator.rb new file mode 100644 index 0000000..f8435a3 --- /dev/null +++ b/wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/model_active_ldap_generator.rb @@ -0,0 +1,70 @@ +class ModelActiveLdapGenerator < Rails::Generator::NamedBase + include ActiveLdap::GetTextSupport + + default_options :dn_attribute => "cn", :classes => nil + + def manifest + record do |m| + # Check for class naming collisions. + m.class_collisions class_path, class_name, "#{class_name}Test" + + # Model, test, and fixture directories. + m.directory File.join('app/models', class_path) + m.directory File.join('test/unit', class_path) + m.directory File.join('test/fixtures', class_path) + + # Model class, unit test, and fixtures. + m.template('model_active_ldap.rb', + File.join('app/models', class_path, "#{file_name}.rb"), + :assigns => {:ldap_mapping => ldap_mapping}) + m.template('unit_test.rb', + File.join('test/unit', class_path, "#{file_name}_test.rb")) + m.template('fixtures.yml', + File.join('test/fixtures', class_path, "#{table_name}.yml")) + end + end + + private + def add_options!(opt) + opt.separator '' + opt.separator 'Options:' + opt.on("--dn-attribute=ATTRIBUTE", + _("Use ATTRIBUTE as default DN attribute for " \ + "instances of this model"), + _("(default: %s)") % options[:dn_attribute]) do |attribute| + options[:dn_attribute] = attribute + end + + opt.on("--prefix=PREFIX", + _("Use PREFIX as prefix for this model"), + _("(default: %s)") % default_prefix) do |prefix| + options[:prefix] = prefix + end + + opt.on("--classes=CLASS,CLASS,...", + Array, + "Use CLASSES as required objectClass for instances of this model", + "(default: %s)" % options[:classes]) do |classes| + options[:classes] = classes + end + end + + def prefix + options[:prefix] || default_prefix + end + + def default_prefix + "ou=#{Inflector.pluralize(Inflector.demodulize(name))}" + end + + def ldap_mapping(indent=' ') + mapping = "ldap_mapping " + mapping_options = [":dn_attribute => #{options[:dn_attribute].dump}"] + mapping_options << ":prefix => #{prefix.dump}" + if options[:classes] + mapping_options << ":classes => #{options[:classes].inspect}" + end + mapping_options = mapping_options.join(",\n#{indent}#{' ' * mapping.size}") + "#{indent}#{mapping}#{mapping_options}" + end +end diff --git a/wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/templates/fixtures.yml b/wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/templates/fixtures.yml new file mode 100644 index 0000000..9f5ae29 --- /dev/null +++ b/wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/templates/fixtures.yml @@ -0,0 +1,11 @@ +# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html +one: + id: 1 +<% for attribute in attributes -%> + <%= attribute.name %>: <%= attribute.default %> +<% end -%> +two: + id: 2 +<% for attribute in attributes -%> + <%= attribute.name %>: <%= attribute.default %> +<% end -%> \ No newline at end of file diff --git a/wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/templates/model_active_ldap.rb b/wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/templates/model_active_ldap.rb new file mode 100644 index 0000000..cdfa66b --- /dev/null +++ b/wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/templates/model_active_ldap.rb @@ -0,0 +1,3 @@ +class <%= class_name %> < ActiveLdap::Base +<%= ldap_mapping %> +end diff --git a/wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/templates/unit_test.rb b/wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/templates/unit_test.rb new file mode 100644 index 0000000..b464de4 --- /dev/null +++ b/wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/templates/unit_test.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../test_helper' + +class <%= class_name %>Test < Test::Unit::TestCase + fixtures :<%= table_name %> + + # Replace this with your real tests. + def test_truth + assert true + end +end diff --git a/wui/src/vendor/plugins/active_ldap/generators/scaffold_active_ldap/scaffold_active_ldap_generator.rb b/wui/src/vendor/plugins/active_ldap/generators/scaffold_active_ldap/scaffold_active_ldap_generator.rb new file mode 100644 index 0000000..35ad937 --- /dev/null +++ b/wui/src/vendor/plugins/active_ldap/generators/scaffold_active_ldap/scaffold_active_ldap_generator.rb @@ -0,0 +1,7 @@ +class ScaffoldActiveLdapGenerator < Rails::Generator::Base + def manifest + record do |m| + m.template("ldap.yml", File.join("config", "ldap.yml")) + end + end +end diff --git a/wui/src/vendor/plugins/active_ldap/generators/scaffold_al/scaffold_al_generator.rb b/wui/src/vendor/plugins/active_ldap/generators/scaffold_al/scaffold_al_generator.rb new file mode 100644 index 0000000..3fa365c --- /dev/null +++ b/wui/src/vendor/plugins/active_ldap/generators/scaffold_al/scaffold_al_generator.rb @@ -0,0 +1,20 @@ +class ScaffoldAlGenerator < Rails::Generator::Base + include ActiveLdap::GetTextSupport + + def initialize(*args) + duped_args = args.collect {|arg| arg.dup} + super + logger.warning(_("scaffold_al is deprecated. " \ + "Use scaffold_active_ldap instead.")) + generator_class = self.class.lookup("scaffold_active_ldap").klass + @generator = generator_class.new(duped_args) + end + + def manifest + @generator.manifest + end + + def source_path(*args) + @generator.source_path(*args) + end +end diff --git a/wui/src/vendor/plugins/active_ldap/init.rb b/wui/src/vendor/plugins/active_ldap/init.rb new file mode 100644 index 0000000..35e19d4 --- /dev/null +++ b/wui/src/vendor/plugins/active_ldap/init.rb @@ -0,0 +1,64 @@ +require_library_or_gem 'active_ldap' +ActiveLdap::Base.logger ||= RAILS_DEFAULT_LOGGER + +required_version = ["0", "9", "1"] +if (ActiveLdap::VERSION.split(".") <=> required_version) < 0 + ActiveLdap::Base.class_eval do + format = _("You need ActiveLdap %s or later") + logger.error(format % required_version.join(".")) + end +end + +ldap_configuration_file = File.join(RAILS_ROOT, 'config', 'ldap.yml') +if File.exist?(ldap_configuration_file) + configurations = YAML.load(ERB.new(IO.read(ldap_configuration_file)).result) + ActiveLdap::Base.configurations = configurations + ActiveLdap::Base.establish_connection +else + ActiveLdap::Base.class_eval do + format = _("You should run 'script/generator scaffold_active_ldap' to make %s.") + logger.error(format % ldap_configuration_file) + end +end + +class ::ActionView::Base + include ActiveLdap::Helper +end + +module ::ActionController + module LdapBenchmarking + def self.included(base) + base.class_eval do + alias_method_chain :render, :active_ldap_benchmark + alias_method_chain :rendering_runtime, :active_ldap + end + end + + protected + def render_with_active_ldap_benchmark(*args, &block) + if logger + @ldap_runtime_before_render = ActiveLdap::Base.reset_runtime + result = render_without_active_ldap_benchmark(*args, &block) + @ldap_runtime_after_render = ActiveLdap::Base.reset_runtime + @rendering_runtime -= @ldap_runtime_after_render + result + else + render_without_active_ldap_benchmark(*args, &block) + end + end + + private + def rendering_runtime_with_active_ldap(runtime) + result = rendering_runtime_without_active_ldap(runtime) + ldap_runtime = ActiveLdap::Base.reset_runtime + ldap_runtime += @ldap_runtime_before_render || 0 + ldap_runtime += @ldap_runtime_after_render || 0 + ldap_percentage = ldap_runtime * 100 / runtime + result + (" | LDAP: %.5f (%d%%)" % [ldap_runtime, ldap_percentage]) + end + end + + class Base + include LdapBenchmarking + end +end -- 1.5.4.1 From pmyers at redhat.com Thu May 8 13:36:03 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Thu, 08 May 2008 09:36:03 -0400 Subject: [Ovirt-devel] [PATCH] split ovirt-wui into separate scripts In-Reply-To: <769584de0805071344y39bbae52xc671660f9baae2f8@mail.gmail.com> References: <769584de0805071344y39bbae52xc671660f9baae2f8@mail.gmail.com> Message-ID: <482301C3.8010100@redhat.com> steve linabery wrote: > Hi ovirt, > > The attached patch attempts to split the ovirt-wui initrd script into > 5 separate scripts, one for each ovirt daemon. > > Bullet points: > 0) names scripts ovirt-host-browser, ovirt-host-keyadd, ... , ovirt-taskomatic > 1) adds 'status' option for init scripts > 2) %post section of rpm spec now removes legacy /etc/init.d/ovirt-wui > script if present > 3) edited rpm spec to handle 5 scripts instead of one where appropriate > 4) added new service names to the ENABLE_SVCS list in the > ovirt-wui-install script > > The new rpm specfile assumes that the install is a fresh install (i.e. > it doesn't attempt to deal with any legacy issues from this patch), > with the exception of the convenience removal of the previous > ovirt-wui script. This looks reasonable, but I have one question. All of the services are at runlevel 97/03. Are there any dependencies between these services such that they should start in a predefined order? If not, then having them all at 97 should be fine. But previously in the combined ovirt-wui they did start in a specific order. Perry From berrange at redhat.com Thu May 8 13:37:49 2008 From: berrange at redhat.com (Daniel P. Berrange) Date: Thu, 8 May 2008 14:37:49 +0100 Subject: [Ovirt-devel] [PATCH] split ovirt-wui into separate scripts In-Reply-To: <482301C3.8010100@redhat.com> References: <769584de0805071344y39bbae52xc671660f9baae2f8@mail.gmail.com> <482301C3.8010100@redhat.com> Message-ID: <20080508133749.GC31890@redhat.com> On Thu, May 08, 2008 at 09:36:03AM -0400, Perry N. Myers wrote: > steve linabery wrote: > >Hi ovirt, > > > >The attached patch attempts to split the ovirt-wui initrd script into > >5 separate scripts, one for each ovirt daemon. > > > >Bullet points: > >0) names scripts ovirt-host-browser, ovirt-host-keyadd, ... , > >ovirt-taskomatic > >1) adds 'status' option for init scripts > >2) %post section of rpm spec now removes legacy /etc/init.d/ovirt-wui > >script if present > >3) edited rpm spec to handle 5 scripts instead of one where appropriate > >4) added new service names to the ENABLE_SVCS list in the > >ovirt-wui-install script > > > >The new rpm specfile assumes that the install is a fresh install (i.e. > >it doesn't attempt to deal with any legacy issues from this patch), > >with the exception of the convenience removal of the previous > >ovirt-wui script. > > This looks reasonable, but I have one question. All of the services are > at runlevel 97/03. Are there any dependencies between these services such > that they should start in a predefined order? If not, then having them > all at 97 should be fine. But previously in the combined ovirt-wui they > did start in a specific order. If there are dependancies they would need to be removed. These 3 services are conceptually independant pieces, so shouldn't need to be ordered wrt each other. Regards, Dan. -- |: Red Hat, Engineering, Boston -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :| From jim at meyering.net Thu May 8 13:40:13 2008 From: jim at meyering.net (Jim Meyering) Date: Thu, 08 May 2008 15:40:13 +0200 Subject: [Ovirt-devel] Rebased - [PATCH] get host networking configuration from ovirt server In-Reply-To: <4820D383.5010409@redhat.com> (Alan Pevec's message of "Tue, 06 May 2008 23:54:11 +0200") References: <48111901.8010105@redhat.com> <4820D383.5010409@redhat.com> Message-ID: <87prrwx6bm.fsf@rho.meyering.net> Alan Pevec wrote: > commit cddbecff92d0d1af74a281bfd353f9faac89e9c1 > Author: Alan Pevec > Date: Tue May 6 23:15:41 2008 +0200 > > get host networking configuration from oVirt server > PXE-boot interface[1] is temporarily setup early in the boot > sequence (init.d/ovirt-early) and configuration[2] is retrieved from > oVirt server. > hostname is put in the requested URL to allow per host configuration, but for now all hosts get the same config: eth0 bridged to ovirtbr0 bridge > [1] IPAPPEND 2 in pxelinux config appends MAC of the PXE-booted > NIC to the kernel cmdln e.g. BOOTIF=01-00-16-3e-12-34-57 > [2] current implementation is a list of augtool commands, see http://augeas.net/tour.html Hi Alan, Looks good. Though something (your mail client?) mangled the patch, removing leading spaces -- that makes it so it doesn't apply. Here are a few comments: > diff --git a/ovirt-host-creator/common-post.ks b/ovirt-host-creator/common-post.ks > index 17291b4..6c503b4 100644 > --- a/ovirt-host-creator/common-post.ks > +++ b/ovirt-host-creator/common-post.ks > @@ -42,19 +42,60 @@ cat > /etc/init.d/ovirt-early << \EOF > > # Source functions library > . /etc/init.d/functions > +. /etc/init.d/ovirt-functions > > -start() { > +configure_from_network() { > + DEVICE=$1 > + if [ $DEVICE ]; then If $DEVICE may somehow expand to a "test" option, like -z, -f, -lt, etc. then the above will malfunction. Add quotes and use -n to be safe: if [ -n "$DEVICE" ]; then > + echo -n "." No need for double quotes. Prefer printf (besides, it's one byte shorter ;-) printf . > + # setup temporary interface to retrieve configuration > + echo "network --device $DEVICE --bootproto dhcp" | nash > + if [ $? -eq 0 ]; then > + echo -n "." > + # from network-scripts/ifup-post > + IPADDR=$(LANG=C ip -o -4 addr ls dev ${DEVICE} | awk '{ print $4 ; exit }') I suppose this sets LANG=C to avoid internationalized output from "ip"? LC_ALL=C is preferable for that, since it trumps LANG. > + eval $(ipcalc --silent --hostname ${IPADDR} ; echo "status=$?") > + if [ "$status" = "0" ]; then > + hostname $HOSTNAME > + # retrieve remote config > + find_srv ovirt tcp > + echo -n "." > + if [ $SRV_HOST -a $SRV_PORT ]; then > + curl -s http://$SRV_HOST:$SRV_PORT/ovirt/cfgdb/$(hostname) \ Add double quotes and -n, just in case $SRV_HOST and $SRV_PORT might ever be bogus (so reviewers can be lazy and not have to ensure -- or assume -- that find_srv or whatever else sets those variables does the right thing: if [ -n "$SRV_HOST" -a -n "$SRV_PORT" ]; then curl -s "http://$SRV_HOST:$SRV_PORT/ovirt/cfgdb/$(hostname)" \ > + | augtool > /dev/null 2>&1 ... > +start() { > + # find boot interface from cmdline > + # IPAPPEND 2 in pxelinux.cfg appends e.g. BOOTIF=01-00-16-3e-12-34-57 > + BOOTIF= > + for i in $(cat /proc/cmdline); do > + case $i in > + BOOTIF=*) > + BOOTMAC=$(echo $i | cut -d- -f2- | sed 's/-/:/g') this could be a little more strict on the input: BOOTIF=??-??-??-??-??-??-??) this can drop the use of cut (i.e. save a pipe): BOOTMAC=$(echo $i | sed 's/^BOOTIF=..-//;s/-/:/g') [actually, you could remove sed, too, and do it all in the shell, assuming you don't mind using a bash'ism (but this is too opaque, imho): i=${i/#BOOTIF=??-/} BOOTMAC=${i//-/:} > + BOOTIF=$(grep -l $BOOTMAC /sys/class/net/eth*/address|rev|cut -d/ -f2|rev) > + ;; > + esac > done > + configure_from_network $BOOTIF > > # find all of the partitions on the system > > diff --git a/ovirt-host-creator/ovirt-pxe.sh b/ovirt-host-creator/ovirt-pxe.sh > index 632ec5d..a586e87 100755 > --- a/ovirt-host-creator/ovirt-pxe.sh > +++ b/ovirt-host-creator/ovirt-pxe.sh > @@ -31,3 +31,11 @@ fi > ISO=`create_iso $ISO` || exit 1 > > livecd-iso-to-pxeboot $ISO > + > +# append BOOTIF with PXE MAC info > +grep -q 'IPAPPEND 2' tftpboot/pxelinux.cfg/default > +found=$? > +if [ $found -ne 0 ]; then > + sed -i -e '/KERNEL/a \ \tIPAPPEND 2' tftpboot/pxelinux.cfg/default > +fi This should be equivalent, and hopefully more readable: [dropped sed's -e, and removed the space-before-TAB] f=tftpboot/pxelinux.cfg/default grep -q 'IPAPPEND 2' $f || sed -i '/KERNEL/a \tIPAPPEND 2' $f From slinabery at gmail.com Thu May 8 14:57:25 2008 From: slinabery at gmail.com (steve linabery) Date: Thu, 8 May 2008 09:57:25 -0500 Subject: [Ovirt-devel] [PATCH] split ovirt-wui into separate scripts In-Reply-To: <20080508133749.GC31890@redhat.com> References: <769584de0805071344y39bbae52xc671660f9baae2f8@mail.gmail.com> <482301C3.8010100@redhat.com> <20080508133749.GC31890@redhat.com> Message-ID: <769584de0805080757h764678b5ra384f36ea1f6b95d@mail.gmail.com> On Thu, May 8, 2008 at 8:37 AM, Daniel P. Berrange wrote: > > On Thu, May 08, 2008 at 09:36:03AM -0400, Perry N. Myers wrote: > > steve linabery wrote: > > >Hi ovirt, > > > > > >The attached patch attempts to split the ovirt-wui initrd script into > > >5 separate scripts, one for each ovirt daemon. > > > > > >Bullet points: > > >0) names scripts ovirt-host-browser, ovirt-host-keyadd, ... , > > >ovirt-taskomatic > > >1) adds 'status' option for init scripts > > >2) %post section of rpm spec now removes legacy /etc/init.d/ovirt-wui > > >script if present > > >3) edited rpm spec to handle 5 scripts instead of one where appropriate > > >4) added new service names to the ENABLE_SVCS list in the > > >ovirt-wui-install script > > > > > >The new rpm specfile assumes that the install is a fresh install (i.e. > > >it doesn't attempt to deal with any legacy issues from this patch), > > >with the exception of the convenience removal of the previous > > >ovirt-wui script. > > > > This looks reasonable, but I have one question. All of the services are > > at runlevel 97/03. Are there any dependencies between these services such > > that they should start in a predefined order? If not, then having them > > all at 97 should be fine. But previously in the combined ovirt-wui they > > did start in a specific order. > > If there are dependancies they would need to be removed. These 3 services > are conceptually independant pieces, so shouldn't need to be ordered wrt > each other. > > Regards, > Dan. > -- > |: Red Hat, Engineering, Boston -o- http://people.redhat.com/berrange/ :| > |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| > |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| > |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :| > Hi guys, I wondered about the ordering as well, but my understanding from IRC chat is that ordering is not crucial. Good day, Steve From dpierce at redhat.com Thu May 8 15:05:38 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Thu, 8 May 2008 11:05:38 -0400 Subject: [Ovirt-devel] [PATCH] Added missing environments to the ldap.yml file. In-Reply-To: <1210259138-13393-4-git-send-email-dpierce@redhat.com> References: <1210259138-13393-1-git-send-email-dpierce@redhat.com> <1210259138-13393-2-git-send-email-dpierce@redhat.com> <1210259138-13393-3-git-send-email-dpierce@redhat.com> <1210259138-13393-4-git-send-email-dpierce@redhat.com> Message-ID: <1210259138-13393-5-git-send-email-dpierce@redhat.com> --- wui/src/.project | 12 ++++++ wui/src/nbproject/private/rake-t.txt | 63 ++++++++++++++++++++++++++++++++++ wui/src/nbproject/project.properties | 2 + wui/src/nbproject/project.xml | 9 +++++ 4 files changed, 86 insertions(+), 0 deletions(-) create mode 100644 .gitconfig create mode 100644 wui/src/.project create mode 100644 wui/src/nbproject/private/rake-t.txt create mode 100644 wui/src/nbproject/project.properties create mode 100644 wui/src/nbproject/project.xml diff --git a/.gitconfig b/.gitconfig new file mode 100644 index 0000000..e69de29 diff --git a/wui/src/.project b/wui/src/.project new file mode 100644 index 0000000..68f07a1 --- /dev/null +++ b/wui/src/.project @@ -0,0 +1,12 @@ + + + oVirt WUI + + + + + + + com.aptana.ide.project.nature.web + + diff --git a/wui/src/nbproject/private/rake-t.txt b/wui/src/nbproject/private/rake-t.txt new file mode 100644 index 0000000..27e016d --- /dev/null +++ b/wui/src/nbproject/private/rake-t.txt @@ -0,0 +1,63 @@ +(in /home/mcpierce/Programming/repos/ovirt/wui/src) +rake db:abort_if_pending_migrations # Raises an error if there are pending... +rake db:charset # Retrieves the charset for the curren... +rake db:collation # Retrieves the collation for the curr... +rake db:create # Create the database defined in confi... +rake db:create:all # Create all the local databases defin... +rake db:drop # Drops the database for the current R... +rake db:drop:all # Drops all the local databases define... +rake db:fixtures:identify # Search for a fixture given a LABEL o... +rake db:fixtures:load # Load fixtures into the current envir... +rake db:migrate # Migrate the database through scripts... +rake db:migrate:redo # Rollbacks the database one migration... +rake db:migrate:reset # Resets your database using your migr... +rake db:reset # Drops and recreates the database fro... +rake db:rollback # Rolls the schema back to the previou... +rake db:schema:dump # Create a db/schema.rb file that can ... +rake db:schema:load # Load a schema.rb file into the database +rake db:sessions:clear # Clear the sessions table +rake db:sessions:create # Creates a sessions migration for use... +rake db:structure:dump # Dump the database structure to a SQL... +rake db:test:clone # Recreate the test database from the ... +rake db:test:clone_structure # Recreate the test databases from the... +rake db:test:prepare # Prepare the test database and load t... +rake db:test:purge # Empty the test database +rake db:version # Retrieves the current schema version... +rake doc:app # Build the app HTML Files +rake doc:clobber_app # Remove rdoc products +rake doc:clobber_plugins # Remove plugin documentation +rake doc:clobber_rails # Remove rdoc products +rake doc:plugins # Generate documentation for all insta... +rake doc:rails # Build the rails HTML Files +rake doc:reapp # Force a rebuild of the RDOC files +rake doc:rerails # Force a rebuild of the RDOC files +rake log:clear # Truncates all *.log files in log/ to... +rake makemo # Create mo-files for L10n +rake notes # Enumerate all annotations +rake notes:fixme # Enumerate all FIXME annotations +rake notes:optimize # Enumerate all OPTIMIZE annotations +rake notes:todo # Enumerate all TODO annotations +rake rails:freeze:edge # Lock to latest Edge Rails or a speci... +rake rails:freeze:gems # Lock this application to the current... +rake rails:unfreeze # Unlock this application from freeze ... +rake rails:update # Update both configs, scripts and pub... +rake rails:update:configs # Update config/boot.rb from your curr... +rake rails:update:javascripts # Update your javascripts from your cu... +rake rails:update:scripts # Add new scripts to the application s... +rake routes # Print out all defined routes in matc... +rake secret # Generate a crytographically secure s... +rake stats # Report code statistics (KLOCs, etc) ... +rake test # Test all units and functionals +rake test:functionals # Run tests for functionalsdb:test:pre... +rake test:integration # Run tests for integrationdb:test:pre... +rake test:plugins # Run tests for pluginsenvironment / R... +rake test:recent # Run tests for recentdb:test:prepare ... +rake test:uncommitted # Run tests for uncommitteddb:test:pre... +rake test:units # Run tests for unitsdb:test:prepare /... +rake tmp:cache:clear # Clears all files and directories in ... +rake tmp:clear # Clear session, cache, and socket fil... +rake tmp:create # Creates tmp directories for sessions... +rake tmp:pids:clear # Clears all files in tmp/pids +rake tmp:sessions:clear # Clears all files in tmp/sessions +rake tmp:sockets:clear # Clears all files in tmp/sockets +rake updatepo # Update pot/po files to match new ver... diff --git a/wui/src/nbproject/project.properties b/wui/src/nbproject/project.properties new file mode 100644 index 0000000..0b610ac --- /dev/null +++ b/wui/src/nbproject/project.properties @@ -0,0 +1,2 @@ +rails.port=3000 +source.encoding=UTF-8 diff --git a/wui/src/nbproject/project.xml b/wui/src/nbproject/project.xml new file mode 100644 index 0000000..0e085d2 --- /dev/null +++ b/wui/src/nbproject/project.xml @@ -0,0 +1,9 @@ + + + org.netbeans.modules.ruby.railsprojects + + + src + + + -- 1.5.4.1 From dpierce at redhat.com Thu May 8 15:05:35 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Thu, 8 May 2008 11:05:35 -0400 Subject: [Ovirt-devel] [PATCH] A basically working LDAP base is started. In-Reply-To: <1210259138-13393-1-git-send-email-dpierce@redhat.com> References: <1210259138-13393-1-git-send-email-dpierce@redhat.com> Message-ID: <1210259138-13393-2-git-send-email-dpierce@redhat.com> From: Darryl L. Pierce --- wui/src/config/ldap.yml | 4 +++ .../scaffold_active_ldap/templates/ldap.yml | 21 ++++++++++++++++++++ wui/src/vendor/plugins/active_ldap/init.rb | 2 +- 3 files changed, 26 insertions(+), 1 deletions(-) create mode 100644 wui/src/config/ldap.yml create mode 100644 wui/src/vendor/plugins/active_ldap/generators/scaffold_active_ldap/templates/ldap.yml diff --git a/wui/src/config/ldap.yml b/wui/src/config/ldap.yml new file mode 100644 index 0000000..c8b167e --- /dev/null +++ b/wui/src/config/ldap.yml @@ -0,0 +1,4 @@ +development: + hostname: ldap.rdu.redhat.com + port: 389 + base: dc=redhat,dc=com diff --git a/wui/src/vendor/plugins/active_ldap/generators/scaffold_active_ldap/templates/ldap.yml b/wui/src/vendor/plugins/active_ldap/generators/scaffold_active_ldap/templates/ldap.yml new file mode 100644 index 0000000..720ec39 --- /dev/null +++ b/wui/src/vendor/plugins/active_ldap/generators/scaffold_active_ldap/templates/ldap.yml @@ -0,0 +1,21 @@ +development: + host: 127.0.0.1 + port: 389 + base: dc=devel,dc=local,dc=net + bind_dn: cn=admin,dc=local,dc=net + password: secret + +test: + host: 127.0.0.1 + port: 389 + base: dc=test,dc=local,dc=net + bind_dn: cn=admin,dc=local,dc=net + password: secret + +production: + host: 127.0.0.1 + port: 389 + method: :tls + base: dc=production,dc=local,dc=net + bind_dn: cn=admin,dc=local,dc=net + password: secret diff --git a/wui/src/vendor/plugins/active_ldap/init.rb b/wui/src/vendor/plugins/active_ldap/init.rb index 35e19d4..fa1484a 100644 --- a/wui/src/vendor/plugins/active_ldap/init.rb +++ b/wui/src/vendor/plugins/active_ldap/init.rb @@ -1,7 +1,7 @@ require_library_or_gem 'active_ldap' ActiveLdap::Base.logger ||= RAILS_DEFAULT_LOGGER -required_version = ["0", "9", "1"] +required_version = ["0", "10", "0"] if (ActiveLdap::VERSION.split(".") <=> required_version) < 0 ActiveLdap::Base.class_eval do format = _("You need ActiveLdap %s or later") -- 1.5.4.1 From dpierce at redhat.com Thu May 8 15:05:36 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Thu, 8 May 2008 11:05:36 -0400 Subject: [Ovirt-devel] [PATCH] Updated the account class. In-Reply-To: <1210259138-13393-2-git-send-email-dpierce@redhat.com> References: <1210259138-13393-1-git-send-email-dpierce@redhat.com> <1210259138-13393-2-git-send-email-dpierce@redhat.com> Message-ID: <1210259138-13393-3-git-send-email-dpierce@redhat.com> From: Darryl L. Pierce --- wui/src/app/helpers/ldap_connection.rb | 18 ++++++++---------- wui/src/app/models/account.rb | 19 ++++++++++++++++++- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/wui/src/app/helpers/ldap_connection.rb b/wui/src/app/helpers/ldap_connection.rb index 53256fa..623c02a 100644 --- a/wui/src/app/helpers/ldap_connection.rb +++ b/wui/src/app/helpers/ldap_connection.rb @@ -21,16 +21,14 @@ # connections with an LDAP server. # class LDAPConnection - @@hostname = nil - @@port = 389 - + @@config = YAML.load(File.open("#{RAILS_ROOT}/config/ldap.yml")) + # Connects the LDAP server. - def LDAPConnection.connect( - base, - hostname = LDAPConnection.hostname, - port = LDAPConnection.port - ) - ActiveLdap::Base.establish_connection(:host => hostname + def LDAPConnection.connect(base,host,port) + + ActiveLdap::Base.establish_connection(:host => host, + :port => port, + :base => base) if LDAPConnection.connected? == false end # Returns whether a connection already exists to the LDAP server. @@ -39,7 +37,7 @@ class LDAPConnection end # Disconnects from the LDAP server. - def LDAPConnection.disconnected + def LDAPConnection.disconnect ActiveLdap::Base.remove_connection if LDAPConnection.connected? end diff --git a/wui/src/app/models/account.rb b/wui/src/app/models/account.rb index 94c3bb6..2664f18 100644 --- a/wui/src/app/models/account.rb +++ b/wui/src/app/models/account.rb @@ -20,5 +20,22 @@ # +Account+ represents a single user's account from the LDAP server. # class Account < ActiveLdap::Base - ldap_mapping :dn_attribute => 'uid', :classes => ['person', 'posixAccount'] + ldap_mapping :dn_attribute => 'cn', :prefix => 'ou=Users', :scope => :one + + # +query+ returns the set of all accounts that contain the given search value. + # + # This API requires that a previous connection be made using + # +LDAPConnection.connect+. + # + def Account.query(value) + + @users = Account.find(:all, value) + + if block_given? + @users.each { |user| yield(user) } + end + + return @users + + end end -- 1.5.4.1 From dpierce at redhat.com Thu May 8 15:05:37 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Thu, 8 May 2008 11:05:37 -0400 Subject: [Ovirt-devel] [PATCH] Finished the LDAP connector. In-Reply-To: <1210259138-13393-3-git-send-email-dpierce@redhat.com> References: <1210259138-13393-1-git-send-email-dpierce@redhat.com> <1210259138-13393-2-git-send-email-dpierce@redhat.com> <1210259138-13393-3-git-send-email-dpierce@redhat.com> Message-ID: <1210259138-13393-4-git-send-email-dpierce@redhat.com> From: Darryl L. Pierce --- wui/src/app/helpers/ldap_connection.rb | 17 +++++++++++------ wui/src/config/ldap.yml | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/wui/src/app/helpers/ldap_connection.rb b/wui/src/app/helpers/ldap_connection.rb index 623c02a..af8b41b 100644 --- a/wui/src/app/helpers/ldap_connection.rb +++ b/wui/src/app/helpers/ldap_connection.rb @@ -21,23 +21,28 @@ # connections with an LDAP server. # class LDAPConnection - @@config = YAML.load(File.open("#{RAILS_ROOT}/config/ldap.yml")) - - # Connects the LDAP server. - def LDAPConnection.connect(base,host,port) + + @@config = YAML::load(File.open("#{RAILS_ROOT}/config/ldap.yml")) + + # Connects the specified LDAP server. + def self.connect(base = nil, host = nil, port = nil) + base = @@config[ENV['RAILS_ENV']]["base"] if base == nil + host = @@config[ENV['RAILS_ENV']]["host"] if host == nil + port = @@config[ENV['RAILS_ENV']]["port"] if port == nil + ActiveLdap::Base.establish_connection(:host => host, :port => port, :base => base) if LDAPConnection.connected? == false end # Returns whether a connection already exists to the LDAP server. - def LDAPConnection.connected? + def self.connected? return ActiveLdap::Base.connected? end # Disconnects from the LDAP server. - def LDAPConnection.disconnect + def self.disconnect ActiveLdap::Base.remove_connection if LDAPConnection.connected? end diff --git a/wui/src/config/ldap.yml b/wui/src/config/ldap.yml index c8b167e..5f8383f 100644 --- a/wui/src/config/ldap.yml +++ b/wui/src/config/ldap.yml @@ -1,4 +1,4 @@ development: - hostname: ldap.rdu.redhat.com + host: ldap.rdu.redhat.com port: 389 base: dc=redhat,dc=com -- 1.5.4.1 From dpierce at redhat.com Thu May 8 15:05:34 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Thu, 8 May 2008 11:05:34 -0400 Subject: [Ovirt-devel] [PATCH] Added to enable LDAP support via the ActiveLdap gem. Message-ID: <1210259138-13393-1-git-send-email-dpierce@redhat.com> From: Darryl L. Pierce --- wui/src/app/helpers/ldap_connection.rb | 46 +++++++++++++ wui/src/app/models/account.rb | 24 +++++++ wui/src/vendor/plugins/active_ldap/README | 54 +++++++++++++++ .../active_ldap/generators/model_active_ldap/USAGE | 17 +++++ .../model_active_ldap_generator.rb | 70 ++++++++++++++++++++ .../model_active_ldap/templates/fixtures.yml | 11 +++ .../templates/model_active_ldap.rb | 3 + .../model_active_ldap/templates/unit_test.rb | 10 +++ .../scaffold_active_ldap_generator.rb | 7 ++ .../scaffold_al/scaffold_al_generator.rb | 20 ++++++ wui/src/vendor/plugins/active_ldap/init.rb | 64 ++++++++++++++++++ 11 files changed, 326 insertions(+), 0 deletions(-) create mode 100644 wui/src/app/helpers/ldap_connection.rb create mode 100644 wui/src/app/models/account.rb create mode 100644 wui/src/vendor/plugins/active_ldap/README create mode 100644 wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/USAGE create mode 100644 wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/model_active_ldap_generator.rb create mode 100644 wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/templates/fixtures.yml create mode 100644 wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/templates/model_active_ldap.rb create mode 100644 wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/templates/unit_test.rb create mode 100644 wui/src/vendor/plugins/active_ldap/generators/scaffold_active_ldap/scaffold_active_ldap_generator.rb create mode 100644 wui/src/vendor/plugins/active_ldap/generators/scaffold_al/scaffold_al_generator.rb create mode 100644 wui/src/vendor/plugins/active_ldap/init.rb diff --git a/wui/src/app/helpers/ldap_connection.rb b/wui/src/app/helpers/ldap_connection.rb new file mode 100644 index 0000000..53256fa --- /dev/null +++ b/wui/src/app/helpers/ldap_connection.rb @@ -0,0 +1,46 @@ +# +# Copyright (C) 2008 Red Hat, Inc. +# Written by Darryl L. Pierce +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + +# +LDAPConnection+ handles establishing, returning and closing +# connections with an LDAP server. +# +class LDAPConnection + @@hostname = nil + @@port = 389 + + # Connects the LDAP server. + def LDAPConnection.connect( + base, + hostname = LDAPConnection.hostname, + port = LDAPConnection.port + ) + ActiveLdap::Base.establish_connection(:host => hostname + end + + # Returns whether a connection already exists to the LDAP server. + def LDAPConnection.connected? + return ActiveLdap::Base.connected? + end + + # Disconnects from the LDAP server. + def LDAPConnection.disconnected + ActiveLdap::Base.remove_connection if LDAPConnection.connected? + end + +end diff --git a/wui/src/app/models/account.rb b/wui/src/app/models/account.rb new file mode 100644 index 0000000..94c3bb6 --- /dev/null +++ b/wui/src/app/models/account.rb @@ -0,0 +1,24 @@ +# +# Copyright (C) 2008 Red Hat, Inc. +# Written by Darryl L. Pierce +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. A copy of the GNU General Public License is +# also available at http://www.gnu.org/copyleft/gpl.html. + +# +Account+ represents a single user's account from the LDAP server. +# +class Account < ActiveLdap::Base + ldap_mapping :dn_attribute => 'uid', :classes => ['person', 'posixAccount'] +end diff --git a/wui/src/vendor/plugins/active_ldap/README b/wui/src/vendor/plugins/active_ldap/README new file mode 100644 index 0000000..8e40086 --- /dev/null +++ b/wui/src/vendor/plugins/active_ldap/README @@ -0,0 +1,54 @@ += ActiveLdap plugin for Ruby on Rails + +== Setup + +You need to write RAILS_ROOT/config/ldap.yml like the following: + + development: + host: 127.0.0.1 + port: 389 + base: dc=devel,dc=local,dc=net + bind_dn: cn=admin,dc=local,dc=net + password: secret + + test: + host: 127.0.0.1 + port: 389 + base: dc=test,dc=local,dc=net + bind_dn: cn=admin,dc=local,dc=net + password: secret + + production: + host: 127.0.0.1 + port: 389 + base: dc=production,dc=local,dc=net + bind_dn: cn=admin,dc=local,dc=net + password: secret + +== Model + +Here is some examples. + +app/model/member.rb: + class Member < ActiveLdap::Base + ldap_mapping :dn_attribute => 'uid', + :classes => ['person', 'posixAccount'] + belongs_to :primary_group, :class => "Group", + :foreign_key => "gidNumber", :primary_key => "gidNumber" + belongs_to :groups, :many => 'memberUid' + end + +app/model/group.rb: + class Group < ActiveLdap::Base + ldap_mapping :dn_attribute => "cn", :classes => ['posixGroup'] + has_many :members, :wrap => "memberUid" + has_many :primary_members, + :foreign_key => 'gidNumber', + :primary_key => 'gidNumber' + end + +app/model/ou.rb: + class Ou < ActiveLdap::Base + ldap_mapping :prefix => "", + :classes => ["top", "organizationalUnit"] + end diff --git a/wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/USAGE b/wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/USAGE new file mode 100644 index 0000000..a86c5dd --- /dev/null +++ b/wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/USAGE @@ -0,0 +1,17 @@ +Description: + The model_activeldap generator creates stubs for a new model. + + The generator takes a model name as its argument. The model name may be given in CamelCase or under_score and + should not be suffixed with 'Model'. + + The generator creates a model class in app/models, a test suite in test/unit, and test fixtures in + test/fixtures/singular_name.yml. It will not create a migration. + +Examples: + ./script/generate model_activeldap user + + This will create a User model: + Model: app/models/user.rb + Test: test/unit/user_test.rb + Fixtures: test/fixtures/users.yml + diff --git a/wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/model_active_ldap_generator.rb b/wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/model_active_ldap_generator.rb new file mode 100644 index 0000000..f8435a3 --- /dev/null +++ b/wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/model_active_ldap_generator.rb @@ -0,0 +1,70 @@ +class ModelActiveLdapGenerator < Rails::Generator::NamedBase + include ActiveLdap::GetTextSupport + + default_options :dn_attribute => "cn", :classes => nil + + def manifest + record do |m| + # Check for class naming collisions. + m.class_collisions class_path, class_name, "#{class_name}Test" + + # Model, test, and fixture directories. + m.directory File.join('app/models', class_path) + m.directory File.join('test/unit', class_path) + m.directory File.join('test/fixtures', class_path) + + # Model class, unit test, and fixtures. + m.template('model_active_ldap.rb', + File.join('app/models', class_path, "#{file_name}.rb"), + :assigns => {:ldap_mapping => ldap_mapping}) + m.template('unit_test.rb', + File.join('test/unit', class_path, "#{file_name}_test.rb")) + m.template('fixtures.yml', + File.join('test/fixtures', class_path, "#{table_name}.yml")) + end + end + + private + def add_options!(opt) + opt.separator '' + opt.separator 'Options:' + opt.on("--dn-attribute=ATTRIBUTE", + _("Use ATTRIBUTE as default DN attribute for " \ + "instances of this model"), + _("(default: %s)") % options[:dn_attribute]) do |attribute| + options[:dn_attribute] = attribute + end + + opt.on("--prefix=PREFIX", + _("Use PREFIX as prefix for this model"), + _("(default: %s)") % default_prefix) do |prefix| + options[:prefix] = prefix + end + + opt.on("--classes=CLASS,CLASS,...", + Array, + "Use CLASSES as required objectClass for instances of this model", + "(default: %s)" % options[:classes]) do |classes| + options[:classes] = classes + end + end + + def prefix + options[:prefix] || default_prefix + end + + def default_prefix + "ou=#{Inflector.pluralize(Inflector.demodulize(name))}" + end + + def ldap_mapping(indent=' ') + mapping = "ldap_mapping " + mapping_options = [":dn_attribute => #{options[:dn_attribute].dump}"] + mapping_options << ":prefix => #{prefix.dump}" + if options[:classes] + mapping_options << ":classes => #{options[:classes].inspect}" + end + mapping_options = mapping_options.join(",\n#{indent}#{' ' * mapping.size}") + "#{indent}#{mapping}#{mapping_options}" + end +end diff --git a/wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/templates/fixtures.yml b/wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/templates/fixtures.yml new file mode 100644 index 0000000..9f5ae29 --- /dev/null +++ b/wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/templates/fixtures.yml @@ -0,0 +1,11 @@ +# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html +one: + id: 1 +<% for attribute in attributes -%> + <%= attribute.name %>: <%= attribute.default %> +<% end -%> +two: + id: 2 +<% for attribute in attributes -%> + <%= attribute.name %>: <%= attribute.default %> +<% end -%> \ No newline at end of file diff --git a/wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/templates/model_active_ldap.rb b/wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/templates/model_active_ldap.rb new file mode 100644 index 0000000..cdfa66b --- /dev/null +++ b/wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/templates/model_active_ldap.rb @@ -0,0 +1,3 @@ +class <%= class_name %> < ActiveLdap::Base +<%= ldap_mapping %> +end diff --git a/wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/templates/unit_test.rb b/wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/templates/unit_test.rb new file mode 100644 index 0000000..b464de4 --- /dev/null +++ b/wui/src/vendor/plugins/active_ldap/generators/model_active_ldap/templates/unit_test.rb @@ -0,0 +1,10 @@ +require File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../test_helper' + +class <%= class_name %>Test < Test::Unit::TestCase + fixtures :<%= table_name %> + + # Replace this with your real tests. + def test_truth + assert true + end +end diff --git a/wui/src/vendor/plugins/active_ldap/generators/scaffold_active_ldap/scaffold_active_ldap_generator.rb b/wui/src/vendor/plugins/active_ldap/generators/scaffold_active_ldap/scaffold_active_ldap_generator.rb new file mode 100644 index 0000000..35ad937 --- /dev/null +++ b/wui/src/vendor/plugins/active_ldap/generators/scaffold_active_ldap/scaffold_active_ldap_generator.rb @@ -0,0 +1,7 @@ +class ScaffoldActiveLdapGenerator < Rails::Generator::Base + def manifest + record do |m| + m.template("ldap.yml", File.join("config", "ldap.yml")) + end + end +end diff --git a/wui/src/vendor/plugins/active_ldap/generators/scaffold_al/scaffold_al_generator.rb b/wui/src/vendor/plugins/active_ldap/generators/scaffold_al/scaffold_al_generator.rb new file mode 100644 index 0000000..3fa365c --- /dev/null +++ b/wui/src/vendor/plugins/active_ldap/generators/scaffold_al/scaffold_al_generator.rb @@ -0,0 +1,20 @@ +class ScaffoldAlGenerator < Rails::Generator::Base + include ActiveLdap::GetTextSupport + + def initialize(*args) + duped_args = args.collect {|arg| arg.dup} + super + logger.warning(_("scaffold_al is deprecated. " \ + "Use scaffold_active_ldap instead.")) + generator_class = self.class.lookup("scaffold_active_ldap").klass + @generator = generator_class.new(duped_args) + end + + def manifest + @generator.manifest + end + + def source_path(*args) + @generator.source_path(*args) + end +end diff --git a/wui/src/vendor/plugins/active_ldap/init.rb b/wui/src/vendor/plugins/active_ldap/init.rb new file mode 100644 index 0000000..35e19d4 --- /dev/null +++ b/wui/src/vendor/plugins/active_ldap/init.rb @@ -0,0 +1,64 @@ +require_library_or_gem 'active_ldap' +ActiveLdap::Base.logger ||= RAILS_DEFAULT_LOGGER + +required_version = ["0", "9", "1"] +if (ActiveLdap::VERSION.split(".") <=> required_version) < 0 + ActiveLdap::Base.class_eval do + format = _("You need ActiveLdap %s or later") + logger.error(format % required_version.join(".")) + end +end + +ldap_configuration_file = File.join(RAILS_ROOT, 'config', 'ldap.yml') +if File.exist?(ldap_configuration_file) + configurations = YAML.load(ERB.new(IO.read(ldap_configuration_file)).result) + ActiveLdap::Base.configurations = configurations + ActiveLdap::Base.establish_connection +else + ActiveLdap::Base.class_eval do + format = _("You should run 'script/generator scaffold_active_ldap' to make %s.") + logger.error(format % ldap_configuration_file) + end +end + +class ::ActionView::Base + include ActiveLdap::Helper +end + +module ::ActionController + module LdapBenchmarking + def self.included(base) + base.class_eval do + alias_method_chain :render, :active_ldap_benchmark + alias_method_chain :rendering_runtime, :active_ldap + end + end + + protected + def render_with_active_ldap_benchmark(*args, &block) + if logger + @ldap_runtime_before_render = ActiveLdap::Base.reset_runtime + result = render_without_active_ldap_benchmark(*args, &block) + @ldap_runtime_after_render = ActiveLdap::Base.reset_runtime + @rendering_runtime -= @ldap_runtime_after_render + result + else + render_without_active_ldap_benchmark(*args, &block) + end + end + + private + def rendering_runtime_with_active_ldap(runtime) + result = rendering_runtime_without_active_ldap(runtime) + ldap_runtime = ActiveLdap::Base.reset_runtime + ldap_runtime += @ldap_runtime_before_render || 0 + ldap_runtime += @ldap_runtime_after_render || 0 + ldap_percentage = ldap_runtime * 100 / runtime + result + (" | LDAP: %.5f (%d%%)" % [ldap_runtime, ldap_percentage]) + end + end + + class Base + include LdapBenchmarking + end +end -- 1.5.4.1 From dpierce at redhat.com Thu May 8 15:09:11 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Thu, 8 May 2008 11:09:11 -0400 Subject: [Ovirt-devel] PATCH: Fix broken test fixtures from my patches yesterday Message-ID: <200805081109.11914.dpierce@redhat.com> -- Darryl L. Pierce - Phone: (919) 754-4383 "In matters of style, swim with the current; In matters of principle, stand like a rock." - Thomas Jefferson -------------- next part -------------- A non-text attachment was scrubbed... Name: ldap_fix_test_fixtures.patch Type: text/x-diff Size: 411 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 189 bytes Desc: This is a digitally signed message part. URL: From slinabery at gmail.com Thu May 8 16:14:16 2008 From: slinabery at gmail.com (steve linabery) Date: Thu, 8 May 2008 11:14:16 -0500 Subject: [Ovirt-devel] [PATCH] split ovirt-wui into separate scripts In-Reply-To: <769584de0805080757h764678b5ra384f36ea1f6b95d@mail.gmail.com> References: <769584de0805071344y39bbae52xc671660f9baae2f8@mail.gmail.com> <482301C3.8010100@redhat.com> <20080508133749.GC31890@redhat.com> <769584de0805080757h764678b5ra384f36ea1f6b95d@mail.gmail.com> Message-ID: <769584de0805080914w5d54e739l8df51ec0bf994a1b@mail.gmail.com> On Thu, May 8, 2008 at 9:57 AM, steve linabery wrote: > > On Thu, May 8, 2008 at 8:37 AM, Daniel P. Berrange wrote: > > > > On Thu, May 08, 2008 at 09:36:03AM -0400, Perry N. Myers wrote: > > > steve linabery wrote: > > > >Hi ovirt, > > > > > > > >The attached patch attempts to split the ovirt-wui initrd script into > > > >5 separate scripts, one for each ovirt daemon. > > > > > > > >Bullet points: > > > >0) names scripts ovirt-host-browser, ovirt-host-keyadd, ... , > > > >ovirt-taskomatic > > > >1) adds 'status' option for init scripts > > > >2) %post section of rpm spec now removes legacy /etc/init.d/ovirt-wui > > > >script if present > > > >3) edited rpm spec to handle 5 scripts instead of one where appropriate > > > >4) added new service names to the ENABLE_SVCS list in the > > > >ovirt-wui-install script > > > > > > > >The new rpm specfile assumes that the install is a fresh install (i.e. > > > >it doesn't attempt to deal with any legacy issues from this patch), > > > >with the exception of the convenience removal of the previous > > > >ovirt-wui script. > > > > > > This looks reasonable, but I have one question. All of the services are > > > at runlevel 97/03. Are there any dependencies between these services such > > > that they should start in a predefined order? If not, then having them > > > all at 97 should be fine. But previously in the combined ovirt-wui they > > > did start in a specific order. > > > > If there are dependancies they would need to be removed. These 3 services > > are conceptually independant pieces, so shouldn't need to be ordered wrt > > each other. > > > > Regards, > > Dan. > > -- > > |: Red Hat, Engineering, Boston -o- http://people.redhat.com/berrange/ :| > > |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| > > |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| > > |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :| > > > > Hi guys, > > I wondered about the ordering as well, but my understanding from IRC > chat is that ordering is not crucial. > > Good day, > Steve > Hi ovirt, Per Jim M's suggestion, here is revised patch with no trailing spaces and 80-char line length enforced (excepting the rpm spec file). Enjoy, Steve -------------- next part -------------- A non-text attachment was scrubbed... Name: daemonsplit.patch Type: text/x-patch Size: 10754 bytes Desc: not available URL: From jim at meyering.net Thu May 8 16:26:38 2008 From: jim at meyering.net (Jim Meyering) Date: Thu, 08 May 2008 18:26:38 +0200 Subject: [Ovirt-devel] [PATCH] split ovirt-wui into separate scripts In-Reply-To: <769584de0805071344y39bbae52xc671660f9baae2f8@mail.gmail.com> (steve linabery's message of "Wed, 7 May 2008 15:44:21 -0500") References: <769584de0805071344y39bbae52xc671660f9baae2f8@mail.gmail.com> Message-ID: <87wsm4vk1t.fsf@rho.meyering.net> "steve linabery" wrote: ... > diff --git a/wui/conf/ovirt-mongrel-rails b/wui/conf/ovirt-mongrel-rails > new file mode 100755 > index 0000000..0e5687b > --- /dev/null > +++ b/wui/conf/ovirt-mongrel-rails > @@ -0,0 +1,72 @@ > +#!/bin/bash > +# > +# > +# ovirt-mongrel-rails startup script for ovirt-mongrel-rails > +# > +# chkconfig: - 97 03 > +# description: ovirt-mongrel-rails is an essential component of the ovirt VM manager. > +# > + > +OVIRT_DIR=/usr/share/ovirt-wui > +MONGREL_LOG=/var/log/ovirt-wui/mongrel.log > +MONGREL_PID=/var/run/ovirt-wui/mongrel.pid ... > + if [ $RETVAL -eq 0 ] && touch /var/lock/subsys/ovirt-wui ; then ... > +stop() { ... > + if [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/ovirt-wui ; then Hi Steve, I know this is mostly just moving existing code around, but this is probably as good a time as any to factor out that repeated lock file name. From slinabery at gmail.com Thu May 8 16:29:27 2008 From: slinabery at gmail.com (steve linabery) Date: Thu, 8 May 2008 11:29:27 -0500 Subject: [Ovirt-devel] [PATCH] split ovirt-wui into separate scripts In-Reply-To: <87wsm4vk1t.fsf@rho.meyering.net> References: <769584de0805071344y39bbae52xc671660f9baae2f8@mail.gmail.com> <87wsm4vk1t.fsf@rho.meyering.net> Message-ID: <769584de0805080929k4c999c38i8402cff1021eb0e5@mail.gmail.com> On Thu, May 8, 2008 at 11:26 AM, Jim Meyering wrote: > "steve linabery" wrote: > ... > > diff --git a/wui/conf/ovirt-mongrel-rails b/wui/conf/ovirt-mongrel-rails > > new file mode 100755 > > index 0000000..0e5687b > > --- /dev/null > > +++ b/wui/conf/ovirt-mongrel-rails > > @@ -0,0 +1,72 @@ > > +#!/bin/bash > > +# > > +# > > +# ovirt-mongrel-rails startup script for ovirt-mongrel-rails > > +# > > +# chkconfig: - 97 03 > > +# description: ovirt-mongrel-rails is an essential component of the ovirt VM manager. > > +# > > + > > +OVIRT_DIR=/usr/share/ovirt-wui > > +MONGREL_LOG=/var/log/ovirt-wui/mongrel.log > > +MONGREL_PID=/var/run/ovirt-wui/mongrel.pid > ... > > + if [ $RETVAL -eq 0 ] && touch /var/lock/subsys/ovirt-wui ; then > ... > > +stop() { > ... > > + if [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/ovirt-wui ; then > > Hi Steve, > I know this is mostly just moving existing code around, but this is > probably as good a time as any to factor out that repeated lock file name. > Agreed. Glad to have your eyes on this stuff! S From slinabery at gmail.com Thu May 8 16:39:27 2008 From: slinabery at gmail.com (steve linabery) Date: Thu, 8 May 2008 11:39:27 -0500 Subject: [Ovirt-devel] [PATCH] split ovirt-wui into separate scripts In-Reply-To: <87wsm4vk1t.fsf@rho.meyering.net> References: <769584de0805071344y39bbae52xc671660f9baae2f8@mail.gmail.com> <87wsm4vk1t.fsf@rho.meyering.net> Message-ID: <769584de0805080939g2efe9196l52de0911441fe65a@mail.gmail.com> On Thu, May 8, 2008 at 11:26 AM, Jim Meyering wrote: > "steve linabery" wrote: > ... > > diff --git a/wui/conf/ovirt-mongrel-rails b/wui/conf/ovirt-mongrel-rails > > new file mode 100755 > > index 0000000..0e5687b > > --- /dev/null > > +++ b/wui/conf/ovirt-mongrel-rails > > @@ -0,0 +1,72 @@ > > +#!/bin/bash > > +# > > +# > > +# ovirt-mongrel-rails startup script for ovirt-mongrel-rails > > +# > > +# chkconfig: - 97 03 > > +# description: ovirt-mongrel-rails is an essential component of the ovirt VM manager. > > +# > > + > > +OVIRT_DIR=/usr/share/ovirt-wui > > +MONGREL_LOG=/var/log/ovirt-wui/mongrel.log > > +MONGREL_PID=/var/run/ovirt-wui/mongrel.pid > ... > > + if [ $RETVAL -eq 0 ] && touch /var/lock/subsys/ovirt-wui ; then > ... > > +stop() { > ... > > + if [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/ovirt-wui ; then > > Hi Steve, > I know this is mostly just moving existing code around, but this is > probably as good a time as any to factor out that repeated lock file name. > Third time charm? I also pulled out the mongrel_rails executable name, since having it down there in the status line was making me nervous. Good day, Steve -------------- next part -------------- A non-text attachment was scrubbed... Name: daemonsplit.patch Type: text/x-patch Size: 11056 bytes Desc: not available URL: From slinabery at gmail.com Thu May 8 17:05:16 2008 From: slinabery at gmail.com (steve linabery) Date: Thu, 8 May 2008 12:05:16 -0500 Subject: [Ovirt-devel] [PATCH] split ovirt-wui into separate scripts In-Reply-To: <769584de0805080939g2efe9196l52de0911441fe65a@mail.gmail.com> References: <769584de0805071344y39bbae52xc671660f9baae2f8@mail.gmail.com> <87wsm4vk1t.fsf@rho.meyering.net> <769584de0805080939g2efe9196l52de0911441fe65a@mail.gmail.com> Message-ID: <769584de0805081005y7dd4a48bgbd8d668253c48563@mail.gmail.com> On Thu, May 8, 2008 at 11:39 AM, steve linabery wrote: > On Thu, May 8, 2008 at 11:26 AM, Jim Meyering wrote: > > > > "steve linabery" wrote: > > ... > > > diff --git a/wui/conf/ovirt-mongrel-rails b/wui/conf/ovirt-mongrel-rails > > > new file mode 100755 > > > index 0000000..0e5687b > > > --- /dev/null > > > +++ b/wui/conf/ovirt-mongrel-rails > > > @@ -0,0 +1,72 @@ > > > +#!/bin/bash > > > +# > > > +# > > > +# ovirt-mongrel-rails startup script for ovirt-mongrel-rails > > > +# > > > +# chkconfig: - 97 03 > > > +# description: ovirt-mongrel-rails is an essential component of the ovirt VM manager. > > > +# > > > + > > > +OVIRT_DIR=/usr/share/ovirt-wui > > > +MONGREL_LOG=/var/log/ovirt-wui/mongrel.log > > > +MONGREL_PID=/var/run/ovirt-wui/mongrel.pid > > ... > > > + if [ $RETVAL -eq 0 ] && touch /var/lock/subsys/ovirt-wui ; then > > ... > > > +stop() { > > ... > > > + if [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/ovirt-wui ; then > > > > Hi Steve, > > I know this is mostly just moving existing code around, but this is > > probably as good a time as any to factor out that repeated lock file name. > > > > Third time charm? > > I also pulled out the mongrel_rails executable name, since having it > down there in the status line was making me nervous. > > Good day, > Steve > With odd artifacts removed from head of file. Thanks, Steve -------------- next part -------------- A non-text attachment was scrubbed... Name: daemonsplit.patch1 Type: application/octet-stream Size: 10565 bytes Desc: not available URL: From jim at meyering.net Thu May 8 18:07:43 2008 From: jim at meyering.net (Jim Meyering) Date: Thu, 08 May 2008 20:07:43 +0200 Subject: [Ovirt-devel] [PATCH] split ovirt-wui into separate scripts In-Reply-To: <769584de0805081005y7dd4a48bgbd8d668253c48563@mail.gmail.com> (steve linabery's message of "Thu, 8 May 2008 12:05:16 -0500") References: <769584de0805071344y39bbae52xc671660f9baae2f8@mail.gmail.com> <87wsm4vk1t.fsf@rho.meyering.net> <769584de0805080939g2efe9196l52de0911441fe65a@mail.gmail.com> <769584de0805081005y7dd4a48bgbd8d668253c48563@mail.gmail.com> Message-ID: <874p98vfdc.fsf@rho.meyering.net> "steve linabery" wrote: ... >> > I know this is mostly just moving existing code around, but this is >> > probably as good a time as any to factor out that repeated lock file name. >> > >> >> Third time charm? Looks good. From sseago at redhat.com Thu May 8 19:43:46 2008 From: sseago at redhat.com (Scott Seago) Date: Thu, 08 May 2008 15:43:46 -0400 Subject: [Ovirt-devel] [Patch] Integrate jquery table widget; convert existing tables to use this format Message-ID: <482357F2.9050704@redhat.com> This patch integrates flexigrid, a jquery plugin that provides a table widget with sorting, paging, and searching capabilities. For the moment, existing display tables have been pulled along with the same attributes we were showing in the old UI. Once we have monitoring columns added to the db, we can determine which attributes we really want to show and modify accordingly. Scott -------------- next part -------------- A non-text attachment was scrubbed... Name: ui-tables.patch Type: text/x-patch Size: 123936 bytes Desc: not available URL: From jguiditt at redhat.com Thu May 8 21:07:35 2008 From: jguiditt at redhat.com (Jason Guiditta) Date: Thu, 08 May 2008 17:07:35 -0400 Subject: [Ovirt-devel] [Patch] Integrate jquery table widget; convert existing tables to use this format In-Reply-To: <482357F2.9050704@redhat.com> References: <482357F2.9050704@redhat.com> Message-ID: <48236B97.1040109@redhat.com> Scott Seago wrote: > This patch integrates flexigrid, a jquery plugin that provides a table > widget with sorting, paging, and searching capabilities. For the > moment, existing display tables have been pulled along with the same > attributes we were showing in the old UI. Once we have monitoring > columns added to the db, we can determine which attributes we really > want to show and modify accordingly. > > Scott > ------------------------------------------------------------------------ > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel Aside from changing id names from things like 'hosts1' to 'hosts-grid', and url_for to link_to, ACK. -j From d.jacobfeuerborn at conversis.de Fri May 9 01:13:39 2008 From: d.jacobfeuerborn at conversis.de (Dennis Jacobfeuerborn) Date: Fri, 09 May 2008 03:13:39 +0200 Subject: [Ovirt-devel] Problem with developer installation Message-ID: <4823A543.7030505@conversis.de> Hi, I wanted to start playing with ovirt so I installed the developer version following the instructions on this page: http://ovirt.org/devel-install.html The installation finished without problems but when I start firefox on the guest according to step 5 I get the following message in the browser: Authorization Required This server could not verify that you are authorized to access the document requested. Either you supplied the wrong credentials (e.g., bad password), or your browser doesn't understand how to supply the credentials required. How exactly does the browser get authorized with the server and does anybody have an idea why this isn't working? I used the F8 boot.iso for the installation because that's what the instructions mention but would a F9 iso be ok too or would the setup scripts get into trouble with a different distribution? Regards, Dennis From d.jacobfeuerborn at conversis.de Fri May 9 01:15:45 2008 From: d.jacobfeuerborn at conversis.de (Dennis Jacobfeuerborn) Date: Fri, 09 May 2008 03:15:45 +0200 Subject: [Ovirt-devel] Problem with developer installation In-Reply-To: <4823A543.7030505@conversis.de> References: <4823A543.7030505@conversis.de> Message-ID: <4823A5C1.5090603@conversis.de> Dennis Jacobfeuerborn wrote: > Hi, > I wanted to start playing with ovirt so I installed the developer > version following the instructions on this page: > http://ovirt.org/devel-install.html > > The installation finished without problems but when I start firefox on > the guest according to step 5 I get the following message in the browser: > > Authorization Required > This server could not verify that you are authorized to access the > document requested. Either you supplied the wrong credentials (e.g., bad > password), or your browser doesn't understand how to supply the > credentials required. > > How exactly does the browser get authorized with the server and does > anybody have an idea why this isn't working? > > I used the F8 boot.iso for the installation because that's what the > instructions mention but would a F9 iso be ok too or would the setup > scripts get into trouble with a different distribution? I just powered down the VM and got a "failed" for "Shutting down host-browser". Maybe that has something to do with the authorization problems? Regards, Dennis From sburgess at redhat.com Fri May 9 02:22:42 2008 From: sburgess at redhat.com (Susan Burgess) Date: Fri, 09 May 2008 12:22:42 +1000 Subject: [Ovirt-devel] Problem with developer installation In-Reply-To: <4823A543.7030505@conversis.de> References: <4823A543.7030505@conversis.de> Message-ID: <4823B572.7020001@redhat.com> Hi Dennis I just had the same problem, same message for an appliance that has been working fine for days. Try restarting the system and then start up developer and node3. Wait a while before trying to get the appliance up. Make sure you are not root when you give the ssh -Y etc command. Either the abvove worked, or the server was down and is now up :-[ . Don't know. but my appliance is now working. Good luck, Susan Dennis Jacobfeuerborn wrote: > Hi, > I wanted to start playing with ovirt so I installed the developer > version following the instructions on this page: > http://ovirt.org/devel-install.html > > The installation finished without problems but when I start firefox on > the guest according to step 5 I get the following message in the browser: > > Authorization Required > This server could not verify that you are authorized to access the > document requested. Either you supplied the wrong credentials (e.g., > bad password), or your browser doesn't understand how to supply the > credentials required. > > How exactly does the browser get authorized with the server and does > anybody have an idea why this isn't working? > > I used the F8 boot.iso for the installation because that's what the > instructions mention but would a F9 iso be ok too or would the setup > scripts get into trouble with a different distribution? > > Regards, > Dennis > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel -- Susan Burgess Content Author Red Hat APAC Level 1, 193 North Quay Brisbane, QLD 4000 Australia Phone +61 7 3514 8179 Fax +61 7 3514 8199 Mail sburgess at redhat.com From d.jacobfeuerborn at conversis.de Fri May 9 02:44:56 2008 From: d.jacobfeuerborn at conversis.de (Dennis Jacobfeuerborn) Date: Fri, 09 May 2008 04:44:56 +0200 Subject: [Fwd: Re: [Ovirt-devel] Problem with developer installation] Message-ID: <4823BAA8.4060204@conversis.de> Hi Susan, I haven't tried to start any additional nodes yet to keep the possible problem sources limited. After taking a closer look at the init scripts and logfiles and doing some strace'ing it looks like I'm missing the file /var/kerberos/krb5kdc/principal which seems to be vital for the kerberos tools. Not sure why this isn't there and the first-run scripts don't regenerate the kerberos stuff either so that explains why the authorization fails. I wonder why the kerberos subsystem got screwed up because I followed the instruction exactly and got no errors during the installation. Everything looked fine until I actually ran the appliance. Regards, Dennis Susan Burgess wrote: > Hi Dennis > > I just had the same problem, same message for an appliance that has been > working fine for days. > Try restarting the system and then start up developer and node3. Wait a > while before trying to get the appliance up. > Make sure you are not root when you give the ssh -Y etc command. > > Either the abvove worked, or the server was down and is now up :-[ . > Don't know. but my appliance is now working. > > Good luck, > Susan > > > > Dennis Jacobfeuerborn wrote: >> Hi, >> I wanted to start playing with ovirt so I installed the developer >> version following the instructions on this page: >> http://ovirt.org/devel-install.html >> >> The installation finished without problems but when I start firefox on >> the guest according to step 5 I get the following message in the browser: >> >> Authorization Required >> This server could not verify that you are authorized to access the >> document requested. Either you supplied the wrong credentials (e.g., >> bad password), or your browser doesn't understand how to supply the >> credentials required. >> >> How exactly does the browser get authorized with the server and does >> anybody have an idea why this isn't working? >> >> I used the F8 boot.iso for the installation because that's what the >> instructions mention but would a F9 iso be ok too or would the setup >> scripts get into trouble with a different distribution? >> >> Regards, >> Dennis >> >> _______________________________________________ >> Ovirt-devel mailing list >> Ovirt-devel at redhat.com >> https://www.redhat.com/mailman/listinfo/ovirt-devel > From sburgess at redhat.com Fri May 9 03:52:06 2008 From: sburgess at redhat.com (Susan Burgess) Date: Fri, 09 May 2008 13:52:06 +1000 Subject: [Fwd: Re: [Ovirt-devel] Problem with developer installation] In-Reply-To: <4823BAA8.4060204@conversis.de> References: <4823BAA8.4060204@conversis.de> Message-ID: <4823CA66.3090304@redhat.com> Sorry Dennis, can't help you with that. If you jump onto the #ovirt chat you may find someone who can help you now, otherwise someone will respond when the US based developers come back online in their morning. Thanks Susan Dennis Jacobfeuerborn wrote: > Hi Susan, > > I haven't tried to start any additional nodes yet to keep the possible > problem sources limited. After taking a closer look at the init > scripts and > logfiles and doing some strace'ing it looks like I'm missing the file > /var/kerberos/krb5kdc/principal which seems to be vital for the kerberos > tools. Not sure why this isn't there and the first-run scripts don't > regenerate the kerberos stuff either so that explains why the > authorization > fails. > > I wonder why the kerberos subsystem got screwed up because I followed the > instruction exactly and got no errors during the installation. Everything > looked fine until I actually ran the appliance. > > Regards, > Dennis > > Susan Burgess wrote: >> Hi Dennis >> >> I just had the same problem, same message for an appliance that has been >> working fine for days. >> Try restarting the system and then start up developer and node3. Wait a >> while before trying to get the appliance up. >> Make sure you are not root when you give the ssh -Y etc command. >> >> Either the abvove worked, or the server was down and is now up :-[ . >> Don't know. but my appliance is now working. >> >> Good luck, >> Susan >> >> >> >> Dennis Jacobfeuerborn wrote: >>> Hi, >>> I wanted to start playing with ovirt so I installed the developer >>> version following the instructions on this page: >>> http://ovirt.org/devel-install.html >>> >>> The installation finished without problems but when I start firefox on >>> the guest according to step 5 I get the following message in the >>> browser: >>> >>> Authorization Required >>> This server could not verify that you are authorized to access the >>> document requested. Either you supplied the wrong credentials (e.g., >>> bad password), or your browser doesn't understand how to supply the >>> credentials required. >>> >>> How exactly does the browser get authorized with the server and does >>> anybody have an idea why this isn't working? >>> >>> I used the F8 boot.iso for the installation because that's what the >>> instructions mention but would a F9 iso be ok too or would the setup >>> scripts get into trouble with a different distribution? >>> >>> Regards, >>> Dennis >>> >>> _______________________________________________ >>> Ovirt-devel mailing list >>> Ovirt-devel at redhat.com >>> https://www.redhat.com/mailman/listinfo/ovirt-devel >> > > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel -- Susan Burgess Content Author Red Hat APAC Level 1, 193 North Quay Brisbane, QLD 4000 Australia Phone +61 7 3514 8179 Fax +61 7 3514 8199 Mail sburgess at redhat.com From slinabery at gmail.com Fri May 9 04:01:01 2008 From: slinabery at gmail.com (steve linabery) Date: Thu, 8 May 2008 23:01:01 -0500 Subject: [Ovirt-devel] [PATCH] make taskomatic.rb robust to database outages Message-ID: <769584de0805082101u5401a8aft9698ded051984c50@mail.gmail.com> Hi ovirt, En route to transaction support, and being of the "if it ain't broke, break it!" school of code spelunking, I noticed that taskomatic.rb dies if one stops postgresql on the appliance. So I offer this first attempt at making taskomatic.rb handle this situation somewhat more gracefully. Key points: 0) move 'require dutils' above the call to daemonize, so that the script will Fail outright if a connection cannot be established before daemonization (not sure about this one really, but I thought the sysadmin doing 'service ovirt-taskomatic start' would like to know immediately that it was failing). 1) use ruby exception handling and extremely rudimentary logging for exceptions in Task.find section. 2) wrap the entire 'case task.action' block (and the following Task state updates) in a begin/rescue. This is meant as a first step toward isolating/handling the many exceptions that can be raised by these statements. I am VERY open to feedback/suggestions on this; in particular, the logging (does anyone know off-hand how to log line numbers in this type of situation?), and making the script fail to start with the init script if the DB appears unavailable (maybe it should just go daemon and keep polling for a connection while logging its error?). Oh, and I use the 'database_connect' method from active_record_env.rb for the case (not sure if it can be reached) where ActiveRecord shows that it's not connected (note: this seems to mean something different from "there's no currently-functioning connection to the db"). I've tested this with database halts before and during execution, and also restarting database during execution. Works for me. Thanks, Steve -------------- next part -------------- A non-text attachment was scrubbed... Name: safe_taskomatic.patch Type: text/x-patch Size: 3013 bytes Desc: not available URL: From imain at redhat.com Fri May 9 04:31:23 2008 From: imain at redhat.com (Ian Main) Date: Thu, 8 May 2008 21:31:23 -0700 Subject: [Ovirt-devel] [PATCH] Host Status Patches Message-ID: <20080508213123.67ab027a@tp.mains.net> A few comments first: There will likely be some fallout from this for the UI and maybe some vm task modifications. This has had some light testing but may still have issues. I just want to get it out there so we can work together to wrap this up. This was developed and tested on 0.4 and then moved to tip but was having problems getting it running. I'll test it more on tip in the morning. --- This patch gets host-status working properly and adds a new STATE_UNREACHABLE to the VM states. This state is set when a managed host with VMs is no longer reachable and we're not sure if it died or fell off the network. Once the host is back up the actual state of the VMs can be inferred and taskomatic will be informed. Signed-off-by: Ian Main diff --git a/wui/src/app/models/vm.rb b/wui/src/app/models/vm.rb index 197ca9c..d5866cc 100644 --- a/wui/src/app/models/vm.rb +++ b/wui/src/app/models/vm.rb @@ -41,6 +41,8 @@ class Vm < ActiveRecord::Base STATE_CREATING = "creating" STATE_RUNNING = "running" + STATE_UNREACHABLE = "unreachable" + STATE_STOPPING = "stopping" STATE_STOPPED = "stopped" STATE_STARTING = "starting" @@ -65,6 +67,7 @@ class Vm < ActiveRecord::Base STATE_RESTORING] EFFECTIVE_STATE = { STATE_PENDING => STATE_PENDING, + STATE_UNREACHABLE => STATE_UNREACHABLE, STATE_CREATING => STATE_STOPPED, STATE_RUNNING => STATE_RUNNING, STATE_STOPPING => STATE_STOPPED, diff --git a/wui/src/host-status/host-status.rb b/wui/src/host-status/host-status.rb index 5063197..e77087e 100755 --- a/wui/src/host-status/host-status.rb +++ b/wui/src/host-status/host-status.rb @@ -58,19 +58,34 @@ end # connects to the db in here require 'dutils' - -def findHost(vm) - host = Host.find(:first, :conditions => [ "id = ?", vm.host_id]) - - if host == nil - # Hm, we didn't find the host_id. Seems odd. Return a failure - raise +def check_state(vm, dom_info) + case dom_info.state + + when Libvirt::Domain::NOSTATE, Libvirt::Domain::SHUTDOWN, + Libvirt::Domain::SHUTOFF, Libvirt::Domain::CRASHED then + if Vm::RUNNING_STATES.include?(vm.state) + # OK, the host thinks this VM is off, while the database thinks it + # is running; we have to kick taskomatic + kick_taskomatic(Vm::STATE_STOPPED, vm) + end + when Libvirt::Domain::RUNNING, Libvirt::Domain::BLOCKED then + if not Vm::RUNNING_STATES.include?(vm.state) + # OK, the host thinks this VM is running, but it's not marked as running + # in the database; kick taskomatic + kick_taskomatic(Vm::STATE_RUNNING, vm) + end + when Libvirt::Domain::PAUSED then + if vm.state != Vm::STATE_SUSPENDING and vm.state != Vm::STATE_SUSPENDED + kick_taskomatic(Vm::STATE_SUSPENDED, vm) + end + else + puts "Unknown vm state...skipping" end - - return host end + def kick_taskomatic(msg, vm) + print "Kicking taskomatic, state is %s\n" % msg task = VmTask.new task.user = "host-status" task.action = VmTask::ACTION_UPDATE_STATE_VM @@ -86,59 +101,89 @@ loop do puts "Waking up to check host status" get_credentials - # FIXME: this only monitors hosts that have VMs running that *we* started. - # We might want to enhance this to look at all hosts that we are capable - # of contacting, just to check that rogue guests didn't get started. - vms = Vm.find(:all, :conditions => [ "host_id is NOT NULL" ]) - vms.each do |vm| - host = findHost(vm) + hosts = Host.find(:all) + hosts.each do |host| + + puts "checking host" + host.hostname begin conn = Libvirt::open("qemu+tcp://" + host.hostname + "/system") rescue - # we couldn't contact the host for whatever reason; we'll try again - # on the next iteration - puts "Failed to contact host " + host.hostname + "; skipping for now" + # we couldn't contact the host for whatever reason. Since we can't get to this + # host, we have to mark all vms on it as disconnected or stopped or such. + puts "Failed to contact host " + host.hostname + "; skipping for now", $! + vms = Vm.find(:all, :conditions => [ "host_id = ?", host.id ]) + vms.each do |vm| + # Since we can't reach the host on which the vms reside, we mark these as + # STATE_UNREACHABLE. If they come back up we can mark them as running again, + # else they'll be stopped. At least for now the user will know what's going on. + kick_taskomatic(Vm::STATE_UNREACHABLE, vm) + end + next end begin - dom = conn.lookup_domain_by_uuid(vm.uuid) + vm_ids = conn.list_domains rescue - # OK. We couldn't find the UUID that we thought was there. The only - # explanation is that the domain is no longer there. Kick taskomatic - # and tell it - puts "Failed to find domain " + vm.description - kick_taskomatic(Vm::STATE_STOPPED, vm) + puts "Failed to request domain list on host " + host.hostname conn.close next end - info = dom.info - conn.close - - case info.state - when Libvirt::Domain::NOSTATE, Libvirt::Domain::SHUTDOWN, - Libvirt::Domain::SHUTOFF, Libvirt::Domain::CRASHED then - if Vm::RUNNING_STATES.include?(vm.state) - # OK, the host thinks this VM is off, while the database thinks it - # is running; we have to kick taskomatic - kick_taskomatic(Vm::STATE_STOPPED, vm) + + puts vm_ids.length + + # Here we're going through every vm listed through libvirt. This + # really only lets us find ones that are started that shouldn't be. + vm_ids.each do |vm_id| + puts "VM ID: %d" % [vm_id] + begin + dom = conn.lookup_domain_by_id(vm_id) + rescue + puts "Failed to find domain " + vm.description + next end - when Libvirt::Domain::RUNNING, Libvirt::Domain::BLOCKED then - if not Vm::RUNNING_STATES.include?(vm.state) - # OK, the host thinks this VM is running, but it's not marked as running - # in the database; kick taskomatic - kick_taskomatic(Vm::STATE_RUNNING, vm) + + vm_uuid = dom.uuid + info = dom.info + + puts "VM UUID: %s" % [vm_uuid] + info = dom.info + puts info.to_s + + vm = Vm.find(:first, :conditions => [ "uuid = ?", vm_uuid ]) + if vm == nil + puts "VM Not found in database, must be created by user. giving up." + next end - when Libvirt::Domain::PAUSED then - if vm.state != Vm::STATE_SUSPENDING and vm.state != Vm::STATE_SUSPENDED - kick_taskomatic(Vm::STATE_SUSPENDED, vm) + + check_state(vm, info) + end + + # Now we get a list of all vms that should be on this system and see if + # they are all running. + vms = Vm.find(:all, :conditions => [ "host_id = ?", host.id ]) + vms.each do |vm| + + begin + dom = conn.lookup_domain_by_uuid(vm.uuid) + rescue + # OK. We couldn't find the UUID that we thought was there. The only + # explanation is that the domain is dead. + puts "Failed to find domain " + vm.description + kick_taskomatic(Vm::STATE_STOPPED, vm) + next end - else - puts "Unknown vm state...skipping" + info = dom.info + check_state(vm, info) + + conn.close + end end STDOUT.flush sleep sleeptime end + + diff --git a/wui/src/task-omatic/task_vm.rb b/wui/src/task-omatic/task_vm.rb index 6c63f48..29bcb1f 100644 --- a/wui/src/task-omatic/task_vm.rb +++ b/wui/src/task-omatic/task_vm.rb @@ -633,6 +633,10 @@ end def update_state_vm(task) puts "update_state_vm" + # NOTE: findVM() will only return a vm if all the host information is filled + # in. So if a vm that we thought was stopped is running, this returns nil + # and we don't update any information about it. The tricky part + # is that we're still not sure what to do in this case :). - Ian begin vm = findVM(task) rescue From jim at meyering.net Fri May 9 07:05:07 2008 From: jim at meyering.net (Jim Meyering) Date: Fri, 09 May 2008 09:05:07 +0200 Subject: [Ovirt-devel] [PATCH] split ovirt-wui into separate scripts In-Reply-To: <769584de0805081005y7dd4a48bgbd8d668253c48563@mail.gmail.com> (steve linabery's message of "Thu, 8 May 2008 12:05:16 -0500") References: <769584de0805071344y39bbae52xc671660f9baae2f8@mail.gmail.com> <87wsm4vk1t.fsf@rho.meyering.net> <769584de0805080939g2efe9196l52de0911441fe65a@mail.gmail.com> <769584de0805081005y7dd4a48bgbd8d668253c48563@mail.gmail.com> Message-ID: <87zlr02c0s.fsf@rho.meyering.net> "steve linabery" wrote: >> Third time charm? >> >> I also pulled out the mongrel_rails executable name, since having it >> down there in the status line was making me nervous. >> >> Good day, >> Steve >> > With odd artifacts removed from head of file. Hi Steve, I'll be happy to apply that, but it's far easier for me if it's in "git am" format. I.e., Please send it one more time, but this time, commit it first, with a descriptive log entry, and then run this: git format-patch --stdout --signoff HEAD~1 > PATCH Then send PATCH as an attachment. Actually, sending it in-line is ok, too, but then you have to be careful to change the first line to protect it from mangling by mailman: s/From />From /. From slinabery at gmail.com Fri May 9 14:17:11 2008 From: slinabery at gmail.com (steve linabery) Date: Fri, 9 May 2008 09:17:11 -0500 Subject: [Ovirt-devel] [PATCH] split ovirt-wui into separate scripts In-Reply-To: <87zlr02c0s.fsf@rho.meyering.net> References: <769584de0805071344y39bbae52xc671660f9baae2f8@mail.gmail.com> <87wsm4vk1t.fsf@rho.meyering.net> <769584de0805080939g2efe9196l52de0911441fe65a@mail.gmail.com> <769584de0805081005y7dd4a48bgbd8d668253c48563@mail.gmail.com> <87zlr02c0s.fsf@rho.meyering.net> Message-ID: <769584de0805090717x6b933714y345ca7d215b3d301@mail.gmail.com> On Fri, May 9, 2008 at 2:05 AM, Jim Meyering wrote: > "steve linabery" wrote: >>> Third time charm? >>> >>> I also pulled out the mongrel_rails executable name, since having it >>> down there in the status line was making me nervous. >>> >>> Good day, >>> Steve >>> >> With odd artifacts removed from head of file. > > Hi Steve, > > I'll be happy to apply that, but it's far easier for me > if it's in "git am" format. I.e., > Please send it one more time, but this time, commit it first, > with a descriptive log entry, and then run this: > > git format-patch --stdout --signoff HEAD~1 > PATCH > > Then send PATCH as an attachment. > Actually, sending it in-line is ok, too, but then you have to be > careful to change the first line to protect it from mangling by > mailman: s/From />From /. > Hi Jim, Thanks as always for sharing the git knowledge. Here's the revised patch file. I'm sticking with attachments since I'm on gmail ATM. Good day, Steve -------------- next part -------------- A non-text attachment was scrubbed... Name: daemonsplit.patch Type: text/x-patch Size: 11689 bytes Desc: not available URL: From apevec at redhat.com Fri May 9 15:21:51 2008 From: apevec at redhat.com (Alan Pevec) Date: Fri, 09 May 2008 17:21:51 +0200 Subject: [Fwd: Re: [Ovirt-devel] Problem with developer installation] In-Reply-To: <4823BAA8.4060204@conversis.de> References: <4823BAA8.4060204@conversis.de> Message-ID: <48246C0F.5030900@redhat.com> Dennis Jacobfeuerborn wrote: > I haven't tried to start any additional nodes yet to keep the possible > problem sources limited. After taking a closer look at the init scripts and > logfiles and doing some strace'ing it looks like I'm missing the file > /var/kerberos/krb5kdc/principal which seems to be vital for the kerberos > tools. Not sure why this isn't there and the first-run scripts don't > regenerate the kerberos stuff either so that explains why the authorization > fails. I guess ipa-server-install is failing on first boot, check /var/log/ipaserver-install.log in the appliance. I'm looking at this issue now. From sseago at redhat.com Fri May 9 17:23:18 2008 From: sseago at redhat.com (Scott Seago) Date: Fri, 09 May 2008 13:23:18 -0400 Subject: [Ovirt-devel] [PATCH] Host Status Patches In-Reply-To: <20080508213123.67ab027a@tp.mains.net> References: <20080508213123.67ab027a@tp.mains.net> Message-ID: <48248886.60901@redhat.com> Ian Main wrote: > A few comments first: > > There will likely be some fallout from this for the UI and maybe some vm task modifications. This has had some light testing but may still have issues. I just want to get it out there so we can work together to wrap this up. > > This was developed and tested on 0.4 and then moved to tip but was having problems getting it running. I'll test it more on tip in the morning. > > --- > > This patch gets host-status working properly and adds a new STATE_UNREACHABLE to the VM states. This state is set when a managed host with VMs is no longer reachable and we're not sure if it died or fell off the network. Once the host is back up the actual state of the VMs can be inferred and taskomatic will be informed. > > Signed-off-by: Ian Main > I guess we'll need to work out how to handle this on the UI. If we're planning on letting users "stop" unreachable VMs, then we'll want to add this to the VALID_ACTIONS_PER_VM_STATE hash in vm_task.rb -- if this should be an admin-only function, then we will need to work out the permission/role rules for this and where it will go in the UI. Other than that, this looks OK from the model side of things. Scott From sseago at redhat.com Fri May 9 17:47:57 2008 From: sseago at redhat.com (Scott Seago) Date: Fri, 09 May 2008 13:47:57 -0400 Subject: [Ovirt-devel] PATCH: Fix broken test fixtures from my patches yesterday In-Reply-To: <200805081109.11914.dpierce@redhat.com> References: <200805081109.11914.dpierce@redhat.com> Message-ID: <48248E4D.8010408@redhat.com> Darryl L. Pierce wrote: > ------------------------------------------------------------------------ > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel These look fine to me. We'll need to start pulling ldap stuff from the DNS SRV records as soon as we can, but the static yml file (which we'll always need as a fallback anyway) is probably good enough for now. Scott From slinabery at gmail.com Sat May 10 03:22:42 2008 From: slinabery at gmail.com (steve linabery) Date: Fri, 9 May 2008 22:22:42 -0500 Subject: [Ovirt-devel] Re: [PATCH] make taskomatic.rb robust to database outages In-Reply-To: <769584de0805082101u5401a8aft9698ded051984c50@mail.gmail.com> References: <769584de0805082101u5401a8aft9698ded051984c50@mail.gmail.com> Message-ID: <769584de0805092022p1501c4ffoc8a3ca2d177845de@mail.gmail.com> On Thu, May 8, 2008 at 11:01 PM, steve linabery wrote: > Hi ovirt, > > En route to transaction support, and being of the "if it ain't broke, > break it!" school of code spelunking, I noticed that taskomatic.rb > dies if one stops postgresql on the appliance. > > So I offer this first attempt at making taskomatic.rb handle this > situation somewhat more gracefully. > > Key points: > 0) move 'require dutils' above the call to daemonize, so that the > script will Fail outright if a connection cannot be established before > daemonization (not sure about this one really, but I thought the > sysadmin doing 'service ovirt-taskomatic start' would like to know > immediately that it was failing). > 1) use ruby exception handling and extremely rudimentary logging for > exceptions in Task.find section. > 2) wrap the entire 'case task.action' block (and the following Task > state updates) in a begin/rescue. This is meant as a first step toward > isolating/handling the many exceptions that can be raised by these > statements. > > I am VERY open to feedback/suggestions on this; in particular, the > logging (does anyone know off-hand how to log line numbers in this > type of situation?), and making the script fail to start with the init > script if the DB appears unavailable (maybe it should just go daemon > and keep polling for a connection while logging its error?). > > Oh, and I use the 'database_connect' method from active_record_env.rb > for the case (not sure if it can be reached) where ActiveRecord shows > that it's not connected (note: this seems to mean something different > from "there's no currently-functioning connection to the db"). > > I've tested this with database halts before and during execution, and > also restarting database during execution. Works for me. > > Thanks, > Steve > Hmm, I see from the libvirt list that perhaps I should have called this "RFC" rather than "Patch", since I don't really mean it's ready for commit, but rather I'm looking for some feedback on it. So, feedback at will. Thanks, Steve From mmorsi at redhat.com Mon May 12 15:26:05 2008 From: mmorsi at redhat.com (Mohammed Morsi) Date: Mon, 12 May 2008 11:26:05 -0400 Subject: [Ovirt-devel] Fwd: (Jay's) [PATCH] graph stuff Message-ID: <4828618D.2010007@redhat.com> Just forwarding Jay's patch for the graphing stuff to ovirt-devel. All changes in the patch are his, I take no credit (or responsibility) for anything there. He also included the following message in a subsequent email, "Forgot that because of my hacked application,rb, that a change didn't go in the patch. On 31, it should be: before_filter :pre_show, :only => [:show, :show_vms, :show_users, :show_hosts, :show_storage, :show_graphs] so the perms work." -Mo -------------- next part -------------- A non-text attachment was scrubbed... Name: graphs.patch Type: text/x-patch Size: 256379 bytes Desc: not available URL: From movitto at yahoo.com Mon May 12 15:31:28 2008 From: movitto at yahoo.com (M. Morsi) Date: Mon, 12 May 2008 08:31:28 -0700 (PDT) Subject: [Ovirt-devel] Fwd: (jay's) [PATCH] graph stuff Message-ID: <497380.65100.qm@web65404.mail.ac4.yahoo.com> Just forwarding Jay's patch for the graphing stuff to ovirt-devel. All changes in the patch are his, I take no credit (or responsibility) for anything there. He also included the following message in a subsequent email, "Forgot that because of my hacked application,rb, that a change didn't go in the patch. On 31, it should be: before_filter :pre_show, :only => [:show, :show_vms, :show_users, :show_hosts, :show_storage, :show_graphs] so the perms work." -Mo ____________________________________________________________________________________ Be a better friend, newshound, and know-it-all with Yahoo! Mobile. Try it now. http://mobile.yahoo.com/;_ylt=Ahu06i62sR8HDtDypao8Wcj9tAcJ -------------- next part -------------- A non-text attachment was scrubbed... Name: graphs.patch Type: application/octet-stream Size: 256379 bytes Desc: 1405688742-graphs.patch URL: From sseago at redhat.com Mon May 12 16:26:00 2008 From: sseago at redhat.com (Scott Seago) Date: Mon, 12 May 2008 12:26:00 -0400 Subject: [Ovirt-devel] [Patch] Message-ID: <48286F98.8030109@redhat.com> Force table widget to single-select mode; add checkboxes to host lists Make host selection popop work, and 'remove host' link works now too. -------------- next part -------------- A non-text attachment was scrubbed... Name: host-table-and-popup.patch Type: text/x-patch Size: 25595 bytes Desc: not available URL: From sseago at redhat.com Mon May 12 19:09:55 2008 From: sseago at redhat.com (Scott Seago) Date: Mon, 12 May 2008 15:09:55 -0400 Subject: [Ovirt-devel] [Patch] table widget and popup enhancements, take 2 In-Reply-To: <48286F98.8030109@redhat.com> References: <48286F98.8030109@redhat.com> Message-ID: <48289603.5060901@redhat.com> Scott Seago wrote: > Force table widget to single-select mode; add checkboxes to host lists > > Make host selection popop work, and 'remove host' link works now too. > Hopefully the patch works this time. Scott -------------- next part -------------- A non-text attachment was scrubbed... Name: host-table-and-popup.patch Type: text/x-patch Size: 28407 bytes Desc: not available URL: From mmorsi at redhat.com Mon May 12 20:01:58 2008 From: mmorsi at redhat.com (Mohammed Morsi) Date: Mon, 12 May 2008 16:01:58 -0400 Subject: [Ovirt-devel] [Patch] Various Interface Additions Message-ID: <4828A236.9060306@redhat.com> This patch incorporates the following changes: * Hi, username is readded (currently a link pointing to nothing) * Div / style adjusted so absolute positioning doesn't prevent user from clicking 'hi, username', search box, or help links * Wired help link up (action still needs to be defined and implemented) * Wired up buttons at the bottom of the tree navigation * Menu widget, right now done in css and is very easy to use where needed in the site. Currently the 'move hosts' menu is implemented (though the actual items don't point to anything useful yet) * Added an IE only css (right now oVirt is horribly broken in IE, this css file will be monumental in fixing that) * Organized the css files a bit more (would like to keep general layout stuff in layout.css, individual component styling in component.css if possible) - Mo -------------- next part -------------- A non-text attachment was scrubbed... Name: navtoolbar.patch Type: text/x-patch Size: 9876 bytes Desc: not available URL: From mmorsi at redhat.com Mon May 12 20:56:49 2008 From: mmorsi at redhat.com (Mohammed Morsi) Date: Mon, 12 May 2008 16:56:49 -0400 Subject: [Ovirt-devel] [Patch] Various Interface Additions In-Reply-To: <4828A236.9060306@redhat.com> References: <4828A236.9060306@redhat.com> Message-ID: <4828AF11.40605@redhat.com> Few various fixes based on feedback, mostly relating to image urls in css and links in header -------------- next part -------------- A non-text attachment was scrubbed... Name: navtoolbar.patch Type: text/x-patch Size: 9898 bytes Desc: not available URL: From hbrock at redhat.com Mon May 12 21:14:34 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Mon, 12 May 2008 17:14:34 -0400 Subject: [Ovirt-devel] [Patch] Various Interface Additions In-Reply-To: <4828AF11.40605@redhat.com> References: <4828A236.9060306@redhat.com> <4828AF11.40605@redhat.com> Message-ID: <20080512211433.GO16435@redhat.com> On Mon, May 12, 2008 at 04:56:49PM -0400, Mohammed Morsi wrote: > Few various fixes based on feedback, mostly relating to image urls in css > and links in header > diff --git a/wui/src/app/controllers/hardware_controller.rb b/wui/src/app/controllers/hardware_controller.rb > index cd069c7..a9e66a0 100644 > --- a/wui/src/app/controllers/hardware_controller.rb > +++ b/wui/src/app/controllers/hardware_controller.rb > @@ -72,6 +72,7 @@ class HardwareController < ApplicationController > > def show_hosts > show > + @hardware_pools = HardwarePool.find :all > end > Give it to me one more time, but without trailing blanks? Also check for lines > 80 chars (outside of the HTML where I think that is probably unenforceable). Thanks, --Hugh From mmorsi at redhat.com Mon May 12 21:39:07 2008 From: mmorsi at redhat.com (Mohammed Morsi) Date: Mon, 12 May 2008 17:39:07 -0400 Subject: [Ovirt-devel] [Patch] Various Interface Additions In-Reply-To: <20080512211433.GO16435@redhat.com> References: <4828A236.9060306@redhat.com> <4828AF11.40605@redhat.com> <20080512211433.GO16435@redhat.com> Message-ID: <4828B8FB.5030909@redhat.com> > Give it to me one more time, but without trailing blanks? > > Also check for lines > 80 chars (outside of the HTML where I think that is probably unenforceable). > > Thanks, > --Hugh > Removed alot of whitespace, hope this does it. No changes in the .rb files > 80 width. -Mo -------------- next part -------------- A non-text attachment was scrubbed... Name: navtoolbar.patch Type: text/x-patch Size: 10186 bytes Desc: not available URL: From hbrock at redhat.com Mon May 12 21:57:51 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Mon, 12 May 2008 17:57:51 -0400 Subject: [Ovirt-devel] [Patch] Various Interface Additions In-Reply-To: <4828B8FB.5030909@redhat.com> References: <4828A236.9060306@redhat.com> <4828AF11.40605@redhat.com> <20080512211433.GO16435@redhat.com> <4828B8FB.5030909@redhat.com> Message-ID: <20080512215750.GQ16435@redhat.com> On Mon, May 12, 2008 at 05:39:07PM -0400, Mohammed Morsi wrote: > >> Give it to me one more time, but without trailing blanks? >> >> Also check for lines > 80 chars (outside of the HTML where I think that is probably unenforceable). >> >> Thanks, >> --Hugh >> > > Removed alot of whitespace, hope this does it. No changes in the .rb files > > 80 width. > > -Mo > diff --git a/wui/src/app/controllers/hardware_controller.rb b/wui/src/app/controllers/hardware_controller.rb > index cd069c7..a9e66a0 100644 > --- a/wui/src/app/controllers/hardware_controller.rb > +++ b/wui/src/app/controllers/hardware_controller.rb > @@ -72,6 +72,7 @@ class HardwareController < ApplicationController > > def show_hosts > show > + @hardware_pools = HardwarePool.find :all > end > > def hosts_json > diff --git a/wui/src/app/views/hardware/show_hosts.rhtml b/wui/src/app/views/hardware/show_hosts.rhtml > index 79b8ef6..e2ac3f5 100644 > --- a/wui/src/app/views/hardware/show_hosts.rhtml > +++ b/wui/src/app/views/hardware/show_hosts.rhtml > @@ -1,8 +1,28 @@ > - > +
> > +<%= render :partial => "/user/show", :locals => { :parent_controller => "hardware", + :pool_id => @pool.id } %> diff --git a/wui/src/app/views/hardware/show_vms.rhtml b/wui/src/app/views/hardware/show_vms.rhtml index 0d91421..407b80c 100644 --- a/wui/src/app/views/hardware/show_vms.rhtml +++ b/wui/src/app/views/hardware/show_vms.rhtml @@ -1,9 +1,32 @@ +
diff --git a/wui/src/app/views/permission/new.rhtml b/wui/src/app/views/permission/new.rhtml index f1b99f1..f2b129f 100644 --- a/wui/src/app/views/permission/new.rhtml +++ b/wui/src/app/views/permission/new.rhtml @@ -1,43 +1,35 @@ -
-
+
+
Add New User
+
Add a new user to <%= @permission.pool.name %> pool.
+
+ +
+
+ <%= render :partial => 'form' %> +
+
) repeat-x; height: 37px; text-align:right; padding: 9px 9px 0 0;"> +
" alt="Create User Permission" /> + <%=image_tag "btn_cancel.png", :title=>"Cancel" %> +
+
+
+ -
- -
-
- -
- <% form_tag :action => 'create' do %> - <%= render :partial => 'form' %> - <%= submit_tag "Add User" %> - <% end %> -
- -
-

Existing Users

- <%= render :partial => "/permission/list", :locals => { :permissions => @perms, :show_object => false, :show_actions => @can_view } %> -
- -
-
- -
- -
-
- - - -
 
-
- -

Actions

-
- <%= link_to "Back to #{@permission.pool.name}", { :controller => @permission.pool.get_controller, :action => 'show', :id => @permission.pool_id }, { :class => "show" } %> -
-
- - <%- content_for :title do -%> <%= "Edit Permissions for #{@permission.pool.name}" %> <%- end -%> diff --git a/wui/src/app/views/resources/_form.rhtml b/wui/src/app/views/resources/_form.rhtml index 1a09872..0f9fa9f 100644 --- a/wui/src/app/views/resources/_form.rhtml +++ b/wui/src/app/views/resources/_form.rhtml @@ -1,11 +1,7 @@ <%= error_messages_for 'vm_resource_pool' %> -<%= hidden_field_tag_with_label ((@parent[:type] == HardwarePool.name) ? - "Hardware Pool" : "Parent VM Resource Pool"), - 'parent_id', @parent.id, @parent.name %> - +<%= hidden_field_tag 'parent_id', @parent.id %> <%= text_field_with_label "Name", 'vm_resource_pool', 'name' %> - diff --git a/wui/src/app/views/resources/new.rhtml b/wui/src/app/views/resources/new.rhtml index 0dbb165..c142fe7 100644 --- a/wui/src/app/views/resources/new.rhtml +++ b/wui/src/app/views/resources/new.rhtml @@ -1,42 +1,34 @@ -
-
- -
- -
-
- -
- <% form_tag :action => 'create' do %> - <%= render :partial => 'form' %> - <%= submit_tag "Create" %> - <% end %> -
- -
- Current VM Resource Pools (<%= @vm_resource_pools.size %>) - <% for resource in @vm_resource_pools %> -
<%= link_to resource.name, { :controller => "resources", :action => "show", :id => resource }, { } %>
- <% end %> -
- -
- -
-
- - - -
 
-
-

Actions

-
-
<%= link_to "back to #{@parent.name}", { :controller => @parent.get_controller, :action => 'show', :id => @parent }, { :class => "" } %>
-
-
- - - +
+
Add New Virtual Machine Pool
+
Add a new Virtual Machine Pool to the <%= @parent.name %> pool.
+
+ +
+
+ <%= render :partial => 'form' %> +
+
) repeat-x; height: 37px; text-align:right; padding: 9px 9px 0 0;"> + +
+
+ <%- content_for :title do -%> <%= _("New VM Resource Pool") %> diff --git a/wui/src/app/views/resources/show_users.rhtml b/wui/src/app/views/resources/show_users.rhtml index fb2fae9..02a1feb 100644 --- a/wui/src/app/views/resources/show_users.rhtml +++ b/wui/src/app/views/resources/show_users.rhtml @@ -1,31 +1,2 @@ - - -
-
- -
- +<%= render :partial => "/user/show", :locals => { :parent_controller => "resources", + :pool_id => @vm_resource_pool.id } %> diff --git a/wui/src/app/views/resources/show_vms.rhtml b/wui/src/app/views/resources/show_vms.rhtml index 98711cf..5f758aa 100644 --- a/wui/src/app/views/resources/show_vms.rhtml +++ b/wui/src/app/views/resources/show_vms.rhtml @@ -5,47 +5,48 @@ <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %>  Actions    <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %>
    <% @actions.each_index { |index| %> -
  • +
  • style="border-bottom: 1px solid black;" <% end %> > - <%= @actions[index] %> + <%=@actions[index][0]%>
  • <% } %>
-
  • <%= image_tag "icon_delete_white.png", :style => "vertical-align:middle;" %>  Delete
  • +
  • <%= image_tag "icon_delete_white.png", :style => "vertical-align:middle;" %>  Delete
  • +
    - + <%= render :partial => "/vm/grid", :locals => { :table_id => "vms_grid", + :pool_id => @vm_resource_pool.id } %>
    -
    Host Name
    Host description goes here if we allow a description.
    diff --git a/wui/src/app/views/user/_change_role_menu.rhtml b/wui/src/app/views/user/_change_role_menu.rhtml index b33ba00..f35cd3b 100644 --- a/wui/src/app/views/user/_change_role_menu.rhtml +++ b/wui/src/app/views/user/_change_role_menu.rhtml @@ -1,13 +1,12 @@ <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %>  Change Role    <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %>
      <% @roles.each_index { |index| %> - -
    • style="border-bottom: 1px solid black;" <% end %> > - <%= @roles[index] %> + <%=@roles[index]%>
    • <% } %>
    diff --git a/wui/src/app/views/user/_grid.rhtml b/wui/src/app/views/user/_grid.rhtml new file mode 100644 index 0000000..24a7b86 --- /dev/null +++ b/wui/src/app/views/user/_grid.rhtml @@ -0,0 +1,30 @@ +
    +
    + +
    +
    + diff --git a/wui/src/app/views/user/_show.rhtml b/wui/src/app/views/user/_show.rhtml new file mode 100644 index 0000000..348e47b --- /dev/null +++ b/wui/src/app/views/user/_show.rhtml @@ -0,0 +1,46 @@ + + + +
    +
    + <%= render :partial => "/user/grid", :locals => { :table_id => "users_grid", + :parent_controller => parent_controller, + :pool_id => pool_id } %> + +
    diff --git a/wui/src/app/views/vm/_grid.rhtml b/wui/src/app/views/vm/_grid.rhtml new file mode 100644 index 0000000..55f9d9b --- /dev/null +++ b/wui/src/app/views/vm/_grid.rhtml @@ -0,0 +1,34 @@ +
    +
    + +
    +
    + diff --git a/wui/src/public/stylesheets/components.css b/wui/src/public/stylesheets/components.css index bef30a2..489dd48 100644 --- a/wui/src/public/stylesheets/components.css +++ b/wui/src/public/stylesheets/components.css @@ -111,3 +111,13 @@ text-align: left; cursor: pointer; } +#toolbar_nav ul ul li a{ + width: 200px; + background: #E5F1FD; + color: #000000; + text-align: left; + cursor: pointer; +} +#toolbar_nav ul ul li:hover a { + background: #1E99DF; +} -- 1.5.4.1 From sseago at kodiak.boston.redhat.com Thu May 15 21:42:59 2008 From: sseago at kodiak.boston.redhat.com (Scott Seago) Date: Thu, 15 May 2008 17:42:59 -0400 Subject: [Ovirt-devel] [PATCH] This patch hooks up the new/add form and change role pulldown for user permissions. Delete works for vms, vm pools, and user permissions. Pulldown for vms is done on the UI side, but the controller method isn't filled out yet. Message-ID: This stuff still needs permissiosn checks and proper validation/confirmation. Signed-off-by: Scott Seago --- wui/src/app/controllers/hardware_controller.rb | 2 +- wui/src/app/controllers/permission_controller.rb | 38 +++++++++++- wui/src/app/controllers/resources_controller.rb | 32 ++++++++-- wui/src/app/controllers/vm_controller.rb | 14 ++++ wui/src/app/views/hardware/show_users.rhtml | 33 +---------- wui/src/app/views/hardware/show_vms.rhtml | 27 ++++++++- wui/src/app/views/permission/new.rhtml | 70 ++++++++++------------ wui/src/app/views/resources/_form.rhtml | 6 +-- wui/src/app/views/resources/new.rhtml | 70 ++++++++++------------ wui/src/app/views/resources/show_users.rhtml | 33 +---------- wui/src/app/views/resources/show_vms.rhtml | 57 +++++++++--------- wui/src/app/views/user/_change_role_menu.rhtml | 5 +- wui/src/app/views/user/_grid.rhtml | 30 +++++++++ wui/src/app/views/user/_show.rhtml | 46 ++++++++++++++ wui/src/app/views/vm/_grid.rhtml | 34 +++++++++++ wui/src/public/stylesheets/components.css | 10 +++ 16 files changed, 320 insertions(+), 187 deletions(-) create mode 100644 wui/src/app/views/user/_grid.rhtml create mode 100644 wui/src/app/views/user/_show.rhtml create mode 100644 wui/src/app/views/vm/_grid.rhtml diff --git a/wui/src/app/controllers/hardware_controller.rb b/wui/src/app/controllers/hardware_controller.rb index 3379199..599d881 100644 --- a/wui/src/app/controllers/hardware_controller.rb +++ b/wui/src/app/controllers/hardware_controller.rb @@ -107,7 +107,7 @@ class HardwareController < ApplicationController def users_json json_list(@pool.permissions, - [:user, :user_role]) + [:id, :user, :user_role]) end def storage_pools_json diff --git a/wui/src/app/controllers/permission_controller.rb b/wui/src/app/controllers/permission_controller.rb index 68eb54d..9fe63d8 100644 --- a/wui/src/app/controllers/permission_controller.rb +++ b/wui/src/app/controllers/permission_controller.rb @@ -45,24 +45,58 @@ class PermissionController < ApplicationController flash[:notice] = 'You do not have permission to create this permission record' redirect_to_parent end + render :layout => 'popup' end def create @permission = Permission.new(params[:permission]) set_perms(@permission.pool) unless @can_set_perms + # FIXME: need to handle proper error messages w/ ajax flash[:notice] = 'You do not have permission to create this permission record' redirect_to_parent else if @permission.save - flash[:notice] = 'Permission was successfully created.' - redirect_to_parent + render :json => "created User Permissions for #{@permission.user}".to_json else + # FIXME: need to handle proper error messages w/ ajax render :action => 'new' end end end + #FIXME: we need permissions checks. user must have permission. We also need to fail + # for pools that aren't currently empty + def update_roles + role = params[:user_role] + permission_ids_str = params[:permission_ids] + permission_ids = permission_ids_str.split(",").collect {|x| x.to_i} + + Permission.transaction do + permissions = Permission.find(:all, :conditions => "id in (#{permission_ids.join(', ')})") + permissions.each do |permission| + permission.user_role = role + permission.save! + end + end + render :text => "deleted user permissions (#{permission_ids.join(', ')})" + end + + #FIXME: we need permissions checks. user must have permission. We also need to fail + # for pools that aren't currently empty + def delete + permission_ids_str = params[:permission_ids] + permission_ids = permission_ids_str.split(",").collect {|x| x.to_i} + + Permission.transaction do + permissions = Permission.find(:all, :conditions => "id in (#{permission_ids.join(', ')})") + permissions.each do |permission| + permission.destroy + end + end + render :text => "deleted user permissions (#{permission_ids.join(', ')})" + end + def destroy @permission = Permission.find(params[:id]) set_perms(@permission.pool) diff --git a/wui/src/app/controllers/resources_controller.rb b/wui/src/app/controllers/resources_controller.rb index 14499ab..68e3abe 100644 --- a/wui/src/app/controllers/resources_controller.rb +++ b/wui/src/app/controllers/resources_controller.rb @@ -58,7 +58,12 @@ class ResourcesController < ApplicationController # resource's vms list page def show_vms show - @actions = VmTask::ACTIONS.keys + @actions = [["Start", VmTask::ACTION_START_VM], + ["Shutdown", VmTask::ACTION_SHUTDOWN_VM, "break"], + ["Suspend", VmTask::ACTION_SUSPEND_VM], + ["Resume", VmTask::ACTION_RESUME_VM], + ["Save", VmTask::ACTION_SAVE_VM], + ["Restore", VmTask::ACTION_RESTORE_VM]] end # resource's users list page @@ -69,23 +74,23 @@ class ResourcesController < ApplicationController def vms_json json_list(@vm_resource_pool.vms, - [:description, :uuid, :num_vcpus_allocated, :memory_allocated_in_mb, :vnic_mac_addr, :state]) + [:id, :description, :uuid, :num_vcpus_allocated, :memory_allocated_in_mb, :vnic_mac_addr, :state]) end def users_json json_list(@vm_resource_pool.permissions, - [:user, :user_role]) + [:id, :user, :user_role]) end def new - @vm_resource_pools = @vm_resource_pool.self_and_like_siblings + render :layout => 'popup' end def create if @vm_resource_pool.create_with_parent(@parent) - flash[:notice] = 'VM Resource Pool was successfully created.' - redirect_to :controller => @vm_resource_pool.parent.get_controller, :action => 'show', :id => @vm_resource_pool.parent + render :json => "created new VM pool #{@vm_resource_pool.name}".to_json else + # FIXME: need to handle proper error messages w/ ajax render :action => 'new' end end @@ -102,6 +107,21 @@ class ResourcesController < ApplicationController end end + #FIXME: we need permissions checks. user must have permission. We also need to fail + # for pools that aren't currently empty + def delete + vm_pool_ids_str = params[:vm_pool_ids] + vm_pool_ids = vm_pool_ids_str.split(",").collect {|x| x.to_i} + + VmResourcePool.transaction do + pools = VmResourcePool.find(:all, :conditions => "id in (#{vm_pool_ids.join(', ')})") + pools.each do |pool| + pool.destroy + end + end + render :text => "deleted vm pools (#{vm_pool_ids.join(', ')})" + end + def destroy parent = @vm_resource_pool.parent @vm_resource_pool.destroy diff --git a/wui/src/app/controllers/vm_controller.rb b/wui/src/app/controllers/vm_controller.rb index ae6d437..4e4faf9 100644 --- a/wui/src/app/controllers/vm_controller.rb +++ b/wui/src/app/controllers/vm_controller.rb @@ -97,6 +97,20 @@ class VmController < ApplicationController end end + #FIXME: we need permissions checks. user must have permission. + def delete + vm_ids_str = params[:vm_ids] + vm_ids = vm_ids_str.split(",").collect {|x| x.to_i} + + Vm.transaction do + vms = Vm.find(:all, :conditions => "id in (#{vm_ids.join(', ')})") + vms.each do |vm| + vm.destroy + end + end + render :text => "deleted vms (#{vm_ids.join(', ')})" + end + def destroy vm_resource_pool = @vm.vm_resource_pool_id if ((@vm.state == Vm::STATE_STOPPED and @vm.get_pending_state == Vm::STATE_STOPPED) or diff --git a/wui/src/app/views/hardware/show_users.rhtml b/wui/src/app/views/hardware/show_users.rhtml index 2a5c9ee..abec65c 100644 --- a/wui/src/app/views/hardware/show_users.rhtml +++ b/wui/src/app/views/hardware/show_users.rhtml @@ -1,31 +1,2 @@ - - -
    -
    - -
    - +<%= render :partial => "/user/show", :locals => { :parent_controller => "hardware", + :pool_id => @pool.id } %> diff --git a/wui/src/app/views/hardware/show_vms.rhtml b/wui/src/app/views/hardware/show_vms.rhtml index 0d91421..407b80c 100644 --- a/wui/src/app/views/hardware/show_vms.rhtml +++ b/wui/src/app/views/hardware/show_vms.rhtml @@ -1,9 +1,32 @@ +
    diff --git a/wui/src/app/views/permission/new.rhtml b/wui/src/app/views/permission/new.rhtml index f1b99f1..f2b129f 100644 --- a/wui/src/app/views/permission/new.rhtml +++ b/wui/src/app/views/permission/new.rhtml @@ -1,43 +1,35 @@ -
    -
    +
    +
    Add New User
    +
    Add a new user to <%= @permission.pool.name %> pool.
    +
    + +
    +
    + <%= render :partial => 'form' %> +
    +
    ) repeat-x; height: 37px; text-align:right; padding: 9px 9px 0 0;"> +
    " alt="Create User Permission" /> + <%=image_tag "btn_cancel.png", :title=>"Cancel" %> +
    +
    +
    + -
    - -
    -
    - -
    - <% form_tag :action => 'create' do %> - <%= render :partial => 'form' %> - <%= submit_tag "Add User" %> - <% end %> -
    - -
    -

    Existing Users

    - <%= render :partial => "/permission/list", :locals => { :permissions => @perms, :show_object => false, :show_actions => @can_view } %> -
    - -
    -
    - -
    - -
    -
    - - - -
     
    -
    - -

    Actions

    -
    - <%= link_to "Back to #{@permission.pool.name}", { :controller => @permission.pool.get_controller, :action => 'show', :id => @permission.pool_id }, { :class => "show" } %> -
    -
    - - <%- content_for :title do -%> <%= "Edit Permissions for #{@permission.pool.name}" %> <%- end -%> diff --git a/wui/src/app/views/resources/_form.rhtml b/wui/src/app/views/resources/_form.rhtml index 1a09872..0f9fa9f 100644 --- a/wui/src/app/views/resources/_form.rhtml +++ b/wui/src/app/views/resources/_form.rhtml @@ -1,11 +1,7 @@ <%= error_messages_for 'vm_resource_pool' %> -<%= hidden_field_tag_with_label ((@parent[:type] == HardwarePool.name) ? - "Hardware Pool" : "Parent VM Resource Pool"), - 'parent_id', @parent.id, @parent.name %> - +<%= hidden_field_tag 'parent_id', @parent.id %> <%= text_field_with_label "Name", 'vm_resource_pool', 'name' %> - diff --git a/wui/src/app/views/resources/new.rhtml b/wui/src/app/views/resources/new.rhtml index 0dbb165..c142fe7 100644 --- a/wui/src/app/views/resources/new.rhtml +++ b/wui/src/app/views/resources/new.rhtml @@ -1,42 +1,34 @@ -
    -
    - -
    - -
    -
    - -
    - <% form_tag :action => 'create' do %> - <%= render :partial => 'form' %> - <%= submit_tag "Create" %> - <% end %> -
    - -
    - Current VM Resource Pools (<%= @vm_resource_pools.size %>) - <% for resource in @vm_resource_pools %> -
    <%= link_to resource.name, { :controller => "resources", :action => "show", :id => resource }, { } %>
    - <% end %> -
    - -
    - -
    -
    - - - -
     
    -
    -

    Actions

    -
    -
    <%= link_to "back to #{@parent.name}", { :controller => @parent.get_controller, :action => 'show', :id => @parent }, { :class => "" } %>
    -
    -
    - - - +
    +
    Add New Virtual Machine Pool
    +
    Add a new Virtual Machine Pool to the <%= @parent.name %> pool.
    +
    + +
    +
    + <%= render :partial => 'form' %> +
    +
    ) repeat-x; height: 37px; text-align:right; padding: 9px 9px 0 0;"> + +
    +
    + <%- content_for :title do -%> <%= _("New VM Resource Pool") %> diff --git a/wui/src/app/views/resources/show_users.rhtml b/wui/src/app/views/resources/show_users.rhtml index fb2fae9..02a1feb 100644 --- a/wui/src/app/views/resources/show_users.rhtml +++ b/wui/src/app/views/resources/show_users.rhtml @@ -1,31 +1,2 @@ - - -
    -
    - -
    - +<%= render :partial => "/user/show", :locals => { :parent_controller => "resources", + :pool_id => @vm_resource_pool.id } %> diff --git a/wui/src/app/views/resources/show_vms.rhtml b/wui/src/app/views/resources/show_vms.rhtml index 98711cf..5f758aa 100644 --- a/wui/src/app/views/resources/show_vms.rhtml +++ b/wui/src/app/views/resources/show_vms.rhtml @@ -5,47 +5,48 @@ <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %>  Actions    <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %>
      <% @actions.each_index { |index| %> -
    • +
    • style="border-bottom: 1px solid black;" <% end %> > - <%= @actions[index] %> + <%=@actions[index][0]%>
    • <% } %>
    -
  • <%= image_tag "icon_delete_white.png", :style => "vertical-align:middle;" %>  Delete
  • +
  • <%= image_tag "icon_delete_white.png", :style => "vertical-align:middle;" %>  Delete
  • +
    - + <%= render :partial => "/vm/grid", :locals => { :table_id => "vms_grid", + :pool_id => @vm_resource_pool.id } %>
    -
    Host Name
    Host description goes here if we allow a description.
    diff --git a/wui/src/app/views/user/_change_role_menu.rhtml b/wui/src/app/views/user/_change_role_menu.rhtml index b33ba00..f35cd3b 100644 --- a/wui/src/app/views/user/_change_role_menu.rhtml +++ b/wui/src/app/views/user/_change_role_menu.rhtml @@ -1,13 +1,12 @@ <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %>  Change Role    <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %>
      <% @roles.each_index { |index| %> - -
    • style="border-bottom: 1px solid black;" <% end %> > - <%= @roles[index] %> + <%=@roles[index]%>
    • <% } %>
    diff --git a/wui/src/app/views/user/_grid.rhtml b/wui/src/app/views/user/_grid.rhtml new file mode 100644 index 0000000..24a7b86 --- /dev/null +++ b/wui/src/app/views/user/_grid.rhtml @@ -0,0 +1,30 @@ +
    +
    + +
    +
    + diff --git a/wui/src/app/views/user/_show.rhtml b/wui/src/app/views/user/_show.rhtml new file mode 100644 index 0000000..348e47b --- /dev/null +++ b/wui/src/app/views/user/_show.rhtml @@ -0,0 +1,46 @@ + + + +
    +
    + <%= render :partial => "/user/grid", :locals => { :table_id => "users_grid", + :parent_controller => parent_controller, + :pool_id => pool_id } %> + +
    diff --git a/wui/src/app/views/vm/_grid.rhtml b/wui/src/app/views/vm/_grid.rhtml new file mode 100644 index 0000000..55f9d9b --- /dev/null +++ b/wui/src/app/views/vm/_grid.rhtml @@ -0,0 +1,34 @@ +
    +
    + +
    +
    + diff --git a/wui/src/public/stylesheets/components.css b/wui/src/public/stylesheets/components.css index bef30a2..489dd48 100644 --- a/wui/src/public/stylesheets/components.css +++ b/wui/src/public/stylesheets/components.css @@ -111,3 +111,13 @@ text-align: left; cursor: pointer; } +#toolbar_nav ul ul li a{ + width: 200px; + background: #E5F1FD; + color: #000000; + text-align: left; + cursor: pointer; +} +#toolbar_nav ul ul li:hover a { + background: #1E99DF; +} -- 1.5.4.1 --------------070909090602030707090105-- From sseago at kodiak.boston.redhat.com Thu May 15 21:42:59 2008 From: sseago at kodiak.boston.redhat.com (Scott Seago) Date: Thu, 15 May 2008 17:42:59 -0400 Subject: [Ovirt-devel] [PATCH] This patch hooks up the new/add form and change role pulldown for user permissions. Delete works for vms, vm pools, and user permissions. Pulldown for vms is done on the UI side, but the controller method isn't filled out yet. Message-ID: This stuff still needs permissiosn checks and proper validation/confirmation. Signed-off-by: Scott Seago --- wui/src/app/controllers/hardware_controller.rb | 2 +- wui/src/app/controllers/permission_controller.rb | 38 +++++++++++- wui/src/app/controllers/resources_controller.rb | 32 ++++++++-- wui/src/app/controllers/vm_controller.rb | 14 ++++ wui/src/app/views/hardware/show_users.rhtml | 33 +---------- wui/src/app/views/hardware/show_vms.rhtml | 27 ++++++++- wui/src/app/views/permission/new.rhtml | 70 ++++++++++------------ wui/src/app/views/resources/_form.rhtml | 6 +-- wui/src/app/views/resources/new.rhtml | 70 ++++++++++------------ wui/src/app/views/resources/show_users.rhtml | 33 +---------- wui/src/app/views/resources/show_vms.rhtml | 57 +++++++++--------- wui/src/app/views/user/_change_role_menu.rhtml | 5 +- wui/src/app/views/user/_grid.rhtml | 30 +++++++++ wui/src/app/views/user/_show.rhtml | 46 ++++++++++++++ wui/src/app/views/vm/_grid.rhtml | 34 +++++++++++ wui/src/public/stylesheets/components.css | 10 +++ 16 files changed, 320 insertions(+), 187 deletions(-) create mode 100644 wui/src/app/views/user/_grid.rhtml create mode 100644 wui/src/app/views/user/_show.rhtml create mode 100644 wui/src/app/views/vm/_grid.rhtml diff --git a/wui/src/app/controllers/hardware_controller.rb b/wui/src/app/controllers/hardware_controller.rb index 3379199..599d881 100644 --- a/wui/src/app/controllers/hardware_controller.rb +++ b/wui/src/app/controllers/hardware_controller.rb @@ -107,7 +107,7 @@ class HardwareController < ApplicationController def users_json json_list(@pool.permissions, - [:user, :user_role]) + [:id, :user, :user_role]) end def storage_pools_json diff --git a/wui/src/app/controllers/permission_controller.rb b/wui/src/app/controllers/permission_controller.rb index 68eb54d..9fe63d8 100644 --- a/wui/src/app/controllers/permission_controller.rb +++ b/wui/src/app/controllers/permission_controller.rb @@ -45,24 +45,58 @@ class PermissionController < ApplicationController flash[:notice] = 'You do not have permission to create this permission record' redirect_to_parent end + render :layout => 'popup' end def create @permission = Permission.new(params[:permission]) set_perms(@permission.pool) unless @can_set_perms + # FIXME: need to handle proper error messages w/ ajax flash[:notice] = 'You do not have permission to create this permission record' redirect_to_parent else if @permission.save - flash[:notice] = 'Permission was successfully created.' - redirect_to_parent + render :json => "created User Permissions for #{@permission.user}".to_json else + # FIXME: need to handle proper error messages w/ ajax render :action => 'new' end end end + #FIXME: we need permissions checks. user must have permission. We also need to fail + # for pools that aren't currently empty + def update_roles + role = params[:user_role] + permission_ids_str = params[:permission_ids] + permission_ids = permission_ids_str.split(",").collect {|x| x.to_i} + + Permission.transaction do + permissions = Permission.find(:all, :conditions => "id in (#{permission_ids.join(', ')})") + permissions.each do |permission| + permission.user_role = role + permission.save! + end + end + render :text => "deleted user permissions (#{permission_ids.join(', ')})" + end + + #FIXME: we need permissions checks. user must have permission. We also need to fail + # for pools that aren't currently empty + def delete + permission_ids_str = params[:permission_ids] + permission_ids = permission_ids_str.split(",").collect {|x| x.to_i} + + Permission.transaction do + permissions = Permission.find(:all, :conditions => "id in (#{permission_ids.join(', ')})") + permissions.each do |permission| + permission.destroy + end + end + render :text => "deleted user permissions (#{permission_ids.join(', ')})" + end + def destroy @permission = Permission.find(params[:id]) set_perms(@permission.pool) diff --git a/wui/src/app/controllers/resources_controller.rb b/wui/src/app/controllers/resources_controller.rb index 14499ab..68e3abe 100644 --- a/wui/src/app/controllers/resources_controller.rb +++ b/wui/src/app/controllers/resources_controller.rb @@ -58,7 +58,12 @@ class ResourcesController < ApplicationController # resource's vms list page def show_vms show - @actions = VmTask::ACTIONS.keys + @actions = [["Start", VmTask::ACTION_START_VM], + ["Shutdown", VmTask::ACTION_SHUTDOWN_VM, "break"], + ["Suspend", VmTask::ACTION_SUSPEND_VM], + ["Resume", VmTask::ACTION_RESUME_VM], + ["Save", VmTask::ACTION_SAVE_VM], + ["Restore", VmTask::ACTION_RESTORE_VM]] end # resource's users list page @@ -69,23 +74,23 @@ class ResourcesController < ApplicationController def vms_json json_list(@vm_resource_pool.vms, - [:description, :uuid, :num_vcpus_allocated, :memory_allocated_in_mb, :vnic_mac_addr, :state]) + [:id, :description, :uuid, :num_vcpus_allocated, :memory_allocated_in_mb, :vnic_mac_addr, :state]) end def users_json json_list(@vm_resource_pool.permissions, - [:user, :user_role]) + [:id, :user, :user_role]) end def new - @vm_resource_pools = @vm_resource_pool.self_and_like_siblings + render :layout => 'popup' end def create if @vm_resource_pool.create_with_parent(@parent) - flash[:notice] = 'VM Resource Pool was successfully created.' - redirect_to :controller => @vm_resource_pool.parent.get_controller, :action => 'show', :id => @vm_resource_pool.parent + render :json => "created new VM pool #{@vm_resource_pool.name}".to_json else + # FIXME: need to handle proper error messages w/ ajax render :action => 'new' end end @@ -102,6 +107,21 @@ class ResourcesController < ApplicationController end end + #FIXME: we need permissions checks. user must have permission. We also need to fail + # for pools that aren't currently empty + def delete + vm_pool_ids_str = params[:vm_pool_ids] + vm_pool_ids = vm_pool_ids_str.split(",").collect {|x| x.to_i} + + VmResourcePool.transaction do + pools = VmResourcePool.find(:all, :conditions => "id in (#{vm_pool_ids.join(', ')})") + pools.each do |pool| + pool.destroy + end + end + render :text => "deleted vm pools (#{vm_pool_ids.join(', ')})" + end + def destroy parent = @vm_resource_pool.parent @vm_resource_pool.destroy diff --git a/wui/src/app/controllers/vm_controller.rb b/wui/src/app/controllers/vm_controller.rb index ae6d437..4e4faf9 100644 --- a/wui/src/app/controllers/vm_controller.rb +++ b/wui/src/app/controllers/vm_controller.rb @@ -97,6 +97,20 @@ class VmController < ApplicationController end end + #FIXME: we need permissions checks. user must have permission. + def delete + vm_ids_str = params[:vm_ids] + vm_ids = vm_ids_str.split(",").collect {|x| x.to_i} + + Vm.transaction do + vms = Vm.find(:all, :conditions => "id in (#{vm_ids.join(', ')})") + vms.each do |vm| + vm.destroy + end + end + render :text => "deleted vms (#{vm_ids.join(', ')})" + end + def destroy vm_resource_pool = @vm.vm_resource_pool_id if ((@vm.state == Vm::STATE_STOPPED and @vm.get_pending_state == Vm::STATE_STOPPED) or diff --git a/wui/src/app/views/hardware/show_users.rhtml b/wui/src/app/views/hardware/show_users.rhtml index 2a5c9ee..abec65c 100644 --- a/wui/src/app/views/hardware/show_users.rhtml +++ b/wui/src/app/views/hardware/show_users.rhtml @@ -1,31 +1,2 @@ - - -
    -
    - -
    - +<%= render :partial => "/user/show", :locals => { :parent_controller => "hardware", + :pool_id => @pool.id } %> diff --git a/wui/src/app/views/hardware/show_vms.rhtml b/wui/src/app/views/hardware/show_vms.rhtml index 0d91421..407b80c 100644 --- a/wui/src/app/views/hardware/show_vms.rhtml +++ b/wui/src/app/views/hardware/show_vms.rhtml @@ -1,9 +1,32 @@ +
    diff --git a/wui/src/app/views/permission/new.rhtml b/wui/src/app/views/permission/new.rhtml index f1b99f1..f2b129f 100644 --- a/wui/src/app/views/permission/new.rhtml +++ b/wui/src/app/views/permission/new.rhtml @@ -1,43 +1,35 @@ -
    -
    +
    +
    Add New User
    +
    Add a new user to <%= @permission.pool.name %> pool.
    +
    + +
    +
    + <%= render :partial => 'form' %> +
    +
    ) repeat-x; height: 37px; text-align:right; padding: 9px 9px 0 0;"> +
    " alt="Create User Permission" /> + <%=image_tag "btn_cancel.png", :title=>"Cancel" %> +
    +
    +
    + -
    - -
    -
    - -
    - <% form_tag :action => 'create' do %> - <%= render :partial => 'form' %> - <%= submit_tag "Add User" %> - <% end %> -
    - -
    -

    Existing Users

    - <%= render :partial => "/permission/list", :locals => { :permissions => @perms, :show_object => false, :show_actions => @can_view } %> -
    - -
    -
    - -
    - -
    -
    - - - -
     
    -
    - -

    Actions

    -
    - <%= link_to "Back to #{@permission.pool.name}", { :controller => @permission.pool.get_controller, :action => 'show', :id => @permission.pool_id }, { :class => "show" } %> -
    -
    - - <%- content_for :title do -%> <%= "Edit Permissions for #{@permission.pool.name}" %> <%- end -%> diff --git a/wui/src/app/views/resources/_form.rhtml b/wui/src/app/views/resources/_form.rhtml index 1a09872..0f9fa9f 100644 --- a/wui/src/app/views/resources/_form.rhtml +++ b/wui/src/app/views/resources/_form.rhtml @@ -1,11 +1,7 @@ <%= error_messages_for 'vm_resource_pool' %> -<%= hidden_field_tag_with_label ((@parent[:type] == HardwarePool.name) ? - "Hardware Pool" : "Parent VM Resource Pool"), - 'parent_id', @parent.id, @parent.name %> - +<%= hidden_field_tag 'parent_id', @parent.id %> <%= text_field_with_label "Name", 'vm_resource_pool', 'name' %> - diff --git a/wui/src/app/views/resources/new.rhtml b/wui/src/app/views/resources/new.rhtml index 0dbb165..c142fe7 100644 --- a/wui/src/app/views/resources/new.rhtml +++ b/wui/src/app/views/resources/new.rhtml @@ -1,42 +1,34 @@ -
    -
    - -
    - -
    -
    - -
    - <% form_tag :action => 'create' do %> - <%= render :partial => 'form' %> - <%= submit_tag "Create" %> - <% end %> -
    - -
    - Current VM Resource Pools (<%= @vm_resource_pools.size %>) - <% for resource in @vm_resource_pools %> -
    <%= link_to resource.name, { :controller => "resources", :action => "show", :id => resource }, { } %>
    - <% end %> -
    - -
    - -
    -
    - - - -
     
    -
    -

    Actions

    -
    -
    <%= link_to "back to #{@parent.name}", { :controller => @parent.get_controller, :action => 'show', :id => @parent }, { :class => "" } %>
    -
    -
    - - - +
    +
    Add New Virtual Machine Pool
    +
    Add a new Virtual Machine Pool to the <%= @parent.name %> pool.
    +
    + +
    +
    + <%= render :partial => 'form' %> +
    +
    ) repeat-x; height: 37px; text-align:right; padding: 9px 9px 0 0;"> + +
    +
    + <%- content_for :title do -%> <%= _("New VM Resource Pool") %> diff --git a/wui/src/app/views/resources/show_users.rhtml b/wui/src/app/views/resources/show_users.rhtml index fb2fae9..02a1feb 100644 --- a/wui/src/app/views/resources/show_users.rhtml +++ b/wui/src/app/views/resources/show_users.rhtml @@ -1,31 +1,2 @@ - - -
    -
    - -
    - +<%= render :partial => "/user/show", :locals => { :parent_controller => "resources", + :pool_id => @vm_resource_pool.id } %> diff --git a/wui/src/app/views/resources/show_vms.rhtml b/wui/src/app/views/resources/show_vms.rhtml index 98711cf..5f758aa 100644 --- a/wui/src/app/views/resources/show_vms.rhtml +++ b/wui/src/app/views/resources/show_vms.rhtml @@ -5,47 +5,48 @@ <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %>  Actions    <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %>
      <% @actions.each_index { |index| %> -
    • +
    • style="border-bottom: 1px solid black;" <% end %> > - <%= @actions[index] %> + <%=@actions[index][0]%>
    • <% } %>
    -
  • <%= image_tag "icon_delete_white.png", :style => "vertical-align:middle;" %>  Delete
  • +
  • <%= image_tag "icon_delete_white.png", :style => "vertical-align:middle;" %>  Delete
  • +
    - + <%= render :partial => "/vm/grid", :locals => { :table_id => "vms_grid", + :pool_id => @vm_resource_pool.id } %>
    -
    Host Name
    Host description goes here if we allow a description.
    diff --git a/wui/src/app/views/user/_change_role_menu.rhtml b/wui/src/app/views/user/_change_role_menu.rhtml index b33ba00..f35cd3b 100644 --- a/wui/src/app/views/user/_change_role_menu.rhtml +++ b/wui/src/app/views/user/_change_role_menu.rhtml @@ -1,13 +1,12 @@ <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %>  Change Role    <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %>
      <% @roles.each_index { |index| %> - -
    • style="border-bottom: 1px solid black;" <% end %> > - <%= @roles[index] %> + <%=@roles[index]%>
    • <% } %>
    diff --git a/wui/src/app/views/user/_grid.rhtml b/wui/src/app/views/user/_grid.rhtml new file mode 100644 index 0000000..24a7b86 --- /dev/null +++ b/wui/src/app/views/user/_grid.rhtml @@ -0,0 +1,30 @@ +
    +
    + +
    +
    + diff --git a/wui/src/app/views/user/_show.rhtml b/wui/src/app/views/user/_show.rhtml new file mode 100644 index 0000000..348e47b --- /dev/null +++ b/wui/src/app/views/user/_show.rhtml @@ -0,0 +1,46 @@ + + + +
    +
    + <%= render :partial => "/user/grid", :locals => { :table_id => "users_grid", + :parent_controller => parent_controller, + :pool_id => pool_id } %> + +
    diff --git a/wui/src/app/views/vm/_grid.rhtml b/wui/src/app/views/vm/_grid.rhtml new file mode 100644 index 0000000..55f9d9b --- /dev/null +++ b/wui/src/app/views/vm/_grid.rhtml @@ -0,0 +1,34 @@ +
    +
    + +
    +
    + diff --git a/wui/src/public/stylesheets/components.css b/wui/src/public/stylesheets/components.css index bef30a2..489dd48 100644 --- a/wui/src/public/stylesheets/components.css +++ b/wui/src/public/stylesheets/components.css @@ -111,3 +111,13 @@ text-align: left; cursor: pointer; } +#toolbar_nav ul ul li a{ + width: 200px; + background: #E5F1FD; + color: #000000; + text-align: left; + cursor: pointer; +} +#toolbar_nav ul ul li:hover a { + background: #1E99DF; +} -- 1.5.4.1 --------------060108070004000702090107-- From hbrock at redhat.com Fri May 16 03:38:31 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Thu, 15 May 2008 23:38:31 -0400 Subject: [Ovirt-devel] [Patch] hook up some more ui components to the new style, including VMs and user permissions In-Reply-To: <482CAFDD.5060602@redhat.com> References: <482CAEB6.60102@redhat.com> <482CAFDD.5060602@redhat.com> Message-ID: <20080516033831.GZ16435@redhat.com> On Thu, May 15, 2008 at 05:49:17PM -0400, Scott Seago wrote: > Scott Seago wrote: >> This patch hooks up the new/add form and change role pulldown for user >> permissions. Delete works for vms, vm pools, and user permissions. >> Pulldown for vms is done on the UI side, but the controller method isn't >> filled out yet. >> >> This stuff still needs permissiosn checks and proper >> validation/confirmation. >> >> Darryl -- you should be able to use this patch as the basis for your >> changes to the permissions setting code. >> >> Scott > OK third try to attach the patch. This time I'll paste it into the message: > Arrgh yeah you have to actually put a character in front of "From" to make it go through, otherwise mailman thinks it's from someone else. To make matters worse probably, I have just allowed your earlier messages through with attached patch. In any case, looking forward to checking out the patch tomorrow... --H From dpierce at redhat.com Fri May 16 12:56:34 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Fri, 16 May 2008 08:56:34 -0400 Subject: [Ovirt-devel] [Patch] hook up some more ui components to the new style, including VMs and user permissions In-Reply-To: <482CAEB6.60102@redhat.com> References: <482CAEB6.60102@redhat.com> Message-ID: <200805160856.37388.dpierce@redhat.com> On Thursday 15 May 2008 05:44:22 pm Scott Seago wrote: > Darryl -- you should be able to use this patch as the basis for your > changes to the permissions setting code. ACK I imported the patch and the only change needed to run it in one place in hardware_controller.rb to work for me. I'll release that update with my changes. -- Darryl L. Pierce - Phone: (919) 754-4383 "In matters of style, swim with the current; In matters of principle, stand like a rock." - Thomas Jefferson -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 189 bytes Desc: This is a digitally signed message part. URL: From dpierce at redhat.com Fri May 16 20:57:57 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Fri, 16 May 2008 16:57:57 -0400 Subject: [Ovirt-devel] [PATCH] Users are displayed from LDAP and filtered based on the current list of users. Message-ID: <1210971477-8069-1-git-send-email-dpierce@redhat.com> Signed-off-by: Darryl L. Pierce --- wui/src/app/controllers/application.rb | 2 +- wui/src/app/controllers/hardware_controller.rb | 2 +- wui/src/app/controllers/permission_controller.rb | 4 ++- wui/src/app/models/account.rb | 30 +++++++++++++++++++--- wui/src/app/models/permission.rb | 7 +++++ wui/src/app/views/permission/_form.rhtml | 3 +- wui/src/config/ldap.yml | 4 +- 7 files changed, 41 insertions(+), 11 deletions(-) diff --git a/wui/src/app/controllers/application.rb b/wui/src/app/controllers/application.rb index d387319..a637487 100644 --- a/wui/src/app/controllers/application.rb +++ b/wui/src/app/controllers/application.rb @@ -34,7 +34,7 @@ class ApplicationController < ActionController::Base def get_login_user # user_from_principal(request.env["HTTP_X_FORWARDED_USER"]) - 'admin' + 'dpierce' end def user_from_principal(principal) diff --git a/wui/src/app/controllers/hardware_controller.rb b/wui/src/app/controllers/hardware_controller.rb index 599d881..734d0b2 100644 --- a/wui/src/app/controllers/hardware_controller.rb +++ b/wui/src/app/controllers/hardware_controller.rb @@ -107,7 +107,7 @@ class HardwareController < ApplicationController def users_json json_list(@pool.permissions, - [:id, :user, :user_role]) + [:id, :name, :user_role]) end def storage_pools_json diff --git a/wui/src/app/controllers/permission_controller.rb b/wui/src/app/controllers/permission_controller.rb index 086e183..c0cbc38 100644 --- a/wui/src/app/controllers/permission_controller.rb +++ b/wui/src/app/controllers/permission_controller.rb @@ -39,6 +39,8 @@ class PermissionController < ApplicationController def new @permission = Permission.new( { :pool_id => params[:pool_id]}) @perms = @permission.pool.permissions + filter = Permission.find(:all).collect{ |permission| permission.uid } + @users = Account.names(filter) set_perms(@permission.pool) # admin permission required to view permissions unless @can_set_perms @@ -57,7 +59,7 @@ class PermissionController < ApplicationController redirect_to_parent else if @permission.save - render :json => "created User Permissions for #{@permission.user}".to_json + render :json => "created User Permissions for #{@permission.uid}".to_json else # FIXME: need to handle proper error messages w/ ajax render :action => 'new' diff --git a/wui/src/app/models/account.rb b/wui/src/app/models/account.rb index 2664f18..e3a1a54 100644 --- a/wui/src/app/models/account.rb +++ b/wui/src/app/models/account.rb @@ -22,6 +22,8 @@ class Account < ActiveLdap::Base ldap_mapping :dn_attribute => 'cn', :prefix => 'ou=Users', :scope => :one + @@users = nil + # +query+ returns the set of all accounts that contain the given search value. # # This API requires that a previous connection be made using @@ -29,13 +31,33 @@ class Account < ActiveLdap::Base # def Account.query(value) - @users = Account.find(:all, value) + @@users ||= Account.find(:all, value) if block_given? - @users.each { |user| yield(user) } + @@users.each { |user| yield(user) } end - return @users - + @@users end + + # Retrieves the list of users from LDAP and returns a hash of + # their uids, indexed by their common name in the form: + # +username (uid) => uid+ + # + # if a filter is passed in, those user ids are filtered out + # of the returned list. + # + def Account.names(filter = []) + result = {} + + Account.query('*') do |user| + unless filter.include? user.uid + key = "#{user.cn} (#{user.uid})" + result[key] = user.uid + end + end + + result.sort + end + end diff --git a/wui/src/app/models/permission.rb b/wui/src/app/models/permission.rb index 7d80e1e..0aab16c 100644 --- a/wui/src/app/models/permission.rb +++ b/wui/src/app/models/permission.rb @@ -50,11 +50,18 @@ class Permission < ActiveRecord::Base return_hash end + def name + @account ||= Account.find("uid=#{uid}") + + @account.cn + end + PRIVILEGES = self.invert_roles def self.privileges_for_role(role) ROLES[role] end + def self.roles_for_privilege(privilege) PRIVILEGES[privilege] end diff --git a/wui/src/app/views/permission/_form.rhtml b/wui/src/app/views/permission/_form.rhtml index cb0abea..2a1e93c 100644 --- a/wui/src/app/views/permission/_form.rhtml +++ b/wui/src/app/views/permission/_form.rhtml @@ -5,8 +5,7 @@ <%= select_with_label 'Role', 'permission', 'user_role', Permission::ROLES.keys %> -<%= text_field_with_label 'User', 'permission', 'uid' %> - +<%= select_with_label 'User', 'permission', 'uid', @users %> diff --git a/wui/src/config/ldap.yml b/wui/src/config/ldap.yml index 796c334..243707f 100644 --- a/wui/src/config/ldap.yml +++ b/wui/src/config/ldap.yml @@ -1,7 +1,7 @@ development: - host: ldap.for.your.domain.com + host: ldap.rdu.redhat.com port: 389 - base: dc=domain,dc=com + base: dc=redhat,dc=com test: host: ldap.for.your.domain.com -- 1.5.4.1 From sseago at redhat.com Fri May 16 21:02:02 2008 From: sseago at redhat.com (Scott Seago) Date: Fri, 16 May 2008 17:02:02 -0400 Subject: [Ovirt-devel] [Patch] move tree popup widget for moving hosts and storage Message-ID: <482DF64A.1020405@redhat.com> >From 1ebce4238a6381d6fd513ed8753803164cef18b0 Mon Sep 17 00:00:00 2001 From: Scott Seago Date: Fri, 16 May 2008 16:52:58 -0400 Subject: [PATCH] first pass at move popup. Still not migrated to storage, and the 'new hardware pool' bits need to be hooked up. Signed-off-by: Scott Seago --- wui/src/app/controllers/hardware_controller.rb | 28 +- wui/src/app/controllers/resources_controller.rb | 2 +- wui/src/app/models/pool.rb | 28 +- wui/src/app/views/hardware/move.rhtml | 43 + wui/src/app/views/hardware/new.html.erb | 76 +- wui/src/app/views/hardware/show_hosts.rhtml | 12 +- wui/src/app/views/hardware/show_storage.rhtml | 2 +- wui/src/app/views/layouts/_tree.rhtml | 2 +- wui/src/app/views/layouts/redux.rhtml | 10 +- wui/src/app/views/user/_grid.rhtml | 2 +- wui/src/public/images/Untitled-4.gif | Bin 0 -> 13123 bytes wui/src/public/images/addstoragepool.png | Bin 0 -> 1069 bytes wui/src/public/images/btn_move.png | Bin 0 -> 1531 bytes wui/src/public/images/btn_moveto_newhost.png | Bin 0 -> 2878 bytes wui/src/public/images/btn_moveto_newpool.png | Bin 0 -> 2731 bytes wui/src/public/images/icon_addvm.png | Bin 0 -> 1242 bytes wui/src/public/images/icon_selection_add.gif | Bin 0 -> 13127 bytes wui/src/public/images/icon_selection_remove.gif | Bin 0 -> 13117 bytes .../public/images/icon_selection_showdetail.gif | Bin 0 -> 13124 bytes wui/src/public/images/loading.gif | Bin 0 -> 2767 bytes wui/src/public/images/slider-bg-1.png | Bin 0 -> 204 bytes wui/src/public/images/slider-bg-2.png | Bin 0 -> 326 bytes wui/src/public/images/slider-handle.gif | Bin 0 -> 176 bytes wui/src/public/javascripts/facebox.js | 1 + .../jquery-treeview/jquery.treeview.async.js | 19 +- wui/src/public/javascripts/jquery.cookie.js | 92 + wui/src/public/javascripts/jquery.js | 3533 ++++++++++++++++++++ wui/src/public/javascripts/ui.core.js | 237 ++ wui/src/public/javascripts/ui.slider.js | 386 +++ wui/src/public/stylesheets/facebox.css | 8 + wui/src/public/stylesheets/layout.css | 138 +- 31 files changed, 4525 insertions(+), 94 deletions(-) create mode 100644 wui/src/app/views/hardware/move.rhtml create mode 100644 wui/src/public/images/Untitled-4.gif create mode 100644 wui/src/public/images/addstoragepool.png create mode 100644 wui/src/public/images/btn_move.png create mode 100644 wui/src/public/images/btn_moveto_newhost.png create mode 100644 wui/src/public/images/btn_moveto_newpool.png create mode 100644 wui/src/public/images/icon_addvm.png create mode 100644 wui/src/public/images/icon_selection_add.gif create mode 100644 wui/src/public/images/icon_selection_remove.gif create mode 100644 wui/src/public/images/icon_selection_showdetail.gif create mode 100755 wui/src/public/images/loading.gif create mode 100755 wui/src/public/images/slider-bg-1.png create mode 100755 wui/src/public/images/slider-bg-2.png create mode 100755 wui/src/public/images/slider-handle.gif create mode 100644 wui/src/public/javascripts/jquery.cookie.js create mode 100755 wui/src/public/javascripts/jquery.js create mode 100755 wui/src/public/javascripts/ui.core.js create mode 100755 wui/src/public/javascripts/ui.slider.js diff --git a/wui/src/app/controllers/hardware_controller.rb b/wui/src/app/controllers/hardware_controller.rb index 599d881..0365931 100644 --- a/wui/src/app/controllers/hardware_controller.rb +++ b/wui/src/app/controllers/hardware_controller.rb @@ -37,22 +37,30 @@ class HardwareController < ApplicationController end end - def json + def json_view_tree + json_tree_internal(Permission::PRIV_VIEW, false) + end + def json_move_tree + json_tree_internal(Permission::PRIV_MODIFY, true) + end + def json_tree_internal(privilege, filter_vm_pools) id = params[:id] if id @pool = Pool.find(id) set_perms(@pool) - unless @can_view - flash[:notice] = 'You do not have permission to view this hardware pool: redirecting to top level' + unless @pool.has_privilege(@user, privilege) + flash[:notice] = 'You do not have permission to access this hardware pool: redirecting to top level' redirect_to :controller => "dashboard" return end end if @pool pools = @pool.children + pools = Pool.select_hardware_pools(pools) if filter_vm_pools open_list = [] else pools = Pool.list_for_user(get_login_user,Permission::PRIV_VIEW) + pools = Pool.select_hardware_pools(pools) if filter_vm_pools current_id = params[:current_id] if current_id current_pool = Pool.find(current_id) @@ -62,7 +70,7 @@ class HardwareController < ApplicationController end end - render :json => Pool.nav_json(pools, open_list) + render :json => Pool.nav_json(pools, open_list, filter_vm_pools) end def show_vms @@ -107,7 +115,7 @@ class HardwareController < ApplicationController def users_json json_list(@pool.permissions, - [:id, :user, :user_role]) + [:id, :uid, :user_role]) end def storage_pools_json @@ -127,6 +135,12 @@ class HardwareController < ApplicationController [:display_name, :size_in_gb, :get_type_label]) end + def move + pre_modify + @resource_type = params[:resource_type] + render :layout => 'popup' + end + def new @pools = @pool.self_and_like_siblings end @@ -174,7 +188,7 @@ class HardwareController < ApplicationController # for hosts that aren't currently empty def move_hosts target_pool_id = params[:target_pool_id] - host_ids_str = params[:host_ids] + host_ids_str = params[:resource_ids] host_ids = host_ids_str.split(",").collect {|x| x.to_i} @pool.transaction do @@ -209,7 +223,7 @@ class HardwareController < ApplicationController # for storage that aren't currently empty def move_storage target_pool_id = params[:target_pool_id] - storage_pool_ids_str = params[:storage_pool_ids] + storage_pool_ids_str = params[:resource_ids] storage_pool_ids = storage_pool_ids_str.split(",").collect {|x| x.to_i} @pool.transaction do diff --git a/wui/src/app/controllers/resources_controller.rb b/wui/src/app/controllers/resources_controller.rb index 68e3abe..5056f09 100644 --- a/wui/src/app/controllers/resources_controller.rb +++ b/wui/src/app/controllers/resources_controller.rb @@ -79,7 +79,7 @@ class ResourcesController < ApplicationController def users_json json_list(@vm_resource_pool.permissions, - [:id, :user, :user_role]) + [:id, :uid, :user_role]) end def new diff --git a/wui/src/app/models/pool.rb b/wui/src/app/models/pool.rb index b6c0e03..34979c0 100644 --- a/wui/src/app/models/pool.rb +++ b/wui/src/app/models/pool.rb @@ -58,11 +58,18 @@ class Pool < ActiveRecord::Base ('#{Permission.roles_for_privilege(privilege).join("', '")}')") end + def self.select_hardware_pools(pools) + pools.select {|pool| pool[:type] == "HardwarePool"} + end + def self.select_vm_pools(pools) + pools.select {|pool| pool[:type] == "VmResourcePool"} + end + def sub_hardware_pools - children.select {|pool| pool[:type] == "HardwarePool"} + Pool.select_hardware_pools(children) end def sub_vm_resource_pools - children.select {|pool| pool[:type] == "VmResourcePool"} + Pool.select_vm_pools(children) end def self_and_like_siblings self_and_siblings.select {|pool| pool[:type] == self.class.name} @@ -113,23 +120,30 @@ class Pool < ActiveRecord::Base return (rgt - lft) != 1 end - def self.nav_json(pools, open_list) - pool_hash(pools, open_list).to_json + def self.nav_json(pools, open_list, filter_vm_pools=false) + pool_hash(pools, open_list, filter_vm_pools).to_json end - def self.pool_hash(pools, open_list) + def self.pool_hash(pools, open_list, filter_vm_pools=false) pools.collect do |pool| hash = {} hash[:id] = pool.id hash[:type] = pool[:type] hash[:text] = pool.name hash[:name] = pool.name - hash[:hasChildren] = pool.hasChildren + children = nil + if filter_vm_pools + children = select_hardware_pools(pool.children) + hash[:hasChildren] = !children.empty? + else + hash[:hasChildren] = pool.hasChildren + end found = false open_list.each do |open_pool| if pool.id == open_pool.id new_open_list = open_list[(open_list.index(open_pool)+1)..-1] unless new_open_list.empty? - hash[:children] = pool_hash(pool.children, new_open_list) + children = pool.children unless children + hash[:children] = pool_hash(children, new_open_list) hash[:expanded] = true hash.delete(:hasChildren) end diff --git a/wui/src/app/views/hardware/move.rhtml b/wui/src/app/views/hardware/move.rhtml new file mode 100644 index 0000000..23ebcf4 --- /dev/null +++ b/wui/src/app/views/hardware/move.rhtml @@ -0,0 +1,43 @@ + + +
    +
    Move <%= @resource_type.capitalize %>
    +
    Select an existing hardware pool or create a new pool for selected <%= @resource_type %>.
    +
    + +
    +
      + + +
      + + + + diff --git a/wui/src/app/views/hardware/new.html.erb b/wui/src/app/views/hardware/new.html.erb index 005b0b2..cf11267 100644 --- a/wui/src/app/views/hardware/new.html.erb +++ b/wui/src/app/views/hardware/new.html.erb @@ -1,46 +1,38 @@ -
      -
      - -
      - -
      -
      - -
      - <% form_tag :action => 'create', :id => @pool do %> - <%= render :partial => 'form' %> - <%= submit_tag 'Create Hardware Pool' %> - <% end %> -
      - -
      - Current Hardware Pool (<%= @pools.size %>) - <% for pool in @pools %> -
      <%= link_to pool.name, { :controller => "hardware", :action => "show", :id => pool }, { } %>
      - <% end %> -
      - -
      -
      - -
      - -
      -
      - - - -
       
      -
      - -

      Actions

      -
      - <%= link_to "Back to #{@parent.name}", { :controller => 'hardware', :action => 'show', :id => @parent }, { :class => "" } if @parent %> -
      -
      - +
      +
      Add New Hardware Pool
      +
      Add a new Hardware Pool to the <%= @parent.name %> pool.
      +
      + +
      +
      + <%= render :partial => 'form' %> +
      +
      ) repeat-x; height: 37px; text-align:right; padding: 9px 9px 0 0;"> +
      " alt="Create Hardware Pool" /> + <%=image_tag "btn_cancel.png", :title=>"Cancel" %> +
      +
      +
      + <%- content_for :title do -%> -<%= _("Create Hardware Pool") %> +<%= _("New Hardware Pool") %> <%- end -%> + diff --git a/wui/src/app/views/hardware/show_hosts.rhtml b/wui/src/app/views/hardware/show_hosts.rhtml index 5aaeeed..e94485f 100644 --- a/wui/src/app/views/hardware/show_hosts.rhtml +++ b/wui/src/app/views/hardware/show_hosts.rhtml @@ -1,13 +1,13 @@ > -
      > \ No newline at end of file > + > +
      > diff --git a/wui/src/app/views/layouts/redux.rhtml b/wui/src/app/views/layouts/redux.rhtml > index bc9d7c3..cd013d1 100644 > --- a/wui/src/app/views/layouts/redux.rhtml > +++ b/wui/src/app/views/layouts/redux.rhtml > @@ -22,7 +22,7 @@ > <%= javascript_include_tag "facebox.js" -%> > <%= javascript_include_tag "jquery-svg/jquery.svg.pack.js" -%> > > - <%= javascript_include_tag "jquery-svg/jquery.svggraph.pack.js" -%> > + <%= javascript_include_tag "jquery-svg/jquery.svggraph.js" -%> > <%= yield :scripts -%> > <%= javascript_include_tag "jquery.form.js" -%> > diff --git a/wui/src/app/views/hardware/show_hosts.rhtml b/wui/src/app/views/hardware/show_hosts.rhtml index 63a86ea..7f126a2 100644 --- a/wui/src/app/views/hardware/show_hosts.rhtml +++ b/wui/src/app/views/hardware/show_hosts.rhtml @@ -1,7 +1,10 @@ @@ -11,13 +14,22 @@ { return get_selected_checkboxes(document.hosts_grid_form) } + function validate_for_move() + { + if (validate_selected(get_selected_hosts(), 'host')) { + $('#move_link_hidden').click() + } + } function remove_hosts() { - $.post('<%= url_for :controller => "hardware", :action => "move_hosts", :id => @pool %>', - { resource_ids: get_selected_hosts().toString(), target_pool_id: <%= Pool.root.id %> }, - function(data,status){ - $("#hosts_grid").flexReload() - }); + hosts = get_selected_hosts() + if (validate_selected(hosts, "host")) { + $.post('<%= url_for :controller => "hardware", :action => "move_hosts", :id => @pool %>', + { resource_ids: hosts.toString(), target_pool_id: <%= Pool.root.id %> }, + function(data,status){ + $("#hosts_grid").flexReload() + }); + } } function hosts_select(selected_rows) { diff --git a/wui/src/app/views/hardware/show_storage.rhtml b/wui/src/app/views/hardware/show_storage.rhtml index 7ef69c9..f673e07 100644 --- a/wui/src/app/views/hardware/show_storage.rhtml +++ b/wui/src/app/views/hardware/show_storage.rhtml @@ -2,7 +2,10 @@ @@ -13,21 +16,33 @@ { return get_selected_checkboxes(document.storage_grid_form) } + function validate_for_move() + { + if (validate_selected(get_selected_storage(), 'storage pool')) { + $('#move_link_hidden').click() + } + } function remove_storage() { - $.post('<%= url_for :controller => "hardware", :action => "move_storage", :id => @pool %>', - { resource_ids: get_selected_storage().toString(), target_pool_id: <%= Pool.root.id %> }, - function(data,status){ - $("#storage_grid").flexReload() - }); + storage = get_selected_storage() + if (validate_selected(storage, "storage pool")) { + $.post('<%= url_for :controller => "hardware", :action => "move_storage", :id => @pool %>', + { resource_ids: storage.toString(), target_pool_id: <%= Pool.root.id %> }, + function(data,status){ + $("#storage_grid").flexReload() + }); + } } function delete_storage() { - $.post('<%= url_for :controller => "storage", :action => "delete_pools", :id => @pool %>', - { storage_pool_ids: get_selected_storage().toString() }, - function(data,status){ - $("#storage_grid").flexReload() - }); + storage = get_selected_storage() + if (validate_selected(storage, "storage pool")) { + $.post('<%= url_for :controller => "storage", :action => "delete_pools", :id => @pool %>', + { storage_pool_ids: storage.toString() }, + function(data,status){ + $("#storage_grid").flexReload() + }); + } } function storage_select(selected_rows) { diff --git a/wui/src/app/views/hardware/show_vms.rhtml b/wui/src/app/views/hardware/show_vms.rhtml index 86477be..44b6f50 100644 --- a/wui/src/app/views/hardware/show_vms.rhtml +++ b/wui/src/app/views/hardware/show_vms.rhtml @@ -11,11 +11,14 @@ } function delete_vm_pools() { - $.post('<%= url_for :controller => "resources", :action => "delete", :id => @pool %>', - { vm_pool_ids: get_selected_vm_pools().toString() }, - function(data,status){ - $("#vmpools_grid").flexReload() - }); + vm_pools = get_selected_vm_pools() + if (validate_selected(vm_pools, "vm_pool")) { + $.post('<%= url_for :controller => "resources", :action => "delete", :id => @pool %>', + { vm_pool_ids: vm_pools.toString() }, + function(data,status){ + $("#vmpools_grid").flexReload() + }); + } } function vmpools_select(selected_rows) { diff --git a/wui/src/app/views/host/addhost.html.erb b/wui/src/app/views/host/addhost.html.erb index 18b8683..5c6844d 100644 --- a/wui/src/app/views/host/addhost.html.erb +++ b/wui/src/app/views/host/addhost.html.erb @@ -27,13 +27,15 @@ { var assigned_selected= get_selected_checkboxes(document.addhosts_assigned_grid_form) var unassigned_selected= get_selected_checkboxes(document.addhosts_unassigned_grid_form) - - $.post('<%= url_for :controller => "hardware", :action => "add_hosts", :id => @hardware_pool %>', - { host_ids: Array.concat(assigned_selected,unassigned_selected).toString() }, - function(data,status){ - jQuery(document).trigger('close.facebox'); - $("#hosts_grid").flexReload() - }); + var hosts = Array.concat(assigned_selected,unassigned_selected) + if (validate_selected(hosts, "host")) { + $.post('<%= url_for :controller => "hardware", :action => "add_hosts", :id => @hardware_pool %>', + { host_ids: hosts.toString() }, + function(data,status){ + jQuery(document).trigger('close.facebox'); + $("#hosts_grid").flexReload() + }); + } }
      diff --git a/wui/src/app/views/layouts/redux.rhtml b/wui/src/app/views/layouts/redux.rhtml index 3a0eb21..bb2bd09 100644 --- a/wui/src/app/views/layouts/redux.rhtml +++ b/wui/src/app/views/layouts/redux.rhtml @@ -27,7 +27,6 @@ <%= javascript_include_tag "ui.slider.js" -%> <%= javascript_include_tag "jquery.cookie.js" -%> <%= javascript_include_tag "jquery.form.js" -%> - <%= yield :scripts -%> diff --git a/wui/src/app/views/permission/new.rhtml b/wui/src/app/views/permission/new.rhtml index f2b129f..2d95cde 100644 --- a/wui/src/app/views/permission/new.rhtml +++ b/wui/src/app/views/permission/new.rhtml @@ -25,8 +25,11 @@ $(function() { $('#new_permission_form').ajaxForm(permissionoptions); }); function afterNewPermission(response, status){ - jQuery(document).trigger('close.facebox'); - $("#users_grid").flexReload() + ajax_validation(response, status) + if (response.success) { + jQuery(document).trigger('close.facebox'); + $("#users_grid").flexReload() + } } diff --git a/wui/src/app/views/resources/new.rhtml b/wui/src/app/views/resources/new.rhtml index c142fe7..c19e1ab 100644 --- a/wui/src/app/views/resources/new.rhtml +++ b/wui/src/app/views/resources/new.rhtml @@ -25,8 +25,11 @@ $(function() { $('#new_vm_pool_form').ajaxForm(vmpooloptions); }); function afterNewVmPool(response, status){ - jQuery(document).trigger('close.facebox'); - $("#vmpools_grid").flexReload() + ajax_validation(response, status) + if (response.success) { + jQuery(document).trigger('close.facebox'); + $("#vmpools_grid").flexReload() + } } diff --git a/wui/src/app/views/resources/show_vms.rhtml b/wui/src/app/views/resources/show_vms.rhtml index 34eb973..8f1f4a3 100644 --- a/wui/src/app/views/resources/show_vms.rhtml +++ b/wui/src/app/views/resources/show_vms.rhtml @@ -25,11 +25,14 @@ } function delete_vms() { - $.post('<%= url_for :controller => "vm", :action => "delete", :id => @pool %>', - { vm_ids: get_selected_vms().toString() }, - function(data,status){ - $("#vms_grid").flexReload() - }); + vms = get_selected_vms() + if (validate_selected(vms, "vm")) { + $.post('<%= url_for :controller => "vm", :action => "delete", :id => @pool %>', + { vm_ids: vms.toString() }, + function(data,status){ + $("#vms_grid").flexReload() + }); + } } function vms_select(selected_rows) { diff --git a/wui/src/app/views/storage/addstorage.html.erb b/wui/src/app/views/storage/addstorage.html.erb index bdfd0cb..67cd920 100644 --- a/wui/src/app/views/storage/addstorage.html.erb +++ b/wui/src/app/views/storage/addstorage.html.erb @@ -27,12 +27,15 @@ { var assigned_selected= get_selected_checkboxes(document.addstorage_assigned_grid_form) var unassigned_selected= get_selected_checkboxes(document.addstorage_unassigned_grid_form) - $.post('<%= url_for :controller => "hardware", :action => "add_storage", :id => @hardware_pool %>', - { storage_pool_ids: Array.concat(assigned_selected,unassigned_selected).toString() }, - function(data,status){ - jQuery(document).trigger('close.facebox'); - $("#storage_grid").flexReload() - }); + var storage = Array.concat(assigned_selected,unassigned_selected) + if (validate_selected(storage, "storage pool")) { + $.post('<%= url_for :controller => "hardware", :action => "add_storage", :id => @hardware_pool %>', + { storage_pool_ids: storage.toString() }, + function(data,status){ + jQuery(document).trigger('close.facebox'); + $("#storage_grid").flexReload() + }); + } }
      diff --git a/wui/src/app/views/storage/new.rhtml b/wui/src/app/views/storage/new.rhtml index 37c6535..8a94a33 100644 --- a/wui/src/app/views/storage/new.rhtml +++ b/wui/src/app/views/storage/new.rhtml @@ -46,7 +46,10 @@ $(function() { $('#new_storage_pool_form').ajaxForm(storageoptions); }); function afterNewStoragePool(response, status){ - jQuery(document).trigger('close.facebox'); - $("#storage_grid").flexReload() + ajax_validation(response, status) + if (response.success) { + jQuery(document).trigger('close.facebox'); + $("#storage_grid").flexReload() + } } diff --git a/wui/src/app/views/user/_show.rhtml b/wui/src/app/views/user/_show.rhtml index a811062..03ecec6 100644 --- a/wui/src/app/views/user/_show.rhtml +++ b/wui/src/app/views/user/_show.rhtml @@ -12,19 +12,25 @@ } function delete_users() { - $.post('<%= url_for :controller => "permission", :action => "delete", :id => pool_id %>', - { permission_ids: get_selected_users().toString() }, + permissions = get_selected_users() + if (validate_selected(permissions, "user")) { + $.post('<%= url_for :controller => "permission", :action => "delete", :id => pool_id %>', + { permission_ids: permissions.toString() }, function(data,status){ $("#users_grid").flexReload() }); + } } function update_users(role) { - $.post('<%= url_for :controller => "permission", :action => "update_roles" %>', - { permission_ids: get_selected_users().toString(), user_role: role }, - function(data,status){ - $("#users_grid").flexReload() - }); + permissions = get_selected_users() + if (validate_selected(permissions, "users)) { + $.post('<%= url_for :controller => "permission", :action => "update_roles" %>', + { permission_ids: permissions.toString(), user_role: role }, + function(data,status){ + $("#users_grid").flexReload() + }); + } } diff --git a/wui/src/app/views/vm/_form.rhtml b/wui/src/app/views/vm/_form.rhtml index 9d8682e..44bfdd3 100644 --- a/wui/src/app/views/vm/_form.rhtml +++ b/wui/src/app/views/vm/_form.rhtml @@ -17,8 +17,8 @@
      <%= text_field_with_label "CPUs:", "vm", "num_vcpus_allocated", {:style=>"width:100px;"}, {:style=>"padding-right: 50px;"} %> -
      max to create: <%=create_resources[:cpus]%> mb
      -
      max to start: <%=start_resources[:cpus]%> mb
      +
      max to create: <%=create_resources[:cpus]%>
      +
      max to start: <%=start_resources[:cpus]%>
      <%= text_field_with_label "Memory:", "vm", "memory_allocated_in_mb", {:style=>"width:100px;"}, {:afterfield=>" mb"} %> diff --git a/wui/src/app/views/vm/new.rhtml b/wui/src/app/views/vm/new.rhtml index 5f9c673..c330ef3 100644 --- a/wui/src/app/views/vm/new.rhtml +++ b/wui/src/app/views/vm/new.rhtml @@ -37,8 +37,11 @@ $(function() { $('#new_vm_form').ajaxForm(vmoptions); }); function afterNewVm(response, status){ - jQuery(document).trigger('close.facebox'); - $("#vms_grid").flexReload() + ajax_validation(response, status) + if (response.success) { + jQuery(document).trigger('close.facebox'); + $("#vms_grid").flexReload() + } } diff --git a/wui/src/public/stylesheets/layout.css b/wui/src/public/stylesheets/layout.css index 784b1ad..1c317af 100644 --- a/wui/src/public/stylesheets/layout.css +++ b/wui/src/public/stylesheets/layout.css @@ -341,7 +341,7 @@ textarea:focus, input:focus { } .textfield_effect { - padding: 2px 0 0 2px; + padding: 2px 0 0 2px; border-width: 1px; border-style: solid; border-color: #999999; @@ -369,6 +369,11 @@ textarea:focus, input:focus { height: 5px; } +.fieldWithErrors { + background-color: #c00; +} + + /* This file skins sliders */ -- 1.5.4.1 --------------070101050409030300030506-- From hbrock at redhat.com Thu May 22 16:56:15 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Thu, 22 May 2008 12:56:15 -0400 Subject: [Ovirt-devel] [PATCH] support optimistic locking with lock_version In-Reply-To: <769584de0805211823u7f135f36pa0c3af7e24454349@mail.gmail.com> References: <769584de0805211823u7f135f36pa0c3af7e24454349@mail.gmail.com> Message-ID: <20080522165615.GR14196@redhat.com> On Wed, May 21, 2008 at 08:23:07PM -0500, steve linabery wrote: > Hi Ovirt, > > Edited the migration files to add the :lock_version column, which will > allow us to use optimistic locking by default. > > We can override this with more restrictive locking when needed, but > this should help catch stuff that might slip through the cracks. > > Thanks, > Steve I have committed this and pushed to the main repo. Thanks! --Hugh From hbrock at redhat.com Thu May 22 17:08:46 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Thu, 22 May 2008 13:08:46 -0400 Subject: [Ovirt-devel] [Patch] Network Load Graphs In-Reply-To: <4834C8E8.5050108@redhat.com> References: <4834C8E8.5050108@redhat.com> Message-ID: <20080522170846.GS14196@redhat.com> On Wed, May 21, 2008 at 09:14:16PM -0400, Mohammed Morsi wrote: > Attached is the patch for the last graphs on the hardware summary page, eg > the network summary graphs. Like the availability graphs, > jquery.svggraph.js had to be modified (previously it was to disable the > y-axis for stackedcolumn graphs, now it was to remove the fixed x-axis from > stackedrow graphs). Also included is some improved style for the history > graphs and I removed the old cruft on the hardware summary page that isn't > in the mockups. As with the others, dummy data is currently being used. > Enjoy. > > -Mo Committed and pushed. Looks great, thanks! --Hugh From hbrock at redhat.com Thu May 22 17:19:26 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Thu, 22 May 2008 13:19:26 -0400 Subject: [Ovirt-devel] [Patch] round 1 of ajax form validation In-Reply-To: <48359E6B.2020704@redhat.com> References: <48359DBB.8090708@redhat.com> <48359E6B.2020704@redhat.com> Message-ID: <20080522171926.GT14196@redhat.com> On Thu, May 22, 2008 at 12:25:15PM -0400, Scott Seago wrote: > Take 2... > >From aedf4c1257fc53dbcb8eb057e47d728ab4a3be1c Mon Sep 17 00:00:00 2001 > From: Scott Seago > Date: Thu, 22 May 2008 12:16:40 -0400 > Subject: [PATCH] ok, now we have some ajax form validation. > > I haven't gone crazy with validation rules -- mostly left things as they were, but added a few more validates_presence_of bits in the models. > create methods now return a json response with the field errors, if there are any. I haven't tested base-level error messages (i.e. general errors not connected to a form field) -- I'll probably need to make a couple more changes to support that. But basic field-level errors are being reported fine. > > Also, for any of the action links/popups requiring grid checkboxes, I've added client-side validation to only perform the action if at least one box is checked -- displaying an error popup if there aren't any. > ACK, and committed. N.B. the error message still reads "{%fn} cannot be blank on the 'create new pool' popup..." Thanks, --Hugh From pmyers at redhat.com Thu May 22 18:57:37 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Thu, 22 May 2008 14:57:37 -0400 Subject: [Ovirt-devel] [PATCH] allow create-wui-appliance to use local repo tree along with ISO Message-ID: <4835C221.9080504@redhat.com> This patch modifies create-wui-appliance.sh so that both a local ISO or an install tree can be used to install the WUI appliance. The advantage of using a local tree is that a kickstart file can be specified so that manually entering the kickstart location during the boot process is not necessary. Signed-off-by: Perry Myers diff --git a/wui-appliance/create-wui-appliance.sh b/wui-appliance/create-wui-appliance.sh index 8f27277..e30f47c 100755 --- a/wui-appliance/create-wui-appliance.sh +++ b/wui-appliance/create-wui-appliance.sh @@ -22,8 +22,10 @@ BRIDGENAME=failme usage() { case $# in 1) warn "$1"; try_h; exit 1;; esac cat < /dev/null 2>&1 virsh undefine $NAME > /dev/null 2>&1 + virt-install -n $NAME -r $RAM -f "$IMGDIR/$IMGNAME" -s $IMGSIZE --vnc \ - --accelerate -v -c "$ISO" --os-type=linux --arch=$ARCH \ - -w network:default -w network:$BRIDGENAME + --accelerate -v --os-type=linux --arch=$ARCH \ + -w network:default -w network:$BRIDGENAME \ + $location_arg $cdrom_arg $extra_flag "$extra_arg" From hbrock at redhat.com Thu May 22 19:02:27 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Thu, 22 May 2008 15:02:27 -0400 Subject: [Ovirt-devel] [PATCH] allow create-wui-appliance to use local repo tree along with ISO In-Reply-To: <4835C221.9080504@redhat.com> References: <4835C221.9080504@redhat.com> Message-ID: <20080522190227.GW14196@redhat.com> On Thu, May 22, 2008 at 02:57:37PM -0400, Perry N. Myers wrote: > This patch modifies create-wui-appliance.sh so that both a local ISO or an > install tree can be used to install the WUI appliance. The advantage of > using a local tree is that a kickstart file can be specified so that > manually entering the kickstart location during the boot process is not > necessary. > > Signed-off-by: Perry Myers > > diff --git a/wui-appliance/create-wui-appliance.sh b/wui-appliance/create-wui-appliance.sh > index 8f27277..e30f47c 100755 > --- a/wui-appliance/create-wui-appliance.sh > +++ b/wui-appliance/create-wui-appliance.sh > @@ -22,8 +22,10 @@ BRIDGENAME=failme > usage() { > case $# in 1) warn "$1"; try_h; exit 1;; esac > cat < -Usage: $ME -i install_iso [-d image_dir] [-a x86_64|i686] > - -i: location of installation ISO (required) > +Usage: $ME -i install_iso | -t install_tree [-d image_dir] [-a x86_64|i686] > + -i: location of installation ISO (required if -t not present) > + -t: location of installation tree (required if -i not present) > + -k: URL of kickstart file for use with installation tree > -d: directory to place virtual disk (default: $IMGDIR_DEFAULT) > -a: architecture for the virtual machine (default: $ARCH_DEFAULT) > -v: Install in developer mode (see http://ovirt.org for details) > @@ -34,24 +36,39 @@ EOF > > err=0 help=0 > devel=0 bundled=0 > -while getopts :a:d:i:hvb c; do > +while getopts :a:d:i:t:k:hvb c; do > case $c in > i) ISO=$OPTARG;; > + t) TREE=$OPTARG;; > + k) KICKSTART=$OPTARG;; > d) IMGDIR=$OPTARG;; > a) ARCH=$OPTARG;; > h) help=1;; > v) devel=1;; > b) bundled=1;; > - '?') err=1; warn "invalid option: \`-$OPTARG'";; > - :) err=1; warn "missing argument to \`-$OPTARG' option";; > + '?') err=1; warn "invalid option: \`-$OPTARG'";; > + :) err=1; warn "missing argument to \`-$OPTARG' option";; > *) err=1; warn "internal error: \`-$OPTARG' not handled";; > esac > done > test $err = 1 && { try_h; exit 1; } > test $help = 1 && { usage; exit 0; } > > -test -z "$ISO" && usage "no ISO file specified" > -test -r "$ISO" || usage "missing or unreadable ISO file: \`$ISO'" > +test -n "$ISO" -a -n "$TREE" && usage "Can only specify one of -i and -t" > +test -z "$ISO" -a -z "$TREE" && usage "Must specify one of -i and -t" > + > +if [ -n "$ISO" ]; then > + test -n "$KICKSTART" && usage "-k not valid in conjunction with -i" > + test -r "$ISO" || usage "missing or unreadable ISO file: \`$ISO'" > + cdrom_arg="-c $ISO" > +elif [ -n "$TREE" ]; then > + location_arg="-l $TREE" > +fi > + > +if [ -n "$KICKSTART" ]; then > + extra_flag=-x > + extra_arg="ksdevice=eth0 ks=$KICKSTART" > +fi > > test $devel = 1 -a $bundled = 1 && usage "Can only specify one of -v and -b" > test $devel = 0 -a $bundled = 0 && usage "Must specify one of -v or -b" > @@ -169,6 +186,8 @@ IMGNAME=$NAME.img > mkdir -p $IMGDIR > virsh destroy $NAME > /dev/null 2>&1 > virsh undefine $NAME > /dev/null 2>&1 > + > virt-install -n $NAME -r $RAM -f "$IMGDIR/$IMGNAME" -s $IMGSIZE --vnc \ > - --accelerate -v -c "$ISO" --os-type=linux --arch=$ARCH \ > - -w network:default -w network:$BRIDGENAME > + --accelerate -v --os-type=linux --arch=$ARCH \ > + -w network:default -w network:$BRIDGENAME \ > + $location_arg $cdrom_arg $extra_flag "$extra_arg" > ACK, very good idea... --H From pmyers at redhat.com Thu May 22 19:48:41 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Thu, 22 May 2008 15:48:41 -0400 Subject: [Ovirt-devel] [PATCH] separate out repo locations into repos.ks files Message-ID: <4835CE19.6020104@redhat.com> Not sure if everyone will think this is a good idea, but I get annoyed when I modify one of the ks to have my local mirrors and then get merge conflicts with other changes. This patch just splits out the repo/url definitions into separate files. ------------- Extract repo locations from the sections of the kickstart that might be modified during developement so that developers can overwrite with their local mirrors. Signed-off-by: Perry Myers diff --git a/ovirt-host-creator/common-install.ks b/ovirt-host-creator/common-install.ks index 2273531..8f4d175 100644 --- a/ovirt-host-creator/common-install.ks +++ b/ovirt-host-creator/common-install.ks @@ -9,6 +9,3 @@ services --enabled=ntpd,collectd,iptables,network bootloader --timeout=1 rootpw --iscrypted Xa8QeYfWrtscM -repo --name=f9 --mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=fedora-9&arch=$basearch -repo --name=f9-updates --mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=updates-released-f9&arch=$basearch - diff --git a/ovirt-host-creator/ovirt-i386.ks b/ovirt-host-creator/ovirt-i386.ks index 4911883..e58176a 100644 --- a/ovirt-host-creator/ovirt-i386.ks +++ b/ovirt-host-creator/ovirt-i386.ks @@ -1,5 +1,7 @@ %include common-install.ks +%include repos.ks + %packages --excludedocs %include common-pkgs.ks diff --git a/ovirt-host-creator/ovirt-x86_64.ks b/ovirt-host-creator/ovirt-x86_64.ks index 62f62d6..91aeea6 100644 --- a/ovirt-host-creator/ovirt-x86_64.ks +++ b/ovirt-host-creator/ovirt-x86_64.ks @@ -1,5 +1,7 @@ %include common-install.ks +%include repos.ks + %packages --excludedocs %include common-pkgs.ks -glibc.i686 diff --git a/ovirt-host-creator/repos.ks b/ovirt-host-creator/repos.ks new file mode 100644 index 0000000..6703b91 --- /dev/null +++ b/ovirt-host-creator/repos.ks @@ -0,0 +1,3 @@ +repo --name=f9 --mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=fedora-9&arch=$basearch +repo --name=f9-updates --mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=updates-released-f9&arch=$basearch + diff --git a/wui-appliance/repos.ks b/wui-appliance/repos.ks new file mode 100644 index 0000000..a182bde --- /dev/null +++ b/wui-appliance/repos.ks @@ -0,0 +1,8 @@ +url --url http://download.fedora.redhat.com/pub/fedora/linux/releases/9/Fedora/x86_64/os/ + +repo --name=f9 --mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=fedora-9&arch=x86_64 +repo --name=f9-updates --mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=updates-released-f9&arch=x86_64 +repo --name=ovirt --baseurl=http://ovirt.org/repos/ovirt/9/x86_64 +# temporary +repo --name=f9testing --includepkgs=rubygem-rubyforge,rubygem-activeldap,rubygem-hoe --mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=updates-testing-f9&arch=x86_64 + diff --git a/wui-appliance/wui-devel-x86_64.ks b/wui-appliance/wui-devel-x86_64.ks index 77dd3c5..84f0eae 100644 --- a/wui-appliance/wui-devel-x86_64.ks +++ b/wui-appliance/wui-devel-x86_64.ks @@ -1,5 +1,4 @@ install -url --url http://download.fedora.redhat.com/pub/fedora/linux/releases/9/Fedora/x86_64/os/ %include common-install.ks @@ -10,12 +9,7 @@ logvol /iscsi3 --name=iSCSI3 --vgname=VolGroup00 --size=64 logvol /iscsi4 --name=iSCSI4 --vgname=VolGroup00 --size=64 logvol /iscsi5 --name=iSCSI5 --vgname=VolGroup00 --size=64 -repo --name=f9 --mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=fedora-9&arch=x86_64 -repo --name=f9-updates --mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=updates-released-f9&arch=x86_64 -repo --name=ovirt-management --baseurl=http://ovirt.org/repos/ovirt/9/x86_64 -# temporary -repo --name=f9testing --includepkgs=rubygem-rubyforge,rubygem-activeldap,rubygem-hoe --mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=updates-testing-f9&arch=x86_64 - +%include repos.ks %packages From hbrock at redhat.com Thu May 22 20:24:49 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Thu, 22 May 2008 16:24:49 -0400 Subject: [Ovirt-devel] [PATCH] separate out repo locations into repos.ks files In-Reply-To: <4835CE19.6020104@redhat.com> References: <4835CE19.6020104@redhat.com> Message-ID: <20080522202449.GX14196@redhat.com> On Thu, May 22, 2008 at 03:48:41PM -0400, Perry N. Myers wrote: > Not sure if everyone will think this is a good idea, but I get annoyed when > I modify one of the ks to have my local mirrors and then get merge > conflicts with other changes. This patch just splits out the repo/url > definitions into separate files. > > ------------- > > Extract repo locations from the sections of the kickstart that might be modified > during developement so that developers can overwrite with their local mirrors. > Signed-off-by: Perry Myers > > diff --git a/ovirt-host-creator/common-install.ks b/ovirt-host-creator/common-install.ks > index 2273531..8f4d175 100644 > --- a/ovirt-host-creator/common-install.ks > +++ b/ovirt-host-creator/common-install.ks > @@ -9,6 +9,3 @@ services --enabled=ntpd,collectd,iptables,network > bootloader --timeout=1 > rootpw --iscrypted Xa8QeYfWrtscM > > -repo --name=f9 --mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=fedora-9&arch=$basearch > -repo --name=f9-updates --mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=updates-released-f9&arch=$basearch > - > diff --git a/ovirt-host-creator/ovirt-i386.ks b/ovirt-host-creator/ovirt-i386.ks > index 4911883..e58176a 100644 > --- a/ovirt-host-creator/ovirt-i386.ks > +++ b/ovirt-host-creator/ovirt-i386.ks > @@ -1,5 +1,7 @@ > %include common-install.ks > > +%include repos.ks > + > %packages --excludedocs > %include common-pkgs.ks > > diff --git a/ovirt-host-creator/ovirt-x86_64.ks b/ovirt-host-creator/ovirt-x86_64.ks > index 62f62d6..91aeea6 100644 > --- a/ovirt-host-creator/ovirt-x86_64.ks > +++ b/ovirt-host-creator/ovirt-x86_64.ks > @@ -1,5 +1,7 @@ > %include common-install.ks > > +%include repos.ks > + > %packages --excludedocs > %include common-pkgs.ks > -glibc.i686 > diff --git a/ovirt-host-creator/repos.ks b/ovirt-host-creator/repos.ks > new file mode 100644 > index 0000000..6703b91 > --- /dev/null > +++ b/ovirt-host-creator/repos.ks > @@ -0,0 +1,3 @@ > +repo --name=f9 --mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=fedora-9&arch=$basearch > +repo --name=f9-updates --mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=updates-released-f9&arch=$basearch > + > diff --git a/wui-appliance/repos.ks b/wui-appliance/repos.ks > new file mode 100644 > index 0000000..a182bde > --- /dev/null > +++ b/wui-appliance/repos.ks > @@ -0,0 +1,8 @@ > +url --url http://download.fedora.redhat.com/pub/fedora/linux/releases/9/Fedora/x86_64/os/ > + > +repo --name=f9 --mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=fedora-9&arch=x86_64 > +repo --name=f9-updates --mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=updates-released-f9&arch=x86_64 > +repo --name=ovirt --baseurl=http://ovirt.org/repos/ovirt/9/x86_64 > +# temporary > +repo --name=f9testing --includepkgs=rubygem-rubyforge,rubygem-activeldap,rubygem-hoe --mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=updates-testing-f9&arch=x86_64 > + > diff --git a/wui-appliance/wui-devel-x86_64.ks b/wui-appliance/wui-devel-x86_64.ks > index 77dd3c5..84f0eae 100644 > --- a/wui-appliance/wui-devel-x86_64.ks > +++ b/wui-appliance/wui-devel-x86_64.ks > @@ -1,5 +1,4 @@ > install > -url --url http://download.fedora.redhat.com/pub/fedora/linux/releases/9/Fedora/x86_64/os/ > > %include common-install.ks > > @@ -10,12 +9,7 @@ logvol /iscsi3 --name=iSCSI3 --vgname=VolGroup00 --size=64 > logvol /iscsi4 --name=iSCSI4 --vgname=VolGroup00 --size=64 > logvol /iscsi5 --name=iSCSI5 --vgname=VolGroup00 --size=64 > > -repo --name=f9 --mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=fedora-9&arch=x86_64 > -repo --name=f9-updates --mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=updates-released-f9&arch=x86_64 > -repo --name=ovirt-management --baseurl=http://ovirt.org/repos/ovirt/9/x86_64 > -# temporary > -repo --name=f9testing --includepkgs=rubygem-rubyforge,rubygem-activeldap,rubygem-hoe --mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=updates-testing-f9&arch=x86_64 > - > +%include repos.ks > > %packages ACK If it works for you, I'm fine with it... --Hugh From sseago at redhat.com Thu May 22 20:50:14 2008 From: sseago at redhat.com (Scott Seago) Date: Thu, 22 May 2008 16:50:14 -0400 Subject: [Ovirt-devel] [PATCH] styling for error messages, cleanup message display Message-ID: <4835DC86.9090203@redhat.com> -------------- next part -------------- A non-text attachment was scrubbed... Name: validation-styling.patch Type: text/x-patch Size: 6753 bytes Desc: not available URL: From hbrock at redhat.com Thu May 22 21:11:33 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Thu, 22 May 2008 17:11:33 -0400 Subject: [Ovirt-devel] [PATCH] styling for error messages, cleanup message display In-Reply-To: <4835DC86.9090203@redhat.com> References: <4835DC86.9090203@redhat.com> Message-ID: <20080522211133.GZ14196@redhat.com> On Thu, May 22, 2008 at 04:50:14PM -0400, Scott Seago wrote: > > >From a46b2229070f238e94f0a442fbc73b2a19ae6d46 Mon Sep 17 00:00:00 2001 > From: Scott Seago > Date: Thu, 22 May 2008 16:33:12 -0400 > Subject: [PATCH] styling for error messages, cleanup message display > > > Signed-off-by: Scott Seago > --- ACK I have committed this after testing several (if not all) the facebox popups with blank entries. We will need more validation of the validation when we get around to doing tests of this stuff... --HUgh From dpierce at redhat.com Thu May 22 21:19:16 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Thu, 22 May 2008 17:19:16 -0400 Subject: [Ovirt-devel] [PATCH] Modified LDAPConnection to work with an SRV record, then fallback to the ldap.yml file if necessary. Message-ID: <1211491156-15561-1-git-send-email-dpierce@redhat.com> Signed-off-by: Darryl L. Pierce --- wui/src/app/controllers/hardware_controller.rb | 2 +- wui/src/app/helpers/ldap_connection.rb | 25 ++++++++++++++++++----- wui/src/app/models/account.rb | 2 +- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/wui/src/app/controllers/hardware_controller.rb b/wui/src/app/controllers/hardware_controller.rb index 296fec3..54d9e91 100644 --- a/wui/src/app/controllers/hardware_controller.rb +++ b/wui/src/app/controllers/hardware_controller.rb @@ -144,7 +144,7 @@ class HardwareController < ApplicationController dates = [ Date::ABBR_MONTHNAMES[today.month] + ' ' + today.day.to_s ] 1.upto(6){ |x| # TODO get # of days from wui dte = today - x - dates.push ( Date::ABBR_MONTHNAMES[dte.month] + ' ' + dte.day.to_s ) + dates.push( Date::ABBR_MONTHNAMES[dte.month] + ' ' + dte.day.to_s ) } dates.reverse! # want in ascending order diff --git a/wui/src/app/helpers/ldap_connection.rb b/wui/src/app/helpers/ldap_connection.rb index af8b41b..f4815bf 100644 --- a/wui/src/app/helpers/ldap_connection.rb +++ b/wui/src/app/helpers/ldap_connection.rb @@ -21,15 +21,28 @@ # connections with an LDAP server. # class LDAPConnection - - @@config = YAML::load(File.open("#{RAILS_ROOT}/config/ldap.yml")) + @@config = YAML::load(File.open("#{RAILS_ROOT}/config/ldap.yml"))[ENV['RAILS_ENV']] # Connects the specified LDAP server. def self.connect(base = nil, host = nil, port = nil) + + # Use the SRV record for the LDAP server, otherwise + # default to what is defined in the ldap.yml file. + unless defined? host + unless defined? @host + Resolv::DNS.new + + dns.getresources("_ldap._tcp.local",Resolv::DNS::Resource::IN::SRV).collect do |resource| + @host = resource.address + end + end + + @host = @@config["host"] unless defined? @host + end - base = @@config[ENV['RAILS_ENV']]["base"] if base == nil - host = @@config[ENV['RAILS_ENV']]["host"] if host == nil - port = @@config[ENV['RAILS_ENV']]["port"] if port == nil + base = @@config["base"] if base == nil + host = @@config["host"] if host == nil + port = @@config["port"] if port == nil ActiveLdap::Base.establish_connection(:host => host, :port => port, @@ -38,7 +51,7 @@ class LDAPConnection # Returns whether a connection already exists to the LDAP server. def self.connected? - return ActiveLdap::Base.connected? + ActiveLdap::Base.connected? end # Disconnects from the LDAP server. diff --git a/wui/src/app/models/account.rb b/wui/src/app/models/account.rb index a2ed1d2..384beda 100644 --- a/wui/src/app/models/account.rb +++ b/wui/src/app/models/account.rb @@ -20,7 +20,7 @@ # +Account+ represents a single user's account from the LDAP server. # class Account < ActiveLdap::Base - ldap_mapping :dn_attribute => 'cn', :scope => :one, :prefix => 'cn=users,cn=accounts' + ldap_mapping :dn_attribute => 'cn', :scope => :one, :prefix => "cn=users,cn=accounts" @@users = nil -- 1.5.4.1 From dpierce at redhat.com Thu May 22 21:42:08 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Thu, 22 May 2008 17:42:08 -0400 Subject: [Ovirt-devel] [PATCH] Modified LDAPConnection to work with an SRV record, then fallback to the ldap.yml file if necessary. Message-ID: <1211492528-16944-1-git-send-email-dpierce@redhat.com> --- wui/src/app/controllers/hardware_controller.rb | 2 +- wui/src/app/helpers/ldap_connection.rb | 25 ++++++++++++++++++----- wui/src/app/models/account.rb | 2 +- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/wui/src/app/controllers/hardware_controller.rb b/wui/src/app/controllers/hardware_controller.rb index 296fec3..54d9e91 100644 --- a/wui/src/app/controllers/hardware_controller.rb +++ b/wui/src/app/controllers/hardware_controller.rb @@ -144,7 +144,7 @@ class HardwareController < ApplicationController dates = [ Date::ABBR_MONTHNAMES[today.month] + ' ' + today.day.to_s ] 1.upto(6){ |x| # TODO get # of days from wui dte = today - x - dates.push ( Date::ABBR_MONTHNAMES[dte.month] + ' ' + dte.day.to_s ) + dates.push( Date::ABBR_MONTHNAMES[dte.month] + ' ' + dte.day.to_s ) } dates.reverse! # want in ascending order diff --git a/wui/src/app/helpers/ldap_connection.rb b/wui/src/app/helpers/ldap_connection.rb index af8b41b..c953366 100644 --- a/wui/src/app/helpers/ldap_connection.rb +++ b/wui/src/app/helpers/ldap_connection.rb @@ -21,15 +21,28 @@ # connections with an LDAP server. # class LDAPConnection - - @@config = YAML::load(File.open("#{RAILS_ROOT}/config/ldap.yml")) + @@config = YAML::load(File.open("#{RAILS_ROOT}/config/ldap.yml"))[ENV['RAILS_ENV']] # Connects the specified LDAP server. def self.connect(base = nil, host = nil, port = nil) + + # Use the SRV record for the LDAP server, otherwise + # default to what is defined in the ldap.yml file. + unless defined? host + unless defined? @host + Resolv::DNS.new + + dns.getresources("_ldap._tcp.#{`domainname`}",Resolv::DNS::Resource::IN::SRV).collect do |resource| + @host = resource.address + end + end + + @host = @@config["host"] unless defined? @host + end - base = @@config[ENV['RAILS_ENV']]["base"] if base == nil - host = @@config[ENV['RAILS_ENV']]["host"] if host == nil - port = @@config[ENV['RAILS_ENV']]["port"] if port == nil + base = @@config["base"] if base == nil + host = @@config["host"] if host == nil + port = @@config["port"] if port == nil ActiveLdap::Base.establish_connection(:host => host, :port => port, @@ -38,7 +51,7 @@ class LDAPConnection # Returns whether a connection already exists to the LDAP server. def self.connected? - return ActiveLdap::Base.connected? + ActiveLdap::Base.connected? end # Disconnects from the LDAP server. diff --git a/wui/src/app/models/account.rb b/wui/src/app/models/account.rb index a2ed1d2..384beda 100644 --- a/wui/src/app/models/account.rb +++ b/wui/src/app/models/account.rb @@ -20,7 +20,7 @@ # +Account+ represents a single user's account from the LDAP server. # class Account < ActiveLdap::Base - ldap_mapping :dn_attribute => 'cn', :scope => :one, :prefix => 'cn=users,cn=accounts' + ldap_mapping :dn_attribute => 'cn', :scope => :one, :prefix => "cn=users,cn=accounts" @@users = nil -- 1.5.4.1 From dpierce at redhat.com Thu May 22 21:48:44 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Thu, 22 May 2008 17:48:44 -0400 Subject: [Ovirt-devel] [PATCH] Modified LDAPConnection to work with an SRV record, then fallback to the ldap.yml file if necessary. Message-ID: <1211492924-17316-1-git-send-email-dpierce@redhat.com> --- wui/src/app/controllers/hardware_controller.rb | 2 +- wui/src/app/helpers/ldap_connection.rb | 25 ++++++++++++++++++----- wui/src/app/models/account.rb | 2 +- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/wui/src/app/controllers/hardware_controller.rb b/wui/src/app/controllers/hardware_controller.rb index 296fec3..54d9e91 100644 --- a/wui/src/app/controllers/hardware_controller.rb +++ b/wui/src/app/controllers/hardware_controller.rb @@ -144,7 +144,7 @@ class HardwareController < ApplicationController dates = [ Date::ABBR_MONTHNAMES[today.month] + ' ' + today.day.to_s ] 1.upto(6){ |x| # TODO get # of days from wui dte = today - x - dates.push ( Date::ABBR_MONTHNAMES[dte.month] + ' ' + dte.day.to_s ) + dates.push( Date::ABBR_MONTHNAMES[dte.month] + ' ' + dte.day.to_s ) } dates.reverse! # want in ascending order diff --git a/wui/src/app/helpers/ldap_connection.rb b/wui/src/app/helpers/ldap_connection.rb index af8b41b..b19e504 100644 --- a/wui/src/app/helpers/ldap_connection.rb +++ b/wui/src/app/helpers/ldap_connection.rb @@ -21,15 +21,28 @@ # connections with an LDAP server. # class LDAPConnection - - @@config = YAML::load(File.open("#{RAILS_ROOT}/config/ldap.yml")) + @@config = YAML::load(File.open("#{RAILS_ROOT}/config/ldap.yml"))[ENV['RAILS_ENV']] # Connects the specified LDAP server. def self.connect(base = nil, host = nil, port = nil) + + # Use the SRV record for the LDAP server, otherwise + # default to what is defined in the ldap.yml file. + unless defined? host + unless defined? @host + Resolv::DNS.new + + dns.getresources("_ldap._tcp.#{`dnsdomainname`}",Resolv::DNS::Resource::IN::SRV).collect do |resource| + @host = resource.address + end + end + + @host = @@config["host"] unless defined? @host + end - base = @@config[ENV['RAILS_ENV']]["base"] if base == nil - host = @@config[ENV['RAILS_ENV']]["host"] if host == nil - port = @@config[ENV['RAILS_ENV']]["port"] if port == nil + base = @@config["base"] if base == nil + host = @@config["host"] if host == nil + port = @@config["port"] if port == nil ActiveLdap::Base.establish_connection(:host => host, :port => port, @@ -38,7 +51,7 @@ class LDAPConnection # Returns whether a connection already exists to the LDAP server. def self.connected? - return ActiveLdap::Base.connected? + ActiveLdap::Base.connected? end # Disconnects from the LDAP server. diff --git a/wui/src/app/models/account.rb b/wui/src/app/models/account.rb index a2ed1d2..384beda 100644 --- a/wui/src/app/models/account.rb +++ b/wui/src/app/models/account.rb @@ -20,7 +20,7 @@ # +Account+ represents a single user's account from the LDAP server. # class Account < ActiveLdap::Base - ldap_mapping :dn_attribute => 'cn', :scope => :one, :prefix => 'cn=users,cn=accounts' + ldap_mapping :dn_attribute => 'cn', :scope => :one, :prefix => "cn=users,cn=accounts" @@users = nil -- 1.5.4.1 From hbrock at redhat.com Thu May 22 21:56:23 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Thu, 22 May 2008 17:56:23 -0400 Subject: [Ovirt-devel] [PATCH] Modified LDAPConnection to work with an SRV record, then fallback to the ldap.yml file if necessary. In-Reply-To: <1211492924-17316-1-git-send-email-dpierce@redhat.com> References: <1211492924-17316-1-git-send-email-dpierce@redhat.com> Message-ID: <20080522215623.GC14196@redhat.com> On Thu, May 22, 2008 at 05:48:44PM -0400, Darryl L. Pierce wrote: > --- > wui/src/app/controllers/hardware_controller.rb | 2 +- > wui/src/app/helpers/ldap_connection.rb | 25 ++++++++++++++++++----- > wui/src/app/models/account.rb | 2 +- > 3 files changed, 21 insertions(+), 8 deletions(-) > > diff --git a/wui/src/app/controllers/hardware_controller.rb b/wui/src/app/controllers/hardware_controller.rb > index 296fec3..54d9e91 100644 > --- a/wui/src/app/controllers/hardware_controller.rb > +++ b/wui/src/app/controllers/hardware_controller.rb > @@ -144,7 +144,7 @@ class HardwareController < ApplicationController > dates = [ Date::ABBR_MONTHNAMES[today.month] + ' ' + today.day.to_s ] > 1.upto(6){ |x| # TODO get # of days from wui > dte = today - x > - dates.push ( Date::ABBR_MONTHNAMES[dte.month] + ' ' + dte.day.to_s ) > + dates.push( Date::ABBR_MONTHNAMES[dte.month] + ' ' + dte.day.to_s ) > } > dates.reverse! # want in ascending order What's the reason for this change? Does the extra space between "push" and "(" matter? > diff --git a/wui/src/app/helpers/ldap_connection.rb b/wui/src/app/helpers/ldap_connection.rb > index af8b41b..b19e504 100644 > --- a/wui/src/app/helpers/ldap_connection.rb > +++ b/wui/src/app/helpers/ldap_connection.rb > @@ -21,15 +21,28 @@ > # connections with an LDAP server. > # > class LDAPConnection > - > - @@config = YAML::load(File.open("#{RAILS_ROOT}/config/ldap.yml")) > + @@config = YAML::load(File.open("#{RAILS_ROOT}/config/ldap.yml"))[ENV['RAILS_ENV']] > > # Connects the specified LDAP server. > def self.connect(base = nil, host = nil, port = nil) > + > + # Use the SRV record for the LDAP server, otherwise > + # default to what is defined in the ldap.yml file. > + unless defined? host > + unless defined? @host > + Resolv::DNS.new > + > + dns.getresources("_ldap._tcp.#{`dnsdomainname`}",Resolv::DNS::Resource::IN::SRV).collect do |resource| > + @host = resource.address > + end > + end > + > + @host = @@config["host"] unless defined? @host > + end OK, but there must be a way to get the local domain from a Ruby syscall I would think... (i.e. instead of `dnsdomainname`) > > - base = @@config[ENV['RAILS_ENV']]["base"] if base == nil > - host = @@config[ENV['RAILS_ENV']]["host"] if host == nil > - port = @@config[ENV['RAILS_ENV']]["port"] if port == nil > + base = @@config["base"] if base == nil > + host = @@config["host"] if host == nil > + port = @@config["port"] if port == nil > > ActiveLdap::Base.establish_connection(:host => host, > :port => port, > @@ -38,7 +51,7 @@ class LDAPConnection > > # Returns whether a connection already exists to the LDAP server. > def self.connected? > - return ActiveLdap::Base.connected? > + ActiveLdap::Base.connected? > end > > # Disconnects from the LDAP server. > diff --git a/wui/src/app/models/account.rb b/wui/src/app/models/account.rb > index a2ed1d2..384beda 100644 > --- a/wui/src/app/models/account.rb > +++ b/wui/src/app/models/account.rb > @@ -20,7 +20,7 @@ > # +Account+ represents a single user's account from the LDAP server. > # > class Account < ActiveLdap::Base > - ldap_mapping :dn_attribute => 'cn', :scope => :one, :prefix => 'cn=users,cn=accounts' > + ldap_mapping :dn_attribute => 'cn', :scope => :one, :prefix => "cn=users,cn=accounts" > > @@users = nil Again, do the single vs. double quotes matter here? Why the change? Thanks, --Hugh From pmyers at redhat.com Thu May 22 23:40:44 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Thu, 22 May 2008 19:40:44 -0400 Subject: [Ovirt-devel] [PATCH] Modified LDAPConnection to work with an SRV record, then fallback to the ldap.yml file if necessary. In-Reply-To: <1211492924-17316-1-git-send-email-dpierce@redhat.com> References: <1211492924-17316-1-git-send-email-dpierce@redhat.com> Message-ID: <4836047C.3060501@redhat.com> Darryl L. Pierce wrote: > --- > wui/src/app/controllers/hardware_controller.rb | 2 +- > wui/src/app/helpers/ldap_connection.rb | 25 ++++++++++++++++++----- > wui/src/app/models/account.rb | 2 +- > 3 files changed, 21 insertions(+), 8 deletions(-) There are still references in the source tree to ActiveLdap::Base.establish_connection, which uses the data from the ldap.yml file. As far as I can tell, nothing in the source tree even uses this LDAPConnection class. (Granted, I know nothing about Ruby. I just did a grep for LDAPConnection and nothing came up except for ldap_connection.rb) account.rb says: # This API requires that a previous connection be made using # +LDAPConnection.connect+. But nothing seems to call LDAPConnection.connect So how is this supposed to work? NACK until these issues are corrected. Perry From pmyers at redhat.com Fri May 23 00:33:40 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Thu, 22 May 2008 20:33:40 -0400 Subject: [Ovirt-devel] [PATCH] Modified LDAPConnection to work with an SRV record, then fallback to the ldap.yml file if necessary. In-Reply-To: <1211492924-17316-1-git-send-email-dpierce@redhat.com> References: <1211492924-17316-1-git-send-email-dpierce@redhat.com> Message-ID: <483610E4.3090106@redhat.com> Darryl L. Pierce wrote: > --- > wui/src/app/controllers/hardware_controller.rb | 2 +- > wui/src/app/helpers/ldap_connection.rb | 25 ++++++++++++++++++----- > wui/src/app/models/account.rb | 2 +- > 3 files changed, 21 insertions(+), 8 deletions(-) > > diff --git a/wui/src/app/controllers/hardware_controller.rb b/wui/src/app/controllers/hardware_controller.rb > index 296fec3..54d9e91 100644 > --- a/wui/src/app/controllers/hardware_controller.rb > +++ b/wui/src/app/controllers/hardware_controller.rb > @@ -144,7 +144,7 @@ class HardwareController < ApplicationController > dates = [ Date::ABBR_MONTHNAMES[today.month] + ' ' + today.day.to_s ] > 1.upto(6){ |x| # TODO get # of days from wui > dte = today - x > - dates.push ( Date::ABBR_MONTHNAMES[dte.month] + ' ' + dte.day.to_s ) > + dates.push( Date::ABBR_MONTHNAMES[dte.month] + ' ' + dte.day.to_s ) > } > dates.reverse! # want in ascending order > > diff --git a/wui/src/app/helpers/ldap_connection.rb b/wui/src/app/helpers/ldap_connection.rb > index af8b41b..b19e504 100644 > --- a/wui/src/app/helpers/ldap_connection.rb > +++ b/wui/src/app/helpers/ldap_connection.rb > @@ -21,15 +21,28 @@ > # connections with an LDAP server. > # > class LDAPConnection > - > - @@config = YAML::load(File.open("#{RAILS_ROOT}/config/ldap.yml")) > + @@config = YAML::load(File.open("#{RAILS_ROOT}/config/ldap.yml"))[ENV['RAILS_ENV']] > > # Connects the specified LDAP server. > def self.connect(base = nil, host = nil, port = nil) > + > + # Use the SRV record for the LDAP server, otherwise > + # default to what is defined in the ldap.yml file. > + unless defined? host > + unless defined? @host > + Resolv::DNS.new > + > + dns.getresources("_ldap._tcp.#{`dnsdomainname`}",Resolv::DNS::Resource::IN::SRV).collect do |resource| > + @host = resource.address You're not getting the port from dns srv as well? We should be getting both host and port from the dns srv record. > + end > + end > + > + @host = @@config["host"] unless defined? @host > + end > > - base = @@config[ENV['RAILS_ENV']]["base"] if base == nil > - host = @@config[ENV['RAILS_ENV']]["host"] if host == nil > - port = @@config[ENV['RAILS_ENV']]["port"] if port == nil > + base = @@config["base"] if base == nil > + host = @@config["host"] if host == nil > + port = @@config["port"] if port == nil Where is base confgured from? If it's the default obtained from ldap.yaml it'll be wrong. It would seem that you should calculate what base is using the value of host. i.e. if host is foo.bar.com then base should be dc=bar,dc=com. > ActiveLdap::Base.establish_connection(:host => host, > :port => port, > @@ -38,7 +51,7 @@ class LDAPConnection > > # Returns whether a connection already exists to the LDAP server. > def self.connected? > - return ActiveLdap::Base.connected? > + ActiveLdap::Base.connected? > end > > # Disconnects from the LDAP server. > diff --git a/wui/src/app/models/account.rb b/wui/src/app/models/account.rb > index a2ed1d2..384beda 100644 > --- a/wui/src/app/models/account.rb > +++ b/wui/src/app/models/account.rb > @@ -20,7 +20,7 @@ > # +Account+ represents a single user's account from the LDAP server. > # > class Account < ActiveLdap::Base > - ldap_mapping :dn_attribute => 'cn', :scope => :one, :prefix => 'cn=users,cn=accounts' > + ldap_mapping :dn_attribute => 'cn', :scope => :one, :prefix => "cn=users,cn=accounts" > > @@users = nil > -- |=- Red Hat, Engineering, Emerging Technologies, Boston -=| |=- Email: pmyers at redhat.com -=| |=- Office: +1 412 474 3552 Mobile: +1 703 362 9622 -=| |=- GnuPG: E65E4F3D 88F9 F1C9 C2F3 1303 01FE 817C C5D2 8B91 E65E 4F3D -=| From pmyers at redhat.com Fri May 23 01:40:40 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Thu, 22 May 2008 21:40:40 -0400 Subject: [Ovirt-devel] [PATCH] set ldap.yml from dns srv during ovirt-wui-install Message-ID: <48362098.5060908@redhat.com> Doing the DNS SRV lookup from Ruby directly is where we want to be (and with Darryl's patches we're almost there) but I decided it wouldn't hurt to edit ldap.yml as part of the install. dig is used to look up the srv record and then if one is found, ldap.yml is edited. I've tested this and verified that it does set the yml file correctly, but even with that set correctly I still can't get the grant_admin_privileges to work properly. Signed-off-by: Perry Myers diff --git a/wui/scripts/ovirt-wui-install b/wui/scripts/ovirt-wui-install index e0cbbc0..f0f8b3e 100755 --- a/wui/scripts/ovirt-wui-install +++ b/wui/scripts/ovirt-wui-install @@ -11,6 +11,7 @@ PW_FILE=${OVIRT_CFG}/db/dbaccess STEP_TICKER=0.fedora.pool.ntp.org STEP_FILE=/etc/ntp/step-tickers SASL_FILE=/etc/sasl2/libvirt.conf +LDAP_CFG=${OVIRT_DIR}/config/ldap.yml DISABLE_SVCS="libvirtd" ENABLE_SVCS="ntpd httpd postgresql ovirt-host-browser ovirt-host-status \ @@ -23,6 +24,17 @@ usage() { exit 1 } >&2 +find_srv() { + local dnsreply + dnsreply=$(dig +short -t srv _$1._$2.$(dnsdomainname)) + if [ $? -eq 0 ]; then + set _ $dnsreply; shift + SRV_HOST=$4; SRV_PORT=$3 + else + SRV_HOST=; SRV_PORT= + fi +} + PASSWD= for i ; do case $1 in @@ -46,6 +58,18 @@ for svc in $ENABLE_SVCS ; do done } > /dev/null 2>&1 +# grab ldap server from DNS +find_srv ldap tcp +if [ -n "$SRV_HOST" -a -n "$SRV_PORT" ]; then + SRV_HOST=${SRV_HOST%.} + SRV_BASE=$(echo $SRV_HOST | awk -F. '{ for(i=2; i <= NF; i++) { printf("dc=%s", $(i)); if(i /dev/null 2>&1 ; then From pmyers at redhat.com Fri May 23 02:59:20 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Thu, 22 May 2008 22:59:20 -0400 Subject: [Ovirt-devel] [PATCH] correct error in dnsmasq for ldap DNS SRV record Message-ID: <48363308.9030601@redhat.com> So... Here's one reason why we're having so many problems with ldap connectivity... This has already been committed :) diff --git a/wui-appliance/wui-devel-x86_64.ks b/wui-appliance/wui-devel-x86_64.ks index 84f0eae..1294c89 100644 --- a/wui-appliance/wui-devel-x86_64.ks +++ b/wui-appliance/wui-devel-x86_64.ks @@ -177,7 +177,7 @@ start() { -s priv.ovirt.org \ -W _ovirt._tcp,management.priv.ovirt.org,80 \ -W _ipa._tcp,management.priv.ovirt.org,80 \ - -W _ldap._tcp,managment.priv.ovirt.org,389 \ + -W _ldap._tcp,management.priv.ovirt.org,389 \ -W _collectd._tcp,management.priv.ovirt.org,25826 \ --enable-tftp --tftp-root=/tftpboot -M pxelinux.0 \ -O option:router,192.168.50.1 -O option:ntp-server,192.168.50.2 \ From pmyers at redhat.com Fri May 23 05:11:56 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Fri, 23 May 2008 01:11:56 -0400 Subject: [Ovirt-devel] [PATCH] REPOST - set ldap.yml from dns srv during ovirt-wui-install In-Reply-To: <48362098.5060908@redhat.com> References: <48362098.5060908@redhat.com> Message-ID: <4836521C.90406@redhat.com> From pmyers at redhat.com Fri May 23 05:15:40 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Fri, 23 May 2008 01:15:40 -0400 Subject: [Ovirt-devel] Re: [PATCH] [REPOST] set ldap.yml from dns srv during ovirt-wui-install In-Reply-To: <48362098.5060908@redhat.com> References: <48362098.5060908@redhat.com> Message-ID: <483652FC.1000902@redhat.com> Subject: [PATCH] This patch adds logic to the ovirt-wui-install script to attempt to determine the ldap server information from dns srv records and then write that info to the ldap.yml file. Signed-off-by: Perry Myers --- wui/scripts/ovirt-wui-install | 66 ++++++++++++++++++++++++++++++++++++++++- 1 files changed, 65 insertions(+), 1 deletions(-) diff --git a/wui/scripts/ovirt-wui-install b/wui/scripts/ovirt-wui-install index e0cbbc0..6285b3c 100755 --- a/wui/scripts/ovirt-wui-install +++ b/wui/scripts/ovirt-wui-install @@ -11,6 +11,7 @@ PW_FILE=${OVIRT_CFG}/db/dbaccess STEP_TICKER=0.fedora.pool.ntp.org STEP_FILE=/etc/ntp/step-tickers SASL_FILE=/etc/sasl2/libvirt.conf +LDAP_CFG=${OVIRT_DIR}/config/ldap.yml DISABLE_SVCS="libvirtd" ENABLE_SVCS="ntpd httpd postgresql ovirt-host-browser ovirt-host-status \ @@ -23,6 +24,52 @@ usage() { exit 1 } >&2 +find_srv() { + local dnsreply + + # This checks to see if we're running on a bundled/developer install. + # If so, the server queried is localhost instead of using resolv.conf. + if [ "$(hostname)" == "management.priv.ovirt.org" ]; then + local server_flag=@localhost + fi + + dnsreply=$(dig $server_flag +short -t srv _$1._$2.$(dnsdomainname)) + if [ $? -eq 0 ]; then + set _ $dnsreply; shift + SRV_HOST=$4; SRV_PORT=$3 + else + SRV_HOST=; SRV_PORT= + fi +} + +find_ldap_base() { + local found=0 + + domain=$(echo $SRV_HOST | cut -d. -f 2-) + while [ -n "$domain" ]; do + base=$(echo $domain | awk -F. '{ for(i=1; i <= NF; i++) { printf("dc=%s", $(i)); if(i /dev/null 2>&1 + if [ $? -eq 0 ]; then + found=1 + break + fi + + if ! echo $domain | grep "\." > /dev/null 2>&1 ; then + domain="" + else + domain=$(echo $domain | cut -d. -f 2-) + fi + done + + if [ $found -eq 1 ]; then + echo $base + return 0 + else + return 1 + fi +} + PASSWD= for i ; do case $1 in @@ -46,10 +93,27 @@ for svc in $ENABLE_SVCS ; do done } > /dev/null 2>&1 +# grab ldap server from DNS +find_srv ldap tcp +if [ -n "$SRV_HOST" -a -n "$SRV_PORT" ]; then + SRV_HOST=${SRV_HOST%.} + srv_base=$(find_ldap_base) + [ $? != 0 ] && echo "Failed to determine base for ldap" && exit 1 + + sed -i -e "s/host: .*/host: $SRV_HOST/g" \ + -e "s/port: .*/port: $SRV_PORT/g" \ + -e "s/base: .*/base: $srv_base/g" \ + $LDAP_CFG +else + # FIXME: Eventually this script should prompt for things that can't + # be found in DNS SRV records. + echo "Failed to get ldap host/port" && exit 1 +fi + # setup an NTP step-ticker if [ -f $STEP_FILE ]; then if ! grep "^$${STEP_TICKER}$" $STEP_FILE > /dev/null 2>&1 ; then - echo $STEP_TICKER >> $STEP_FILE + echo $STEP_TICKER >> $STEP_FILE fi fi From pmyers at redhat.com Fri May 23 05:17:35 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Fri, 23 May 2008 01:17:35 -0400 Subject: [Ovirt-devel] [PATCH] fix ovirt service startup in ovirt-wui-install script Message-ID: <4836536F.1050501@redhat.com> Subject: [PATCH] Split the services that need to be turned on into chkconfig into base services and ovirt specific services. This is so at the end of the install script these services can be started in a loop. Also, remove the disable services loop since it only contains libvirtd and we don't want to always disable libvirtd when we install ovirt Signed-off-by: Perry Myers --- wui/scripts/ovirt-wui-install | 17 ++++++++--------- 1 files changed, 8 insertions(+), 9 deletions(-) diff --git a/wui/scripts/ovirt-wui-install b/wui/scripts/ovirt-wui-install index 6285b3c..3eb1c4d 100755 --- a/wui/scripts/ovirt-wui-install +++ b/wui/scripts/ovirt-wui-install @@ -13,9 +13,9 @@ STEP_FILE=/etc/ntp/step-tickers SASL_FILE=/etc/sasl2/libvirt.conf LDAP_CFG=${OVIRT_DIR}/config/ldap.yml -DISABLE_SVCS="libvirtd" -ENABLE_SVCS="ntpd httpd postgresql ovirt-host-browser ovirt-host-status \ - ovirt-taskomatic ovirt-host-keyadd ovirt-mongrel-rails" +OVIRT_SVCS="ovirt-host-browser ovirt-host-status \ + ovirt-taskomatic ovirt-host-keyadd ovirt-mongrel-rails" +ENABLE_SVCS="ntpd httpd postgresql" usage() { echo "usage: $0 [-p password]" @@ -83,12 +83,7 @@ for i ; do done { -for svc in $DISABLE_SVCS ; do - chkconfig $svc off - service $svc off -done - -for svc in $ENABLE_SVCS ; do +for svc in $ENABLE_SVCS $OVIRT_SVCS; do chkconfig $svc on done } > /dev/null 2>&1 @@ -182,5 +177,9 @@ if [ -f /etc/httpd/conf.d/ipa.conf ]; then service ipa_webgui restart fi +for svc in $OVIRT_SVCS ; do + service $svc start +done + exit 0 From pmyers at redhat.com Fri May 23 05:19:31 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Fri, 23 May 2008 01:19:31 -0400 Subject: [Ovirt-devel] [PATCH] fix ovirt service startup in ovirt-wui-install script In-Reply-To: <4836536F.1050501@redhat.com> References: <4836536F.1050501@redhat.com> Message-ID: <483653E3.3090002@redhat.com> Perry N. Myers wrote: > > Subject: [PATCH] Split the services that need to be turned on into > chkconfig into base > services and ovirt specific services. This is so at the end of the > install script these services can be started in a loop. > > Also, remove the disable services loop since it only contains > libvirtd and we don't want to always disable libvirtd when we > install ovirt Btw, with this patch and with the patch to fix ldap.yml via the ovirt-wui-install script, ([PATCH] set ldap.yml from dns srv during ovirt-wui-install) I'm now able to install the wui appliance in developer mode and on first boot everything comes up and is working well. Perry From clalance at redhat.com Fri May 23 06:31:19 2008 From: clalance at redhat.com (Chris Lalancette) Date: Fri, 23 May 2008 08:31:19 +0200 Subject: [Ovirt-devel] [PATCH] fix ovirt service startup in ovirt-wui-install script In-Reply-To: <4836536F.1050501@redhat.com> References: <4836536F.1050501@redhat.com> Message-ID: <483664B7.2000705@redhat.com> Perry N. Myers wrote: > Subject: [PATCH] Split the services that need to be turned on into chkconfig into base > services and ovirt specific services. This is so at the end of the > install script these services can be started in a loop. > > Also, remove the disable services loop since it only contains > libvirtd and we don't want to always disable libvirtd when we > install ovirt > > Signed-off-by: Perry Myers We actually probably do want libvirtd running on the WUI anyway, because we may be able to use it as a fallback (if we can't find a suitable, running host at the moment) to do some of our "scanning" type stuff in taskomatic. In that vein, the patch is fine, but I would add libvirtd to the list of ENABLE_SVCS. ACK otherwise Chris Lalancette From clalance at redhat.com Fri May 23 06:34:37 2008 From: clalance at redhat.com (Chris Lalancette) Date: Fri, 23 May 2008 08:34:37 +0200 Subject: [Ovirt-devel] [PATCH] Modified LDAPConnection to work with an SRV record, then fallback to the ldap.yml file if necessary. In-Reply-To: <20080522215623.GC14196@redhat.com> References: <1211492924-17316-1-git-send-email-dpierce@redhat.com> <20080522215623.GC14196@redhat.com> Message-ID: <4836657D.4070902@redhat.com> Hugh O. Brock wrote: >> # Connects the specified LDAP server. >> def self.connect(base = nil, host = nil, port = nil) >> + >> + # Use the SRV record for the LDAP server, otherwise >> + # default to what is defined in the ldap.yml file. >> + unless defined? host >> + unless defined? @host >> + Resolv::DNS.new >> + >> + dns.getresources("_ldap._tcp.#{`dnsdomainname`}",Resolv::DNS::Resource::IN::SRV).collect do |resource| >> + @host = resource.address >> + end >> + end >> + >> + @host = @@config["host"] unless defined? @host >> + end > > OK, but there must be a way to get the local domain from a Ruby > syscall I would think... (i.e. instead of `dnsdomainname`) Yeah, agreed. I think there are some methods in the socket class that might do this for you. If not, I'm sure there is some native Ruby way to do this, which is better than shelling out. Chris Lalancette From dpierce at redhat.com Fri May 23 13:51:19 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Fri, 23 May 2008 09:51:19 -0400 Subject: [Ovirt-devel] Re: Modified LDAPConnection to work with an SRV record, then fallback to the ldap.yml file if necessary. In-Reply-To: <483610E4.3090106@redhat.com> References: <1211492924-17316-1-git-send-email-dpierce@redhat.com> <483610E4.3090106@redhat.com> Message-ID: <20080523135119.GA10366@redhat.com> +++ Perry N. Myers [22/05/08 20:33 -0400]: >> + dns.getresources("_ldap._tcp.#{`dnsdomainname`}",Resolv::DNS::Resource::IN::SRV).collect do |resource| >> + @host = resource.address > > You're not getting the port from dns srv as well? We should be getting > both host and port from the dns srv record. Okay, I'll update and send a new patch out. >> + base = @@config["base"] if base == nil >> + host = @@config["host"] if host == nil >> + port = @@config["port"] if port == nil > > Where is base confgured from? If it's the default obtained from ldap.yaml > it'll be wrong. It would seem that you should calculate what base is using > the value of host. i.e. if host is foo.bar.com then base should be > dc=bar,dc=com. "base" is being pulled from ldap.yml as well. But I think determining it from the hostname might not be correct, either, yes? For example, the server in Boston is ovirt-freeipa.lab.bos.redhat.com but it's base is dc=ovirt-devel,dc=redhat,dc=com which you couldn't determine from the hostname. -- Darryl L. Pierce - Phone: (919) 754-4383 Sr. Software Engineer -- Red Hat, Inc. "In matters of style, swim with the current; In matters of principle, stand like a rock." - Thomas Jefferson -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 189 bytes Desc: not available URL: From dpierce at redhat.com Fri May 23 13:54:45 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Fri, 23 May 2008 09:54:45 -0400 Subject: [Ovirt-devel] Re: Modified LDAPConnection to work with an SRV record, then fallback to the ldap.yml file if necessary. In-Reply-To: <4836047C.3060501@redhat.com> References: <1211492924-17316-1-git-send-email-dpierce@redhat.com> <4836047C.3060501@redhat.com> Message-ID: <20080523135445.GB10366@redhat.com> +++ Perry N. Myers [22/05/08 19:40 -0400]: > Darryl L. Pierce wrote: >> --- >> wui/src/app/controllers/hardware_controller.rb | 2 +- >> wui/src/app/helpers/ldap_connection.rb | 25 ++++++++++++++++++----- >> wui/src/app/models/account.rb | 2 +- >> 3 files changed, 21 insertions(+), 8 deletions(-) > > There are still references in the source tree to > ActiveLdap::Base.establish_connection, which uses the data from the > ldap.yml file. > > As far as I can tell, nothing in the source tree even uses this > LDAPConnection class. (Granted, I know nothing about Ruby. I just did a > grep for LDAPConnection and nothing came up except for ldap_connection.rb) grant_admin_privileges calls LDAPConnection.connect to establish a connection prior to confirming the uid is valid. > account.rb says: > # This API requires that a previous connection be made using > # +LDAPConnection.connect+. > > But nothing seems to call LDAPConnection.connect > > So how is this supposed to work? I'll fix this and resend a patch today. -- Darryl L. Pierce - Phone: (919) 754-4383 Sr. Software Engineer -- Red Hat, Inc. "In matters of style, swim with the current; In matters of principle, stand like a rock." - Thomas Jefferson -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 189 bytes Desc: not available URL: From hbrock at redhat.com Fri May 23 14:09:18 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Fri, 23 May 2008 10:09:18 -0400 Subject: [Ovirt-devel] Re: [PATCH] [REPOST] set ldap.yml from dns srv during ovirt-wui-install In-Reply-To: <483652FC.1000902@redhat.com> References: <48362098.5060908@redhat.com> <483652FC.1000902@redhat.com> Message-ID: <20080523140911.GD14196@redhat.com> On Fri, May 23, 2008 at 01:15:40AM -0400, Perry N. Myers wrote: > > Subject: [PATCH] This patch adds logic to the ovirt-wui-install script to attempt to determine > the ldap server information from dns srv records and then write that info > to the ldap.yml file. > > Signed-off-by: Perry Myers > --- > wui/scripts/ovirt-wui-install | 66 ++++++++++++++++++++++++++++++++++++++++- > 1 files changed, 65 insertions(+), 1 deletions(-) > > diff --git a/wui/scripts/ovirt-wui-install b/wui/scripts/ovirt-wui-install > index e0cbbc0..6285b3c 100755 > --- a/wui/scripts/ovirt-wui-install > +++ b/wui/scripts/ovirt-wui-install > @@ -11,6 +11,7 @@ PW_FILE=${OVIRT_CFG}/db/dbaccess > STEP_TICKER=0.fedora.pool.ntp.org > STEP_FILE=/etc/ntp/step-tickers > SASL_FILE=/etc/sasl2/libvirt.conf > +LDAP_CFG=${OVIRT_DIR}/config/ldap.yml > > DISABLE_SVCS="libvirtd" ENABLE_SVCS="ntpd httpd postgresql > ovirt-host-browser ovirt-host-status \ > @@ -23,6 +24,52 @@ usage() { > exit 1 > } >&2 > > +find_srv() { > + local dnsreply > + + # This checks to see if we're running on a bundled/developer > install. + # If so, the server queried is localhost instead of using > resolv.conf. + if [ "$(hostname)" == "management.priv.ovirt.org" ]; > then > + local server_flag=@localhost > + fi > + > + dnsreply=$(dig $server_flag +short -t srv _$1._$2.$(dnsdomainname)) > + if [ $? -eq 0 ]; then > + set _ $dnsreply; shift > + SRV_HOST=$4; SRV_PORT=$3 > + else > + SRV_HOST=; SRV_PORT= > + fi > +} > + > +find_ldap_base() { > + local found=0 > + + domain=$(echo $SRV_HOST | cut -d. -f 2-) > + while [ -n "$domain" ]; do > + base=$(echo $domain | awk -F. '{ for(i=1; i <= NF; i++) { printf("dc=%s", $(i)); if(i + ldapsearch -h $SRV_HOST -p $SRV_PORT -x \ > + -b "cn=users,cn=accounts,$base" -LLL uid > /dev/null 2>&1 > + if [ $? -eq 0 ]; then > + found=1 > + break > + fi > + + if ! echo $domain | grep "\." > /dev/null 2>&1 ; then > + domain="" > + else > + domain=$(echo $domain | cut -d. -f 2-) > + fi > + done > + + if [ $found -eq 1 ]; then > + echo $base > + return 0 > + else > + return 1 > + fi +} > + > PASSWD= > for i ; do > case $1 in > @@ -46,10 +93,27 @@ for svc in $ENABLE_SVCS ; do > done > } > /dev/null 2>&1 > > +# grab ldap server from DNS > +find_srv ldap tcp > +if [ -n "$SRV_HOST" -a -n "$SRV_PORT" ]; then > + SRV_HOST=${SRV_HOST%.} > + srv_base=$(find_ldap_base) > + [ $? != 0 ] && echo "Failed to determine base for ldap" && exit 1 > + + sed -i -e "s/host: .*/host: $SRV_HOST/g" \ > + -e "s/port: .*/port: $SRV_PORT/g" \ > + -e "s/base: .*/base: $srv_base/g" \ > + $LDAP_CFG > +else > + # FIXME: Eventually this script should prompt for things that can't > + # be found in DNS SRV records. > + echo "Failed to get ldap host/port" && exit 1 > +fi > + > # setup an NTP step-ticker > if [ -f $STEP_FILE ]; then > if ! grep "^$${STEP_TICKER}$" $STEP_FILE > /dev/null 2>&1 ; then > - echo $STEP_TICKER >> $STEP_FILE > + echo $STEP_TICKER >> $STEP_FILE > fi > fi ACK... but I think your mailer mangled it. We have got to get this mailman problem fixed. --Hugh From pmyers at redhat.com Fri May 23 14:27:14 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Fri, 23 May 2008 10:27:14 -0400 Subject: [Ovirt-devel] Re: [PATCH] [REPOST] set ldap.yml from dns srv during ovirt-wui-install In-Reply-To: <20080523140911.GD14196@redhat.com> References: <48362098.5060908@redhat.com> <483652FC.1000902@redhat.com> <20080523140911.GD14196@redhat.com> Message-ID: <4836D442.5050308@redhat.com> [snip] > ACK... but I think your mailer mangled it. We have got to get this mailman problem fixed. > > --Hugh Yeah, it was either thunderbird or the list that mangled it. I think I'm going to start sending patches from the command line instead of trying to do it via a MUA. Perry -- |=- Red Hat, Engineering, Emerging Technologies, Boston -=| |=- Email: pmyers at redhat.com -=| |=- Office: +1 412 474 3552 Mobile: +1 703 362 9622 -=| |=- GnuPG: E65E4F3D 88F9 F1C9 C2F3 1303 01FE 817C C5D2 8B91 E65E 4F3D -=| From clalance at redhat.com Fri May 23 14:54:29 2008 From: clalance at redhat.com (Chris Lalancette) Date: Fri, 23 May 2008 16:54:29 +0200 Subject: [Ovirt-devel] [PATCH] make taskomatic.rb robust to database outages In-Reply-To: <769584de0805212100o3825fb8dme74e62e028e54216@mail.gmail.com> References: <769584de0805212100o3825fb8dme74e62e028e54216@mail.gmail.com> Message-ID: <4836DAA5.8010407@redhat.com> steve linabery wrote: > Hi ovirt, > > Resurrecting this patch that I wrote before I started having trouble > with my appliance. I decided (in the absence of comments) that it was > better for script to become a daemon and connect at earliest > opportunity if DB connection failed at initial runtime (logging this > fact, of course). OK, looks pretty good. It doesn't cover all the cases; for instance, if you stop the database after we've started executing the task, but before we hit "task.save", we won't re-process the task if/when the database comes back up. But that is OK for now. This is better than it was, and we can improve it over time. ACK Chris Lalancette From pmyers at redhat.com Fri May 23 18:15:43 2008 From: pmyers at redhat.com (Perry Myers) Date: Fri, 23 May 2008 14:15:43 -0400 Subject: [Ovirt-devel] [PATCH] Fix so libvirt does not start default network interface on developer/bundled Message-ID: <1211566543-10584-1-git-send-email-pmyers@redhat.com> Libvirt by default tries to create a private network for running guests. Because on the bundled/developer install we use dnsmasq ourselves, this conflicts with the default libvirt network. Solution is that the appliance must always be configured (via kickstart) to not start libvirtd. Then when the ovirt install script runs it removes default.xml and starts libvirt up. Signed-off-by: Perry Myers --- wui/scripts/ovirt-wui-install | 23 ++++++++++++++++------- 1 files changed, 16 insertions(+), 7 deletions(-) diff --git a/wui/scripts/ovirt-wui-install b/wui/scripts/ovirt-wui-install index 41b4f3d..423bb87 100755 --- a/wui/scripts/ovirt-wui-install +++ b/wui/scripts/ovirt-wui-install @@ -17,6 +17,13 @@ OVIRT_SVCS="ovirt-host-browser ovirt-host-status \ ovirt-taskomatic ovirt-host-keyadd ovirt-mongrel-rails" ENABLE_SVCS="ntpd httpd postgresql libvirtd" +# This checks to see if we're running on a bundled/developer install. +# If we are, set PROD_INST to false +PROD_INST=true +if [ "$(hostname)" == "management.priv.ovirt.org" ]; then + PROD_INST=false +fi + usage() { echo "usage: $0 [-p password]" echo " -p : password to use for database connections, if omitted" @@ -27,13 +34,7 @@ usage() { find_srv() { local dnsreply - # This checks to see if we're running on a bundled/developer install. - # If so, the server queried is localhost instead of using resolv.conf. - if [ "$(hostname)" == "management.priv.ovirt.org" ]; then - local server_flag=@localhost - fi - - dnsreply=$(dig $server_flag +short -t srv _$1._$2.$(dnsdomainname)) + dnsreply=$(dig +short -t srv _$1._$2.$(dnsdomainname)) if [ $? -eq 0 ]; then set _ $dnsreply; shift SRV_HOST=$4; SRV_PORT=$3 @@ -118,6 +119,14 @@ if [ `egrep -c '^mech_list: gssapi' $SASL_FILE` -eq 0 ]; then echo "mech_list: gssapi" >> $SASL_FILE fi +# if we are developer/bundled install, remove default network +# so dnsmasq from libvirt doesn't interfere with the dev/bundled +# dnsmasq +if [[ "$PROD_INST" == "false" ]]; then + rm -fv /etc/libvirt/qemu/networks/autostart/default.xml + rm -fv /etc/libvirt/qemu/networks/default.xml +fi + service postgresql stop > /dev/null 2>&1 service postgresql initdb > /dev/null 2>&1 echo "local all all trust" > /var/lib/pgsql/data/pg_hba.conf -- 1.5.4.5 From berrange at redhat.com Fri May 23 18:19:54 2008 From: berrange at redhat.com (Daniel P. Berrange) Date: Fri, 23 May 2008 19:19:54 +0100 Subject: [Ovirt-devel] [PATCH] Fix so libvirt does not start default network interface on developer/bundled In-Reply-To: <1211566543-10584-1-git-send-email-pmyers@redhat.com> References: <1211566543-10584-1-git-send-email-pmyers@redhat.com> Message-ID: <20080523181954.GB12467@redhat.com> On Fri, May 23, 2008 at 02:15:43PM -0400, Perry Myers wrote: > Libvirt by default tries to create a private network for running guests. > Because on the bundled/developer install we use dnsmasq ourselves, this > conflicts with the default libvirt network. Solution is that the appliance > must always be configured (via kickstart) to not start libvirtd. Then > when the ovirt install script runs it removes default.xml and starts > libvirt up. > +# if we are developer/bundled install, remove default network > +# so dnsmasq from libvirt doesn't interfere with the dev/bundled > +# dnsmasq > +if [[ "$PROD_INST" == "false" ]]; then > + rm -fv /etc/libvirt/qemu/networks/autostart/default.xml > + rm -fv /etc/libvirt/qemu/networks/default.xml > +fi No, no, no and no. To disable it use virsh virsh destroy default virsh autostart --disable default Dan. -- |: Red Hat, Engineering, Boston -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :| From sseago at redhat.com Fri May 23 18:58:52 2008 From: sseago at redhat.com (Scott Seago) Date: Fri, 23 May 2008 14:58:52 -0400 Subject: [Ovirt-devel] [PATCH] updated dialog forms to use text messages instead of images with embeded text. Message-ID: <483713EC.3020603@redhat.com> -------------- next part -------------- A non-text attachment was scrubbed... Name: dialog-buttons.patch Type: text/x-patch Size: 56943 bytes Desc: not available URL: From jguiditt at redhat.com Fri May 23 19:28:40 2008 From: jguiditt at redhat.com (Jason Guiditta) Date: Fri, 23 May 2008 15:28:40 -0400 Subject: [Ovirt-devel] [PATCH] graphs for detail pane of hosts Message-ID: <1211570920.4053.4.camel@localhost.localdomain> Besides adding the new graphs, I also added a param that can be passed into the js in _graph.rhtml to allow you to specify a css class for the svg container div. This means instead of having to have id-based classes to set height and width (so the svg shows up) we can reuse classes whenever it makes sense (for example, all detail pane graphs should be the same size, etc). Also, for some reason, I did not hit the js error thrown in the background by some of the other graphs. I chalk this up to something being different in the returned json (I am using a different controller) but haven't traked it down quite yet. I'll keep looking, but wanted to get the main patch out in the meantime. -j -------------- next part -------------- A non-text attachment was scrubbed... Name: s2_host_detail_graph.patch Type: text/x-patch Size: 6587 bytes Desc: not available URL: From jguiditt at redhat.com Fri May 23 20:03:50 2008 From: jguiditt at redhat.com (Jason Guiditta) Date: Fri, 23 May 2008 16:03:50 -0400 Subject: [Ovirt-devel] [PATCH] graphs for detail pane of hosts take 2 Message-ID: <1211573030.4053.8.camel@localhost.localdomain> Sorry, forgot to update before I made that last patch, there would be a cnlfict, this one should better. Reposting notes if you want to ignore the last one: Besides adding the new graphs, I also added a param that can be passed into the js in _graph.rhtml to allow you to specify a css class for the svg container div. This means instead of having to have id-based classes to set height and width (so the svg shows up) we can reuse classes whenever it makes sense (for example, all detail pane graphs should be the same size, etc). Also, for some reason, I did not hit the js error thrown in the background by some of the other graphs. I chalk this up to something being different in the returned json (I am using a different controller) but haven't traked it down quite yet. I'll keep looking, but wanted to get the main patch out in the meantime. -j -------------- next part -------------- A non-text attachment was scrubbed... Name: s2-host-graph-redux.patch Type: text/x-patch Size: 6443 bytes Desc: not available URL: From hbrock at redhat.com Fri May 23 20:34:40 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Fri, 23 May 2008 16:34:40 -0400 Subject: [Ovirt-devel] [PATCH] make taskomatic.rb robust to database outages In-Reply-To: <4836DAA5.8010407@redhat.com> References: <769584de0805212100o3825fb8dme74e62e028e54216@mail.gmail.com> <4836DAA5.8010407@redhat.com> Message-ID: <20080523203439.GH14196@redhat.com> On Fri, May 23, 2008 at 04:54:29PM +0200, Chris Lalancette wrote: > steve linabery wrote: > > Hi ovirt, > > > > Resurrecting this patch that I wrote before I started having trouble > > with my appliance. I decided (in the absence of comments) that it was > > better for script to become a daemon and connect at earliest > > opportunity if DB connection failed at initial runtime (logging this > > fact, of course). > > OK, looks pretty good. It doesn't cover all the cases; for instance, if you > stop the database after we've started executing the task, but before we hit > "task.save", we won't re-process the task if/when the database comes back up. > But that is OK for now. This is better than it was, and we can improve it over > time. > > ACK > > Chris Lalancette > Committed based on the fact that taskomatic hasn't seen any love in quite a while. --Hugh From mmorsi at redhat.com Fri May 23 21:18:41 2008 From: mmorsi at redhat.com (Mohammed Morsi) Date: Fri, 23 May 2008 17:18:41 -0400 Subject: [Ovirt-devel] [PATCH] graphs for detail pane of hosts take 2 In-Reply-To: <1211573030.4053.8.camel@localhost.localdomain> References: <1211573030.4053.8.camel@localhost.localdomain> Message-ID: <483734B1.30000@redhat.com> Overall looks good (didn't apply it yet and try it out though). Just had one question. Why in _graph.rhtml do you have this: - svg.graph.noDraw(); + //svg.graph.noDraw().title('',10); eg. you commented out the call to noDraw(). I think this might be a mistake as you didn't comment out the call to reDraw() below. In any case, these both shouldn't be commented out, as they prevent a graph from appearing until is done being generated (I still think we should expirement with removing the noDraw and redraw methods from _graph and putting them at the top and bottom of the site layout, to see if we can get it so all the graphs on a page appear at once in a timely manner). Perhaps thats the reason w/ you weren't getting the js error (in any case we should look into that as well). Other than that, the patch looks good. -Mo Jason Guiditta wrote: > Sorry, forgot to update before I made that last patch, there would be a > cnlfict, this one should better. Reposting notes if you want to ignore > the last one: > > Besides adding the new graphs, I also added a param that can be passed > into the js in _graph.rhtml to allow you to specify a css class for the > svg container div. This means instead of having to have id-based > classes to set height and width (so the svg shows up) we can reuse > classes whenever it makes sense (for example, all detail pane graphs > should be the same size, etc). Also, for some reason, I did not hit the > js error thrown in the background by some of the other graphs. I chalk > this up to something being different in the returned json (I am using a > different controller) but haven't traked it down quite yet. I'll keep > looking, but wanted to get the main patch out in the meantime. > > -j > > ------------------------------------------------------------------------ > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel -------------- next part -------------- An HTML attachment was scrubbed... URL: From hbrock at redhat.com Fri May 23 21:31:04 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Fri, 23 May 2008 17:31:04 -0400 Subject: [Ovirt-devel] [PATCH] updated dialog forms to use text messages instead of images with embeded text. In-Reply-To: <483713EC.3020603@redhat.com> References: <483713EC.3020603@redhat.com> Message-ID: <20080523213103.GI14196@redhat.com> On Fri, May 23, 2008 at 02:58:52PM -0400, Scott Seago wrote: > > >From 059a9b9790bc966d86ffb5453e8072e59d2f0b1a Mon Sep 17 00:00:00 2001 > From: Scott Seago > Date: Fri, 23 May 2008 14:56:39 -0400 > Subject: [PATCH] updated dialog forms to use text messages instead of images with embeded text. Cleaned up some links we don't need anymore. > > > Signed-off-by: Scott Seago > --- > wui/src/app/controllers/hardware_controller.rb | 2 +- > wui/src/app/controllers/resources_controller.rb | 2 +- > wui/src/app/helpers/application_helper.rb | 18 +++++++ > wui/src/app/views/hardware/move.rhtml | 12 ++++- > wui/src/app/views/hardware/new.html.erb | 7 +-- > wui/src/app/views/hardware/show.html.erb | 7 --- > wui/src/app/views/host/_grid.rhtml | 2 +- > wui/src/app/views/host/addhost.html.erb | 8 +--- > wui/src/app/views/layouts/_navigation_tabs.rhtml | 1 - > wui/src/app/views/permission/new.rhtml | 10 +--- > wui/src/app/views/resources/new.rhtml | 10 +--- > wui/src/app/views/resources/show.rhtml | 6 -- > wui/src/app/views/storage/addstorage.html.erb | 7 +-- > wui/src/app/views/storage/new.rhtml | 10 +--- > wui/src/app/views/vm/new.rhtml | 11 +--- > wui/src/public/images/btn_addhosts.png | Bin 3335 -> 0 bytes > wui/src/public/images/btn_addstorage.png | Bin 3031 -> 0 bytes > wui/src/public/images/btn_addvm.png | Bin 2991 -> 0 bytes > wui/src/public/images/btn_cancel.png | Bin 1522 -> 0 bytes > wui/src/public/images/btn_move.png | Bin 1531 -> 0 bytes > wui/src/public/images/btn_moveto_newhost.png | Bin 2878 -> 0 bytes > wui/src/public/images/btn_moveto_newpool.png | Bin 2731 -> 0 bytes > wui/src/public/images/btn_next.png | Bin 1403 -> 0 bytes > wui/src/public/images/btn_previous.png | Bin 1686 -> 0 bytes > wui/src/public/images/button_left.png | Bin 0 -> 476 bytes > wui/src/public/images/button_left_grey.png | Bin 0 -> 446 bytes > wui/src/public/images/button_left_grey_f2.png | Bin 0 -> 446 bytes > wui/src/public/images/button_middle.png | Bin 0 -> 261 bytes > wui/src/public/images/button_middle_grey.png | Bin 0 -> 255 bytes > wui/src/public/images/button_middle_grey_f2.png | Bin 0 -> 255 bytes > wui/src/public/images/button_right.png | Bin 0 -> 473 bytes > wui/src/public/images/button_right_grey.png | Bin 0 -> 436 bytes > wui/src/public/images/button_right_grey_f2.png | Bin 0 -> 436 bytes > wui/src/public/stylesheets/layout.css | 54 ++++++++++++++++++++++ > 34 files changed, 100 insertions(+), 67 deletions(-) > delete mode 100644 wui/src/public/images/btn_addhosts.png > delete mode 100644 wui/src/public/images/btn_addstorage.png > delete mode 100644 wui/src/public/images/btn_addvm.png > delete mode 100644 wui/src/public/images/btn_cancel.png > delete mode 100644 wui/src/public/images/btn_move.png > delete mode 100644 wui/src/public/images/btn_moveto_newhost.png > delete mode 100644 wui/src/public/images/btn_moveto_newpool.png > delete mode 100644 wui/src/public/images/btn_next.png > delete mode 100644 wui/src/public/images/btn_previous.png > create mode 100644 wui/src/public/images/button_left.png > create mode 100644 wui/src/public/images/button_left_grey.png > create mode 100644 wui/src/public/images/button_left_grey_f2.png > create mode 100644 wui/src/public/images/button_middle.png > create mode 100644 wui/src/public/images/button_middle_grey.png > create mode 100644 wui/src/public/images/button_middle_grey_f2.png > create mode 100644 wui/src/public/images/button_right.png > create mode 100644 wui/src/public/images/button_right_grey.png > create mode 100644 wui/src/public/images/button_right_grey_f2.png > > diff --git a/wui/src/app/controllers/hardware_controller.rb b/wui/src/app/controllers/hardware_controller.rb > index ee143bb..93f9722 100644 > --- a/wui/src/app/controllers/hardware_controller.rb > +++ b/wui/src/app/controllers/hardware_controller.rb > @@ -284,7 +284,7 @@ class HardwareController < ApplicationController > begin > @pool.create_with_resources(@parent, resource_type, resource_ids) > render :json => { :object => "pool", :success => true, > - :alert => "Storage Pool was successfully created." } > + :alert => "Hardware Pool was successfully created." } > rescue > render :json => { :object => "pool", :success => false, > :errors => @pool.errors.localize_error_messages.to_a } > diff --git a/wui/src/app/controllers/resources_controller.rb b/wui/src/app/controllers/resources_controller.rb > index 0690b89..aef2fd5 100644 > --- a/wui/src/app/controllers/resources_controller.rb > +++ b/wui/src/app/controllers/resources_controller.rb > @@ -101,7 +101,7 @@ class ResourcesController < ApplicationController > begin > @vm_resource_pool.create_with_parent(@parent) > render :json => { :object => "vm_resource_pool", :success => true, > - :alert => "Storage Pool was successfully created." } > + :alert => "Virtual Machine Pool was successfully created." } > rescue > render :json => { :object => "vm_resource_pool", :success => false, > :errors => @vm_resource_pool.errors.localize_error_messages.to_a} > diff --git a/wui/src/app/helpers/application_helper.rb b/wui/src/app/helpers/application_helper.rb > index 1bf917d..4dbf2b8 100644 > --- a/wui/src/app/helpers/application_helper.rb > +++ b/wui/src/app/helpers/application_helper.rb > @@ -77,6 +77,24 @@ module ApplicationHelper > } > end > > + def popup_footer(action, label) > + %{ > +
      > +
      > +
      > + > +
      > +
      > +
      > +
      > + > +
      > +
      > +
      > + } > + end > + > + > def timeout_flash(name) > %{ > > -
      ) repeat-x; height: 37px; text-align:right; padding: 9px 9px 0 0;"> > - > -
      > - > +<%= popup_footer("add_hosts()", "Add Hosts") %> > diff --git a/wui/src/app/views/layouts/_navigation_tabs.rhtml b/wui/src/app/views/layouts/_navigation_tabs.rhtml > index a3b94e4..e820f46 100644 > --- a/wui/src/app/views/layouts/_navigation_tabs.rhtml > +++ b/wui/src/app/views/layouts/_navigation_tabs.rhtml > @@ -6,7 +6,6 @@ > > > > - > <% elsif controller.controller_name == "resources" and @vm_resource_pool != nil %> > > > diff --git a/wui/src/app/views/permission/new.rhtml b/wui/src/app/views/permission/new.rhtml > index 2d95cde..45dc239 100644 > --- a/wui/src/app/views/permission/new.rhtml > +++ b/wui/src/app/views/permission/new.rhtml > @@ -3,15 +3,11 @@ >
      Add a new user to <%= @permission.pool.name %> pool.
      >
      > > -
      > + >
      > <%= render :partial => 'form' %> >
      > -
      ) repeat-x; height: 37px; text-align:right; padding: 9px 9px 0 0;"> > -
      " alt="Create User Permission" /> > - <%=image_tag "btn_cancel.png", :title=>"Cancel" %> > -
      > -
      > +<%= popup_footer("$('#permission_form').submit()", "Create User Permission") %> >
      > > -
      ) repeat-x; height: 37px; text-align:right; padding: 9px 9px 0 0;"> > - > -
      > +<%= popup_footer("add_storage()", "Add Selected Storage Pools") %> > > diff --git a/wui/src/app/views/storage/new.rhtml b/wui/src/app/views/storage/new.rhtml > index 8a94a33..6f88ce3 100644 > --- a/wui/src/app/views/storage/new.rhtml > +++ b/wui/src/app/views/storage/new.rhtml > @@ -16,16 +16,12 @@ >
      >
      >
      > -
      > + >
      >
      > >
      > -
      ) repeat-x; height: 37px; text-align:right; padding: 9px 9px 0 0;"> > -
      " alt="Add Storage Server" /> > - <%=image_tag "btn_cancel.png", :title=>"Cancel" %> > -
      > -
      > +<%= popup_footer("$('#storage_pool_form').submit()", "New Storage Pool") %> > > > > -
      > +
      > diff --git a/wui/src/public/stylesheets/components.css b/wui/src/public/stylesheets/components.css > index 0e9301b..dc16bab 100644 > --- a/wui/src/public/stylesheets/components.css > +++ b/wui/src/public/stylesheets/components.css > @@ -201,3 +201,18 @@ > float: left; > padding-top: 3px; > } > + > +.detail-pane-chart { > + height: 50px; > + width: 375px; > +} > + > +.detail-pane-chart-header { > + width:252.5px; > + background: #F0F0F0; > + position:relative; > + margin-left:37px; > + margin-bottom:-4px; > + padding: 5px; > + border: 1px solid #CCCCCC; > +} > diff --git a/wui/src/public/stylesheets/layout.css b/wui/src/public/stylesheets/layout.css > index 455b6ca..632f13c 100644 > --- a/wui/src/public/stylesheets/layout.css > +++ b/wui/src/public/stylesheets/layout.css > @@ -251,7 +251,8 @@ textarea:focus, input:focus { > width:48%; > float: right; > border-left: 1px solid #CCCCCC; > - background: #F0F0F0; > + /*background: #F0F0F0;*/ > + height: 148px; > } > > .selection_right_title { > -- > 1.5.4.1 Line graphs look like a good start... ACK and committed. --Hugh From slinabery at gmail.com Sun May 25 19:31:55 2008 From: slinabery at gmail.com (steve linabery) Date: Sun, 25 May 2008 14:31:55 -0500 Subject: [Ovirt-devel] we should rescue RecordNotFound exceptions from ActiveRecord find method Message-ID: <769584de0805251231u18db890fpfb6ffa8591662f2a@mail.gmail.com> Hi Ovirt. Look here: http://api.rubyonrails.org/classes/ActiveRecord/Base.html#M001376 We have several instances of ActiveRecordFoo.find(id) that doesn't rescue the possible RecordNotFound exception. Wanted to mention it via email so I don't forget. Thanks, Steve From slinabery at gmail.com Sun May 25 20:30:35 2008 From: slinabery at gmail.com (steve linabery) Date: Sun, 25 May 2008 15:30:35 -0500 Subject: [Ovirt-devel] [PATCH] transactions in models and controllers Message-ID: <769584de0805251330q55f5393avfd1903d0eaacd493@mail.gmail.com> Hi Ovirt, I believe this will make everything currently in app/models and app/controllers transactional where necessary. As an aside, please note that these (and other recent) transaction additions create the need for some exception handling that is not currently present. Good day, Steve -------------- next part -------------- A non-text attachment was scrubbed... Name: transactions.patch Type: text/x-patch Size: 4181 bytes Desc: not available URL: From Pierre.Inglebert at inria.fr Mon May 26 12:25:59 2008 From: Pierre.Inglebert at inria.fr (Pierre Inglebert) Date: Mon, 26 May 2008 14:25:59 +0200 Subject: [Ovirt-devel] Questions about Xen support Message-ID: <1211804759.15391.93.camel@rollot.futurs.inria.fr> Hi ovirt, I'm working on the Xen support for oVirt, so first i wanna know if anyone else is working on or is interrested to. Thanks to libvirt, it is quite easy to make ovirt only work with Xen or KVM but not with both because there are some hardcoded ?parts for KVM. This hardcoded parts are in task-omatic (especially in task_vm.rb), libvirt uri connections as "qemu+tcp://" don't work with Xen, so i'm trying to find a way to dynamicly modify this uri (e.g.change it to "xen +tcp://" for xen). To do this, we have to know the hypervisor type before the connection, we also have to know what type of VM we are creating in case of many hypervisor types available and for the migration, the hosts need to have the same hypervisor. For me, there are 2 solutions. The first solution is ?to allow an host to have more than one hypervisor, these solutions require some changes : - the VM will have an hypervisor type - On the host, a list of available hypervisors (possibly dynamic?) - For the user, we have to ask about hypervisor/arch on the VM creation form (from the list of available hypervisors (dynamic listing will be hard)) - for the VM creation/migration task, we have to check if the Host is compatible with the VM, - during the Host addition, we have to get all the hypervisor capabilities. The second solution is to keep the restriction of one hypervisor by Host. We can seperate 2 cases : - One Hypervisor by Host collection : - Check the availability of the hypervisor during the Host addition. - Move the Hypervisor Type to the Host collection (actually on Host) - One Hypervisor by Host (Multiple for Collection) : - Ask user about the hypervisor to use during the Host addition (possibility to choose it from a list) - For the VM creation, ask the user about the hypervisor type from the hypervisor list of the Host Collection. - For migration, check available hosts in the Collection. So ?I wanna know what do you think about it. -- Pierre Inglebert From apevec at redhat.com Mon May 26 13:16:41 2008 From: apevec at redhat.com (Alan Pevec) Date: Mon, 26 May 2008 15:16:41 +0200 Subject: [Ovirt-devel] [PATCH] Fix so libvirt does not start default network interface on developer/bundled In-Reply-To: <20080523181954.GB12467@redhat.com> References: <1211566543-10584-1-git-send-email-pmyers@redhat.com> <20080523181954.GB12467@redhat.com> Message-ID: <483AB839.3020102@redhat.com> Daniel P. Berrange wrote: > On Fri, May 23, 2008 at 02:15:43PM -0400, Perry Myers wrote: >> Libvirt by default tries to create a private network for running guests. >> Because on the bundled/developer install we use dnsmasq ourselves, this >> conflicts with the default libvirt network. Solution is that the appliance >> must always be configured (via kickstart) to not start libvirtd. Then >> when the ovirt install script runs it removes default.xml and starts >> libvirt up. > > >> +# if we are developer/bundled install, remove default network >> +# so dnsmasq from libvirt doesn't interfere with the dev/bundled >> +# dnsmasq >> +if [[ "$PROD_INST" == "false" ]]; then >> + rm -fv /etc/libvirt/qemu/networks/autostart/default.xml >> + rm -fv /etc/libvirt/qemu/networks/default.xml >> +fi > > No, no, no and no. To disable it use virsh > > virsh destroy default > virsh autostart --disable default I'll commit it with: + virsh net-destroy default + virsh net-undefine default net-undefine removes autostart link too From apevec at redhat.com Mon May 26 14:28:23 2008 From: apevec at redhat.com (Alan Pevec) Date: Mon, 26 May 2008 16:28:23 +0200 Subject: [Ovirt-devel] [PATCH] Fix so libvirt does not start default network interface on developer/bundled In-Reply-To: <483AB839.3020102@redhat.com> References: <1211566543-10584-1-git-send-email-pmyers@redhat.com> <20080523181954.GB12467@redhat.com> <483AB839.3020102@redhat.com> Message-ID: <483AC907.5050508@redhat.com> >> No, no, no and no. To disable it use virsh >> >> virsh destroy default >> virsh autostart --disable default > > I'll commit it with: > > + virsh net-destroy default > + virsh net-undefine default > > net-undefine removes autostart link too Correction: virsh needs running libvirtd and ovirt-wui-first-run start priority is 96 while libvirtd is 97. I'll change ovirt-wui-first-run to 98. From pmyers at redhat.com Mon May 26 15:42:41 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Mon, 26 May 2008 11:42:41 -0400 Subject: [Ovirt-devel] [PATCH] Fix so libvirt does not start default network interface on developer/bundled In-Reply-To: <483AC907.5050508@redhat.com> References: <1211566543-10584-1-git-send-email-pmyers@redhat.com> <20080523181954.GB12467@redhat.com> <483AB839.3020102@redhat.com> <483AC907.5050508@redhat.com> Message-ID: <483ADA71.6050700@redhat.com> Alan Pevec wrote: >>> No, no, no and no. To disable it use virsh >>> >>> virsh destroy default >>> virsh autostart --disable default >> >> I'll commit it with: >> >> + virsh net-destroy default >> + virsh net-undefine default >> >> net-undefine removes autostart link too > > Correction: virsh needs running libvirtd and ovirt-wui-first-run start > priority is 96 while libvirtd is 97. > I'll change ovirt-wui-first-run to 98. This may not be an issue, since on first boot none of the init scripts for the oVirt daemons are active anyhow... The oVirt daemons are all runlevel 97. If you set ovirt-wui-first-run to 98 it'll be after the ovirt daemons, which conceptually is confusing. The other thing that needs to change is libvirtd -must- be set to start in the kickstart. Right now it's off by default. So make sure you update the ks file. Perry From sburgess at redhat.com Mon May 26 23:42:33 2008 From: sburgess at redhat.com (Susan Burgess) Date: Tue, 27 May 2008 09:42:33 +1000 Subject: [Ovirt-devel] oVirt Admin UI oddities..can you explain? Message-ID: <483B4AE9.6020402@redhat.com> Hi. If anyone can explain the following: 1. Hosts can never be deleted. The "Delete" button results in it being removed from the hardware pool, but it will still appear in the Add Hosts dialog. 2. Storage servers can be both removed and deleted. The "Delete" button results in it being exterminated - it no longer appears in any dialog boxes This use of the term "Delete" is inconsistent with its usage in point 1 above. 3. If a storage server can be used only by a single hardware pool as the interface currently allows, why is this? 4. Hosts and Storage get "moved" directly from the dialog boxes without any message. Its all a bit magical - nice but could get confusing 5. In the Add Host dialog, if there are more than 17 hosts, and the number of lines is set to > 15, the buttons disappear. 6. Why are there two identical unlabelled green buttons in the top right corner, that do different things? 7. What will "Search" return when its implemented? And in which View will it be? Thanks Susan -- Susan Burgess Content Author Red Hat APAC Level 1, 193 North Quay Brisbane, QLD 4000 Australia Phone +61 7 3514 8179 Fax +61 7 3514 8199 Mail sburgess at redhat.com From apevec at redhat.com Tue May 27 01:00:58 2008 From: apevec at redhat.com (Alan Pevec) Date: Tue, 27 May 2008 03:00:58 +0200 Subject: [Ovirt-devel] [PATCH] Fix so libvirt does not start default network interface on developer/bundled In-Reply-To: <483ADA71.6050700@redhat.com> References: <1211566543-10584-1-git-send-email-pmyers@redhat.com> <20080523181954.GB12467@redhat.com> <483AB839.3020102@redhat.com> <483AC907.5050508@redhat.com> <483ADA71.6050700@redhat.com> Message-ID: <483B5D4A.70707@redhat.com> Here is modified Perry's patch: - use virsh to remove 'default' network - remove ovirt-fix-ipa, IPA is now at /ipa - use new ovirt-management repo URL - minor edits: Ovirt -> oVirt, use ${OVIRT_DIR} diff --git a/wui-appliance/common-install.ks b/wui-appliance/common-install.ks index 5a590b5..e2fa902 100644 --- a/wui-appliance/common-install.ks +++ b/wui-appliance/common-install.ks @@ -5,7 +5,7 @@ rootpw --iscrypted Xa8QeYfWrtscM firewall --disabled authconfig --enableshadow --enablemd5 selinux --disabled -services --disabled=iptables,yum-updatesd,libvirtd,bluetooth,cups,gpm,pcscd,NetworkManager,NetworkManagerDispatcher --enabled=ntpd,httpd,postgresql,ovirt-wui,tgtd,nfs,collectd,network +services --disabled=libvirtd,postgresql,iptables,yum-updatesd,bluetooth,cups,gpm,pcscd,NetworkManager,NetworkManagerDispatcher --enabled=network,tgtd,nfs timezone --utc UTC text diff --git a/wui-appliance/common-post.ks b/wui-appliance/common-post.ks index 67a885b..a4e0bd2 100644 --- a/wui-appliance/common-post.ks +++ b/wui-appliance/common-post.ks @@ -25,7 +25,7 @@ cp /etc/issue /etc/issue.net cat > /etc/init.d/ovirt-wui-first-run << \EOF #!/bin/bash # -# ovirt-wui-first-run First run configuration for Ovirt WUI appliance +# ovirt-wui-first-run First run configuration for oVirt WUI appliance # # chkconfig: 3 96 01 # description: ovirt wui appliance first run configuration @@ -65,7 +65,7 @@ chkconfig ovirt-wui-first-run on cat > /etc/yum.repos.d/ovirt-management.repo << \EOF [ovirt-management] name=ovirt-management -baseurl=http://ovirt.et.redhat.com/repos/ovirt-management-repo/$basearch/ +baseurl=http://ovirt.org/repos/ovirt/9/$basearch/ enabled=1 gpgcheck=0 EOF diff --git a/wui-appliance/wui-devel-x86_64.ks b/wui-appliance/wui-devel-x86_64.ks index 1294c89..1ab990f 100644 --- a/wui-appliance/wui-devel-x86_64.ks +++ b/wui-appliance/wui-devel-x86_64.ks @@ -110,7 +110,7 @@ sed -e "s, at cron_file@,$cron_file," \ > $first_run_file << \EOF #!/bin/bash # -# ovirt-wui-dev-first-run First run configuration for Ovirt WUI Dev appliance +# ovirt-wui-dev-first-run First run configuration for oVirt WUI Dev appliance # # chkconfig: 3 95 01 # description: ovirt dev wui appliance first run configuration @@ -160,7 +160,7 @@ chkconfig ovirt-wui-dev-first-run on cat > /etc/init.d/ovirt-wui-dev << \EOF #!/bin/bash # -# ovirt-wui-dev Ovirt WUI Dev appliance service +# ovirt-wui-dev oVirt WUI Dev appliance service # # chkconfig: 3 60 40 # description: ovirt dev wui appliance service diff --git a/wui/scripts/ovirt-fix-ipa b/wui/scripts/ovirt-fix-ipa deleted file mode 100755 index 9e4aa14..0000000 --- a/wui/scripts/ovirt-fix-ipa +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/python - -import os, string, re - -ipaConfName = '/etc/httpd/conf.d/ipa.conf' -ipaRewriteConfName = '/etc/httpd/conf.d/ipa-rewrite.conf' - -# make sure we skip this on subsequent runs of this script -if string.find(file(ipaConfName, 'rb').read(), '') < 0: - ipaConf = open(ipaConfName, 'r') - ipaText = ipaConf.readlines() - ipaConf.close() - - ipaConf2 = open(ipaConfName, 'w') - print >>ipaConf2, "Listen 8089" - print >>ipaConf2, "NameVirtualHost *:8089" - print >>ipaConf2, "" - for line in ipaText: - ipaConf2.write(line) - print >>ipaConf2, "" - ipaConf2.close() - -if os.path.isfile(ipaRewriteConfName): - os.remove(ipaRewriteConfName) - ipaRewriteConf = open(ipaRewriteConfName, 'w') - print >>ipaRewriteConf, "" - ipaRewriteConf.close() - diff --git a/wui/scripts/ovirt-wui-install b/wui/scripts/ovirt-wui-install index 41b4f3d..d1b8452 100755 --- a/wui/scripts/ovirt-wui-install +++ b/wui/scripts/ovirt-wui-install @@ -13,9 +13,16 @@ STEP_FILE=/etc/ntp/step-tickers SASL_FILE=/etc/sasl2/libvirt.conf LDAP_CFG=${OVIRT_DIR}/config/ldap.yml -OVIRT_SVCS="ovirt-host-browser ovirt-host-status \ - ovirt-taskomatic ovirt-host-keyadd ovirt-mongrel-rails" -ENABLE_SVCS="ntpd httpd postgresql libvirtd" +OVIRT_SVCS="ovirt-host-browser ovirt-host-keyadd ovirt-host-status \ + ovirt-mongrel-rails ovirt-taskomatic" +ENABLE_SVCS="ntpd httpd postgresql libvirtd collectd" + +# This checks to see if we're running on a bundled/developer install. +# If we are, set PROD_INST to false +PROD_INST=true +if [ "$(hostname)" == "management.priv.ovirt.org" ]; then + PROD_INST=false +fi usage() { echo "usage: $0 [-p password]" @@ -27,13 +34,7 @@ usage() { find_srv() { local dnsreply - # This checks to see if we're running on a bundled/developer install. - # If so, the server queried is localhost instead of using resolv.conf. - if [ "$(hostname)" == "management.priv.ovirt.org" ]; then - local server_flag=@localhost - fi - - dnsreply=$(dig $server_flag +short -t srv _$1._$2.$(dnsdomainname)) + dnsreply=$(dig +short -t srv _$1._$2.$(dnsdomainname)) if [ $? -eq 0 ]; then set _ $dnsreply; shift SRV_HOST=$4; SRV_PORT=$3 @@ -118,6 +119,15 @@ if [ `egrep -c '^mech_list: gssapi' $SASL_FILE` -eq 0 ]; then echo "mech_list: gssapi" >> $SASL_FILE fi +# if we are developer/bundled install, remove default network +# so dnsmasq from libvirt doesn't interfere with the dev/bundled +# dnsmasq +if [[ "$PROD_INST" == "false" ]]; then + service libvirtd status > /dev/null 2&>1 || service libvirtd start > /dev/null 2>&1 + virsh net-destroy default + virsh net-undefine default +fi + service postgresql stop > /dev/null 2>&1 service postgresql initdb > /dev/null 2>&1 echo "local all all trust" > /var/lib/pgsql/data/pg_hba.conf @@ -162,20 +172,12 @@ cd - ${OVIRT_DIR}/script/grant_admin_privileges admin [ $? != 0 ] && echo "Failed to grant admin privileges" && exit 1 -if [ -f /usr/share/ovirt-wui/ovirtadmin.tab ]; then +if [ -f ${OVIRT_DIR}/ovirtadmin.tab ]; then ${OVIRT_DIR}/script/grant_admin_privileges ovirtadmin [ $? != 0 ] && echo "Failed to grant ovirtadmin privileges" && exit 1 fi -/usr/bin/ovirt-add-host $(hostname) ${OVIRT_DIR}/ovirt.keytab - -# This is temporary until we get a version of FreeIPA that runs under /ipa -# instead of as root -if [ -f /etc/httpd/conf.d/ipa.conf ]; then - /usr/bin/ovirt-fix-ipa - service httpd restart - service ipa_webgui restart -fi +ovirt-add-host $(hostname) ${OVIRT_DIR}/ovirt.keytab for svc in $OVIRT_SVCS $ENABLE_SVCS; do service $svc start From pmyers at redhat.com Tue May 27 01:43:35 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Mon, 26 May 2008 21:43:35 -0400 Subject: [Ovirt-devel] [PATCH] Fix so libvirt does not start default network interface on developer/bundled In-Reply-To: <483B5D4A.70707@redhat.com> References: <1211566543-10584-1-git-send-email-pmyers@redhat.com> <20080523181954.GB12467@redhat.com> <483AB839.3020102@redhat.com> <483AC907.5050508@redhat.com> <483ADA71.6050700@redhat.com> <483B5D4A.70707@redhat.com> Message-ID: <483B6747.3080407@redhat.com> Alan Pevec wrote: > Here is modified Perry's patch: > - use virsh to remove 'default' network > - remove ovirt-fix-ipa, IPA is now at /ipa > - use new ovirt-management repo URL > - minor edits: Ovirt -> oVirt, use ${OVIRT_DIR} Looks good. A few minor comments below. The only thing of concern that I have is my first comment about the removal of services from --enabled. Perry > diff --git a/wui-appliance/common-install.ks > b/wui-appliance/common-install.ks > index 5a590b5..e2fa902 100644 > --- a/wui-appliance/common-install.ks > +++ b/wui-appliance/common-install.ks > @@ -5,7 +5,7 @@ rootpw --iscrypted Xa8QeYfWrtscM > firewall --disabled > authconfig --enableshadow --enablemd5 > selinux --disabled > -services > --disabled=iptables,yum-updatesd,libvirtd,bluetooth,cups,gpm,pcscd,NetworkManager,NetworkManagerDispatcher > --enabled=ntpd,httpd,postgresql,ovirt-wui,tgtd,nfs,collectd,network > +services > --disabled=libvirtd,postgresql,iptables,yum-updatesd,bluetooth,cups,gpm,pcscd,NetworkManager,NetworkManagerDispatcher > --enabled=network,tgtd,nfs Hmm. Why is --enabled reduced to just network, tgtd and nfs? What about ntpd, httpd, etc?? > timezone --utc UTC > text > > diff --git a/wui-appliance/common-post.ks b/wui-appliance/common-post.ks > index 67a885b..a4e0bd2 100644 > --- a/wui-appliance/common-post.ks > +++ b/wui-appliance/common-post.ks > @@ -25,7 +25,7 @@ cp /etc/issue /etc/issue.net > cat > /etc/init.d/ovirt-wui-first-run << \EOF > #!/bin/bash > # > -# ovirt-wui-first-run First run configuration for Ovirt WUI appliance > +# ovirt-wui-first-run First run configuration for oVirt WUI appliance > # > # chkconfig: 3 96 01 > # description: ovirt wui appliance first run configuration > @@ -65,7 +65,7 @@ chkconfig ovirt-wui-first-run on > cat > /etc/yum.repos.d/ovirt-management.repo << \EOF > [ovirt-management] > name=ovirt-management > -baseurl=http://ovirt.et.redhat.com/repos/ovirt-management-repo/$basearch/ > +baseurl=http://ovirt.org/repos/ovirt/9/$basearch/ > enabled=1 > gpgcheck=0 > EOF > diff --git a/wui-appliance/wui-devel-x86_64.ks > b/wui-appliance/wui-devel-x86_64.ks > index 1294c89..1ab990f 100644 > --- a/wui-appliance/wui-devel-x86_64.ks > +++ b/wui-appliance/wui-devel-x86_64.ks > @@ -110,7 +110,7 @@ sed -e "s, at cron_file@,$cron_file," \ > > $first_run_file << \EOF > #!/bin/bash > # > -# ovirt-wui-dev-first-run First run configuration for Ovirt WUI Dev > appliance > +# ovirt-wui-dev-first-run First run configuration for oVirt WUI Dev > appliance > # > # chkconfig: 3 95 01 > # description: ovirt dev wui appliance first run configuration > @@ -160,7 +160,7 @@ chkconfig ovirt-wui-dev-first-run on > cat > /etc/init.d/ovirt-wui-dev << \EOF > #!/bin/bash > # > -# ovirt-wui-dev Ovirt WUI Dev appliance service > +# ovirt-wui-dev oVirt WUI Dev appliance service > # > # chkconfig: 3 60 40 # description: ovirt dev wui appliance service > diff --git a/wui/scripts/ovirt-fix-ipa b/wui/scripts/ovirt-fix-ipa > deleted file mode 100755 > index 9e4aa14..0000000 > --- a/wui/scripts/ovirt-fix-ipa > +++ /dev/null > @@ -1,28 +0,0 @@ > -#!/usr/bin/python > - > -import os, string, re > - > -ipaConfName = '/etc/httpd/conf.d/ipa.conf' > -ipaRewriteConfName = '/etc/httpd/conf.d/ipa-rewrite.conf' > - > -# make sure we skip this on subsequent runs of this script > -if string.find(file(ipaConfName, 'rb').read(), '') > < 0: > - ipaConf = open(ipaConfName, 'r') > - ipaText = ipaConf.readlines() > - ipaConf.close() > - > - ipaConf2 = open(ipaConfName, 'w') > - print >>ipaConf2, "Listen 8089" > - print >>ipaConf2, "NameVirtualHost *:8089" > - print >>ipaConf2, "" > - for line in ipaText: > - ipaConf2.write(line) > - print >>ipaConf2, "" > - ipaConf2.close() > - > -if os.path.isfile(ipaRewriteConfName): > - os.remove(ipaRewriteConfName) > - ipaRewriteConf = open(ipaRewriteConfName, 'w') > - print >>ipaRewriteConf, "" > - ipaRewriteConf.close() > - > diff --git a/wui/scripts/ovirt-wui-install b/wui/scripts/ovirt-wui-install > index 41b4f3d..d1b8452 100755 > --- a/wui/scripts/ovirt-wui-install > +++ b/wui/scripts/ovirt-wui-install > @@ -13,9 +13,16 @@ STEP_FILE=/etc/ntp/step-tickers > SASL_FILE=/etc/sasl2/libvirt.conf > LDAP_CFG=${OVIRT_DIR}/config/ldap.yml > > -OVIRT_SVCS="ovirt-host-browser ovirt-host-status \ > - ovirt-taskomatic ovirt-host-keyadd ovirt-mongrel-rails" > -ENABLE_SVCS="ntpd httpd postgresql libvirtd" > +OVIRT_SVCS="ovirt-host-browser ovirt-host-keyadd ovirt-host-status \ > + ovirt-mongrel-rails ovirt-taskomatic" Did you reorder OVIRT_SVCS just to alphabetize it? :) > +ENABLE_SVCS="ntpd httpd postgresql libvirtd collectd" > + > +# This checks to see if we're running on a bundled/developer install. > +# If we are, set PROD_INST to false > +PROD_INST=true > +if [ "$(hostname)" == "management.priv.ovirt.org" ]; then > + PROD_INST=false > +fi > > usage() { > echo "usage: $0 [-p password]" > @@ -27,13 +34,7 @@ usage() { > find_srv() { > local dnsreply > - # This checks to see if we're running on a bundled/developer > install. - # If so, the server queried is localhost instead of using > resolv.conf. - if [ "$(hostname)" == "management.priv.ovirt.org" ]; This looks mangled. Probably just MUA or listman problem. I think my original patch was mangled as well, so if you inherited this from my patch I apologize... > then > - local server_flag=@localhost > - fi > - > - dnsreply=$(dig $server_flag +short -t srv _$1._$2.$(dnsdomainname)) > + dnsreply=$(dig +short -t srv _$1._$2.$(dnsdomainname)) > if [ $? -eq 0 ]; then > set _ $dnsreply; shift > SRV_HOST=$4; SRV_PORT=$3 > @@ -118,6 +119,15 @@ if [ `egrep -c '^mech_list: gssapi' $SASL_FILE` -eq > 0 ]; then > echo "mech_list: gssapi" >> $SASL_FILE > fi > > +# if we are developer/bundled install, remove default network > +# so dnsmasq from libvirt doesn't interfere with the dev/bundled > +# dnsmasq > +if [[ "$PROD_INST" == "false" ]]; then > + service libvirtd status > /dev/null 2&>1 || service libvirtd start > > /dev/null 2>&1 > + virsh net-destroy default > + virsh net-undefine default > +fi > + > service postgresql stop > /dev/null 2>&1 > service postgresql initdb > /dev/null 2>&1 > echo "local all all trust" > /var/lib/pgsql/data/pg_hba.conf @@ -162,20 > +172,12 @@ cd - > ${OVIRT_DIR}/script/grant_admin_privileges admin > [ $? != 0 ] && echo "Failed to grant admin privileges" && exit 1 > > -if [ -f /usr/share/ovirt-wui/ovirtadmin.tab ]; then > +if [ -f ${OVIRT_DIR}/ovirtadmin.tab ]; then > ${OVIRT_DIR}/script/grant_admin_privileges ovirtadmin > [ $? != 0 ] && echo "Failed to grant ovirtadmin privileges" && exit 1 > fi > > -/usr/bin/ovirt-add-host $(hostname) ${OVIRT_DIR}/ovirt.keytab > - > -# This is temporary until we get a version of FreeIPA that runs under /ipa > -# instead of as root > -if [ -f /etc/httpd/conf.d/ipa.conf ]; then > - /usr/bin/ovirt-fix-ipa > - service httpd restart > - service ipa_webgui restart > -fi > +ovirt-add-host $(hostname) ${OVIRT_DIR}/ovirt.keytab > > for svc in $OVIRT_SVCS $ENABLE_SVCS; do > service $svc start > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel -- |=- Red Hat, Engineering, Emerging Technologies, Boston -=| |=- Email: pmyers at redhat.com -=| |=- Office: +1 412 474 3552 Mobile: +1 703 362 9622 -=| |=- GnuPG: E65E4F3D 88F9 F1C9 C2F3 1303 01FE 817C C5D2 8B91 E65E 4F3D -=| From apevec at redhat.com Tue May 27 09:08:32 2008 From: apevec at redhat.com (Alan Pevec) Date: Tue, 27 May 2008 11:08:32 +0200 Subject: [Ovirt-devel] [PATCH] Fix so libvirt does not start default network interface on developer/bundled In-Reply-To: <483B6747.3080407@redhat.com> References: <1211566543-10584-1-git-send-email-pmyers@redhat.com> <20080523181954.GB12467@redhat.com> <483AB839.3020102@redhat.com> <483AC907.5050508@redhat.com> <483ADA71.6050700@redhat.com> <483B5D4A.70707@redhat.com> <483B6747.3080407@redhat.com> Message-ID: <483BCF90.6070408@redhat.com> >> --disabled=iptables,yum-updatesd,libvirtd,bluetooth,cups,gpm,pcscd,NetworkManager,NetworkManagerDispatcher >> --enabled=ntpd,httpd,postgresql,ovirt-wui,tgtd,nfs,collectd,network >> +services >> --disabled=libvirtd,postgresql,iptables,yum-updatesd,bluetooth,cups,gpm,pcscd,NetworkManager,NetworkManagerDispatcher >> --enabled=network,tgtd,nfs > > Hmm. Why is --enabled reduced to just network, tgtd and nfs? What > about ntpd, httpd, etc?? They'll be enabled and started after they are configured in ovirt-wui-install >> -OVIRT_SVCS="ovirt-host-browser ovirt-host-status \ >> - ovirt-taskomatic ovirt-host-keyadd ovirt-mongrel-rails" >> -ENABLE_SVCS="ntpd httpd postgresql libvirtd" >> +OVIRT_SVCS="ovirt-host-browser ovirt-host-keyadd ovirt-host-status \ >> + ovirt-mongrel-rails ovirt-taskomatic" > > Did you reorder OVIRT_SVCS just to alphabetize it? :) yeah, doesn't matter really, just looks better to my squared mind :) >> - # This checks to see if we're running on a bundled/developer >> install. - # If so, the server queried is localhost instead of >> using resolv.conf. - if [ "$(hostname)" == >> "management.priv.ovirt.org" ]; > > This looks mangled. Probably just MUA or listman problem. I think my > original patch was mangled as well, so if you inherited this from my > patch I apologize... Looks ok with View -> Message Source, so it must be Thunderbird mangling it during display/quoting. Guess we both should switch to a real MUA like mutt :) ap From pmyers at redhat.com Tue May 27 13:10:16 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Tue, 27 May 2008 09:10:16 -0400 Subject: [Ovirt-devel] [PATCH] Fix so libvirt does not start default network interface on developer/bundled In-Reply-To: <483BCF90.6070408@redhat.com> References: <1211566543-10584-1-git-send-email-pmyers@redhat.com> <20080523181954.GB12467@redhat.com> <483AB839.3020102@redhat.com> <483AC907.5050508@redhat.com> <483ADA71.6050700@redhat.com> <483B5D4A.70707@redhat.com> <483B6747.3080407@redhat.com> <483BCF90.6070408@redhat.com> Message-ID: <483C0838.2080806@redhat.com> Alan Pevec wrote: >>> --disabled=iptables,yum-updatesd,libvirtd,bluetooth,cups,gpm,pcscd,NetworkManager,NetworkManagerDispatcher >>> --enabled=ntpd,httpd,postgresql,ovirt-wui,tgtd,nfs,collectd,network >>> +services >>> --disabled=libvirtd,postgresql,iptables,yum-updatesd,bluetooth,cups,gpm,pcscd,NetworkManager,NetworkManagerDispatcher >>> --enabled=network,tgtd,nfs >> >> Hmm. Why is --enabled reduced to just network, tgtd and nfs? What >> about ntpd, httpd, etc?? > They'll be enabled and started after they are configured in > ovirt-wui-install Ah, ok. Ack then, please commit this :) Perry From sseago at redhat.com Tue May 27 14:22:58 2008 From: sseago at redhat.com (Scott Seago) Date: Tue, 27 May 2008 10:22:58 -0400 Subject: [Ovirt-devel] [PATCH] hooked up VM Actions support. Message-ID: <483C1942.6030008@redhat.com> -------------- next part -------------- A non-text attachment was scrubbed... Name: vm-actions.patch Type: text/x-patch Size: 16424 bytes Desc: not available URL: From sseago at redhat.com Tue May 27 16:20:04 2008 From: sseago at redhat.com (Scott Seago) Date: Tue, 27 May 2008 12:20:04 -0400 Subject: [Ovirt-devel] [PATCH] added confirmation dialogs for remaining actions Message-ID: <483C34B4.7040101@redhat.com> -------------- next part -------------- A non-text attachment was scrubbed... Name: confirmation-messages.patch Type: text/x-patch Size: 16857 bytes Desc: not available URL: From hbrock at redhat.com Tue May 27 17:29:36 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Tue, 27 May 2008 13:29:36 -0400 Subject: [Ovirt-devel] [PATCH] hooked up VM Actions support. In-Reply-To: <483C1942.6030008@redhat.com> References: <483C1942.6030008@redhat.com> Message-ID: <20080527172936.GL14196@redhat.com> On Tue, May 27, 2008 at 10:22:58AM -0400, Scott Seago wrote: > > >From 95b8ffe92a8ed62837e71ec59c5fcfea1622e27c Mon Sep 17 00:00:00 2001 > From: Scott Seago > Date: Tue, 27 May 2008 10:19:08 -0400 > Subject: [PATCH] hooked up VM Actions support. The confirmation dialog here needs a bit of styling work, but otherwise it works. > > > Signed-off-by: Scott Seago > --- > wui/src/app/controllers/resources_controller.rb | 97 +++++++++++++--------- > wui/src/app/controllers/vm_controller.rb | 17 ++--- > wui/src/app/helpers/application_helper.rb | 12 +++ > wui/src/app/models/vm.rb | 10 +++ > wui/src/app/models/vm_task.rb | 20 +++-- > wui/src/app/views/layouts/confirmation.rhtml | 2 + > wui/src/app/views/resources/show_vms.rhtml | 14 +++- > wui/src/app/views/resources/vm_actions.rhtml | 35 ++++++++ > 8 files changed, 147 insertions(+), 60 deletions(-) > create mode 100644 wui/src/app/views/layouts/confirmation.rhtml > create mode 100644 wui/src/app/views/resources/vm_actions.rhtml > > diff --git a/wui/src/app/controllers/resources_controller.rb b/wui/src/app/controllers/resources_controller.rb > index aef2fd5..febbbb6 100644 > --- a/wui/src/app/controllers/resources_controller.rb > +++ b/wui/src/app/controllers/resources_controller.rb > @@ -24,6 +24,7 @@ class ResourcesController < ApplicationController > end > > before_filter :pre_json, :only => [:vms_json, :users_json] > + before_filter :pre_vm_actions, :only => [:vm_actions] > > # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html) > verify :method => :post, :only => [ :destroy, :create, :update ], > @@ -69,12 +70,12 @@ class ResourcesController < ApplicationController > # resource's vms list page > def show_vms > show > - @actions = [["Start", VmTask::ACTION_START_VM], > - ["Shutdown", VmTask::ACTION_SHUTDOWN_VM, "break"], > - ["Suspend", VmTask::ACTION_SUSPEND_VM], > - ["Resume", VmTask::ACTION_RESUME_VM], > - ["Save", VmTask::ACTION_SAVE_VM], > - ["Restore", VmTask::ACTION_RESTORE_VM]] > + @actions = [VmTask.label_and_action(VmTask::ACTION_START_VM), > + (VmTask.label_and_action(VmTask::ACTION_SHUTDOWN_VM) << "break"), > + VmTask.label_and_action(VmTask::ACTION_SUSPEND_VM), > + VmTask.label_and_action(VmTask::ACTION_RESUME_VM), > + VmTask.label_and_action(VmTask::ACTION_SAVE_VM), > + VmTask.label_and_action(VmTask::ACTION_RESTORE_VM)] > end > > # resource's users list page > @@ -143,45 +144,54 @@ class ResourcesController < ApplicationController > end > > def vm_actions > - @vm_resource_pool = VmResourcePool.find(params[:vm_resource_pool_id]) > - set_perms(@vm_resource_pool) > - unless @can_modify > - flash[:notice] = 'You do not have permission to perform VM actions for this VM Resource Pool ' > - redirect_to :action => 'show', :id => @vm_resource_pool > - else > - params[:vm_actions].each do |name, param| > - print "param: ", name, ", ", param, "\n" > - end > - if params[:vm_actions][:vms] > - vms = params[:vm_actions][:vms] > - if params[:vm_actions][VmTask::ACTION_START_VM] > - flash[:notice] = "Starting Machines #{vms.join(',')}." > - elsif params[:vm_actions][VmTask::ACTION_SHUTDOWN_VM] > - flash[:notice] = "Stopping Machines #{vms.join(',')}." > - elsif params[:vm_actions][:other_actions] > - case params[:vm_actions][:other_actions] > - when VmTask::ACTION_SHUTDOWN_VM then flash[:notice] = "Stopping Machines #{vms.join(',')}." > - when VmTask::ACTION_START_VM then flash[:notice] = "Starting Machines #{vms.join(',')}." > - when VmTask::ACTION_SUSPEND_VM then flash[:notice] = "Suspending Machines #{vms.join(',')}." > - when VmTask::ACTION_RESUME_VM then flash[:notice] = "Resuming Machines #{vms.join(',')}." > - when VmTask::ACTION_SAVE_VM then flash[:notice] = "Saving Machines #{vms.join(',')}." > - when VmTask::ACTION_RESTORE_VM then flash[:notice] = "Restoring Machines #{vms.join(',')}." > - when "destroy" then flash[:notice] = "Destroying Machines #{vms.join(',')}." > + @action = params[:vm_action] > + @action_label = VmTask.action_label(@action) > + vms_str = params[:vm_ids] > + @vms = vms_str.split(",").collect {|x| Vm.find(x.to_i)} > + @success_list = [] > + @failure_list = [] > + begin > + @vm_resource_pool.transaction do > + @vms.each do |vm| > + if vm.queue_action(@user, @action) > + @success_list << vm > + print vm.description, vm.id, "\n" > else > - flash[:notice] = 'No Action Chosen.' > + @failure_list << vm > end > - else > - flash[:notice] = 'No Action Chosen.' > end > - else > - flash[:notice] = 'No Virtual Machines Selected.' > - end > - if params[:vm_actions][:vm_resource_pool_id] > - redirect_to :action => 'show', :id => params[:vm_actions][:vm_resource_pool_id] > - else > - redirect_to :action => 'list' > end > + rescue > + flash[:errmsg] = 'Error queueing VM actions.' > + @success_list = [] > + @failure_list = [] > end > + render :layout => 'confirmation' > + > + #if params[:vm_actions][:vms] > + # vms = params[:vm_actions][:vms] > + # if params[:vm_actions][VmTask::ACTION_START_VM] > + # flash[:notice] = "Starting Machines #{vms.join(',')}." > + # elsif params[:vm_actions][VmTask::ACTION_SHUTDOWN_VM] > + # flash[:notice] = "Stopping Machines #{vms.join(',')}." > + # elsif params[:vm_actions][:other_actions] > + # case params[:vm_actions][:other_actions] > + # when VmTask::ACTION_SHUTDOWN_VM then flash[:notice] = "Stopping Machines #{vms.join(',')}." > + # when VmTask::ACTION_START_VM then flash[:notice] = "Starting Machines #{vms.join(',')}." > + # when VmTask::ACTION_SUSPEND_VM then flash[:notice] = "Suspending Machines #{vms.join(',')}." > + # when VmTask::ACTION_RESUME_VM then flash[:notice] = "Resuming Machines #{vms.join(',')}." > + # when VmTask::ACTION_SAVE_VM then flash[:notice] = "Saving Machines #{vms.join(',')}." > + # when VmTask::ACTION_RESTORE_VM then flash[:notice] = "Restoring Machines #{vms.join(',')}." > + # when "destroy" then flash[:notice] = "Destroying Machines #{vms.join(',')}." > + # else > + # flash[:notice] = 'No Action Chosen.' > + # end > + # else > + # flash[:notice] = 'No Action Chosen.' > + # end > + #else > + # flash[:notice] = 'No Virtual Machines Selected.' > + #end > end > > protected > @@ -215,5 +225,12 @@ class ResourcesController < ApplicationController > pre_show > show > end > + def pre_vm_actions > + @vm_resource_pool = VmResourcePool.find(params[:id]) > + @parent = @vm_resource_pool.parent > + @perm_obj = @vm_resource_pool > + @redir_obj = @vm_resource_pool > + authorize_user > + end > > end > diff --git a/wui/src/app/controllers/vm_controller.rb b/wui/src/app/controllers/vm_controller.rb > index 7eba30c..ac29beb 100644 > --- a/wui/src/app/controllers/vm_controller.rb > +++ b/wui/src/app/controllers/vm_controller.rb > @@ -138,20 +138,15 @@ class VmController < ApplicationController > end > > def vm_action > - if @vm.get_action_list.include?(params[:vm_action]) > - @task = VmTask.new({ :user => get_login_user, > - :vm_id => params[:id], > - :action => params[:vm_action], > - :state => Task::STATE_QUEUED}) > - if @task.save > - flash[:notice] = "#{params[:vm_action]} was successfully queued." > + begin > + if @vm.queue_action(get_login_user, params[:vm_action]) > + render :json => { :object => "vm", :success => true, :alert => "#{vm_action} was successfully queued." } > else > - flash[:notice] = "Error in inserting task for #{params[:vm_action]}." > + render :json => { :object => "vm", :success => false, :alert => "#{vm_action} is an invalid action." } > end > - else > - flash[:notice] = "#{params[:vm_action]} is an invalid action." > + rescue > + render :json => { :object => "vm", :success => false, :alert => "Error in queueing #{vm_action}." } > end > - redirect_to :controller => 'vm', :action => 'show', :id => params[:id] > end > > def cancel_queued_tasks > diff --git a/wui/src/app/helpers/application_helper.rb b/wui/src/app/helpers/application_helper.rb > index 4dbf2b8..20c344f 100644 > --- a/wui/src/app/helpers/application_helper.rb > +++ b/wui/src/app/helpers/application_helper.rb > @@ -94,6 +94,18 @@ module ApplicationHelper > } > end > > + def ok_footer > + %{ > +
      > +
      > +
      > + > +
      > +
      > +
      > + } > + end > + > > def timeout_flash(name) > %{ > diff --git a/wui/src/app/models/vm.rb b/wui/src/app/models/vm.rb > index 7a9cc79..f80c50b 100644 > --- a/wui/src/app/models/vm.rb > +++ b/wui/src/app/models/vm.rb > @@ -170,6 +170,16 @@ class Vm < ActiveRecord::Base > vm_tasks > end > > + def queue_action(user, action) > + return false unless get_action_list.include?(action) > + task = VmTask.new({ :user => user, > + :vm_id => id, > + :action => action, > + :state => Task::STATE_QUEUED}) > + task.save! > + return true > + end > + > protected > def validate > resources = vm_resource_pool.max_resources_for_vm(self) > diff --git a/wui/src/app/models/vm_task.rb b/wui/src/app/models/vm_task.rb > index f458a68..7e46b93 100644 > --- a/wui/src/app/models/vm_task.rb > +++ b/wui/src/app/models/vm_task.rb > @@ -34,37 +34,37 @@ class VmTask < Task > ACTION_UPDATE_STATE_VM = "update_state_vm" > > # a hash of task actions which point to a hash which define valid state transitions > - ACTIONS = { ACTION_CREATE_VM => { :label => "Create VM", > + ACTIONS = { ACTION_CREATE_VM => { :label => "Create", > :start => Vm::STATE_PENDING, > :running => Vm::STATE_CREATING, > :success => Vm::STATE_STOPPED, > :failure => Vm::STATE_CREATE_FAILED}, > - ACTION_START_VM => { :label => "Start VM", > + ACTION_START_VM => { :label => "Start", > :start => Vm::STATE_STOPPED, > :running => Vm::STATE_STARTING, > :success => Vm::STATE_RUNNING, > :failure => Vm::STATE_STOPPED}, > - ACTION_SHUTDOWN_VM => { :label => "Shutdown VM", > + ACTION_SHUTDOWN_VM => { :label => "Shutdown", > :start => Vm::STATE_RUNNING, > :running => Vm::STATE_STOPPING, > :success => Vm::STATE_STOPPED, > :failure => Vm::STATE_RUNNING}, > - ACTION_SUSPEND_VM => { :label => "Suspend VM", > + ACTION_SUSPEND_VM => { :label => "Suspend", > :start => Vm::STATE_RUNNING, > :running => Vm::STATE_SUSPENDING, > :success => Vm::STATE_SUSPENDED, > :failure => Vm::STATE_RUNNING}, > - ACTION_RESUME_VM => { :label => "Resume VM", > + ACTION_RESUME_VM => { :label => "Resume", > :start => Vm::STATE_SUSPENDED, > :running => Vm::STATE_RESUMING, > :success => Vm::STATE_RUNNING, > :failure => Vm::STATE_SUSPENDED}, > - ACTION_SAVE_VM => { :label => "Save VM", > + ACTION_SAVE_VM => { :label => "Save", > :start => Vm::STATE_RUNNING, > :running => Vm::STATE_SAVING, > :success => Vm::STATE_SAVED, > :failure => Vm::STATE_RUNNING}, > - ACTION_RESTORE_VM => { :label => "Restore VM", > + ACTION_RESTORE_VM => { :label => "Restore", > :start => Vm::STATE_SAVED, > :running => Vm::STATE_RESTORING, > :success => Vm::STATE_RUNNING, > @@ -80,4 +80,10 @@ class VmTask < Task > Vm::STATE_CREATE_FAILED => [], > Vm::STATE_INVALID => []} > > + def self.action_label(action) > + return ACTIONS[action][:label] > + end > + def self.label_and_action(action) > + return [action_label(action), action] > + end > end > diff --git a/wui/src/app/views/layouts/confirmation.rhtml b/wui/src/app/views/layouts/confirmation.rhtml > new file mode 100644 > index 0000000..736517c > --- /dev/null > +++ b/wui/src/app/views/layouts/confirmation.rhtml > @@ -0,0 +1,2 @@ > +<%# currently nothing for popups here. %> > +<%= yield %> > diff --git a/wui/src/app/views/resources/show_vms.rhtml b/wui/src/app/views/resources/show_vms.rhtml > index 8f1f4a3..8e951bf 100644 > --- a/wui/src/app/views/resources/show_vms.rhtml > +++ b/wui/src/app/views/resources/show_vms.rhtml > @@ -5,7 +5,7 @@ > <%= image_tag "icon_move.png", :style => "vertical-align:middle;" %>  Actions    <%= image_tag "icon_toolbar_arrow.gif", :style => "vertical-align:middle;" %> >
        > <% @actions.each_index { |index| %> > -
      • +
      • <% if (index == @actions.length - 1) or @actions[index].length == 3 %> > style="border-bottom: 1px solid black;" > <% end %> > @@ -27,13 +27,23 @@ > { > vms = get_selected_vms() > if (validate_selected(vms, "vm")) { > - $.post('<%= url_for :controller => "vm", :action => "delete", :id => @pool %>', > + $.post('<%= url_for :controller => "vm", :action => "delete", :id => @vm_resource_pool %>', > { vm_ids: vms.toString() }, > function(data,status){ > $("#vms_grid").flexReload() > }); > } > } > + function vm_actions(action) > + { > + vms = get_selected_vms() > + if (validate_selected(vms, "vm")) { > + jQuery.facebox('
        ') > + $('#vm_action_results').load('<%= url_for :controller => "resources", > + :action => "vm_actions", :id => @vm_resource_pool %>', > + { vm_ids: vms.toString(), vm_action: action }); > + } > + } > function vms_select(selected_rows) > { > var selected_ids = new Array() > diff --git a/wui/src/app/views/resources/vm_actions.rhtml b/wui/src/app/views/resources/vm_actions.rhtml > new file mode 100644 > index 0000000..d556b94 > --- /dev/null > +++ b/wui/src/app/views/resources/vm_actions.rhtml > @@ -0,0 +1,35 @@ > +
        > +
        Virtual Machine Action Results
        > +
        Results for <%= @action_label %> action
        > +
        > +
        > + > + <% if flash[:notice] or flash[:errmsg] %> > + <% if flash[:notice] %> > + <%= flash[:notice] %> > + <% end %> > + > + <% if flash[:notice] and flash[:errmsg] %> > +
        > + <% end %> > + > + <% if flash[:errmsg] %> > + <%= flash[:errmsg] %> > + <% end %> > +
        > + <% end %> > +Action succeeded for these VMs: > +
          > + <% for vm in @success_list %> > +
        • <%= vm.description %>
        • > + <% end %> > +
        > + > +Action invalid for these VMs: > +
          > + <% for vm in @failure_list %> > +
        • <%= vm.description %>
        • > + <% end %> > +
        > +
        > +<%= ok_footer %> > -- > 1.5.4.1 > ACK and committed, with the note that a future patch will add confirmation on deleting a VM (currently missing). --Hugh From sseago at redhat.com Tue May 27 17:34:03 2008 From: sseago at redhat.com (Scott Seago) Date: Tue, 27 May 2008 13:34:03 -0400 Subject: [Ovirt-devel] [PATCH] added confirmation dialogs for remaining actions In-Reply-To: <483C34B4.7040101@redhat.com> References: <483C34B4.7040101@redhat.com> Message-ID: <483C460B.6010606@redhat.com> Scott Seago wrote: > > ------------------------------------------------------------------------ > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel Missed an error in the patch... From sseago at redhat.com Tue May 27 17:35:11 2008 From: sseago at redhat.com (Scott Seago) Date: Tue, 27 May 2008 13:35:11 -0400 Subject: [Ovirt-devel] [PATCH] added confirmation dialogs for remaining actions In-Reply-To: <483C34B4.7040101@redhat.com> References: <483C34B4.7040101@redhat.com> Message-ID: <483C464F.4000007@redhat.com> Scott Seago wrote: > > ------------------------------------------------------------------------ > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel Trying again with the patch sufficiently mangled... -------------- next part -------------- A non-text attachment was scrubbed... Name: confirmation-messages-2.patch Type: text/x-patch Size: 1007 bytes Desc: not available URL: From hbrock at redhat.com Tue May 27 17:49:06 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Tue, 27 May 2008 13:49:06 -0400 Subject: [Ovirt-devel] [PATCH] added confirmation dialogs for remaining actions In-Reply-To: <483C34B4.7040101@redhat.com> References: <483C34B4.7040101@redhat.com> Message-ID: <20080527174859.GM14196@redhat.com> On Tue, May 27, 2008 at 12:20:04PM -0400, Scott Seago wrote: > > >From cd827b580ca56c8b552acf21cb2d3f457dcfbe0a Mon Sep 17 00:00:00 2001 > From: Scott Seago > Date: Tue, 27 May 2008 12:17:51 -0400 > Subject: [PATCH] added confirmation dialogs for remaining actions > > > Signed-off-by: Scott Seago > --- > wui/src/app/controllers/hardware_controller.rb | 52 ++++++++++++++++------ > wui/src/app/controllers/permission_controller.rb | 38 ++++++++++----- > wui/src/app/controllers/resources_controller.rb | 19 +++++--- > wui/src/app/controllers/storage_controller.rb | 18 +++++--- > wui/src/app/controllers/vm_controller.rb | 17 +++++--- > wui/src/app/views/hardware/move.rhtml | 5 ++- > wui/src/app/views/hardware/show_hosts.rhtml | 5 ++- > wui/src/app/views/hardware/show_storage.rhtml | 10 +++- > wui/src/app/views/hardware/show_vms.rhtml | 5 ++- > wui/src/app/views/host/addhost.html.erb | 5 ++- > wui/src/app/views/layouts/_side_toolbar.rhtml | 2 +- > wui/src/app/views/resources/show_vms.rhtml | 5 ++- > wui/src/app/views/storage/addstorage.html.erb | 5 ++- > wui/src/app/views/user/_show.rhtml | 12 ++++- > 14 files changed, 141 insertions(+), 57 deletions(-) > > diff --git a/wui/src/app/controllers/hardware_controller.rb b/wui/src/app/controllers/hardware_controller.rb > index a052885..ad857f1 100644 > --- a/wui/src/app/controllers/hardware_controller.rb > +++ b/wui/src/app/controllers/hardware_controller.rb > @@ -310,11 +310,17 @@ class HardwareController < ApplicationController > def add_hosts > host_ids_str = params[:host_ids] > host_ids = host_ids_str.split(",").collect {|x| x.to_i} > - > - @pool.transaction do > - @pool.move_hosts(host_ids, @pool.id) > + > + begin > + @pool.transaction do > + @pool.move_hosts(host_ids, @pool.id) > + end > + render :json => { :object => "host", :success => true, > + :alert => "Hosts were successfully added to this Hardware pool." } > + rescue > + render :json => { :object => "host", :success => false, > + :alert => "Error adding Hosts to this Hardware pool." } > end > - render :text => "added hosts (#{host_ids.join(', ')})" > end > > #FIXME: we need permissions checks. user must have permission on src pool > @@ -325,10 +331,16 @@ class HardwareController < ApplicationController > host_ids_str = params[:resource_ids] > host_ids = host_ids_str.split(",").collect {|x| x.to_i} > > - @pool.transaction do > - @pool.move_hosts(host_ids, target_pool_id) > + begin > + @pool.transaction do > + @pool.move_hosts(host_ids, target_pool_id) > + end > + render :json => { :object => "host", :success => true, > + :alert => "Hosts were successfully moved." } > + rescue > + render :json => { :object => "host", :success => false, > + :alert => "Error moving hosts." } > end > - render :text => "added hosts (#{host_ids.join(', ')})" > end > > #FIXME: we need permissions checks. user must have permission on src pool > @@ -338,10 +350,16 @@ class HardwareController < ApplicationController > storage_pool_ids_str = params[:storage_pool_ids] > storage_pool_ids = storage_pool_ids_str.split(",").collect {|x| x.to_i} > > - @pool.transaction do > - @pool.move_storage(storage_pool_ids, @pool.id) > + begin > + @pool.transaction do > + @pool.move_storage(storage_pool_ids, @pool.id) > + end > + render :json => { :object => "storage_pool", :success => true, > + :alert => "Storage Pools were successfully added to this Hardware pool." } > + rescue > + render :json => { :object => "storage_pool", :success => false, > + :alert => "Error adding storage pools to this Hardware pool." } > end > - render :text => "added storage (#{storage_pool_ids.join(', ')})" > end > > #FIXME: we need permissions checks. user must have permission on src pool > @@ -351,11 +369,17 @@ class HardwareController < ApplicationController > target_pool_id = params[:target_pool_id] > storage_pool_ids_str = params[:resource_ids] > storage_pool_ids = storage_pool_ids_str.split(",").collect {|x| x.to_i} > - > - @pool.transaction do > - @pool.move_storage(storage_pool_ids, target_pool_id) > + > + begin > + @pool.transaction do > + @pool.move_storage(storage_pool_ids, target_pool_id) > + end > + render :json => { :object => "storage_pool", :success => true, > + :alert => "Storage Pools were successfully moved." } > + rescue > + render :json => { :object => "storage_pool", :success => false, > + :alert => "Error moving storage pools." } > end > - render :text => "added storage (#{storage_pool_ids.join(', ')})" > end > > def destroy > diff --git a/wui/src/app/controllers/permission_controller.rb b/wui/src/app/controllers/permission_controller.rb > index 1787a27..14358de 100644 > --- a/wui/src/app/controllers/permission_controller.rb > +++ b/wui/src/app/controllers/permission_controller.rb > @@ -74,15 +74,21 @@ class PermissionController < ApplicationController > role = params[:user_role] > permission_ids_str = params[:permission_ids] > permission_ids = permission_ids_str.split(",").collect {|x| x.to_i} > - > - Permission.transaction do > - permissions = Permission.find(:all, :conditions => "id in (#{permission_ids.join(', ')})") > - permissions.each do |permission| > - permission.user_role = role > - permission.save! > + > + begin > + Permission.transaction do > + permissions = Permission.find(:all, :conditions => "id in (#{permission_ids.join(', ')})") > + permissions.each do |permission| > + permission.user_role = role > + permission.save! > + end > end > + render :json => { :object => "permission", :success => true, > + :alert => "User roles were successfully updated." } > + rescue > + render :json => { :object => "permission", :success => false, > + :alert => "Error updating user roles: #{$!}" } > end > - render :text => "deleted user permissions (#{permission_ids.join(', ')})" > end > > #FIXME: we need permissions checks. user must have permission. We also need to fail > @@ -90,14 +96,20 @@ class PermissionController < ApplicationController > def delete > permission_ids_str = params[:permission_ids] > permission_ids = permission_ids_str.split(",").collect {|x| x.to_i} > - > - Permission.transaction do > - permissions = Permission.find(:all, :conditions => "id in (#{permission_ids.join(', ')})") > - permissions.each do |permission| > - permission.destroy > + > + begin > + Permission.transaction do > + permissions = Permission.find(:all, :conditions => "id in (#{permission_ids.join(', ')})") > + permissions.each do |permission| > + permission.destroy > + end > end > + render :json => { :object => "permission", :success => true, > + :alert => "User roles were successfully deleted." } > + rescue > + render :json => { :object => "permission", :success => false, > + :alert => "Error deleting user roles." } > end > - render :text => "deleted user permissions (#{permission_ids.join(', ')})" > end > > def destroy > diff --git a/wui/src/app/controllers/resources_controller.rb b/wui/src/app/controllers/resources_controller.rb > index febbbb6..c891447 100644 > --- a/wui/src/app/controllers/resources_controller.rb > +++ b/wui/src/app/controllers/resources_controller.rb > @@ -127,14 +127,21 @@ class ResourcesController < ApplicationController > def delete > vm_pool_ids_str = params[:vm_pool_ids] > vm_pool_ids = vm_pool_ids_str.split(",").collect {|x| x.to_i} > - > - VmResourcePool.transaction do > - pools = VmResourcePool.find(:all, :conditions => "id in (#{vm_pool_ids.join(', ')})") > - pools.each do |pool| > - pool.destroy > + vm_pool_names = [] > + begin > + VmResourcePool.transaction do > + pools = VmResourcePool.find(:all, :conditions => "id in (#{vm_pool_ids.join(', ')})") > + pools.each do |pool| > + vm_pool_names << pool.name > + pool.destroy > + end > end > + render :json => { :object => "vm_resource_pool", :success => true, > + :alert => "Virtual Machine Pools #{vm_pool_names.join(', ')} were successfully deleted." } > + rescue > + render :json => { :object => "vm_resource_pool", :success => false, > + :alert => "Error in deleting Virtual Machine Pools."} > end > - render :text => "deleted vm pools (#{vm_pool_ids.join(', ')})" > end > > def destroy > diff --git a/wui/src/app/controllers/storage_controller.rb b/wui/src/app/controllers/storage_controller.rb > index 618acb4..853472a 100644 > --- a/wui/src/app/controllers/storage_controller.rb > +++ b/wui/src/app/controllers/storage_controller.rb > @@ -155,14 +155,20 @@ class StorageController < ApplicationController > def delete_pools > storage_pool_ids_str = params[:storage_pool_ids] > storage_pool_ids = storage_pool_ids_str.split(",").collect {|x| x.to_i} > - > - StoragePool.transaction do > - storage = StoragePool.find(:all, :conditions => "id in (#{storage_pool_ids.join(', ')})") > - storage.each do |storage_pool| > - storage_pool.destroy > + > + begin > + StoragePool.transaction do > + storage = StoragePool.find(:all, :conditions => "id in (#{storage_pool_ids.join(', ')})") > + storage.each do |storage_pool| > + storage_pool.destroy > + end > end > + render :json => { :object => "storage_pool", :success => true, > + :alert => "Storage Pools were successfully deleted." } > + rescue > + render :json => { :object => "storage_pool", :success => true, > + :alert => "Error deleting storage pools." } > end > - render :text => "deleted storage (#{storage_pool_ids.join(', ')})" > end > > def vm_action > diff --git a/wui/src/app/controllers/vm_controller.rb b/wui/src/app/controllers/vm_controller.rb > index ac29beb..8e6d7f8 100644 > --- a/wui/src/app/controllers/vm_controller.rb > +++ b/wui/src/app/controllers/vm_controller.rb > @@ -102,13 +102,18 @@ class VmController < ApplicationController > vm_ids_str = params[:vm_ids] > vm_ids = vm_ids_str.split(",").collect {|x| x.to_i} > > - Vm.transaction do > - vms = Vm.find(:all, :conditions => "id in (#{vm_ids.join(', ')})") > - vms.each do |vm| > - vm.destroy > - end > + begin > + Vm.transaction do > + vms = Vm.find(:all, :conditions => "id in (#{vm_ids.join(', ')})") > + vms.each do |vm| > + vm.destroy > + end > + end render :json => { :object => "vm", :success => true, > + :alert => "Virtual Machines were successfully deleted." } > + rescue > + render :json => { :object => "vm", :success => false, > + :alert => "Error deleting virtual machines." } > end > - render :text => "deleted vms (#{vm_ids.join(', ')})" > end > > def destroy > diff --git a/wui/src/app/views/hardware/move.rhtml b/wui/src/app/views/hardware/move.rhtml > index fb0bf51..190fc03 100644 > --- a/wui/src/app/views/hardware/move.rhtml > +++ b/wui/src/app/views/hardware/move.rhtml > @@ -19,7 +19,10 @@ > function(data,status){ > $("#<%= @resource_type %>_grid").flexReload() > jQuery(document).trigger('close.facebox'); > - }); > + if (data.alert) { > + alert(data.alert); > + } > + }, 'json'); > } > $('#move_to_new_pool').click(function(){ > $('#window').fadeOut('fast'); > diff --git a/wui/src/app/views/hardware/show_hosts.rhtml b/wui/src/app/views/hardware/show_hosts.rhtml > index 7f126a2..ae0e8af 100644 > --- a/wui/src/app/views/hardware/show_hosts.rhtml > +++ b/wui/src/app/views/hardware/show_hosts.rhtml > @@ -28,7 +28,10 @@ > { resource_ids: hosts.toString(), target_pool_id: <%= Pool.root.id %> }, > function(data,status){ > $("#hosts_grid").flexReload() > - }); > + if (data.alert) { > + alert(data.alert); > + } > + }, 'json'); > } > } > function hosts_select(selected_rows) > diff --git a/wui/src/app/views/hardware/show_storage.rhtml b/wui/src/app/views/hardware/show_storage.rhtml > index f673e07..3d547db 100644 > --- a/wui/src/app/views/hardware/show_storage.rhtml > +++ b/wui/src/app/views/hardware/show_storage.rhtml > @@ -30,7 +30,10 @@ > { resource_ids: storage.toString(), target_pool_id: <%= Pool.root.id %> }, > function(data,status){ > $("#storage_grid").flexReload() > - }); > + if (data.alert) { > + alert(data.alert); > + } > + }, 'json'); > } > } > function delete_storage() > @@ -41,7 +44,10 @@ > { storage_pool_ids: storage.toString() }, > function(data,status){ > $("#storage_grid").flexReload() > - }); > + if (data.alert) { > + alert(data.alert); > + } > + }, 'json'); > } > } > function storage_select(selected_rows) > diff --git a/wui/src/app/views/hardware/show_vms.rhtml b/wui/src/app/views/hardware/show_vms.rhtml > index 44b6f50..285f2c2 100644 > --- a/wui/src/app/views/hardware/show_vms.rhtml > +++ b/wui/src/app/views/hardware/show_vms.rhtml > @@ -17,7 +17,10 @@ > { vm_pool_ids: vm_pools.toString() }, > function(data,status){ > $("#vmpools_grid").flexReload() > - }); > + if (data.alert) { > + alert(data.alert); > + } > + }, 'json'); > } > } > function vmpools_select(selected_rows) > diff --git a/wui/src/app/views/host/addhost.html.erb b/wui/src/app/views/host/addhost.html.erb > index f485d8f..69e0e66 100644 > --- a/wui/src/app/views/host/addhost.html.erb > +++ b/wui/src/app/views/host/addhost.html.erb > @@ -34,7 +34,10 @@ > function(data,status){ > jQuery(document).trigger('close.facebox'); > $("#hosts_grid").flexReload() > - }); > + if (data.alert) { > + alert(data.alert); > + } > + }, 'json'); > } > } > > diff --git a/wui/src/app/views/layouts/_side_toolbar.rhtml b/wui/src/app/views/layouts/_side_toolbar.rhtml > index 1613799..000cb66 100644 > --- a/wui/src/app/views/layouts/_side_toolbar.rhtml > +++ b/wui/src/app/views/layouts/_side_toolbar.rhtml > @@ -10,11 +10,11 @@ > <%= image_tag "icon_add_vmpool.png", :title=>"Add Virtual Machine Pool" %> > >
        > +<% end -%> >
        > <%= link_to image_tag ("icon_delete.gif", :title=>"Delete Selected Pool"), > { :action => 'destroy', :id => pool }, > { :method => :post, :confirm => 'Are you sure you want to delete - %s?' % pool.name} %> > -<% end -%> >
        > >
        > diff --git a/wui/src/app/views/resources/show_vms.rhtml b/wui/src/app/views/resources/show_vms.rhtml > index 8e951bf..34764a6 100644 > --- a/wui/src/app/views/resources/show_vms.rhtml > +++ b/wui/src/app/views/resources/show_vms.rhtml > @@ -31,7 +31,10 @@ > { vm_ids: vms.toString() }, > function(data,status){ > $("#vms_grid").flexReload() > - }); > + if (data.alert) { > + alert(data.alert); > + } > + }, 'json'); > } > } > function vm_actions(action) > diff --git a/wui/src/app/views/storage/addstorage.html.erb b/wui/src/app/views/storage/addstorage.html.erb > index cf75ae5..a747502 100644 > --- a/wui/src/app/views/storage/addstorage.html.erb > +++ b/wui/src/app/views/storage/addstorage.html.erb > @@ -34,7 +34,10 @@ > function(data,status){ > jQuery(document).trigger('close.facebox'); > $("#storage_grid").flexReload() > - }); > + if (data.alert) { > + alert(data.alert); > + } > + }, 'json'); > } > } > > diff --git a/wui/src/app/views/user/_show.rhtml b/wui/src/app/views/user/_show.rhtml > index 03ecec6..d1c0ec1 100644 > --- a/wui/src/app/views/user/_show.rhtml > +++ b/wui/src/app/views/user/_show.rhtml > @@ -18,18 +18,24 @@ > { permission_ids: permissions.toString() }, > function(data,status){ > $("#users_grid").flexReload() > - }); > + if (data.alert) { > + alert(data.alert); > + } > + }, 'json'); > } > } > function update_users(role) > { > permissions = get_selected_users() > - if (validate_selected(permissions, "users)) { > + if (validate_selected(permissions, "users")) { > $.post('<%= url_for :controller => "permission", :action => "update_roles" %>', > { permission_ids: permissions.toString(), user_role: role }, > function(data,status){ > $("#users_grid").flexReload() > - }); > + if (data.alert) { > + alert(data.alert); > + } > + }, 'json'); > } > } > > -- > 1.5.4.1 Tested, works with the patch that follows (confirmation-dialog-2.patch)... therefore ACKed and committed --Hugh From hbrock at redhat.com Tue May 27 17:49:28 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Tue, 27 May 2008 13:49:28 -0400 Subject: [Ovirt-devel] [PATCH] added confirmation dialogs for remaining actions In-Reply-To: <483C464F.4000007@redhat.com> References: <483C34B4.7040101@redhat.com> <483C464F.4000007@redhat.com> Message-ID: <20080527174927.GN14196@redhat.com> On Tue, May 27, 2008 at 01:35:11PM -0400, Scott Seago wrote: > Scott Seago wrote: >> >> ------------------------------------------------------------------------ >> >> _______________________________________________ >> Ovirt-devel mailing list >> Ovirt-devel at redhat.com >> https://www.redhat.com/mailman/listinfo/ovirt-devel > Trying again with the patch sufficiently mangled... > >From 57e45b26956bc8349ce57fd854e104371e7461ba Mon Sep 17 00:00:00 2001 > From: Scott Seago > Date: Tue, 27 May 2008 13:33:03 -0400 > Subject: [PATCH] fixed a copy-and-paste bug in my last patch > > > Signed-off-by: Scott Seago > --- > wui/src/app/controllers/vm_controller.rb | 3 ++- > 1 files changed, 2 insertions(+), 1 deletions(-) > > diff --git a/wui/src/app/controllers/vm_controller.rb b/wui/src/app/controllers/vm_controller.rb > index 8e6d7f8..9bfd665 100644 > --- a/wui/src/app/controllers/vm_controller.rb > +++ b/wui/src/app/controllers/vm_controller.rb > @@ -108,7 +108,8 @@ class VmController < ApplicationController > vms.each do |vm| > vm.destroy > end > - end render :json => { :object => "vm", :success => true, > + end > + render :json => { :object => "vm", :success => true, > :alert => "Virtual Machines were successfully deleted." } > rescue > render :json => { :object => "vm", :success => false, > -- ACK and committed --H From slinabery at gmail.com Tue May 27 18:16:21 2008 From: slinabery at gmail.com (steve linabery) Date: Tue, 27 May 2008 13:16:21 -0500 Subject: [Ovirt-devel] Re: [PATCH] transactions in models and controllers In-Reply-To: <769584de0805251330q55f5393avfd1903d0eaacd493@mail.gmail.com> References: <769584de0805251330q55f5393avfd1903d0eaacd493@mail.gmail.com> Message-ID: <769584de0805271116l15014806i1532d02d94b90ce4@mail.gmail.com> On Sun, May 25, 2008 at 3:30 PM, steve linabery wrote: > Hi Ovirt, > > I believe this will make everything currently in app/models and > app/controllers transactional where necessary. > > As an aside, please note that these (and other recent) transaction > additions create the need for some exception handling that is not > currently present. > > Good day, > Steve > Hi Ovirt, Scott and I decided it would be better to wrap the insert_refresh_task with the create/update of StoragePool. So this version includes those changes as well. Thanks! Steve -------------- next part -------------- A non-text attachment was scrubbed... Name: transactions.patch Type: text/x-patch Size: 6056 bytes Desc: not available URL: From hbrock at redhat.com Tue May 27 21:31:07 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Tue, 27 May 2008 17:31:07 -0400 Subject: [Ovirt-devel] Re: [PATCH] transactions in models and controllers In-Reply-To: <769584de0805271116l15014806i1532d02d94b90ce4@mail.gmail.com> References: <769584de0805251330q55f5393avfd1903d0eaacd493@mail.gmail.com> <769584de0805271116l15014806i1532d02d94b90ce4@mail.gmail.com> Message-ID: <20080527213106.GO14196@redhat.com> On Tue, May 27, 2008 at 01:16:21PM -0500, steve linabery wrote: > On Sun, May 25, 2008 at 3:30 PM, steve linabery wrote: > > Hi Ovirt, > > > > I believe this will make everything currently in app/models and > > app/controllers transactional where necessary. > > > > As an aside, please note that these (and other recent) transaction > > additions create the need for some exception handling that is not > > currently present. > > > > Good day, > > Steve > > > > Hi Ovirt, > > Scott and I decided it would be better to wrap the insert_refresh_task > with the create/update of StoragePool. So this version includes those > changes as well. > > Thanks! > Steve > From d1abfa2e37701f97768ed5b0b030467b5fb06c82 Mon Sep 17 00:00:00 2001 > From: Steve Linabery > Date: Tue, 27 May 2008 13:12:06 -0500 > Subject: [PATCH] Adds remaining transactions to models and controllers. > > > Signed-off-by: Steve Linabery > --- > wui/src/app/controllers/permission_controller.rb | 2 +- > wui/src/app/controllers/storage_controller.rb | 24 ++++++++++++--------- > wui/src/app/controllers/vm_controller.rb | 24 ++++++++++++++------- > wui/src/app/models/hardware_pool.rb | 16 +++++++++----- > wui/src/app/models/task.rb | 2 +- > 5 files changed, 42 insertions(+), 26 deletions(-) > > diff --git a/wui/src/app/controllers/permission_controller.rb b/wui/src/app/controllers/permission_controller.rb > index 1787a27..3cbaaf6 100644 > --- a/wui/src/app/controllers/permission_controller.rb > +++ b/wui/src/app/controllers/permission_controller.rb > @@ -74,7 +74,7 @@ class PermissionController < ApplicationController > role = params[:user_role] > permission_ids_str = params[:permission_ids] > permission_ids = permission_ids_str.split(",").collect {|x| x.to_i} > - > + > Permission.transaction do > permissions = Permission.find(:all, :conditions => "id in (#{permission_ids.join(', ')})") > permissions.each do |permission| > diff --git a/wui/src/app/controllers/storage_controller.rb b/wui/src/app/controllers/storage_controller.rb > index 618acb4..d154a80 100644 > --- a/wui/src/app/controllers/storage_controller.rb > +++ b/wui/src/app/controllers/storage_controller.rb > @@ -112,8 +112,10 @@ class StorageController < ApplicationController > > def create > begin > - @storage_pool.save! > - insert_refresh_task > + StoragePool.transaction do > + @storage_pool.save! > + insert_refresh_task > + end > render :json => { :object => "storage_pool", :success => true, > :alert => "Storage Pool was successfully created." } > rescue > @@ -128,14 +130,16 @@ class StorageController < ApplicationController > > def update > # FIXME: handle save! properly, in conjunction w/ update_attributes, json, etc > - if @storage_pool.update_attributes(params[:storage_pool]) > - if insert_refresh_task > - storage_url = url_for(:controller => "storage", :action => "show", :id => @storage_pool) > - flash[:notice] = '%s was successfully updated.' % [ storage_url , at storage_pool.ip_addr] > - redirect_to :action => 'show', :id => @storage_pool > - else > - render :action => 'edit' > - end > + StoragePool.transaction do > + @storage_pool.update_attributes!(params[:storage_pool]) > + insert_refresh_task > + transaction_succeeded = true > + end > + > + if transaction_succeeded > + storage_url = url_for(:controller => "storage", :action => "show", :id => @storage_pool) > + flash[:notice] = '%s was successfully updated.' % [ storage_url , at storage_pool.ip_addr] > + redirect_to :action => 'show', :id => @storage_pool > else > render :action => 'edit' > end > diff --git a/wui/src/app/controllers/vm_controller.rb b/wui/src/app/controllers/vm_controller.rb > index ac29beb..856c494 100644 > --- a/wui/src/app/controllers/vm_controller.rb > +++ b/wui/src/app/controllers/vm_controller.rb > @@ -40,12 +40,14 @@ class VmController < ApplicationController > > def create > begin > - @vm.save! > - @task = VmTask.new({ :user => @user, > - :vm_id => @vm.id, > - :action => VmTask::ACTION_CREATE_VM, > - :state => Task::STATE_QUEUED}) > - @task.save! > + Vm.transaction do > + @vm.save! > + @task = VmTask.new({ :user => @user, > + :vm_id => @vm.id, > + :action => VmTask::ACTION_CREATE_VM, > + :state => Task::STATE_QUEUED}) > + @task.save! > + end > start_now = params[:start_now] > if (start_now) > if @vm.get_action_list.include?(VmTask::ACTION_START_VM) > @@ -150,8 +152,14 @@ class VmController < ApplicationController > end > > def cancel_queued_tasks > - @vm.get_queued_tasks.each { |task| task.cancel} > - flash[:notice] = "queued tasks canceled." > + begin > + Task.transaction do > + @vm.get_queued_tasks.each { |task| task.cancel} > + end > + flash[:notice] = "queued tasks canceled." > + rescue > + flash[:notice] = "cancel queued tasks failed." > + end > redirect_to :controller => 'vm', :action => 'show', :id => params[:id] > end > > diff --git a/wui/src/app/models/hardware_pool.rb b/wui/src/app/models/hardware_pool.rb > index df22b90..b1adc8f 100644 > --- a/wui/src/app/models/hardware_pool.rb > +++ b/wui/src/app/models/hardware_pool.rb > @@ -60,17 +60,21 @@ class HardwarePool < Pool > > def move_hosts(host_ids, target_pool_id) > hosts = Host.find(:all, :conditions => "id in (#{host_ids.join(', ')})") > - hosts.each do |host| > - host.hardware_pool_id = target_pool_id > - host.save! > + transaction do > + hosts.each do |host| > + host.hardware_pool_id = target_pool_id > + host.save! > + end > end > end > > def move_storage(storage_pool_ids, target_pool_id) > storage_pools = StoragePool.find(:all, :conditions => "id in (#{storage_pool_ids.join(', ')})") > - storage_pools.each do |storage_pool| > - storage_pool.hardware_pool_id = target_pool_id > - storage_pool.save! > + transaction do > + storage_pools.each do |storage_pool| > + storage_pool.hardware_pool_id = target_pool_id > + storage_pool.save! > + end > end > end > > diff --git a/wui/src/app/models/task.rb b/wui/src/app/models/task.rb > index a3e82c9..7960056 100644 > --- a/wui/src/app/models/task.rb > +++ b/wui/src/app/models/task.rb > @@ -31,7 +31,7 @@ class Task < ActiveRecord::Base > > def cancel > self[:state] = STATE_CANCELED > - save > + save! > end > > def self.working_tasks(user = nil) > -- ACK. Tested, appears to function normally, committed. Obviously we need to add error handling to deal with some failures here, but this is a good start. Thanks! --Hugh From mmorsi at redhat.com Tue May 27 21:23:40 2008 From: mmorsi at redhat.com (Mohammed Morsi) Date: Tue, 27 May 2008 17:23:40 -0400 Subject: [Ovirt-devel] [Patch] Experimental Graphs Backend Code Message-ID: <483C7BDC.3020206@redhat.com> This patch is for review only, and is not meant to be committed (partly because I didn't update before generating it and partly because I know some parts are wrong, but need feedback on how to fix them). The major changes to this patch are in the hardware controller and consist of wiring up the backend calls to generate the graphs on the hardware summary page, namely the calls to the database to generate the availability graphs and the calls to Mark's API to generate the history and snapshot graphs. Various other small interface and styling tweaks are also included. -Mo -------------- next part -------------- A non-text attachment was scrubbed... Name: graphs-backend-expir.patch Type: text/x-patch Size: 26520 bytes Desc: not available URL: From pmyers at redhat.com Wed May 28 01:18:37 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Tue, 27 May 2008 21:18:37 -0400 Subject: [Ovirt-devel] Questions about Xen support In-Reply-To: <1211804759.15391.93.camel@rollot.futurs.inria.fr> References: <1211804759.15391.93.camel@rollot.futurs.inria.fr> Message-ID: <483CB2ED.1010306@redhat.com> Pierre Inglebert wrote: > Hi ovirt, > > I'm working on the Xen support for oVirt, so first i wanna know if > anyone else is working on or is interrested to. Pierre, Thanks for writing. We haven't started implementing oVirt for Xen yet, but it is on our roadmap. We definitely want to be able to support a Xen host as a managed node in an oVirt network. > Thanks to libvirt, it is quite easy to make ovirt only work with Xen or > KVM but not with both because there are some hardcoded ?parts for KVM. > > This hardcoded parts are in task-omatic (especially in task_vm.rb), > libvirt uri connections as "qemu+tcp://" don't work with Xen, so i'm > trying to find a way to dynamicly modify this uri (e.g.change it to "xen > +tcp://" for xen). > > To do this, we have to know the hypervisor type before the connection, > we also have to know what type of VM we are creating in case of many > hypervisor types available and for the migration, the hosts need to have > the same hypervisor. I agree with the first part, but not necessarily the second. For the first part... What we should do is provide a way for a managed node to identify itself to the oVirt server. Right now when a Managed Node using KVM is booted it contacts the oVirt Server (using DNS SRV records) to tell it that it is alive. This mechanism could be extended to also provide other information to the oVirt Server like what type of Hypervisor the node is. (So instead of just a HELLO message it could be something like, "HELLO:KVM or HELLO:XEN") The daemon on the oVirt Server that is listening for the HELLO is called the ovirt-host-keyadd daemon. Darryl Pierce is going to be working with this daemon and the ovirt-host-browser daemon to merge their functionality (and get rid of the Avahi notification process) so it would be worthwhile to discuss this in depth with him. This identification is done presently in an init script on the managed node that is placed there by the node kickstart. This should really be moved to an RPM instead of being placed in a kickstart file, and it should be made a little more generic so that it can be used on either Xen or KVM hosts. Once we have the ability for a node to identify to the oVirt Server what kind of hypervisor it is running, then we need to be able to store that information in the database and it in the WUI. Then when taskomatic actions are requested it can use that information to determine the virsh url. The second part about not being able to move guests from one managed node to another is not so clear... Initially I agree that this should be the case, since disk image formats and configuration files will differ somewhat. We may want to simplify the initial support of multiple HV types by allowing hardware pools to only contain HVs of one type. i.e. if you have both Managed Nodes (KVM) and RHEL 5.1 hosts (XEN) you could not have both of these host types in the same hardware pool. They need to go in separate HW pools with like HV hosts. However, there is work going on in another project to provide tools to migrate guests from one HV to another. Once we have these tools linked in to oVirt, we should be able to run a guest on any HV that we support and remove the restriction that hardware pools need to contain nodes with the same HV type. > For me, there are 2 solutions. > The first solution is ?to allow an host to have more than one > hypervisor, these solutions require some changes : > - the VM will have an hypervisor type Agree with this, but eventually we'll allow this to be changed manually or even dynamically as the tools for guest HV migrations evolve. > - On the host, a list of available hypervisors (possibly dynamic?) What do you mean by host here? If host == Node (as in Managed Node) then there is not a choice. RHEL will only support Xen and the oVirt Managed Node will only support KVM. I suppose Fedora could support both, but this could be detected automatically on node boot (i.e. if you're in a Xen kernel say HELLO:XEN, if you detect hardware virt support and are not in a Xen kernel say HELLO:KVM to the oVirt server) > - For the user, we have to ask about hypervisor/arch on the VM creation > form (from the list of available hypervisors (dynamic listing will be > hard)) Agree. We should be able to list only hypervisors that are present in a given hardware pool (which for the initial implementation will be restricted by the fact that hardware pools have to be homogeneous) > - for the VM creation/migration task, we have to check if the Host is > compatible with the VM, Eventually, but for initial implementation this can be omitted. > - during the Host addition, we have to get all the hypervisor > capabilities. Agreed > > The second solution is to keep the restriction of one hypervisor by > Host. > We can seperate 2 cases : > - One Hypervisor by Host collection : > - Check the availability of the hypervisor during the Host addition. > - Move the Hypervisor Type to the Host collection (actually on Host) Don't know if this should be automatic. When a new node appears in the oVirt WUI it should be identified by what HV is running on it, and it should only be permitted to move to a HW pool containing like HVs. > > - One Hypervisor by Host (Multiple for Collection) : > - Ask user about the hypervisor to use during the Host addition > (possibility to choose it from a list) This isn't necessary since the host can tell you what HV it's using. One thing this brings up though... For Fedora since you can use either Xen or KVM, you could conceivably toggle he Node back and forth. If we decide to initially implement using homogeneous HW pools, we will have to automatically remove the Node from its assigned HW pool if it switches HV types... > - For the VM creation, ask the user about the hypervisor type from > the hypervisor list of the Host Collection. > - For migration, check available hosts in the Collection. > > So ?I wanna know what do you think about it. Good thoughts. If you want to start looking at creating patches to support Xen, it would probably make sense to start with the code on the Managed Node for identifying the node to the oVirt Server. This needs to be extracted from the kickstart, made into an RPM and then modified so that it identifies the HV type when it communicates to the server. We also want to eventually send information like hardware capabilities (dmidecode info, storage/network devices, processor flags, etc...) as well. So we need to give some thought to how we should package up that hardware information for transmission to the server. The HV type can be part of that information that is sent. There is other work being done right now on the hardware enumeration task, so I'd just focus on detecting the HV type and sending that data. We can merge in the additional hardware info later. Perry -- |=- Red Hat, Engineering, Emerging Technologies, Boston -=| |=- Email: pmyers at redhat.com -=| |=- Office: +1 412 474 3552 Mobile: +1 703 362 9622 -=| |=- GnuPG: E65E4F3D 88F9 F1C9 C2F3 1303 01FE 817C C5D2 8B91 E65E 4F3D -=| From sseago at redhat.com Tue May 27 17:33:03 2008 From: sseago at redhat.com (Scott Seago) Date: Tue, 27 May 2008 13:33:03 -0400 Subject: [Ovirt-devel] [PATCH] fixed a copy-and-paste bug in my last patch Message-ID: Signed-off-by: Scott Seago --- wui/src/app/controllers/vm_controller.rb | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/wui/src/app/controllers/vm_controller.rb b/wui/src/app/controllers/vm_controller.rb index 8e6d7f8..9bfd665 100644 --- a/wui/src/app/controllers/vm_controller.rb +++ b/wui/src/app/controllers/vm_controller.rb @@ -108,7 +108,8 @@ class VmController < ApplicationController vms.each do |vm| vm.destroy end - end render :json => { :object => "vm", :success => true, + end + render :json => { :object => "vm", :success => true, :alert => "Virtual Machines were successfully deleted." } rescue render :json => { :object => "vm", :success => false, -- 1.5.4.1 --------------090607030702060505040307-- From dpierce at redhat.com Wed May 28 10:27:40 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 28 May 2008 06:27:40 -0400 Subject: [Ovirt-devel] Still having issues with the wui appliance install Message-ID: <483D339C.1050005@redhat.com> I ran through it again and it's still not creating the ovirt database or role. After it finished the full installation and restarted, I watched it as it tried to bring up the ovirt system it complained that the postgres database was not initialized. When I got to a command prompt, went into Postgres and listed databases with \l I only saw postgres, template0 and template1 listed. -- Darryl L. Pierce, Sr. Software Engineer Red Hat, Inc. - http://www.redhat.com/ oVirt - Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" From apevec at redhat.com Wed May 28 16:16:49 2008 From: apevec at redhat.com (Alan Pevec) Date: Wed, 28 May 2008 18:16:49 +0200 Subject: [PATCH] wait for db to become ready - WAS Re: [Ovirt-devel] Still having issues with the wui appliance install In-Reply-To: <483D339C.1050005@redhat.com> References: <483D339C.1050005@redhat.com> Message-ID: <483D8571.3060802@redhat.com> Darryl L. Pierce wrote: > I ran through it again and it's still not creating the ovirt database or > role. After it finished the full installation and restarted, I watched > it as it tried to bring up the ovirt system it complained that the > postgres database was not initialized. When I got to a command prompt, > went into Postgres and listed databases with \l I only saw postgres, > template0 and template1 listed. This turned out to be a timing issue in ovirt-wui-install during first boot, postgres was not ready immediately after 'service postgres start' returned. PG initscript has optimistic sleep 2 after starting postmaster daemon but this wui VM was created w/o KVM support (VT was not enabled in BIOS) and running slooowly with qemu-system-x86_64 With KVM it's fast enough so this doesn't happen. Here's the patch which should fix this: wait until we can connect to the database or timeout diff --git a/wui/scripts/ovirt-wui-install b/wui/scripts/ovirt-wui-install index 8d95d48..3891604 100755 --- a/wui/scripts/ovirt-wui-install +++ b/wui/scripts/ovirt-wui-install @@ -135,6 +135,21 @@ echo "host all all 127.0.0.1 255.255.255.0 trust" >> /var/lib/pgsql/data/pg_hba. service postgresql stop > /dev/null 2>&1 service postgresql start [ $? != 0 ] && echo "Failed to start database" && exit 1 +declare -i timeout=10 +while [[ timeout -gt 0 ]] +do + sleep 2 + psql -l -U postgres > /dev/null 2>&1 + rc=$? + if [[ rc -eq 0 ]] + then + break + else + echo Database not ready yet, retrying... + fi + let timeout-- +done +[[ timeout -eq 0 ]] && echo "Failed to start database" && exit 1 if [ -z $PASSWD ]; then # generate random pg user password From pmyers at redhat.com Wed May 28 16:26:28 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Wed, 28 May 2008 12:26:28 -0400 Subject: [PATCH] wait for db to become ready - WAS Re: [Ovirt-devel] Still having issues with the wui appliance install In-Reply-To: <483D8571.3060802@redhat.com> References: <483D339C.1050005@redhat.com> <483D8571.3060802@redhat.com> Message-ID: <483D87B4.8050609@redhat.com> Alan Pevec wrote: > Darryl L. Pierce wrote: >> I ran through it again and it's still not creating the ovirt database >> or role. After it finished the full installation and restarted, I >> watched it as it tried to bring up the ovirt system it complained that >> the postgres database was not initialized. When I got to a command >> prompt, went into Postgres and listed databases with \l I only saw >> postgres, template0 and template1 listed. > > This turned out to be a timing issue in ovirt-wui-install during first > boot, postgres was not ready immediately after 'service postgres start' > returned. > PG initscript has optimistic sleep 2 after starting postmaster daemon > but this wui VM was created w/o KVM support (VT was not enabled in BIOS) > and running slooowly with qemu-system-x86_64 > With KVM it's fast enough so this doesn't happen. We really should print a warning if create-wui-appliance doesn't detect hardware virt support or if the qemu process is not launched with qemu-kvm. That way people will understand why things are so slow. Though... create-wui-appliance will need to be rewritten once we start using livecd creator from the ADK to generate the appliance and this will be moot. > Here's the patch which should fix this: wait until we can connect to the > database or timeout Looks ok to me. ACK. Perry > diff --git a/wui/scripts/ovirt-wui-install b/wui/scripts/ovirt-wui-install > index 8d95d48..3891604 100755 > --- a/wui/scripts/ovirt-wui-install > +++ b/wui/scripts/ovirt-wui-install > @@ -135,6 +135,21 @@ echo "host all all 127.0.0.1 255.255.255.0 trust" > >> /var/lib/pgsql/data/pg_hba. > service postgresql stop > /dev/null 2>&1 > service postgresql start > [ $? != 0 ] && echo "Failed to start database" && exit 1 > +declare -i timeout=10 +while [[ timeout -gt 0 ]] > +do > + sleep 2 > + psql -l -U postgres > /dev/null 2>&1 > + rc=$? > + if [[ rc -eq 0 ]] > + then > + break > + else > + echo Database not ready yet, retrying... > + fi > + let timeout-- > +done > +[[ timeout -eq 0 ]] && echo "Failed to start database" && exit 1 > > if [ -z $PASSWD ]; then > # generate random pg user password > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel -- |=- Red Hat, Engineering, Emerging Technologies, Boston -=| |=- Email: pmyers at redhat.com -=| |=- Office: +1 412 474 3552 Mobile: +1 703 362 9622 -=| |=- GnuPG: E65E4F3D 88F9 F1C9 C2F3 1303 01FE 817C C5D2 8B91 E65E 4F3D -=| From hbrock at redhat.com Wed May 28 19:46:14 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Wed, 28 May 2008 15:46:14 -0400 Subject: [Ovirt-devel] Re: [Patch] Experimental Graphs Backend Code In-Reply-To: <483C7BDC.3020206@redhat.com> References: <483C7BDC.3020206@redhat.com> Message-ID: <20080528194612.GB20260@redhat.com> On Tue, May 27, 2008 at 05:23:40PM -0400, Mohammed Morsi wrote: > This patch is for review only, and is not meant to be committed (partly > because I didn't update before generating it and partly because I know some > parts are wrong, but need feedback on how to fix them). The major changes > to this patch are in the hardware controller and consist of wiring up the > backend calls to generate the graphs on the hardware summary page, namely > the calls to the database to generate the availability graphs and the calls > to Mark's API to generate the history and snapshot graphs. Various other > small interface and styling tweaks are also included. Hi Mo, thanks for this. Responses in-line below. > diff --git a/wui/src/app/controllers/application.rb b/wui/src/app/controllers/application.rb > index 5f20be3..0123b3e 100644 > --- a/wui/src/app/controllers/application.rb > +++ b/wui/src/app/controllers/application.rb > @@ -31,11 +31,12 @@ class ApplicationController < ActionController::Base > before_filter :pre_edit, :only => [:edit, :update, :destroy] > before_filter :pre_show, :only => [:show, :show_vms, :show_users, > :show_hosts, :show_storage, > - :available_graph, :history_graph, :network_traffic_graph] > + :available_graph, :history_graph, :snapshot_graph] > before_filter :authorize_admin, :only => [:new, :create, :edit, :update, :destroy] > > def get_login_user > - user_from_principal(request.env["HTTP_X_FORWARDED_USER"]) > + #user_from_principal(request.env["HTTP_X_FORWARDED_USER"]) > + 'admin' Assume this ^^^ is unintentional... > end > > def user_from_principal(principal) > diff --git a/wui/src/app/controllers/hardware_controller.rb b/wui/src/app/controllers/hardware_controller.rb > index 25201d9..1afc3e1 100644 > --- a/wui/src/app/controllers/hardware_controller.rb > +++ b/wui/src/app/controllers/hardware_controller.rb > @@ -16,6 +16,8 @@ > # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, > # MA 02110-1301, USA. A copy of the GNU General Public License is > # also available at http://www.gnu.org/copyleft/gpl.html. > +# > +require 'util/stats/Stats' > > class HardwareController < ApplicationController > > @@ -98,72 +100,85 @@ class HardwareController < ApplicationController > > # retrieves data to be used by availablilty bar charts > def available_graph > + data_sets = [] > + color = 'blue' > + > target = params[:target] > - available = nil > - used = nil > - if target == 'memory' > - available = @available_memory > - used = @used_memory > - elsif target == 'storage' > - available = @available_storage > - used = @used_storage > + if target == 'cpu' > + if (@total[:cpu] > @used[:cpu]) > + # 3/4 is the critical boundry for now > + color = 'red' if (@used[:cpu].to_f / @total[:cpu].to_f) > 0.75 > + data_sets.push ({ :name => 'cpu_used', :values => [@used[:cpu]], > + :fill => color, :stroke => 'lightgray', :strokeWidth => 1 }, > + { :name => 'cpu_available', > + :values => [@available[:cpu]], :fill => 'white', > + :stroke => 'lightgray', :strokeWidth => 1}) > + else > + data_sets.push ({ :name => 'cpu_available', :values => [@available[:cpu]], > + :fill => 'white', :stroke => 'lightgray', :strokeWidth => 1 }, > + { :name => 'cpu_used', > + :values => [@used[:cpu]], :fill => 'red', > + :stroke => 'lightgray', :strokeWidth => 1}) > + end If I'm reading this right, this will flip the bar depending on whether vcpus are overcommitted relative to physical CPUs or not, yes? If so that's good. Also it's important to somewhere make the distinction that we are talking about integer values of CPUs, at least for the moment -- we can't meaningfully assign some percentage of 1 physical CPU (yet). > + elsif target == 'memory' > + if (@total[:memory] > @used[:memory]) > + color = 'red' if (@used[:memory].to_f / @total[:memory].to_f) > 0.75 > + data_sets.push ({ :name => 'memory_used', :values => [@used[:memory]], > + :fill => color, :stroke => 'lightgray', :strokeWidth => 1 }, > + { :name => 'memory_available', > + :values => [@available[:memory]], :fill => 'white', > + :stroke => 'lightgray', :strokeWidth => 1}) > + else > + data_sets.push ({ :name => 'memory_available', :values => [@available[:memory]], > + :fill => 'white', :stroke => 'lightgray', :strokeWidth => 1 }, > + { :name => 'memory_used', > + :values => [@used[:memory]], :fill => 'red', > + :stroke => 'lightgray', :strokeWidth => 1}) > + end > + Right now we *can't* overcommit RAM, so I don't know if we want the same logic for this graph as for the cpu graph. Also, I assume that memory_available is "the sum of all memory on all machines in the pool," where "memory used" is "the sum of all memory currently in use by active VMs?" (Scott, you can probably comment on this too I'm sure) > elsif target == 'vms' > - available = @available_vms > - used = @used_vms > + total_remaining = @total[:vms] - @used[:vms] - @available[:vms] > + data_sets.push({ :name => 'vms_used', :values => [@used[:vms]], > + :fill => 'blue', :stroke => 'lightgray', :strokeWidth => 1 }, > + { :name => 'vms_available', :values => [@available[:vms]], > + :fill => 'red', :stroke => 'lightgray', :strokeWidth => 1 }, > + { :name => 'vms_remaining', :values => [total_remaining], > + :fill => 'white', :stroke => 'lightgray', :strokeWidth => 1}) I think we realized the other day that there is only one useful number we can give about VMs in a hardware pool, which is "how many are currently running?" I'm not sure how to best express this. Do you suppose it would be useful to contrast the number of VMs currently running in the pool with the number of physical hosts currently in the pool? Or is that just a waste of time? Scott? > end > > - color = 'blue' > - color = 'red' if (used.to_f / (available + used).to_f) > 0.75 # 3/4 is the critical boundry for now > - > - graph_object = { > - :timepoints => [], > - :dataset => > - [ > - { > - :name => target + "used", > - :values => [used], > - :fill => color, > - :stroke => 'lightgray', > - :strokeWidth => 1 > - }, > - { > - :name => target + "available", > - :values => [available], > - :fill => 'white', > - :stroke => 'lightgray', > - :strokeWidth => 1 > - } > - ] > - } > - render :json => graph_object > + render :json => { :timepoints => [], :dataset => data_sets } > end > > # retrieves data used by history graphs > def history_graph > - today = DateTime.now > + target = params[:target] > + today = Time.now > + requestList = [ StatsRequest.new(@pool.id, target, 0, "used", today.to_i - 3600, 3600, 0), > + StatsRequest.new(@pool.id, target, 0, "peak", today.to_i - 3600, 3600, 0) ] > dates = [ Date::ABBR_MONTHNAMES[today.month] + ' ' + today.day.to_s ] > 1.upto(6){ |x| # TODO get # of days from wui > dte = today - x > dates.push ( Date::ABBR_MONTHNAMES[dte.month] + ' ' + dte.day.to_s ) > + requestList.push ( StatsRequest.new (@pool.id, target, 0, "used", dte.to_i - 3600, 3600, 0), > + StatsRequest.new (@pool.id, target, 0, "peak", dte.to_i - 3600, 3600, 0) ) > } > dates.reverse! # want in ascending order > - > - target = params[:target] > - peakvalues = nil > - avgvalues = nil > - if target == 'host_usage' > - peakvalues = [95.97, 91.80, 88.16, 86.64, 99.14, 75.14, 85.69] # TODO real values! > - avgvalues = [3.39, 2.83, 1.61, 0.00, 4.56, 1.23, 5.32] # TODO real values! > - elsif target == 'storage_usage' > - peakvalues = [11.12, 22.29, 99.12, 13.23, 54.32, 17.91, 50.1] # TODO real values! > - avgvalues = [19.23, 19.23, 19.23, 29.12, 68.96, 43.11, 0.1] # TODO real values! > - elsif target == 'vm_pool_usage_history' > - peakvalues = [42, 42, 42, 42, 42, 42, 42] # TODO real values! > - avgvalues = [0, 0, 0, 0, 0, 0, 0] # TODO real values! > - elsif target == 'overall_load' > - peakvalues = [19.68, 20.08, 19.84, 17.76, 0.0, 14.78, 9.71] # TODO real values! > - avgvalues = [0, 1, 2, 4, 8, 16, 32] # TODO real values! > - end > + requestList.reverse! > + > + statsList = getStatsData?( requestList ) > + statsList.each { |stat| > + devClass = stat.get_devClass? > + counter = stat.get_counter? > + value = stat.get_value?.to_i + 20 > + if devClass == target > + if counter == "used" > + @avg_history[:values].push value > + else > + #elsif counter == "peak" > + @peak_history[:values].push value > + end > + end > + } > > graph_object = { > :timepoints => dates, > @@ -171,14 +186,14 @@ class HardwareController < ApplicationController > [ > { > :name => target + "peak", > - :values => peakvalues, > - :stroke => @peak_color, > + :values => @peak_history[:values], > + :stroke => @peak_history[:color], > :strokeWidth => 1 > }, > { > :name => target + "average", > - :values => avgvalues, > - :stroke => @average_color, > + :values => @avg_history[:values], > + :stroke => @avg_history[:color], > :strokeWidth => 1 > } > ] > @@ -186,21 +201,25 @@ class HardwareController < ApplicationController > render :json => graph_object > end > > - def network_traffic_graph > + def snapshot_graph > target = params[:target] > - network_load = nil > - if target == 'in' > - network_load = @network_traffic['in'] > + snapshot = nil > + if target == 'overall_load' > + snapshot = @snapshots[:overall_load] > + elsif target == 'cpu' > + snapshot = @snapshots[:cpu] > + elsif target == 'in' > + snapshot = @snapshots[:in] > elsif target == 'out' > - network_load = @network_traffic['out'] > + snapshot = @snapshots[:out] > elsif target == 'io' > - network_load = @network_traffic['io'] > + snapshot = @snapshots[:io] > end This looks exactly like what we talked about -- understand you still need feedback from Mark regarding the right way to pull this info out. > - network_load_remaining = 1024 - network_load > + snapshot_remaining = 1024 - snapshot > > color = 'blue' > - color = 'red' if (network_load.to_f / 1024.to_f) > 0.75 # 3/4 is the critical boundry for now > + color = 'red' if (snapshot.to_f / 1024.to_f) > 0.75 # 3/4 is the critical boundry for now > > graph_object = { > :timepoints => [], > @@ -208,14 +227,14 @@ class HardwareController < ApplicationController > [ > { > :name => target, > - :values => [network_load], > + :values => [snapshot], > :fill => color, > :stroke => 'lightgray', > :strokeWidth => 1 > }, > { > :name => target + "remaining", > - :values => [network_load_remaining], > + :values => [snapshot_remaining], > :fill => 'white', > :stroke => 'lightgray', > :strokeWidth => 1 > @@ -395,23 +414,56 @@ class HardwareController < ApplicationController > @perm_obj = @pool > @current_pool_id=@pool.id > > - # TODO pull real values in > - @available_memory = 18 > - @used_memory = 62 > - > - @available_storage = 183 > - @used_storage = 61 > - > - @available_vms = 1 > - @used_vms = 26 > - > - @peak_color = 'red' > - @average_color = 'blue' > + # availability graphs - used > + @used = {:cpu => 0, :memory => 0, :vms => 0} > + @pool.sub_vm_resource_pools.each { |svrp| @used[:cpu] += svrp.allocated_resources[:current][:cpus] } > + @pool.sub_vm_resource_pools.each { |svrp| @used[:memory] += svrp.allocated_resources[:current][:memory] } > + @pool.sub_vm_resource_pools.each { |svrp| @used[:vms] += svrp.allocated_resources[:current][:vms] } > + > + # availability graphs - total > + @total = {:cpu => 0, :memory => 0, :vms => 0} > + @total[:cpu] = @pool.total_resources[:cpus] > + @total[:memory] = @pool.total_resources[:memory] > + @total[:vms] = @pool.total_resources[:vms] > + @total.each_key { |k| @total[k] = 0 if @total[k] == nil } > + > + # availability graphs - available > + @available = {} > + @available[:cpu] = (@total[:cpu] - @used[:cpu]).abs > + @available[:memory] = (@total[:memory] - @used[:memory]).abs > + @available[:vms] = 5 # TODO ? > + > + # history graphs > + @peak_history = { :color => 'red', :values => [] } > + @avg_history = { :color => 'blue', :values => [] } > + > + # snapshot graphs > + ret_time = Time.now.to_i - 3600 > + @snapshots = { :overall_load => 0, :cpu => 0, :in => 0, :out => 0, :io => 0 } > + requestList = [] > + requestList << StatsRequest.new(@pool.id, "system", 0, "used", ret_time, 3600, 0) > + requestList << StatsRequest.new(@pool.id, "cpu", 0, "used", ret_time, 3600, 0) > + requestList << StatsRequest.new(@pool.id, "in", 0, "used", ret_time, 3600, 0) > + requestList << StatsRequest.new(@pool.id, "out", 0, "used", ret_time, 3600, 0) > + requestList << StatsRequest.new(@pool.id, "io", 0, "used", ret_time, 3600, 0) > + statsList = getStatsData?( requestList ) > + statsList.each { |stat| > + devClass = stat.get_devClass? > + value = stat.get_value? > + if devClass == "system" > + @snapshots[:overall_load] = value > + elsif devClass == "cpu" > + @snapshots[:cpu] = value > + elsif devClass == "in" > + @snapshots[:in] = value > + elsif devClass == "out" > + @snapshots[:out] = value > + elsif devClass == "io" > + @snapshots[:io] = value > + end > + } > + #@snapshots = { :overall_load => 500, :cpu => 10, :in => 100, :out => 1024, :io => 200 } > This also looks correct. > - # TODO pull real values in > - @network_traffic = { 'in' => 100, 'out' => 1024, 'io' => 200 } > - @network_errors = { 'in' => 0, 'out' => 4, 'io' => 2 } > - @network_trends = { 'in' => 'up', 'out' => 'down', 'io' => 'check' } > end > def pre_json > pre_show > diff --git a/wui/src/app/views/hardware/show.html.erb b/wui/src/app/views/hardware/show.html.erb > index e524f97..f164ec5 100644 > --- a/wui/src/app/views/hardware/show.html.erb > +++ b/wui/src/app/views/hardware/show.html.erb > @@ -12,31 +12,32 @@ >
        >
        >
        > - <%= render :partial => '/layouts/graph', :locals => { :div_id => 'available_memory', :chartType => 'stackedColumn', :url => (url_for :controller => 'hardware', :action => 'available_graph', :target => 'memory' ) } %> > + <%= render :partial => '/layouts/graph', :locals => { :div_id => 'available_cpu', :chartType => 'stackedColumn', :url => (url_for :controller => 'hardware', :action => 'available_graph', :target => 'cpu' ) } %> >
        >
        > - Available: <%= @available_memory %>
        Used: <%= @used_memory %>
        <%= @available_memory + @used_memory %> GB of Memory
        > + Available: <%= @available[:cpu] %>
        Used: <%= @used[:cpu] %>
        <%= @total[:cpu] %> CPUs
        >
        >
        > >
        >
        > - <%= render :partial => '/layouts/graph', :locals => { :div_id => 'available_storage', :chartType => 'stackedColumn', :url => (url_for :controller => 'hardware', :action => 'available_graph', :target => 'storage') } %> > + <%= render :partial => '/layouts/graph', :locals => { :div_id => 'available_memory', :chartType => 'stackedColumn', :url => (url_for :controller => 'hardware', :action => 'available_graph', :target => 'memory') } %> >
        >
        > - Available: <%= @available_storage %>
        Used: <%= @used_storage %>
        <%= @available_storage + @used_storage %> GB of Storage
        > + Available: <%= @available[:memory] %>
        Used: <%= @used[:memory] %>
        <%= @total[:memory] %> GB of Memory
        >
        >
        > >
        >
        > - <%= render :partial => '/layouts/graph', :locals => { :div_id => 'available_vms', :chartType => 'stackedColumn', :url => (url_for :controller => 'hardware', :action => 'available_graph', :target => 'vms' ) } %> > + <%= render :partial => '/layouts/graph', :locals => { :div_id => 'available_vms', :chartType => 'stackedColumn', :url => (url_for :controller => 'hardware', :action => 'available_graph', :target => 'vms' ) } %> >
        >
        > - Available: <%= @available_vms %>
        Used: <%= @used_vms %>
        <%= @available_vms + @used_vms %> Virtual Machines
        > + Assigned: <%= @available[:vms] %>
        Active: <%= @used[:vms] %>
        <%= @total[:vms] %> Virtual Machines
        >
        >
        >
        > + >
        >
        >
        > @@ -49,10 +50,9 @@ > > >
        >
        > @@ -61,51 +61,56 @@ >
      >
      >
      > - Peak     > - Average     > + Peak     > + Average     >
      >
      >
      > -
      <%= render :partial => '/layouts/graph', :locals => { :div_id => 'host_usage_history', :chartType => 'line', :yGridLines => 'lightgrey', :url => (url_for :controller => 'hardware', :action => 'history_graph', :target => 'host_usage' ) } %>
      > -
      <%= render :partial => '/layouts/graph', :locals => { :div_id => 'storage_usage_history', :chartType => 'line', :yGridLines => 'lightgrey', :url => (url_for :controller => 'hardware', :action => 'history_graph', :target => 'storage_usage' ) } %>
      > -
      <%= render :partial => '/layouts/graph', :locals => { :div_id => 'vm_pool_usage_history', :chartType => 'line', :yGridLines => 'lightgrey', :url => (url_for :controller => 'hardware', :action => 'history_graph', :target => 'vm_pool_usage_history' ) } %>
      > -
      <%= render :partial => '/layouts/graph', :locals => { :div_id => 'overall_load_history', :chartType => 'line', :yGridLines => 'lightgrey', :url => (url_for :controller => 'hardware', :action => 'history_graph', :target => 'overall_load' ) } %>
      > +
      <%= render :partial => '/layouts/graph', :locals => { :div_id => 'cpu_history', :chartType => 'line', :yGridLines => 'lightgrey', :url => (url_for :controller => 'hardware', :action => 'history_graph', :target => 'cpu' ) } %>
      > +
      <%= render :partial => '/layouts/graph', :locals => { :div_id => 'io_history', :chartType => 'line', :yGridLines => 'lightgrey', :url => (url_for :controller => 'hardware', :action => 'history_graph', :target => 'io' ) } %>
      > +
      <%= render :partial => '/layouts/graph', :locals => { :div_id => 'overall_load_history', :chartType => 'line', :yGridLines => 'lightgrey', :url => (url_for :controller => 'hardware', :action => 'history_graph', :target => 'system' ) } %>
      >
      >
      > -
      > +
      > > > - > - > - > - > + > + > > > > + > + > + > + > + > + > + > + > > > - > - > > > > > - > - > > > > > - > - > +
      <%= @snapshots[:io] %> mb/s
      > + <%= render :partial => '/layouts/graph', :locals => { :div_id => 'io_snapshot', :chartType => 'stackedRow', :url => (url_for :controller => 'hardware', :action => 'snapshot_graph', :target => 'io' ) } %> > > >
      Network TrafficLoadErrorsTrendMetricLoad
      Overall Load > +
      <%= @snapshots[:overall_load] %>
      > + <%= render :partial => '/layouts/graph', :locals => { :div_id => 'overall_load_snapshot', :chartType => 'stackedRow', :url => (url_for :controller => 'hardware', :action => 'snapshot_graph', :target => 'overall_load' ) } %> > +
      CPU > +
      <%= @snapshots[:cpu] %>
      > + <%= render :partial => '/layouts/graph', :locals => { :div_id => 'cpu_snapshot', :chartType => 'stackedRow', :url => (url_for :controller => 'hardware', :action => 'snapshot_graph', :target => 'cpu' ) } %> > +
      Network In > -
      <%= @network_traffic['in'] %> mb/s
      > - <%= render :partial => '/layouts/graph', :locals => { :div_id => 'network_traffic_in', :chartType => 'stackedRow', :url => (url_for :controller => 'hardware', :action => 'network_traffic_graph', :target => 'in' ) } %> > +
      <%= @snapshots[:in] %> mb/s
      > + <%= render :partial => '/layouts/graph', :locals => { :div_id => 'net_in_snapshot', :chartType => 'stackedRow', :url => (url_for :controller => 'hardware', :action => 'snapshot_graph', :target => 'in' ) } %> >
      <%= @network_errors['in'] == 0 ? 'none' : (image_tag 'network_error.png') + '   ' + @network_errors['in'].to_s %><%= @network_trends['in'] == 'up' ? (image_tag 'network_trend_up.png') : (@network_trends['in'] == 'down' ? (image_tag 'network_trend_down.png') : (image_tag 'network_trend_check.png')) %>
      Network Out > -
      <%= @network_traffic['out'] %> mb/s
      > - <%= render :partial => '/layouts/graph', :locals => { :div_id => 'network_traffic_out', :chartType => 'stackedRow', :url => (url_for :controller => 'hardware', :action => 'network_traffic_graph', :target => 'out' ) } %> > +
      <%= @snapshots[:out] %> mb/s
      > + <%= render :partial => '/layouts/graph', :locals => { :div_id => 'net_out_snapshot', :chartType => 'stackedRow', :url => (url_for :controller => 'hardware', :action => 'snapshot_graph', :target => 'out' ) } %> >
      <%= @network_errors['out'] == 0 ? 'none' : (image_tag 'network_error.png') + '   ' + @network_errors['out'].to_s %><%= @network_trends['out'] == 'up' ? (image_tag 'network_trend_up.png') : (@network_trends['out'] == 'down' ? (image_tag 'network_trend_down.png') : (image_tag 'network_trend_check.png')) %>
      I/O > -
      <%= @network_traffic['io'] %> mb/s
      > - <%= render :partial => '/layouts/graph', :locals => { :div_id => 'network_traffic_io', :chartType => 'stackedRow', :url => (url_for :controller => 'hardware', :action => 'network_traffic_graph', :target => 'io' ) } %>
      <%= @network_errors['io'] == 0 ? 'none' : (image_tag 'network_error.png') + '   ' + @network_errors['io'].to_s %><%= @network_trends['io'] == 'up' ? (image_tag 'network_trend_up.png') : (@network_trends['io'] == 'down' ? (image_tag 'network_trend_down.png') : (image_tag 'network_trend_check.png')) %>
      > diff --git a/wui/src/public/stylesheets/components.css b/wui/src/public/stylesheets/components.css > index 0e9301b..9f6bb1d 100644 > --- a/wui/src/public/stylesheets/components.css > +++ b/wui/src/public/stylesheets/components.css > @@ -132,7 +132,7 @@ > .availability_graph { float: left; width: 33%;} > .availability_graph_left { float: left; width: 50px;} > .availability_graph_right { float: left; margin-top: 10%; margin-left: 125px; min-width: 100px;} > -#available_memory, #available_storage, #available_vms {margin-left:50px;width:100px;height:100px} > +#available_cpu, #available_memory, #available_vms {margin-left:50px;width:100px;height:100px} > > /* history graphs on hardware / resource summary tab */ > #history_graphs { height: 270px; overflow: hidden; margin-left: 40px; margin-top: 40px; } > @@ -184,20 +184,21 @@ > position: relative; > float: left; > } > -#host_usage_history, #storage_usage_history, #vm_pool_usage_history, #overall_load_history{ > +#cpu_history, #io_history, #overall_load_history{ > height: 200px; width: 1200px; position: absolute; left: -70px; > } > > > -/* network traffic graphs on hardware / resource summary tab */ > -#network_traffic_graphs { height: 150px; padding-left: 60px; } > -#network_traffic_graphs table { width: 90%; border-spacing: 0;} > -#network_traffic_graphs th { background: #CCCCCC; text-align: left; padding-left: 10px; border: 1px solid #DDDDDD;} > -#network_traffic_graphs td { padding-left: 10px; border: 1px solid #DDDDDD;} > -#network_traffic_in, #network_traffic_out, #network_traffic_io { > - width: 350px; height: 20px; float: right; > +/* snapshot graphs on hardware / resource summary tab */ > +#snapshot_graphs { height: 150px; padding-left: 60px; } > +#snapshot_graphs table { width: 90%; border-spacing: 0;} > +#snapshot_graphs th { background: #CCCCCC; text-align: left; padding-left: 10px; border: 1px solid #DDDDDD;} > +#snapshot_graphs td { padding-left: 10px; border: 1px solid #DDDDDD;} > +#overall_load_snapshot, #cpu_snapshot, #net_in_snapshot, #net_out_snapshot, #io_snapshot { > + width: 350px; height: 20px; float: left; > } > -.network_traffic_load_text { > +.snapshot_graph_text { > float: left; > padding-top: 3px; > + width: 100px; > } I'm anxious to see it in action, but subject to the comments above this looks like what we need. Take care, --Hugh From hbrock at redhat.com Wed May 28 20:22:34 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Wed, 28 May 2008 16:22:34 -0400 Subject: [Ovirt-devel] Re: [Patch] Experimental Graphs Backend Code In-Reply-To: <20080528194612.GB20260@redhat.com> References: <483C7BDC.3020206@redhat.com> <20080528194612.GB20260@redhat.com> Message-ID: <20080528202234.GA20641@redhat.com> On Wed, May 28, 2008 at 03:46:14PM -0400, Hugh O. Brock wrote: > On Tue, May 27, 2008 at 05:23:40PM -0400, Mohammed Morsi wrote: > > This patch is for review only, and is not meant to be committed (partly > > because I didn't update before generating it and partly because I know some > > parts are wrong, but need feedback on how to fix them). The major changes > > to this patch are in the hardware controller and consist of wiring up the > > backend calls to generate the graphs on the hardware summary page, namely > > the calls to the database to generate the availability graphs and the calls > > to Mark's API to generate the history and snapshot graphs. Various other > > small interface and styling tweaks are also included. > > > Right now we *can't* overcommit RAM, so I don't know if we want the > same logic for this graph as for the cpu graph. Also, I assume that > memory_available is "the sum of all memory on all machines in the > pool," where "memory used" is "the sum of all memory currently in use > by active VMs?" (Scott, you can probably comment on this too I'm sure) Correction: Dan and Brian tell me that KVM will actually overcommit RAM, so yeah, I guess we had best leave the "flippable" stacked bar in for RAM as well. --Hugh From mwagner at redhat.com Wed May 28 20:24:38 2008 From: mwagner at redhat.com (mark wagner) Date: Wed, 28 May 2008 16:24:38 -0400 Subject: [Ovirt-devel] Re: [Patch] Experimental Graphs Backend Code In-Reply-To: <20080528194612.GB20260@redhat.com> References: <483C7BDC.3020206@redhat.com> <20080528194612.GB20260@redhat.com> Message-ID: <483DBF86.7020404@redhat.com> Comments inline Hugh O. Brock wrote: >> # retrieves data used by history graphs >> def history_graph >> - today = DateTime.now >> + target = params[:target] >> + today = Time.now >> + requestList = [ StatsRequest.new(@pool.id, target, 0, "used", today.to_i - 3600, 3600, 0), >> + StatsRequest.new(@pool.id, target, 0, "peak", today.to_i - 3600, 3600, 0) ] >> dates = [ Date::ABBR_MONTHNAMES[today.month] + ' ' + today.day.to_s ] >> 1.upto(6){ |x| # TODO get # of days from wui >> dte = today - x >> dates.push ( Date::ABBR_MONTHNAMES[dte.month] + ' ' + dte.day.to_s ) >> + requestList.push ( StatsRequest.new (@pool.id, target, 0, "used", dte.to_i - 3600, 3600, 0), >> + StatsRequest.new (@pool.id, target, 0, "peak", dte.to_i - 3600, 3600, 0) ) >> Not sure what exactly you are trying to get in the above chunk of code. Doesn't look like its something gathered by collectd at this point in time. If you let me know what data it is, we can see about adding it to the collectd configuration. >> } >> dates.reverse! # want in ascending order >> - >> - target = params[:target] >> - peakvalues = nil >> - avgvalues = nil >> - if target == 'host_usage' >> - peakvalues = [95.97, 91.80, 88.16, 86.64, 99.14, 75.14, 85.69] # TODO real values! >> - avgvalues = [3.39, 2.83, 1.61, 0.00, 4.56, 1.23, 5.32] # TODO real values! >> - elsif target == 'storage_usage' >> - peakvalues = [11.12, 22.29, 99.12, 13.23, 54.32, 17.91, 50.1] # TODO real values! >> - avgvalues = [19.23, 19.23, 19.23, 29.12, 68.96, 43.11, 0.1] # TODO real values! >> - elsif target == 'vm_pool_usage_history' >> - peakvalues = [42, 42, 42, 42, 42, 42, 42] # TODO real values! >> - avgvalues = [0, 0, 0, 0, 0, 0, 0] # TODO real values! >> - elsif target == 'overall_load' >> - peakvalues = [19.68, 20.08, 19.84, 17.76, 0.0, 14.78, 9.71] # TODO real values! >> - avgvalues = [0, 1, 2, 4, 8, 16, 32] # TODO real values! >> - end >> + requestList.reverse! >> + >> + statsList = getStatsData?( requestList ) >> + statsList.each { |stat| >> + devClass = stat.get_devClass? >> + counter = stat.get_counter? >> + value = stat.get_value?.to_i + 20 >> + if devClass == target >> + if counter == "used" >> + @avg_history[:values].push value >> + else >> + #elsif counter == "peak" >> + @peak_history[:values].push value >> + end >> + end >> + } >> >> The interface is changing for retrieving data. I've created a StatsDataList object that will contain a lot of the "duplicate" info thats in the StatsData objects. This will allow the StatsData objects to be smaller. In addition, I will be passing back a list of lists. The API you currently have basically just passes back a big array of data objects that need to get parsed. With the list of StatsDataLists, you are guaranteed that each StatsDataList only contains the data for a unique counter (so this list only contains data for node3/cpu-0/cpu-idle). >> graph_object = { >> :timepoints => dates, >> @@ -171,14 +186,14 @@ class HardwareController < ApplicationController >> [ >> { >> :name => target + "peak", >> - :values => peakvalues, >> - :stroke => @peak_color, >> + :values => @peak_history[:values], >> + :stroke => @peak_history[:color], >> :strokeWidth => 1 >> }, >> { >> :name => target + "average", >> - :values => avgvalues, >> - :stroke => @average_color, >> + :values => @avg_history[:values], >> + :stroke => @avg_history[:color], >> :strokeWidth => 1 >> } >> ] >> We typically use rrd to provide the "average" values, we can also get min and max values. I'll look into adding calls for those >> @@ -186,21 +201,25 @@ class HardwareController < ApplicationController >> render :json => graph_object >> end >> >> - def network_traffic_graph >> + def snapshot_graph >> target = params[:target] >> - network_load = nil >> - if target == 'in' >> - network_load = @network_traffic['in'] >> + snapshot = nil >> + if target == 'overall_load' >> + snapshot = @snapshots[:overall_load] >> + elsif target == 'cpu' >> + snapshot = @snapshots[:cpu] >> + elsif target == 'in' >> + snapshot = @snapshots[:in] >> elsif target == 'out' >> - network_load = @network_traffic['out'] >> + snapshot = @snapshots[:out] >> elsif target == 'io' >> - network_load = @network_traffic['io'] >> + snapshot = @snapshots[:io] >> end >> I need to modify the collectd configs to include network and the others . > - > > This looks exactly like what we talked about -- understand you still > need feedback from Mark regarding the right way to pull this info out. > > > >> - network_load_remaining = 1024 - network_load >> + snapshot_remaining = 1024 - snapshot >> >> color = 'blue' >> - color = 'red' if (network_load.to_f / 1024.to_f) > 0.75 # 3/4 is the critical boundry for now >> + color = 'red' if (snapshot.to_f / 1024.to_f) > 0.75 # 3/4 is the critical boundry for now >> >> graph_object = { >> :timepoints => [], >> @@ -208,14 +227,14 @@ class HardwareController < ApplicationController >> [ >> { >> :name => target, >> - :values => [network_load], >> + :values => [snapshot], >> :fill => color, >> :stroke => 'lightgray', >> :strokeWidth => 1 >> }, >> { >> :name => target + "remaining", >> - :values => [network_load_remaining], >> + :values => [snapshot_remaining], >> :fill => 'white', >> :stroke => 'lightgray', >> :strokeWidth => 1 >> @@ -395,23 +414,56 @@ class HardwareController < ApplicationController >> @perm_obj = @pool >> @current_pool_id=@pool.id >> >> - # TODO pull real values in >> - @available_memory = 18 >> - @used_memory = 62 >> - >> - @available_storage = 183 >> - @used_storage = 61 >> - >> - @available_vms = 1 >> - @used_vms = 26 >> - >> - @peak_color = 'red' >> - @average_color = 'blue' >> + # availability graphs - used >> + @used = {:cpu => 0, :memory => 0, :vms => 0} >> + @pool.sub_vm_resource_pools.each { |svrp| @used[:cpu] += svrp.allocated_resources[:current][:cpus] } >> + @pool.sub_vm_resource_pools.each { |svrp| @used[:memory] += svrp.allocated_resources[:current][:memory] } >> + @pool.sub_vm_resource_pools.each { |svrp| @used[:vms] += svrp.allocated_resources[:current][:vms] } >> + >> + # availability graphs - total >> + @total = {:cpu => 0, :memory => 0, :vms => 0} >> + @total[:cpu] = @pool.total_resources[:cpus] >> + @total[:memory] = @pool.total_resources[:memory] >> + @total[:vms] = @pool.total_resources[:vms] >> + @total.each_key { |k| @total[k] = 0 if @total[k] == nil } >> + >> + # availability graphs - available >> + @available = {} >> + @available[:cpu] = (@total[:cpu] - @used[:cpu]).abs >> + @available[:memory] = (@total[:memory] - @used[:memory]).abs >> + @available[:vms] = 5 # TODO ? >> + >> + # history graphs >> + @peak_history = { :color => 'red', :values => [] } >> + @avg_history = { :color => 'blue', :values => [] } >> + >> + # snapshot graphs >> + ret_time = Time.now.to_i - 3600 >> + @snapshots = { :overall_load => 0, :cpu => 0, :in => 0, :out => 0, :io => 0 } >> + requestList = [] >> + requestList << StatsRequest.new(@pool.id, "system", 0, "used", ret_time, 3600, 0) >> + requestList << StatsRequest.new(@pool.id, "cpu", 0, "used", ret_time, 3600, 0) >> + requestList << StatsRequest.new(@pool.id, "in", 0, "used", ret_time, 3600, 0) >> + requestList << StatsRequest.new(@pool.id, "out", 0, "used", ret_time, 3600, 0) >> + requestList << StatsRequest.new(@pool.id, "io", 0, "used", ret_time, 3600, 0) >> these calls don't look right I am assuming that @pool.id returns the machine name. however "io", "in", "out" do not appear to be devClasses. -mark -------------- next part -------------- An HTML attachment was scrubbed... URL: From dpierce at redhat.com Wed May 28 21:10:48 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Wed, 28 May 2008 17:10:48 -0400 Subject: [Ovirt-devel] Status as of 28 May 2008 Message-ID: <483DCA58.6050408@redhat.com> - Sent in LDAP patch for grant_admin_privileges - Began working on replacing the avahi daemons -* Ruby host-browser that will accept HELLO from managed nodes and ensure keytabs are generated -* C-based daemon on the managed node to announce itself on startup - Struggled valiantly, with the help of apevec, to get my McCreary box working -* Lots of speedbumps, but finally got things going -- Darryl L. Pierce, Sr. Software Engineer Red Hat, Inc. - http://www.redhat.com/ oVirt - Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -------------- next part -------------- A non-text attachment was scrubbed... Name: dpierce.vcf Type: text/x-vcard Size: 298 bytes Desc: not available URL: From apevec at redhat.com Wed May 28 21:17:38 2008 From: apevec at redhat.com (Alan Pevec) Date: Wed, 28 May 2008 23:17:38 +0200 Subject: [Ovirt-devel] [PATCH] replace kadmin.local with ipa-* commands Message-ID: <483DCBF2.6030904@redhat.com> replace kadmin.local with ipa-* commands We should not use kadmin with IPA, see http://freeipa.org/page/IpaConcepts#How_IPA_and_Kerberos_Work_Together This change makes finally 'grant_admin_privileges ovirtadmin' work, since now we get user object created at expected prefix cn=users,cn=accounts 'grant_admin_privileges admin' is removed, admin is IPA system account and has nothing to do with oVirt diff --git a/wui-appliance/wui-devel-x86_64.ks b/wui-appliance/wui-devel-x86_64.ks index 1ab990f..173e448 100644 --- a/wui-appliance/wui-devel-x86_64.ks +++ b/wui-appliance/wui-devel-x86_64.ks @@ -30,7 +30,9 @@ for i in `seq 3 252` ; do echo "192.168.50.$i node$i.priv.ovirt.org" >> /etc/hosts done -principal=ovirtadmin at PRIV.OVIRT.ORG +principal=ovirtadmin +realm=PRIV.OVIRT.ORG +password=ovirt cron_file=/etc/cron.hourly/ovirtadmin.cron ktab_file=/usr/share/ovirt-wui/ovirtadmin.tab @@ -40,7 +42,7 @@ cat > $cron_file << EOF #!/bin/bash export PATH=/usr/kerberos/bin:$PATH kdestroy -kinit -k -t $ktab_file $principal +kinit -k -t $ktab_file $principal@$realm EOF chmod 755 $cron_file @@ -106,6 +108,8 @@ EOF first_run_file=/etc/init.d/ovirt-wui-dev-first-run sed -e "s, at cron_file@,$cron_file," \ -e "s, at principal@,$principal," \ + -e "s, at realm@,$realm," \ + -e "s, at password@,$password,g" \ -e "s, at ktab_file@,$ktab_file," \ > $first_run_file << \EOF #!/bin/bash @@ -119,18 +123,18 @@ sed -e "s, at cron_file@,$cron_file," \ # Source functions library . /etc/init.d/functions -KADMIN=/usr/kerberos/sbin/kadmin.local - start() { echo -n "Starting ovirt-dev-wui-first-run: " ( # set up freeipa - ipa-server-install -r PRIV.OVIRT.ORG -p ovirt -P ovirt -a ovirtwui \ + ipa-server-install -r PRIV.OVIRT.ORG -p @password@ -P @password@ -a @password@ \ --hostname management.priv.ovirt.org -u dirsrv -U # now create the ovirtadmin user - $KADMIN -q 'addprinc -randkey @principal@' - $KADMIN -q 'ktadd -k @ktab_file@ @principal@' + echo @password@|kinit admin + ipa-adduser -f Ovirt -l Admin -p @password@ @principal@ + ipa-moduser --setattr krbPasswordExpiration=19700101000000Z @principal@ + ipa-getkeytab -s management.priv.ovirt.org -p @principal@ -k @ktab_file@ @cron_file@ ) > /var/log/ovirt-wui-dev-first-run.log 2>&1 diff --git a/wui/scripts/ovirt-wui-install b/wui/scripts/ovirt-wui-install index 9cc3ac4..61da1b6 100755 --- a/wui/scripts/ovirt-wui-install +++ b/wui/scripts/ovirt-wui-install @@ -184,9 +184,6 @@ mkdir -p log rake db:migrate cd - -${OVIRT_DIR}/script/grant_admin_privileges admin -[ $? != 0 ] && echo "Failed to grant admin privileges" && exit 1 - if [ -f ${OVIRT_DIR}/ovirtadmin.tab ]; then ${OVIRT_DIR}/script/grant_admin_privileges ovirtadmin [ $? != 0 ] && echo "Failed to grant ovirtadmin privileges" && exit 1 @@ -199,6 +196,3 @@ for svc in $OVIRT_SVCS $ENABLE_SVCS; do done exit 0 - - - From sseago at redhat.com Wed May 28 21:39:24 2008 From: sseago at redhat.com (Scott Seago) Date: Wed, 28 May 2008 17:39:24 -0400 Subject: [Ovirt-devel] Re: [Patch] Experimental Graphs Backend Code In-Reply-To: <20080528194612.GB20260@redhat.com> References: <483C7BDC.3020206@redhat.com> <20080528194612.GB20260@redhat.com> Message-ID: <483DD10C.7070106@redhat.com> Hugh O. Brock wrote: > >> + elsif target == 'memory' >> + if (@total[:memory] > @used[:memory]) >> + color = 'red' if (@used[:memory].to_f / @total[:memory].to_f) > 0.75 >> + data_sets.push ({ :name => 'memory_used', :values => [@used[:memory]], >> + :fill => color, :stroke => 'lightgray', :strokeWidth => 1 }, >> + { :name => 'memory_available', >> + :values => [@available[:memory]], :fill => 'white', >> + :stroke => 'lightgray', :strokeWidth => 1}) >> + else >> + data_sets.push ({ :name => 'memory_available', :values => [@available[:memory]], >> + :fill => 'white', :stroke => 'lightgray', :strokeWidth => 1 }, >> + { :name => 'memory_used', >> + :values => [@used[:memory]], :fill => 'red', >> + :stroke => 'lightgray', :strokeWidth => 1}) >> + end >> + >> > > Right now we *can't* overcommit RAM, so I don't know if we want the > same logic for this graph as for the cpu graph. Also, I assume that > memory_available is "the sum of all memory on all machines in the > pool," where "memory used" is "the sum of all memory currently in use > by active VMs?" (Scott, you can probably comment on this too I'm sure) > > That's how I would interpret this. also, "active VMs" refers to all VMs that are either running or suspended. We don't care about stopped VMs. >> elsif target == 'vms' >> - available = @available_vms >> - used = @used_vms >> + total_remaining = @total[:vms] - @used[:vms] - @available[:vms] >> + data_sets.push({ :name => 'vms_used', :values => [@used[:vms]], >> + :fill => 'blue', :stroke => 'lightgray', :strokeWidth => 1 }, >> + { :name => 'vms_available', :values => [@available[:vms]], >> + :fill => 'red', :stroke => 'lightgray', :strokeWidth => 1 }, >> + { :name => 'vms_remaining', :values => [total_remaining], >> + :fill => 'white', :stroke => 'lightgray', :strokeWidth => 1}) >> > > I think we realized the other day that there is only one useful number > we can give about VMs in a hardware pool, which is "how many are > currently running?" I'm not sure how to best express this. > > Do you suppose it would be useful to contrast the number of VMs > currently running in the pool with the number of physical hosts > currently in the pool? Or is that just a waste of time? Scott? > > Not sure what metric is useful here. We've established that we don't care about quotas here -- if we want to discuss quotas, we need a separate area where we mention _all_ quota values (memory, disk, vms, etc.) -- especially, since, in the long run, those other params are more important to quotas than number of VMs. In addition, we don't care about how many non-running VMs a user has defined. Maybe we show vms-per-host, but that would vary based on host size as much as anything else, and it's still not appropriate for a percentage-type graph as the rest of these are. Maybe we move the VMs from this row entirely and show it somewhere else on the summary. Surely we have other parameters we're showing eventually that are in this same category (i.e. it's a single number, not a time series or a percentage, so a graph isn't really any more useful than just a plan number in a legible font) > > >> - network_load_remaining = 1024 - network_load >> + snapshot_remaining = 1024 - snapshot >> >> color = 'blue' >> - color = 'red' if (network_load.to_f / 1024.to_f) > 0.75 # 3/4 is the critical boundry for now >> + color = 'red' if (snapshot.to_f / 1024.to_f) > 0.75 # 3/4 is the critical boundry for now >> >> graph_object = { >> :timepoints => [], >> @@ -208,14 +227,14 @@ class HardwareController < ApplicationController >> [ >> { >> :name => target, >> - :values => [network_load], >> + :values => [snapshot], >> :fill => color, >> :stroke => 'lightgray', >> :strokeWidth => 1 >> }, >> { >> :name => target + "remaining", >> - :values => [network_load_remaining], >> + :values => [snapshot_remaining], >> :fill => 'white', >> :stroke => 'lightgray', >> :strokeWidth => 1 >> @@ -395,23 +414,56 @@ class HardwareController < ApplicationController >> @perm_obj = @pool >> @current_pool_id=@pool.id >> >> - # TODO pull real values in >> - @available_memory = 18 >> - @used_memory = 62 >> - >> - @available_storage = 183 >> - @used_storage = 61 >> - >> - @available_vms = 1 >> - @used_vms = 26 >> - >> - @peak_color = 'red' >> - @average_color = 'blue' >> + # availability graphs - used >> + @used = {:cpu => 0, :memory => 0, :vms => 0} >> + @pool.sub_vm_resource_pools.each { |svrp| @used[:cpu] += svrp.allocated_resources[:current][:cpus] } >> + @pool.sub_vm_resource_pools.each { |svrp| @used[:memory] += svrp.allocated_resources[:current][:memory] } >> + @pool.sub_vm_resource_pools.each { |svrp| @used[:vms] += svrp.allocated_resources[:current][:vms] } >> + >> + # availability graphs - total >> + @total = {:cpu => 0, :memory => 0, :vms => 0} >> + @total[:cpu] = @pool.total_resources[:cpus] >> + @total[:memory] = @pool.total_resources[:memory] >> + @total[:vms] = @pool.total_resources[:vms] >> + @total.each_key { |k| @total[k] = 0 if @total[k] == nil } >> + >> + # availability graphs - available >> + @available = {} >> + @available[:cpu] = (@total[:cpu] - @used[:cpu]).abs >> + @available[:memory] = (@total[:memory] - @used[:memory]).abs >> + @available[:vms] = 5 # TODO ? >> + >> @pool.total_resources refers to the default quota for the pool -- if you want total CPUs and Memory in the pool ,we need to define a new API to aggregate host stats. I think the latter is what you want here. Scott From pmyers at redhat.com Wed May 28 23:42:14 2008 From: pmyers at redhat.com (Perry N. Myers) Date: Wed, 28 May 2008 19:42:14 -0400 Subject: [Ovirt-devel] Status as of 28 May 2008 In-Reply-To: <483DCA58.6050408@redhat.com> References: <483DCA58.6050408@redhat.com> Message-ID: <483DEDD6.9050502@redhat.com> Darryl L. Pierce wrote: > - Sent in LDAP patch for grant_admin_privileges > - Began working on replacing the avahi daemons > -* Ruby host-browser that will accept HELLO from managed nodes and > ensure keytabs are generated > -* C-based daemon on the managed node to announce itself on startup This is good initially, but later this should be extended to send hardware configuration information to the oVirt server so the server knows about the node's capabilities. > - Struggled valiantly, with the help of apevec, to get my McCreary box > working > -* Lots of speedbumps, but finally got things going > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel -- |=- Red Hat, Engineering, Emerging Technologies, Boston -=| |=- Email: pmyers at redhat.com -=| |=- Office: +1 412 474 3552 Mobile: +1 703 362 9622 -=| |=- GnuPG: E65E4F3D 88F9 F1C9 C2F3 1303 01FE 817C C5D2 8B91 E65E 4F3D -=| From imain at redhat.com Thu May 29 00:32:31 2008 From: imain at redhat.com (Ian Main) Date: Wed, 28 May 2008 17:32:31 -0700 Subject: [Ovirt-devel] [PATCH] replace kadmin.local with ipa-* commands In-Reply-To: <483DCBF2.6030904@redhat.com> References: <483DCBF2.6030904@redhat.com> Message-ID: <20080528173231.5c7ba5e6@tp.mains.net> On Wed, 28 May 2008 23:17:38 +0200 Alan Pevec wrote: > replace kadmin.local with ipa-* commands > > We should not use kadmin with IPA, see http://freeipa.org/page/IpaConcepts#How_IPA_and_Kerberos_Work_Together > This change makes finally 'grant_admin_privileges ovirtadmin' work, since now we get user object created at expected prefix cn=users,cn=accounts > > 'grant_admin_privileges admin' is removed, admin is IPA system account and has nothing to do with oVirt Hey Alan, I ran this and in the log you see: The password for this file is in /etc/dirsrv/slapd-PRIV-OVIRT-ORG/pwdfile.txt /etc/rc3.d/S95ovirt-wui-dev-first-run: line 20: kinit: command not found Could not initialize GSSAPI: Unspecified GSS failure. Minor code may provide more information/No credentials cache found Could not initialize GSSAPI: ('Unspecified GSS failure. Minor code may provide more information', 851968)/('No credentials cache found', -1765328189) so I'll add the kerb bin dir to the path and try it again. Ian From imain at redhat.com Thu May 29 02:46:29 2008 From: imain at redhat.com (Ian Main) Date: Wed, 28 May 2008 19:46:29 -0700 Subject: [Ovirt-devel] [PATCH] replace kadmin.local with ipa-* commands In-Reply-To: <20080528173231.5c7ba5e6@tp.mains.net> References: <483DCBF2.6030904@redhat.com> <20080528173231.5c7ba5e6@tp.mains.net> Message-ID: <20080528194629.07fd4618@tp.mains.net> On Wed, 28 May 2008 17:32:31 -0700 Ian Main wrote: > On Wed, 28 May 2008 23:17:38 +0200 > Alan Pevec wrote: > > > replace kadmin.local with ipa-* commands > > > > We should not use kadmin with IPA, see http://freeipa.org/page/IpaConcepts#How_IPA_and_Kerberos_Work_Together > > This change makes finally 'grant_admin_privileges ovirtadmin' work, since now we get user object created at expected prefix cn=users,cn=accounts > > > > 'grant_admin_privileges admin' is removed, admin is IPA system account and has nothing to do with oVirt > > Hey Alan, I ran this and in the log you see: > > The password for this file is in /etc/dirsrv/slapd-PRIV-OVIRT-ORG/pwdfile.txt > /etc/rc3.d/S95ovirt-wui-dev-first-run: line 20: kinit: command not found > Could not initialize GSSAPI: Unspecified GSS failure. Minor code may provide more information/No credentials cache found > Could not initialize GSSAPI: ('Unspecified GSS failure. Minor code may provide more information', 851968)/('No credentials cache found', -1765328189) > > so I'll add the kerb bin dir to the path and try it again. Yeah, I just added: diff --git a/wui-appliance/wui-devel-x86_64.ks b/wui-appliance/wui-devel-x86_64.ks index 1ab990f..c34893c 100644 --- a/wui-appliance/wui-devel-x86_64.ks +++ b/wui-appliance/wui-devel-x86_64.ks @@ -119,18 +123,20 @@ sed -e "s, at cron_file@,$cron_file," \ # Source functions library . /etc/init.d/functions +export PATH=/usr/kerberos/bin:$PATH start() { And all seems good. So ACK with the path added. Ian From apevec at redhat.com Thu May 29 12:57:05 2008 From: apevec at redhat.com (Alan Pevec) Date: Thu, 29 May 2008 14:57:05 +0200 Subject: [Ovirt-devel] From: Alan Pevec Message-ID: <1212065825-11449-1-git-send-email-apevec@redhat.com> remove obsolete rubygem-kerberos and its references in ruby source Signed-off-by: Alan Pevec --- srpms/rubygem-kerberos-0.4-1.fc8.src.rpm | Bin 11611 -> 0 bytes wui/ovirt-wui.spec | 13 ++++++++----- wui/src/dutils/dutils.rb | 4 ++-- wui/src/host-keyadd/host-keyadd.rb | 6 ++---- 4 files changed, 12 insertions(+), 11 deletions(-) delete mode 100644 srpms/rubygem-kerberos-0.4-1.fc8.src.rpm diff --git a/srpms/rubygem-kerberos-0.4-1.fc8.src.rpm b/srpms/rubygem-kerberos-0.4-1.fc8.src.rpm deleted file mode 100644 index 3a302d53f0e3216c9b80b9abb4ad47e57a456fd9..0000000000000000000000000000000000000000 diff --git a/wui/ovirt-wui.spec b/wui/ovirt-wui.spec index ebf1d94..269b7de 100644 --- a/wui/ovirt-wui.spec +++ b/wui/ovirt-wui.spec @@ -1,7 +1,7 @@ %define pbuild %{_builddir}/%{name}-%{version} %define app_root %{_datadir}/%{name} -Summary: Ovirt front end WUI +Summary: oVirt front end WUI Name: ovirt-wui Source1: version Version: %(echo `awk '{ print $1 }' %{SOURCE1}`) @@ -17,7 +17,7 @@ Requires: ruby(abi) = 1.8 Requires: rubygem(activeldap) >= 0.10.0 Requires: rubygem(rails) >= 2.0.1 Requires: rubygem(mongrel) >= 1.0.1 -Requires: rubygem(kerberos) >= 0.4 +Requires: rubygem(krb5-auth) >= 0.6 Requires: ruby-gettext-package Requires: postgresql-server Requires: ruby-postgres @@ -38,11 +38,11 @@ BuildRequires: avahi-devel Provides: ovirt-wui BuildArch: i386 x86_64 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot -URL: http://ovirt.et.redhat.com +URL: http://ovirt.org/ %description -The webapp for Ovirt. +The webapp for oVirt. %prep %setup -q @@ -123,7 +123,7 @@ rm -rf $RPM_BUILD_ROOT %pre /usr/sbin/groupadd -r ovirt 2>/dev/null || : -/usr/sbin/useradd -g ovirt -c "Ovirt" \ +/usr/sbin/useradd -g ovirt -c "oVirt" \ -s /sbin/nologin -r -d /var/ovirt ovirt 2> /dev/null || : %post @@ -150,6 +150,9 @@ if [ "$1" = 0 ] ; then /sbin/chkconfig --del ovirt-taskomatic fi %changelog +* Thu May 29 2008 Alan Pevec - 0.0.5-0 +- use rubygem-krb5-auth + * Fri Nov 2 2007 - 0.0.1-1 - Initial build. diff --git a/wui/src/dutils/dutils.rb b/wui/src/dutils/dutils.rb index b1a1248..a90c068 100644 --- a/wui/src/dutils/dutils.rb +++ b/wui/src/dutils/dutils.rb @@ -17,8 +17,8 @@ # also available at http://www.gnu.org/copyleft/gpl.html. require 'active_record_env' -require 'kerberos' -include Kerberos +require 'krb5_auth' +include Krb5Auth ENV['KRB5CCNAME'] = '/usr/share/ovirt-wui/ovirt-cc' diff --git a/wui/src/host-keyadd/host-keyadd.rb b/wui/src/host-keyadd/host-keyadd.rb index e9b3450..d88abc9 100755 --- a/wui/src/host-keyadd/host-keyadd.rb +++ b/wui/src/host-keyadd/host-keyadd.rb @@ -20,8 +20,8 @@ require 'socket' require 'rubygems' -require 'kerberos' -include Kerberos +require 'krb5_auth' +include Krb5Auth require 'optparse' require 'daemons' include Daemonize @@ -29,8 +29,6 @@ include Daemonize $logfile = '/var/log/ovirt-wui/host-keyadd.log' def kadmin_local(command) - # FIXME: we really should implement the ruby-kerberos bindings to do the - # same thing as kadmin.local # FIXME: we should check the return value from the system() call and throw # an exception. # FIXME: we need to return the output back to the caller here -- 1.5.4.1 From clalance at redhat.com Thu May 29 13:01:43 2008 From: clalance at redhat.com (Chris Lalancette) Date: Thu, 29 May 2008 15:01:43 +0200 Subject: [Ovirt-devel] From: Alan Pevec In-Reply-To: <1212065825-11449-1-git-send-email-apevec@redhat.com> References: <1212065825-11449-1-git-send-email-apevec@redhat.com> Message-ID: <483EA937.90104@redhat.com> Alan Pevec wrote: > remove obsolete rubygem-kerberos and its references in ruby source > > Signed-off-by: Alan Pevec > --- > srpms/rubygem-kerberos-0.4-1.fc8.src.rpm | Bin 11611 -> 0 bytes > wui/ovirt-wui.spec | 13 ++++++++----- > wui/src/dutils/dutils.rb | 4 ++-- > wui/src/host-keyadd/host-keyadd.rb | 6 ++---- > 4 files changed, 12 insertions(+), 11 deletions(-) > delete mode 100644 srpms/rubygem-kerberos-0.4-1.fc8.src.rpm > OK. The package name has changed, but we are getting that from the dependencies for the ovirt-wui RPM, so this should also take care of wui-appliance kickstarts. ACK Chris Lalancette From dpierce at redhat.com Thu May 29 13:59:00 2008 From: dpierce at redhat.com (Darryl L. Pierce) Date: Thu, 29 May 2008 09:59:00 -0400 Subject: [Ovirt-devel] host-browser flow Message-ID: <483EB6A4.2090506@redhat.com> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 ~ 1. server comes up, starts the node collector. ~ 2. node collector begins listening on the appropriate port (per SRV). ~ 3. managed node comes up, determines the address/port for the WUI node collector. ~ 4. managed node gets its hardware information. ~ 5. managed node connects to the collector, says "HELLO" . ~ 6. collector sends "ACK". ~ 7. managed node sends hardware information. ~ 8. collector checks if a keytab is needed and generates one if necessary. ~ 9. if a keytab was created, collector responds with "TAB". 10. if a keytab wasn't created, collector responds with "RCVD". 11. managed node responds with "BYE". 12. if managed node recieved "TAB" then it downloads the keytab. - -- Darryl L. Pierce, Sr. Software Engineer Red Hat, Inc. - http://www.redhat.com/ oVirt - Virtual Machine Management - http://www.ovirt.org/ "What do you care what other people think, Mr. Feynman?" -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (GNU/Linux) Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org iD8DBQFIPrakjaT4DmxOfxsRAsUPAJ9pqniEX6GWF6nuFCktD8YZ9DcoNwCfV/b4 TnY9HIqL8lMJd8pzGw7L8UY= =MkXx -----END PGP SIGNATURE----- -------------- next part -------------- A non-text attachment was scrubbed... Name: dpierce.vcf Type: text/x-vcard Size: 298 bytes Desc: not available URL: From apevec at redhat.com Thu May 29 15:36:35 2008 From: apevec at redhat.com (Alan Pevec) Date: Thu, 29 May 2008 17:36:35 +0200 Subject: [Ovirt-devel] host-browser flow In-Reply-To: <483EB6A4.2090506@redhat.com> References: <483EB6A4.2090506@redhat.com> Message-ID: <483ECD83.30004@redhat.com> Darryl L. Pierce wrote: > ~ 1. server comes up, starts the node collector. > ~ 2. node collector begins listening on the appropriate port (per SRV). > ~ 3. managed node comes up, determines the address/port for the WUI node > collector. > ~ 4. managed node gets its hardware information. > ~ 5. managed node connects to the collector, says "HELLO" . > ~ 6. collector sends "ACK". > ~ 7. managed node sends hardware information. 7.5. node sends kvno from its cached ktab, 0 for "don't have ktab" > ~ 8. collector checks if a keytab is needed and generates one if necessary. > ~ 9. if a keytab was created, collector responds with "TAB". > 10. if a keytab wasn't created, collector responds with "RCVD". 8-10. collector checks: = resolve from incoming IP if not exists "libvirt/" principal add service principal "libvirt/" get kvno_from_kdc for "libvirt/" if kvno_from_kdc != kvno_from_node get keytab for "libvirt/" respond "TAB" else respond "BYE" > 11. managed node responds with "BYE". > 12. if managed node recieved "TAB" then it downloads the keytab. From mmorsi at redhat.com Thu May 29 16:17:22 2008 From: mmorsi at redhat.com (Mohammed Morsi) Date: Thu, 29 May 2008 12:17:22 -0400 Subject: [Ovirt-devel] Re: [Patch] Experimental Graphs Backend Code In-Reply-To: <483DBF86.7020404@redhat.com> References: <483C7BDC.3020206@redhat.com> <20080528194612.GB20260@redhat.com> <483DBF86.7020404@redhat.com> Message-ID: <483ED712.7080704@redhat.com> mark wagner wrote: > Comments inline > > Hugh O. Brock wrote: >>> # retrieves data used by history graphs >>> def history_graph >>> - today = DateTime.now >>> + target = params[:target] >>> + today = Time.now >>> + requestList = [ StatsRequest.new(@pool.id, target, 0, "used", today.to_i - 3600, 3600, 0), >>> + StatsRequest.new(@pool.id, target, 0, "peak", today.to_i - 3600, 3600, 0) ] >>> dates = [ Date::ABBR_MONTHNAMES[today.month] + ' ' + today.day.to_s ] >>> 1.upto(6){ |x| # TODO get # of days from wui >>> dte = today - x >>> dates.push ( Date::ABBR_MONTHNAMES[dte.month] + ' ' + dte.day.to_s ) >>> + requestList.push ( StatsRequest.new (@pool.id, target, 0, "used", dte.to_i - 3600, 3600, 0), >>> + StatsRequest.new (@pool.id, target, 0, "peak", dte.to_i - 3600, 3600, 0) ) >>> > Not sure what exactly you are trying to get in the above chunk of > code. Doesn't look like its something gathered by collectd at this > point in time. If you let me know what data it is, we can see about > adding it to the collectd configuration. So this is invoked via a callback when each history graph is being rendered. The history graphs are the line graphs on the 2nd row of the hardware pool summary page, each describing the 7 day history (at some point the time frame will be able to be set via the WUI) for the particular target the user selects to view. Here I am passing the following data into your StatsRequest API. * node - id of the pool the user is looking at * devClass - 'targets', get passed in from the WUI. oOne of the following string values: cpu, io, system (last is for 'overall load'). * instance - 0 (what should i set this to?) * counter - "used" and "peak" for the two data sets respectively * starttime / duration - i'm just looking for one day's worth of data. I loop through the past seven days, trying to collect the statistic for one particular day one each pass. It seems that I'm getting alot more data than I need back * precision - 0 as you mentioned in your email Are all (or any) of these right? >>> } >>> dates.reverse! # want in ascending order >>> - >>> - target = params[:target] >>> - peakvalues = nil >>> - avgvalues = nil >>> - if target == 'host_usage' >>> - peakvalues = [95.97, 91.80, 88.16, 86.64, 99.14, 75.14, 85.69] # TODO real values! >>> - avgvalues = [3.39, 2.83, 1.61, 0.00, 4.56, 1.23, 5.32] # TODO real values! >>> - elsif target == 'storage_usage' >>> - peakvalues = [11.12, 22.29, 99.12, 13.23, 54.32, 17.91, 50.1] # TODO real values! >>> - avgvalues = [19.23, 19.23, 19.23, 29.12, 68.96, 43.11, 0.1] # TODO real values! >>> - elsif target == 'vm_pool_usage_history' >>> - peakvalues = [42, 42, 42, 42, 42, 42, 42] # TODO real values! >>> - avgvalues = [0, 0, 0, 0, 0, 0, 0] # TODO real values! >>> - elsif target == 'overall_load' >>> - peakvalues = [19.68, 20.08, 19.84, 17.76, 0.0, 14.78, 9.71] # TODO real values! >>> - avgvalues = [0, 1, 2, 4, 8, 16, 32] # TODO real values! >>> - end >>> + requestList.reverse! >>> + >>> + statsList = getStatsData?( requestList ) >>> + statsList.each { |stat| >>> + devClass = stat.get_devClass? >>> + counter = stat.get_counter? >>> + value = stat.get_value?.to_i + 20 >>> + if devClass == target >>> + if counter == "used" >>> + @avg_history[:values].push value >>> + else >>> + #elsif counter == "peak" >>> + @peak_history[:values].push value >>> + end >>> + end >>> + } >>> >>> > The interface is changing for retrieving data. I've created a > StatsDataList object that will contain a lot of the "duplicate" info > thats in the StatsData objects. This will allow the StatsData objects > to be smaller. In addition, I will be passing back a list of lists. > The API you currently have basically just passes back a big array of > data objects that need to get parsed. With the list of > StatsDataLists, you are guaranteed that each StatsDataList only > contains the data for a unique counter (so this list only contains > data for node3/cpu-0/cpu-idle). > So when we have the new API, I will loop through the list in a manner like so? list1 = getStatsData?( requestList ) list1.each { |sublist| sublist.each{ |item| ... } } What specifically will be contained in each list. Eg. is list1 a list of unique devices containing a sublist of all unique counter values for that device? Also once again, I'm a fan of hashes in ruby, they allow you to do almost everything an array does, but it is alot easier for the client to lookup information. Perhaps we can create hashes indexed by device identifier / counter name or whatever else is appropriate. > >>> graph_object = { >>> :timepoints => dates, >>> @@ -171,14 +186,14 @@ class HardwareController < ApplicationController >>> [ >>> { >>> :name => target + "peak", >>> - :values => peakvalues, >>> - :stroke => @peak_color, >>> + :values => @peak_history[:values], >>> + :stroke => @peak_history[:color], >>> :strokeWidth => 1 >>> }, >>> { >>> :name => target + "average", >>> - :values => avgvalues, >>> - :stroke => @average_color, >>> + :values => @avg_history[:values], >>> + :stroke => @avg_history[:color], >>> :strokeWidth => 1 >>> } >>> ] >>> > > We typically use rrd to provide the "average" values, we can also get > min and max values. I'll look into adding calls for those How will these be referenced when I call them via your API. eg. is "average" equivalent to the "used" counter? What are the counters for "max" and "min" >>> @@ -186,21 +201,25 @@ class HardwareController < ApplicationController >>> render :json => graph_object >>> end >>> >>> - def network_traffic_graph >>> + def snapshot_graph >>> target = params[:target] >>> - network_load = nil >>> - if target == 'in' >>> - network_load = @network_traffic['in'] >>> + snapshot = nil >>> + if target == 'overall_load' >>> + snapshot = @snapshots[:overall_load] >>> + elsif target == 'cpu' >>> + snapshot = @snapshots[:cpu] >>> + elsif target == 'in' >>> + snapshot = @snapshots[:in] >>> elsif target == 'out' >>> - network_load = @network_traffic['out'] >>> + snapshot = @snapshots[:out] >>> elsif target == 'io' >>> - network_load = @network_traffic['io'] >>> + snapshot = @snapshots[:io] >>> end >>> > I need to modify the collectd configs to include network and the others . > >> - >> >> This looks exactly like what we talked about -- understand you still >> need feedback from Mark regarding the right way to pull this info out. >> >> >> >>> - network_load_remaining = 1024 - network_load >>> + snapshot_remaining = 1024 - snapshot >>> >>> color = 'blue' >>> - color = 'red' if (network_load.to_f / 1024.to_f) > 0.75 # 3/4 is the critical boundry for now >>> + color = 'red' if (snapshot.to_f / 1024.to_f) > 0.75 # 3/4 is the critical boundry for now >>> >>> graph_object = { >>> :timepoints => [], >>> @@ -208,14 +227,14 @@ class HardwareController < ApplicationController >>> [ >>> { >>> :name => target, >>> - :values => [network_load], >>> + :values => [snapshot], >>> :fill => color, >>> :stroke => 'lightgray', >>> :strokeWidth => 1 >>> }, >>> { >>> :name => target + "remaining", >>> - :values => [network_load_remaining], >>> + :values => [snapshot_remaining], >>> :fill => 'white', >>> :stroke => 'lightgray', >>> :strokeWidth => 1 >>> @@ -395,23 +414,56 @@ class HardwareController < ApplicationController >>> @perm_obj = @pool >>> @current_pool_id=@pool.id >>> >>> - # TODO pull real values in >>> - @available_memory = 18 >>> - @used_memory = 62 >>> - >>> - @available_storage = 183 >>> - @used_storage = 61 >>> - >>> - @available_vms = 1 >>> - @used_vms = 26 >>> - >>> - @peak_color = 'red' >>> - @average_color = 'blue' >>> + # availability graphs - used >>> + @used = {:cpu => 0, :memory => 0, :vms => 0} >>> + @pool.sub_vm_resource_pools.each { |svrp| @used[:cpu] += svrp.allocated_resources[:current][:cpus] } >>> + @pool.sub_vm_resource_pools.each { |svrp| @used[:memory] += svrp.allocated_resources[:current][:memory] } >>> + @pool.sub_vm_resource_pools.each { |svrp| @used[:vms] += svrp.allocated_resources[:current][:vms] } >>> + >>> + # availability graphs - total >>> + @total = {:cpu => 0, :memory => 0, :vms => 0} >>> + @total[:cpu] = @pool.total_resources[:cpus] >>> + @total[:memory] = @pool.total_resources[:memory] >>> + @total[:vms] = @pool.total_resources[:vms] >>> + @total.each_key { |k| @total[k] = 0 if @total[k] == nil } >>> + >>> + # availability graphs - available >>> + @available = {} >>> + @available[:cpu] = (@total[:cpu] - @used[:cpu]).abs >>> + @available[:memory] = (@total[:memory] - @used[:memory]).abs >>> + @available[:vms] = 5 # TODO ? >>> + >>> + # history graphs >>> + @peak_history = { :color => 'red', :values => [] } >>> + @avg_history = { :color => 'blue', :values => [] } >>> + >>> + # snapshot graphs >>> + ret_time = Time.now.to_i - 3600 >>> + @snapshots = { :overall_load => 0, :cpu => 0, :in => 0, :out => 0, :io => 0 } >>> + requestList = [] >>> + requestList << StatsRequest.new(@pool.id, "system", 0, "used", ret_time, 3600, 0) >>> + requestList << StatsRequest.new(@pool.id, "cpu", 0, "used", ret_time, 3600, 0) >>> + requestList << StatsRequest.new(@pool.id, "in", 0, "used", ret_time, 3600, 0) >>> + requestList << StatsRequest.new(@pool.id, "out", 0, "used", ret_time, 3600, 0) >>> + requestList << StatsRequest.new(@pool.id, "io", 0, "used", ret_time, 3600, 0) >>> > these calls don't look right I am assuming that @pool.id returns the > machine name. however "io", "in", "out" do not appear to be devClasses. Previous questions apply here. When invoking your API should I just pass in a set (configurable?) machine name? Should I use pool id for the instance id? "in" and "out" are the network device classes (i can change the names if needed) and "io" is for the i/o statistics / graphs. > > -mark -Mo -------------- next part -------------- An HTML attachment was scrubbed... URL: From mmorsi at redhat.com Thu May 29 16:53:02 2008 From: mmorsi at redhat.com (Mohammed Morsi) Date: Thu, 29 May 2008 12:53:02 -0400 Subject: [Ovirt-devel] Re: [Patch] Experimental Graphs Backend Code In-Reply-To: <483DD10C.7070106@redhat.com> References: <483C7BDC.3020206@redhat.com> <20080528194612.GB20260@redhat.com> <483DD10C.7070106@redhat.com> Message-ID: <483EDF6E.5090700@redhat.com> Scott Seago wrote: > Hugh O. Brock wrote: >> >>> + elsif target == 'memory' >>> + if (@total[:memory] > @used[:memory]) >>> + color = 'red' if (@used[:memory].to_f / >>> @total[:memory].to_f) > 0.75 >>> + data_sets.push ({ :name => 'memory_used', :values => >>> [@used[:memory]], >>> + :fill => color, :stroke => >>> 'lightgray', :strokeWidth => 1 }, >>> + { :name => 'memory_available', >>> + :values => [@available[:memory]], >>> :fill => 'white', >>> + :stroke => 'lightgray', >>> :strokeWidth => 1}) >>> + else >>> + data_sets.push ({ :name => 'memory_available', :values >>> => [@available[:memory]], >>> + :fill => 'white', :stroke => >>> 'lightgray', :strokeWidth => 1 }, >>> + { :name => 'memory_used', >>> + :values => [@used[:memory]], :fill >>> => 'red', >>> + :stroke => 'lightgray', >>> :strokeWidth => 1}) >>> + end >>> + >>> >> >> Right now we *can't* overcommit RAM, so I don't know if we want the >> same logic for this graph as for the cpu graph. Also, I assume that >> memory_available is "the sum of all memory on all machines in the >> pool," where "memory used" is "the sum of all memory currently in use >> by active VMs?" (Scott, you can probably comment on this too I'm sure) >> >> > That's how I would interpret this. also, "active VMs" refers to all > VMs that are either running or suspended. We don't care about stopped > VMs. So for memory (and cpu?) available, I take a hardware pool and: used = 0 @selected_pool.all_sub_vm_resource_pools { |pool| pool.vms.each { |vm| if (vm.state == running || vm.state == suspended) used += vm.memory_used // or num_vcpus_used } } correct? Also when you say "memory_available is "the sum of all memory on all machines in the pool,"". 1. By this definition it sounds like you mean "total memory". I've been using "available" as how much can be used at the given point, eg total = used + available 2. is the definition of machine == host? If so do "all machines" only encompass the hosts in the current pool? Or do they include all hosts in all subpools? I think the latter case would look like: total = 0 @selected_pool.hosts.each { |host| total += host.memory // or cpus } @selected_pool.all_sub_hardware_pools { |pool| pool.hosts.each { |host| total += host.memory // or cpus } } >>> elsif target == 'vms' >>> - available = @available_vms >>> - used = @used_vms >>> + total_remaining = @total[:vms] - @used[:vms] - >>> @available[:vms] >>> + data_sets.push({ :name => 'vms_used', :values => >>> [@used[:vms]], >>> + :fill => 'blue', :stroke => 'lightgray', >>> :strokeWidth => 1 }, >>> + { :name => 'vms_available', :values => >>> [@available[:vms]], >>> + :fill => 'red', :stroke => 'lightgray', >>> :strokeWidth => 1 }, >>> + { :name => 'vms_remaining', :values => >>> [total_remaining], >>> + :fill => 'white', :stroke => 'lightgray', >>> :strokeWidth => 1}) >>> >> >> I think we realized the other day that there is only one useful number >> we can give about VMs in a hardware pool, which is "how many are >> currently running?" I'm not sure how to best express this. >> Do you suppose it would be useful to contrast the number of VMs >> currently running in the pool with the number of physical hosts >> currently in the pool? Or is that just a waste of time? Scott? >> >> > Not sure what metric is useful here. We've established that we don't > care about quotas here -- if we want to discuss quotas, we need a > separate area where we mention _all_ quota values (memory, disk, vms, > etc.) -- especially, since, in the long run, those other params are > more important to quotas than number of VMs. > > In addition, we don't care about how many non-running VMs a user has > defined. Maybe we show vms-per-host, but that would vary based on host > size as much as anything else, and it's still not appropriate for a > percentage-type graph as the rest of these are. Maybe we move the VMs > from this row entirely and show it somewhere else on the summary. > Surely we have other parameters we're showing eventually that are in > this same category (i.e. it's a single number, not a time series or a > percentage, so a graph isn't really any more useful than just a plan > number in a legible font) It can be removed, or contrasted against any metric. I just need a final decision before I can proceed with it. If we want to leave it in, I say the simplest way is to contrast active against total. If the graph is a little skewed due to quotas so be it for now. >> >> >>> - network_load_remaining = 1024 - network_load >>> + snapshot_remaining = 1024 - snapshot >>> >>> color = 'blue' >>> - color = 'red' if (network_load.to_f / 1024.to_f) > 0.75 # 3/4 >>> is the critical boundry for now >>> + color = 'red' if (snapshot.to_f / 1024.to_f) > 0.75 # 3/4 is >>> the critical boundry for now >>> >>> graph_object = { >>> :timepoints => [], >>> @@ -208,14 +227,14 @@ class HardwareController < ApplicationController >>> [ >>> { >>> :name => target, >>> - :values => [network_load], >>> + :values => [snapshot], >>> :fill => color, >>> :stroke => 'lightgray', >>> :strokeWidth => 1 >>> }, >>> { >>> :name => target + "remaining", >>> - :values => [network_load_remaining], >>> + :values => [snapshot_remaining], >>> :fill => 'white', >>> :stroke => 'lightgray', >>> :strokeWidth => 1 >>> @@ -395,23 +414,56 @@ class HardwareController < ApplicationController >>> @perm_obj = @pool >>> @current_pool_id=@pool.id >>> >>> - # TODO pull real values in >>> - @available_memory = 18 >>> - @used_memory = 62 >>> - - @available_storage = 183 >>> - @used_storage = 61 >>> - >>> - @available_vms = 1 >>> - @used_vms = 26 >>> - >>> - @peak_color = 'red' >>> - @average_color = 'blue' >>> + # availability graphs - used >>> + @used = {:cpu => 0, :memory => 0, :vms => 0} >>> + @pool.sub_vm_resource_pools.each { |svrp| @used[:cpu] += >>> svrp.allocated_resources[:current][:cpus] } >>> + @pool.sub_vm_resource_pools.each { |svrp| @used[:memory] += >>> svrp.allocated_resources[:current][:memory] } >>> + @pool.sub_vm_resource_pools.each { |svrp| @used[:vms] += >>> svrp.allocated_resources[:current][:vms] } >>> + >>> + # availability graphs - total >>> + @total = {:cpu => 0, :memory => 0, :vms => 0} >>> + @total[:cpu] = @pool.total_resources[:cpus] >>> + @total[:memory] = @pool.total_resources[:memory] >>> + @total[:vms] = @pool.total_resources[:vms] >>> + @total.each_key { |k| @total[k] = 0 if @total[k] == nil } >>> + >>> + # availability graphs - available >>> + @available = {} >>> + @available[:cpu] = (@total[:cpu] - @used[:cpu]).abs >>> + @available[:memory] = (@total[:memory] - @used[:memory]).abs >>> + @available[:vms] = 5 # TODO ? >>> + >>> > @pool.total_resources refers to the default quota for the pool -- if > you want total CPUs and Memory in the pool ,we need to define a new > API to aggregate host stats. > I think the latter is what you want here. > > > Scott -Mo From jim at meyering.net Thu May 29 17:58:04 2008 From: jim at meyering.net (Jim Meyering) Date: Thu, 29 May 2008 19:58:04 +0200 Subject: [Ovirt-devel] [PATCH] Fix so libvirt does not start default network interface on developer/bundled In-Reply-To: <483BCF90.6070408@redhat.com> (Alan Pevec's message of "Tue, 27 May 2008 11:08:32 +0200") References: <1211566543-10584-1-git-send-email-pmyers@redhat.com> <20080523181954.GB12467@redhat.com> <483AB839.3020102@redhat.com> <483AC907.5050508@redhat.com> <483ADA71.6050700@redhat.com> <483B5D4A.70707@redhat.com> <483B6747.3080407@redhat.com> <483BCF90.6070408@redhat.com> Message-ID: <87iqwxouvn.fsf@rho.meyering.net> Alan Pevec wrote: >>> --disabled=iptables,yum-updatesd,libvirtd,bluetooth,cups,gpm,pcscd,NetworkManager,NetworkManagerDispatcher >>> --enabled=ntpd,httpd,postgresql,ovirt-wui,tgtd,nfs,collectd,network >>> +services >>> --disabled=libvirtd,postgresql,iptables,yum-updatesd,bluetooth,cups,gpm,pcscd,NetworkManager,NetworkManagerDispatcher >>> --enabled=network,tgtd,nfs >> >> Hmm. Why is --enabled reduced to just network, tgtd and nfs? What >> about ntpd, httpd, etc?? > They'll be enabled and started after they are configured in ovirt-wui-install > >>> -OVIRT_SVCS="ovirt-host-browser ovirt-host-status \ >>> - ovirt-taskomatic ovirt-host-keyadd ovirt-mongrel-rails" >>> -ENABLE_SVCS="ntpd httpd postgresql libvirtd" >>> +OVIRT_SVCS="ovirt-host-browser ovirt-host-keyadd ovirt-host-status \ >>> + ovirt-mongrel-rails ovirt-taskomatic" >> >> Did you reorder OVIRT_SVCS just to alphabetize it? :) > yeah, doesn't matter really, just looks better to my squared mind :) same here ;-) slightly more maintainable, too. If it's sorted, it's harder to accidentally insert a duplicate. Speaking of maintainability, I've come to prefer to make such lists one per line, if they get much longer (this is borderline). If you use single quotes rather than double quotes, the reader doesn't have to wonder if there's something like a $var or `cmd` reference hidden in the list of literals. With either type of quote, you can omit the trailing backslashes. OVIRT_SVCS=' ovirt-host-browser ovirt-host-keyadd ovirt-host-status ovirt-mongrel-rails ovirt-taskomatic ' From sseago at redhat.com Thu May 29 19:53:50 2008 From: sseago at redhat.com (Scott Seago) Date: Thu, 29 May 2008 15:53:50 -0400 Subject: [Ovirt-devel] Re: [Patch] Experimental Graphs Backend Code In-Reply-To: <483EDF6E.5090700@redhat.com> References: <483C7BDC.3020206@redhat.com> <20080528194612.GB20260@redhat.com> <483DD10C.7070106@redhat.com> <483EDF6E.5090700@redhat.com> Message-ID: <483F09CE.2090108@redhat.com> Mohammed Morsi wrote: > Scott Seago wrote: >> Hugh O. Brock wrote: >>> >>>> + elsif target == 'memory' >>>> + if (@total[:memory] > @used[:memory]) >>>> + color = 'red' if (@used[:memory].to_f / >>>> @total[:memory].to_f) > 0.75 >>>> + data_sets.push ({ :name => 'memory_used', :values => >>>> [@used[:memory]], >>>> + :fill => color, :stroke => >>>> 'lightgray', :strokeWidth => 1 }, >>>> + { :name => 'memory_available', >>>> + :values => [@available[:memory]], >>>> :fill => 'white', >>>> + :stroke => 'lightgray', >>>> :strokeWidth => 1}) >>>> + else >>>> + data_sets.push ({ :name => 'memory_available', :values >>>> => [@available[:memory]], >>>> + :fill => 'white', :stroke => >>>> 'lightgray', :strokeWidth => 1 }, >>>> + { :name => 'memory_used', >>>> + :values => [@used[:memory]], :fill >>>> => 'red', >>>> + :stroke => 'lightgray', >>>> :strokeWidth => 1}) >>>> + end >>>> + >>>> >>> >>> Right now we *can't* overcommit RAM, so I don't know if we want the >>> same logic for this graph as for the cpu graph. Also, I assume that >>> memory_available is "the sum of all memory on all machines in the >>> pool," where "memory used" is "the sum of all memory currently in use >>> by active VMs?" (Scott, you can probably comment on this too I'm sure) >>> >>> >> That's how I would interpret this. also, "active VMs" refers to all >> VMs that are either running or suspended. We don't care about stopped >> VMs. > > So for memory (and cpu?) available, I take a hardware pool and: > > used = 0 > @selected_pool.all_sub_vm_resource_pools { |pool| > pool.vms.each { |vm| > if (vm.state == running || vm.state == suspended) > used += vm.memory_used // or num_vcpus_used > } > } > > correct? > Yes, although for in-use resources, you can actually use VmResourcePool.allocated_resources, which essentially does the above. allocated_resources is "what's now in use", total_resources is "what's the quota" and available_resources is the difference between the two (with allowances for unlimited quota values). So for the HW page, what you really want is the sum of the allocated_resources values for the VM resource pools. > Also when you say "memory_available is "the sum of all memory on all > machines in the pool,"". > 1. By this definition it sounds like you mean "total memory". I've > been using "available" as how much can be used at the given point, eg > total = used + available That's right. I may have said it wrong before. With quotas, at least, we have total=allocated+available, where allocated==used for HW pools, it will be the same thing, but total will be based on hosts rather than VM pools. > 2. is the definition of machine == host? If so do "all machines" only > encompass the hosts in the current pool? Or do they include all hosts > in all subpools? I think the latter case would look like: > > total = 0 > @selected_pool.hosts.each { |host| > total += host.memory // or cpus > } > > @selected_pool.all_sub_hardware_pools { |pool| > pool.hosts.each { |host| > total += host.memory // or cpus > } > } > As I mentioned in IRC, we probably need both numbers. But the most important will be for just the current hardware pool. For one thing, if you traverse subpools for hosts, you've also got to traverse subpools for vm pools (and vms). And, from the point of view of managing load within a given HW pool, subpools don't matter a bit. Also, if you look at the definition of the hosts association in hardware pools.rb: has_many :hosts, :include => :nics, :dependent => :nullify, :order => "hosts.id ASC" do def total_cpus find(:all).inject(0){ |sum, host| sum + host.num_cpus } end end We already have a defintiion for total CPUs. just add another for memory. Then you can do @selected_pool.hosts.total_cpus and @selected_pool.hosts.memory. Scott From sseago at redhat.com Thu May 29 19:57:10 2008 From: sseago at redhat.com (Scott Seago) Date: Thu, 29 May 2008 15:57:10 -0400 Subject: [Ovirt-devel] [PATCH] refactored popups and grids to pull more into the layouts, Message-ID: <483F0A96.20108@redhat.com> From sseago at redhat.com Thu May 29 19:58:56 2008 From: sseago at redhat.com (Scott Seago) Date: Thu, 29 May 2008 15:58:56 -0400 Subject: [Ovirt-devel] [PATCH] refactored popups and grids to pull more into the layouts, In-Reply-To: <483F0A96.20108@redhat.com> References: <483F0A96.20108@redhat.com> Message-ID: <483F0B00.4090903@redhat.com> Scott Seago wrote: > > ------------------------------------------------------------------------ > > _______________________________________________ > Ovirt-devel mailing list > Ovirt-devel at redhat.com > https://www.redhat.com/mailman/listinfo/ovirt-devel -------------- next part -------------- A non-text attachment was scrubbed... Name: dialog-refactoring-1.patch Type: text/x-patch Size: 80056 bytes Desc: not available URL: From hbrock at redhat.com Thu May 29 21:05:42 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Thu, 29 May 2008 17:05:42 -0400 Subject: [Ovirt-devel] [PATCH] refactored popups and grids to pull more into the layouts, In-Reply-To: <483F0B00.4090903@redhat.com> References: <483F0A96.20108@redhat.com> <483F0B00.4090903@redhat.com> Message-ID: <20080529210540.GD20641@redhat.com> On Thu, May 29, 2008 at 03:58:56PM -0400, Scott Seago wrote: > Scott Seago wrote: >> >> ------------------------------------------------------------------------ >> >> _______________________________________________ >> Ovirt-devel mailing list >> Ovirt-devel at redhat.com >> https://www.redhat.com/mailman/listinfo/ovirt-devel > > >From 2351f8a85747668407463440c8c05c641788564b Mon Sep 17 00:00:00 2001 > From: Scott Seago > Date: Thu, 29 May 2008 15:54:19 -0400 > Subject: [PATCH] refactored popups and grids to pull more into the layouts, and static js functions into ovirt.js. > > Also, the children and all_children methods on Pool now accept find parameters. > > Signed-off-by: Scott Seago > --- > wui/src/app/controllers/application.rb | 24 +- > wui/src/app/controllers/hardware_controller.rb | 46 ++- > wui/src/app/controllers/host_controller.rb | 3 - > wui/src/app/controllers/storage_controller.rb | 2 +- > wui/src/app/models/pool.rb | 11 +- > wui/src/app/views/dashboard/index.html.erb | 50 -- > wui/src/app/views/hardware/move.rhtml | 13 +- > wui/src/app/views/hardware/new.html.erb | 38 +- > wui/src/app/views/hardware/show_hosts.rhtml | 1 + > wui/src/app/views/hardware/show_storage.rhtml | 1 + > wui/src/app/views/host/_grid.rhtml | 21 +- > wui/src/app/views/host/addhost.html.erb | 71 +-- > wui/src/app/views/layouts/popup.rhtml | 7 +- > wui/src/app/views/layouts/redux.rhtml | 64 +-- > wui/src/app/views/permission/new.rhtml | 26 +- > wui/src/app/views/resources/new.rhtml | 27 +- > wui/src/app/views/resources/show.rhtml | 78 --- > wui/src/app/views/storage/_grid.rhtml | 11 +- > wui/src/app/views/storage/addstorage.html.erb | 48 +- > wui/src/app/views/storage/new.rhtml | 42 +- > wui/src/app/views/vm/new.rhtml | 28 +- > wui/src/public/javascripts/ovirt.js | 138 +++++ > .../betternestedset/lib/#better_nested_set.rb# | 583 -------------------- > .../betternestedset/lib/better_nested_set.rb | 33 +- > 24 files changed, 350 insertions(+), 1016 deletions(-) > create mode 100644 wui/src/public/javascripts/ovirt.js > delete mode 100644 wui/src/vendor/plugins/betternestedset/lib/#better_nested_set.rb# > > diff --git a/wui/src/app/controllers/application.rb b/wui/src/app/controllers/application.rb > index 5f20be3..3ca5125 100644 > --- a/wui/src/app/controllers/application.rb > +++ b/wui/src/app/controllers/application.rb > @@ -84,18 +84,30 @@ class ApplicationController < ActionController::Base > end > end > end > - def json_list(full_items, attributes) > + > + # don't define find_opts for array inputs > + def json_list(full_items, attributes, arg_list=[], find_opts={}) > page = params[:page].to_i > - item_list = full_items.paginate(:page => page, > - :order => "#{params[:sortname]} #{params[:sortorder]}", > - :per_page => params[:rp]) > + paginate_opts = {:page => page, > + :order => "#{params[:sortname]} #{params[:sortorder]}", > + :per_page => params[:rp]} > + arg_list << find_opts.merge(paginate_opts) > + item_list = full_items.paginate(*arg_list) > json_hash = {} > json_hash[:page] = page > - json_hash[:total] = full_items.size > + json_hash[:total] = item_list.total_entries > json_hash[:rows] = item_list.collect do |item| > item_hash = {} > item_hash[:id] = item.id > - item_hash[:cell] = attributes.collect {|attr| item.send(attr)} > + item_hash[:cell] = attributes.collect do |attr| > + if attr.is_a? Array > + value = item > + attr.each { |attr_item| value = value.send(attr_item)} > + value > + else > + item.send(attr) > + end > + end > item_hash > end > render :json => json_hash.to_json > diff --git a/wui/src/app/controllers/hardware_controller.rb b/wui/src/app/controllers/hardware_controller.rb > index ad857f1..0f0c904 100644 > --- a/wui/src/app/controllers/hardware_controller.rb > +++ b/wui/src/app/controllers/hardware_controller.rb > @@ -229,17 +229,27 @@ class HardwareController < ApplicationController > if params[:id] > pre_json > hosts = @pool.hosts > + find_opts = {} > + include_pool = false > else > - # FIXME: no permissions checks here yet, no filtering of current pool yet > - hosts = Host.find(:all) > + # FIXME: no permissions or usage checks here yet > + # filtering on which pool to exclude > + id = params[:exclude_id] > + hosts = Host > + find_opts = {:include => :hardware_pool, > + :conditions => ["pools.id != ?", id]} > + include_pool = true > end > - json_list(hosts, > - [:id, :hostname, :uuid, :hypervisor_type, :num_cpus, :cpu_speed, :arch, :memory_in_mb, :is_disabled_str]) > + attr_list = [:id, :hostname, :uuid, :hypervisor_type, :num_cpus, :cpu_speed, :arch, :memory_in_mb, :is_disabled_str] > + attr_list.insert(2, [:hardware_pool, :name]) if include_pool > + json_list(hosts, attr_list, [:all], find_opts) > end > > def vm_pools_json > - json_list(@pool.sub_vm_resource_pools, > - [:id, :name]) > + json_list(Pool, > + [:id, :name], > + [@pool, :children], > + {:finder => 'call_finder', :conditions => ["type = 'VmResourcePool'"]}) > end > > def users_json > @@ -251,12 +261,20 @@ class HardwareController < ApplicationController > if params[:id] > pre_json > storage_pools = @pool.storage_pools > + find_opts = {} > + include_pool = false > else > - # FIXME: no permissions checks here yet, no filtering of current pool yet > - storage_pools = StoragePool.find(:all) > + # FIXME: no permissions or usage checks here yet > + # filtering on which pool to exclude > + id = params[:exclude_id] > + storage_pools = StoragePool > + find_opts = {:include => :hardware_pool, > + :conditions => ["pools.id != ?", id]} > + include_pool = true > end > - json_list(storage_pools, > - [:id, :display_name, :ip_addr, :get_type_label]) > + attr_list = [:id, :display_name, :ip_addr, :get_type_label] > + attr_list.insert(2, [:hardware_pool, :name]) if include_pool > + json_list(storage_pools, attr_list, [:all], find_opts) > end > > def storage_volumes_json > @@ -283,8 +301,10 @@ class HardwareController < ApplicationController > resource_ids = resource_ids_str.split(",").collect {|x| x.to_i} if resource_ids_str > begin > @pool.create_with_resources(@parent, resource_type, resource_ids) > - render :json => { :object => "pool", :success => true, > + reply = { :object => "pool", :success => true, > :alert => "Hardware Pool was successfully created." } > + reply[:resource_type] = resource_type if resource_type > + render :json => reply > rescue > render :json => { :object => "pool", :success => false, > :errors => @pool.errors.localize_error_messages.to_a } > @@ -308,7 +328,7 @@ class HardwareController < ApplicationController > # in addition to the current pool (which is checked). We also need to fail > # for hosts that aren't currently empty > def add_hosts > - host_ids_str = params[:host_ids] > + host_ids_str = params[:resource_ids] > host_ids = host_ids_str.split(",").collect {|x| x.to_i} > > begin > @@ -347,7 +367,7 @@ class HardwareController < ApplicationController > # in addition to the current pool (which is checked). We also need to fail > # for storage that aren't currently empty > def add_storage > - storage_pool_ids_str = params[:storage_pool_ids] > + storage_pool_ids_str = params[:resource_ids] > storage_pool_ids = storage_pool_ids_str.split(",").collect {|x| x.to_i} > > begin > diff --git a/wui/src/app/controllers/host_controller.rb b/wui/src/app/controllers/host_controller.rb > index f89997f..623cc0c 100644 > --- a/wui/src/app/controllers/host_controller.rb > +++ b/wui/src/app/controllers/host_controller.rb > @@ -58,9 +58,6 @@ class HostController < ApplicationController > > def addhost > @hardware_pool = Pool.find(params[:hardware_pool_id]) > - @unassigned = Pool.root.hosts.size > - # FIXME: @assigned should match the updated assigned hosts query when that's done > - @assigned = Host.find(:all).size > render :layout => 'popup' > end > > diff --git a/wui/src/app/controllers/storage_controller.rb b/wui/src/app/controllers/storage_controller.rb > index 1c5b392..c8831e6 100644 > --- a/wui/src/app/controllers/storage_controller.rb > +++ b/wui/src/app/controllers/storage_controller.rb > @@ -88,7 +88,7 @@ class StorageController < ApplicationController > > def new2 > @storage_pools = @storage_pool.hardware_pool.storage_volumes > - render :layout => 'popup' > + render :layout => false > end > > def insert_refresh_task > diff --git a/wui/src/app/models/pool.rb b/wui/src/app/models/pool.rb > index 490c5e6..5390beb 100644 > --- a/wui/src/app/models/pool.rb > +++ b/wui/src/app/models/pool.rb > @@ -69,10 +69,10 @@ class Pool < ActiveRecord::Base > end > > def sub_hardware_pools > - Pool.select_hardware_pools(children) > + children({:conditions => "type='HardwarePool'"}) > end > def sub_vm_resource_pools > - Pool.select_vm_pools(children) > + children({:conditions => "type='VmResourcePool'"}) > end > def self_and_like_siblings > self_and_siblings.select {|pool| pool[:type] == self.class.name} > @@ -156,7 +156,12 @@ class Pool < ActiveRecord::Base > hash > end > end > - > + > + def self.call_finder(*args) > + obj = args.shift > + method = args.shift > + obj.send(method, *args) > + end > > protected > def traverse_parents > diff --git a/wui/src/app/views/dashboard/index.html.erb b/wui/src/app/views/dashboard/index.html.erb > index 8715261..92cb4da 100644 > --- a/wui/src/app/views/dashboard/index.html.erb > +++ b/wui/src/app/views/dashboard/index.html.erb > @@ -1,57 +1,7 @@ > -
      > -
      > - > -
      > - > - <%= render :partial => "/layouts/quick_stats", :locals => { :hpool => @default_pool, :vms => @vms } %> > - > -
      > - > - <%= render :partial => "/layouts/hardware_pool_type_list", :locals => { :hardware_pools => @hardware_pools } %> > - > -
      > - > -
      > -
      Available Hosts (<%= @available_hosts.size %>)
      > -
      Statistics Data
      > -
      > -
      > - <%= render :partial => "/host/list", :locals => { :hosts => @available_hosts } %> > -
      > -
      > -
      > - > -
      > -
      Available Storage (<%= @available_storage_volumes.size %>)
      > -
      Storage Pools (<%= @storage_pools.size %>)
      > -
      Statistics Data
      > -
      > -
      > - <%= render :partial => "/storage/list_volumes", :locals => { :storage_volumes => @available_storage_volumes } %> > -
      > -
      > -
      > - > -
      > - > -
      > -
      > - > - > > -
       
      >
      > >

      Actions

      > - <%if @can_modify -%> > -
      > - > - <%= link_to 'Create New Pool', { :controller => "hardware", :action => 'new', :parent_id => @default_pool}, { :class => "create" } %> > -
      > - <% end -%> > >
      >
      <%= link_to_if @can_set_perms, 'User Permissions', { :controller => 'permission', :action => 'new', :pool_id => @default_pool }, { :class => "edit" } %>
      > diff --git a/wui/src/app/views/hardware/move.rhtml b/wui/src/app/views/hardware/move.rhtml > index 190fc03..f5824c6 100644 > --- a/wui/src/app/views/hardware/move.rhtml > +++ b/wui/src/app/views/hardware/move.rhtml > @@ -1,3 +1,10 @@ > +<%- content_for :title do -%> > + Move <%= @resource_type.capitalize %> > +<%- end -%> > +<%- content_for :description do -%> > + Select an existing hardware pool or create a new pool for selected <%= @resource_type %>. > +<%- end -%> > + > > > -
      > > -
      > -
      Move <%= @resource_type.capitalize %>
      > -
      Select an existing hardware pool or create a new pool for selected <%= @resource_type %>.
      > -
      > >
      >
        > @@ -63,4 +65,3 @@ $('#move_to_new_pool').click(function(){ >
        >
        >
        > -
        > diff --git a/wui/src/app/views/hardware/new.html.erb b/wui/src/app/views/hardware/new.html.erb > index a533871..f594009 100644 > --- a/wui/src/app/views/hardware/new.html.erb > +++ b/wui/src/app/views/hardware/new.html.erb > @@ -1,40 +1,30 @@ > -
        > -
        Add New Hardware Pool
        > -
        Add a new Hardware Pool to the <%= @parent.name %> pool. > - <%= "Checked #{@resource_type} will be added to the new pool." if @resource_type %> > -
        > -
        > +<%- content_for :title do -%> > + <%= _("Add New Hardware Pool") %> > +<%- end -%> > +<%- content_for :description do -%> > + Add a new Hardware Pool to the <%= @parent.name %> pool. > + <%= "Checked #{@resource_type} will be added to the new pool." if @resource_type %> > +<%- end -%> > >
        > -
        > - <%= render :partial => 'form' %> > -
        > -<%= popup_footer("$('#pool_form').submit()", "Create Hardware Pool") %> > +
        > + <%= render :partial => 'form' %> > +
        > + <%= popup_footer("$('#pool_form').submit()", "Create Hardware Pool") %> >
        > - > > -<%- content_for :title do -%> > -<%= _("New Hardware Pool") %> > -<%- end -%> > > > diff --git a/wui/src/app/views/hardware/show_hosts.rhtml b/wui/src/app/views/hardware/show_hosts.rhtml > index ae0e8af..bcbc2b8 100644 > --- a/wui/src/app/views/hardware/show_hosts.rhtml > +++ b/wui/src/app/views/hardware/show_hosts.rhtml > @@ -51,6 +51,7 @@ >
        > <%= render :partial => "/host/grid", :locals => { :table_id => "hosts_grid", > :hwpool_id => @pool.id, > + :exclude_id => nil, > :on_select => "hosts_select" } %> >
        >
        > diff --git a/wui/src/app/views/hardware/show_storage.rhtml b/wui/src/app/views/hardware/show_storage.rhtml > index 3d547db..f0b14bc 100644 > --- a/wui/src/app/views/hardware/show_storage.rhtml > +++ b/wui/src/app/views/hardware/show_storage.rhtml > @@ -68,6 +68,7 @@ >
        > <%= render :partial => "/storage/grid", :locals => { :table_id => "storage_grid", > :hwpool_id => @pool.id, > + :exclude_id => nil, > :on_select => "storage_select" } %> >
        > > diff --git a/wui/src/app/views/host/_grid.rhtml b/wui/src/app/views/host/_grid.rhtml > index 338bc78..25bdfd7 100644 > --- a/wui/src/app/views/host/_grid.rhtml > +++ b/wui/src/app/views/host/_grid.rhtml > @@ -7,18 +7,19 @@ > $("#<%= table_id %>").flexigrid > ( > { > - url: '<%= url_for :controller => "hardware", :action => "hosts_json", :id => hwpool_id %>', > + url: '<%= url_for :controller => "hardware", :action => "hosts_json", :id => hwpool_id, :exclude_id => exclude_id %>', > dataType: 'json', > colModel : [ > - {display: '', name : 'id', width : 20, sortable : false, align: 'left', process: <%= table_id %>checkbox}, > - {display: 'Hostname', name : 'hostname', width : 60, sortable : true, align: 'left'}, > - {display: 'UUID', name : 'uuid', width : 180, sortable : true, align: 'left'}, > - {display: 'Hypervisor Type', name : 'hypervisor_type', width : 80, sortable : true, align: 'left'}, > - {display: 'CPUs', name : 'num_cpus', width : 40, sortable : true, align: 'left'}, > - {display: 'Speed (MHz)', name : 'cpu_speed', width : 60, sortable : true, align: 'right'}, > - {display: 'Arch', name : 'arch', width : 50, sortable : true, align: 'right'}, > - {display: 'RAM (MB)', name : 'memory', width : 60, sortable : true, align: 'right'}, > - {display: 'Disabled', name : 'is_disabled', width : 50, sortable : true, align: 'right'} > + {display: '', width : 20, align: 'left', process: <%= table_id %>checkbox}, > + {display: 'Hostname', name : 'hostname', width : 60, align: 'left'}, > + <%= "{display: 'Hardware Pool', name : 'pools.name', width : 100, align: 'left'}," if exclude_id %> > + {display: 'UUID', name : 'uuid', width : 180, align: 'left'}, > + {display: 'Hypervisor Type', name : 'hypervisor_type', width : 80, align: 'left'}, > + {display: 'CPUs', name : 'num_cpus', width : 40, align: 'left'}, > + {display: 'Speed (MHz)', name : 'cpu_speed', width : 60, align: 'right'}, > + {display: 'Arch', name : 'arch', width : 50, align: 'right'}, > + {display: 'RAM (MB)', name : 'memory', width : 60, align: 'right'}, > + {display: 'Disabled', name : 'is_disabled', width : 50, align: 'right'} > ], > sortname: "hostname", > sortorder: "asc", > diff --git a/wui/src/app/views/host/addhost.html.erb b/wui/src/app/views/host/addhost.html.erb > index 69e0e66..bc3c797 100644 > --- a/wui/src/app/views/host/addhost.html.erb > +++ b/wui/src/app/views/host/addhost.html.erb > @@ -1,55 +1,18 @@ > -
        > -
        Add Host
        > -
        Select hosts from the list below to add to the <%= @hardware_pool.name %> hardware pool. Learn how to manage hosts
        > +<%- content_for :title do -%> > + <%= _("Add Host") %> > +<%- end -%> > +<%- content_for :description do -%> > + Select hosts from the list below to add to the <%= @hardware_pool.name %> hardware pool. Learn how to manage hosts > +<%- end -%> > + > +
        > +
        > + <%= render :partial => "/host/grid", :locals => { :table_id => "addhosts_grid", > + :hwpool_id => nil, :exclude_id => @hardware_pool.id, > + :on_select => "false" } %> >
        > - > - > -
        > -
        > - <%= render :partial => "/host/grid", :locals => { :table_id => "addhosts_unassigned_grid", > - :hwpool_id => Pool.root.id, :on_select => "false" } %> > - <%= render :partial => "/host/grid", :locals => { :table_id => "addhosts_assigned_grid", > - :hwpool_id => nil, :on_select => "false" } %> > -
        > -
        > - > -<%= popup_footer("add_hosts()", "Add Hosts") %> > + > +<%= popup_footer("add_hosts('#{url_for :controller => "hardware", > + :action => "add_hosts", > + :id => @hardware_pool}')", > + "Add Hosts") %> > diff --git a/wui/src/app/views/layouts/popup.rhtml b/wui/src/app/views/layouts/popup.rhtml > index 736517c..55dda58 100644 > --- a/wui/src/app/views/layouts/popup.rhtml > +++ b/wui/src/app/views/layouts/popup.rhtml > @@ -1,2 +1,7 @@ > -<%# currently nothing for popups here. %> > +
        > +
        > +
        <%= yield :title -%>
        > +
        <%= yield :description -%>
        > +
        > <%= yield %> > +
        > diff --git a/wui/src/app/views/layouts/redux.rhtml b/wui/src/app/views/layouts/redux.rhtml > index 72a49f8..63a9a56 100644 > --- a/wui/src/app/views/layouts/redux.rhtml > +++ b/wui/src/app/views/layouts/redux.rhtml > @@ -27,6 +27,9 @@ > <%= javascript_include_tag "ui.slider.js" -%> > <%= javascript_include_tag "jquery.cookie.js" -%> > <%= javascript_include_tag "jquery.form.js" -%> > + > + > -
        > - > -
        > -
        VM Resource Pool Quota
        > -
        Statistics Data
        > -
        > -
        > - > - > - > - > - > - > - <% resources = @vm_resource_pool.full_resources %> > - <% for item in resources[:labels] %> > - <% total_limit = resources[:total][item[1]] > - total_limit = "unlimited" if total_limit.nil? %> > - > - > - > - > - <% end %> > -
        in use / awaiting use / total allowed
        <%= item[0]%>:<%= resources[:allocated][:current][item[1]] %> / <%= resources[:allocated][:pending][item[1]] %> / <%= total_limit %> > - <%= item[2]%>
        > - > -
        > -
        > -
        > - > - > -
        > - > -
        > -
        > - > - > >
         
        >
        >

        Actions

        > > - <%if @can_modify -%> > -
        > - <%= link_to_if @vm_resource_pool, 'Create New VM', {:controller => "vm", :action => 'new', :vm_resource_pool_id => @vm_resource_pool}, { :class => "create" } %> > -
        > - <% end -%> >
        > <%if @is_hwpool_admin -%> > <%= link_to 'Edit VM Resource Pool', { :action => 'edit', :id => @vm_resource_pool }, { :class => "edit" } %> > diff --git a/wui/src/app/views/storage/_grid.rhtml b/wui/src/app/views/storage/_grid.rhtml > index 56fb621..feb855a 100644 > --- a/wui/src/app/views/storage/_grid.rhtml > +++ b/wui/src/app/views/storage/_grid.rhtml > @@ -7,13 +7,14 @@ > $("#<%= table_id %>").flexigrid > ( > { > - url: '<%= url_for :controller => "hardware", :action => "storage_pools_json", :id => hwpool_id %>', > + url: '<%= url_for :controller => "hardware", :action => "storage_pools_json", :id => hwpool_id, :exclude_id => exclude_id %>', > dataType: 'json', > colModel : [ > - {display: '', name : 'id', width : 20, sortable : false, align: 'left', process: <%= table_id %>checkbox}, > - {display: 'Alias', name : 'display_name', width : 180, sortable : false, align: 'left'}, > - {display: 'IP', name : 'ip_addr', width : 80, sortable : true, align: 'left'}, > - {display: 'Type', name : 'type', width : 80, sortable : true, align: 'left'} > + {display: '', width : 20, align: 'left', process: <%= table_id %>checkbox}, > + {display: 'Alias', width : 180, align: 'left'}, > + <%= "{display: 'Hardware Pool', name : 'pools.name', width : 100, align: 'left'}," if exclude_id %> > + {display: 'IP', name : 'ip_addr', width : 80, align: 'left'}, > + {display: 'Type', name : 'storage_pools.type', width : 80, align: 'left'} > ], > sortname: "ip_addr", > sortorder: "asc", > diff --git a/wui/src/app/views/storage/addstorage.html.erb b/wui/src/app/views/storage/addstorage.html.erb > index a747502..e465d12 100644 > --- a/wui/src/app/views/storage/addstorage.html.erb > +++ b/wui/src/app/views/storage/addstorage.html.erb > @@ -1,14 +1,17 @@ > -
        > -
        Add Storage
        > -
        Select storage pools from the list below to add to the <%= @hardware_pool.name %> hardware pool.
        > -
        > +<%- content_for :title do -%> > + Add Storage > +<%- end -%> > +<%- content_for :description do -%> > + Select storage pools from the list below to add to the <%= @hardware_pool.name %> hardware pool. > +<%- end -%> > + > + >
        >
        > - <%= render :partial => "/storage/grid", :locals => { :table_id => "addstorage_unassigned_grid", > - :hwpool_id => Pool.root.id, :on_select => "false" } %> > - <%= render :partial => "/storage/grid", :locals => { :table_id => "addstorage_assigned_grid", > - :hwpool_id => nil, :on_select => "false" } %> > + <%= render :partial => "/storage/grid", :locals => { :table_id => "addstorage_grid", > + :hwpool_id => nil, :exclude_id => @hardware_pool.id, > + :on_select => "false" } %> >
        >
        > - > -<%= popup_footer("add_storage()", "Add Selected Storage Pools") %> > +<%= popup_footer("add_storage('#{url_for :controller => 'hardware', > + :action => 'add_storage', > + :id => @hardware_pool}')", > + "Add Selected Storage Pools") %> > > diff --git a/wui/src/app/views/storage/new.rhtml b/wui/src/app/views/storage/new.rhtml > index 6f88ce3..13dedb9 100644 > --- a/wui/src/app/views/storage/new.rhtml > +++ b/wui/src/app/views/storage/new.rhtml > @@ -1,51 +1,47 @@ > -
        > -
        Add New Storage Pool
        > -
        Add a new Storage Pool to this oVirt server.
        > -
        > +<%- content_for :title do -%> > + Add New Storage Pool > +<%- end -%> > +<%- content_for :description do -%> > + Add a new Storage Pool to this oVirt server. > +<%- end -%> > >
        > <%= error_messages_for 'storage_pool' %> > - <% form_tag do %> > > + <% form_tag do %> > > <%= hidden_field_tag 'hardware_pool_id', @hardware_pool.id %> > - <%= select_tag_with_label "Storage Type:", 'storage_type', @storage_types, :onChange => "load_details()" %> > + <%= select_tag_with_label "Storage Type:", 'storage_type', @storage_types, :onChange => "load_storage_subform()" %> > > <% end %> > >
        >
        >
        > -
        > -
        > -
        > > -
        > -<%= popup_footer("$('#storage_pool_form').submit()", "New Storage Pool") %> > + > +
        > +
        > +
        > + <%= popup_footer("$('#storage_pool_form').submit()", "New Storage Pool") %> > > - > + > diff --git a/wui/src/app/views/vm/new.rhtml b/wui/src/app/views/vm/new.rhtml > index 60dbcd6..767f806 100644 > --- a/wui/src/app/views/vm/new.rhtml > +++ b/wui/src/app/views/vm/new.rhtml > @@ -1,12 +1,9 @@ > -
        > - > +<%- content_for :title do -%> > + Add Virtual Machine > +<%- end -%> > +<%- content_for :description do -%> > +<%- end -%> > > - > -
        > -
        Add Virtual Machine
        > -
        > - > - > >
        >
        > @@ -15,9 +12,6 @@ > > <%= popup_footer("$('#vm_form').submit()", "Add Virtual Machine") %> > > -
        > - > - > > > > -<%- content_for :title do -%> > -<%= "New Virtual Machine" %> > -<%- end -%> > diff --git a/wui/src/public/javascripts/ovirt.js b/wui/src/public/javascripts/ovirt.js > new file mode 100644 > index 0000000..675f20d > --- /dev/null > +++ b/wui/src/public/javascripts/ovirt.js > @@ -0,0 +1,138 @@ > +// ovirt-specific javascript functions are defined here > + > + > +// helper functions for dialogs and action links > + > + > +// returns an array of selected values for flexigrid checkboxes > +function get_selected_checkboxes(obj_form) > +{ > + var selected_array = new Array() > + var selected_index = 0 > + var checkboxes > + if (obj_form.grid_checkbox) { > + if (obj_form.grid_checkbox.length == undefined) { > + checkboxes = [obj_form.grid_checkbox] > + } else { > + checkboxes = obj_form.grid_checkbox > + } > + for(var i=0; i < checkboxes.length; i++){ > + if(checkboxes[i].checked) > + { > + selected_array[selected_index]= checkboxes[i].value > + selected_index++ > + } > + } > + } > + return selected_array > +} > + > + > +// make sure that at least one item is selected to continue > +function validate_selected(selected_array, name) > +{ > + if (selected_array.length == 0) { > + alert("Please select at least one " + name + " to continue") > + return false > + } else { > + return true > + } > +} > + > +function add_hosts(url) > +{ > + hosts= get_selected_checkboxes(document.addhosts_grid_form) > + if (validate_selected(hosts, "host")) { > + $.post(url, > + { resource_ids: hosts.toString() }, > + function(data,status){ > + jQuery(document).trigger('close.facebox'); > + $("#hosts_grid").flexReload() > + if (data.alert) { > + alert(data.alert); > + } > + }, 'json'); > + } > +} > +function add_storage(url) > +{ > + storage= get_selected_checkboxes(document.addstorage_grid_form) > + if (validate_selected(storage, "storage pool")) { > + $.post(url, > + { resource_ids: storage.toString() }, > + function(data,status){ > + jQuery(document).trigger('close.facebox'); > + $("#storage_grid").flexReload() > + if (data.alert) { > + alert(data.alert); > + } > + }, 'json'); > + } > +} > +// deal with ajax form response, filling in validation messages where required. > +function ajax_validation(response, status) > +{ > + if (response.object) { > + $(".fieldWithErrors").removeClass("fieldWithErrors"); > + $("div.errorExplanation").remove(); > + if (!response.success) { > + for(i=0; i + var element = $("div.form_field:has(#"+response.object + "_" + response.errors[i][0]+")"); > + if (element) { > + element.addClass("fieldWithErrors"); > + for(j=0; j + element.append('
        '+response.errors[i][1][j]+'
        '); > + } > + } > + } > + } > + if (response.alert) { > + alert(response.alert) > + } > + } > +} > + > +// callback actions for dialog submissions > +function afterHwPool(response, status){ > + ajax_validation(response, status) > + if (response.success) { > + jQuery(document).trigger('close.facebox'); > + // FIXME do we need to reload the tree here > + > + // this is for reloading the host/storage grid when > + // adding hosts/storage to a new HW pool > + if (response.resource_type) { > + $('#' + response.resource_type + '_grid').flexReload() > + } > + // do we have HW pools grid? > + //$("#vmpools_grid").flexReload() > + } > +} > +function afterVmPool(response, status){ > + ajax_validation(response, status) > + if (response.success) { > + jQuery(document).trigger('close.facebox'); > + $("#vmpools_grid").flexReload() > + } > +} > +function afterStoragePool(response, status){ > + ajax_validation(response, status) > + if (response.success) { > + jQuery(document).trigger('close.facebox'); > + $("#storage_grid").flexReload() > + } > +} > +function afterPermission(response, status){ > + ajax_validation(response, status) > + if (response.success) { > + jQuery(document).trigger('close.facebox'); > + $("#users_grid").flexReload() > + } > +} > +function afterVm(response, status){ > + ajax_validation(response, status) > + if (response.success) { > + jQuery(document).trigger('close.facebox'); > + $("#vms_grid").flexReload() > + } > +} > diff --git a/wui/src/vendor/plugins/betternestedset/lib/#better_nested_set.rb# b/wui/src/vendor/plugins/betternestedset/lib/#better_nested_set.rb# > deleted file mode 100644 > index d430419..0000000 > --- a/wui/src/vendor/plugins/betternestedset/lib/#better_nested_set.rb# > +++ /dev/null > @@ -1,583 +0,0 @@ > -module SymetrieCom > - module Acts #:nodoc: > - module NestedSet #:nodoc: > - def self.included(base) > - base.extend(ClassMethods) > - end > - # This module provides an enhanced acts_as_nested_set mixin for ActiveRecord. > - # Please see the README for background information, examples, and tips on usage. > - module ClassMethods > - # Configuration options are: > - # * +parent_column+ - Column name for the parent/child foreign key (default: +parent_id+). > - # * +left_column+ - Column name for the left index (default: +lft+). > - # * +right_column+ - Column name for the right index (default: +rgt+). NOTE: > - # Don't use +left+ and +right+, since these are reserved database words. > - # * +scope+ - Restricts what is to be considered a tree. Given a symbol, it'll attach "_id" > - # (if it isn't there already) and use that as the foreign key restriction. It's also possible > - # to give it an entire string that is interpolated if you need a tighter scope than just a foreign key. > - # Example: acts_as_nested_set :scope => 'tree_id = #{tree_id} AND completed = 0' > - # * +text_column+ - Column name for the title field (optional). Used as default in the > - # {your-class}_options_for_select helper method. If empty, will use the first string field > - # of your model class. > - def acts_as_nested_set(options = {}) > - > - options[:scope] = "#{options[:scope]}_id".intern if options[:scope].is_a?(Symbol) && options[:scope].to_s !~ /_id$/ > - > - write_inheritable_attribute(:acts_as_nested_set_options, > - { :parent_column => (options[:parent_column] || 'parent_id'), > - :left_column => (options[:left_column] || 'lft'), > - :right_column => (options[:right_column] || 'rgt'), > - :scope => (options[:scope] || '1 = 1'), > - :text_column => (options[:text_column] || columns.collect{|c| (c.type == :string) ? c.name : nil }.compact.first), > - :class => self # for single-table inheritance > - } ) > - > - class_inheritable_reader :acts_as_nested_set_options > - > - if acts_as_nested_set_options[:scope].is_a?(Symbol) > - scope_condition_method = %( > - def scope_condition > - if #{acts_as_nested_set_options[:scope].to_s}.nil? > - "#{acts_as_nested_set_options[:scope].to_s} IS NULL" > - else > - "#{acts_as_nested_set_options[:scope].to_s} = \#{#{acts_as_nested_set_options[:scope].to_s}}" > - end > - end > - ) > - else > - scope_condition_method = "def scope_condition() \"#{acts_as_nested_set_options[:scope]}\" end" > - end > - > - # no bulk assignment > - attr_protected acts_as_nested_set_options[:left_column].intern, > - acts_as_nested_set_options[:right_column].intern, > - acts_as_nested_set_options[:parent_column].intern > - # no assignment to structure fields > - module_eval <<-"end_eval", __FILE__, __LINE__ > - def #{acts_as_nested_set_options[:left_column]}=(x) > - raise ActiveRecord::ActiveRecordError, "Unauthorized assignment to #{acts_as_nested_set_options[:left_column]}: it's an internal field handled by acts_as_nested_set code, use move_to_* methods instead." > - end > - def #{acts_as_nested_set_options[:right_column]}=(x) > - raise ActiveRecord::ActiveRecordError, "Unauthorized assignment to #{acts_as_nested_set_options[:right_column]}: it's an internal field handled by acts_as_nested_set code, use move_to_* methods instead." > - end > - def #{acts_as_nested_set_options[:parent_column]}=(x) > - raise ActiveRecord::ActiveRecordError, "Unauthorized assignment to #{acts_as_nested_set_options[:parent_column]}: it's an internal field handled by acts_as_nested_set code, use move_to_* methods instead." > - end > - #{scope_condition_method} > - end_eval > - > - > - include SymetrieCom::Acts::NestedSet::InstanceMethods > - extend SymetrieCom::Acts::NestedSet::ClassMethods > - > - # adds the helper for the class > -# ActionView::Base.send(:define_method, "#{Inflector.underscore(self.class)}_options_for_select") { special=nil > -# "#{acts_as_nested_set_options[:text_column]} || "#{self.class} id #{id}" > -# } > - > - end > - > - > - # Returns the single root for the class (or just the first root, if there are several). > - # Deprecation note: the original acts_as_nested_set allowed roots to have parent_id = 0, > - # so we currently do the same. This silliness will not be tolerated in future versions, however. > - def root > - acts_as_nested_set_options[:class].find(:first, :conditions => "(#{acts_as_nested_set_options[:parent_column]} IS NULL OR #{acts_as_nested_set_options[:parent_column]} = 0)") > - end > - > - # Returns the roots and/or virtual roots of all trees. See the explanation of virtual roots in the README. > - def roots > - acts_as_nested_set_options[:class].find(:all, :conditions => "(#{acts_as_nested_set_options[:parent_column]} IS NULL OR #{acts_as_nested_set_options[:parent_column]} = 0)", :order => "#{acts_as_nested_set_options[:left_column]}") > - end > - > - # Checks the left/right indexes of all records, > - # returning the number of records checked. Throws ActiveRecord::ActiveRecordError if it finds a problem. > - def check_all > - total = 0 > - transaction do > - # if there are virtual roots, only call check_full_tree on the first, because it will check other virtual roots in that tree. > - total = roots.inject(0) {|sum, r| sum + (r[r.left_col_name] == 1 ? r.check_full_tree : 0 )} > - raise ActiveRecord::ActiveRecordError, "Scope problems or nodes without a valid root" unless acts_as_nested_set_options[:class].count == total > - end > - return total > - end > - > - # Re-calculate the left/right values of all nodes. Can be used to convert ordinary trees into nested sets. > - def renumber_all > - scopes = [] > - # only call it once for each scope_condition (if the scope conditions are messed up, this will obviously cause problems) > - roots.each do |r| > - r.renumber_full_tree unless scopes.include?(r.scope_condition) > - scopes << r.scope_condition > - end > - end > - > - # Returns an SQL fragment that matches _items_ *and* all of their descendants, for use in a WHERE clause. > - # You can pass it a single object, a single ID, or an array of objects and/or IDs. > - # # if a.lft = 2, a.rgt = 7, b.lft = 12 and b.rgt = 13 > - # Set.sql_for([a,b]) # returns "((lft BETWEEN 2 AND 7) OR (lft BETWEEN 12 AND 13))" > - # Returns "1 != 1" if passed no items. If you need to exclude items, just use "NOT (#{sql_for(items)})". > - # Note that if you have multiple trees, it is up to you to apply your scope condition. > - def sql_for(items) > - items = [items] unless items.is_a?(Array) > - # get objects for IDs > - items.collect! {|s| s.is_a?(acts_as_nested_set_options[:class]) ? s : acts_as_nested_set_options[:class].find(s)}.uniq > - items.reject! {|e| e.new_record?} # exclude unsaved items, since they don't have left/right values yet > - > - return "1 != 1" if items.empty? # PostgreSQL didn't like '0', and SQLite3 didn't like 'FALSE' > - items.map! {|e| "(#{acts_as_nested_set_options[:left_column]} BETWEEN #{e[acts_as_nested_set_options[:left_column]]} AND #{e[acts_as_nested_set_options[:right_column]]})" } > - "(#{items.join(' OR ')})" > - end > - > - end > - > - # This module provides instance methods for an enhanced acts_as_nested_set mixin. Please see the README for background information, examples, and tips on usage. > - module InstanceMethods > - # convenience methods to make the code more readable > - def left_col_name()#:nodoc: > - acts_as_nested_set_options[:left_column] > - end > - def right_col_name()#:nodoc: > - acts_as_nested_set_options[:right_column] > - end > - def parent_col_name()#:nodoc: > - acts_as_nested_set_options[:parent_column] > - end > - alias parent_column parent_col_name#:nodoc: Deprecated > - def base_set_class()#:nodoc: > - acts_as_nested_set_options[:class] # for single-table inheritance > - end > - > - # On creation, automatically add the new node to the right of all existing nodes in this tree. > - def before_create # already protected by a transaction > - maxright = base_set_class.maximum(right_col_name, :conditions => scope_condition) || 0 > - self[left_col_name] = maxright+1 > - self[right_col_name] = maxright+2 > - end > - > - # On destruction, delete all children and shift the lft/rgt values back to the left so the counts still work. > - def before_destroy # already protected by a transaction > - return if self[right_col_name].nil? || self[left_col_name].nil? > - self.reload # in case a concurrent move has altered the indexes > - dif = self[right_col_name] - self[left_col_name] + 1 > - base_set_class.delete_all( "#{scope_condition} AND (#{left_col_name} BETWEEN #{self[left_col_name]} AND #{self[right_col_name]})" ) > - base_set_class.update_all("#{left_col_name} = CASE \ > - WHEN #{left_col_name} > #{self[right_col_name]} THEN (#{left_col_name} - #{dif}) \ > - ELSE #{left_col_name} END, \ > - #{right_col_name} = CASE \ > - WHEN #{right_col_name} > #{self[right_col_name]} THEN (#{right_col_name} - #{dif} ) \ > - ELSE #{right_col_name} END", > - scope_condition) > - end > - > - # By default, records are compared and sorted using the left column. > - def <=>(x) > - self[left_col_name] <=> x[left_col_name] > - end > - > - # Deprecated. Returns true if this is a root node. > - def root? > - parent_id = self[parent_col_name] > - (parent_id == 0 || parent_id.nil?) && self[right_col_name] && self[left_col_name] && (self[right_col_name] > self[left_col_name]) > - end > - > - # Deprecated. Returns true if this is a child node > - def child? > - parent_id = self[parent_col_name] > - !(parent_id == 0 || parent_id.nil?) && (self[left_col_name] > 1) && (self[right_col_name] > self[left_col_name]) > - end > - > - # Deprecated. Returns true if we have no idea what this is > - def unknown? > - !root? && !child? > - end > - > - # Returns this record's root ancestor. > - def root > - # the BETWEEN clause is needed to ensure we get the right virtual root, if using those > - base_set_class.find(:first, :conditions => "#{scope_condition} \ > - AND (#{parent_col_name} IS NULL OR #{parent_col_name} = 0) AND (#{self[left_col_name]} BETWEEN #{left_col_name} AND #{right_col_name})") > - end > - > - # Returns the root or virtual roots of this record's tree (a tree cannot have more than one real root). See the explanation of virtual roots in the README. > - def roots > - base_set_class.find(:all, :conditions => "#{scope_condition} AND (#{parent_col_name} IS NULL OR #{parent_col_name} = 0)", :order => "#{left_col_name}") > - end > - > - # Returns this record's parent. > - def parent > - base_set_class.find(self[parent_col_name]) if self[parent_col_name] > - end > - > - # Returns an array of all parents, starting with the root. > - def ancestors > - self_and_ancestors - [self] > - end > - > - # Returns an array of all parents plus self, starting with the root. > - def self_and_ancestors > - base_set_class.find(:all, :conditions => "#{scope_condition} AND (#{self[left_col_name]} BETWEEN #{left_col_name} AND #{right_col_name})", :order => left_col_name ) > - end > - > - # Returns all the children of this node's parent, except self. > - def siblings > - self_and_siblings - [self] > - end > - > - # Returns all the children of this node's parent, including self. > - def self_and_siblings > - if self[parent_col_name].nil? || self[parent_col_name].zero? > - [self] > - else > - base_set_class.find(:all, :conditions => "#{scope_condition} AND #{parent_col_name} = #{self[parent_col_name]}", :order => left_col_name) > - end > - end > - > - # Returns the level of this object in the tree, root level being 0. > - def level > - return 0 if self[parent_col_name].nil? > - base_set_class.count(:conditions => "#{scope_condition} AND (#{self[left_col_name]} BETWEEN #{left_col_name} AND #{right_col_name})") - 1 > - end > - > - # Returns the number of nested children of this object. > - def all_children_count > - return (self[right_col_name] - self[left_col_name] - 1)/2 > - end > - > - # Returns itself and all nested children. > - # Pass :exclude => item, or id, or [items or id] to exclude one or more items *and* all of their descendants. > - def full_set(special=nil) > - if special && special[:exclude] > - exclude_str = " AND NOT (#{base_set_class.sql_for(special[:exclude])}) " > - elsif new_record? || self[right_col_name] - self[left_col_name] == 1 > - return [self] > - endas > - base_set_class.find(:all, :conditions => "#{scope_condition} #{exclude_str} AND (#{left_col_name} BETWEEN #{self[left_col_name]} AND #{self[right_col_name]})", :order => left_col_name) > - end > - > - # Returns all children and nested children. > - # Pass :exclude => item, or id, or [items or id] to exclude one or more items *and* all of their descendants. > - def all_children(special=nil) > - full_set(special) - [self] > - end > - > - # Returns this record's immediate children. > - def children > - base_set_class.find(:all, :conditions => "#{scope_condition} AND #{parent_col_name} = #{self.id}", :order => left_col_name) > - end > - > - # Deprecated > - alias direct_children children > - > - # Returns this record's terminal children (nodes without children). > - def leaves > - base_set_class.find(:all, :conditions => "#{scope_condition} AND (#{left_col_name} BETWEEN #{self[left_col_name]} AND #{self[right_col_name]}) AND #{left_col_name} + 1 = #{right_col_name}", :order => left_col_name) > - end > - > - # Returns the count of this record's terminal children (nodes without children). > - def leaves_count > - base_set_class.count(:conditions => "#{scope_condition} AND (#{left_col_name} BETWEEN #{self[left_col_name]} AND #{self[right_col_name]}) AND #{left_col_name} + 1 = #{right_col_name}") > - end > - > - # Checks the left/right indexes of one node and all descendants. > - # Throws ActiveRecord::ActiveRecordError if it finds a problem. > - def check_subtree > - transaction do > - self.reload > - check # this method is implemented via #check, so that we don't generate lots of unnecessary nested transactions > - end > - end > - > - # Checks the left/right indexes of the entire tree that this node belongs to, > - # returning the number of records checked. Throws ActiveRecord::ActiveRecordError if it finds a problem. > - # This method is needed because check_subtree alone cannot find gaps between virtual roots, orphaned nodes or endless loops. > - def check_full_tree > - total_nodes = 0 > - transaction do > - # virtual roots make this method more complex than it otherwise would be > - n = 1 > - roots.each do |r| > - raise ActiveRecord::ActiveRecordError, "Gaps between roots in the tree containing record ##{r.id}" if r[left_col_name] != n > - r.check_subtree > - n = r[right_col_name] + 1 > - end > - total_nodes = roots.inject(0) {|sum, r| sum + r.all_children_count + 1 } > - unless base_set_class.count(:conditions => "#{scope_condition}") == total_nodes > - raise ActiveRecord::ActiveRecordError, "Orphaned nodes or endless loops in the tree containing record ##{self.id}" > - end > - end > - return total_nodes > - end > - > - # Re-calculate the left/right values of all nodes in this record's tree. Can be used to convert an ordinary tree into a nested set. > - def renumber_full_tree > - indexes = [] > - n = 1 > - transaction do > - for r in roots # because we may have virtual roots > - n = r.calc_numbers(n, indexes) > - end > - for i in indexes > - base_set_class.update_all("#{left_col_name} = #{i[:lft]}, #{right_col_name} = #{i[:rgt]}", "#{self.class.primary_key} = #{i[:id]}") > - end > - end > - ## reload? > - end > - > - # Deprecated. Adds a child to this object in the tree. If this object hasn't been initialized, > - # it gets set up as a root node. > - # > - # This method exists only for compatibility and will be removed in future versions. > - def add_child(child) > - transaction do > - self.reload; child.reload # for compatibility with old version > - # the old version allows records with nil values for lft and rgt > - unless self[left_col_name] && self[right_col_name] > - if child[left_col_name] || child[right_col_name] > - raise ActiveRecord::ActiveRecordError, "If parent lft or rgt are nil, you can't add a child with non-nil lft or rgt" > - end > - base_set_class.update_all("#{left_col_name} = CASE \ > - WHEN id = #{self.id} \ > - THEN 1 \ > - WHEN id = #{child.id} \ > - THEN 3 \ > - ELSE #{left_col_name} END, \ > - #{right_col_name} = CASE \ > - WHEN id = #{self.id} \ > - THEN 2 \ > - WHEN id = #{child.id} \ > - THEN 4 \ > - ELSE #{right_col_name} END", > - scope_condition) > - self.reload; child.reload > - end > - unless child[left_col_name] && child[right_col_name] > - maxright = base_set_class.maximum(right_col_name, :conditions => scope_condition) || 0 > - base_set_class.update_all("#{left_col_name} = CASE \ > - WHEN id = #{child.id} \ > - THEN #{maxright + 1} \ > - ELSE #{left_col_name} END, \ > - #{right_col_name} = CASE \ > - WHEN id = #{child.id} \ > - THEN #{maxright + 2} \ > - ELSE #{right_col_name} END", > - scope_condition) > - child.reload > - end > - > - child.move_to_child_of(self) > - # self.reload ## even though move_to calls target.reload, at least one object in the tests was not reloading (near the end of test_common_usage) > - end > - # self.reload > - # child.reload > - # > - # if child.root? > - # raise ActiveRecord::ActiveRecordError, "Adding sub-tree isn\'t currently supported" > - # else > - # if ( (self[left_col_name] == nil) || (self[right_col_name] == nil) ) > - # # Looks like we're now the root node! Woo > - # self[left_col_name] = 1 > - # self[right_col_name] = 4 > - # > - # # What do to do about validation? > - # return nil unless self.save > - # > - # child[parent_col_name] = self.id > - # child[left_col_name] = 2 > - # child[right_col_name]= 3 > - # return child.save > - # else > - # # OK, we need to add and shift everything else to the right > - # child[parent_col_name] = self.id > - # right_bound = self[right_col_name] > - # child[left_col_name] = right_bound > - # child[right_col_name] = right_bound + 1 > - # self[right_col_name] += 2 > - # self.class.transaction { > - # self.class.update_all( "#{left_col_name} = (#{left_col_name} + 2)", "#{scope_condition} AND #{left_col_name} >= #{right_bound}" ) > - # self.class.update_all( "#{right_col_name} = (#{right_col_name} + 2)", "#{scope_condition} AND #{right_col_name} >= #{right_bound}" ) > - # self.save > - # child.save > - # } > - # end > - # end > - end > - > - # Move this node to the left of _target_ (you can pass an object or just an id). > - # Unsaved changes in either object will be lost. Raises ActiveRecord::ActiveRecordError if it encounters a problem. > - def move_to_left_of(target) > - self.move_to target, :left > - end > - > - # Move this node to the right of _target_ (you can pass an object or just an id). > - # Unsaved changes in either object will be lost. Raises ActiveRecord::ActiveRecordError if it encounters a problem. > - def move_to_right_of(target) > - self.move_to target, :right > - end > - > - # Make this node a child of _target_ (you can pass an object or just an id). > - # Unsaved changes in either object will be lost. Raises ActiveRecord::ActiveRecordError if it encounters a problem. > - def move_to_child_of(target) > - self.move_to target, :child > - end > - > - protected > - def move_to(target, position) #:nodoc: > - raise ActiveRecord::ActiveRecordError, "You cannot move a new node" if new_record? > - raise ActiveRecord::ActiveRecordError, "You cannot move a node if left or right is nil" unless self[left_col_name] && self[right_col_name] > - > - transaction do > - self.reload # the lft/rgt values could be stale (target is reloaded below) > - if target.is_a?(base_set_class) > - target.reload # could be stale > - else > - target = base_set_class.find(target) # load object if we were given an ID > - end > - > - if (target[left_col_name] >= self[left_col_name]) && (target[right_col_name] <= self[right_col_name]) > - raise ActiveRecord::ActiveRecordError, "Impossible move, target node cannot be inside moved tree." > - end > - > - # prevent moves between different trees > - if target.scope_condition != scope_condition > - raise ActiveRecord::ActiveRecordError, "Scope conditions do not match. Is the target in the same tree?" > - end > - > - # the move: we just need to define two adjoining segments of the left/right index and swap their positions > - bound = case position > - when :child then target[right_col_name] > - when :left then target[left_col_name] > - when :right then target[right_col_name] + 1 > - else raise ActiveRecord::ActiveRecordError, "Position should be :child, :left or :right ('#{position}' received)." > - end > - > - if bound > self[right_col_name] > - bound = bound - 1 > - other_bound = self[right_col_name] + 1 > - else > - other_bound = self[left_col_name] - 1 > - end > - > - return if bound == self[right_col_name] || bound == self[left_col_name] # there would be no change, and other_bound is now wrong anyway > - > - # we have defined the boundaries of two non-overlapping intervals, > - # so sorting puts both the intervals and their boundaries in order > - a, b, c, d = [self[left_col_name], self[right_col_name], bound, other_bound].sort > - > - # change nil to NULL for new parent > - if position == :child > - new_parent = target.id > - else > - new_parent = target[parent_col_name].nil? ? 'NULL' : target[parent_col_name] > - end > - > - base_set_class.update_all("\ > - #{left_col_name} = CASE \ > - WHEN #{left_col_name} BETWEEN #{a} AND #{b} THEN #{left_col_name} + #{d - b} \ > - WHEN #{left_col_name} BETWEEN #{c} AND #{d} THEN #{left_col_name} + #{a - c} \ > - ELSE #{left_col_name} END, \ > - #{right_col_name} = CASE \ > - WHEN #{right_col_name} BETWEEN #{a} AND #{b} THEN #{right_col_name} + #{d - b} \ > - WHEN #{right_col_name} BETWEEN #{c} AND #{d} THEN #{right_col_name} + #{a - c} \ > - ELSE #{right_col_name} END, \ > - #{parent_col_name} = CASE \ > - WHEN #{self.class.primary_key} = #{self.id} THEN #{new_parent} \ > - ELSE #{parent_col_name} END", > - scope_condition) > - self.reload > - target.reload > - end > - end > - > - def check #:nodoc: > - # performance improvements (3X or more for tables with lots of columns) by using :select to load just id, lft and rgt > - ## i don't use the scope condition here, because it shouldn't be needed > - my_children = base_set_class.find(:all, :conditions => "#{parent_col_name} = #{self.id}", > - :order => left_col_name, :select => "#{self.class.primary_key}, #{left_col_name}, #{right_col_name}") > - > - if my_children.empty? > - unless self[left_col_name] && self[right_col_name] > - raise ActiveRecord::ActiveRecordError, "#{self.class.name}##{self.id}.#{right_col_name} or #{left_col_name} is blank" > - end > - unless self[right_col_name] - self[left_col_name] == 1 > - raise ActiveRecord::ActiveRecordError, "#{self.class.name}##{self.id}.#{right_col_name} should be 1 greater than #{left_col_name}" > - end > - else > - n = self[left_col_name] > - for c in (my_children) # the children come back ordered by lft > - unless c[left_col_name] && c[right_col_name] > - raise ActiveRecord::ActiveRecordError, "#{self.class.name}##{c.id}.#{right_col_name} or #{left_col_name} is blank" > - end > - unless c[left_col_name] == n + 1 > - raise ActiveRecord::ActiveRecordError, "#{self.class.name}##{c.id}.#{left_col_name} should be 1 greater than #{n}" > - end > - c.check > - n = c[right_col_name] > - end > - unless self[right_col_name] == n + 1 > - raise ActiveRecord::ActiveRecordError, "#{self.class.name}##{self.id}.#{right_col_name} should be 1 greater than #{n}" > - end > - end > - end > - > - # used by the renumbering methods > - def calc_numbers(n, indexes) #:nodoc: > - my_lft = n > - # performance improvements (3X or more for tables with lots of columns) by using :select to load just id, lft and rgt > - ## i don't use the scope condition here, because it shouldn't be needed > - my_children = base_set_class.find(:all, :conditions => "#{parent_col_name} = #{self.id}", > - :order => left_col_name, :select => "#{self.class.primary_key}, #{left_col_name}, #{right_col_name}") > - if my_children.empty? > - my_rgt = (n += 1) > - else > - for c in (my_children) > - n = c.calc_numbers(n + 1, indexes) > - end > - my_rgt = (n += 1) > - end > - indexes << {:id => self.id, :lft => my_lft, :rgt => my_rgt} unless self[left_col_name] == my_lft && self[right_col_name] == my_rgt > - return n > - end > - > - > - > - # The following code is my crude method of making things concurrency-safe. > - # Basically, we need to ensure that whenever a record is saved, the lft/rgt > - # values are _not_ written to the database, because if any changes to the tree > - # structure occurrred since the object was loaded, the lft/rgt values could > - # be out of date and corrupt the indexes. > - # I hope that someone with a little more ruby-foo can look at this and come > - # up with a more elegant solution. > - private > - # override ActiveRecord to prevent lft/rgt values from being saved (can corrupt indexes under concurrent usage) > - def update #:nodoc: > - connection.update( > - "UPDATE #{self.class.table_name} " + > - "SET #{quoted_comma_pair_list(connection, special_attributes_with_quotes(false))} " + > - "WHERE #{self.class.primary_key} = #{quote_value(id)}", > - "#{self.class.name} Update" > - ) > - end > - > - # exclude the lft/rgt columns from update statements > - def special_attributes_with_quotes(include_primary_key = true) #:nodoc: > - attributes.inject({}) do |quoted, (name, value)| > - if column = column_for_attribute(name) > - quoted[name] = quote_value(value, column) unless (!include_primary_key && column.primary) || [acts_as_nested_set_options[:left_column], acts_as_nested_set_options[:right_column]].include?(column.name) > - end > - quoted > - end > - end > - > - # i couldn't figure out how to call attributes_with_quotes without cutting and pasting this private method in. :( > - # Quote strings appropriately for SQL statements. > - def quote_value(value, column = nil) #:nodoc: > - self.class.connection.quote(value, column) > - end > - > - end > - end > - end > -end > - > - > diff --git a/wui/src/vendor/plugins/betternestedset/lib/better_nested_set.rb b/wui/src/vendor/plugins/betternestedset/lib/better_nested_set.rb > index 43b46ca..ed5d3e3 100644 > --- a/wui/src/vendor/plugins/betternestedset/lib/better_nested_set.rb > +++ b/wui/src/vendor/plugins/betternestedset/lib/better_nested_set.rb > @@ -246,24 +246,33 @@ module SymetrieCom > > # Returns itself and all nested children. > # Pass :exclude => item, or id, or [items or id] to exclude one or more items *and* all of their descendants. > - def full_set(special=nil) > - if special && special[:exclude] > - exclude_str = " AND NOT (#{base_set_class.sql_for(special[:exclude])}) " > + # in addition to the standard find opts > + def full_set(find_opts={}) > + exclude = find_opts.delete(:exclude) > + if exclude > + exclude_str = " AND NOT (#{base_set_class.sql_for(exclude)}) " > elsif new_record? || self[right_col_name] - self[left_col_name] == 1 > return [self] > end > - base_set_class.find(:all, :conditions => "#{scope_condition} #{exclude_str} AND (#{left_col_name} BETWEEN #{self[left_col_name]} AND #{self[right_col_name]})", :order => left_col_name) > + opts = merge_incoming_opts({:conditions => "#{scope_condition} #{exclude_str} AND (#{left_col_name} BETWEEN #{self[left_col_name]} AND #{self[right_col_name]})", > + :order => left_col_name}, > + find_opts) > + base_set_class.find(:all, opts) > end > > # Returns all children and nested children. > # Pass :exclude => item, or id, or [items or id] to exclude one or more items *and* all of their descendants. > - def all_children(special=nil) > - full_set(special) - [self] > + # in addition to the standard find opts > + def all_children(find_opts=nil) > + full_set(find_opts) - [self] > end > > # Returns this record's immediate children. > - def children > - base_set_class.find(:all, :conditions => "#{scope_condition} AND #{parent_col_name} = #{self.id}", :order => left_col_name) > + def children(find_opts={}) > + opts = merge_incoming_opts({:conditions => "#{scope_condition} AND #{parent_col_name} = #{self.id}", > + :order => left_col_name}, > + find_opts) > + base_set_class.find(:all, opts) > end > > # Deprecated > @@ -575,6 +584,14 @@ module SymetrieCom > self.class.connection.quote(value, column) > end > > + # accept incoming opts to allow filtering of results. > + # So far only tested in limited use cases encountered in oVirt devel. > + def merge_incoming_opts(set_opts, incoming_opts) > + new_conditions = incoming_opts.delete(:conditions) > + set_opts[:conditions] = "(#{set_opts[:conditions]}) AND (#{new_conditions})" if new_conditions > + set_opts.merge(incoming_opts) > + end > + > end > end > end > -- > 1.5.4.1 > This looks like it does what it's supposed to. ACK, and committed. Note that the add-host-to-pool dialog exposed a bug in the pager wherein if there are more than 10 hosts you can't click "OK" -- but nothing in this patch caused that bug. --Hugh From mmorsi at redhat.com Fri May 30 05:16:42 2008 From: mmorsi at redhat.com (Mohammed Morsi) Date: Fri, 30 May 2008 01:16:42 -0400 Subject: [Ovirt-devel] [Patch] Updated Graphs Message-ID: <483F8DBA.2050204@redhat.com> Attached is my patch containing alot of graphing related updates. I updated my local dev copy to the latest revision in the repo before generating the patch, but only included the very latest commit on my development tree, so you will not be able to apply it to your own (if you would like the patch for all my commits, just ask but it is 1.2MB). Included are the following changes * Consolidated almost all of the graphing stuff into the graphing controller * Added and styled all of the remaining required graphs on all tabs / pages (some minor style tweaks might be needed, but these most likely will wait till overall site polishing) * Finished backing code for cpu / memory availability graphs on the hardware / resources summary page (vm availability graph is still up in the air as far as reqs, so left undone) * Added latest version of Mark's API to code base (removed from attached patch to save inbox space), I had to comment out the calls to it and replace them with dummy data to an exception I am getting with the API that I cannot figure out (it seems RRD.fetch is requiring a parameter of type T_FixNum and everything I pass in is a BigNum). Essentially all that is remaining is to correctly integrate the Mark's API into the backend and to finally figure out / finish the vm availability graph (or if we are removing it, figure out what will occupy its place if anything). Enjoy. -Mo -------------- next part -------------- A non-text attachment was scrubbed... Name: more-graphs.patch Type: text/x-patch Size: 61734 bytes Desc: not available URL: From sseago at redhat.com Thu May 29 19:54:19 2008 From: sseago at redhat.com (Scott Seago) Date: Thu, 29 May 2008 15:54:19 -0400 Subject: [Ovirt-devel] [PATCH] refactored popups and grids to pull more into the layouts, and static js functions into ovirt.js. Message-ID: Also, the children and all_children methods on Pool now accept find parameters. Signed-off-by: Scott Seago --- wui/src/app/controllers/application.rb | 24 +- wui/src/app/controllers/hardware_controller.rb | 46 ++- wui/src/app/controllers/host_controller.rb | 3 - wui/src/app/controllers/storage_controller.rb | 2 +- wui/src/app/models/pool.rb | 11 +- wui/src/app/views/dashboard/index.html.erb | 50 -- wui/src/app/views/hardware/move.rhtml | 13 +- wui/src/app/views/hardware/new.html.erb | 38 +- wui/src/app/views/hardware/show_hosts.rhtml | 1 + wui/src/app/views/hardware/show_storage.rhtml | 1 + wui/src/app/views/host/_grid.rhtml | 21 +- wui/src/app/views/host/addhost.html.erb | 71 +-- wui/src/app/views/layouts/popup.rhtml | 7 +- wui/src/app/views/layouts/redux.rhtml | 64 +-- wui/src/app/views/permission/new.rhtml | 26 +- wui/src/app/views/resources/new.rhtml | 27 +- wui/src/app/views/resources/show.rhtml | 78 --- wui/src/app/views/storage/_grid.rhtml | 11 +- wui/src/app/views/storage/addstorage.html.erb | 48 +- wui/src/app/views/storage/new.rhtml | 42 +- wui/src/app/views/vm/new.rhtml | 28 +- wui/src/public/javascripts/ovirt.js | 138 +++++ .../betternestedset/lib/#better_nested_set.rb# | 583 -------------------- .../betternestedset/lib/better_nested_set.rb | 33 +- 24 files changed, 350 insertions(+), 1016 deletions(-) create mode 100644 wui/src/public/javascripts/ovirt.js delete mode 100644 wui/src/vendor/plugins/betternestedset/lib/#better_nested_set.rb# diff --git a/wui/src/app/controllers/application.rb b/wui/src/app/controllers/application.rb index 5f20be3..3ca5125 100644 --- a/wui/src/app/controllers/application.rb +++ b/wui/src/app/controllers/application.rb @@ -84,18 +84,30 @@ class ApplicationController < ActionController::Base end end end - def json_list(full_items, attributes) + + # don't define find_opts for array inputs + def json_list(full_items, attributes, arg_list=[], find_opts={}) page = params[:page].to_i - item_list = full_items.paginate(:page => page, - :order => "#{params[:sortname]} #{params[:sortorder]}", - :per_page => params[:rp]) + paginate_opts = {:page => page, + :order => "#{params[:sortname]} #{params[:sortorder]}", + :per_page => params[:rp]} + arg_list << find_opts.merge(paginate_opts) + item_list = full_items.paginate(*arg_list) json_hash = {} json_hash[:page] = page - json_hash[:total] = full_items.size + json_hash[:total] = item_list.total_entries json_hash[:rows] = item_list.collect do |item| item_hash = {} item_hash[:id] = item.id - item_hash[:cell] = attributes.collect {|attr| item.send(attr)} + item_hash[:cell] = attributes.collect do |attr| + if attr.is_a? Array + value = item + attr.each { |attr_item| value = value.send(attr_item)} + value + else + item.send(attr) + end + end item_hash end render :json => json_hash.to_json diff --git a/wui/src/app/controllers/hardware_controller.rb b/wui/src/app/controllers/hardware_controller.rb index ad857f1..0f0c904 100644 --- a/wui/src/app/controllers/hardware_controller.rb +++ b/wui/src/app/controllers/hardware_controller.rb @@ -229,17 +229,27 @@ class HardwareController < ApplicationController if params[:id] pre_json hosts = @pool.hosts + find_opts = {} + include_pool = false else - # FIXME: no permissions checks here yet, no filtering of current pool yet - hosts = Host.find(:all) + # FIXME: no permissions or usage checks here yet + # filtering on which pool to exclude + id = params[:exclude_id] + hosts = Host + find_opts = {:include => :hardware_pool, + :conditions => ["pools.id != ?", id]} + include_pool = true end - json_list(hosts, - [:id, :hostname, :uuid, :hypervisor_type, :num_cpus, :cpu_speed, :arch, :memory_in_mb, :is_disabled_str]) + attr_list = [:id, :hostname, :uuid, :hypervisor_type, :num_cpus, :cpu_speed, :arch, :memory_in_mb, :is_disabled_str] + attr_list.insert(2, [:hardware_pool, :name]) if include_pool + json_list(hosts, attr_list, [:all], find_opts) end def vm_pools_json - json_list(@pool.sub_vm_resource_pools, - [:id, :name]) + json_list(Pool, + [:id, :name], + [@pool, :children], + {:finder => 'call_finder', :conditions => ["type = 'VmResourcePool'"]}) end def users_json @@ -251,12 +261,20 @@ class HardwareController < ApplicationController if params[:id] pre_json storage_pools = @pool.storage_pools + find_opts = {} + include_pool = false else - # FIXME: no permissions checks here yet, no filtering of current pool yet - storage_pools = StoragePool.find(:all) + # FIXME: no permissions or usage checks here yet + # filtering on which pool to exclude + id = params[:exclude_id] + storage_pools = StoragePool + find_opts = {:include => :hardware_pool, + :conditions => ["pools.id != ?", id]} + include_pool = true end - json_list(storage_pools, - [:id, :display_name, :ip_addr, :get_type_label]) + attr_list = [:id, :display_name, :ip_addr, :get_type_label] + attr_list.insert(2, [:hardware_pool, :name]) if include_pool + json_list(storage_pools, attr_list, [:all], find_opts) end def storage_volumes_json @@ -283,8 +301,10 @@ class HardwareController < ApplicationController resource_ids = resource_ids_str.split(",").collect {|x| x.to_i} if resource_ids_str begin @pool.create_with_resources(@parent, resource_type, resource_ids) - render :json => { :object => "pool", :success => true, + reply = { :object => "pool", :success => true, :alert => "Hardware Pool was successfully created." } + reply[:resource_type] = resource_type if resource_type + render :json => reply rescue render :json => { :object => "pool", :success => false, :errors => @pool.errors.localize_error_messages.to_a } @@ -308,7 +328,7 @@ class HardwareController < ApplicationController # in addition to the current pool (which is checked). We also need to fail # for hosts that aren't currently empty def add_hosts - host_ids_str = params[:host_ids] + host_ids_str = params[:resource_ids] host_ids = host_ids_str.split(",").collect {|x| x.to_i} begin @@ -347,7 +367,7 @@ class HardwareController < ApplicationController # in addition to the current pool (which is checked). We also need to fail # for storage that aren't currently empty def add_storage - storage_pool_ids_str = params[:storage_pool_ids] + storage_pool_ids_str = params[:resource_ids] storage_pool_ids = storage_pool_ids_str.split(",").collect {|x| x.to_i} begin diff --git a/wui/src/app/controllers/host_controller.rb b/wui/src/app/controllers/host_controller.rb index f89997f..623cc0c 100644 --- a/wui/src/app/controllers/host_controller.rb +++ b/wui/src/app/controllers/host_controller.rb @@ -58,9 +58,6 @@ class HostController < ApplicationController def addhost @hardware_pool = Pool.find(params[:hardware_pool_id]) - @unassigned = Pool.root.hosts.size - # FIXME: @assigned should match the updated assigned hosts query when that's done - @assigned = Host.find(:all).size render :layout => 'popup' end diff --git a/wui/src/app/controllers/storage_controller.rb b/wui/src/app/controllers/storage_controller.rb index 1c5b392..c8831e6 100644 --- a/wui/src/app/controllers/storage_controller.rb +++ b/wui/src/app/controllers/storage_controller.rb @@ -88,7 +88,7 @@ class StorageController < ApplicationController def new2 @storage_pools = @storage_pool.hardware_pool.storage_volumes - render :layout => 'popup' + render :layout => false end def insert_refresh_task diff --git a/wui/src/app/models/pool.rb b/wui/src/app/models/pool.rb index 490c5e6..5390beb 100644 --- a/wui/src/app/models/pool.rb +++ b/wui/src/app/models/pool.rb @@ -69,10 +69,10 @@ class Pool < ActiveRecord::Base end def sub_hardware_pools - Pool.select_hardware_pools(children) + children({:conditions => "type='HardwarePool'"}) end def sub_vm_resource_pools - Pool.select_vm_pools(children) + children({:conditions => "type='VmResourcePool'"}) end def self_and_like_siblings self_and_siblings.select {|pool| pool[:type] == self.class.name} @@ -156,7 +156,12 @@ class Pool < ActiveRecord::Base hash end end - + + def self.call_finder(*args) + obj = args.shift + method = args.shift + obj.send(method, *args) + end protected def traverse_parents diff --git a/wui/src/app/views/dashboard/index.html.erb b/wui/src/app/views/dashboard/index.html.erb index 8715261..92cb4da 100644 --- a/wui/src/app/views/dashboard/index.html.erb +++ b/wui/src/app/views/dashboard/index.html.erb @@ -1,57 +1,7 @@ -
        -
        - -
        - - <%= render :partial => "/layouts/quick_stats", :locals => { :hpool => @default_pool, :vms => @vms } %> - -
        - - <%= render :partial => "/layouts/hardware_pool_type_list", :locals => { :hardware_pools => @hardware_pools } %> - -
        - -
        -
        Available Hosts (<%= @available_hosts.size %>)
        -
        Statistics Data
        -
        -
        - <%= render :partial => "/host/list", :locals => { :hosts => @available_hosts } %> -
        -
        -
        - -
        -
        Available Storage (<%= @available_storage_volumes.size %>)
        -
        Storage Pools (<%= @storage_pools.size %>)
        -
        Statistics Data
        -
        -
        - <%= render :partial => "/storage/list_volumes", :locals => { :storage_volumes => @available_storage_volumes } %> -
        -
        -
        - -
        - -
        -
        - - -
         

        Actions

        - <%if @can_modify -%> -
        - - <%= link_to 'Create New Pool', { :controller => "hardware", :action => 'new', :parent_id => @default_pool}, { :class => "create" } %> -
        - <% end -%>
        <%= link_to_if @can_set_perms, 'User Permissions', { :controller => 'permission', :action => 'new', :pool_id => @default_pool }, { :class => "edit" } %>
        diff --git a/wui/src/app/views/hardware/move.rhtml b/wui/src/app/views/hardware/move.rhtml index 190fc03..f5824c6 100644 --- a/wui/src/app/views/hardware/move.rhtml +++ b/wui/src/app/views/hardware/move.rhtml @@ -1,3 +1,10 @@ +<%- content_for :title do -%> + Move <%= @resource_type.capitalize %> +<%- end -%> +<%- content_for :description do -%> + Select an existing hardware pool or create a new pool for selected <%= @resource_type %>. +<%- end -%> + -
        -
        -
        Move <%= @resource_type.capitalize %>
        -
        Select an existing hardware pool or create a new pool for selected <%= @resource_type %>.
        -
          @@ -63,4 +65,3 @@ $('#move_to_new_pool').click(function(){
          -
          diff --git a/wui/src/app/views/hardware/new.html.erb b/wui/src/app/views/hardware/new.html.erb index a533871..f594009 100644 --- a/wui/src/app/views/hardware/new.html.erb +++ b/wui/src/app/views/hardware/new.html.erb @@ -1,40 +1,30 @@ -
          -
          Add New Hardware Pool
          -
          Add a new Hardware Pool to the <%= @parent.name %> pool. - <%= "Checked #{@resource_type} will be added to the new pool." if @resource_type %> -
          -
          +<%- content_for :title do -%> + <%= _("Add New Hardware Pool") %> +<%- end -%> +<%- content_for :description do -%> + Add a new Hardware Pool to the <%= @parent.name %> pool. + <%= "Checked #{@resource_type} will be added to the new pool." if @resource_type %> +<%- end -%>
          -
          - <%= render :partial => 'form' %> -
          -<%= popup_footer("$('#pool_form').submit()", "Create Hardware Pool") %> +
          + <%= render :partial => 'form' %> +
          + <%= popup_footer("$('#pool_form').submit()", "Create Hardware Pool") %>
          - -<%- content_for :title do -%> -<%= _("New Hardware Pool") %> -<%- end -%> diff --git a/wui/src/app/views/hardware/show_hosts.rhtml b/wui/src/app/views/hardware/show_hosts.rhtml index ae0e8af..bcbc2b8 100644 --- a/wui/src/app/views/hardware/show_hosts.rhtml +++ b/wui/src/app/views/hardware/show_hosts.rhtml @@ -51,6 +51,7 @@
          <%= render :partial => "/host/grid", :locals => { :table_id => "hosts_grid", :hwpool_id => @pool.id, + :exclude_id => nil, :on_select => "hosts_select" } %>
          diff --git a/wui/src/app/views/hardware/show_storage.rhtml b/wui/src/app/views/hardware/show_storage.rhtml index 3d547db..f0b14bc 100644 --- a/wui/src/app/views/hardware/show_storage.rhtml +++ b/wui/src/app/views/hardware/show_storage.rhtml @@ -68,6 +68,7 @@
          <%= render :partial => "/storage/grid", :locals => { :table_id => "storage_grid", :hwpool_id => @pool.id, + :exclude_id => nil, :on_select => "storage_select" } %>
          diff --git a/wui/src/app/views/host/_grid.rhtml b/wui/src/app/views/host/_grid.rhtml index 338bc78..25bdfd7 100644 --- a/wui/src/app/views/host/_grid.rhtml +++ b/wui/src/app/views/host/_grid.rhtml @@ -7,18 +7,19 @@ $("#<%= table_id %>").flexigrid ( { - url: '<%= url_for :controller => "hardware", :action => "hosts_json", :id => hwpool_id %>', + url: '<%= url_for :controller => "hardware", :action => "hosts_json", :id => hwpool_id, :exclude_id => exclude_id %>', dataType: 'json', colModel : [ - {display: '', name : 'id', width : 20, sortable : false, align: 'left', process: <%= table_id %>checkbox}, - {display: 'Hostname', name : 'hostname', width : 60, sortable : true, align: 'left'}, - {display: 'UUID', name : 'uuid', width : 180, sortable : true, align: 'left'}, - {display: 'Hypervisor Type', name : 'hypervisor_type', width : 80, sortable : true, align: 'left'}, - {display: 'CPUs', name : 'num_cpus', width : 40, sortable : true, align: 'left'}, - {display: 'Speed (MHz)', name : 'cpu_speed', width : 60, sortable : true, align: 'right'}, - {display: 'Arch', name : 'arch', width : 50, sortable : true, align: 'right'}, - {display: 'RAM (MB)', name : 'memory', width : 60, sortable : true, align: 'right'}, - {display: 'Disabled', name : 'is_disabled', width : 50, sortable : true, align: 'right'} + {display: '', width : 20, align: 'left', process: <%= table_id %>checkbox}, + {display: 'Hostname', name : 'hostname', width : 60, align: 'left'}, + <%= "{display: 'Hardware Pool', name : 'pools.name', width : 100, align: 'left'}," if exclude_id %> + {display: 'UUID', name : 'uuid', width : 180, align: 'left'}, + {display: 'Hypervisor Type', name : 'hypervisor_type', width : 80, align: 'left'}, + {display: 'CPUs', name : 'num_cpus', width : 40, align: 'left'}, + {display: 'Speed (MHz)', name : 'cpu_speed', width : 60, align: 'right'}, + {display: 'Arch', name : 'arch', width : 50, align: 'right'}, + {display: 'RAM (MB)', name : 'memory', width : 60, align: 'right'}, + {display: 'Disabled', name : 'is_disabled', width : 50, align: 'right'} ], sortname: "hostname", sortorder: "asc", diff --git a/wui/src/app/views/host/addhost.html.erb b/wui/src/app/views/host/addhost.html.erb index 69e0e66..bc3c797 100644 --- a/wui/src/app/views/host/addhost.html.erb +++ b/wui/src/app/views/host/addhost.html.erb @@ -1,55 +1,18 @@ -
          -
          Add Host
          -
          Select hosts from the list below to add to the <%= @hardware_pool.name %> hardware pool. Learn how to manage hosts
          +<%- content_for :title do -%> + <%= _("Add Host") %> +<%- end -%> +<%- content_for :description do -%> + Select hosts from the list below to add to the <%= @hardware_pool.name %> hardware pool. Learn how to manage hosts +<%- end -%> + +
          +
          + <%= render :partial => "/host/grid", :locals => { :table_id => "addhosts_grid", + :hwpool_id => nil, :exclude_id => @hardware_pool.id, + :on_select => "false" } %>
          - - -
          -
          - <%= render :partial => "/host/grid", :locals => { :table_id => "addhosts_unassigned_grid", - :hwpool_id => Pool.root.id, :on_select => "false" } %> - <%= render :partial => "/host/grid", :locals => { :table_id => "addhosts_assigned_grid", - :hwpool_id => nil, :on_select => "false" } %> -
          -
          - -<%= popup_footer("add_hosts()", "Add Hosts") %> + +<%= popup_footer("add_hosts('#{url_for :controller => "hardware", + :action => "add_hosts", + :id => @hardware_pool}')", + "Add Hosts") %> diff --git a/wui/src/app/views/layouts/popup.rhtml b/wui/src/app/views/layouts/popup.rhtml index 736517c..55dda58 100644 --- a/wui/src/app/views/layouts/popup.rhtml +++ b/wui/src/app/views/layouts/popup.rhtml @@ -1,2 +1,7 @@ -<%# currently nothing for popups here. %> +
          +
          +
          <%= yield :title -%>
          +
          <%= yield :description -%>
          +
          <%= yield %> +
          diff --git a/wui/src/app/views/layouts/redux.rhtml b/wui/src/app/views/layouts/redux.rhtml index 72a49f8..63a9a56 100644 --- a/wui/src/app/views/layouts/redux.rhtml +++ b/wui/src/app/views/layouts/redux.rhtml @@ -27,6 +27,9 @@ <%= javascript_include_tag "ui.slider.js" -%> <%= javascript_include_tag "jquery.cookie.js" -%> <%= javascript_include_tag "jquery.form.js" -%> + + -
          - -
          -
          VM Resource Pool Quota
          -
          Statistics Data
          -
          -
          - - - - - - - <% resources = @vm_resource_pool.full_resources %> - <% for item in resources[:labels] %> - <% total_limit = resources[:total][item[1]] - total_limit = "unlimited" if total_limit.nil? %> - - - - - <% end %> -
          in use / awaiting use / total allowed
          <%= item[0]%>:<%= resources[:allocated][:current][item[1]] %> / <%= resources[:allocated][:pending][item[1]] %> / <%= total_limit %> - <%= item[2]%>
          - -
          -
          -
          - - -
          - -
          -
          - -
           

          Actions

          - <%if @can_modify -%> -
          - <%= link_to_if @vm_resource_pool, 'Create New VM', {:controller => "vm", :action => 'new', :vm_resource_pool_id => @vm_resource_pool}, { :class => "create" } %> -
          - <% end -%>
          <%if @is_hwpool_admin -%> <%= link_to 'Edit VM Resource Pool', { :action => 'edit', :id => @vm_resource_pool }, { :class => "edit" } %> diff --git a/wui/src/app/views/storage/_grid.rhtml b/wui/src/app/views/storage/_grid.rhtml index 56fb621..feb855a 100644 --- a/wui/src/app/views/storage/_grid.rhtml +++ b/wui/src/app/views/storage/_grid.rhtml @@ -7,13 +7,14 @@ $("#<%= table_id %>").flexigrid ( { - url: '<%= url_for :controller => "hardware", :action => "storage_pools_json", :id => hwpool_id %>', + url: '<%= url_for :controller => "hardware", :action => "storage_pools_json", :id => hwpool_id, :exclude_id => exclude_id %>', dataType: 'json', colModel : [ - {display: '', name : 'id', width : 20, sortable : false, align: 'left', process: <%= table_id %>checkbox}, - {display: 'Alias', name : 'display_name', width : 180, sortable : false, align: 'left'}, - {display: 'IP', name : 'ip_addr', width : 80, sortable : true, align: 'left'}, - {display: 'Type', name : 'type', width : 80, sortable : true, align: 'left'} + {display: '', width : 20, align: 'left', process: <%= table_id %>checkbox}, + {display: 'Alias', width : 180, align: 'left'}, + <%= "{display: 'Hardware Pool', name : 'pools.name', width : 100, align: 'left'}," if exclude_id %> + {display: 'IP', name : 'ip_addr', width : 80, align: 'left'}, + {display: 'Type', name : 'storage_pools.type', width : 80, align: 'left'} ], sortname: "ip_addr", sortorder: "asc", diff --git a/wui/src/app/views/storage/addstorage.html.erb b/wui/src/app/views/storage/addstorage.html.erb index a747502..e465d12 100644 --- a/wui/src/app/views/storage/addstorage.html.erb +++ b/wui/src/app/views/storage/addstorage.html.erb @@ -1,14 +1,17 @@ -
          -
          Add Storage
          -
          Select storage pools from the list below to add to the <%= @hardware_pool.name %> hardware pool.
          -
          +<%- content_for :title do -%> + Add Storage +<%- end -%> +<%- content_for :description do -%> + Select storage pools from the list below to add to the <%= @hardware_pool.name %> hardware pool. +<%- end -%> + +
          - <%= render :partial => "/storage/grid", :locals => { :table_id => "addstorage_unassigned_grid", - :hwpool_id => Pool.root.id, :on_select => "false" } %> - <%= render :partial => "/storage/grid", :locals => { :table_id => "addstorage_assigned_grid", - :hwpool_id => nil, :on_select => "false" } %> + <%= render :partial => "/storage/grid", :locals => { :table_id => "addstorage_grid", + :hwpool_id => nil, :exclude_id => @hardware_pool.id, + :on_select => "false" } %>
          - -<%= popup_footer("add_storage()", "Add Selected Storage Pools") %> +<%= popup_footer("add_storage('#{url_for :controller => 'hardware', + :action => 'add_storage', + :id => @hardware_pool}')", + "Add Selected Storage Pools") %> diff --git a/wui/src/app/views/storage/new.rhtml b/wui/src/app/views/storage/new.rhtml index 6f88ce3..13dedb9 100644 --- a/wui/src/app/views/storage/new.rhtml +++ b/wui/src/app/views/storage/new.rhtml @@ -1,51 +1,47 @@ -
          -
          Add New Storage Pool
          -
          Add a new Storage Pool to this oVirt server.
          -
          +<%- content_for :title do -%> + Add New Storage Pool +<%- end -%> +<%- content_for :description do -%> + Add a new Storage Pool to this oVirt server. +<%- end -%>
          <%= error_messages_for 'storage_pool' %> - <% form_tag do %> + <% form_tag do %> <%= hidden_field_tag 'hardware_pool_id', @hardware_pool.id %> - <%= select_tag_with_label "Storage Type:", 'storage_type', @storage_types, :onChange => "load_details()" %> + <%= select_tag_with_label "Storage Type:", 'storage_type', @storage_types, :onChange => "load_storage_subform()" %> <% end %>
          -
          -
          -
          -
          -<%= popup_footer("$('#storage_pool_form').submit()", "New Storage Pool") %> + +
          +
          +
          + <%= popup_footer("$('#storage_pool_form').submit()", "New Storage Pool") %> - + diff --git a/wui/src/app/views/vm/new.rhtml b/wui/src/app/views/vm/new.rhtml index 60dbcd6..767f806 100644 --- a/wui/src/app/views/vm/new.rhtml +++ b/wui/src/app/views/vm/new.rhtml @@ -1,12 +1,9 @@ -
          - +<%- content_for :title do -%> + Add Virtual Machine +<%- end -%> +<%- content_for :description do -%> +<%- end -%> - -
          -
          Add Virtual Machine
          -
          - -
          @@ -15,9 +12,6 @@ <%= popup_footer("$('#vm_form').submit()", "Add Virtual Machine") %> -
          - - -<%- content_for :title do -%> -<%= "New Virtual Machine" %> -<%- end -%> diff --git a/wui/src/public/javascripts/ovirt.js b/wui/src/public/javascripts/ovirt.js new file mode 100644 index 0000000..675f20d --- /dev/null +++ b/wui/src/public/javascripts/ovirt.js @@ -0,0 +1,138 @@ +// ovirt-specific javascript functions are defined here + + +// helper functions for dialogs and action links + + +// returns an array of selected values for flexigrid checkboxes +function get_selected_checkboxes(obj_form) +{ + var selected_array = new Array() + var selected_index = 0 + var checkboxes + if (obj_form.grid_checkbox) { + if (obj_form.grid_checkbox.length == undefined) { + checkboxes = [obj_form.grid_checkbox] + } else { + checkboxes = obj_form.grid_checkbox + } + for(var i=0; i < checkboxes.length; i++){ + if(checkboxes[i].checked) + { + selected_array[selected_index]= checkboxes[i].value + selected_index++ + } + } + } + return selected_array +} + + +// make sure that at least one item is selected to continue +function validate_selected(selected_array, name) +{ + if (selected_array.length == 0) { + alert("Please select at least one " + name + " to continue") + return false + } else { + return true + } +} + +function add_hosts(url) +{ + hosts= get_selected_checkboxes(document.addhosts_grid_form) + if (validate_selected(hosts, "host")) { + $.post(url, + { resource_ids: hosts.toString() }, + function(data,status){ + jQuery(document).trigger('close.facebox'); + $("#hosts_grid").flexReload() + if (data.alert) { + alert(data.alert); + } + }, 'json'); + } +} +function add_storage(url) +{ + storage= get_selected_checkboxes(document.addstorage_grid_form) + if (validate_selected(storage, "storage pool")) { + $.post(url, + { resource_ids: storage.toString() }, + function(data,status){ + jQuery(document).trigger('close.facebox'); + $("#storage_grid").flexReload() + if (data.alert) { + alert(data.alert); + } + }, 'json'); + } +} +// deal with ajax form response, filling in validation messages where required. +function ajax_validation(response, status) +{ + if (response.object) { + $(".fieldWithErrors").removeClass("fieldWithErrors"); + $("div.errorExplanation").remove(); + if (!response.success) { + for(i=0; i'+response.errors[i][1][j]+'
          '); + } + } + } + } + if (response.alert) { + alert(response.alert) + } + } +} + +// callback actions for dialog submissions +function afterHwPool(response, status){ + ajax_validation(response, status) + if (response.success) { + jQuery(document).trigger('close.facebox'); + // FIXME do we need to reload the tree here + + // this is for reloading the host/storage grid when + // adding hosts/storage to a new HW pool + if (response.resource_type) { + $('#' + response.resource_type + '_grid').flexReload() + } + // do we have HW pools grid? + //$("#vmpools_grid").flexReload() + } +} +function afterVmPool(response, status){ + ajax_validation(response, status) + if (response.success) { + jQuery(document).trigger('close.facebox'); + $("#vmpools_grid").flexReload() + } +} +function afterStoragePool(response, status){ + ajax_validation(response, status) + if (response.success) { + jQuery(document).trigger('close.facebox'); + $("#storage_grid").flexReload() + } +} +function afterPermission(response, status){ + ajax_validation(response, status) + if (response.success) { + jQuery(document).trigger('close.facebox'); + $("#users_grid").flexReload() + } +} +function afterVm(response, status){ + ajax_validation(response, status) + if (response.success) { + jQuery(document).trigger('close.facebox'); + $("#vms_grid").flexReload() + } +} diff --git a/wui/src/vendor/plugins/betternestedset/lib/#better_nested_set.rb# b/wui/src/vendor/plugins/betternestedset/lib/#better_nested_set.rb# deleted file mode 100644 index d430419..0000000 --- a/wui/src/vendor/plugins/betternestedset/lib/#better_nested_set.rb# +++ /dev/null @@ -1,583 +0,0 @@ -module SymetrieCom - module Acts #:nodoc: - module NestedSet #:nodoc: - def self.included(base) - base.extend(ClassMethods) - end - # This module provides an enhanced acts_as_nested_set mixin for ActiveRecord. - # Please see the README for background information, examples, and tips on usage. - module ClassMethods - # Configuration options are: - # * +parent_column+ - Column name for the parent/child foreign key (default: +parent_id+). - # * +left_column+ - Column name for the left index (default: +lft+). - # * +right_column+ - Column name for the right index (default: +rgt+). NOTE: - # Don't use +left+ and +right+, since these are reserved database words. - # * +scope+ - Restricts what is to be considered a tree. Given a symbol, it'll attach "_id" - # (if it isn't there already) and use that as the foreign key restriction. It's also possible - # to give it an entire string that is interpolated if you need a tighter scope than just a foreign key. - # Example: acts_as_nested_set :scope => 'tree_id = #{tree_id} AND completed = 0' - # * +text_column+ - Column name for the title field (optional). Used as default in the - # {your-class}_options_for_select helper method. If empty, will use the first string field - # of your model class. - def acts_as_nested_set(options = {}) - - options[:scope] = "#{options[:scope]}_id".intern if options[:scope].is_a?(Symbol) && options[:scope].to_s !~ /_id$/ - - write_inheritable_attribute(:acts_as_nested_set_options, - { :parent_column => (options[:parent_column] || 'parent_id'), - :left_column => (options[:left_column] || 'lft'), - :right_column => (options[:right_column] || 'rgt'), - :scope => (options[:scope] || '1 = 1'), - :text_column => (options[:text_column] || columns.collect{|c| (c.type == :string) ? c.name : nil }.compact.first), - :class => self # for single-table inheritance - } ) - - class_inheritable_reader :acts_as_nested_set_options - - if acts_as_nested_set_options[:scope].is_a?(Symbol) - scope_condition_method = %( - def scope_condition - if #{acts_as_nested_set_options[:scope].to_s}.nil? - "#{acts_as_nested_set_options[:scope].to_s} IS NULL" - else - "#{acts_as_nested_set_options[:scope].to_s} = \#{#{acts_as_nested_set_options[:scope].to_s}}" - end - end - ) - else - scope_condition_method = "def scope_condition() \"#{acts_as_nested_set_options[:scope]}\" end" - end - - # no bulk assignment - attr_protected acts_as_nested_set_options[:left_column].intern, - acts_as_nested_set_options[:right_column].intern, - acts_as_nested_set_options[:parent_column].intern - # no assignment to structure fields - module_eval <<-"end_eval", __FILE__, __LINE__ - def #{acts_as_nested_set_options[:left_column]}=(x) - raise ActiveRecord::ActiveRecordError, "Unauthorized assignment to #{acts_as_nested_set_options[:left_column]}: it's an internal field handled by acts_as_nested_set code, use move_to_* methods instead." - end - def #{acts_as_nested_set_options[:right_column]}=(x) - raise ActiveRecord::ActiveRecordError, "Unauthorized assignment to #{acts_as_nested_set_options[:right_column]}: it's an internal field handled by acts_as_nested_set code, use move_to_* methods instead." - end - def #{acts_as_nested_set_options[:parent_column]}=(x) - raise ActiveRecord::ActiveRecordError, "Unauthorized assignment to #{acts_as_nested_set_options[:parent_column]}: it's an internal field handled by acts_as_nested_set code, use move_to_* methods instead." - end - #{scope_condition_method} - end_eval - - - include SymetrieCom::Acts::NestedSet::InstanceMethods - extend SymetrieCom::Acts::NestedSet::ClassMethods - - # adds the helper for the class -# ActionView::Base.send(:define_method, "#{Inflector.underscore(self.class)}_options_for_select") { special=nil -# "#{acts_as_nested_set_options[:text_column]} || "#{self.class} id #{id}" -# } - - end - - - # Returns the single root for the class (or just the first root, if there are several). - # Deprecation note: the original acts_as_nested_set allowed roots to have parent_id = 0, - # so we currently do the same. This silliness will not be tolerated in future versions, however. - def root - acts_as_nested_set_options[:class].find(:first, :conditions => "(#{acts_as_nested_set_options[:parent_column]} IS NULL OR #{acts_as_nested_set_options[:parent_column]} = 0)") - end - - # Returns the roots and/or virtual roots of all trees. See the explanation of virtual roots in the README. - def roots - acts_as_nested_set_options[:class].find(:all, :conditions => "(#{acts_as_nested_set_options[:parent_column]} IS NULL OR #{acts_as_nested_set_options[:parent_column]} = 0)", :order => "#{acts_as_nested_set_options[:left_column]}") - end - - # Checks the left/right indexes of all records, - # returning the number of records checked. Throws ActiveRecord::ActiveRecordError if it finds a problem. - def check_all - total = 0 - transaction do - # if there are virtual roots, only call check_full_tree on the first, because it will check other virtual roots in that tree. - total = roots.inject(0) {|sum, r| sum + (r[r.left_col_name] == 1 ? r.check_full_tree : 0 )} - raise ActiveRecord::ActiveRecordError, "Scope problems or nodes without a valid root" unless acts_as_nested_set_options[:class].count == total - end - return total - end - - # Re-calculate the left/right values of all nodes. Can be used to convert ordinary trees into nested sets. - def renumber_all - scopes = [] - # only call it once for each scope_condition (if the scope conditions are messed up, this will obviously cause problems) - roots.each do |r| - r.renumber_full_tree unless scopes.include?(r.scope_condition) - scopes << r.scope_condition - end - end - - # Returns an SQL fragment that matches _items_ *and* all of their descendants, for use in a WHERE clause. - # You can pass it a single object, a single ID, or an array of objects and/or IDs. - # # if a.lft = 2, a.rgt = 7, b.lft = 12 and b.rgt = 13 - # Set.sql_for([a,b]) # returns "((lft BETWEEN 2 AND 7) OR (lft BETWEEN 12 AND 13))" - # Returns "1 != 1" if passed no items. If you need to exclude items, just use "NOT (#{sql_for(items)})". - # Note that if you have multiple trees, it is up to you to apply your scope condition. - def sql_for(items) - items = [items] unless items.is_a?(Array) - # get objects for IDs - items.collect! {|s| s.is_a?(acts_as_nested_set_options[:class]) ? s : acts_as_nested_set_options[:class].find(s)}.uniq - items.reject! {|e| e.new_record?} # exclude unsaved items, since they don't have left/right values yet - - return "1 != 1" if items.empty? # PostgreSQL didn't like '0', and SQLite3 didn't like 'FALSE' - items.map! {|e| "(#{acts_as_nested_set_options[:left_column]} BETWEEN #{e[acts_as_nested_set_options[:left_column]]} AND #{e[acts_as_nested_set_options[:right_column]]})" } - "(#{items.join(' OR ')})" - end - - end - - # This module provides instance methods for an enhanced acts_as_nested_set mixin. Please see the README for background information, examples, and tips on usage. - module InstanceMethods - # convenience methods to make the code more readable - def left_col_name()#:nodoc: - acts_as_nested_set_options[:left_column] - end - def right_col_name()#:nodoc: - acts_as_nested_set_options[:right_column] - end - def parent_col_name()#:nodoc: - acts_as_nested_set_options[:parent_column] - end - alias parent_column parent_col_name#:nodoc: Deprecated - def base_set_class()#:nodoc: - acts_as_nested_set_options[:class] # for single-table inheritance - end - - # On creation, automatically add the new node to the right of all existing nodes in this tree. - def before_create # already protected by a transaction - maxright = base_set_class.maximum(right_col_name, :conditions => scope_condition) || 0 - self[left_col_name] = maxright+1 - self[right_col_name] = maxright+2 - end - - # On destruction, delete all children and shift the lft/rgt values back to the left so the counts still work. - def before_destroy # already protected by a transaction - return if self[right_col_name].nil? || self[left_col_name].nil? - self.reload # in case a concurrent move has altered the indexes - dif = self[right_col_name] - self[left_col_name] + 1 - base_set_class.delete_all( "#{scope_condition} AND (#{left_col_name} BETWEEN #{self[left_col_name]} AND #{self[right_col_name]})" ) - base_set_class.update_all("#{left_col_name} = CASE \ - WHEN #{left_col_name} > #{self[right_col_name]} THEN (#{left_col_name} - #{dif}) \ - ELSE #{left_col_name} END, \ - #{right_col_name} = CASE \ - WHEN #{right_col_name} > #{self[right_col_name]} THEN (#{right_col_name} - #{dif} ) \ - ELSE #{right_col_name} END", - scope_condition) - end - - # By default, records are compared and sorted using the left column. - def <=>(x) - self[left_col_name] <=> x[left_col_name] - end - - # Deprecated. Returns true if this is a root node. - def root? - parent_id = self[parent_col_name] - (parent_id == 0 || parent_id.nil?) && self[right_col_name] && self[left_col_name] && (self[right_col_name] > self[left_col_name]) - end - - # Deprecated. Returns true if this is a child node - def child? - parent_id = self[parent_col_name] - !(parent_id == 0 || parent_id.nil?) && (self[left_col_name] > 1) && (self[right_col_name] > self[left_col_name]) - end - - # Deprecated. Returns true if we have no idea what this is - def unknown? - !root? && !child? - end - - # Returns this record's root ancestor. - def root - # the BETWEEN clause is needed to ensure we get the right virtual root, if using those - base_set_class.find(:first, :conditions => "#{scope_condition} \ - AND (#{parent_col_name} IS NULL OR #{parent_col_name} = 0) AND (#{self[left_col_name]} BETWEEN #{left_col_name} AND #{right_col_name})") - end - - # Returns the root or virtual roots of this record's tree (a tree cannot have more than one real root). See the explanation of virtual roots in the README. - def roots - base_set_class.find(:all, :conditions => "#{scope_condition} AND (#{parent_col_name} IS NULL OR #{parent_col_name} = 0)", :order => "#{left_col_name}") - end - - # Returns this record's parent. - def parent - base_set_class.find(self[parent_col_name]) if self[parent_col_name] - end - - # Returns an array of all parents, starting with the root. - def ancestors - self_and_ancestors - [self] - end - - # Returns an array of all parents plus self, starting with the root. - def self_and_ancestors - base_set_class.find(:all, :conditions => "#{scope_condition} AND (#{self[left_col_name]} BETWEEN #{left_col_name} AND #{right_col_name})", :order => left_col_name ) - end - - # Returns all the children of this node's parent, except self. - def siblings - self_and_siblings - [self] - end - - # Returns all the children of this node's parent, including self. - def self_and_siblings - if self[parent_col_name].nil? || self[parent_col_name].zero? - [self] - else - base_set_class.find(:all, :conditions => "#{scope_condition} AND #{parent_col_name} = #{self[parent_col_name]}", :order => left_col_name) - end - end - - # Returns the level of this object in the tree, root level being 0. - def level - return 0 if self[parent_col_name].nil? - base_set_class.count(:conditions => "#{scope_condition} AND (#{self[left_col_name]} BETWEEN #{left_col_name} AND #{right_col_name})") - 1 - end - - # Returns the number of nested children of this object. - def all_children_count - return (self[right_col_name] - self[left_col_name] - 1)/2 - end - - # Returns itself and all nested children. - # Pass :exclude => item, or id, or [items or id] to exclude one or more items *and* all of their descendants. - def full_set(special=nil) - if special && special[:exclude] - exclude_str = " AND NOT (#{base_set_class.sql_for(special[:exclude])}) " - elsif new_record? || self[right_col_name] - self[left_col_name] == 1 - return [self] - endas - base_set_class.find(:all, :conditions => "#{scope_condition} #{exclude_str} AND (#{left_col_name} BETWEEN #{self[left_col_name]} AND #{self[right_col_name]})", :order => left_col_name) - end - - # Returns all children and nested children. - # Pass :exclude => item, or id, or [items or id] to exclude one or more items *and* all of their descendants. - def all_children(special=nil) - full_set(special) - [self] - end - - # Returns this record's immediate children. - def children - base_set_class.find(:all, :conditions => "#{scope_condition} AND #{parent_col_name} = #{self.id}", :order => left_col_name) - end - - # Deprecated - alias direct_children children - - # Returns this record's terminal children (nodes without children). - def leaves - base_set_class.find(:all, :conditions => "#{scope_condition} AND (#{left_col_name} BETWEEN #{self[left_col_name]} AND #{self[right_col_name]}) AND #{left_col_name} + 1 = #{right_col_name}", :order => left_col_name) - end - - # Returns the count of this record's terminal children (nodes without children). - def leaves_count - base_set_class.count(:conditions => "#{scope_condition} AND (#{left_col_name} BETWEEN #{self[left_col_name]} AND #{self[right_col_name]}) AND #{left_col_name} + 1 = #{right_col_name}") - end - - # Checks the left/right indexes of one node and all descendants. - # Throws ActiveRecord::ActiveRecordError if it finds a problem. - def check_subtree - transaction do - self.reload - check # this method is implemented via #check, so that we don't generate lots of unnecessary nested transactions - end - end - - # Checks the left/right indexes of the entire tree that this node belongs to, - # returning the number of records checked. Throws ActiveRecord::ActiveRecordError if it finds a problem. - # This method is needed because check_subtree alone cannot find gaps between virtual roots, orphaned nodes or endless loops. - def check_full_tree - total_nodes = 0 - transaction do - # virtual roots make this method more complex than it otherwise would be - n = 1 - roots.each do |r| - raise ActiveRecord::ActiveRecordError, "Gaps between roots in the tree containing record ##{r.id}" if r[left_col_name] != n - r.check_subtree - n = r[right_col_name] + 1 - end - total_nodes = roots.inject(0) {|sum, r| sum + r.all_children_count + 1 } - unless base_set_class.count(:conditions => "#{scope_condition}") == total_nodes - raise ActiveRecord::ActiveRecordError, "Orphaned nodes or endless loops in the tree containing record ##{self.id}" - end - end - return total_nodes - end - - # Re-calculate the left/right values of all nodes in this record's tree. Can be used to convert an ordinary tree into a nested set. - def renumber_full_tree - indexes = [] - n = 1 - transaction do - for r in roots # because we may have virtual roots - n = r.calc_numbers(n, indexes) - end - for i in indexes - base_set_class.update_all("#{left_col_name} = #{i[:lft]}, #{right_col_name} = #{i[:rgt]}", "#{self.class.primary_key} = #{i[:id]}") - end - end - ## reload? - end - - # Deprecated. Adds a child to this object in the tree. If this object hasn't been initialized, - # it gets set up as a root node. - # - # This method exists only for compatibility and will be removed in future versions. - def add_child(child) - transaction do - self.reload; child.reload # for compatibility with old version - # the old version allows records with nil values for lft and rgt - unless self[left_col_name] && self[right_col_name] - if child[left_col_name] || child[right_col_name] - raise ActiveRecord::ActiveRecordError, "If parent lft or rgt are nil, you can't add a child with non-nil lft or rgt" - end - base_set_class.update_all("#{left_col_name} = CASE \ - WHEN id = #{self.id} \ - THEN 1 \ - WHEN id = #{child.id} \ - THEN 3 \ - ELSE #{left_col_name} END, \ - #{right_col_name} = CASE \ - WHEN id = #{self.id} \ - THEN 2 \ - WHEN id = #{child.id} \ - THEN 4 \ - ELSE #{right_col_name} END", - scope_condition) - self.reload; child.reload - end - unless child[left_col_name] && child[right_col_name] - maxright = base_set_class.maximum(right_col_name, :conditions => scope_condition) || 0 - base_set_class.update_all("#{left_col_name} = CASE \ - WHEN id = #{child.id} \ - THEN #{maxright + 1} \ - ELSE #{left_col_name} END, \ - #{right_col_name} = CASE \ - WHEN id = #{child.id} \ - THEN #{maxright + 2} \ - ELSE #{right_col_name} END", - scope_condition) - child.reload - end - - child.move_to_child_of(self) - # self.reload ## even though move_to calls target.reload, at least one object in the tests was not reloading (near the end of test_common_usage) - end - # self.reload - # child.reload - # - # if child.root? - # raise ActiveRecord::ActiveRecordError, "Adding sub-tree isn\'t currently supported" - # else - # if ( (self[left_col_name] == nil) || (self[right_col_name] == nil) ) - # # Looks like we're now the root node! Woo - # self[left_col_name] = 1 - # self[right_col_name] = 4 - # - # # What do to do about validation? - # return nil unless self.save - # - # child[parent_col_name] = self.id - # child[left_col_name] = 2 - # child[right_col_name]= 3 - # return child.save - # else - # # OK, we need to add and shift everything else to the right - # child[parent_col_name] = self.id - # right_bound = self[right_col_name] - # child[left_col_name] = right_bound - # child[right_col_name] = right_bound + 1 - # self[right_col_name] += 2 - # self.class.transaction { - # self.class.update_all( "#{left_col_name} = (#{left_col_name} + 2)", "#{scope_condition} AND #{left_col_name} >= #{right_bound}" ) - # self.class.update_all( "#{right_col_name} = (#{right_col_name} + 2)", "#{scope_condition} AND #{right_col_name} >= #{right_bound}" ) - # self.save - # child.save - # } - # end - # end - end - - # Move this node to the left of _target_ (you can pass an object or just an id). - # Unsaved changes in either object will be lost. Raises ActiveRecord::ActiveRecordError if it encounters a problem. - def move_to_left_of(target) - self.move_to target, :left - end - - # Move this node to the right of _target_ (you can pass an object or just an id). - # Unsaved changes in either object will be lost. Raises ActiveRecord::ActiveRecordError if it encounters a problem. - def move_to_right_of(target) - self.move_to target, :right - end - - # Make this node a child of _target_ (you can pass an object or just an id). - # Unsaved changes in either object will be lost. Raises ActiveRecord::ActiveRecordError if it encounters a problem. - def move_to_child_of(target) - self.move_to target, :child - end - - protected - def move_to(target, position) #:nodoc: - raise ActiveRecord::ActiveRecordError, "You cannot move a new node" if new_record? - raise ActiveRecord::ActiveRecordError, "You cannot move a node if left or right is nil" unless self[left_col_name] && self[right_col_name] - - transaction do - self.reload # the lft/rgt values could be stale (target is reloaded below) - if target.is_a?(base_set_class) - target.reload # could be stale - else - target = base_set_class.find(target) # load object if we were given an ID - end - - if (target[left_col_name] >= self[left_col_name]) && (target[right_col_name] <= self[right_col_name]) - raise ActiveRecord::ActiveRecordError, "Impossible move, target node cannot be inside moved tree." - end - - # prevent moves between different trees - if target.scope_condition != scope_condition - raise ActiveRecord::ActiveRecordError, "Scope conditions do not match. Is the target in the same tree?" - end - - # the move: we just need to define two adjoining segments of the left/right index and swap their positions - bound = case position - when :child then target[right_col_name] - when :left then target[left_col_name] - when :right then target[right_col_name] + 1 - else raise ActiveRecord::ActiveRecordError, "Position should be :child, :left or :right ('#{position}' received)." - end - - if bound > self[right_col_name] - bound = bound - 1 - other_bound = self[right_col_name] + 1 - else - other_bound = self[left_col_name] - 1 - end - - return if bound == self[right_col_name] || bound == self[left_col_name] # there would be no change, and other_bound is now wrong anyway - - # we have defined the boundaries of two non-overlapping intervals, - # so sorting puts both the intervals and their boundaries in order - a, b, c, d = [self[left_col_name], self[right_col_name], bound, other_bound].sort - - # change nil to NULL for new parent - if position == :child - new_parent = target.id - else - new_parent = target[parent_col_name].nil? ? 'NULL' : target[parent_col_name] - end - - base_set_class.update_all("\ - #{left_col_name} = CASE \ - WHEN #{left_col_name} BETWEEN #{a} AND #{b} THEN #{left_col_name} + #{d - b} \ - WHEN #{left_col_name} BETWEEN #{c} AND #{d} THEN #{left_col_name} + #{a - c} \ - ELSE #{left_col_name} END, \ - #{right_col_name} = CASE \ - WHEN #{right_col_name} BETWEEN #{a} AND #{b} THEN #{right_col_name} + #{d - b} \ - WHEN #{right_col_name} BETWEEN #{c} AND #{d} THEN #{right_col_name} + #{a - c} \ - ELSE #{right_col_name} END, \ - #{parent_col_name} = CASE \ - WHEN #{self.class.primary_key} = #{self.id} THEN #{new_parent} \ - ELSE #{parent_col_name} END", - scope_condition) - self.reload - target.reload - end - end - - def check #:nodoc: - # performance improvements (3X or more for tables with lots of columns) by using :select to load just id, lft and rgt - ## i don't use the scope condition here, because it shouldn't be needed - my_children = base_set_class.find(:all, :conditions => "#{parent_col_name} = #{self.id}", - :order => left_col_name, :select => "#{self.class.primary_key}, #{left_col_name}, #{right_col_name}") - - if my_children.empty? - unless self[left_col_name] && self[right_col_name] - raise ActiveRecord::ActiveRecordError, "#{self.class.name}##{self.id}.#{right_col_name} or #{left_col_name} is blank" - end - unless self[right_col_name] - self[left_col_name] == 1 - raise ActiveRecord::ActiveRecordError, "#{self.class.name}##{self.id}.#{right_col_name} should be 1 greater than #{left_col_name}" - end - else - n = self[left_col_name] - for c in (my_children) # the children come back ordered by lft - unless c[left_col_name] && c[right_col_name] - raise ActiveRecord::ActiveRecordError, "#{self.class.name}##{c.id}.#{right_col_name} or #{left_col_name} is blank" - end - unless c[left_col_name] == n + 1 - raise ActiveRecord::ActiveRecordError, "#{self.class.name}##{c.id}.#{left_col_name} should be 1 greater than #{n}" - end - c.check - n = c[right_col_name] - end - unless self[right_col_name] == n + 1 - raise ActiveRecord::ActiveRecordError, "#{self.class.name}##{self.id}.#{right_col_name} should be 1 greater than #{n}" - end - end - end - - # used by the renumbering methods - def calc_numbers(n, indexes) #:nodoc: - my_lft = n - # performance improvements (3X or more for tables with lots of columns) by using :select to load just id, lft and rgt - ## i don't use the scope condition here, because it shouldn't be needed - my_children = base_set_class.find(:all, :conditions => "#{parent_col_name} = #{self.id}", - :order => left_col_name, :select => "#{self.class.primary_key}, #{left_col_name}, #{right_col_name}") - if my_children.empty? - my_rgt = (n += 1) - else - for c in (my_children) - n = c.calc_numbers(n + 1, indexes) - end - my_rgt = (n += 1) - end - indexes << {:id => self.id, :lft => my_lft, :rgt => my_rgt} unless self[left_col_name] == my_lft && self[right_col_name] == my_rgt - return n - end - - - - # The following code is my crude method of making things concurrency-safe. - # Basically, we need to ensure that whenever a record is saved, the lft/rgt - # values are _not_ written to the database, because if any changes to the tree - # structure occurrred since the object was loaded, the lft/rgt values could - # be out of date and corrupt the indexes. - # I hope that someone with a little more ruby-foo can look at this and come - # up with a more elegant solution. - private - # override ActiveRecord to prevent lft/rgt values from being saved (can corrupt indexes under concurrent usage) - def update #:nodoc: - connection.update( - "UPDATE #{self.class.table_name} " + - "SET #{quoted_comma_pair_list(connection, special_attributes_with_quotes(false))} " + - "WHERE #{self.class.primary_key} = #{quote_value(id)}", - "#{self.class.name} Update" - ) - end - - # exclude the lft/rgt columns from update statements - def special_attributes_with_quotes(include_primary_key = true) #:nodoc: - attributes.inject({}) do |quoted, (name, value)| - if column = column_for_attribute(name) - quoted[name] = quote_value(value, column) unless (!include_primary_key && column.primary) || [acts_as_nested_set_options[:left_column], acts_as_nested_set_options[:right_column]].include?(column.name) - end - quoted - end - end - - # i couldn't figure out how to call attributes_with_quotes without cutting and pasting this private method in. :( - # Quote strings appropriately for SQL statements. - def quote_value(value, column = nil) #:nodoc: - self.class.connection.quote(value, column) - end - - end - end - end -end - - diff --git a/wui/src/vendor/plugins/betternestedset/lib/better_nested_set.rb b/wui/src/vendor/plugins/betternestedset/lib/better_nested_set.rb index 43b46ca..ed5d3e3 100644 --- a/wui/src/vendor/plugins/betternestedset/lib/better_nested_set.rb +++ b/wui/src/vendor/plugins/betternestedset/lib/better_nested_set.rb @@ -246,24 +246,33 @@ module SymetrieCom # Returns itself and all nested children. # Pass :exclude => item, or id, or [items or id] to exclude one or more items *and* all of their descendants. - def full_set(special=nil) - if special && special[:exclude] - exclude_str = " AND NOT (#{base_set_class.sql_for(special[:exclude])}) " + # in addition to the standard find opts + def full_set(find_opts={}) + exclude = find_opts.delete(:exclude) + if exclude + exclude_str = " AND NOT (#{base_set_class.sql_for(exclude)}) " elsif new_record? || self[right_col_name] - self[left_col_name] == 1 return [self] end - base_set_class.find(:all, :conditions => "#{scope_condition} #{exclude_str} AND (#{left_col_name} BETWEEN #{self[left_col_name]} AND #{self[right_col_name]})", :order => left_col_name) + opts = merge_incoming_opts({:conditions => "#{scope_condition} #{exclude_str} AND (#{left_col_name} BETWEEN #{self[left_col_name]} AND #{self[right_col_name]})", + :order => left_col_name}, + find_opts) + base_set_class.find(:all, opts) end # Returns all children and nested children. # Pass :exclude => item, or id, or [items or id] to exclude one or more items *and* all of their descendants. - def all_children(special=nil) - full_set(special) - [self] + # in addition to the standard find opts + def all_children(find_opts=nil) + full_set(find_opts) - [self] end # Returns this record's immediate children. - def children - base_set_class.find(:all, :conditions => "#{scope_condition} AND #{parent_col_name} = #{self.id}", :order => left_col_name) + def children(find_opts={}) + opts = merge_incoming_opts({:conditions => "#{scope_condition} AND #{parent_col_name} = #{self.id}", + :order => left_col_name}, + find_opts) + base_set_class.find(:all, opts) end # Deprecated @@ -575,6 +584,14 @@ module SymetrieCom self.class.connection.quote(value, column) end + # accept incoming opts to allow filtering of results. + # So far only tested in limited use cases encountered in oVirt devel. + def merge_incoming_opts(set_opts, incoming_opts) + new_conditions = incoming_opts.delete(:conditions) + set_opts[:conditions] = "(#{set_opts[:conditions]}) AND (#{new_conditions})" if new_conditions + set_opts.merge(incoming_opts) + end + end end end -- 1.5.4.1 --------------040805000303080804070604-- From sseago at redhat.com Fri May 30 16:43:28 2008 From: sseago at redhat.com (Scott Seago) Date: Fri, 30 May 2008 12:43:28 -0400 Subject: [Ovirt-devel] [Patch] HW pool quota add/edit/delete/view Message-ID: <48402EB0.1090005@redhat.com> -------------- next part -------------- A non-text attachment was scrubbed... Name: hw-pool-quota.patch Type: text/x-patch Size: 21304 bytes Desc: not available URL: From sseago at redhat.com Fri May 30 17:11:49 2008 From: sseago at redhat.com (Scott Seago) Date: Fri, 30 May 2008 13:11:49 -0400 Subject: [Ovirt-devel] [Patch] VM pool quota add/edit Message-ID: <48403555.4020209@redhat.com> -------------- next part -------------- A non-text attachment was scrubbed... Name: vm-pool-quota.patch Type: text/x-patch Size: 3397 bytes Desc: not available URL: From hbrock at redhat.com Fri May 30 17:15:26 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Fri, 30 May 2008 13:15:26 -0400 Subject: [Ovirt-devel] [Patch] HW pool quota add/edit/delete/view In-Reply-To: <48402EB0.1090005@redhat.com> References: <48402EB0.1090005@redhat.com> Message-ID: <20080530171525.GB27672@redhat.com> On Fri, May 30, 2008 at 12:43:28PM -0400, Scott Seago wrote: > > >From f76391b8b1b2e21875fdb3cb8c541e6a70ecb7ee Mon Sep 17 00:00:00 2001 > From: Scott Seago > Date: Fri, 30 May 2008 12:39:40 -0400 > Subject: [PATCH] added default quota to HW pool form. it can be edited/deleted too... > > > Signed-off-by: Scott Seago > --- > wui/src/app/controllers/hardware_controller.rb | 10 +++ > wui/src/app/controllers/quota_controller.rb | 38 +++++++----- > wui/src/app/helpers/application_helper.rb | 1 - > wui/src/app/views/hardware/quick_summary.rhtml | 56 ++++++++++++++++++ > wui/src/app/views/hardware/show.html.erb | 15 +++++ > wui/src/app/views/host/show.rhtml | 13 +++-- > wui/src/app/views/layouts/redux.rhtml | 5 +- > wui/src/app/views/layouts/selection.rhtml | 28 ++++++++- > wui/src/app/views/quota/_form.rhtml | 2 +- > wui/src/app/views/quota/edit.rhtml | 68 +++++++++++----------- > wui/src/app/views/quota/new.rhtml | 71 +++++++++++------------ > wui/src/app/views/resources/quick_summary.rhtml | 8 +- > wui/src/app/views/resources/show.rhtml | 9 ++- > wui/src/public/images/icon_edit.png | Bin 0 -> 375 bytes > wui/src/public/images/icon_separator.png | Bin 0 -> 216 bytes > wui/src/public/images/icon_x.png | Bin 0 -> 340 bytes > wui/src/public/javascripts/ovirt.js | 12 ++++ > wui/src/public/stylesheets/layout.css | 31 ++++++++++ > 18 files changed, 260 insertions(+), 107 deletions(-) > create mode 100644 wui/src/app/views/hardware/quick_summary.rhtml > create mode 100644 wui/src/public/images/icon_edit.png > create mode 100644 wui/src/public/images/icon_separator.png > create mode 100644 wui/src/public/images/icon_x.png > > diff --git a/wui/src/app/controllers/hardware_controller.rb b/wui/src/app/controllers/hardware_controller.rb > index 0f0c904..0eaf76f 100644 > --- a/wui/src/app/controllers/hardware_controller.rb > +++ b/wui/src/app/controllers/hardware_controller.rb > @@ -225,6 +225,16 @@ class HardwareController < ApplicationController > render :json => graph_object > end > > + def quick_summary > + pre_show > + set_perms(@perm_obj) > + unless @can_view > + flash[:notice] = 'You do not have permission to view this Hardware Pool: redirecting to top level' > + redirect_to :action => 'list' > + end > + render :layout => 'selection' > + end > + > def hosts_json > if params[:id] > pre_json > diff --git a/wui/src/app/controllers/quota_controller.rb b/wui/src/app/controllers/quota_controller.rb > index d865529..cfedf2d 100644 > --- a/wui/src/app/controllers/quota_controller.rb > +++ b/wui/src/app/controllers/quota_controller.rb > @@ -38,39 +38,45 @@ class QuotaController < ApplicationController > end > > def new > + render :layout => 'popup' > end > > def create > - if @quota.save > - flash[:notice] = 'Quota was successfully created.' > - redirect_to_parent > - else > - render :action => 'new' > + begin > + @quota.save! > + render :json => { :object => "quota", :success => true, > + :alert => "Quota was successfully created." } > + rescue > + render :json => { :object => "quota", :success => false, > + :errors => @quota.errors.localize_error_messages.to_a} > end > end > > def edit > + render :layout => 'popup' > end > > def update > - if @quota.update_attributes(params[:quota]) > - flash[:notice] = 'Quota was successfully updated.' > - redirect_to_parent > - else > - render :action => 'edit' > + begin > + @quota.update_attributes!(params[:quota]) > + render :json => { :object => "quota", :success => true, > + :alert => "Quota was successfully updated." } > + rescue > + render :json => { :object => "quota", :success => false, > + :errors => @quota.errors.localize_error_messages.to_a} > end > end > > def destroy > pool = @quota.pool > - unless @quota.destroy > - flash[:notice] = 'destroying quota failed ' > - end > - if pool > - redirect_to :controller => pool.get_controller, :action => 'show', :id => pool.id > + if @quota.destroy > + alert="Quota was successfully deleted." > + success=true > else > - redirect_to :controller => 'dashboard' > + alert="Failed to delete quota." > + success=false > end > + render :json => { :object => "quota", :success => success, :alert => alert } > end > > protected > diff --git a/wui/src/app/helpers/application_helper.rb b/wui/src/app/helpers/application_helper.rb > index 20c344f..75b6195 100644 > --- a/wui/src/app/helpers/application_helper.rb > +++ b/wui/src/app/helpers/application_helper.rb > @@ -106,7 +106,6 @@ module ApplicationHelper > } > end > > - > def timeout_flash(name) > %{ > > + > + > + <% resources = @pool.full_resources %> > +
          > +
          > + <% for item in resources[:labels] %> > + <% total_limit = resources[:total][item[1]] > + total_limit = "unlimited" if total_limit.nil? %> > + <%= item[0]%>:
          > + <% end %> > +
          > +
          > + default allowed
          > + <% for item in resources[:labels] %> > + <% total_limit = resources[:total][item[1]] > + total_limit = "unlimited" if total_limit.nil? %> > + <%= total_limit %> > + <%= item[2]%>
          > + <% end %> > +
          > diff --git a/wui/src/app/views/hardware/show.html.erb b/wui/src/app/views/hardware/show.html.erb > index 81bb708..b52243b 100644 > --- a/wui/src/app/views/hardware/show.html.erb > +++ b/wui/src/app/views/hardware/show.html.erb > @@ -1,4 +1,5 @@ >
          > +
          > >
             <%= @pool.name %>

          > > @@ -102,4 +103,18 @@ > > > > +
          > +
          > +
          > +
          Hardware pool quota details.
          >
          > +<%- content_for :scripts do -%> > + > +<%- end -%> > diff --git a/wui/src/app/views/host/show.rhtml b/wui/src/app/views/host/show.rhtml > index dbc9028..c50d511 100644 > --- a/wui/src/app/views/host/show.rhtml > +++ b/wui/src/app/views/host/show.rhtml > @@ -1,5 +1,7 @@ > -
          > -
          <%=h @host.hostname %>
          > +<%- content_for :title do -%> > + <%=h @host.hostname %> > +<%- end -%> > + >
          > UUID:
          > CPUs:
          > @@ -22,7 +24,7 @@ > disabled > <% end -%> >
          > -
          > + > >
          > -
          > + > +<%- content_for :right do -%> >
          > > Load > @@ -62,5 +65,5 @@ > :chartType => 'line', > :yGridLines => 'lightgrey', > :url => (url_for :controller => 'graph', :action => 'graph', :type => 'detail') } %> > -
          > +<%- end -%> > > diff --git a/wui/src/app/views/layouts/redux.rhtml b/wui/src/app/views/layouts/redux.rhtml > index 63a9a56..a40cb1f 100644 > --- a/wui/src/app/views/layouts/redux.rhtml > +++ b/wui/src/app/views/layouts/redux.rhtml > @@ -43,10 +43,7 @@ > }) > }); > $(document).ready(function(){ > - $('a[rel*=facebox]').facebox() > - }) > - $(document).ready(function(){ > - $('a[rel*=close]').trigger('close.facebox') > + refresh_facebox() > }) > > <%= yield :scripts -%> > diff --git a/wui/src/app/views/layouts/selection.rhtml b/wui/src/app/views/layouts/selection.rhtml > index 736517c..ff9583b 100644 > --- a/wui/src/app/views/layouts/selection.rhtml > +++ b/wui/src/app/views/layouts/selection.rhtml > @@ -1,2 +1,26 @@ > -<%# currently nothing for popups here. %> > -<%= yield %> > +
          > +
          <%= yield :title -%>
          > + > + <% tools = yield :action_links -%> > + <% if tools %> > +
            > +
          • > + <%= image_tag "icon_separator.png", :style=>"vertical-align: middle;" %> > +
          • > + <%= tools -%> > +
          > + <% end %> > +
          > + > + <%= yield %> > + > +
          > +<% right = yield :right -%> > +<% if right %> > +
          > + <%= right -%> > +
          > +<% end %> > + > \ No newline at end of file > diff --git a/wui/src/app/views/quota/_form.rhtml b/wui/src/app/views/quota/_form.rhtml > index 88d9adc..ac55550 100644 > --- a/wui/src/app/views/quota/_form.rhtml > +++ b/wui/src/app/views/quota/_form.rhtml > @@ -1,7 +1,7 @@ > <%= error_messages_for 'quota' %> > > > -<%= hidden_field_with_label (@quota.pool[:type] == "HardwarePool" ? "Hardware Pool" : "VM Resource Pool"), 'quota', 'pool_id', @quota.pool.name %> > +<%= hidden_field 'quota', 'pool_id' %> > > <%= text_field_with_label "Total Virtual CPUs", 'quota', 'total_vcpus' %> > > diff --git a/wui/src/app/views/quota/edit.rhtml b/wui/src/app/views/quota/edit.rhtml > index 30db6b7..d2f4be0 100644 > --- a/wui/src/app/views/quota/edit.rhtml > +++ b/wui/src/app/views/quota/edit.rhtml > @@ -1,35 +1,37 @@ > -
          > - > -
          > -
          > - > -
          > - <% form_tag :action => 'update', :id => @quota do %> > - <%= render :partial => 'form' %> > - <%= submit_tag 'Edit' %> > - <% end %> > -
          > - > -
          > -
          > - > -
          > - > -
          > -

          Actions

          > - > - <%if @can_modify -%> > -
          > - <%= link_to 'Remove Quota (unlimited)', { :controller => 'quota', :action => 'destroy', :id => @quota }, { :confirm => 'Are you sure?', :method=> :post, :class => "edit" } %> > -
          > - <%- end -%> > - > -
          > - <%= link_to "Back to #{@quota.pool.name}", { :controller => @quota.pool.get_controller, :action => 'show', :id => @quota.pool }, { :class => "show" } %> > -
          > - > -
          > - > <%- content_for :title do -%> > -<%= _("Editing Quota") %> > + Edit Quota > <%- end -%> > +<%- content_for :description do -%> > + Edit the quota for <%= @quota.pool.name %>. > +<%- end -%> > + > +
          > +
          > + <%= hidden_field_tag 'id', @quota.id %> > + <%= render :partial => 'form' %> > +
          > +<%= popup_footer("$('#quota_form').submit()", "Edit Quota") %> > +
          > + > + > diff --git a/wui/src/app/views/quota/new.rhtml b/wui/src/app/views/quota/new.rhtml > index 7473884..861d74f 100644 > --- a/wui/src/app/views/quota/new.rhtml > +++ b/wui/src/app/views/quota/new.rhtml > @@ -1,39 +1,36 @@ > -
          > -
          > - > -
          > - > -
          > -
          > - > -
          > - > - <% form_tag :action => 'create' do %> > - <%= render :partial => 'form' %> > - <%= submit_tag "Create" %> > - <% end %> > -
          > - > -
          > -
          > - > -
          > - > -
          > -
          > - > - > - > -
           
          > -
          > -

          Actions

          > -
          > - <%= link_to "Back to #{@quota.pool.name}", { :controller => @quota.pool.get_controller, :action => 'show', :id => @quota.pool }, { :class => "show" } %> > -
          > -
          > - > - > - > <%- content_for :title do -%> > -<%= _("New Quota") %> > + Add New Quota > +<%- end -%> > +<%- content_for :description do -%> > + Add a quota for <%= @quota.pool.name %>. > <%- end -%> > + > +
          > +
          > + <%= render :partial => 'form' %> > +
          > +<%= popup_footer("$('#quota_form').submit()", "Create Quota") %> > +
          > + > + > diff --git a/wui/src/app/views/resources/quick_summary.rhtml b/wui/src/app/views/resources/quick_summary.rhtml > index 3bdeefa..e71d9c9 100644 > --- a/wui/src/app/views/resources/quick_summary.rhtml > +++ b/wui/src/app/views/resources/quick_summary.rhtml > @@ -1,6 +1,7 @@ > -
          > -
          <%=h @vm_resource_pool.name %> quota
          > - > +<%- content_for :title do -%> > + <%=h @vm_resource_pool.name %> quota > +<%- end -%> > + > <% resources = @vm_resource_pool.full_resources %> >
          >
          > @@ -19,4 +20,3 @@ > <%= item[2]%>
          > <% end %> >
          > -
          > diff --git a/wui/src/app/views/resources/show.rhtml b/wui/src/app/views/resources/show.rhtml > index ecf8fc6..64bd019 100644 > --- a/wui/src/app/views/resources/show.rhtml > +++ b/wui/src/app/views/resources/show.rhtml > @@ -40,7 +40,7 @@ > > >
          > -
          Select a VM pool above.
          > +
          VM pool quota details.
          >
          > > <%- content_for :title do -%> > @@ -50,9 +50,10 @@ > <%- content_for :scripts do -%> > > > diff --git a/wui/src/public/images/icon_edit.png b/wui/src/public/images/icon_edit.png > new file mode 100644 > index 0000000000000000000000000000000000000000..aaf2459f2e31ee73a7fff3e324d2825e4fca1e65 > GIT binary patch > literal 375 > zcmeAS at N?(olHy`uVBq!ia0vp^0zk~e!3HF=pW8M9DVAa<&kznEsNqQI0P;BtJR*x3 > z7`Q%wFr(8NlNmrk(Gu5)66d1S#FEVXJcW?V+*AfreIrYK0}CgYnWjJmG9U%P`DrEP > ziAAXljw$&`sS0kHMXBZaMcKs)&cVhruDLM-)m`v(aSYLzICYY3-XRA8H~D>xw%a|D > zgO at M)ThkJw;OaGpc})@jHk0%lYl~U}mM&c6;r at B4LxjXn_AsfnCf4sW)3$J@^(_&* > z!7$(O*s-$rduKHMEwsulJMjA92G&`>X9YH at Oiw*|x`^|@?T;Nx-a0pF$ApTSI-IMS > zfBuNX_h8xb5BL3(mrqr-Y)SBB<4M>pzPNy^WRkXxrbJWl0``6`xmI at 8Nm14}{roh2 > z4mme9omN+Te&*@F)W3WOlFA-COe|iuZvU<$#s$}}`fk~Lv|RZQ^UZCi<#~2Lx&rhY > NgQu&X%Q~loCII`8jh_Gj > > literal 0 > HcmV?d00001 > > diff --git a/wui/src/public/images/icon_separator.png b/wui/src/public/images/icon_separator.png > new file mode 100644 > index 0000000000000000000000000000000000000000..225fd6e2ab616d20cfd99837a53cce1049185155 > GIT binary patch > literal 216 > zcmeAS at N?(olHy`uVBq!ia0vp^LO{&J!3HGrh2HJ~QY^(zo*^7SP{WbZ0pxQQctjR6 > zFmQbUVMeDlCNqG7q9v{oCC){ui6xo&c?uz!xv31M`bL)e1{O{(GfjaCWIzgn^V3So > z6N^$A98>a>QWe}Xi&D$;i?WLqoP&*LTytXvsx$O-aSYLznEd1ae|u&g<>r~j>HplP > zDYwj&Si$1PD`lDyAbF%?j;VyCWT48$&AfID41TFbn`OhyB!QY4JYD@<);T3K0RRug > BI;H>s > > literal 0 > HcmV?d00001 > > diff --git a/wui/src/public/images/icon_x.png b/wui/src/public/images/icon_x.png > new file mode 100644 > index 0000000000000000000000000000000000000000..7190b38303f8657e9840311376f88899f1253a68 > GIT binary patch > literal 340 > zcmeAS at N?(olHy`uVBq!ia0vp at K+MU(1|(lrEz1H at EX7WqAsj$Z!;#Vfk}U9uEM{Qf > z`T)X=PHRkN00l)$Tq8=Hi&7IyGV}8kLNaqx8BFz!EcFd6oLpv_0u{)B6a?p|m6RtI > zr7}3C zb8J>#p&Ie#-vu49ZdDGUWuDp3HblIcbn0-y((K=p)N0HBzEcf z-9wYPH*5`Sm1}TPadoMQeOHtCf0yF7V>1L-sJz^C;|OzMMLFjKMaJ`=x8}>(`$uGp > z8XrGn|I%djq%`9%H azpyTpsQIrKP$&#^ID at CFpUXO@geCykaeLGN > > literal 0 > HcmV?d00001 > > diff --git a/wui/src/public/javascripts/ovirt.js b/wui/src/public/javascripts/ovirt.js > index 675f20d..00befa1 100644 > --- a/wui/src/public/javascripts/ovirt.js > +++ b/wui/src/public/javascripts/ovirt.js > @@ -136,3 +136,15 @@ function afterVm(response, status){ > $("#vms_grid").flexReload() > } > } > + > +//selection detail refresh > +function refresh_summary(element_id, url, obj_id){ > + $('#'+element_id+'').load(url, { id: obj_id}) > +} > + > +// this must be called again after ajax loading of content with facebox links > +function refresh_facebox(){ > + $('a[rel*=facebox]').facebox() > + $('a[rel*=close]').trigger('close.facebox') > +} > + > diff --git a/wui/src/public/stylesheets/layout.css b/wui/src/public/stylesheets/layout.css > index 3bbf1a1..74dd3c0 100644 > --- a/wui/src/public/stylesheets/layout.css > +++ b/wui/src/public/stylesheets/layout.css > @@ -233,8 +233,39 @@ textarea:focus, input:focus { > font-size: 120%; > font-weight:bold; > padding-bottom: 10px; > + float: left; > } > > +.selection_tools { > + background:transparent none repeat scroll 0%; > + color:#000000; > + float:left; > + line-height:1.7; > + list-style-type:none; > + margin:0pt; > + padding:0pt 8px; > + text-align:center; > + text-decoration:none; > +} > +.selection_tools li { > + float:left; > + margin:0pt 1px; > + padding:0pt; > +} > +.selection_tools img { > +} > +.selection_tools a { > + background:transparent none repeat scroll 0%; > + color:#000000; > + float:left; > + line-height:1.7; > + padding:0pt 8px; > + text-align:center; > + text-decoration:none; > +} > +.selection_tools a:hover { > + background:#B0CBDE none repeat scroll 0%; > +} > .selection_key { > text-align:right; > float:left; > -- > 1.5.4.1 Starting to get somewhere here... looks good. ACK and committed to the main repo. --H From hbrock at redhat.com Fri May 30 17:25:29 2008 From: hbrock at redhat.com (Hugh O. Brock) Date: Fri, 30 May 2008 13:25:29 -0400 Subject: [Ovirt-devel] [Patch] VM pool quota add/edit In-Reply-To: <48403555.4020209@redhat.com> References: <48403555.4020209@redhat.com> Message-ID: <20080530172529.GC27672@redhat.com> On Fri, May 30, 2008 at 01:11:49PM -0400, Scott Seago wrote: > > >From ac4b03baf95f12f19b29893266ab469e8500617e Mon Sep 17 00:00:00 2001 > From: Scott Seago > Date: Fri, 30 May 2008 13:10:15 -0400 > Subject: [PATCH] working action links for VM quotas > > > Signed-off-by: Scott Seago > --- > wui/src/app/views/hardware/show_vms.rhtml | 9 +++--- > wui/src/app/views/resources/quick_summary.rhtml | 33 +++++++++++++++++++++++ > 2 files changed, 38 insertions(+), 4 deletions(-) > > diff --git a/wui/src/app/views/hardware/show_vms.rhtml b/wui/src/app/views/hardware/show_vms.rhtml > index 285f2c2..f88f0d3 100644 > --- a/wui/src/app/views/hardware/show_vms.rhtml > +++ b/wui/src/app/views/hardware/show_vms.rhtml > @@ -31,9 +31,10 @@ > } > if (selected_ids.length == 1) > { > - $('#vmpools_selection').load('<%= url_for :controller => "resources", > - :action => "quick_summary" %>', > - { id: parseInt(selected_ids[0].substring(3))}) > + refresh_summary('vmpool_selection', > + '<%= url_for :controller => "resources", > + :action => "quick_summary" %>', > + parseInt(selected_ids[0].substring(3))) > } > } > > @@ -45,6 +46,6 @@ > :pool_id => @pool.id, > :on_select => "vmpools_select" } %> >
          > -
          > +
          >
          Select a VM pool above.
          >
          > diff --git a/wui/src/app/views/resources/quick_summary.rhtml b/wui/src/app/views/resources/quick_summary.rhtml > index e71d9c9..8632b30 100644 > --- a/wui/src/app/views/resources/quick_summary.rhtml > +++ b/wui/src/app/views/resources/quick_summary.rhtml > @@ -1,6 +1,39 @@ > <%- content_for :title do -%> > <%=h @vm_resource_pool.name %> quota > <%- end -%> > +<%- content_for :action_links do -%> > + <%if @is_hwpool_admin -%> > + <%if @vm_resource_pool.quota -%> > + <%= link_to image_tag("icon_edit.png") + " Edit Quota", > + {:controller => 'quota', :action => 'edit', :id => @vm_resource_pool.quota}, > + :rel=>"facebox[.bolder]" %> > + > + <%= image_tag "icon_x.png" %> Revert to Default Quota > + > + <% else -%> > + <%= link_to image_tag("icon_edit.png") + " Edit Quota", > + {:controller => 'quota', :action => 'new', :pool_id => @vm_resource_pool }, > + :rel=>"facebox[.bolder]" %> > + <% end -%> > + <% end -%> > +<% end -%> > + > > <% resources = @vm_resource_pool.full_resources %> >
          > -- > 1.5.4.1 > ACK I have committed this. --H From jguiditt at redhat.com Fri May 30 20:10:40 2008 From: jguiditt at redhat.com (Jason Guiditta) Date: Fri, 30 May 2008 16:10:40 -0400 Subject: [Ovirt-devel] [PATCH] ajaxiness for tree and tabs Message-ID: <1212178240.5557.1.camel@localhost.localdomain> -------------- next part -------------- A non-text attachment was scrubbed... Name: s3-ajax-tree-v1.patch Type: text/x-patch Size: 182217 bytes Desc: not available URL: From jguiditt at redhat.com Fri May 30 20:16:56 2008 From: jguiditt at redhat.com (Jason Guiditta) Date: Fri, 30 May 2008 16:16:56 -0400 Subject: [Ovirt-devel] [PATCH] since there were 2 included in the last one.. Message-ID: <1212178616.5557.3.camel@localhost.localdomain> Forgot the '>', so part 2 didn't make it through. Here it is (tiny one) -------------- next part -------------- A non-text attachment was scrubbed... Name: s3-ajax-tree-v2.patch Type: text/x-patch Size: 949 bytes Desc: not available URL: From jguiditt at redhat.com Fri May 30 20:02:38 2008 From: jguiditt at redhat.com (Jason Guiditta) Date: Fri, 30 May 2008 16:02:38 -0400 Subject: [Ovirt-devel] [PATCH] facebox.close not needed anywhere Message-ID: Signed-off-by: Jason Guiditta --- wui/src/app/views/layouts/redux.rhtml | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/wui/src/app/views/layouts/redux.rhtml b/wui/src/app/views/layo= uts/redux.rhtml index 9b906f0..00ec126 100644 --- a/wui/src/app/views/layouts/redux.rhtml +++ b/wui/src/app/views/layouts/redux.rhtml @@ -44,7 +44,6 @@ action_type: "hyperlink" }) $('a[rel*=3Dfacebox]').livequery(function(){$(this).facebox();= },function(){}); - $('a[rel*=3Dclose]').trigger('close.facebox'); $('#side a').livequery(function(){ $(this).bind('click', function(){=20 $('#side span').each(function(){ --=20 1.5.4.1 --=-5NoAarKk6lno4EBP3lvi-- From jguiditt at redhat.com Fri May 30 21:01:27 2008 From: jguiditt at redhat.com (Jason Guiditta) Date: Fri, 30 May 2008 17:01:27 -0400 Subject: [Ovirt-devel] [PATCH] third time's the charm? Message-ID: <1212181287.5869.0.camel@localhost.localdomain> -------------- next part -------------- A non-text attachment was scrubbed... Name: s3-ajax-tree-v3.patch Type: text/x-patch Size: 186649 bytes Desc: not available URL: From jguiditt at redhat.com Fri May 30 21:13:38 2008 From: jguiditt at redhat.com (Jason Guiditta) Date: Fri, 30 May 2008 17:13:38 -0400 Subject: [Ovirt-devel] [PATCH] this one's for the gipper Message-ID: <1212182018.5869.2.camel@localhost.localdomain> From jguiditt at redhat.com Fri May 30 22:13:00 2008 From: jguiditt at redhat.com (Jason Guiditta) Date: Fri, 30 May 2008 18:13:00 -0400 Subject: [Ovirt-devel] [PATCH] fixed some 500 internal server errors Message-ID: <1212185580.6084.2.camel@localhost.localdomain> Including all 4 pieces of this patch, for easier application, but the only new one is 0004. Some variables were not getting set, pretty simple fix. -j -------------- next part -------------- A non-text attachment was scrubbed... Name: 0001-reload-content-area-when-something-in-the-tree-is-cl.patch Type: text/x-patch Size: 3479 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: 0002-make-the-tree-links-ajax-calls-that-refresh-t.patch Type: text/x-patch Size: 182217 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: 0003-facebox.close-not-needed-anywhere.patch Type: text/x-patch Size: 951 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: 0004-some-of-the-show-methods-had-variaable-to-be-set-bu.patch Type: text/x-patch Size: 2121 bytes Desc: not available URL: From mmorsi at redhat.com Fri May 30 22:39:51 2008 From: mmorsi at redhat.com (Mohammed Morsi) Date: Fri, 30 May 2008 18:39:51 -0400 Subject: [Ovirt-devel] [Patch] Graphing Message-ID: <48408237.8080002@redhat.com> Included is a tarball of all my graphing related commits. It includes all the graphing stuff so far, including the frontend and styling, and backend / API integration. All that is remaining is to iron out the calls to Mark's API. I updated, and made sure to resolve all conflicts before generating this patch, so it is committable. Have a great weekend! -Mo -------------- next part -------------- A non-text attachment was scrubbed... Name: graphing.tar.gz Type: application/x-gzip Size: 71670 bytes Desc: not available URL: From jguiditt at redhat.com Tue May 27 22:35:31 2008 From: jguiditt at redhat.com (Jason Guiditta) Date: Tue, 27 May 2008 18:35:31 -0400 Subject: [Ovirt-devel] [PATCH] reload content area when something in the tree is clicked, and update the links w/in the tabs. Rough, early cut. Message-ID: Signed-off-by: Jason Guiditta --- wui/src/app/controllers/hardware_controller.rb | 3 ++ .../jquery-treeview/jquery.treeview.async.js | 26 ++++++++++++++++++++ 2 files changed, 29 insertions(+), 0 deletions(-) diff --git a/wui/src/app/controllers/hardware_controller.rb b/wui/src/app/controllers/hardware_controller.rb index 0eaf76f..97e8207 100644 --- a/wui/src/app/controllers/hardware_controller.rb +++ b/wui/src/app/controllers/hardware_controller.rb @@ -35,6 +35,9 @@ class HardwareController < ApplicationController flash[:notice] = 'You do not have permission to view this hardware pool: redirecting to top level' redirect_to :controller => "dashboard" end + if params[:ajax] + render :layout => false #:template => 'hardware/show.html.erb' + end end def json_view_tree diff --git a/wui/src/public/javascripts/jquery-treeview/jquery.treeview.async.js b/wui/src/public/javascripts/jquery-treeview/jquery.treeview.async.js index 8161bd1..d277a32 100644 --- a/wui/src/public/javascripts/jquery-treeview/jquery.treeview.async.js +++ b/wui/src/public/javascripts/jquery-treeview/jquery.treeview.async.js @@ -49,6 +49,32 @@ function load(settings, params, child, container) { } else { current.html("" + link_open + this.text + link_close + "") .appendTo(parent); + $('li #' + this.id + ' span > a') + .bind('click', function() { +// $.ajax({ +// url: this.href, +// type: 'GET', +// data: {ajax:true}, +// dataType: 'html', +// success: function(data) { alert(data);}, +// error: function(xhr) {alert(xhr.status + ' ' + xhr.statusText);} +// }) + $('#content-area').load(this.href,{ajax:true}); + var new_id = $(this).parent().parent().get(0).id; + $('ul[class=tab_nav] a').each(function(){ + this.href = this.href.slice(0,this.href.lastIndexOf('/'+1)) + new_id; + }); + $('ul[class=tab_nav] li').each(function(){ + $(this).removeClass('current'); + }); + $('#nav_summary').addClass('current'); + //var current_e = $('span[class^=current_]'); + //current_e.removeClass(current_e.attr('class')); + //$(this).addClass('current_folder'); + //var my_container = $(container); + return false; + }); + } if (this.classes) { current.children("span").addClass(this.classes); -- 1.5.4.1 --=-FeeZJ3ybHM80BpIC4CGc Content-Disposition: attachment; filename=0002-make-the-tree-links-ajax-calls-that-refresh-t.patch Content-Type: application/mbox; name=0002-make-the-tree-links-ajax-calls-that-refresh-t.patch Content-Transfer-Encoding: base64 RnJvbSA0MjEwY2JkMDdhZGFlOGY3YTYxNDBjMDhhNTdjYzNmYjA4ZThjNThlIE1vbiBTZXAgMTcg MDA6MDA6MDAgMjAwMQpGcm9tOiBKYXNvbiBHdWlkaXR0YSA8amd1aWRpdHRAcmVkaGF0LmNvbT4K RGF0ZTogRnJpLCAzMCBNYXkgMjAwOCAxNTowMDoxOSAtMDQwMApTdWJqZWN0OiBbUEFUQ0hdICAg ICAqICBtYWtlIHRoZSB0cmVlIGxpbmtzIGFqYXggY2FsbHMgdGhhdCByZWZyZXNoIHRoZSBtYWlu IGNvbnRlbnQgcGFuZWwKICAgICAqIHJlZmFjdG9yIHRhYiBuYXYgdG8gYmUgaW4gYSBzZXBhcmF0 ZWx5IGNhbGxhYmxlIGxheW91dAogICAgICogdXBkYXRlIGFueXRoaW5nIG9uIHRoZSB0cmVlIHBh bmVsIHRoYXQgbWFrZXMgdXNlIG9mIHRoZSBjdXJyZW50IHNlbGVjdGlvbiBhbmQgY2hhbmdlIHRo ZSBuZXcvZGVsZXRlIGxpbmtzIGFwcHJvcHJpYXRlbHkgRG9uZQogICAgICogY2hhbmdlIHRyZWUg d2lkZ2V0IHRvIHN1cHBvcnQgc2hvd2luZyBzZWxlY3RlZCBub2RlIHcvbyBwYWdlIHJlZnJlc2gK ICAgICAqIG1ha2UgdGhlIHRhYnMgb24gdGhlIG1haW4gcGFuZWwgaW50byBhamF4IGNhbGxzIHRo YXQgdXBkYXRlIHRoZSBtYWluIGNvbnRlbnQgcGFuZWwgdG8gc2hvdyBhIGRpZmZlcmVudCB0YWIu IFJldiAxIG1ha2VzIGEgbmV3IGNhbGwgd2l0aCBlYWNoIGNsaWNrCgoKU2lnbmVkLW9mZi1ieTog SmFzb24gR3VpZGl0dGEgPGpndWlkaXR0QHJlZGhhdC5jb20+Ci0tLQogd3VpL3NyYy9hcHAvY29u dHJvbGxlcnMvZGFzaGJvYXJkX2NvbnRyb2xsZXIucmIgICAgfCAgICA0ICstCiB3dWkvc3JjL2Fw cC9jb250cm9sbGVycy9oYXJkd2FyZV9jb250cm9sbGVyLnJiICAgICB8ICAgIDIgKy0KIHd1aS9z cmMvYXBwL2NvbnRyb2xsZXJzL3Jlc291cmNlc19jb250cm9sbGVyLnJiICAgIHwgICAgMyArCiB3 dWkvc3JjL2FwcC92aWV3cy9sYXlvdXRzL19zaWRlX3Rvb2xiYXIucmh0bWwgICAgICB8ICAgIDIg Ky0KIHd1aS9zcmMvYXBwL3ZpZXdzL2xheW91dHMvcmVkdXgucmh0bWwgICAgICAgICAgICAgIHwg ICA3NSArLQogd3VpL3NyYy9hcHAvdmlld3MvbGF5b3V0cy90YWJzLWFuZC1jb250ZW50LnJodG1s ICAgfCAgIDExICsKIHd1aS9zcmMvcHVibGljL2phdmFzY3JpcHRzL2pxdWVyeS0xLjIuNi5qcyAg ICAgICAgIHwgMzU0OSArKysrKysrKysrKysrKysrKysrKwogd3VpL3NyYy9wdWJsaWMvamF2YXNj cmlwdHMvanF1ZXJ5LTEuMi42Lm1pbi5qcyAgICAgfCAgIDMyICsKIC4uLi9qcXVlcnktdHJlZXZp ZXcvanF1ZXJ5LnRyZWV2aWV3LmFzeW5jLmpzICAgICAgIHwgICAyNCArLQogLi4uL2phdmFzY3Jp cHRzL2pxdWVyeS10cmVldmlldy9vdmlydC50cmVldmlldy5jc3MgfCAgICA4ICstCiB3dWkvc3Jj L3B1YmxpYy9qYXZhc2NyaXB0cy9qcXVlcnkubGl2ZXF1ZXJ5LmpzICAgICB8ICAgIDIgKy0KIHd1 aS9zcmMvcHVibGljL2phdmFzY3JpcHRzL2pxdWVyeS5saXZlcXVlcnkubWluLmpzIHwgICAxMSAr CiAuLi4vcHVibGljL2phdmFzY3JpcHRzL2pxdWVyeS5saXZlcXVlcnkucGFjay5qcyAgICB8ICAg IDkgKwogMTMgZmlsZXMgY2hhbmdlZCwgMzY5NyBpbnNlcnRpb25zKCspLCAzNSBkZWxldGlvbnMo LSkKIGNyZWF0ZSBtb2RlIDEwMDY0NCB3dWkvc3JjL2FwcC92aWV3cy9sYXlvdXRzL3RhYnMtYW5k LWNvbnRlbnQucmh0bWwKIGNyZWF0ZSBtb2RlIDEwMDY0NCB3dWkvc3JjL3B1YmxpYy9qYXZhc2Ny aXB0cy9qcXVlcnktMS4yLjYuanMKIGNyZWF0ZSBtb2RlIDEwMDY0NCB3dWkvc3JjL3B1YmxpYy9q YXZhc2NyaXB0cy9qcXVlcnktMS4yLjYubWluLmpzCiBjcmVhdGUgbW9kZSAxMDA2NDQgd3VpL3Ny Yy9wdWJsaWMvamF2YXNjcmlwdHMvanF1ZXJ5LmxpdmVxdWVyeS5taW4uanMKIGNyZWF0ZSBtb2Rl IDEwMDY0NCB3dWkvc3JjL3B1YmxpYy9qYXZhc2NyaXB0cy9qcXVlcnkubGl2ZXF1ZXJ5LnBhY2su anMKCmRpZmYgLS1naXQgYS93dWkvc3JjL2FwcC9jb250cm9sbGVycy9kYXNoYm9hcmRfY29udHJv bGxlci5yYiBiL3d1aS9zcmMvYXBwL2NvbnRyb2xsZXJzL2Rhc2hib2FyZF9jb250cm9sbGVyLnJi CmluZGV4IDNmZmFlYmMuLmM0ODMwZGYgMTAwNjQ0Ci0tLSBhL3d1aS9zcmMvYXBwL2NvbnRyb2xs ZXJzL2Rhc2hib2FyZF9jb250cm9sbGVyLnJiCisrKyBiL3d1aS9zcmMvYXBwL2NvbnRyb2xsZXJz L2Rhc2hib2FyZF9jb250cm9sbGVyLnJiCkBAIC0xOCw3ICsxOCw2IEBACiAjIGFsc28gYXZhaWxh YmxlIGF0IGh0dHA6Ly93d3cuZ251Lm9yZy9jb3B5bGVmdC9ncGwuaHRtbC4KIAogY2xhc3MgRGFz aGJvYXJkQ29udHJvbGxlciA8IEFwcGxpY2F0aW9uQ29udHJvbGxlcgotCiAgIGRlZiBpbmRleAog ICAgIEBkZWZhdWx0X3Bvb2wgPSBIYXJkd2FyZVBvb2wuZ2V0X2RlZmF1bHRfcG9vbAogICAgIHNl dF9wZXJtcyhAZGVmYXVsdF9wb29sKQpAQCAtMzAsNSArMjksOCBAQCBjbGFzcyBEYXNoYm9hcmRD b250cm9sbGVyIDwgQXBwbGljYXRpb25Db250cm9sbGVyCiAgICAgQGhvc3RzID0gSG9zdC5maW5k KDphbGwpCiAgICAgQHN0b3JhZ2Vfdm9sdW1lcyA9IFN0b3JhZ2VWb2x1bWUuZmluZCg6YWxsKQog ICAgIEB2bXMgPSBWbS5maW5kKDphbGwpCisgICAgaWYgcGFyYW1zWzphamF4XQorICAgICAgcmVu ZGVyIDpsYXlvdXQgPT4gJ3RhYnMtYW5kLWNvbnRlbnQnICM6dGVtcGxhdGUgPT4gJ2hhcmR3YXJl L3Nob3cuaHRtbC5lcmInCisgICAgZW5kCiAgIGVuZAogZW5kCmRpZmYgLS1naXQgYS93dWkvc3Jj L2FwcC9jb250cm9sbGVycy9oYXJkd2FyZV9jb250cm9sbGVyLnJiIGIvd3VpL3NyYy9hcHAvY29u dHJvbGxlcnMvaGFyZHdhcmVfY29udHJvbGxlci5yYgppbmRleCA5N2U4MjA3Li5iODZkOTI5IDEw MDY0NAotLS0gYS93dWkvc3JjL2FwcC9jb250cm9sbGVycy9oYXJkd2FyZV9jb250cm9sbGVyLnJi CisrKyBiL3d1aS9zcmMvYXBwL2NvbnRyb2xsZXJzL2hhcmR3YXJlX2NvbnRyb2xsZXIucmIKQEAg LTM2LDcgKzM2LDcgQEAgY2xhc3MgSGFyZHdhcmVDb250cm9sbGVyIDwgQXBwbGljYXRpb25Db250 cm9sbGVyCiAgICAgICByZWRpcmVjdF90byA6Y29udHJvbGxlciA9PiAiZGFzaGJvYXJkIgogICAg IGVuZAogICAgIGlmIHBhcmFtc1s6YWpheF0KLSAgICAgIHJlbmRlciA6bGF5b3V0ID0+IGZhbHNl ICM6dGVtcGxhdGUgPT4gJ2hhcmR3YXJlL3Nob3cuaHRtbC5lcmInCisgICAgICByZW5kZXIgOmxh eW91dCA9PiAndGFicy1hbmQtY29udGVudCcKICAgICBlbmQKICAgZW5kCiAgIApkaWZmIC0tZ2l0 IGEvd3VpL3NyYy9hcHAvY29udHJvbGxlcnMvcmVzb3VyY2VzX2NvbnRyb2xsZXIucmIgYi93dWkv c3JjL2FwcC9jb250cm9sbGVycy9yZXNvdXJjZXNfY29udHJvbGxlci5yYgppbmRleCBjODkxNDQ3 Li5lOWEwY2JhIDEwMDY0NAotLS0gYS93dWkvc3JjL2FwcC9jb250cm9sbGVycy9yZXNvdXJjZXNf Y29udHJvbGxlci5yYgorKysgYi93dWkvc3JjL2FwcC9jb250cm9sbGVycy9yZXNvdXJjZXNfY29u dHJvbGxlci5yYgpAQCAtNTQsNiArNTQsOSBAQCBjbGFzcyBSZXNvdXJjZXNDb250cm9sbGVyIDwg QXBwbGljYXRpb25Db250cm9sbGVyCiAgICAgICBmbGFzaFs6bm90aWNlXSA9ICdZb3UgZG8gbm90 IGhhdmUgcGVybWlzc2lvbiB0byB2aWV3IHRoaXMgVk0gUmVzb3VyY2UgUG9vbDogcmVkaXJlY3Rp bmcgdG8gdG9wIGxldmVsJwogICAgICAgcmVkaXJlY3RfdG8gOmFjdGlvbiA9PiAnbGlzdCcKICAg ICBlbmQKKyAgICBpZiBwYXJhbXNbOmFqYXhdCisgICAgICByZW5kZXIgOmxheW91dCA9PiAndGFi cy1hbmQtY29udGVudCcgIzp0ZW1wbGF0ZSA9PiAnaGFyZHdhcmUvc2hvdy5odG1sLmVyYicKKyAg ICBlbmQKICAgZW5kCiAKICAgZGVmIHF1aWNrX3N1bW1hcnkKZGlmZiAtLWdpdCBhL3d1aS9zcmMv YXBwL3ZpZXdzL2xheW91dHMvX3NpZGVfdG9vbGJhci5yaHRtbCBiL3d1aS9zcmMvYXBwL3ZpZXdz L2xheW91dHMvX3NpZGVfdG9vbGJhci5yaHRtbAppbmRleCA4NzhjODI3Li5kOTFlNGFiIDEwMDY0 NAotLS0gYS93dWkvc3JjL2FwcC92aWV3cy9sYXlvdXRzL19zaWRlX3Rvb2xiYXIucmh0bWwKKysr IGIvd3VpL3NyYy9hcHAvdmlld3MvbGF5b3V0cy9fc2lkZV90b29sYmFyLnJodG1sCkBAIC0xMyw3 ICsxMyw3IEBACiA8L2Rpdj4KIDwlIGVuZCAtJT4KIDxkaXYgY2xhc3M9InRvb2xiYXIiIHN0eWxl PSJmbG9hdDpsZWZ0OyI+Ci0gICA8JT0gbGlua190byBpbWFnZV90YWcgKCJpY29uX2RlbGV0ZS5n aWYiLCA6dGl0bGU9PiJEZWxldGUgU2VsZWN0ZWQgUG9vbCIpLCAKKyAgIDwlPSBsaW5rX3RvIGlt YWdlX3RhZygiaWNvbl9kZWxldGUuZ2lmIiwgOnRpdGxlPT4iRGVsZXRlIFNlbGVjdGVkIFBvb2wi KSwgCiAgICAgICAgeyA6YWN0aW9uID0+ICdkZXN0cm95JywgOmlkID0+IHBvb2wgfSwgCiAgICAg ICAgeyA6bWV0aG9kID0+IDpwb3N0LCA6Y29uZmlybSA9PiAnQXJlIHlvdSBzdXJlIHlvdSB3YW50 IHRvIGRlbGV0ZSAtICVzPycgJSBwb29sLm5hbWV9ICU+CiA8L2Rpdj4KZGlmZiAtLWdpdCBhL3d1 aS9zcmMvYXBwL3ZpZXdzL2xheW91dHMvcmVkdXgucmh0bWwgYi93dWkvc3JjL2FwcC92aWV3cy9s YXlvdXRzL3JlZHV4LnJodG1sCmluZGV4IGE0MGNiMWYuLjliOTA2ZjAgMTAwNjQ0Ci0tLSBhL3d1 aS9zcmMvYXBwL3ZpZXdzL2xheW91dHMvcmVkdXgucmh0bWwKKysrIGIvd3VpL3NyYy9hcHAvdmll d3MvbGF5b3V0cy9yZWR1eC5yaHRtbApAQCAtMTUsNyArMTUsOCBAQAogICA8JT0gc3R5bGVzaGVl dF9saW5rX3RhZyAnL2phdmFzY3JpcHRzL2pxdWVyeS10cmVldmlldy9vdmlydC50cmVldmlldy5j c3MnICU+CiAgIDwlPSBzdHlsZXNoZWV0X2xpbmtfdGFnICdmbGV4aWdyaWQvZmxleGlncmlkLmNz cycgJT4KICAgPCU9IHN0eWxlc2hlZXRfbGlua190YWcgJ2ZhY2Vib3gnICU+Ci0gIDwlPSBqYXZh c2NyaXB0X2luY2x1ZGVfdGFnICJqcXVlcnkucGFjay5qcyIgLSU+CisgIDwhLS0lPSBzdHlsZXNo ZWV0X2xpbmtfdGFnICdqcXVlcnkudWktMS41YjQvdGhlbWVzL2Zsb3JhL2Zsb3JhLnRhYnMuY3Nz JyAlLS0+CisgIDwlPSBqYXZhc2NyaXB0X2luY2x1ZGVfdGFnICJqcXVlcnktMS4yLjYubWluLmpz IiAtJT4KICAgPCU9IGphdmFzY3JpcHRfaW5jbHVkZV90YWcgImpxdWVyeS10cmVldmlldy9qcXVl cnkudHJlZXZpZXcuanMiIC0lPgogICA8JT0gamF2YXNjcmlwdF9pbmNsdWRlX3RhZyAianF1ZXJ5 LXRyZWV2aWV3L2pxdWVyeS50cmVldmlldy5hc3luYy5qcyIgLSU+CiAgIDwlPSBqYXZhc2NyaXB0 X2luY2x1ZGVfdGFnICJmbGV4aWdyaWQuanMiIC0lPgpAQCAtMjMsMTIgKzI0LDEzIEBACiAgIDwl PSBqYXZhc2NyaXB0X2luY2x1ZGVfdGFnICJqcXVlcnktc3ZnL2pxdWVyeS5zdmcucGFjay5qcyIg LSU+CiAgIDwhLS0lPSBqYXZhc2NyaXB0X2luY2x1ZGVfdGFnICJqcXVlcnktc3ZnL2pxdWVyeS5z dmdmaWx0ZXIuanMiIC0lLS0+CiAgIDwlPSBqYXZhc2NyaXB0X2luY2x1ZGVfdGFnICJqcXVlcnkt c3ZnL2pxdWVyeS5zdmdncmFwaC5qcyIgLSU+Ci0gIDwlPSBqYXZhc2NyaXB0X2luY2x1ZGVfdGFn ICJ1aS5jb3JlLmpzIiAtJT4KLSAgPCU9IGphdmFzY3JpcHRfaW5jbHVkZV90YWcgInVpLnNsaWRl ci5qcyIgLSU+CisgIDwhLS0lPSBqYXZhc2NyaXB0X2luY2x1ZGVfdGFnICJqcXVlcnkudWktMS41 YjQvdWkuY29yZS5qcyIgLSU+CisgIDwgJT0gamF2YXNjcmlwdF9pbmNsdWRlX3RhZyAianF1ZXJ5 LnVpLTEuNWI0L3VpLnRhYnMuanMiIC0lLS0+CiAgIDwlPSBqYXZhc2NyaXB0X2luY2x1ZGVfdGFn ICJqcXVlcnkuY29va2llLmpzIiAtJT4KKyAgPCU9IGphdmFzY3JpcHRfaW5jbHVkZV90YWcgImpx dWVyeS5saXZlcXVlcnkucGFjay5qcyIgLSU+CiAgIDwlPSBqYXZhc2NyaXB0X2luY2x1ZGVfdGFn ICJqcXVlcnkuZm9ybS5qcyIgLSU+CiAKLSAgPCEtLSBvdmlydC1zcGVjaWZpYyBmdW5jdGlvbnMg ZGVmaW5lZCBoZXJlCisgIDwhLS0gb3ZpcnQtc3BlY2lmaWMgZnVuY3Rpb25zIGRlZmluZWQgaGVy ZSAtLT4KICAgPCU9IGphdmFzY3JpcHRfaW5jbHVkZV90YWcgIm92aXJ0LmpzIiAtJT4KICAgICA8 c2NyaXB0IHR5cGU9InRleHQvamF2YXNjcmlwdCI+CiAgICAgICAkKGRvY3VtZW50KS5yZWFkeShm dW5jdGlvbigpeyAgICAgICAgIApAQCAtNDEsMTAgKzQzLDUzIEBACiAgICAgICAgICAgICByZXNv dXJjZV91cmw6ICI8JT0gIHVybF9mb3IgOmNvbnRyb2xsZXIgPT4nL3Jlc291cmNlcycsIDphY3Rp b24gPT4gJ3Nob3cnICU+IiwKICAgICAgICAgICAgIGFjdGlvbl90eXBlOiAiaHlwZXJsaW5rIgog CSAgICB9KQotCX0pOyAKLSAgICAgICQoZG9jdW1lbnQpLnJlYWR5KGZ1bmN0aW9uKCl7ICAgICAg ICAgCisgICAgICAgICAgICAkKCdhW3JlbCo9ZmFjZWJveF0nKS5saXZlcXVlcnkoZnVuY3Rpb24o KXskKHRoaXMpLmZhY2Vib3goKTt9LGZ1bmN0aW9uKCl7fSk7CisgICAgICAgICAgICAkKCdhW3Jl bCo9Y2xvc2VdJykudHJpZ2dlcignY2xvc2UuZmFjZWJveCcpOworICAgICAgICAgICAgJCgnI3Np ZGUgYScpLmxpdmVxdWVyeShmdW5jdGlvbigpeworICAgICAgICAgICAgICAgICQodGhpcykuYmlu ZCgnY2xpY2snLCBmdW5jdGlvbigpeyAKKyAgICAgICAgICAgICAgICAgICAgJCgnI3NpZGUgc3Bh bicpLmVhY2goZnVuY3Rpb24oKXsKKyAgICAgICAgICAgICAgICAgICAgICAgIHZhciBub2RlVHlw ZSA9ICQodGhpcykuYXR0cignY2xhc3MnKTsKKyAgICAgICAgICAgICAgICAgICAgICAgIGlmIChu b2RlVHlwZS5pbmRleE9mKCdfJykgIT0gLTEpeworICAgICAgICAgICAgICAgICAgICAgICAgICAg IG5vZGVUeXBlID0gbm9kZVR5cGUuc3Vic3RyKG5vZGVUeXBlLmluZGV4T2YoJ18nKSArMSk7Cisg ICAgICAgICAgICAgICAgICAgICAgICAgICAgJCh0aGlzKS5hdHRyKCdjbGFzcycsIG5vZGVUeXBl KTsKKyAgICAgICAgICAgICAgICAgICAgICAgIH0gICAgICAgICAgICAgICAgICAgICAgICAKKyAg ICAgICAgICAgICAgICAgICAgfSk7CisgICAgICAgICAgICAgICAgICAgIHZhciBub2RlVHlwZSA9 ICQodGhpcykucGFyZW50KCkuYXR0cignY2xhc3MnKTsKKyAgICAgICAgICAgICAgICAgICAgJCh0 aGlzKS5wYXJlbnQoKS5hdHRyKCdjbGFzcycsICdjdXJyZW50XycgKyBub2RlVHlwZSk7CisgICAg ICAgICAgICAgICAgICAgICQuYWpheCh7CisgICAgICAgICAgICAgICAgICAgICAgICB1cmw6ICQo dGhpcykuYXR0cignaHJlZicpLAorICAgICAgICAgICAgICAgICAgICAgICAgdHlwZTogJ0dFVCcs CisgICAgICAgICAgICAgICAgICAgICAgICBkYXRhOiB7YWpheDp0cnVlfSwKKyAgICAgICAgICAg ICAgICAgICAgICAgIGRhdGFUeXBlOiAnaHRtbCcsCisgICAgICAgICAgICAgICAgICAgICAgICBz dWNjZXNzOiBmdW5jdGlvbihkYXRhKSB7CisgICAgICAgICAgICAgICAgICAgICAgICAgICQoJyNz aWRlLXRvb2xiYXInKS5odG1sKCQoZGF0YSkuZmluZCgnZGl2LnRvb2xiYXInKSk7CisgICAgICAg ICAgICAgICAgICAgICAgICAgICQoJyN0YWJzLWFuZC1jb250ZW50LWNvbnRhaW5lcicpLmh0bWwo JChkYXRhKS5ub3QoJ2RpdiNzaWRlLXRvb2xiYXInKSk7CisgICAgICAgICAgICAgICAgICAgICAg ICB9LAorICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3I6IGZ1bmN0aW9uKHhocikge2FsZXJ0 KHhoci5zdGF0dXMgKyAnICcgKyB4aHIuc3RhdHVzVGV4dCk7fQorICAgICAgICAgICAgICAgICAg ICB9KTsKKyAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO30pfSxmdW5jdGlvbigpe30p OworICAgICAgICAgICAgJCgnLnRhYl9uYXYgYScpLmxpdmVxdWVyeShmdW5jdGlvbigpeworICAg ICAgICAgICAgICAgICQodGhpcykuYmluZCgnY2xpY2snLCBmdW5jdGlvbigpeworICAgICAgICAg ICAgICAgICAgICAkKCcudGFiX25hdiBsaScpLnJlbW92ZUNsYXNzKCdjdXJyZW50Jyk7CisgICAg ICAgICAgICAgICAgICAgICQodGhpcykucGFyZW50KCkuYWRkQ2xhc3MoJ2N1cnJlbnQnKTsKKyAg ICAgICAgICAgICAgICAgICAgJC5hamF4KHsKKyAgICAgICAgICAgICAgICAgICAgICAgIHVybDog JCh0aGlzKS5hdHRyKCdocmVmJyksCisgICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiAnR0VU JywKKyAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE6IHthamF4OnRydWV9LAorICAgICAgICAg ICAgICAgICAgICAgICAgZGF0YVR5cGU6ICdodG1sJywKKyAgICAgICAgICAgICAgICAgICAgICAg IHN1Y2Nlc3M6IGZ1bmN0aW9uKGRhdGEpIHsgCisgICAgICAgICAgICAgICAgICAgICAgICAgIHZh ciB3cmFwcGVkX2RhdGEgPSAkKGRhdGEpLmZpbmQoJ2RpdicpLmZpbHRlcignW2lkPWNvbnRlbnQt YXJlYV0nKTsKKyAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIG15X3BhcmVudCA9ICQodGhp cykucGFyZW50KCk7CisgICAgICAgICAgICAgICAgICAgICAgICAgICQoJyNjb250ZW50LWFyZWEn KS5odG1sKCQoZGF0YSkuZmluZCgnZGl2JykuZmlsdGVyKCdbaWQ9Y29udGVudC1hcmVhXScpKTsK KyAgICAgICAgICAgICAgICAgICAgICAgIH0sCisgICAgICAgICAgICAgICAgICAgICAgICBlcnJv cjogZnVuY3Rpb24oeGhyKSB7YWxlcnQoeGhyLnN0YXR1cyArICcgJyArIHhoci5zdGF0dXNUZXh0 KTt9CisgICAgICAgICAgICAgICAgICAgIH0pOworICAgICAgICAgICAgICAgICAgICByZXR1cm4g ZmFsc2U7fSl9LGZ1bmN0aW9uKCl7fSk7CisgICAgICAgICAgICAKKwl9KTsKKyAgICAgIC8qJChk b2N1bWVudCkucmVhZHkoZnVuY3Rpb24oKXsgICAgICAgICAKICAgICAgICAgcmVmcmVzaF9mYWNl Ym94KCkKLSAgICAgIH0pCisgICAgICB9KSovCiAgICAgICA8L3NjcmlwdD4KICAgIDwlPSB5aWVs ZCA6c2NyaXB0cyAtJT4KICA8L2hlYWQ+CkBAIC02MywxMyArMTA4LDE1IEBACiAgICAgIDwlPSBy ZW5kZXIgOnBhcnRpYWwgPT4gJy9sYXlvdXRzL3NpZGVfdG9vbGJhcicgJT4KICAgIDwvZGl2Pgog Ci0gICA8ZGl2IGlkPSJuYXZpZ2F0aW9uLXRhYnMiIHN0eWxlPSJwb3NpdGlvbjphYnNvbHV0ZTsg dG9wOjQwcHg7IGxlZnQ6MjMxcHg7Ij4KLSAgICAgPCU9IHJlbmRlciA6cGFydGlhbCA9PiAnL2xh eW91dHMvbmF2aWdhdGlvbl90YWJzJyAlPgotICAgPC9kaXY+IAotICAgPGRpdiBpZD0ibWFpbiI+ Ci0gICAgICA8ZGl2IGlkPSJjb250ZW50LWFyZWEiPgotICAgICAgICA8JT0geWllbGQgICU+IDwl IyB0aGUgcmVzdCBvZiB0aGUgY2VudGVyIGFuZCByaWdodCBoYW5kIHNpZGUgJT4KLSAgICAgIDwv ZGl2PgorICAgPGRpdiBpZD0idGFicy1hbmQtY29udGVudC1jb250YWluZXIiPgorICAgICA8ZGl2 IGlkPSJuYXZpZ2F0aW9uLXRhYnMiIHN0eWxlPSJwb3NpdGlvbjphYnNvbHV0ZTsgdG9wOjQwcHg7 IGxlZnQ6MjMxcHg7Ij4KKyAgICAgICA8JT0gcmVuZGVyIDpwYXJ0aWFsID0+ICcvbGF5b3V0cy9u YXZpZ2F0aW9uX3RhYnMnICU+CisgICAgIDwvZGl2PiAKKyAgICAgPGRpdiBpZD0ibWFpbiI+Cisg ICAgICAgIDxkaXYgaWQ9ImNvbnRlbnQtYXJlYSI+CisgICAgICAgICAgPCU9IHlpZWxkICAlPiA8 JSMgdGhlIHJlc3Qgb2YgdGhlIGNlbnRlciBhbmQgcmlnaHQgaGFuZCBzaWRlICU+CisgICAgICAg IDwvZGl2PgorICAgICA8L2Rpdj4KICAgIDwvZGl2PgogCiAgPC9ib2R5PgpkaWZmIC0tZ2l0IGEv d3VpL3NyYy9hcHAvdmlld3MvbGF5b3V0cy90YWJzLWFuZC1jb250ZW50LnJodG1sIGIvd3VpL3Ny Yy9hcHAvdmlld3MvbGF5b3V0cy90YWJzLWFuZC1jb250ZW50LnJodG1sCm5ldyBmaWxlIG1vZGUg MTAwNjQ0CmluZGV4IDAwMDAwMDAuLjY2OWM2NTMKLS0tIC9kZXYvbnVsbAorKysgYi93dWkvc3Jj L2FwcC92aWV3cy9sYXlvdXRzL3RhYnMtYW5kLWNvbnRlbnQucmh0bWwKQEAgLTAsMCArMSwxMSBA QAorPGRpdiBpZD0ic2lkZS10b29sYmFyIiBjbGFzcz0iaGVhZGVyX21lbnVfd3JhcHBlciI+Cisg IDwlPSByZW5kZXIgOnBhcnRpYWwgPT4gJy9sYXlvdXRzL3NpZGVfdG9vbGJhcicgJT4KKzwvZGl2 PgorPGRpdiBpZD0ibmF2aWdhdGlvbi10YWJzIiBzdHlsZT0icG9zaXRpb246YWJzb2x1dGU7IHRv cDo0MHB4OyBsZWZ0OjIzMXB4OyI+CisgPCU9IHJlbmRlciA6cGFydGlhbCA9PiAnL2xheW91dHMv bmF2aWdhdGlvbl90YWJzJyAlPgorPC9kaXY+IAorPGRpdiBpZD0ibWFpbiI+CisgIDxkaXYgaWQ9 ImNvbnRlbnQtYXJlYSI+CisgICAgPCU9IHlpZWxkICAlPiA8JSMgdGhlIHJlc3Qgb2YgdGhlIGNl bnRlciBhbmQgcmlnaHQgaGFuZCBzaWRlICU+CisgIDwvZGl2PgorPC9kaXY+ClwgTm8gbmV3bGlu ZSBhdCBlbmQgb2YgZmlsZQpkaWZmIC0tZ2l0IGEvd3VpL3NyYy9wdWJsaWMvamF2YXNjcmlwdHMv anF1ZXJ5LTEuMi42LmpzIGIvd3VpL3NyYy9wdWJsaWMvamF2YXNjcmlwdHMvanF1ZXJ5LTEuMi42 LmpzCm5ldyBmaWxlIG1vZGUgMTAwNjQ0CmluZGV4IDAwMDAwMDAuLjg4ZTY2MWUKLS0tIC9kZXYv bnVsbAorKysgYi93dWkvc3JjL3B1YmxpYy9qYXZhc2NyaXB0cy9qcXVlcnktMS4yLjYuanMKQEAg LTAsMCArMSwzNTQ5IEBACisoZnVuY3Rpb24oKXsKKy8qCisgKiBqUXVlcnkgMS4yLjYgLSBOZXcg V2F2ZSBKYXZhc2NyaXB0CisgKgorICogQ29weXJpZ2h0IChjKSAyMDA4IEpvaG4gUmVzaWcgKGpx dWVyeS5jb20pCisgKiBEdWFsIGxpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgKE1JVC1MSUNFTlNFLnR4 dCkKKyAqIGFuZCBHUEwgKEdQTC1MSUNFTlNFLnR4dCkgbGljZW5zZXMuCisgKgorICogJERhdGU6 IDIwMDgtMDUtMjQgMTQ6MjI6MTcgLTA0MDAgKFNhdCwgMjQgTWF5IDIwMDgpICQKKyAqICRSZXY6 IDU2ODUgJAorICovCisKKy8vIE1hcCBvdmVyIGpRdWVyeSBpbiBjYXNlIG9mIG92ZXJ3cml0ZQor dmFyIF9qUXVlcnkgPSB3aW5kb3cualF1ZXJ5LAorLy8gTWFwIG92ZXIgdGhlICQgaW4gY2FzZSBv ZiBvdmVyd3JpdGUKKwlfJCA9IHdpbmRvdy4kOworCit2YXIgalF1ZXJ5ID0gd2luZG93LmpRdWVy eSA9IHdpbmRvdy4kID0gZnVuY3Rpb24oIHNlbGVjdG9yLCBjb250ZXh0ICkgeworCS8vIFRoZSBq UXVlcnkgb2JqZWN0IGlzIGFjdHVhbGx5IGp1c3QgdGhlIGluaXQgY29uc3RydWN0b3IgJ2VuaGFu Y2VkJworCXJldHVybiBuZXcgalF1ZXJ5LmZuLmluaXQoIHNlbGVjdG9yLCBjb250ZXh0ICk7Cit9 OworCisvLyBBIHNpbXBsZSB3YXkgdG8gY2hlY2sgZm9yIEhUTUwgc3RyaW5ncyBvciBJRCBzdHJp bmdzCisvLyAoYm90aCBvZiB3aGljaCB3ZSBvcHRpbWl6ZSBmb3IpCit2YXIgcXVpY2tFeHByID0g L15bXjxdKig8KC58XHMpKz4pW14+XSokfF4jKFx3KykkLywKKworLy8gSXMgaXQgYSBzaW1wbGUg c2VsZWN0b3IKKwlpc1NpbXBsZSA9IC9eLlteOiNcW1wuXSokLywKKworLy8gV2lsbCBzcGVlZCB1 cCByZWZlcmVuY2VzIHRvIHVuZGVmaW5lZCwgYW5kIGFsbG93cyBtdW5naW5nIGl0cyBuYW1lLgor CXVuZGVmaW5lZDsKKworalF1ZXJ5LmZuID0galF1ZXJ5LnByb3RvdHlwZSA9IHsKKwlpbml0OiBm dW5jdGlvbiggc2VsZWN0b3IsIGNvbnRleHQgKSB7CisJCS8vIE1ha2Ugc3VyZSB0aGF0IGEgc2Vs ZWN0aW9uIHdhcyBwcm92aWRlZAorCQlzZWxlY3RvciA9IHNlbGVjdG9yIHx8IGRvY3VtZW50Owor CisJCS8vIEhhbmRsZSAkKERPTUVsZW1lbnQpCisJCWlmICggc2VsZWN0b3Iubm9kZVR5cGUgKSB7 CisJCQl0aGlzWzBdID0gc2VsZWN0b3I7CisJCQl0aGlzLmxlbmd0aCA9IDE7CisJCQlyZXR1cm4g dGhpczsKKwkJfQorCQkvLyBIYW5kbGUgSFRNTCBzdHJpbmdzCisJCWlmICggdHlwZW9mIHNlbGVj dG9yID09ICJzdHJpbmciICkgeworCQkJLy8gQXJlIHdlIGRlYWxpbmcgd2l0aCBIVE1MIHN0cmlu ZyBvciBhbiBJRD8KKwkJCXZhciBtYXRjaCA9IHF1aWNrRXhwci5leGVjKCBzZWxlY3RvciApOwor CisJCQkvLyBWZXJpZnkgYSBtYXRjaCwgYW5kIHRoYXQgbm8gY29udGV4dCB3YXMgc3BlY2lmaWVk IGZvciAjaWQKKwkJCWlmICggbWF0Y2ggJiYgKG1hdGNoWzFdIHx8ICFjb250ZXh0KSApIHsKKwor CQkJCS8vIEhBTkRMRTogJChodG1sKSAtPiAkKGFycmF5KQorCQkJCWlmICggbWF0Y2hbMV0gKQor CQkJCQlzZWxlY3RvciA9IGpRdWVyeS5jbGVhbiggWyBtYXRjaFsxXSBdLCBjb250ZXh0ICk7CisK KwkJCQkvLyBIQU5ETEU6ICQoIiNpZCIpCisJCQkJZWxzZSB7CisJCQkJCXZhciBlbGVtID0gZG9j dW1lbnQuZ2V0RWxlbWVudEJ5SWQoIG1hdGNoWzNdICk7CisKKwkJCQkJLy8gTWFrZSBzdXJlIGFu IGVsZW1lbnQgd2FzIGxvY2F0ZWQKKwkJCQkJaWYgKCBlbGVtICl7CisJCQkJCQkvLyBIYW5kbGUg dGhlIGNhc2Ugd2hlcmUgSUUgYW5kIE9wZXJhIHJldHVybiBpdGVtcworCQkJCQkJLy8gYnkgbmFt ZSBpbnN0ZWFkIG9mIElECisJCQkJCQlpZiAoIGVsZW0uaWQgIT0gbWF0Y2hbM10gKQorCQkJCQkJ CXJldHVybiBqUXVlcnkoKS5maW5kKCBzZWxlY3RvciApOworCisJCQkJCQkvLyBPdGhlcndpc2Us IHdlIGluamVjdCB0aGUgZWxlbWVudCBkaXJlY3RseSBpbnRvIHRoZSBqUXVlcnkgb2JqZWN0CisJ CQkJCQlyZXR1cm4galF1ZXJ5KCBlbGVtICk7CisJCQkJCX0KKwkJCQkJc2VsZWN0b3IgPSBbXTsK KwkJCQl9CisKKwkJCS8vIEhBTkRMRTogJChleHByLCBbY29udGV4dF0pCisJCQkvLyAod2hpY2gg aXMganVzdCBlcXVpdmFsZW50IHRvOiAkKGNvbnRlbnQpLmZpbmQoZXhwcikKKwkJCX0gZWxzZQor CQkJCXJldHVybiBqUXVlcnkoIGNvbnRleHQgKS5maW5kKCBzZWxlY3RvciApOworCisJCS8vIEhB TkRMRTogJChmdW5jdGlvbikKKwkJLy8gU2hvcnRjdXQgZm9yIGRvY3VtZW50IHJlYWR5CisJCX0g ZWxzZSBpZiAoIGpRdWVyeS5pc0Z1bmN0aW9uKCBzZWxlY3RvciApICkKKwkJCXJldHVybiBqUXVl cnkoIGRvY3VtZW50IClbIGpRdWVyeS5mbi5yZWFkeSA/ICJyZWFkeSIgOiAibG9hZCIgXSggc2Vs ZWN0b3IgKTsKKworCQlyZXR1cm4gdGhpcy5zZXRBcnJheShqUXVlcnkubWFrZUFycmF5KHNlbGVj dG9yKSk7CisJfSwKKworCS8vIFRoZSBjdXJyZW50IHZlcnNpb24gb2YgalF1ZXJ5IGJlaW5nIHVz ZWQKKwlqcXVlcnk6ICIxLjIuNiIsCisKKwkvLyBUaGUgbnVtYmVyIG9mIGVsZW1lbnRzIGNvbnRh aW5lZCBpbiB0aGUgbWF0Y2hlZCBlbGVtZW50IHNldAorCXNpemU6IGZ1bmN0aW9uKCkgeworCQly ZXR1cm4gdGhpcy5sZW5ndGg7CisJfSwKKworCS8vIFRoZSBudW1iZXIgb2YgZWxlbWVudHMgY29u dGFpbmVkIGluIHRoZSBtYXRjaGVkIGVsZW1lbnQgc2V0CisJbGVuZ3RoOiAwLAorCisJLy8gR2V0 IHRoZSBOdGggZWxlbWVudCBpbiB0aGUgbWF0Y2hlZCBlbGVtZW50IHNldCBPUgorCS8vIEdldCB0 aGUgd2hvbGUgbWF0Y2hlZCBlbGVtZW50IHNldCBhcyBhIGNsZWFuIGFycmF5CisJZ2V0OiBmdW5j dGlvbiggbnVtICkgeworCQlyZXR1cm4gbnVtID09IHVuZGVmaW5lZCA/CisKKwkJCS8vIFJldHVy biBhICdjbGVhbicgYXJyYXkKKwkJCWpRdWVyeS5tYWtlQXJyYXkoIHRoaXMgKSA6CisKKwkJCS8v IFJldHVybiBqdXN0IHRoZSBvYmplY3QKKwkJCXRoaXNbIG51bSBdOworCX0sCisKKwkvLyBUYWtl IGFuIGFycmF5IG9mIGVsZW1lbnRzIGFuZCBwdXNoIGl0IG9udG8gdGhlIHN0YWNrCisJLy8gKHJl dHVybmluZyB0aGUgbmV3IG1hdGNoZWQgZWxlbWVudCBzZXQpCisJcHVzaFN0YWNrOiBmdW5jdGlv biggZWxlbXMgKSB7CisJCS8vIEJ1aWxkIGEgbmV3IGpRdWVyeSBtYXRjaGVkIGVsZW1lbnQgc2V0 CisJCXZhciByZXQgPSBqUXVlcnkoIGVsZW1zICk7CisKKwkJLy8gQWRkIHRoZSBvbGQgb2JqZWN0 IG9udG8gdGhlIHN0YWNrIChhcyBhIHJlZmVyZW5jZSkKKwkJcmV0LnByZXZPYmplY3QgPSB0aGlz OworCisJCS8vIFJldHVybiB0aGUgbmV3bHktZm9ybWVkIGVsZW1lbnQgc2V0CisJCXJldHVybiBy ZXQ7CisJfSwKKworCS8vIEZvcmNlIHRoZSBjdXJyZW50IG1hdGNoZWQgc2V0IG9mIGVsZW1lbnRz IHRvIGJlY29tZQorCS8vIHRoZSBzcGVjaWZpZWQgYXJyYXkgb2YgZWxlbWVudHMgKGRlc3Ryb3lp bmcgdGhlIHN0YWNrIGluIHRoZSBwcm9jZXNzKQorCS8vIFlvdSBzaG91bGQgdXNlIHB1c2hTdGFj aygpIGluIG9yZGVyIHRvIGRvIHRoaXMsIGJ1dCBtYWludGFpbiB0aGUgc3RhY2sKKwlzZXRBcnJh eTogZnVuY3Rpb24oIGVsZW1zICkgeworCQkvLyBSZXNldHRpbmcgdGhlIGxlbmd0aCB0byAwLCB0 aGVuIHVzaW5nIHRoZSBuYXRpdmUgQXJyYXkgcHVzaAorCQkvLyBpcyBhIHN1cGVyLWZhc3Qgd2F5 IHRvIHBvcHVsYXRlIGFuIG9iamVjdCB3aXRoIGFycmF5LWxpa2UgcHJvcGVydGllcworCQl0aGlz Lmxlbmd0aCA9IDA7CisJCUFycmF5LnByb3RvdHlwZS5wdXNoLmFwcGx5KCB0aGlzLCBlbGVtcyAp OworCisJCXJldHVybiB0aGlzOworCX0sCisKKwkvLyBFeGVjdXRlIGEgY2FsbGJhY2sgZm9yIGV2 ZXJ5IGVsZW1lbnQgaW4gdGhlIG1hdGNoZWQgc2V0LgorCS8vIChZb3UgY2FuIHNlZWQgdGhlIGFy Z3VtZW50cyB3aXRoIGFuIGFycmF5IG9mIGFyZ3MsIGJ1dCB0aGlzIGlzCisJLy8gb25seSB1c2Vk IGludGVybmFsbHkuKQorCWVhY2g6IGZ1bmN0aW9uKCBjYWxsYmFjaywgYXJncyApIHsKKwkJcmV0 dXJuIGpRdWVyeS5lYWNoKCB0aGlzLCBjYWxsYmFjaywgYXJncyApOworCX0sCisKKwkvLyBEZXRl cm1pbmUgdGhlIHBvc2l0aW9uIG9mIGFuIGVsZW1lbnQgd2l0aGluCisJLy8gdGhlIG1hdGNoZWQg c2V0IG9mIGVsZW1lbnRzCisJaW5kZXg6IGZ1bmN0aW9uKCBlbGVtICkgeworCQl2YXIgcmV0ID0g LTE7CisKKwkJLy8gTG9jYXRlIHRoZSBwb3NpdGlvbiBvZiB0aGUgZGVzaXJlZCBlbGVtZW50CisJ CXJldHVybiBqUXVlcnkuaW5BcnJheSgKKwkJCS8vIElmIGl0IHJlY2VpdmVzIGEgalF1ZXJ5IG9i amVjdCwgdGhlIGZpcnN0IGVsZW1lbnQgaXMgdXNlZAorCQkJZWxlbSAmJiBlbGVtLmpxdWVyeSA/ IGVsZW1bMF0gOiBlbGVtCisJCSwgdGhpcyApOworCX0sCisKKwlhdHRyOiBmdW5jdGlvbiggbmFt ZSwgdmFsdWUsIHR5cGUgKSB7CisJCXZhciBvcHRpb25zID0gbmFtZTsKKworCQkvLyBMb29rIGZv ciB0aGUgY2FzZSB3aGVyZSB3ZSdyZSBhY2Nlc3NpbmcgYSBzdHlsZSB2YWx1ZQorCQlpZiAoIG5h bWUuY29uc3RydWN0b3IgPT0gU3RyaW5nICkKKwkJCWlmICggdmFsdWUgPT09IHVuZGVmaW5lZCAp CisJCQkJcmV0dXJuIHRoaXNbMF0gJiYgalF1ZXJ5WyB0eXBlIHx8ICJhdHRyIiBdKCB0aGlzWzBd LCBuYW1lICk7CisKKwkJCWVsc2UgeworCQkJCW9wdGlvbnMgPSB7fTsKKwkJCQlvcHRpb25zWyBu YW1lIF0gPSB2YWx1ZTsKKwkJCX0KKworCQkvLyBDaGVjayB0byBzZWUgaWYgd2UncmUgc2V0dGlu ZyBzdHlsZSB2YWx1ZXMKKwkJcmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbihpKXsKKwkJCS8vIFNl dCBhbGwgdGhlIHN0eWxlcworCQkJZm9yICggbmFtZSBpbiBvcHRpb25zICkKKwkJCQlqUXVlcnku YXR0cigKKwkJCQkJdHlwZSA/CisJCQkJCQl0aGlzLnN0eWxlIDoKKwkJCQkJCXRoaXMsCisJCQkJ CW5hbWUsIGpRdWVyeS5wcm9wKCB0aGlzLCBvcHRpb25zWyBuYW1lIF0sIHR5cGUsIGksIG5hbWUg KQorCQkJCSk7CisJCX0pOworCX0sCisKKwljc3M6IGZ1bmN0aW9uKCBrZXksIHZhbHVlICkgewor CQkvLyBpZ25vcmUgbmVnYXRpdmUgd2lkdGggYW5kIGhlaWdodCB2YWx1ZXMKKwkJaWYgKCAoa2V5 ID09ICd3aWR0aCcgfHwga2V5ID09ICdoZWlnaHQnKSAmJiBwYXJzZUZsb2F0KHZhbHVlKSA8IDAg KQorCQkJdmFsdWUgPSB1bmRlZmluZWQ7CisJCXJldHVybiB0aGlzLmF0dHIoIGtleSwgdmFsdWUs ICJjdXJDU1MiICk7CisJfSwKKworCXRleHQ6IGZ1bmN0aW9uKCB0ZXh0ICkgeworCQlpZiAoIHR5 cGVvZiB0ZXh0ICE9ICJvYmplY3QiICYmIHRleHQgIT0gbnVsbCApCisJCQlyZXR1cm4gdGhpcy5l bXB0eSgpLmFwcGVuZCggKHRoaXNbMF0gJiYgdGhpc1swXS5vd25lckRvY3VtZW50IHx8IGRvY3Vt ZW50KS5jcmVhdGVUZXh0Tm9kZSggdGV4dCApICk7CisKKwkJdmFyIHJldCA9ICIiOworCisJCWpR dWVyeS5lYWNoKCB0ZXh0IHx8IHRoaXMsIGZ1bmN0aW9uKCl7CisJCQlqUXVlcnkuZWFjaCggdGhp cy5jaGlsZE5vZGVzLCBmdW5jdGlvbigpeworCQkJCWlmICggdGhpcy5ub2RlVHlwZSAhPSA4ICkK KwkJCQkJcmV0ICs9IHRoaXMubm9kZVR5cGUgIT0gMSA/CisJCQkJCQl0aGlzLm5vZGVWYWx1ZSA6 CisJCQkJCQlqUXVlcnkuZm4udGV4dCggWyB0aGlzIF0gKTsKKwkJCX0pOworCQl9KTsKKworCQly ZXR1cm4gcmV0OworCX0sCisKKwl3cmFwQWxsOiBmdW5jdGlvbiggaHRtbCApIHsKKwkJaWYgKCB0 aGlzWzBdICkKKwkJCS8vIFRoZSBlbGVtZW50cyB0byB3cmFwIHRoZSB0YXJnZXQgYXJvdW5kCisJ CQlqUXVlcnkoIGh0bWwsIHRoaXNbMF0ub3duZXJEb2N1bWVudCApCisJCQkJLmNsb25lKCkKKwkJ CQkuaW5zZXJ0QmVmb3JlKCB0aGlzWzBdICkKKwkJCQkubWFwKGZ1bmN0aW9uKCl7CisJCQkJCXZh ciBlbGVtID0gdGhpczsKKworCQkJCQl3aGlsZSAoIGVsZW0uZmlyc3RDaGlsZCApCisJCQkJCQll bGVtID0gZWxlbS5maXJzdENoaWxkOworCisJCQkJCXJldHVybiBlbGVtOworCQkJCX0pCisJCQkJ LmFwcGVuZCh0aGlzKTsKKworCQlyZXR1cm4gdGhpczsKKwl9LAorCisJd3JhcElubmVyOiBmdW5j dGlvbiggaHRtbCApIHsKKwkJcmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbigpeworCQkJalF1ZXJ5 KCB0aGlzICkuY29udGVudHMoKS53cmFwQWxsKCBodG1sICk7CisJCX0pOworCX0sCisKKwl3cmFw OiBmdW5jdGlvbiggaHRtbCApIHsKKwkJcmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbigpeworCQkJ alF1ZXJ5KCB0aGlzICkud3JhcEFsbCggaHRtbCApOworCQl9KTsKKwl9LAorCisJYXBwZW5kOiBm dW5jdGlvbigpIHsKKwkJcmV0dXJuIHRoaXMuZG9tTWFuaXAoYXJndW1lbnRzLCB0cnVlLCBmYWxz ZSwgZnVuY3Rpb24oZWxlbSl7CisJCQlpZiAodGhpcy5ub2RlVHlwZSA9PSAxKQorCQkJCXRoaXMu YXBwZW5kQ2hpbGQoIGVsZW0gKTsKKwkJfSk7CisJfSwKKworCXByZXBlbmQ6IGZ1bmN0aW9uKCkg eworCQlyZXR1cm4gdGhpcy5kb21NYW5pcChhcmd1bWVudHMsIHRydWUsIHRydWUsIGZ1bmN0aW9u KGVsZW0peworCQkJaWYgKHRoaXMubm9kZVR5cGUgPT0gMSkKKwkJCQl0aGlzLmluc2VydEJlZm9y ZSggZWxlbSwgdGhpcy5maXJzdENoaWxkICk7CisJCX0pOworCX0sCisKKwliZWZvcmU6IGZ1bmN0 aW9uKCkgeworCQlyZXR1cm4gdGhpcy5kb21NYW5pcChhcmd1bWVudHMsIGZhbHNlLCBmYWxzZSwg ZnVuY3Rpb24oZWxlbSl7CisJCQl0aGlzLnBhcmVudE5vZGUuaW5zZXJ0QmVmb3JlKCBlbGVtLCB0 aGlzICk7CisJCX0pOworCX0sCisKKwlhZnRlcjogZnVuY3Rpb24oKSB7CisJCXJldHVybiB0aGlz LmRvbU1hbmlwKGFyZ3VtZW50cywgZmFsc2UsIHRydWUsIGZ1bmN0aW9uKGVsZW0peworCQkJdGhp cy5wYXJlbnROb2RlLmluc2VydEJlZm9yZSggZWxlbSwgdGhpcy5uZXh0U2libGluZyApOworCQl9 KTsKKwl9LAorCisJZW5kOiBmdW5jdGlvbigpIHsKKwkJcmV0dXJuIHRoaXMucHJldk9iamVjdCB8 fCBqUXVlcnkoIFtdICk7CisJfSwKKworCWZpbmQ6IGZ1bmN0aW9uKCBzZWxlY3RvciApIHsKKwkJ dmFyIGVsZW1zID0galF1ZXJ5Lm1hcCh0aGlzLCBmdW5jdGlvbihlbGVtKXsKKwkJCXJldHVybiBq UXVlcnkuZmluZCggc2VsZWN0b3IsIGVsZW0gKTsKKwkJfSk7CisKKwkJcmV0dXJuIHRoaXMucHVz aFN0YWNrKCAvW14rPl0gW14rPl0vLnRlc3QoIHNlbGVjdG9yICkgfHwgc2VsZWN0b3IuaW5kZXhP ZigiLi4iKSA+IC0xID8KKwkJCWpRdWVyeS51bmlxdWUoIGVsZW1zICkgOgorCQkJZWxlbXMgKTsK Kwl9LAorCisJY2xvbmU6IGZ1bmN0aW9uKCBldmVudHMgKSB7CisJCS8vIERvIHRoZSBjbG9uZQor CQl2YXIgcmV0ID0gdGhpcy5tYXAoZnVuY3Rpb24oKXsKKwkJCWlmICggalF1ZXJ5LmJyb3dzZXIu bXNpZSAmJiAhalF1ZXJ5LmlzWE1MRG9jKHRoaXMpICkgeworCQkJCS8vIElFIGNvcGllcyBldmVu dHMgYm91bmQgdmlhIGF0dGFjaEV2ZW50IHdoZW4KKwkJCQkvLyB1c2luZyBjbG9uZU5vZGUuIENh bGxpbmcgZGV0YWNoRXZlbnQgb24gdGhlCisJCQkJLy8gY2xvbmUgd2lsbCBhbHNvIHJlbW92ZSB0 aGUgZXZlbnRzIGZyb20gdGhlIG9yaWduYWwKKwkJCQkvLyBJbiBvcmRlciB0byBnZXQgYXJvdW5k IHRoaXMsIHdlIHVzZSBpbm5lckhUTUwuCisJCQkJLy8gVW5mb3J0dW5hdGVseSwgdGhpcyBtZWFu cyBzb21lIG1vZGlmaWNhdGlvbnMgdG8KKwkJCQkvLyBhdHRyaWJ1dGVzIGluIElFIHRoYXQgYXJl IGFjdHVhbGx5IG9ubHkgc3RvcmVkCisJCQkJLy8gYXMgcHJvcGVydGllcyB3aWxsIG5vdCBiZSBj b3BpZWQgKHN1Y2ggYXMgdGhlCisJCQkJLy8gdGhlIG5hbWUgYXR0cmlidXRlIG9uIGFuIGlucHV0 KS4KKwkJCQl2YXIgY2xvbmUgPSB0aGlzLmNsb25lTm9kZSh0cnVlKSwKKwkJCQkJY29udGFpbmVy ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiZGl2Iik7CisJCQkJY29udGFpbmVyLmFwcGVuZENo aWxkKGNsb25lKTsKKwkJCQlyZXR1cm4galF1ZXJ5LmNsZWFuKFtjb250YWluZXIuaW5uZXJIVE1M XSlbMF07CisJCQl9IGVsc2UKKwkJCQlyZXR1cm4gdGhpcy5jbG9uZU5vZGUodHJ1ZSk7CisJCX0p OworCisJCS8vIE5lZWQgdG8gc2V0IHRoZSBleHBhbmRvIHRvIG51bGwgb24gdGhlIGNsb25lZCBz ZXQgaWYgaXQgZXhpc3RzCisJCS8vIHJlbW92ZURhdGEgZG9lc24ndCB3b3JrIGhlcmUsIElFIHJl bW92ZXMgaXQgZnJvbSB0aGUgb3JpZ2luYWwgYXMgd2VsbAorCQkvLyB0aGlzIGlzIHByaW1hcmls eSBmb3IgSUUgYnV0IHRoZSBkYXRhIGV4cGFuZG8gc2hvdWxkbid0IGJlIGNvcGllZCBvdmVyIGlu IGFueSBicm93c2VyCisJCXZhciBjbG9uZSA9IHJldC5maW5kKCIqIikuYW5kU2VsZigpLmVhY2go ZnVuY3Rpb24oKXsKKwkJCWlmICggdGhpc1sgZXhwYW5kbyBdICE9IHVuZGVmaW5lZCApCisJCQkJ dGhpc1sgZXhwYW5kbyBdID0gbnVsbDsKKwkJfSk7CisKKwkJLy8gQ29weSB0aGUgZXZlbnRzIGZy b20gdGhlIG9yaWdpbmFsIHRvIHRoZSBjbG9uZQorCQlpZiAoIGV2ZW50cyA9PT0gdHJ1ZSApCisJ CQl0aGlzLmZpbmQoIioiKS5hbmRTZWxmKCkuZWFjaChmdW5jdGlvbihpKXsKKwkJCQlpZiAodGhp cy5ub2RlVHlwZSA9PSAzKQorCQkJCQlyZXR1cm47CisJCQkJdmFyIGV2ZW50cyA9IGpRdWVyeS5k YXRhKCB0aGlzLCAiZXZlbnRzIiApOworCisJCQkJZm9yICggdmFyIHR5cGUgaW4gZXZlbnRzICkK KwkJCQkJZm9yICggdmFyIGhhbmRsZXIgaW4gZXZlbnRzWyB0eXBlIF0gKQorCQkJCQkJalF1ZXJ5 LmV2ZW50LmFkZCggY2xvbmVbIGkgXSwgdHlwZSwgZXZlbnRzWyB0eXBlIF1bIGhhbmRsZXIgXSwg ZXZlbnRzWyB0eXBlIF1bIGhhbmRsZXIgXS5kYXRhICk7CisJCQl9KTsKKworCQkvLyBSZXR1cm4g dGhlIGNsb25lZCBzZXQKKwkJcmV0dXJuIHJldDsKKwl9LAorCisJZmlsdGVyOiBmdW5jdGlvbigg c2VsZWN0b3IgKSB7CisJCXJldHVybiB0aGlzLnB1c2hTdGFjaygKKwkJCWpRdWVyeS5pc0Z1bmN0 aW9uKCBzZWxlY3RvciApICYmCisJCQlqUXVlcnkuZ3JlcCh0aGlzLCBmdW5jdGlvbihlbGVtLCBp KXsKKwkJCQlyZXR1cm4gc2VsZWN0b3IuY2FsbCggZWxlbSwgaSApOworCQkJfSkgfHwKKworCQkJ alF1ZXJ5Lm11bHRpRmlsdGVyKCBzZWxlY3RvciwgdGhpcyApICk7CisJfSwKKworCW5vdDogZnVu Y3Rpb24oIHNlbGVjdG9yICkgeworCQlpZiAoIHNlbGVjdG9yLmNvbnN0cnVjdG9yID09IFN0cmlu ZyApCisJCQkvLyB0ZXN0IHNwZWNpYWwgY2FzZSB3aGVyZSBqdXN0IG9uZSBzZWxlY3RvciBpcyBw YXNzZWQgaW4KKwkJCWlmICggaXNTaW1wbGUudGVzdCggc2VsZWN0b3IgKSApCisJCQkJcmV0dXJu IHRoaXMucHVzaFN0YWNrKCBqUXVlcnkubXVsdGlGaWx0ZXIoIHNlbGVjdG9yLCB0aGlzLCB0cnVl ICkgKTsKKwkJCWVsc2UKKwkJCQlzZWxlY3RvciA9IGpRdWVyeS5tdWx0aUZpbHRlciggc2VsZWN0 b3IsIHRoaXMgKTsKKworCQl2YXIgaXNBcnJheUxpa2UgPSBzZWxlY3Rvci5sZW5ndGggJiYgc2Vs ZWN0b3Jbc2VsZWN0b3IubGVuZ3RoIC0gMV0gIT09IHVuZGVmaW5lZCAmJiAhc2VsZWN0b3Iubm9k ZVR5cGU7CisJCXJldHVybiB0aGlzLmZpbHRlcihmdW5jdGlvbigpIHsKKwkJCXJldHVybiBpc0Fy cmF5TGlrZSA/IGpRdWVyeS5pbkFycmF5KCB0aGlzLCBzZWxlY3RvciApIDwgMCA6IHRoaXMgIT0g c2VsZWN0b3I7CisJCX0pOworCX0sCisKKwlhZGQ6IGZ1bmN0aW9uKCBzZWxlY3RvciApIHsKKwkJ cmV0dXJuIHRoaXMucHVzaFN0YWNrKCBqUXVlcnkudW5pcXVlKCBqUXVlcnkubWVyZ2UoCisJCQl0 aGlzLmdldCgpLAorCQkJdHlwZW9mIHNlbGVjdG9yID09ICdzdHJpbmcnID8KKwkJCQlqUXVlcnko IHNlbGVjdG9yICkgOgorCQkJCWpRdWVyeS5tYWtlQXJyYXkoIHNlbGVjdG9yICkKKwkJKSkpOwor CX0sCisKKwlpczogZnVuY3Rpb24oIHNlbGVjdG9yICkgeworCQlyZXR1cm4gISFzZWxlY3RvciAm JiBqUXVlcnkubXVsdGlGaWx0ZXIoIHNlbGVjdG9yLCB0aGlzICkubGVuZ3RoID4gMDsKKwl9LAor CisJaGFzQ2xhc3M6IGZ1bmN0aW9uKCBzZWxlY3RvciApIHsKKwkJcmV0dXJuIHRoaXMuaXMoICIu IiArIHNlbGVjdG9yICk7CisJfSwKKworCXZhbDogZnVuY3Rpb24oIHZhbHVlICkgeworCQlpZiAo IHZhbHVlID09IHVuZGVmaW5lZCApIHsKKworCQkJaWYgKCB0aGlzLmxlbmd0aCApIHsKKwkJCQl2 YXIgZWxlbSA9IHRoaXNbMF07CisKKwkJCQkvLyBXZSBuZWVkIHRvIGhhbmRsZSBzZWxlY3QgYm94 ZXMgc3BlY2lhbAorCQkJCWlmICggalF1ZXJ5Lm5vZGVOYW1lKCBlbGVtLCAic2VsZWN0IiApICkg eworCQkJCQl2YXIgaW5kZXggPSBlbGVtLnNlbGVjdGVkSW5kZXgsCisJCQkJCQl2YWx1ZXMgPSBb XSwKKwkJCQkJCW9wdGlvbnMgPSBlbGVtLm9wdGlvbnMsCisJCQkJCQlvbmUgPSBlbGVtLnR5cGUg PT0gInNlbGVjdC1vbmUiOworCisJCQkJCS8vIE5vdGhpbmcgd2FzIHNlbGVjdGVkCisJCQkJCWlm ICggaW5kZXggPCAwICkKKwkJCQkJCXJldHVybiBudWxsOworCisJCQkJCS8vIExvb3AgdGhyb3Vn aCBhbGwgdGhlIHNlbGVjdGVkIG9wdGlvbnMKKwkJCQkJZm9yICggdmFyIGkgPSBvbmUgPyBpbmRl eCA6IDAsIG1heCA9IG9uZSA/IGluZGV4ICsgMSA6IG9wdGlvbnMubGVuZ3RoOyBpIDwgbWF4OyBp KysgKSB7CisJCQkJCQl2YXIgb3B0aW9uID0gb3B0aW9uc1sgaSBdOworCisJCQkJCQlpZiAoIG9w dGlvbi5zZWxlY3RlZCApIHsKKwkJCQkJCQkvLyBHZXQgdGhlIHNwZWNpZmMgdmFsdWUgZm9yIHRo ZSBvcHRpb24KKwkJCQkJCQl2YWx1ZSA9IGpRdWVyeS5icm93c2VyLm1zaWUgJiYgIW9wdGlvbi5h dHRyaWJ1dGVzLnZhbHVlLnNwZWNpZmllZCA/IG9wdGlvbi50ZXh0IDogb3B0aW9uLnZhbHVlOwor CisJCQkJCQkJLy8gV2UgZG9uJ3QgbmVlZCBhbiBhcnJheSBmb3Igb25lIHNlbGVjdHMKKwkJCQkJ CQlpZiAoIG9uZSApCisJCQkJCQkJCXJldHVybiB2YWx1ZTsKKworCQkJCQkJCS8vIE11bHRpLVNl bGVjdHMgcmV0dXJuIGFuIGFycmF5CisJCQkJCQkJdmFsdWVzLnB1c2goIHZhbHVlICk7CisJCQkJ CQl9CisJCQkJCX0KKworCQkJCQlyZXR1cm4gdmFsdWVzOworCisJCQkJLy8gRXZlcnl0aGluZyBl bHNlLCB3ZSBqdXN0IGdyYWIgdGhlIHZhbHVlCisJCQkJfSBlbHNlCisJCQkJCXJldHVybiAodGhp c1swXS52YWx1ZSB8fCAiIikucmVwbGFjZSgvXHIvZywgIiIpOworCisJCQl9CisKKwkJCXJldHVy biB1bmRlZmluZWQ7CisJCX0KKworCQlpZiggdmFsdWUuY29uc3RydWN0b3IgPT0gTnVtYmVyICkK KwkJCXZhbHVlICs9ICcnOworCisJCXJldHVybiB0aGlzLmVhY2goZnVuY3Rpb24oKXsKKwkJCWlm ICggdGhpcy5ub2RlVHlwZSAhPSAxICkKKwkJCQlyZXR1cm47CisKKwkJCWlmICggdmFsdWUuY29u c3RydWN0b3IgPT0gQXJyYXkgJiYgL3JhZGlvfGNoZWNrYm94Ly50ZXN0KCB0aGlzLnR5cGUgKSAp CisJCQkJdGhpcy5jaGVja2VkID0gKGpRdWVyeS5pbkFycmF5KHRoaXMudmFsdWUsIHZhbHVlKSA+ PSAwIHx8CisJCQkJCWpRdWVyeS5pbkFycmF5KHRoaXMubmFtZSwgdmFsdWUpID49IDApOworCisJ CQllbHNlIGlmICggalF1ZXJ5Lm5vZGVOYW1lKCB0aGlzLCAic2VsZWN0IiApICkgeworCQkJCXZh ciB2YWx1ZXMgPSBqUXVlcnkubWFrZUFycmF5KHZhbHVlKTsKKworCQkJCWpRdWVyeSggIm9wdGlv biIsIHRoaXMgKS5lYWNoKGZ1bmN0aW9uKCl7CisJCQkJCXRoaXMuc2VsZWN0ZWQgPSAoalF1ZXJ5 LmluQXJyYXkoIHRoaXMudmFsdWUsIHZhbHVlcyApID49IDAgfHwKKwkJCQkJCWpRdWVyeS5pbkFy cmF5KCB0aGlzLnRleHQsIHZhbHVlcyApID49IDApOworCQkJCX0pOworCisJCQkJaWYgKCAhdmFs dWVzLmxlbmd0aCApCisJCQkJCXRoaXMuc2VsZWN0ZWRJbmRleCA9IC0xOworCisJCQl9IGVsc2UK KwkJCQl0aGlzLnZhbHVlID0gdmFsdWU7CisJCX0pOworCX0sCisKKwlodG1sOiBmdW5jdGlvbigg dmFsdWUgKSB7CisJCXJldHVybiB2YWx1ZSA9PSB1bmRlZmluZWQgPworCQkJKHRoaXNbMF0gPwor CQkJCXRoaXNbMF0uaW5uZXJIVE1MIDoKKwkJCQludWxsKSA6CisJCQl0aGlzLmVtcHR5KCkuYXBw ZW5kKCB2YWx1ZSApOworCX0sCisKKwlyZXBsYWNlV2l0aDogZnVuY3Rpb24oIHZhbHVlICkgewor CQlyZXR1cm4gdGhpcy5hZnRlciggdmFsdWUgKS5yZW1vdmUoKTsKKwl9LAorCisJZXE6IGZ1bmN0 aW9uKCBpICkgeworCQlyZXR1cm4gdGhpcy5zbGljZSggaSwgaSArIDEgKTsKKwl9LAorCisJc2xp Y2U6IGZ1bmN0aW9uKCkgeworCQlyZXR1cm4gdGhpcy5wdXNoU3RhY2soIEFycmF5LnByb3RvdHlw ZS5zbGljZS5hcHBseSggdGhpcywgYXJndW1lbnRzICkgKTsKKwl9LAorCisJbWFwOiBmdW5jdGlv biggY2FsbGJhY2sgKSB7CisJCXJldHVybiB0aGlzLnB1c2hTdGFjayggalF1ZXJ5Lm1hcCh0aGlz LCBmdW5jdGlvbihlbGVtLCBpKXsKKwkJCXJldHVybiBjYWxsYmFjay5jYWxsKCBlbGVtLCBpLCBl bGVtICk7CisJCX0pKTsKKwl9LAorCisJYW5kU2VsZjogZnVuY3Rpb24oKSB7CisJCXJldHVybiB0 aGlzLmFkZCggdGhpcy5wcmV2T2JqZWN0ICk7CisJfSwKKworCWRhdGE6IGZ1bmN0aW9uKCBrZXks IHZhbHVlICl7CisJCXZhciBwYXJ0cyA9IGtleS5zcGxpdCgiLiIpOworCQlwYXJ0c1sxXSA9IHBh cnRzWzFdID8gIi4iICsgcGFydHNbMV0gOiAiIjsKKworCQlpZiAoIHZhbHVlID09PSB1bmRlZmlu ZWQgKSB7CisJCQl2YXIgZGF0YSA9IHRoaXMudHJpZ2dlckhhbmRsZXIoImdldERhdGEiICsgcGFy dHNbMV0gKyAiISIsIFtwYXJ0c1swXV0pOworCisJCQlpZiAoIGRhdGEgPT09IHVuZGVmaW5lZCAm JiB0aGlzLmxlbmd0aCApCisJCQkJZGF0YSA9IGpRdWVyeS5kYXRhKCB0aGlzWzBdLCBrZXkgKTsK KworCQkJcmV0dXJuIGRhdGEgPT09IHVuZGVmaW5lZCAmJiBwYXJ0c1sxXSA/CisJCQkJdGhpcy5k YXRhKCBwYXJ0c1swXSApIDoKKwkJCQlkYXRhOworCQl9IGVsc2UKKwkJCXJldHVybiB0aGlzLnRy aWdnZXIoInNldERhdGEiICsgcGFydHNbMV0gKyAiISIsIFtwYXJ0c1swXSwgdmFsdWVdKS5lYWNo KGZ1bmN0aW9uKCl7CisJCQkJalF1ZXJ5LmRhdGEoIHRoaXMsIGtleSwgdmFsdWUgKTsKKwkJCX0p OworCX0sCisKKwlyZW1vdmVEYXRhOiBmdW5jdGlvbigga2V5ICl7CisJCXJldHVybiB0aGlzLmVh Y2goZnVuY3Rpb24oKXsKKwkJCWpRdWVyeS5yZW1vdmVEYXRhKCB0aGlzLCBrZXkgKTsKKwkJfSk7 CisJfSwKKworCWRvbU1hbmlwOiBmdW5jdGlvbiggYXJncywgdGFibGUsIHJldmVyc2UsIGNhbGxi YWNrICkgeworCQl2YXIgY2xvbmUgPSB0aGlzLmxlbmd0aCA+IDEsIGVsZW1zOworCisJCXJldHVy biB0aGlzLmVhY2goZnVuY3Rpb24oKXsKKwkJCWlmICggIWVsZW1zICkgeworCQkJCWVsZW1zID0g alF1ZXJ5LmNsZWFuKCBhcmdzLCB0aGlzLm93bmVyRG9jdW1lbnQgKTsKKworCQkJCWlmICggcmV2 ZXJzZSApCisJCQkJCWVsZW1zLnJldmVyc2UoKTsKKwkJCX0KKworCQkJdmFyIG9iaiA9IHRoaXM7 CisKKwkJCWlmICggdGFibGUgJiYgalF1ZXJ5Lm5vZGVOYW1lKCB0aGlzLCAidGFibGUiICkgJiYg alF1ZXJ5Lm5vZGVOYW1lKCBlbGVtc1swXSwgInRyIiApICkKKwkJCQlvYmogPSB0aGlzLmdldEVs ZW1lbnRzQnlUYWdOYW1lKCJ0Ym9keSIpWzBdIHx8IHRoaXMuYXBwZW5kQ2hpbGQoIHRoaXMub3du ZXJEb2N1bWVudC5jcmVhdGVFbGVtZW50KCJ0Ym9keSIpICk7CisKKwkJCXZhciBzY3JpcHRzID0g alF1ZXJ5KCBbXSApOworCisJCQlqUXVlcnkuZWFjaChlbGVtcywgZnVuY3Rpb24oKXsKKwkJCQl2 YXIgZWxlbSA9IGNsb25lID8KKwkJCQkJalF1ZXJ5KCB0aGlzICkuY2xvbmUoIHRydWUgKVswXSA6 CisJCQkJCXRoaXM7CisKKwkJCQkvLyBleGVjdXRlIGFsbCBzY3JpcHRzIGFmdGVyIHRoZSBlbGVt ZW50cyBoYXZlIGJlZW4gaW5qZWN0ZWQKKwkJCQlpZiAoIGpRdWVyeS5ub2RlTmFtZSggZWxlbSwg InNjcmlwdCIgKSApCisJCQkJCXNjcmlwdHMgPSBzY3JpcHRzLmFkZCggZWxlbSApOworCQkJCWVs c2UgeworCQkJCQkvLyBSZW1vdmUgYW55IGlubmVyIHNjcmlwdHMgZm9yIGxhdGVyIGV2YWx1YXRp b24KKwkJCQkJaWYgKCBlbGVtLm5vZGVUeXBlID09IDEgKQorCQkJCQkJc2NyaXB0cyA9IHNjcmlw dHMuYWRkKCBqUXVlcnkoICJzY3JpcHQiLCBlbGVtICkucmVtb3ZlKCkgKTsKKworCQkJCQkvLyBJ bmplY3QgdGhlIGVsZW1lbnRzIGludG8gdGhlIGRvY3VtZW50CisJCQkJCWNhbGxiYWNrLmNhbGwo IG9iaiwgZWxlbSApOworCQkJCX0KKwkJCX0pOworCisJCQlzY3JpcHRzLmVhY2goIGV2YWxTY3Jp cHQgKTsKKwkJfSk7CisJfQorfTsKKworLy8gR2l2ZSB0aGUgaW5pdCBmdW5jdGlvbiB0aGUgalF1 ZXJ5IHByb3RvdHlwZSBmb3IgbGF0ZXIgaW5zdGFudGlhdGlvbgoralF1ZXJ5LmZuLmluaXQucHJv dG90eXBlID0galF1ZXJ5LmZuOworCitmdW5jdGlvbiBldmFsU2NyaXB0KCBpLCBlbGVtICkgewor CWlmICggZWxlbS5zcmMgKQorCQlqUXVlcnkuYWpheCh7CisJCQl1cmw6IGVsZW0uc3JjLAorCQkJ YXN5bmM6IGZhbHNlLAorCQkJZGF0YVR5cGU6ICJzY3JpcHQiCisJCX0pOworCisJZWxzZQorCQlq UXVlcnkuZ2xvYmFsRXZhbCggZWxlbS50ZXh0IHx8IGVsZW0udGV4dENvbnRlbnQgfHwgZWxlbS5p bm5lckhUTUwgfHwgIiIgKTsKKworCWlmICggZWxlbS5wYXJlbnROb2RlICkKKwkJZWxlbS5wYXJl bnROb2RlLnJlbW92ZUNoaWxkKCBlbGVtICk7Cit9CisKK2Z1bmN0aW9uIG5vdygpeworCXJldHVy biArbmV3IERhdGU7Cit9CisKK2pRdWVyeS5leHRlbmQgPSBqUXVlcnkuZm4uZXh0ZW5kID0gZnVu Y3Rpb24oKSB7CisJLy8gY29weSByZWZlcmVuY2UgdG8gdGFyZ2V0IG9iamVjdAorCXZhciB0YXJn ZXQgPSBhcmd1bWVudHNbMF0gfHwge30sIGkgPSAxLCBsZW5ndGggPSBhcmd1bWVudHMubGVuZ3Ro LCBkZWVwID0gZmFsc2UsIG9wdGlvbnM7CisKKwkvLyBIYW5kbGUgYSBkZWVwIGNvcHkgc2l0dWF0 aW9uCisJaWYgKCB0YXJnZXQuY29uc3RydWN0b3IgPT0gQm9vbGVhbiApIHsKKwkJZGVlcCA9IHRh cmdldDsKKwkJdGFyZ2V0ID0gYXJndW1lbnRzWzFdIHx8IHt9OworCQkvLyBza2lwIHRoZSBib29s ZWFuIGFuZCB0aGUgdGFyZ2V0CisJCWkgPSAyOworCX0KKworCS8vIEhhbmRsZSBjYXNlIHdoZW4g dGFyZ2V0IGlzIGEgc3RyaW5nIG9yIHNvbWV0aGluZyAocG9zc2libGUgaW4gZGVlcCBjb3B5KQor CWlmICggdHlwZW9mIHRhcmdldCAhPSAib2JqZWN0IiAmJiB0eXBlb2YgdGFyZ2V0ICE9ICJmdW5j dGlvbiIgKQorCQl0YXJnZXQgPSB7fTsKKworCS8vIGV4dGVuZCBqUXVlcnkgaXRzZWxmIGlmIG9u bHkgb25lIGFyZ3VtZW50IGlzIHBhc3NlZAorCWlmICggbGVuZ3RoID09IGkgKSB7CisJCXRhcmdl dCA9IHRoaXM7CisJCS0taTsKKwl9CisKKwlmb3IgKCA7IGkgPCBsZW5ndGg7IGkrKyApCisJCS8v IE9ubHkgZGVhbCB3aXRoIG5vbi1udWxsL3VuZGVmaW5lZCB2YWx1ZXMKKwkJaWYgKCAob3B0aW9u cyA9IGFyZ3VtZW50c1sgaSBdKSAhPSBudWxsICkKKwkJCS8vIEV4dGVuZCB0aGUgYmFzZSBvYmpl Y3QKKwkJCWZvciAoIHZhciBuYW1lIGluIG9wdGlvbnMgKSB7CisJCQkJdmFyIHNyYyA9IHRhcmdl dFsgbmFtZSBdLCBjb3B5ID0gb3B0aW9uc1sgbmFtZSBdOworCisJCQkJLy8gUHJldmVudCBuZXZl ci1lbmRpbmcgbG9vcAorCQkJCWlmICggdGFyZ2V0ID09PSBjb3B5ICkKKwkJCQkJY29udGludWU7 CisKKwkJCQkvLyBSZWN1cnNlIGlmIHdlJ3JlIG1lcmdpbmcgb2JqZWN0IHZhbHVlcworCQkJCWlm ICggZGVlcCAmJiBjb3B5ICYmIHR5cGVvZiBjb3B5ID09ICJvYmplY3QiICYmICFjb3B5Lm5vZGVU eXBlICkKKwkJCQkJdGFyZ2V0WyBuYW1lIF0gPSBqUXVlcnkuZXh0ZW5kKCBkZWVwLCAKKwkJCQkJ CS8vIE5ldmVyIG1vdmUgb3JpZ2luYWwgb2JqZWN0cywgY2xvbmUgdGhlbQorCQkJCQkJc3JjIHx8 ICggY29weS5sZW5ndGggIT0gbnVsbCA/IFsgXSA6IHsgfSApCisJCQkJCSwgY29weSApOworCisJ CQkJLy8gRG9uJ3QgYnJpbmcgaW4gdW5kZWZpbmVkIHZhbHVlcworCQkJCWVsc2UgaWYgKCBjb3B5 ICE9PSB1bmRlZmluZWQgKQorCQkJCQl0YXJnZXRbIG5hbWUgXSA9IGNvcHk7CisKKwkJCX0KKwor CS8vIFJldHVybiB0aGUgbW9kaWZpZWQgb2JqZWN0CisJcmV0dXJuIHRhcmdldDsKK307CisKK3Zh ciBleHBhbmRvID0gImpRdWVyeSIgKyBub3coKSwgdXVpZCA9IDAsIHdpbmRvd0RhdGEgPSB7fSwK KwkvLyBleGNsdWRlIHRoZSBmb2xsb3dpbmcgY3NzIHByb3BlcnRpZXMgdG8gYWRkIHB4CisJZXhj bHVkZSA9IC96LT9pbmRleHxmb250LT93ZWlnaHR8b3BhY2l0eXx6b29tfGxpbmUtP2hlaWdodC9p LAorCS8vIGNhY2hlIGRlZmF1bHRWaWV3CisJZGVmYXVsdFZpZXcgPSBkb2N1bWVudC5kZWZhdWx0 VmlldyB8fCB7fTsKKworalF1ZXJ5LmV4dGVuZCh7CisJbm9Db25mbGljdDogZnVuY3Rpb24oIGRl ZXAgKSB7CisJCXdpbmRvdy4kID0gXyQ7CisKKwkJaWYgKCBkZWVwICkKKwkJCXdpbmRvdy5qUXVl cnkgPSBfalF1ZXJ5OworCisJCXJldHVybiBqUXVlcnk7CisJfSwKKworCS8vIFNlZSB0ZXN0L3Vu aXQvY29yZS5qcyBmb3IgZGV0YWlscyBjb25jZXJuaW5nIHRoaXMgZnVuY3Rpb24uCisJaXNGdW5j dGlvbjogZnVuY3Rpb24oIGZuICkgeworCQlyZXR1cm4gISFmbiAmJiB0eXBlb2YgZm4gIT0gInN0 cmluZyIgJiYgIWZuLm5vZGVOYW1lICYmCisJCQlmbi5jb25zdHJ1Y3RvciAhPSBBcnJheSAmJiAv Xltcc1tdP2Z1bmN0aW9uLy50ZXN0KCBmbiArICIiICk7CisJfSwKKworCS8vIGNoZWNrIGlmIGFu IGVsZW1lbnQgaXMgaW4gYSAob3IgaXMgYW4pIFhNTCBkb2N1bWVudAorCWlzWE1MRG9jOiBmdW5j dGlvbiggZWxlbSApIHsKKwkJcmV0dXJuIGVsZW0uZG9jdW1lbnRFbGVtZW50ICYmICFlbGVtLmJv ZHkgfHwKKwkJCWVsZW0udGFnTmFtZSAmJiBlbGVtLm93bmVyRG9jdW1lbnQgJiYgIWVsZW0ub3du ZXJEb2N1bWVudC5ib2R5OworCX0sCisKKwkvLyBFdmFsdWxhdGVzIGEgc2NyaXB0IGluIGEgZ2xv YmFsIGNvbnRleHQKKwlnbG9iYWxFdmFsOiBmdW5jdGlvbiggZGF0YSApIHsKKwkJZGF0YSA9IGpR dWVyeS50cmltKCBkYXRhICk7CisKKwkJaWYgKCBkYXRhICkgeworCQkJLy8gSW5zcGlyZWQgYnkg Y29kZSBieSBBbmRyZWEgR2lhbW1hcmNoaQorCQkJLy8gaHR0cDovL3dlYnJlZmxlY3Rpb24uYmxv Z3Nwb3QuY29tLzIwMDcvMDgvZ2xvYmFsLXNjb3BlLWV2YWx1YXRpb24tYW5kLWRvbS5odG1sCisJ CQl2YXIgaGVhZCA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCJoZWFkIilbMF0gfHwg ZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LAorCQkJCXNjcmlwdCA9IGRvY3VtZW50LmNyZWF0ZUVs ZW1lbnQoInNjcmlwdCIpOworCisJCQlzY3JpcHQudHlwZSA9ICJ0ZXh0L2phdmFzY3JpcHQiOwor CQkJaWYgKCBqUXVlcnkuYnJvd3Nlci5tc2llICkKKwkJCQlzY3JpcHQudGV4dCA9IGRhdGE7CisJ CQllbHNlCisJCQkJc2NyaXB0LmFwcGVuZENoaWxkKCBkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZSgg ZGF0YSApICk7CisKKwkJCS8vIFVzZSBpbnNlcnRCZWZvcmUgaW5zdGVhZCBvZiBhcHBlbmRDaGls ZCAgdG8gY2lyY3VtdmVudCBhbiBJRTYgYnVnLgorCQkJLy8gVGhpcyBhcmlzZXMgd2hlbiBhIGJh c2Ugbm9kZSBpcyB1c2VkICgjMjcwOSkuCisJCQloZWFkLmluc2VydEJlZm9yZSggc2NyaXB0LCBo ZWFkLmZpcnN0Q2hpbGQgKTsKKwkJCWhlYWQucmVtb3ZlQ2hpbGQoIHNjcmlwdCApOworCQl9CisJ fSwKKworCW5vZGVOYW1lOiBmdW5jdGlvbiggZWxlbSwgbmFtZSApIHsKKwkJcmV0dXJuIGVsZW0u bm9kZU5hbWUgJiYgZWxlbS5ub2RlTmFtZS50b1VwcGVyQ2FzZSgpID09IG5hbWUudG9VcHBlckNh c2UoKTsKKwl9LAorCisJY2FjaGU6IHt9LAorCisJZGF0YTogZnVuY3Rpb24oIGVsZW0sIG5hbWUs IGRhdGEgKSB7CisJCWVsZW0gPSBlbGVtID09IHdpbmRvdyA/CisJCQl3aW5kb3dEYXRhIDoKKwkJ CWVsZW07CisKKwkJdmFyIGlkID0gZWxlbVsgZXhwYW5kbyBdOworCisJCS8vIENvbXB1dGUgYSB1 bmlxdWUgSUQgZm9yIHRoZSBlbGVtZW50CisJCWlmICggIWlkICkKKwkJCWlkID0gZWxlbVsgZXhw YW5kbyBdID0gKyt1dWlkOworCisJCS8vIE9ubHkgZ2VuZXJhdGUgdGhlIGRhdGEgY2FjaGUgaWYg d2UncmUKKwkJLy8gdHJ5aW5nIHRvIGFjY2VzcyBvciBtYW5pcHVsYXRlIGl0CisJCWlmICggbmFt ZSAmJiAhalF1ZXJ5LmNhY2hlWyBpZCBdICkKKwkJCWpRdWVyeS5jYWNoZVsgaWQgXSA9IHt9Owor CisJCS8vIFByZXZlbnQgb3ZlcnJpZGluZyB0aGUgbmFtZWQgY2FjaGUgd2l0aCB1bmRlZmluZWQg dmFsdWVzCisJCWlmICggZGF0YSAhPT0gdW5kZWZpbmVkICkKKwkJCWpRdWVyeS5jYWNoZVsgaWQg XVsgbmFtZSBdID0gZGF0YTsKKworCQkvLyBSZXR1cm4gdGhlIG5hbWVkIGNhY2hlIGRhdGEsIG9y IHRoZSBJRCBmb3IgdGhlIGVsZW1lbnQKKwkJcmV0dXJuIG5hbWUgPworCQkJalF1ZXJ5LmNhY2hl WyBpZCBdWyBuYW1lIF0gOgorCQkJaWQ7CisJfSwKKworCXJlbW92ZURhdGE6IGZ1bmN0aW9uKCBl bGVtLCBuYW1lICkgeworCQllbGVtID0gZWxlbSA9PSB3aW5kb3cgPworCQkJd2luZG93RGF0YSA6 CisJCQllbGVtOworCisJCXZhciBpZCA9IGVsZW1bIGV4cGFuZG8gXTsKKworCQkvLyBJZiB3ZSB3 YW50IHRvIHJlbW92ZSBhIHNwZWNpZmljIHNlY3Rpb24gb2YgdGhlIGVsZW1lbnQncyBkYXRhCisJ CWlmICggbmFtZSApIHsKKwkJCWlmICggalF1ZXJ5LmNhY2hlWyBpZCBdICkgeworCQkJCS8vIFJl bW92ZSB0aGUgc2VjdGlvbiBvZiBjYWNoZSBkYXRhCisJCQkJZGVsZXRlIGpRdWVyeS5jYWNoZVsg aWQgXVsgbmFtZSBdOworCisJCQkJLy8gSWYgd2UndmUgcmVtb3ZlZCBhbGwgdGhlIGRhdGEsIHJl bW92ZSB0aGUgZWxlbWVudCdzIGNhY2hlCisJCQkJbmFtZSA9ICIiOworCisJCQkJZm9yICggbmFt ZSBpbiBqUXVlcnkuY2FjaGVbIGlkIF0gKQorCQkJCQlicmVhazsKKworCQkJCWlmICggIW5hbWUg KQorCQkJCQlqUXVlcnkucmVtb3ZlRGF0YSggZWxlbSApOworCQkJfQorCisJCS8vIE90aGVyd2lz ZSwgd2Ugd2FudCB0byByZW1vdmUgYWxsIG9mIHRoZSBlbGVtZW50J3MgZGF0YQorCQl9IGVsc2Ug eworCQkJLy8gQ2xlYW4gdXAgdGhlIGVsZW1lbnQgZXhwYW5kbworCQkJdHJ5IHsKKwkJCQlkZWxl dGUgZWxlbVsgZXhwYW5kbyBdOworCQkJfSBjYXRjaChlKXsKKwkJCQkvLyBJRSBoYXMgdHJvdWJs ZSBkaXJlY3RseSByZW1vdmluZyB0aGUgZXhwYW5kbworCQkJCS8vIGJ1dCBpdCdzIG9rIHdpdGgg dXNpbmcgcmVtb3ZlQXR0cmlidXRlCisJCQkJaWYgKCBlbGVtLnJlbW92ZUF0dHJpYnV0ZSApCisJ CQkJCWVsZW0ucmVtb3ZlQXR0cmlidXRlKCBleHBhbmRvICk7CisJCQl9CisKKwkJCS8vIENvbXBs ZXRlbHkgcmVtb3ZlIHRoZSBkYXRhIGNhY2hlCisJCQlkZWxldGUgalF1ZXJ5LmNhY2hlWyBpZCBd OworCQl9CisJfSwKKworCS8vIGFyZ3MgaXMgZm9yIGludGVybmFsIHVzYWdlIG9ubHkKKwllYWNo OiBmdW5jdGlvbiggb2JqZWN0LCBjYWxsYmFjaywgYXJncyApIHsKKwkJdmFyIG5hbWUsIGkgPSAw LCBsZW5ndGggPSBvYmplY3QubGVuZ3RoOworCisJCWlmICggYXJncyApIHsKKwkJCWlmICggbGVu Z3RoID09IHVuZGVmaW5lZCApIHsKKwkJCQlmb3IgKCBuYW1lIGluIG9iamVjdCApCisJCQkJCWlm ICggY2FsbGJhY2suYXBwbHkoIG9iamVjdFsgbmFtZSBdLCBhcmdzICkgPT09IGZhbHNlICkKKwkJ CQkJCWJyZWFrOworCQkJfSBlbHNlCisJCQkJZm9yICggOyBpIDwgbGVuZ3RoOyApCisJCQkJCWlm ICggY2FsbGJhY2suYXBwbHkoIG9iamVjdFsgaSsrIF0sIGFyZ3MgKSA9PT0gZmFsc2UgKQorCQkJ CQkJYnJlYWs7CisKKwkJLy8gQSBzcGVjaWFsLCBmYXN0LCBjYXNlIGZvciB0aGUgbW9zdCBjb21t b24gdXNlIG9mIGVhY2gKKwkJfSBlbHNlIHsKKwkJCWlmICggbGVuZ3RoID09IHVuZGVmaW5lZCAp IHsKKwkJCQlmb3IgKCBuYW1lIGluIG9iamVjdCApCisJCQkJCWlmICggY2FsbGJhY2suY2FsbCgg b2JqZWN0WyBuYW1lIF0sIG5hbWUsIG9iamVjdFsgbmFtZSBdICkgPT09IGZhbHNlICkKKwkJCQkJ CWJyZWFrOworCQkJfSBlbHNlCisJCQkJZm9yICggdmFyIHZhbHVlID0gb2JqZWN0WzBdOworCQkJ CQlpIDwgbGVuZ3RoICYmIGNhbGxiYWNrLmNhbGwoIHZhbHVlLCBpLCB2YWx1ZSApICE9PSBmYWxz ZTsgdmFsdWUgPSBvYmplY3RbKytpXSApe30KKwkJfQorCisJCXJldHVybiBvYmplY3Q7CisJfSwK KworCXByb3A6IGZ1bmN0aW9uKCBlbGVtLCB2YWx1ZSwgdHlwZSwgaSwgbmFtZSApIHsKKwkJLy8g SGFuZGxlIGV4ZWN1dGFibGUgZnVuY3Rpb25zCisJCWlmICggalF1ZXJ5LmlzRnVuY3Rpb24oIHZh bHVlICkgKQorCQkJdmFsdWUgPSB2YWx1ZS5jYWxsKCBlbGVtLCBpICk7CisKKwkJLy8gSGFuZGxl IHBhc3NpbmcgaW4gYSBudW1iZXIgdG8gYSBDU1MgcHJvcGVydHkKKwkJcmV0dXJuIHZhbHVlICYm IHZhbHVlLmNvbnN0cnVjdG9yID09IE51bWJlciAmJiB0eXBlID09ICJjdXJDU1MiICYmICFleGNs dWRlLnRlc3QoIG5hbWUgKSA/CisJCQl2YWx1ZSArICJweCIgOgorCQkJdmFsdWU7CisJfSwKKwor CWNsYXNzTmFtZTogeworCQkvLyBpbnRlcm5hbCBvbmx5LCB1c2UgYWRkQ2xhc3MoImNsYXNzIikK KwkJYWRkOiBmdW5jdGlvbiggZWxlbSwgY2xhc3NOYW1lcyApIHsKKwkJCWpRdWVyeS5lYWNoKChj bGFzc05hbWVzIHx8ICIiKS5zcGxpdCgvXHMrLyksIGZ1bmN0aW9uKGksIGNsYXNzTmFtZSl7CisJ CQkJaWYgKCBlbGVtLm5vZGVUeXBlID09IDEgJiYgIWpRdWVyeS5jbGFzc05hbWUuaGFzKCBlbGVt LmNsYXNzTmFtZSwgY2xhc3NOYW1lICkgKQorCQkJCQllbGVtLmNsYXNzTmFtZSArPSAoZWxlbS5j bGFzc05hbWUgPyAiICIgOiAiIikgKyBjbGFzc05hbWU7CisJCQl9KTsKKwkJfSwKKworCQkvLyBp bnRlcm5hbCBvbmx5LCB1c2UgcmVtb3ZlQ2xhc3MoImNsYXNzIikKKwkJcmVtb3ZlOiBmdW5jdGlv biggZWxlbSwgY2xhc3NOYW1lcyApIHsKKwkJCWlmIChlbGVtLm5vZGVUeXBlID09IDEpCisJCQkJ ZWxlbS5jbGFzc05hbWUgPSBjbGFzc05hbWVzICE9IHVuZGVmaW5lZCA/CisJCQkJCWpRdWVyeS5n cmVwKGVsZW0uY2xhc3NOYW1lLnNwbGl0KC9ccysvKSwgZnVuY3Rpb24oY2xhc3NOYW1lKXsKKwkJ CQkJCXJldHVybiAhalF1ZXJ5LmNsYXNzTmFtZS5oYXMoIGNsYXNzTmFtZXMsIGNsYXNzTmFtZSAp OworCQkJCQl9KS5qb2luKCIgIikgOgorCQkJCQkiIjsKKwkJfSwKKworCQkvLyBpbnRlcm5hbCBv bmx5LCB1c2UgaGFzQ2xhc3MoImNsYXNzIikKKwkJaGFzOiBmdW5jdGlvbiggZWxlbSwgY2xhc3NO YW1lICkgeworCQkJcmV0dXJuIGpRdWVyeS5pbkFycmF5KCBjbGFzc05hbWUsIChlbGVtLmNsYXNz TmFtZSB8fCBlbGVtKS50b1N0cmluZygpLnNwbGl0KC9ccysvKSApID4gLTE7CisJCX0KKwl9LAor CisJLy8gQSBtZXRob2QgZm9yIHF1aWNrbHkgc3dhcHBpbmcgaW4vb3V0IENTUyBwcm9wZXJ0aWVz IHRvIGdldCBjb3JyZWN0IGNhbGN1bGF0aW9ucworCXN3YXA6IGZ1bmN0aW9uKCBlbGVtLCBvcHRp b25zLCBjYWxsYmFjayApIHsKKwkJdmFyIG9sZCA9IHt9OworCQkvLyBSZW1lbWJlciB0aGUgb2xk IHZhbHVlcywgYW5kIGluc2VydCB0aGUgbmV3IG9uZXMKKwkJZm9yICggdmFyIG5hbWUgaW4gb3B0 aW9ucyApIHsKKwkJCW9sZFsgbmFtZSBdID0gZWxlbS5zdHlsZVsgbmFtZSBdOworCQkJZWxlbS5z dHlsZVsgbmFtZSBdID0gb3B0aW9uc1sgbmFtZSBdOworCQl9CisKKwkJY2FsbGJhY2suY2FsbCgg ZWxlbSApOworCisJCS8vIFJldmVydCB0aGUgb2xkIHZhbHVlcworCQlmb3IgKCB2YXIgbmFtZSBp biBvcHRpb25zICkKKwkJCWVsZW0uc3R5bGVbIG5hbWUgXSA9IG9sZFsgbmFtZSBdOworCX0sCisK Kwljc3M6IGZ1bmN0aW9uKCBlbGVtLCBuYW1lLCBmb3JjZSApIHsKKwkJaWYgKCBuYW1lID09ICJ3 aWR0aCIgfHwgbmFtZSA9PSAiaGVpZ2h0IiApIHsKKwkJCXZhciB2YWwsIHByb3BzID0geyBwb3Np dGlvbjogImFic29sdXRlIiwgdmlzaWJpbGl0eTogImhpZGRlbiIsIGRpc3BsYXk6ImJsb2NrIiB9 LCB3aGljaCA9IG5hbWUgPT0gIndpZHRoIiA/IFsgIkxlZnQiLCAiUmlnaHQiIF0gOiBbICJUb3Ai LCAiQm90dG9tIiBdOworCisJCQlmdW5jdGlvbiBnZXRXSCgpIHsKKwkJCQl2YWwgPSBuYW1lID09 ICJ3aWR0aCIgPyBlbGVtLm9mZnNldFdpZHRoIDogZWxlbS5vZmZzZXRIZWlnaHQ7CisJCQkJdmFy IHBhZGRpbmcgPSAwLCBib3JkZXIgPSAwOworCQkJCWpRdWVyeS5lYWNoKCB3aGljaCwgZnVuY3Rp b24oKSB7CisJCQkJCXBhZGRpbmcgKz0gcGFyc2VGbG9hdChqUXVlcnkuY3VyQ1NTKCBlbGVtLCAi cGFkZGluZyIgKyB0aGlzLCB0cnVlKSkgfHwgMDsKKwkJCQkJYm9yZGVyICs9IHBhcnNlRmxvYXQo alF1ZXJ5LmN1ckNTUyggZWxlbSwgImJvcmRlciIgKyB0aGlzICsgIldpZHRoIiwgdHJ1ZSkpIHx8 IDA7CisJCQkJfSk7CisJCQkJdmFsIC09IE1hdGgucm91bmQocGFkZGluZyArIGJvcmRlcik7CisJ CQl9CisKKwkJCWlmICggalF1ZXJ5KGVsZW0pLmlzKCI6dmlzaWJsZSIpICkKKwkJCQlnZXRXSCgp OworCQkJZWxzZQorCQkJCWpRdWVyeS5zd2FwKCBlbGVtLCBwcm9wcywgZ2V0V0ggKTsKKworCQkJ cmV0dXJuIE1hdGgubWF4KDAsIHZhbCk7CisJCX0KKworCQlyZXR1cm4galF1ZXJ5LmN1ckNTUygg ZWxlbSwgbmFtZSwgZm9yY2UgKTsKKwl9LAorCisJY3VyQ1NTOiBmdW5jdGlvbiggZWxlbSwgbmFt ZSwgZm9yY2UgKSB7CisJCXZhciByZXQsIHN0eWxlID0gZWxlbS5zdHlsZTsKKworCQkvLyBBIGhl bHBlciBtZXRob2QgZm9yIGRldGVybWluaW5nIGlmIGFuIGVsZW1lbnQncyB2YWx1ZXMgYXJlIGJy b2tlbgorCQlmdW5jdGlvbiBjb2xvciggZWxlbSApIHsKKwkJCWlmICggIWpRdWVyeS5icm93c2Vy LnNhZmFyaSApCisJCQkJcmV0dXJuIGZhbHNlOworCisJCQkvLyBkZWZhdWx0VmlldyBpcyBjYWNo ZWQKKwkJCXZhciByZXQgPSBkZWZhdWx0Vmlldy5nZXRDb21wdXRlZFN0eWxlKCBlbGVtLCBudWxs ICk7CisJCQlyZXR1cm4gIXJldCB8fCByZXQuZ2V0UHJvcGVydHlWYWx1ZSgiY29sb3IiKSA9PSAi IjsKKwkJfQorCisJCS8vIFdlIG5lZWQgdG8gaGFuZGxlIG9wYWNpdHkgc3BlY2lhbCBpbiBJRQor CQlpZiAoIG5hbWUgPT0gIm9wYWNpdHkiICYmIGpRdWVyeS5icm93c2VyLm1zaWUgKSB7CisJCQly ZXQgPSBqUXVlcnkuYXR0ciggc3R5bGUsICJvcGFjaXR5IiApOworCisJCQlyZXR1cm4gcmV0ID09 ICIiID8KKwkJCQkiMSIgOgorCQkJCXJldDsKKwkJfQorCQkvLyBPcGVyYSBzb21ldGltZXMgd2ls bCBnaXZlIHRoZSB3cm9uZyBkaXNwbGF5IGFuc3dlciwgdGhpcyBmaXhlcyBpdCwgc2VlICMyMDM3 CisJCWlmICggalF1ZXJ5LmJyb3dzZXIub3BlcmEgJiYgbmFtZSA9PSAiZGlzcGxheSIgKSB7CisJ CQl2YXIgc2F2ZSA9IHN0eWxlLm91dGxpbmU7CisJCQlzdHlsZS5vdXRsaW5lID0gIjAgc29saWQg YmxhY2siOworCQkJc3R5bGUub3V0bGluZSA9IHNhdmU7CisJCX0KKworCQkvLyBNYWtlIHN1cmUg d2UncmUgdXNpbmcgdGhlIHJpZ2h0IG5hbWUgZm9yIGdldHRpbmcgdGhlIGZsb2F0IHZhbHVlCisJ CWlmICggbmFtZS5tYXRjaCggL2Zsb2F0L2kgKSApCisJCQluYW1lID0gc3R5bGVGbG9hdDsKKwor CQlpZiAoICFmb3JjZSAmJiBzdHlsZSAmJiBzdHlsZVsgbmFtZSBdICkKKwkJCXJldCA9IHN0eWxl WyBuYW1lIF07CisKKwkJZWxzZSBpZiAoIGRlZmF1bHRWaWV3LmdldENvbXB1dGVkU3R5bGUgKSB7 CisKKwkJCS8vIE9ubHkgImZsb2F0IiBpcyBuZWVkZWQgaGVyZQorCQkJaWYgKCBuYW1lLm1hdGNo KCAvZmxvYXQvaSApICkKKwkJCQluYW1lID0gImZsb2F0IjsKKworCQkJbmFtZSA9IG5hbWUucmVw bGFjZSggLyhbQS1aXSkvZywgIi0kMSIgKS50b0xvd2VyQ2FzZSgpOworCisJCQl2YXIgY29tcHV0 ZWRTdHlsZSA9IGRlZmF1bHRWaWV3LmdldENvbXB1dGVkU3R5bGUoIGVsZW0sIG51bGwgKTsKKwor CQkJaWYgKCBjb21wdXRlZFN0eWxlICYmICFjb2xvciggZWxlbSApICkKKwkJCQlyZXQgPSBjb21w dXRlZFN0eWxlLmdldFByb3BlcnR5VmFsdWUoIG5hbWUgKTsKKworCQkJLy8gSWYgdGhlIGVsZW1l bnQgaXNuJ3QgcmVwb3J0aW5nIGl0cyB2YWx1ZXMgcHJvcGVybHkgaW4gU2FmYXJpCisJCQkvLyB0 aGVuIHNvbWUgZGlzcGxheTogbm9uZSBlbGVtZW50cyBhcmUgaW52b2x2ZWQKKwkJCWVsc2Ugewor CQkJCXZhciBzd2FwID0gW10sIHN0YWNrID0gW10sIGEgPSBlbGVtLCBpID0gMDsKKworCQkJCS8v IExvY2F0ZSBhbGwgb2YgdGhlIHBhcmVudCBkaXNwbGF5OiBub25lIGVsZW1lbnRzCisJCQkJZm9y ICggOyBhICYmIGNvbG9yKGEpOyBhID0gYS5wYXJlbnROb2RlICkKKwkJCQkJc3RhY2sudW5zaGlm dChhKTsKKworCQkJCS8vIEdvIHRocm91Z2ggYW5kIG1ha2UgdGhlbSB2aXNpYmxlLCBidXQgaW4g cmV2ZXJzZQorCQkJCS8vIChJdCB3b3VsZCBiZSBiZXR0ZXIgaWYgd2Uga25ldyB0aGUgZXhhY3Qg ZGlzcGxheSB0eXBlIHRoYXQgdGhleSBoYWQpCisJCQkJZm9yICggOyBpIDwgc3RhY2subGVuZ3Ro OyBpKysgKQorCQkJCQlpZiAoIGNvbG9yKCBzdGFja1sgaSBdICkgKSB7CisJCQkJCQlzd2FwWyBp IF0gPSBzdGFja1sgaSBdLnN0eWxlLmRpc3BsYXk7CisJCQkJCQlzdGFja1sgaSBdLnN0eWxlLmRp c3BsYXkgPSAiYmxvY2siOworCQkJCQl9CisKKwkJCQkvLyBTaW5jZSB3ZSBmbGlwIHRoZSBkaXNw bGF5IHN0eWxlLCB3ZSBoYXZlIHRvIGhhbmRsZSB0aGF0CisJCQkJLy8gb25lIHNwZWNpYWwsIG90 aGVyd2lzZSBnZXQgdGhlIHZhbHVlCisJCQkJcmV0ID0gbmFtZSA9PSAiZGlzcGxheSIgJiYgc3dh cFsgc3RhY2subGVuZ3RoIC0gMSBdICE9IG51bGwgPworCQkJCQkibm9uZSIgOgorCQkJCQkoIGNv bXB1dGVkU3R5bGUgJiYgY29tcHV0ZWRTdHlsZS5nZXRQcm9wZXJ0eVZhbHVlKCBuYW1lICkgKSB8 fCAiIjsKKworCQkJCS8vIEZpbmFsbHksIHJldmVydCB0aGUgZGlzcGxheSBzdHlsZXMgYmFjawor CQkJCWZvciAoIGkgPSAwOyBpIDwgc3dhcC5sZW5ndGg7IGkrKyApCisJCQkJCWlmICggc3dhcFsg aSBdICE9IG51bGwgKQorCQkJCQkJc3RhY2tbIGkgXS5zdHlsZS5kaXNwbGF5ID0gc3dhcFsgaSBd OworCQkJfQorCisJCQkvLyBXZSBzaG91bGQgYWx3YXlzIGdldCBhIG51bWJlciBiYWNrIGZyb20g b3BhY2l0eQorCQkJaWYgKCBuYW1lID09ICJvcGFjaXR5IiAmJiByZXQgPT0gIiIgKQorCQkJCXJl dCA9ICIxIjsKKworCQl9IGVsc2UgaWYgKCBlbGVtLmN1cnJlbnRTdHlsZSApIHsKKwkJCXZhciBj YW1lbENhc2UgPSBuYW1lLnJlcGxhY2UoL1wtKFx3KS9nLCBmdW5jdGlvbihhbGwsIGxldHRlcil7 CisJCQkJcmV0dXJuIGxldHRlci50b1VwcGVyQ2FzZSgpOworCQkJfSk7CisKKwkJCXJldCA9IGVs ZW0uY3VycmVudFN0eWxlWyBuYW1lIF0gfHwgZWxlbS5jdXJyZW50U3R5bGVbIGNhbWVsQ2FzZSBd OworCisJCQkvLyBGcm9tIHRoZSBhd2Vzb21lIGhhY2sgYnkgRGVhbiBFZHdhcmRzCisJCQkvLyBo dHRwOi8vZXJpay5lYWUubmV0L2FyY2hpdmVzLzIwMDcvMDcvMjcvMTguNTQuMTUvI2NvbW1lbnQt MTAyMjkxCisKKwkJCS8vIElmIHdlJ3JlIG5vdCBkZWFsaW5nIHdpdGggYSByZWd1bGFyIHBpeGVs IG51bWJlcgorCQkJLy8gYnV0IGEgbnVtYmVyIHRoYXQgaGFzIGEgd2VpcmQgZW5kaW5nLCB3ZSBu ZWVkIHRvIGNvbnZlcnQgaXQgdG8gcGl4ZWxzCisJCQlpZiAoICEvXlxkKyhweCk/JC9pLnRlc3Qo IHJldCApICYmIC9eXGQvLnRlc3QoIHJldCApICkgeworCQkJCS8vIFJlbWVtYmVyIHRoZSBvcmln aW5hbCB2YWx1ZXMKKwkJCQl2YXIgbGVmdCA9IHN0eWxlLmxlZnQsIHJzTGVmdCA9IGVsZW0ucnVu dGltZVN0eWxlLmxlZnQ7CisKKwkJCQkvLyBQdXQgaW4gdGhlIG5ldyB2YWx1ZXMgdG8gZ2V0IGEg Y29tcHV0ZWQgdmFsdWUgb3V0CisJCQkJZWxlbS5ydW50aW1lU3R5bGUubGVmdCA9IGVsZW0uY3Vy cmVudFN0eWxlLmxlZnQ7CisJCQkJc3R5bGUubGVmdCA9IHJldCB8fCAwOworCQkJCXJldCA9IHN0 eWxlLnBpeGVsTGVmdCArICJweCI7CisKKwkJCQkvLyBSZXZlcnQgdGhlIGNoYW5nZWQgdmFsdWVz CisJCQkJc3R5bGUubGVmdCA9IGxlZnQ7CisJCQkJZWxlbS5ydW50aW1lU3R5bGUubGVmdCA9IHJz TGVmdDsKKwkJCX0KKwkJfQorCisJCXJldHVybiByZXQ7CisJfSwKKworCWNsZWFuOiBmdW5jdGlv biggZWxlbXMsIGNvbnRleHQgKSB7CisJCXZhciByZXQgPSBbXTsKKwkJY29udGV4dCA9IGNvbnRl eHQgfHwgZG9jdW1lbnQ7CisJCS8vICFjb250ZXh0LmNyZWF0ZUVsZW1lbnQgZmFpbHMgaW4gSUUg d2l0aCBhbiBlcnJvciBidXQgcmV0dXJucyB0eXBlb2YgJ29iamVjdCcKKwkJaWYgKHR5cGVvZiBj b250ZXh0LmNyZWF0ZUVsZW1lbnQgPT0gJ3VuZGVmaW5lZCcpCisJCQljb250ZXh0ID0gY29udGV4 dC5vd25lckRvY3VtZW50IHx8IGNvbnRleHRbMF0gJiYgY29udGV4dFswXS5vd25lckRvY3VtZW50 IHx8IGRvY3VtZW50OworCisJCWpRdWVyeS5lYWNoKGVsZW1zLCBmdW5jdGlvbihpLCBlbGVtKXsK KwkJCWlmICggIWVsZW0gKQorCQkJCXJldHVybjsKKworCQkJaWYgKCBlbGVtLmNvbnN0cnVjdG9y ID09IE51bWJlciApCisJCQkJZWxlbSArPSAnJzsKKworCQkJLy8gQ29udmVydCBodG1sIHN0cmlu ZyBpbnRvIERPTSBub2RlcworCQkJaWYgKCB0eXBlb2YgZWxlbSA9PSAic3RyaW5nIiApIHsKKwkJ CQkvLyBGaXggIlhIVE1MIi1zdHlsZSB0YWdzIGluIGFsbCBicm93c2VycworCQkJCWVsZW0gPSBl bGVtLnJlcGxhY2UoLyg8KFx3KylbXj5dKj8pXC8+L2csIGZ1bmN0aW9uKGFsbCwgZnJvbnQsIHRh Zyl7CisJCQkJCXJldHVybiB0YWcubWF0Y2goL14oYWJicnxicnxjb2x8aW1nfGlucHV0fGxpbmt8 bWV0YXxwYXJhbXxocnxhcmVhfGVtYmVkKSQvaSkgPworCQkJCQkJYWxsIDoKKwkJCQkJCWZyb250 ICsgIj48LyIgKyB0YWcgKyAiPiI7CisJCQkJfSk7CisKKwkJCQkvLyBUcmltIHdoaXRlc3BhY2Us IG90aGVyd2lzZSBpbmRleE9mIHdvbid0IHdvcmsgYXMgZXhwZWN0ZWQKKwkJCQl2YXIgdGFncyA9 IGpRdWVyeS50cmltKCBlbGVtICkudG9Mb3dlckNhc2UoKSwgZGl2ID0gY29udGV4dC5jcmVhdGVF bGVtZW50KCJkaXYiKTsKKworCQkJCXZhciB3cmFwID0KKwkJCQkJLy8gb3B0aW9uIG9yIG9wdGdy b3VwCisJCQkJCSF0YWdzLmluZGV4T2YoIjxvcHQiKSAmJgorCQkJCQlbIDEsICI8c2VsZWN0IG11 bHRpcGxlPSdtdWx0aXBsZSc+IiwgIjwvc2VsZWN0PiIgXSB8fAorCisJCQkJCSF0YWdzLmluZGV4 T2YoIjxsZWciKSAmJgorCQkJCQlbIDEsICI8ZmllbGRzZXQ+IiwgIjwvZmllbGRzZXQ+IiBdIHx8 CisKKwkJCQkJdGFncy5tYXRjaCgvXjwodGhlYWR8dGJvZHl8dGZvb3R8Y29sZ3xjYXApLykgJiYK KwkJCQkJWyAxLCAiPHRhYmxlPiIsICI8L3RhYmxlPiIgXSB8fAorCisJCQkJCSF0YWdzLmluZGV4 T2YoIjx0ciIpICYmCisJCQkJCVsgMiwgIjx0YWJsZT48dGJvZHk+IiwgIjwvdGJvZHk+PC90YWJs ZT4iIF0gfHwKKworCQkJCSAJLy8gPHRoZWFkPiBtYXRjaGVkIGFib3ZlCisJCQkJCSghdGFncy5p bmRleE9mKCI8dGQiKSB8fCAhdGFncy5pbmRleE9mKCI8dGgiKSkgJiYKKwkJCQkJWyAzLCAiPHRh YmxlPjx0Ym9keT48dHI+IiwgIjwvdHI+PC90Ym9keT48L3RhYmxlPiIgXSB8fAorCisJCQkJCSF0 YWdzLmluZGV4T2YoIjxjb2wiKSAmJgorCQkJCQlbIDIsICI8dGFibGU+PHRib2R5PjwvdGJvZHk+ PGNvbGdyb3VwPiIsICI8L2NvbGdyb3VwPjwvdGFibGU+IiBdIHx8CisKKwkJCQkJLy8gSUUgY2Fu J3Qgc2VyaWFsaXplIDxsaW5rPiBhbmQgPHNjcmlwdD4gdGFncyBub3JtYWxseQorCQkJCQlqUXVl cnkuYnJvd3Nlci5tc2llICYmCisJCQkJCVsgMSwgImRpdjxkaXY+IiwgIjwvZGl2PiIgXSB8fAor CisJCQkJCVsgMCwgIiIsICIiIF07CisKKwkJCQkvLyBHbyB0byBodG1sIGFuZCBiYWNrLCB0aGVu IHBlZWwgb2ZmIGV4dHJhIHdyYXBwZXJzCisJCQkJZGl2LmlubmVySFRNTCA9IHdyYXBbMV0gKyBl bGVtICsgd3JhcFsyXTsKKworCQkJCS8vIE1vdmUgdG8gdGhlIHJpZ2h0IGRlcHRoCisJCQkJd2hp bGUgKCB3cmFwWzBdLS0gKQorCQkJCQlkaXYgPSBkaXYubGFzdENoaWxkOworCisJCQkJLy8gUmVt b3ZlIElFJ3MgYXV0b2luc2VydGVkIDx0Ym9keT4gZnJvbSB0YWJsZSBmcmFnbWVudHMKKwkJCQlp ZiAoIGpRdWVyeS5icm93c2VyLm1zaWUgKSB7CisKKwkJCQkJLy8gU3RyaW5nIHdhcyBhIDx0YWJs ZT4sICptYXkqIGhhdmUgc3B1cmlvdXMgPHRib2R5PgorCQkJCQl2YXIgdGJvZHkgPSAhdGFncy5p bmRleE9mKCI8dGFibGUiKSAmJiB0YWdzLmluZGV4T2YoIjx0Ym9keSIpIDwgMCA/CisJCQkJCQlk aXYuZmlyc3RDaGlsZCAmJiBkaXYuZmlyc3RDaGlsZC5jaGlsZE5vZGVzIDoKKworCQkJCQkJLy8g U3RyaW5nIHdhcyBhIGJhcmUgPHRoZWFkPiBvciA8dGZvb3Q+CisJCQkJCQl3cmFwWzFdID09ICI8 dGFibGU+IiAmJiB0YWdzLmluZGV4T2YoIjx0Ym9keSIpIDwgMCA/CisJCQkJCQkJZGl2LmNoaWxk Tm9kZXMgOgorCQkJCQkJCVtdOworCisJCQkJCWZvciAoIHZhciBqID0gdGJvZHkubGVuZ3RoIC0g MTsgaiA+PSAwIDsgLS1qICkKKwkJCQkJCWlmICggalF1ZXJ5Lm5vZGVOYW1lKCB0Ym9keVsgaiBd LCAidGJvZHkiICkgJiYgIXRib2R5WyBqIF0uY2hpbGROb2Rlcy5sZW5ndGggKQorCQkJCQkJCXRi b2R5WyBqIF0ucGFyZW50Tm9kZS5yZW1vdmVDaGlsZCggdGJvZHlbIGogXSApOworCisJCQkJCS8v IElFIGNvbXBsZXRlbHkga2lsbHMgbGVhZGluZyB3aGl0ZXNwYWNlIHdoZW4gaW5uZXJIVE1MIGlz IHVzZWQKKwkJCQkJaWYgKCAvXlxzLy50ZXN0KCBlbGVtICkgKQorCQkJCQkJZGl2Lmluc2VydEJl Zm9yZSggY29udGV4dC5jcmVhdGVUZXh0Tm9kZSggZWxlbS5tYXRjaCgvXlxzKi8pWzBdICksIGRp di5maXJzdENoaWxkICk7CisKKwkJCQl9CisKKwkJCQllbGVtID0galF1ZXJ5Lm1ha2VBcnJheSgg ZGl2LmNoaWxkTm9kZXMgKTsKKwkJCX0KKworCQkJaWYgKCBlbGVtLmxlbmd0aCA9PT0gMCAmJiAo IWpRdWVyeS5ub2RlTmFtZSggZWxlbSwgImZvcm0iICkgJiYgIWpRdWVyeS5ub2RlTmFtZSggZWxl bSwgInNlbGVjdCIgKSkgKQorCQkJCXJldHVybjsKKworCQkJaWYgKCBlbGVtWzBdID09IHVuZGVm aW5lZCB8fCBqUXVlcnkubm9kZU5hbWUoIGVsZW0sICJmb3JtIiApIHx8IGVsZW0ub3B0aW9ucyAp CisJCQkJcmV0LnB1c2goIGVsZW0gKTsKKworCQkJZWxzZQorCQkJCXJldCA9IGpRdWVyeS5tZXJn ZSggcmV0LCBlbGVtICk7CisKKwkJfSk7CisKKwkJcmV0dXJuIHJldDsKKwl9LAorCisJYXR0cjog ZnVuY3Rpb24oIGVsZW0sIG5hbWUsIHZhbHVlICkgeworCQkvLyBkb24ndCBzZXQgYXR0cmlidXRl cyBvbiB0ZXh0IGFuZCBjb21tZW50IG5vZGVzCisJCWlmICghZWxlbSB8fCBlbGVtLm5vZGVUeXBl ID09IDMgfHwgZWxlbS5ub2RlVHlwZSA9PSA4KQorCQkJcmV0dXJuIHVuZGVmaW5lZDsKKworCQl2 YXIgbm90eG1sID0gIWpRdWVyeS5pc1hNTERvYyggZWxlbSApLAorCQkJLy8gV2hldGhlciB3ZSBh cmUgc2V0dGluZyAob3IgZ2V0dGluZykKKwkJCXNldCA9IHZhbHVlICE9PSB1bmRlZmluZWQsCisJ CQltc2llID0galF1ZXJ5LmJyb3dzZXIubXNpZTsKKworCQkvLyBUcnkgdG8gbm9ybWFsaXplL2Zp eCB0aGUgbmFtZQorCQluYW1lID0gbm90eG1sICYmIGpRdWVyeS5wcm9wc1sgbmFtZSBdIHx8IG5h bWU7CisKKwkJLy8gT25seSBkbyBhbGwgdGhlIGZvbGxvd2luZyBpZiB0aGlzIGlzIGEgbm9kZSAo ZmFzdGVyIGZvciBzdHlsZSkKKwkJLy8gSUUgZWxlbS5nZXRBdHRyaWJ1dGUgcGFzc2VzIGV2ZW4g Zm9yIHN0eWxlCisJCWlmICggZWxlbS50YWdOYW1lICkgeworCisJCQkvLyBUaGVzZSBhdHRyaWJ1 dGVzIHJlcXVpcmUgc3BlY2lhbCB0cmVhdG1lbnQKKwkJCXZhciBzcGVjaWFsID0gL2hyZWZ8c3Jj fHN0eWxlLy50ZXN0KCBuYW1lICk7CisKKwkJCS8vIFNhZmFyaSBtaXMtcmVwb3J0cyB0aGUgZGVm YXVsdCBzZWxlY3RlZCBwcm9wZXJ0eSBvZiBhIGhpZGRlbiBvcHRpb24KKwkJCS8vIEFjY2Vzc2lu ZyB0aGUgcGFyZW50J3Mgc2VsZWN0ZWRJbmRleCBwcm9wZXJ0eSBmaXhlcyBpdAorCQkJaWYgKCBu YW1lID09ICJzZWxlY3RlZCIgJiYgalF1ZXJ5LmJyb3dzZXIuc2FmYXJpICkKKwkJCQllbGVtLnBh cmVudE5vZGUuc2VsZWN0ZWRJbmRleDsKKworCQkJLy8gSWYgYXBwbGljYWJsZSwgYWNjZXNzIHRo ZSBhdHRyaWJ1dGUgdmlhIHRoZSBET00gMCB3YXkKKwkJCWlmICggbmFtZSBpbiBlbGVtICYmIG5v dHhtbCAmJiAhc3BlY2lhbCApIHsKKwkJCQlpZiAoIHNldCApeworCQkJCQkvLyBXZSBjYW4ndCBh bGxvdyB0aGUgdHlwZSBwcm9wZXJ0eSB0byBiZSBjaGFuZ2VkIChzaW5jZSBpdCBjYXVzZXMgcHJv YmxlbXMgaW4gSUUpCisJCQkJCWlmICggbmFtZSA9PSAidHlwZSIgJiYgalF1ZXJ5Lm5vZGVOYW1l KCBlbGVtLCAiaW5wdXQiICkgJiYgZWxlbS5wYXJlbnROb2RlICkKKwkJCQkJCXRocm93ICJ0eXBl IHByb3BlcnR5IGNhbid0IGJlIGNoYW5nZWQiOworCisJCQkJCWVsZW1bIG5hbWUgXSA9IHZhbHVl OworCQkJCX0KKworCQkJCS8vIGJyb3dzZXJzIGluZGV4IGVsZW1lbnRzIGJ5IGlkL25hbWUgb24g Zm9ybXMsIGdpdmUgcHJpb3JpdHkgdG8gYXR0cmlidXRlcy4KKwkJCQlpZiggalF1ZXJ5Lm5vZGVO YW1lKCBlbGVtLCAiZm9ybSIgKSAmJiBlbGVtLmdldEF0dHJpYnV0ZU5vZGUobmFtZSkgKQorCQkJ CQlyZXR1cm4gZWxlbS5nZXRBdHRyaWJ1dGVOb2RlKCBuYW1lICkubm9kZVZhbHVlOworCisJCQkJ cmV0dXJuIGVsZW1bIG5hbWUgXTsKKwkJCX0KKworCQkJaWYgKCBtc2llICYmIG5vdHhtbCAmJiAg bmFtZSA9PSAic3R5bGUiICkKKwkJCQlyZXR1cm4galF1ZXJ5LmF0dHIoIGVsZW0uc3R5bGUsICJj c3NUZXh0IiwgdmFsdWUgKTsKKworCQkJaWYgKCBzZXQgKQorCQkJCS8vIGNvbnZlcnQgdGhlIHZh bHVlIHRvIGEgc3RyaW5nIChhbGwgYnJvd3NlcnMgZG8gdGhpcyBidXQgSUUpIHNlZSAjMTA3MAor CQkJCWVsZW0uc2V0QXR0cmlidXRlKCBuYW1lLCAiIiArIHZhbHVlICk7CisKKwkJCXZhciBhdHRy ID0gbXNpZSAmJiBub3R4bWwgJiYgc3BlY2lhbAorCQkJCQkvLyBTb21lIGF0dHJpYnV0ZXMgcmVx dWlyZSBhIHNwZWNpYWwgY2FsbCBvbiBJRQorCQkJCQk/IGVsZW0uZ2V0QXR0cmlidXRlKCBuYW1l LCAyICkKKwkJCQkJOiBlbGVtLmdldEF0dHJpYnV0ZSggbmFtZSApOworCisJCQkvLyBOb24tZXhp c3RlbnQgYXR0cmlidXRlcyByZXR1cm4gbnVsbCwgd2Ugbm9ybWFsaXplIHRvIHVuZGVmaW5lZAor CQkJcmV0dXJuIGF0dHIgPT09IG51bGwgPyB1bmRlZmluZWQgOiBhdHRyOworCQl9CisKKwkJLy8g ZWxlbSBpcyBhY3R1YWxseSBlbGVtLnN0eWxlIC4uLiBzZXQgdGhlIHN0eWxlCisKKwkJLy8gSUUg dXNlcyBmaWx0ZXJzIGZvciBvcGFjaXR5CisJCWlmICggbXNpZSAmJiBuYW1lID09ICJvcGFjaXR5 IiApIHsKKwkJCWlmICggc2V0ICkgeworCQkJCS8vIElFIGhhcyB0cm91YmxlIHdpdGggb3BhY2l0 eSBpZiBpdCBkb2VzIG5vdCBoYXZlIGxheW91dAorCQkJCS8vIEZvcmNlIGl0IGJ5IHNldHRpbmcg dGhlIHpvb20gbGV2ZWwKKwkJCQllbGVtLnpvb20gPSAxOworCisJCQkJLy8gU2V0IHRoZSBhbHBo YSBmaWx0ZXIgdG8gc2V0IHRoZSBvcGFjaXR5CisJCQkJZWxlbS5maWx0ZXIgPSAoZWxlbS5maWx0 ZXIgfHwgIiIpLnJlcGxhY2UoIC9hbHBoYVwoW14pXSpcKS8sICIiICkgKworCQkJCQkocGFyc2VJ bnQoIHZhbHVlICkgKyAnJyA9PSAiTmFOIiA/ICIiIDogImFscGhhKG9wYWNpdHk9IiArIHZhbHVl ICogMTAwICsgIikiKTsKKwkJCX0KKworCQkJcmV0dXJuIGVsZW0uZmlsdGVyICYmIGVsZW0uZmls dGVyLmluZGV4T2YoIm9wYWNpdHk9IikgPj0gMCA/CisJCQkJKHBhcnNlRmxvYXQoIGVsZW0uZmls dGVyLm1hdGNoKC9vcGFjaXR5PShbXildKikvKVsxXSApIC8gMTAwKSArICcnOgorCQkJCSIiOwor CQl9CisKKwkJbmFtZSA9IG5hbWUucmVwbGFjZSgvLShbYS16XSkvaWcsIGZ1bmN0aW9uKGFsbCwg bGV0dGVyKXsKKwkJCXJldHVybiBsZXR0ZXIudG9VcHBlckNhc2UoKTsKKwkJfSk7CisKKwkJaWYg KCBzZXQgKQorCQkJZWxlbVsgbmFtZSBdID0gdmFsdWU7CisKKwkJcmV0dXJuIGVsZW1bIG5hbWUg XTsKKwl9LAorCisJdHJpbTogZnVuY3Rpb24oIHRleHQgKSB7CisJCXJldHVybiAodGV4dCB8fCAi IikucmVwbGFjZSggL15ccyt8XHMrJC9nLCAiIiApOworCX0sCisKKwltYWtlQXJyYXk6IGZ1bmN0 aW9uKCBhcnJheSApIHsKKwkJdmFyIHJldCA9IFtdOworCisJCWlmKCBhcnJheSAhPSBudWxsICl7 CisJCQl2YXIgaSA9IGFycmF5Lmxlbmd0aDsKKwkJCS8vdGhlIHdpbmRvdywgc3RyaW5ncyBhbmQg ZnVuY3Rpb25zIGFsc28gaGF2ZSAnbGVuZ3RoJworCQkJaWYoIGkgPT0gbnVsbCB8fCBhcnJheS5z cGxpdCB8fCBhcnJheS5zZXRJbnRlcnZhbCB8fCBhcnJheS5jYWxsICkKKwkJCQlyZXRbMF0gPSBh cnJheTsKKwkJCWVsc2UKKwkJCQl3aGlsZSggaSApCisJCQkJCXJldFstLWldID0gYXJyYXlbaV07 CisJCX0KKworCQlyZXR1cm4gcmV0OworCX0sCisKKwlpbkFycmF5OiBmdW5jdGlvbiggZWxlbSwg YXJyYXkgKSB7CisJCWZvciAoIHZhciBpID0gMCwgbGVuZ3RoID0gYXJyYXkubGVuZ3RoOyBpIDwg bGVuZ3RoOyBpKysgKQorCQkvLyBVc2UgPT09IGJlY2F1c2Ugb24gSUUsIHdpbmRvdyA9PSBkb2N1 bWVudAorCQkJaWYgKCBhcnJheVsgaSBdID09PSBlbGVtICkKKwkJCQlyZXR1cm4gaTsKKworCQly ZXR1cm4gLTE7CisJfSwKKworCW1lcmdlOiBmdW5jdGlvbiggZmlyc3QsIHNlY29uZCApIHsKKwkJ Ly8gV2UgaGF2ZSB0byBsb29wIHRoaXMgd2F5IGJlY2F1c2UgSUUgJiBPcGVyYSBvdmVyd3JpdGUg dGhlIGxlbmd0aAorCQkvLyBleHBhbmRvIG9mIGdldEVsZW1lbnRzQnlUYWdOYW1lCisJCXZhciBp ID0gMCwgZWxlbSwgcG9zID0gZmlyc3QubGVuZ3RoOworCQkvLyBBbHNvLCB3ZSBuZWVkIHRvIG1h a2Ugc3VyZSB0aGF0IHRoZSBjb3JyZWN0IGVsZW1lbnRzIGFyZSBiZWluZyByZXR1cm5lZAorCQkv LyAoSUUgcmV0dXJucyBjb21tZW50IG5vZGVzIGluIGEgJyonIHF1ZXJ5KQorCQlpZiAoIGpRdWVy eS5icm93c2VyLm1zaWUgKSB7CisJCQl3aGlsZSAoIGVsZW0gPSBzZWNvbmRbIGkrKyBdICkKKwkJ CQlpZiAoIGVsZW0ubm9kZVR5cGUgIT0gOCApCisJCQkJCWZpcnN0WyBwb3MrKyBdID0gZWxlbTsK KworCQl9IGVsc2UKKwkJCXdoaWxlICggZWxlbSA9IHNlY29uZFsgaSsrIF0gKQorCQkJCWZpcnN0 WyBwb3MrKyBdID0gZWxlbTsKKworCQlyZXR1cm4gZmlyc3Q7CisJfSwKKworCXVuaXF1ZTogZnVu Y3Rpb24oIGFycmF5ICkgeworCQl2YXIgcmV0ID0gW10sIGRvbmUgPSB7fTsKKworCQl0cnkgewor CisJCQlmb3IgKCB2YXIgaSA9IDAsIGxlbmd0aCA9IGFycmF5Lmxlbmd0aDsgaSA8IGxlbmd0aDsg aSsrICkgeworCQkJCXZhciBpZCA9IGpRdWVyeS5kYXRhKCBhcnJheVsgaSBdICk7CisKKwkJCQlp ZiAoICFkb25lWyBpZCBdICkgeworCQkJCQlkb25lWyBpZCBdID0gdHJ1ZTsKKwkJCQkJcmV0LnB1 c2goIGFycmF5WyBpIF0gKTsKKwkJCQl9CisJCQl9CisKKwkJfSBjYXRjaCggZSApIHsKKwkJCXJl dCA9IGFycmF5OworCQl9CisKKwkJcmV0dXJuIHJldDsKKwl9LAorCisJZ3JlcDogZnVuY3Rpb24o IGVsZW1zLCBjYWxsYmFjaywgaW52ICkgeworCQl2YXIgcmV0ID0gW107CisKKwkJLy8gR28gdGhy b3VnaCB0aGUgYXJyYXksIG9ubHkgc2F2aW5nIHRoZSBpdGVtcworCQkvLyB0aGF0IHBhc3MgdGhl IHZhbGlkYXRvciBmdW5jdGlvbgorCQlmb3IgKCB2YXIgaSA9IDAsIGxlbmd0aCA9IGVsZW1zLmxl bmd0aDsgaSA8IGxlbmd0aDsgaSsrICkKKwkJCWlmICggIWludiAhPSAhY2FsbGJhY2soIGVsZW1z WyBpIF0sIGkgKSApCisJCQkJcmV0LnB1c2goIGVsZW1zWyBpIF0gKTsKKworCQlyZXR1cm4gcmV0 OworCX0sCisKKwltYXA6IGZ1bmN0aW9uKCBlbGVtcywgY2FsbGJhY2sgKSB7CisJCXZhciByZXQg PSBbXTsKKworCQkvLyBHbyB0aHJvdWdoIHRoZSBhcnJheSwgdHJhbnNsYXRpbmcgZWFjaCBvZiB0 aGUgaXRlbXMgdG8gdGhlaXIKKwkJLy8gbmV3IHZhbHVlIChvciB2YWx1ZXMpLgorCQlmb3IgKCB2 YXIgaSA9IDAsIGxlbmd0aCA9IGVsZW1zLmxlbmd0aDsgaSA8IGxlbmd0aDsgaSsrICkgeworCQkJ dmFyIHZhbHVlID0gY2FsbGJhY2soIGVsZW1zWyBpIF0sIGkgKTsKKworCQkJaWYgKCB2YWx1ZSAh PSBudWxsICkKKwkJCQlyZXRbIHJldC5sZW5ndGggXSA9IHZhbHVlOworCQl9CisKKwkJcmV0dXJu IHJldC5jb25jYXQuYXBwbHkoIFtdLCByZXQgKTsKKwl9Cit9KTsKKwordmFyIHVzZXJBZ2VudCA9 IG5hdmlnYXRvci51c2VyQWdlbnQudG9Mb3dlckNhc2UoKTsKKworLy8gRmlndXJlIG91dCB3aGF0 IGJyb3dzZXIgaXMgYmVpbmcgdXNlZAoralF1ZXJ5LmJyb3dzZXIgPSB7CisJdmVyc2lvbjogKHVz ZXJBZ2VudC5tYXRjaCggLy4rKD86cnZ8aXR8cmF8aWUpW1wvOiBdKFtcZC5dKykvICkgfHwgW10p WzFdLAorCXNhZmFyaTogL3dlYmtpdC8udGVzdCggdXNlckFnZW50ICksCisJb3BlcmE6IC9vcGVy YS8udGVzdCggdXNlckFnZW50ICksCisJbXNpZTogL21zaWUvLnRlc3QoIHVzZXJBZ2VudCApICYm ICEvb3BlcmEvLnRlc3QoIHVzZXJBZ2VudCApLAorCW1vemlsbGE6IC9tb3ppbGxhLy50ZXN0KCB1 c2VyQWdlbnQgKSAmJiAhLyhjb21wYXRpYmxlfHdlYmtpdCkvLnRlc3QoIHVzZXJBZ2VudCApCit9 OworCit2YXIgc3R5bGVGbG9hdCA9IGpRdWVyeS5icm93c2VyLm1zaWUgPworCSJzdHlsZUZsb2F0 IiA6CisJImNzc0Zsb2F0IjsKKworalF1ZXJ5LmV4dGVuZCh7CisJLy8gQ2hlY2sgdG8gc2VlIGlm IHRoZSBXM0MgYm94IG1vZGVsIGlzIGJlaW5nIHVzZWQKKwlib3hNb2RlbDogIWpRdWVyeS5icm93 c2VyLm1zaWUgfHwgZG9jdW1lbnQuY29tcGF0TW9kZSA9PSAiQ1NTMUNvbXBhdCIsCisKKwlwcm9w czogeworCQkiZm9yIjogImh0bWxGb3IiLAorCQkiY2xhc3MiOiAiY2xhc3NOYW1lIiwKKwkJImZs b2F0Ijogc3R5bGVGbG9hdCwKKwkJY3NzRmxvYXQ6IHN0eWxlRmxvYXQsCisJCXN0eWxlRmxvYXQ6 IHN0eWxlRmxvYXQsCisJCXJlYWRvbmx5OiAicmVhZE9ubHkiLAorCQltYXhsZW5ndGg6ICJtYXhM ZW5ndGgiLAorCQljZWxsc3BhY2luZzogImNlbGxTcGFjaW5nIgorCX0KK30pOworCitqUXVlcnku ZWFjaCh7CisJcGFyZW50OiBmdW5jdGlvbihlbGVtKXtyZXR1cm4gZWxlbS5wYXJlbnROb2RlO30s CisJcGFyZW50czogZnVuY3Rpb24oZWxlbSl7cmV0dXJuIGpRdWVyeS5kaXIoZWxlbSwicGFyZW50 Tm9kZSIpO30sCisJbmV4dDogZnVuY3Rpb24oZWxlbSl7cmV0dXJuIGpRdWVyeS5udGgoZWxlbSwy LCJuZXh0U2libGluZyIpO30sCisJcHJldjogZnVuY3Rpb24oZWxlbSl7cmV0dXJuIGpRdWVyeS5u dGgoZWxlbSwyLCJwcmV2aW91c1NpYmxpbmciKTt9LAorCW5leHRBbGw6IGZ1bmN0aW9uKGVsZW0p e3JldHVybiBqUXVlcnkuZGlyKGVsZW0sIm5leHRTaWJsaW5nIik7fSwKKwlwcmV2QWxsOiBmdW5j dGlvbihlbGVtKXtyZXR1cm4galF1ZXJ5LmRpcihlbGVtLCJwcmV2aW91c1NpYmxpbmciKTt9LAor CXNpYmxpbmdzOiBmdW5jdGlvbihlbGVtKXtyZXR1cm4galF1ZXJ5LnNpYmxpbmcoZWxlbS5wYXJl bnROb2RlLmZpcnN0Q2hpbGQsZWxlbSk7fSwKKwljaGlsZHJlbjogZnVuY3Rpb24oZWxlbSl7cmV0 dXJuIGpRdWVyeS5zaWJsaW5nKGVsZW0uZmlyc3RDaGlsZCk7fSwKKwljb250ZW50czogZnVuY3Rp b24oZWxlbSl7cmV0dXJuIGpRdWVyeS5ub2RlTmFtZShlbGVtLCJpZnJhbWUiKT9lbGVtLmNvbnRl bnREb2N1bWVudHx8ZWxlbS5jb250ZW50V2luZG93LmRvY3VtZW50OmpRdWVyeS5tYWtlQXJyYXko ZWxlbS5jaGlsZE5vZGVzKTt9Cit9LCBmdW5jdGlvbihuYW1lLCBmbil7CisJalF1ZXJ5LmZuWyBu YW1lIF0gPSBmdW5jdGlvbiggc2VsZWN0b3IgKSB7CisJCXZhciByZXQgPSBqUXVlcnkubWFwKCB0 aGlzLCBmbiApOworCisJCWlmICggc2VsZWN0b3IgJiYgdHlwZW9mIHNlbGVjdG9yID09ICJzdHJp bmciICkKKwkJCXJldCA9IGpRdWVyeS5tdWx0aUZpbHRlciggc2VsZWN0b3IsIHJldCApOworCisJ CXJldHVybiB0aGlzLnB1c2hTdGFjayggalF1ZXJ5LnVuaXF1ZSggcmV0ICkgKTsKKwl9OworfSk7 CisKK2pRdWVyeS5lYWNoKHsKKwlhcHBlbmRUbzogImFwcGVuZCIsCisJcHJlcGVuZFRvOiAicHJl cGVuZCIsCisJaW5zZXJ0QmVmb3JlOiAiYmVmb3JlIiwKKwlpbnNlcnRBZnRlcjogImFmdGVyIiwK KwlyZXBsYWNlQWxsOiAicmVwbGFjZVdpdGgiCit9LCBmdW5jdGlvbihuYW1lLCBvcmlnaW5hbCl7 CisJalF1ZXJ5LmZuWyBuYW1lIF0gPSBmdW5jdGlvbigpIHsKKwkJdmFyIGFyZ3MgPSBhcmd1bWVu dHM7CisKKwkJcmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbigpeworCQkJZm9yICggdmFyIGkgPSAw LCBsZW5ndGggPSBhcmdzLmxlbmd0aDsgaSA8IGxlbmd0aDsgaSsrICkKKwkJCQlqUXVlcnkoIGFy Z3NbIGkgXSApWyBvcmlnaW5hbCBdKCB0aGlzICk7CisJCX0pOworCX07Cit9KTsKKworalF1ZXJ5 LmVhY2goeworCXJlbW92ZUF0dHI6IGZ1bmN0aW9uKCBuYW1lICkgeworCQlqUXVlcnkuYXR0cigg dGhpcywgbmFtZSwgIiIgKTsKKwkJaWYgKHRoaXMubm9kZVR5cGUgPT0gMSkKKwkJCXRoaXMucmVt b3ZlQXR0cmlidXRlKCBuYW1lICk7CisJfSwKKworCWFkZENsYXNzOiBmdW5jdGlvbiggY2xhc3NO YW1lcyApIHsKKwkJalF1ZXJ5LmNsYXNzTmFtZS5hZGQoIHRoaXMsIGNsYXNzTmFtZXMgKTsKKwl9 LAorCisJcmVtb3ZlQ2xhc3M6IGZ1bmN0aW9uKCBjbGFzc05hbWVzICkgeworCQlqUXVlcnkuY2xh c3NOYW1lLnJlbW92ZSggdGhpcywgY2xhc3NOYW1lcyApOworCX0sCisKKwl0b2dnbGVDbGFzczog ZnVuY3Rpb24oIGNsYXNzTmFtZXMgKSB7CisJCWpRdWVyeS5jbGFzc05hbWVbIGpRdWVyeS5jbGFz c05hbWUuaGFzKCB0aGlzLCBjbGFzc05hbWVzICkgPyAicmVtb3ZlIiA6ICJhZGQiIF0oIHRoaXMs IGNsYXNzTmFtZXMgKTsKKwl9LAorCisJcmVtb3ZlOiBmdW5jdGlvbiggc2VsZWN0b3IgKSB7CisJ CWlmICggIXNlbGVjdG9yIHx8IGpRdWVyeS5maWx0ZXIoIHNlbGVjdG9yLCBbIHRoaXMgXSApLnIu bGVuZ3RoICkgeworCQkJLy8gUHJldmVudCBtZW1vcnkgbGVha3MKKwkJCWpRdWVyeSggIioiLCB0 aGlzICkuYWRkKHRoaXMpLmVhY2goZnVuY3Rpb24oKXsKKwkJCQlqUXVlcnkuZXZlbnQucmVtb3Zl KHRoaXMpOworCQkJCWpRdWVyeS5yZW1vdmVEYXRhKHRoaXMpOworCQkJfSk7CisJCQlpZiAodGhp cy5wYXJlbnROb2RlKQorCQkJCXRoaXMucGFyZW50Tm9kZS5yZW1vdmVDaGlsZCggdGhpcyApOwor CQl9CisJfSwKKworCWVtcHR5OiBmdW5jdGlvbigpIHsKKwkJLy8gUmVtb3ZlIGVsZW1lbnQgbm9k ZXMgYW5kIHByZXZlbnQgbWVtb3J5IGxlYWtzCisJCWpRdWVyeSggIj4qIiwgdGhpcyApLnJlbW92 ZSgpOworCisJCS8vIFJlbW92ZSBhbnkgcmVtYWluaW5nIG5vZGVzCisJCXdoaWxlICggdGhpcy5m aXJzdENoaWxkICkKKwkJCXRoaXMucmVtb3ZlQ2hpbGQoIHRoaXMuZmlyc3RDaGlsZCApOworCX0K K30sIGZ1bmN0aW9uKG5hbWUsIGZuKXsKKwlqUXVlcnkuZm5bIG5hbWUgXSA9IGZ1bmN0aW9uKCl7 CisJCXJldHVybiB0aGlzLmVhY2goIGZuLCBhcmd1bWVudHMgKTsKKwl9OworfSk7CisKK2pRdWVy eS5lYWNoKFsgIkhlaWdodCIsICJXaWR0aCIgXSwgZnVuY3Rpb24oaSwgbmFtZSl7CisJdmFyIHR5 cGUgPSBuYW1lLnRvTG93ZXJDYXNlKCk7CisKKwlqUXVlcnkuZm5bIHR5cGUgXSA9IGZ1bmN0aW9u KCBzaXplICkgeworCQkvLyBHZXQgd2luZG93IHdpZHRoIG9yIGhlaWdodAorCQlyZXR1cm4gdGhp c1swXSA9PSB3aW5kb3cgPworCQkJLy8gT3BlcmEgcmVwb3J0cyBkb2N1bWVudC5ib2R5LmNsaWVu dFtXaWR0aC9IZWlnaHRdIHByb3Blcmx5IGluIGJvdGggcXVpcmtzIGFuZCBzdGFuZGFyZHMKKwkJ CWpRdWVyeS5icm93c2VyLm9wZXJhICYmIGRvY3VtZW50LmJvZHlbICJjbGllbnQiICsgbmFtZSBd IHx8CisKKwkJCS8vIFNhZmFyaSByZXBvcnRzIGlubmVyW1dpZHRoL0hlaWdodF0ganVzdCBmaW5l IChNb3ppbGxhIGFuZCBPcGVyYSBpbmNsdWRlIHNjcm9sbCBiYXIgd2lkdGhzKQorCQkJalF1ZXJ5 LmJyb3dzZXIuc2FmYXJpICYmIHdpbmRvd1sgImlubmVyIiArIG5hbWUgXSB8fAorCisJCQkvLyBF dmVyeW9uZSBlbHNlIHVzZSBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQgb3IgZG9jdW1lbnQuYm9k eSBkZXBlbmRpbmcgb24gUXVpcmtzIHZzIFN0YW5kYXJkcyBtb2RlCisJCQlkb2N1bWVudC5jb21w YXRNb2RlID09ICJDU1MxQ29tcGF0IiAmJiBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnRbICJjbGll bnQiICsgbmFtZSBdIHx8IGRvY3VtZW50LmJvZHlbICJjbGllbnQiICsgbmFtZSBdIDoKKworCQkJ Ly8gR2V0IGRvY3VtZW50IHdpZHRoIG9yIGhlaWdodAorCQkJdGhpc1swXSA9PSBkb2N1bWVudCA/ CisJCQkJLy8gRWl0aGVyIHNjcm9sbFtXaWR0aC9IZWlnaHRdIG9yIG9mZnNldFtXaWR0aC9IZWln aHRdLCB3aGljaGV2ZXIgaXMgZ3JlYXRlcgorCQkJCU1hdGgubWF4KAorCQkJCQlNYXRoLm1heChk b2N1bWVudC5ib2R5WyJzY3JvbGwiICsgbmFtZV0sIGRvY3VtZW50LmRvY3VtZW50RWxlbWVudFsi c2Nyb2xsIiArIG5hbWVdKSwKKwkJCQkJTWF0aC5tYXgoZG9jdW1lbnQuYm9keVsib2Zmc2V0IiAr IG5hbWVdLCBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnRbIm9mZnNldCIgKyBuYW1lXSkKKwkJCQkp IDoKKworCQkJCS8vIEdldCBvciBzZXQgd2lkdGggb3IgaGVpZ2h0IG9uIHRoZSBlbGVtZW50CisJ CQkJc2l6ZSA9PSB1bmRlZmluZWQgPworCQkJCQkvLyBHZXQgd2lkdGggb3IgaGVpZ2h0IG9uIHRo ZSBlbGVtZW50CisJCQkJCSh0aGlzLmxlbmd0aCA/IGpRdWVyeS5jc3MoIHRoaXNbMF0sIHR5cGUg KSA6IG51bGwpIDoKKworCQkJCQkvLyBTZXQgdGhlIHdpZHRoIG9yIGhlaWdodCBvbiB0aGUgZWxl bWVudCAoZGVmYXVsdCB0byBwaXhlbHMgaWYgdmFsdWUgaXMgdW5pdGxlc3MpCisJCQkJCXRoaXMu Y3NzKCB0eXBlLCBzaXplLmNvbnN0cnVjdG9yID09IFN0cmluZyA/IHNpemUgOiBzaXplICsgInB4 IiApOworCX07Cit9KTsKKworLy8gSGVscGVyIGZ1bmN0aW9uIHVzZWQgYnkgdGhlIGRpbWVuc2lv bnMgYW5kIG9mZnNldCBtb2R1bGVzCitmdW5jdGlvbiBudW0oZWxlbSwgcHJvcCkgeworCXJldHVy biBlbGVtWzBdICYmIHBhcnNlSW50KCBqUXVlcnkuY3VyQ1NTKGVsZW1bMF0sIHByb3AsIHRydWUp LCAxMCApIHx8IDA7Cit9dmFyIGNoYXJzID0galF1ZXJ5LmJyb3dzZXIuc2FmYXJpICYmIHBhcnNl SW50KGpRdWVyeS5icm93c2VyLnZlcnNpb24pIDwgNDE3ID8KKwkJIig/OltcXHcqXy1dfFxcXFwu KSIgOgorCQkiKD86W1xcd1x1MDEyOC1cdUZGRkYqXy1dfFxcXFwuKSIsCisJcXVpY2tDaGlsZCA9 IG5ldyBSZWdFeHAoIl4+XFxzKigiICsgY2hhcnMgKyAiKykiKSwKKwlxdWlja0lEID0gbmV3IFJl Z0V4cCgiXigiICsgY2hhcnMgKyAiKykoIykoIiArIGNoYXJzICsgIispIiksCisJcXVpY2tDbGFz cyA9IG5ldyBSZWdFeHAoIl4oWyMuXT8pKCIgKyBjaGFycyArICIqKSIpOworCitqUXVlcnkuZXh0 ZW5kKHsKKwlleHByOiB7CisJCSIiOiBmdW5jdGlvbihhLGksbSl7cmV0dXJuIG1bMl09PSIqInx8 alF1ZXJ5Lm5vZGVOYW1lKGEsbVsyXSk7fSwKKwkJIiMiOiBmdW5jdGlvbihhLGksbSl7cmV0dXJu IGEuZ2V0QXR0cmlidXRlKCJpZCIpPT1tWzJdO30sCisJCSI6IjogeworCQkJLy8gUG9zaXRpb24g Q2hlY2tzCisJCQlsdDogZnVuY3Rpb24oYSxpLG0pe3JldHVybiBpPG1bM10tMDt9LAorCQkJZ3Q6 IGZ1bmN0aW9uKGEsaSxtKXtyZXR1cm4gaT5tWzNdLTA7fSwKKwkJCW50aDogZnVuY3Rpb24oYSxp LG0pe3JldHVybiBtWzNdLTA9PWk7fSwKKwkJCWVxOiBmdW5jdGlvbihhLGksbSl7cmV0dXJuIG1b M10tMD09aTt9LAorCQkJZmlyc3Q6IGZ1bmN0aW9uKGEsaSl7cmV0dXJuIGk9PTA7fSwKKwkJCWxh c3Q6IGZ1bmN0aW9uKGEsaSxtLHIpe3JldHVybiBpPT1yLmxlbmd0aC0xO30sCisJCQlldmVuOiBm dW5jdGlvbihhLGkpe3JldHVybiBpJTI9PTA7fSwKKwkJCW9kZDogZnVuY3Rpb24oYSxpKXtyZXR1 cm4gaSUyO30sCisKKwkJCS8vIENoaWxkIENoZWNrcworCQkJImZpcnN0LWNoaWxkIjogZnVuY3Rp b24oYSl7cmV0dXJuIGEucGFyZW50Tm9kZS5nZXRFbGVtZW50c0J5VGFnTmFtZSgiKiIpWzBdPT1h O30sCisJCQkibGFzdC1jaGlsZCI6IGZ1bmN0aW9uKGEpe3JldHVybiBqUXVlcnkubnRoKGEucGFy ZW50Tm9kZS5sYXN0Q2hpbGQsMSwicHJldmlvdXNTaWJsaW5nIik9PWE7fSwKKwkJCSJvbmx5LWNo aWxkIjogZnVuY3Rpb24oYSl7cmV0dXJuICFqUXVlcnkubnRoKGEucGFyZW50Tm9kZS5sYXN0Q2hp bGQsMiwicHJldmlvdXNTaWJsaW5nIik7fSwKKworCQkJLy8gUGFyZW50IENoZWNrcworCQkJcGFy ZW50OiBmdW5jdGlvbihhKXtyZXR1cm4gYS5maXJzdENoaWxkO30sCisJCQllbXB0eTogZnVuY3Rp b24oYSl7cmV0dXJuICFhLmZpcnN0Q2hpbGQ7fSwKKworCQkJLy8gVGV4dCBDaGVjaworCQkJY29u dGFpbnM6IGZ1bmN0aW9uKGEsaSxtKXtyZXR1cm4gKGEudGV4dENvbnRlbnR8fGEuaW5uZXJUZXh0 fHxqUXVlcnkoYSkudGV4dCgpfHwiIikuaW5kZXhPZihtWzNdKT49MDt9LAorCisJCQkvLyBWaXNp YmlsaXR5CisJCQl2aXNpYmxlOiBmdW5jdGlvbihhKXtyZXR1cm4gImhpZGRlbiIhPWEudHlwZSYm alF1ZXJ5LmNzcyhhLCJkaXNwbGF5IikhPSJub25lIiYmalF1ZXJ5LmNzcyhhLCJ2aXNpYmlsaXR5 IikhPSJoaWRkZW4iO30sCisJCQloaWRkZW46IGZ1bmN0aW9uKGEpe3JldHVybiAiaGlkZGVuIj09 YS50eXBlfHxqUXVlcnkuY3NzKGEsImRpc3BsYXkiKT09Im5vbmUifHxqUXVlcnkuY3NzKGEsInZp c2liaWxpdHkiKT09ImhpZGRlbiI7fSwKKworCQkJLy8gRm9ybSBhdHRyaWJ1dGVzCisJCQllbmFi bGVkOiBmdW5jdGlvbihhKXtyZXR1cm4gIWEuZGlzYWJsZWQ7fSwKKwkJCWRpc2FibGVkOiBmdW5j dGlvbihhKXtyZXR1cm4gYS5kaXNhYmxlZDt9LAorCQkJY2hlY2tlZDogZnVuY3Rpb24oYSl7cmV0 dXJuIGEuY2hlY2tlZDt9LAorCQkJc2VsZWN0ZWQ6IGZ1bmN0aW9uKGEpe3JldHVybiBhLnNlbGVj dGVkfHxqUXVlcnkuYXR0cihhLCJzZWxlY3RlZCIpO30sCisKKwkJCS8vIEZvcm0gZWxlbWVudHMK KwkJCXRleHQ6IGZ1bmN0aW9uKGEpe3JldHVybiAidGV4dCI9PWEudHlwZTt9LAorCQkJcmFkaW86 IGZ1bmN0aW9uKGEpe3JldHVybiAicmFkaW8iPT1hLnR5cGU7fSwKKwkJCWNoZWNrYm94OiBmdW5j dGlvbihhKXtyZXR1cm4gImNoZWNrYm94Ij09YS50eXBlO30sCisJCQlmaWxlOiBmdW5jdGlvbihh KXtyZXR1cm4gImZpbGUiPT1hLnR5cGU7fSwKKwkJCXBhc3N3b3JkOiBmdW5jdGlvbihhKXtyZXR1 cm4gInBhc3N3b3JkIj09YS50eXBlO30sCisJCQlzdWJtaXQ6IGZ1bmN0aW9uKGEpe3JldHVybiAi c3VibWl0Ij09YS50eXBlO30sCisJCQlpbWFnZTogZnVuY3Rpb24oYSl7cmV0dXJuICJpbWFnZSI9 PWEudHlwZTt9LAorCQkJcmVzZXQ6IGZ1bmN0aW9uKGEpe3JldHVybiAicmVzZXQiPT1hLnR5cGU7 fSwKKwkJCWJ1dHRvbjogZnVuY3Rpb24oYSl7cmV0dXJuICJidXR0b24iPT1hLnR5cGV8fGpRdWVy eS5ub2RlTmFtZShhLCJidXR0b24iKTt9LAorCQkJaW5wdXQ6IGZ1bmN0aW9uKGEpe3JldHVybiAv aW5wdXR8c2VsZWN0fHRleHRhcmVhfGJ1dHRvbi9pLnRlc3QoYS5ub2RlTmFtZSk7fSwKKworCQkJ Ly8gOmhhcygpCisJCQloYXM6IGZ1bmN0aW9uKGEsaSxtKXtyZXR1cm4galF1ZXJ5LmZpbmQobVsz XSxhKS5sZW5ndGg7fSwKKworCQkJLy8gOmhlYWRlcgorCQkJaGVhZGVyOiBmdW5jdGlvbihhKXty ZXR1cm4gL2hcZC9pLnRlc3QoYS5ub2RlTmFtZSk7fSwKKworCQkJLy8gOmFuaW1hdGVkCisJCQlh bmltYXRlZDogZnVuY3Rpb24oYSl7cmV0dXJuIGpRdWVyeS5ncmVwKGpRdWVyeS50aW1lcnMsZnVu Y3Rpb24oZm4pe3JldHVybiBhPT1mbi5lbGVtO30pLmxlbmd0aDt9CisJCX0KKwl9LAorCisJLy8g VGhlIHJlZ3VsYXIgZXhwcmVzc2lvbnMgdGhhdCBwb3dlciB0aGUgcGFyc2luZyBlbmdpbmUKKwlw YXJzZTogWworCQkvLyBNYXRjaDogW0B2YWx1ZT0ndGVzdCddLCBbQGZvb10KKwkJL14oXFspICpA PyhbXHctXSspICooWyEqJF5+PV0qKSAqKCc/Ij8pKC4qPylcNCAqXF0vLAorCisJCS8vIE1hdGNo OiA6Y29udGFpbnMoJ2ZvbycpCisJCS9eKDopKFtcdy1dKylcKCI/Jz8oLio/KFwoLio/XCkpP1te KF0qPykiPyc/XCkvLAorCisJCS8vIE1hdGNoOiA6ZXZlbiwgOmxhc3QtY2hpbGQsICNpZCwgLmNs YXNzCisJCW5ldyBSZWdFeHAoIl4oWzouI10qKSgiICsgY2hhcnMgKyAiKykiKQorCV0sCisKKwlt dWx0aUZpbHRlcjogZnVuY3Rpb24oIGV4cHIsIGVsZW1zLCBub3QgKSB7CisJCXZhciBvbGQsIGN1 ciA9IFtdOworCisJCXdoaWxlICggZXhwciAmJiBleHByICE9IG9sZCApIHsKKwkJCW9sZCA9IGV4 cHI7CisJCQl2YXIgZiA9IGpRdWVyeS5maWx0ZXIoIGV4cHIsIGVsZW1zLCBub3QgKTsKKwkJCWV4 cHIgPSBmLnQucmVwbGFjZSgvXlxzKixccyovLCAiIiApOworCQkJY3VyID0gbm90ID8gZWxlbXMg PSBmLnIgOiBqUXVlcnkubWVyZ2UoIGN1ciwgZi5yICk7CisJCX0KKworCQlyZXR1cm4gY3VyOwor CX0sCisKKwlmaW5kOiBmdW5jdGlvbiggdCwgY29udGV4dCApIHsKKwkJLy8gUXVpY2tseSBoYW5k bGUgbm9uLXN0cmluZyBleHByZXNzaW9ucworCQlpZiAoIHR5cGVvZiB0ICE9ICJzdHJpbmciICkK KwkJCXJldHVybiBbIHQgXTsKKworCQkvLyBjaGVjayB0byBtYWtlIHN1cmUgY29udGV4dCBpcyBh IERPTSBlbGVtZW50IG9yIGEgZG9jdW1lbnQKKwkJaWYgKCBjb250ZXh0ICYmIGNvbnRleHQubm9k ZVR5cGUgIT0gMSAmJiBjb250ZXh0Lm5vZGVUeXBlICE9IDkpCisJCQlyZXR1cm4gWyBdOworCisJ CS8vIFNldCB0aGUgY29ycmVjdCBjb250ZXh0IChpZiBub25lIGlzIHByb3ZpZGVkKQorCQljb250 ZXh0ID0gY29udGV4dCB8fCBkb2N1bWVudDsKKworCQkvLyBJbml0aWFsaXplIHRoZSBzZWFyY2gK KwkJdmFyIHJldCA9IFtjb250ZXh0XSwgZG9uZSA9IFtdLCBsYXN0LCBub2RlTmFtZTsKKworCQkv LyBDb250aW51ZSB3aGlsZSBhIHNlbGVjdG9yIGV4cHJlc3Npb24gZXhpc3RzLCBhbmQgd2hpbGUK KwkJLy8gd2UncmUgbm8gbG9uZ2VyIGxvb3BpbmcgdXBvbiBvdXJzZWx2ZXMKKwkJd2hpbGUgKCB0 ICYmIGxhc3QgIT0gdCApIHsKKwkJCXZhciByID0gW107CisJCQlsYXN0ID0gdDsKKworCQkJdCA9 IGpRdWVyeS50cmltKHQpOworCisJCQl2YXIgZm91bmRUb2tlbiA9IGZhbHNlLAorCisJCQkvLyBB biBhdHRlbXB0IGF0IHNwZWVkaW5nIHVwIGNoaWxkIHNlbGVjdG9ycyB0aGF0CisJCQkvLyBwb2lu dCB0byBhIHNwZWNpZmljIGVsZW1lbnQgdGFnCisJCQkJcmUgPSBxdWlja0NoaWxkLAorCisJCQkJ bSA9IHJlLmV4ZWModCk7CisKKwkJCWlmICggbSApIHsKKwkJCQlub2RlTmFtZSA9IG1bMV0udG9V cHBlckNhc2UoKTsKKworCQkJCS8vIFBlcmZvcm0gb3VyIG93biBpdGVyYXRpb24gYW5kIGZpbHRl cgorCQkJCWZvciAoIHZhciBpID0gMDsgcmV0W2ldOyBpKysgKQorCQkJCQlmb3IgKCB2YXIgYyA9 IHJldFtpXS5maXJzdENoaWxkOyBjOyBjID0gYy5uZXh0U2libGluZyApCisJCQkJCQlpZiAoIGMu bm9kZVR5cGUgPT0gMSAmJiAobm9kZU5hbWUgPT0gIioiIHx8IGMubm9kZU5hbWUudG9VcHBlckNh c2UoKSA9PSBub2RlTmFtZSkgKQorCQkJCQkJCXIucHVzaCggYyApOworCisJCQkJcmV0ID0gcjsK KwkJCQl0ID0gdC5yZXBsYWNlKCByZSwgIiIgKTsKKwkJCQlpZiAoIHQuaW5kZXhPZigiICIpID09 IDAgKSBjb250aW51ZTsKKwkJCQlmb3VuZFRva2VuID0gdHJ1ZTsKKwkJCX0gZWxzZSB7CisJCQkJ cmUgPSAvXihbPit+XSlccyooXHcqKS9pOworCisJCQkJaWYgKCAobSA9IHJlLmV4ZWModCkpICE9 IG51bGwgKSB7CisJCQkJCXIgPSBbXTsKKworCQkJCQl2YXIgbWVyZ2UgPSB7fTsKKwkJCQkJbm9k ZU5hbWUgPSBtWzJdLnRvVXBwZXJDYXNlKCk7CisJCQkJCW0gPSBtWzFdOworCisJCQkJCWZvciAo IHZhciBqID0gMCwgcmwgPSByZXQubGVuZ3RoOyBqIDwgcmw7IGorKyApIHsKKwkJCQkJCXZhciBu ID0gbSA9PSAifiIgfHwgbSA9PSAiKyIgPyByZXRbal0ubmV4dFNpYmxpbmcgOiByZXRbal0uZmly c3RDaGlsZDsKKwkJCQkJCWZvciAoIDsgbjsgbiA9IG4ubmV4dFNpYmxpbmcgKQorCQkJCQkJCWlm ICggbi5ub2RlVHlwZSA9PSAxICkgeworCQkJCQkJCQl2YXIgaWQgPSBqUXVlcnkuZGF0YShuKTsK KworCQkJCQkJCQlpZiAoIG0gPT0gIn4iICYmIG1lcmdlW2lkXSApIGJyZWFrOworCisJCQkJCQkJ CWlmICghbm9kZU5hbWUgfHwgbi5ub2RlTmFtZS50b1VwcGVyQ2FzZSgpID09IG5vZGVOYW1lICkg eworCQkJCQkJCQkJaWYgKCBtID09ICJ+IiApIG1lcmdlW2lkXSA9IHRydWU7CisJCQkJCQkJCQly LnB1c2goIG4gKTsKKwkJCQkJCQkJfQorCisJCQkJCQkJCWlmICggbSA9PSAiKyIgKSBicmVhazsK KwkJCQkJCQl9CisJCQkJCX0KKworCQkJCQlyZXQgPSByOworCisJCQkJCS8vIEFuZCByZW1vdmUg dGhlIHRva2VuCisJCQkJCXQgPSBqUXVlcnkudHJpbSggdC5yZXBsYWNlKCByZSwgIiIgKSApOwor CQkJCQlmb3VuZFRva2VuID0gdHJ1ZTsKKwkJCQl9CisJCQl9CisKKwkJCS8vIFNlZSBpZiB0aGVy ZSdzIHN0aWxsIGFuIGV4cHJlc3Npb24sIGFuZCB0aGF0IHdlIGhhdmVuJ3QgYWxyZWFkeQorCQkJ Ly8gbWF0Y2hlZCBhIHRva2VuCisJCQlpZiAoIHQgJiYgIWZvdW5kVG9rZW4gKSB7CisJCQkJLy8g SGFuZGxlIG11bHRpcGxlIGV4cHJlc3Npb25zCisJCQkJaWYgKCAhdC5pbmRleE9mKCIsIikgKSB7 CisJCQkJCS8vIENsZWFuIHRoZSByZXN1bHQgc2V0CisJCQkJCWlmICggY29udGV4dCA9PSByZXRb MF0gKSByZXQuc2hpZnQoKTsKKworCQkJCQkvLyBNZXJnZSB0aGUgcmVzdWx0IHNldHMKKwkJCQkJ ZG9uZSA9IGpRdWVyeS5tZXJnZSggZG9uZSwgcmV0ICk7CisKKwkJCQkJLy8gUmVzZXQgdGhlIGNv bnRleHQKKwkJCQkJciA9IHJldCA9IFtjb250ZXh0XTsKKworCQkJCQkvLyBUb3VjaCB1cCB0aGUg c2VsZWN0b3Igc3RyaW5nCisJCQkJCXQgPSAiICIgKyB0LnN1YnN0cigxLHQubGVuZ3RoKTsKKwor CQkJCX0gZWxzZSB7CisJCQkJCS8vIE9wdGltaXplIGZvciB0aGUgY2FzZSBub2RlTmFtZSNpZE5h bWUKKwkJCQkJdmFyIHJlMiA9IHF1aWNrSUQ7CisJCQkJCXZhciBtID0gcmUyLmV4ZWModCk7CisK KwkJCQkJLy8gUmUtb3JnYW5pemUgdGhlIHJlc3VsdHMsIHNvIHRoYXQgdGhleSdyZSBjb25zaXN0 ZW50CisJCQkJCWlmICggbSApIHsKKwkJCQkJCW0gPSBbIDAsIG1bMl0sIG1bM10sIG1bMV0gXTsK KworCQkJCQl9IGVsc2UgeworCQkJCQkJLy8gT3RoZXJ3aXNlLCBkbyBhIHRyYWRpdGlvbmFsIGZp bHRlciBjaGVjayBmb3IKKwkJCQkJCS8vIElELCBjbGFzcywgYW5kIGVsZW1lbnQgc2VsZWN0b3Jz CisJCQkJCQlyZTIgPSBxdWlja0NsYXNzOworCQkJCQkJbSA9IHJlMi5leGVjKHQpOworCQkJCQl9 CisKKwkJCQkJbVsyXSA9IG1bMl0ucmVwbGFjZSgvXFwvZywgIiIpOworCisJCQkJCXZhciBlbGVt ID0gcmV0W3JldC5sZW5ndGgtMV07CisKKwkJCQkJLy8gVHJ5IHRvIGRvIGEgZ2xvYmFsIHNlYXJj aCBieSBJRCwgd2hlcmUgd2UgY2FuCisJCQkJCWlmICggbVsxXSA9PSAiIyIgJiYgZWxlbSAmJiBl bGVtLmdldEVsZW1lbnRCeUlkICYmICFqUXVlcnkuaXNYTUxEb2MoZWxlbSkgKSB7CisJCQkJCQkv LyBPcHRpbWl6YXRpb24gZm9yIEhUTUwgZG9jdW1lbnQgY2FzZQorCQkJCQkJdmFyIG9pZCA9IGVs ZW0uZ2V0RWxlbWVudEJ5SWQobVsyXSk7CisKKwkJCQkJCS8vIERvIGEgcXVpY2sgY2hlY2sgZm9y IHRoZSBleGlzdGVuY2Ugb2YgdGhlIGFjdHVhbCBJRCBhdHRyaWJ1dGUKKwkJCQkJCS8vIHRvIGF2 b2lkIHNlbGVjdGluZyBieSB0aGUgbmFtZSBhdHRyaWJ1dGUgaW4gSUUKKwkJCQkJCS8vIGFsc28g Y2hlY2sgdG8gaW5zdXJlIGlkIGlzIGEgc3RyaW5nIHRvIGF2b2lkIHNlbGVjdGluZyBhbiBlbGVt ZW50IHdpdGggdGhlIG5hbWUgb2YgJ2lkJyBpbnNpZGUgYSBmb3JtCisJCQkJCQlpZiAoIChqUXVl cnkuYnJvd3Nlci5tc2llfHxqUXVlcnkuYnJvd3Nlci5vcGVyYSkgJiYgb2lkICYmIHR5cGVvZiBv aWQuaWQgPT0gInN0cmluZyIgJiYgb2lkLmlkICE9IG1bMl0gKQorCQkJCQkJCW9pZCA9IGpRdWVy eSgnW0BpZD0iJyttWzJdKyciXScsIGVsZW0pWzBdOworCisJCQkJCQkvLyBEbyBhIHF1aWNrIGNo ZWNrIGZvciBub2RlIG5hbWUgKHdoZXJlIGFwcGxpY2FibGUpIHNvCisJCQkJCQkvLyB0aGF0IGRp diNmb28gc2VhcmNoZXMgd2lsbCBiZSByZWFsbHkgZmFzdAorCQkJCQkJcmV0ID0gciA9IG9pZCAm JiAoIW1bM10gfHwgalF1ZXJ5Lm5vZGVOYW1lKG9pZCwgbVszXSkpID8gW29pZF0gOiBbXTsKKwkJ CQkJfSBlbHNlIHsKKwkJCQkJCS8vIFdlIG5lZWQgdG8gZmluZCBhbGwgZGVzY2VuZGFudCBlbGVt ZW50cworCQkJCQkJZm9yICggdmFyIGkgPSAwOyByZXRbaV07IGkrKyApIHsKKwkJCQkJCQkvLyBH cmFiIHRoZSB0YWcgbmFtZSBiZWluZyBzZWFyY2hlZCBmb3IKKwkJCQkJCQl2YXIgdGFnID0gbVsx XSA9PSAiIyIgJiYgbVszXSA/IG1bM10gOiBtWzFdICE9ICIiIHx8IG1bMF0gPT0gIiIgPyAiKiIg OiBtWzJdOworCisJCQkJCQkJLy8gSGFuZGxlIElFNyBiZWluZyByZWFsbHkgZHVtYiBhYm91dCA8 b2JqZWN0PnMKKwkJCQkJCQlpZiAoIHRhZyA9PSAiKiIgJiYgcmV0W2ldLm5vZGVOYW1lLnRvTG93 ZXJDYXNlKCkgPT0gIm9iamVjdCIgKQorCQkJCQkJCQl0YWcgPSAicGFyYW0iOworCisJCQkJCQkJ ciA9IGpRdWVyeS5tZXJnZSggciwgcmV0W2ldLmdldEVsZW1lbnRzQnlUYWdOYW1lKCB0YWcgKSk7 CisJCQkJCQl9CisKKwkJCQkJCS8vIEl0J3MgZmFzdGVyIHRvIGZpbHRlciBieSBjbGFzcyBhbmQg YmUgZG9uZSB3aXRoIGl0CisJCQkJCQlpZiAoIG1bMV0gPT0gIi4iICkKKwkJCQkJCQlyID0galF1 ZXJ5LmNsYXNzRmlsdGVyKCByLCBtWzJdICk7CisKKwkJCQkJCS8vIFNhbWUgd2l0aCBJRCBmaWx0 ZXJpbmcKKwkJCQkJCWlmICggbVsxXSA9PSAiIyIgKSB7CisJCQkJCQkJdmFyIHRtcCA9IFtdOwor CisJCQkJCQkJLy8gVHJ5IHRvIGZpbmQgdGhlIGVsZW1lbnQgd2l0aCB0aGUgSUQKKwkJCQkJCQlm b3IgKCB2YXIgaSA9IDA7IHJbaV07IGkrKyApCisJCQkJCQkJCWlmICggcltpXS5nZXRBdHRyaWJ1 dGUoImlkIikgPT0gbVsyXSApIHsKKwkJCQkJCQkJCXRtcCA9IFsgcltpXSBdOworCQkJCQkJCQkJ YnJlYWs7CisJCQkJCQkJCX0KKworCQkJCQkJCXIgPSB0bXA7CisJCQkJCQl9CisKKwkJCQkJCXJl dCA9IHI7CisJCQkJCX0KKworCQkJCQl0ID0gdC5yZXBsYWNlKCByZTIsICIiICk7CisJCQkJfQor CisJCQl9CisKKwkJCS8vIElmIGEgc2VsZWN0b3Igc3RyaW5nIHN0aWxsIGV4aXN0cworCQkJaWYg KCB0ICkgeworCQkJCS8vIEF0dGVtcHQgdG8gZmlsdGVyIGl0CisJCQkJdmFyIHZhbCA9IGpRdWVy eS5maWx0ZXIodCxyKTsKKwkJCQlyZXQgPSByID0gdmFsLnI7CisJCQkJdCA9IGpRdWVyeS50cmlt KHZhbC50KTsKKwkJCX0KKwkJfQorCisJCS8vIEFuIGVycm9yIG9jY3VycmVkIHdpdGggdGhlIHNl bGVjdG9yOworCQkvLyBqdXN0IHJldHVybiBhbiBlbXB0eSBzZXQgaW5zdGVhZAorCQlpZiAoIHQg KQorCQkJcmV0ID0gW107CisKKwkJLy8gUmVtb3ZlIHRoZSByb290IGNvbnRleHQKKwkJaWYgKCBy ZXQgJiYgY29udGV4dCA9PSByZXRbMF0gKQorCQkJcmV0LnNoaWZ0KCk7CisKKwkJLy8gQW5kIGNv bWJpbmUgdGhlIHJlc3VsdHMKKwkJZG9uZSA9IGpRdWVyeS5tZXJnZSggZG9uZSwgcmV0ICk7CisK KwkJcmV0dXJuIGRvbmU7CisJfSwKKworCWNsYXNzRmlsdGVyOiBmdW5jdGlvbihyLG0sbm90KXsK KwkJbSA9ICIgIiArIG0gKyAiICI7CisJCXZhciB0bXAgPSBbXTsKKwkJZm9yICggdmFyIGkgPSAw OyByW2ldOyBpKysgKSB7CisJCQl2YXIgcGFzcyA9ICgiICIgKyByW2ldLmNsYXNzTmFtZSArICIg IikuaW5kZXhPZiggbSApID49IDA7CisJCQlpZiAoICFub3QgJiYgcGFzcyB8fCBub3QgJiYgIXBh c3MgKQorCQkJCXRtcC5wdXNoKCByW2ldICk7CisJCX0KKwkJcmV0dXJuIHRtcDsKKwl9LAorCisJ ZmlsdGVyOiBmdW5jdGlvbih0LHIsbm90KSB7CisJCXZhciBsYXN0OworCisJCS8vIExvb2sgZm9y IGNvbW1vbiBmaWx0ZXIgZXhwcmVzc2lvbnMKKwkJd2hpbGUgKCB0ICYmIHQgIT0gbGFzdCApIHsK KwkJCWxhc3QgPSB0OworCisJCQl2YXIgcCA9IGpRdWVyeS5wYXJzZSwgbTsKKworCQkJZm9yICgg dmFyIGkgPSAwOyBwW2ldOyBpKysgKSB7CisJCQkJbSA9IHBbaV0uZXhlYyggdCApOworCisJCQkJ aWYgKCBtICkgeworCQkJCQkvLyBSZW1vdmUgd2hhdCB3ZSBqdXN0IG1hdGNoZWQKKwkJCQkJdCA9 IHQuc3Vic3RyaW5nKCBtWzBdLmxlbmd0aCApOworCisJCQkJCW1bMl0gPSBtWzJdLnJlcGxhY2Uo L1xcL2csICIiKTsKKwkJCQkJYnJlYWs7CisJCQkJfQorCQkJfQorCisJCQlpZiAoICFtICkKKwkJ CQlicmVhazsKKworCQkJLy8gOm5vdCgpIGlzIGEgc3BlY2lhbCBjYXNlIHRoYXQgY2FuIGJlIG9w dGltaXplZCBieQorCQkJLy8ga2VlcGluZyBpdCBvdXQgb2YgdGhlIGV4cHJlc3Npb24gbGlzdAor CQkJaWYgKCBtWzFdID09ICI6IiAmJiBtWzJdID09ICJub3QiICkKKwkJCQkvLyBvcHRpbWl6ZSBp ZiBvbmx5IG9uZSBzZWxlY3RvciBmb3VuZCAobW9zdCBjb21tb24gY2FzZSkKKwkJCQlyID0gaXNT aW1wbGUudGVzdCggbVszXSApID8KKwkJCQkJalF1ZXJ5LmZpbHRlcihtWzNdLCByLCB0cnVlKS5y IDoKKwkJCQkJalF1ZXJ5KCByICkubm90KCBtWzNdICk7CisKKwkJCS8vIFdlIGNhbiBnZXQgYSBi aWcgc3BlZWQgYm9vc3QgYnkgZmlsdGVyaW5nIGJ5IGNsYXNzIGhlcmUKKwkJCWVsc2UgaWYgKCBt WzFdID09ICIuIiApCisJCQkJciA9IGpRdWVyeS5jbGFzc0ZpbHRlcihyLCBtWzJdLCBub3QpOwor CisJCQllbHNlIGlmICggbVsxXSA9PSAiWyIgKSB7CisJCQkJdmFyIHRtcCA9IFtdLCB0eXBlID0g bVszXTsKKworCQkJCWZvciAoIHZhciBpID0gMCwgcmwgPSByLmxlbmd0aDsgaSA8IHJsOyBpKysg KSB7CisJCQkJCXZhciBhID0gcltpXSwgeiA9IGFbIGpRdWVyeS5wcm9wc1ttWzJdXSB8fCBtWzJd IF07CisKKwkJCQkJaWYgKCB6ID09IG51bGwgfHwgL2hyZWZ8c3JjfHNlbGVjdGVkLy50ZXN0KG1b Ml0pICkKKwkJCQkJCXogPSBqUXVlcnkuYXR0cihhLG1bMl0pIHx8ICcnOworCisJCQkJCWlmICgg KHR5cGUgPT0gIiIgJiYgISF6IHx8CisJCQkJCQkgdHlwZSA9PSAiPSIgJiYgeiA9PSBtWzVdIHx8 CisJCQkJCQkgdHlwZSA9PSAiIT0iICYmIHogIT0gbVs1XSB8fAorCQkJCQkJIHR5cGUgPT0gIl49 IiAmJiB6ICYmICF6LmluZGV4T2YobVs1XSkgfHwKKwkJCQkJCSB0eXBlID09ICIkPSIgJiYgei5z dWJzdHIoei5sZW5ndGggLSBtWzVdLmxlbmd0aCkgPT0gbVs1XSB8fAorCQkJCQkJICh0eXBlID09 ICIqPSIgfHwgdHlwZSA9PSAifj0iKSAmJiB6LmluZGV4T2YobVs1XSkgPj0gMCkgXiBub3QgKQor CQkJCQkJCXRtcC5wdXNoKCBhICk7CisJCQkJfQorCisJCQkJciA9IHRtcDsKKworCQkJLy8gV2Ug Y2FuIGdldCBhIHNwZWVkIGJvb3N0IGJ5IGhhbmRsaW5nIG50aC1jaGlsZCBoZXJlCisJCQl9IGVs c2UgaWYgKCBtWzFdID09ICI6IiAmJiBtWzJdID09ICJudGgtY2hpbGQiICkgeworCQkJCXZhciBt ZXJnZSA9IHt9LCB0bXAgPSBbXSwKKwkJCQkJLy8gcGFyc2UgZXF1YXRpb25zIGxpa2UgJ2V2ZW4n LCAnb2RkJywgJzUnLCAnMm4nLCAnM24rMicsICc0bi0xJywgJy1uKzYnCisJCQkJCXRlc3QgPSAv KC0/KShcZCopbigoPzpcK3wtKT9cZCopLy5leGVjKAorCQkJCQkJbVszXSA9PSAiZXZlbiIgJiYg IjJuIiB8fCBtWzNdID09ICJvZGQiICYmICIybisxIiB8fAorCQkJCQkJIS9cRC8udGVzdChtWzNd KSAmJiAiMG4rIiArIG1bM10gfHwgbVszXSksCisJCQkJCS8vIGNhbGN1bGF0ZSB0aGUgbnVtYmVy cyAoZmlyc3QpbisobGFzdCkgaW5jbHVkaW5nIGlmIHRoZXkgYXJlIG5lZ2F0aXZlCisJCQkJCWZp cnN0ID0gKHRlc3RbMV0gKyAodGVzdFsyXSB8fCAxKSkgLSAwLCBsYXN0ID0gdGVzdFszXSAtIDA7 CisKKwkJCQkvLyBsb29wIHRocm91Z2ggYWxsIHRoZSBlbGVtZW50cyBsZWZ0IGluIHRoZSBqUXVl cnkgb2JqZWN0CisJCQkJZm9yICggdmFyIGkgPSAwLCBybCA9IHIubGVuZ3RoOyBpIDwgcmw7IGkr KyApIHsKKwkJCQkJdmFyIG5vZGUgPSByW2ldLCBwYXJlbnROb2RlID0gbm9kZS5wYXJlbnROb2Rl LCBpZCA9IGpRdWVyeS5kYXRhKHBhcmVudE5vZGUpOworCisJCQkJCWlmICggIW1lcmdlW2lkXSAp IHsKKwkJCQkJCXZhciBjID0gMTsKKworCQkJCQkJZm9yICggdmFyIG4gPSBwYXJlbnROb2RlLmZp cnN0Q2hpbGQ7IG47IG4gPSBuLm5leHRTaWJsaW5nICkKKwkJCQkJCQlpZiAoIG4ubm9kZVR5cGUg PT0gMSApCisJCQkJCQkJCW4ubm9kZUluZGV4ID0gYysrOworCisJCQkJCQltZXJnZVtpZF0gPSB0 cnVlOworCQkJCQl9CisKKwkJCQkJdmFyIGFkZCA9IGZhbHNlOworCisJCQkJCWlmICggZmlyc3Qg PT0gMCApIHsKKwkJCQkJCWlmICggbm9kZS5ub2RlSW5kZXggPT0gbGFzdCApCisJCQkJCQkJYWRk ID0gdHJ1ZTsKKwkJCQkJfSBlbHNlIGlmICggKG5vZGUubm9kZUluZGV4IC0gbGFzdCkgJSBmaXJz dCA9PSAwICYmIChub2RlLm5vZGVJbmRleCAtIGxhc3QpIC8gZmlyc3QgPj0gMCApCisJCQkJCQlh ZGQgPSB0cnVlOworCisJCQkJCWlmICggYWRkIF4gbm90ICkKKwkJCQkJCXRtcC5wdXNoKCBub2Rl ICk7CisJCQkJfQorCisJCQkJciA9IHRtcDsKKworCQkJLy8gT3RoZXJ3aXNlLCBmaW5kIHRoZSBl eHByZXNzaW9uIHRvIGV4ZWN1dGUKKwkJCX0gZWxzZSB7CisJCQkJdmFyIGZuID0galF1ZXJ5LmV4 cHJbIG1bMV0gXTsKKwkJCQlpZiAoIHR5cGVvZiBmbiA9PSAib2JqZWN0IiApCisJCQkJCWZuID0g Zm5bIG1bMl0gXTsKKworCQkJCWlmICggdHlwZW9mIGZuID09ICJzdHJpbmciICkKKwkJCQkJZm4g PSBldmFsKCJmYWxzZXx8ZnVuY3Rpb24oYSxpKXtyZXR1cm4gIiArIGZuICsgIjt9Iik7CisKKwkJ CQkvLyBFeGVjdXRlIGl0IGFnYWluc3QgdGhlIGN1cnJlbnQgZmlsdGVyCisJCQkJciA9IGpRdWVy eS5ncmVwKCByLCBmdW5jdGlvbihlbGVtLCBpKXsKKwkJCQkJcmV0dXJuIGZuKGVsZW0sIGksIG0s IHIpOworCQkJCX0sIG5vdCApOworCQkJfQorCQl9CisKKwkJLy8gUmV0dXJuIGFuIGFycmF5IG9m IGZpbHRlcmVkIGVsZW1lbnRzIChyKQorCQkvLyBhbmQgdGhlIG1vZGlmaWVkIGV4cHJlc3Npb24g c3RyaW5nICh0KQorCQlyZXR1cm4geyByOiByLCB0OiB0IH07CisJfSwKKworCWRpcjogZnVuY3Rp b24oIGVsZW0sIGRpciApeworCQl2YXIgbWF0Y2hlZCA9IFtdLAorCQkJY3VyID0gZWxlbVtkaXJd OworCQl3aGlsZSAoIGN1ciAmJiBjdXIgIT0gZG9jdW1lbnQgKSB7CisJCQlpZiAoIGN1ci5ub2Rl VHlwZSA9PSAxICkKKwkJCQltYXRjaGVkLnB1c2goIGN1ciApOworCQkJY3VyID0gY3VyW2Rpcl07 CisJCX0KKwkJcmV0dXJuIG1hdGNoZWQ7CisJfSwKKworCW50aDogZnVuY3Rpb24oY3VyLHJlc3Vs dCxkaXIsZWxlbSl7CisJCXJlc3VsdCA9IHJlc3VsdCB8fCAxOworCQl2YXIgbnVtID0gMDsKKwor CQlmb3IgKCA7IGN1cjsgY3VyID0gY3VyW2Rpcl0gKQorCQkJaWYgKCBjdXIubm9kZVR5cGUgPT0g MSAmJiArK251bSA9PSByZXN1bHQgKQorCQkJCWJyZWFrOworCisJCXJldHVybiBjdXI7CisJfSwK KworCXNpYmxpbmc6IGZ1bmN0aW9uKCBuLCBlbGVtICkgeworCQl2YXIgciA9IFtdOworCisJCWZv ciAoIDsgbjsgbiA9IG4ubmV4dFNpYmxpbmcgKSB7CisJCQlpZiAoIG4ubm9kZVR5cGUgPT0gMSAm JiBuICE9IGVsZW0gKQorCQkJCXIucHVzaCggbiApOworCQl9CisKKwkJcmV0dXJuIHI7CisJfQor fSk7CisvKgorICogQSBudW1iZXIgb2YgaGVscGVyIGZ1bmN0aW9ucyB1c2VkIGZvciBtYW5hZ2lu ZyBldmVudHMuCisgKiBNYW55IG9mIHRoZSBpZGVhcyBiZWhpbmQgdGhpcyBjb2RlIG9yaWduYXRl ZCBmcm9tCisgKiBEZWFuIEVkd2FyZHMnIGFkZEV2ZW50IGxpYnJhcnkuCisgKi8KK2pRdWVyeS5l dmVudCA9IHsKKworCS8vIEJpbmQgYW4gZXZlbnQgdG8gYW4gZWxlbWVudAorCS8vIE9yaWdpbmFs IGJ5IERlYW4gRWR3YXJkcworCWFkZDogZnVuY3Rpb24oZWxlbSwgdHlwZXMsIGhhbmRsZXIsIGRh dGEpIHsKKwkJaWYgKCBlbGVtLm5vZGVUeXBlID09IDMgfHwgZWxlbS5ub2RlVHlwZSA9PSA4ICkK KwkJCXJldHVybjsKKworCQkvLyBGb3Igd2hhdGV2ZXIgcmVhc29uLCBJRSBoYXMgdHJvdWJsZSBw YXNzaW5nIHRoZSB3aW5kb3cgb2JqZWN0CisJCS8vIGFyb3VuZCwgY2F1c2luZyBpdCB0byBiZSBj bG9uZWQgaW4gdGhlIHByb2Nlc3MKKwkJaWYgKCBqUXVlcnkuYnJvd3Nlci5tc2llICYmIGVsZW0u c2V0SW50ZXJ2YWwgKQorCQkJZWxlbSA9IHdpbmRvdzsKKworCQkvLyBNYWtlIHN1cmUgdGhhdCB0 aGUgZnVuY3Rpb24gYmVpbmcgZXhlY3V0ZWQgaGFzIGEgdW5pcXVlIElECisJCWlmICggIWhhbmRs ZXIuZ3VpZCApCisJCQloYW5kbGVyLmd1aWQgPSB0aGlzLmd1aWQrKzsKKworCQkvLyBpZiBkYXRh IGlzIHBhc3NlZCwgYmluZCB0byBoYW5kbGVyCisJCWlmKCBkYXRhICE9IHVuZGVmaW5lZCApIHsK KwkJCS8vIENyZWF0ZSB0ZW1wb3JhcnkgZnVuY3Rpb24gcG9pbnRlciB0byBvcmlnaW5hbCBoYW5k bGVyCisJCQl2YXIgZm4gPSBoYW5kbGVyOworCisJCQkvLyBDcmVhdGUgdW5pcXVlIGhhbmRsZXIg ZnVuY3Rpb24sIHdyYXBwZWQgYXJvdW5kIG9yaWdpbmFsIGhhbmRsZXIKKwkJCWhhbmRsZXIgPSB0 aGlzLnByb3h5KCBmbiwgZnVuY3Rpb24oKSB7CisJCQkJLy8gUGFzcyBhcmd1bWVudHMgYW5kIGNv bnRleHQgdG8gb3JpZ2luYWwgaGFuZGxlcgorCQkJCXJldHVybiBmbi5hcHBseSh0aGlzLCBhcmd1 bWVudHMpOworCQkJfSk7CisKKwkJCS8vIFN0b3JlIGRhdGEgaW4gdW5pcXVlIGhhbmRsZXIKKwkJ CWhhbmRsZXIuZGF0YSA9IGRhdGE7CisJCX0KKworCQkvLyBJbml0IHRoZSBlbGVtZW50J3MgZXZl bnQgc3RydWN0dXJlCisJCXZhciBldmVudHMgPSBqUXVlcnkuZGF0YShlbGVtLCAiZXZlbnRzIikg fHwgalF1ZXJ5LmRhdGEoZWxlbSwgImV2ZW50cyIsIHt9KSwKKwkJCWhhbmRsZSA9IGpRdWVyeS5k YXRhKGVsZW0sICJoYW5kbGUiKSB8fCBqUXVlcnkuZGF0YShlbGVtLCAiaGFuZGxlIiwgZnVuY3Rp b24oKXsKKwkJCQkvLyBIYW5kbGUgdGhlIHNlY29uZCBldmVudCBvZiBhIHRyaWdnZXIgYW5kIHdo ZW4KKwkJCQkvLyBhbiBldmVudCBpcyBjYWxsZWQgYWZ0ZXIgYSBwYWdlIGhhcyB1bmxvYWRlZAor CQkJCWlmICggdHlwZW9mIGpRdWVyeSAhPSAidW5kZWZpbmVkIiAmJiAhalF1ZXJ5LmV2ZW50LnRy aWdnZXJlZCApCisJCQkJCXJldHVybiBqUXVlcnkuZXZlbnQuaGFuZGxlLmFwcGx5KGFyZ3VtZW50 cy5jYWxsZWUuZWxlbSwgYXJndW1lbnRzKTsKKwkJCX0pOworCQkvLyBBZGQgZWxlbSBhcyBhIHBy b3BlcnR5IG9mIHRoZSBoYW5kbGUgZnVuY3Rpb24KKwkJLy8gVGhpcyBpcyB0byBwcmV2ZW50IGEg bWVtb3J5IGxlYWsgd2l0aCBub24tbmF0aXZlCisJCS8vIGV2ZW50IGluIElFLgorCQloYW5kbGUu ZWxlbSA9IGVsZW07CisKKwkJLy8gSGFuZGxlIG11bHRpcGxlIGV2ZW50cyBzZXBhcmF0ZWQgYnkg YSBzcGFjZQorCQkvLyBqUXVlcnkoLi4uKS5iaW5kKCJtb3VzZW92ZXIgbW91c2VvdXQiLCBmbik7 CisJCWpRdWVyeS5lYWNoKHR5cGVzLnNwbGl0KC9ccysvKSwgZnVuY3Rpb24oaW5kZXgsIHR5cGUp IHsKKwkJCS8vIE5hbWVzcGFjZWQgZXZlbnQgaGFuZGxlcnMKKwkJCXZhciBwYXJ0cyA9IHR5cGUu c3BsaXQoIi4iKTsKKwkJCXR5cGUgPSBwYXJ0c1swXTsKKwkJCWhhbmRsZXIudHlwZSA9IHBhcnRz WzFdOworCisJCQkvLyBHZXQgdGhlIGN1cnJlbnQgbGlzdCBvZiBmdW5jdGlvbnMgYm91bmQgdG8g dGhpcyBldmVudAorCQkJdmFyIGhhbmRsZXJzID0gZXZlbnRzW3R5cGVdOworCisJCQkvLyBJbml0 IHRoZSBldmVudCBoYW5kbGVyIHF1ZXVlCisJCQlpZiAoIWhhbmRsZXJzKSB7CisJCQkJaGFuZGxl cnMgPSBldmVudHNbdHlwZV0gPSB7fTsKKworCQkJCS8vIENoZWNrIGZvciBhIHNwZWNpYWwgZXZl bnQgaGFuZGxlcgorCQkJCS8vIE9ubHkgdXNlIGFkZEV2ZW50TGlzdGVuZXIvYXR0YWNoRXZlbnQg aWYgdGhlIHNwZWNpYWwKKwkJCQkvLyBldmVudHMgaGFuZGxlciByZXR1cm5zIGZhbHNlCisJCQkJ aWYgKCAhalF1ZXJ5LmV2ZW50LnNwZWNpYWxbdHlwZV0gfHwgalF1ZXJ5LmV2ZW50LnNwZWNpYWxb dHlwZV0uc2V0dXAuY2FsbChlbGVtKSA9PT0gZmFsc2UgKSB7CisJCQkJCS8vIEJpbmQgdGhlIGds b2JhbCBldmVudCBoYW5kbGVyIHRvIHRoZSBlbGVtZW50CisJCQkJCWlmIChlbGVtLmFkZEV2ZW50 TGlzdGVuZXIpCisJCQkJCQllbGVtLmFkZEV2ZW50TGlzdGVuZXIodHlwZSwgaGFuZGxlLCBmYWxz ZSk7CisJCQkJCWVsc2UgaWYgKGVsZW0uYXR0YWNoRXZlbnQpCisJCQkJCQllbGVtLmF0dGFjaEV2 ZW50KCJvbiIgKyB0eXBlLCBoYW5kbGUpOworCQkJCX0KKwkJCX0KKworCQkJLy8gQWRkIHRoZSBm dW5jdGlvbiB0byB0aGUgZWxlbWVudCdzIGhhbmRsZXIgbGlzdAorCQkJaGFuZGxlcnNbaGFuZGxl ci5ndWlkXSA9IGhhbmRsZXI7CisKKwkJCS8vIEtlZXAgdHJhY2sgb2Ygd2hpY2ggZXZlbnRzIGhh dmUgYmVlbiB1c2VkLCBmb3IgZ2xvYmFsIHRyaWdnZXJpbmcKKwkJCWpRdWVyeS5ldmVudC5nbG9i YWxbdHlwZV0gPSB0cnVlOworCQl9KTsKKworCQkvLyBOdWxsaWZ5IGVsZW0gdG8gcHJldmVudCBt ZW1vcnkgbGVha3MgaW4gSUUKKwkJZWxlbSA9IG51bGw7CisJfSwKKworCWd1aWQ6IDEsCisJZ2xv YmFsOiB7fSwKKworCS8vIERldGFjaCBhbiBldmVudCBvciBzZXQgb2YgZXZlbnRzIGZyb20gYW4g ZWxlbWVudAorCXJlbW92ZTogZnVuY3Rpb24oZWxlbSwgdHlwZXMsIGhhbmRsZXIpIHsKKwkJLy8g ZG9uJ3QgZG8gZXZlbnRzIG9uIHRleHQgYW5kIGNvbW1lbnQgbm9kZXMKKwkJaWYgKCBlbGVtLm5v ZGVUeXBlID09IDMgfHwgZWxlbS5ub2RlVHlwZSA9PSA4ICkKKwkJCXJldHVybjsKKworCQl2YXIg ZXZlbnRzID0galF1ZXJ5LmRhdGEoZWxlbSwgImV2ZW50cyIpLCByZXQsIGluZGV4OworCisJCWlm ICggZXZlbnRzICkgeworCQkJLy8gVW5iaW5kIGFsbCBldmVudHMgZm9yIHRoZSBlbGVtZW50CisJ CQlpZiAoIHR5cGVzID09IHVuZGVmaW5lZCB8fCAodHlwZW9mIHR5cGVzID09ICJzdHJpbmciICYm IHR5cGVzLmNoYXJBdCgwKSA9PSAiLiIpICkKKwkJCQlmb3IgKCB2YXIgdHlwZSBpbiBldmVudHMg KQorCQkJCQl0aGlzLnJlbW92ZSggZWxlbSwgdHlwZSArICh0eXBlcyB8fCAiIikgKTsKKwkJCWVs c2UgeworCQkJCS8vIHR5cGVzIGlzIGFjdHVhbGx5IGFuIGV2ZW50IG9iamVjdCBoZXJlCisJCQkJ aWYgKCB0eXBlcy50eXBlICkgeworCQkJCQloYW5kbGVyID0gdHlwZXMuaGFuZGxlcjsKKwkJCQkJ dHlwZXMgPSB0eXBlcy50eXBlOworCQkJCX0KKworCQkJCS8vIEhhbmRsZSBtdWx0aXBsZSBldmVu dHMgc2VwZXJhdGVkIGJ5IGEgc3BhY2UKKwkJCQkvLyBqUXVlcnkoLi4uKS51bmJpbmQoIm1vdXNl b3ZlciBtb3VzZW91dCIsIGZuKTsKKwkJCQlqUXVlcnkuZWFjaCh0eXBlcy5zcGxpdCgvXHMrLyks IGZ1bmN0aW9uKGluZGV4LCB0eXBlKXsKKwkJCQkJLy8gTmFtZXNwYWNlZCBldmVudCBoYW5kbGVy cworCQkJCQl2YXIgcGFydHMgPSB0eXBlLnNwbGl0KCIuIik7CisJCQkJCXR5cGUgPSBwYXJ0c1sw XTsKKworCQkJCQlpZiAoIGV2ZW50c1t0eXBlXSApIHsKKwkJCQkJCS8vIHJlbW92ZSB0aGUgZ2l2 ZW4gaGFuZGxlciBmb3IgdGhlIGdpdmVuIHR5cGUKKwkJCQkJCWlmICggaGFuZGxlciApCisJCQkJ CQkJZGVsZXRlIGV2ZW50c1t0eXBlXVtoYW5kbGVyLmd1aWRdOworCisJCQkJCQkvLyByZW1vdmUg YWxsIGhhbmRsZXJzIGZvciB0aGUgZ2l2ZW4gdHlwZQorCQkJCQkJZWxzZQorCQkJCQkJCWZvciAo IGhhbmRsZXIgaW4gZXZlbnRzW3R5cGVdICkKKwkJCQkJCQkJLy8gSGFuZGxlIHRoZSByZW1vdmFs IG9mIG5hbWVzcGFjZWQgZXZlbnRzCisJCQkJCQkJCWlmICggIXBhcnRzWzFdIHx8IGV2ZW50c1t0 eXBlXVtoYW5kbGVyXS50eXBlID09IHBhcnRzWzFdICkKKwkJCQkJCQkJCWRlbGV0ZSBldmVudHNb dHlwZV1baGFuZGxlcl07CisKKwkJCQkJCS8vIHJlbW92ZSBnZW5lcmljIGV2ZW50IGhhbmRsZXIg aWYgbm8gbW9yZSBoYW5kbGVycyBleGlzdAorCQkJCQkJZm9yICggcmV0IGluIGV2ZW50c1t0eXBl XSApIGJyZWFrOworCQkJCQkJaWYgKCAhcmV0ICkgeworCQkJCQkJCWlmICggIWpRdWVyeS5ldmVu dC5zcGVjaWFsW3R5cGVdIHx8IGpRdWVyeS5ldmVudC5zcGVjaWFsW3R5cGVdLnRlYXJkb3duLmNh bGwoZWxlbSkgPT09IGZhbHNlICkgeworCQkJCQkJCQlpZiAoZWxlbS5yZW1vdmVFdmVudExpc3Rl bmVyKQorCQkJCQkJCQkJZWxlbS5yZW1vdmVFdmVudExpc3RlbmVyKHR5cGUsIGpRdWVyeS5kYXRh KGVsZW0sICJoYW5kbGUiKSwgZmFsc2UpOworCQkJCQkJCQllbHNlIGlmIChlbGVtLmRldGFjaEV2 ZW50KQorCQkJCQkJCQkJZWxlbS5kZXRhY2hFdmVudCgib24iICsgdHlwZSwgalF1ZXJ5LmRhdGEo ZWxlbSwgImhhbmRsZSIpKTsKKwkJCQkJCQl9CisJCQkJCQkJcmV0ID0gbnVsbDsKKwkJCQkJCQlk ZWxldGUgZXZlbnRzW3R5cGVdOworCQkJCQkJfQorCQkJCQl9CisJCQkJfSk7CisJCQl9CisKKwkJ CS8vIFJlbW92ZSB0aGUgZXhwYW5kbyBpZiBpdCdzIG5vIGxvbmdlciB1c2VkCisJCQlmb3IgKCBy ZXQgaW4gZXZlbnRzICkgYnJlYWs7CisJCQlpZiAoICFyZXQgKSB7CisJCQkJdmFyIGhhbmRsZSA9 IGpRdWVyeS5kYXRhKCBlbGVtLCAiaGFuZGxlIiApOworCQkJCWlmICggaGFuZGxlICkgaGFuZGxl LmVsZW0gPSBudWxsOworCQkJCWpRdWVyeS5yZW1vdmVEYXRhKCBlbGVtLCAiZXZlbnRzIiApOwor CQkJCWpRdWVyeS5yZW1vdmVEYXRhKCBlbGVtLCAiaGFuZGxlIiApOworCQkJfQorCQl9CisJfSwK KworCXRyaWdnZXI6IGZ1bmN0aW9uKHR5cGUsIGRhdGEsIGVsZW0sIGRvbmF0aXZlLCBleHRyYSkg eworCQkvLyBDbG9uZSB0aGUgaW5jb21pbmcgZGF0YSwgaWYgYW55CisJCWRhdGEgPSBqUXVlcnku bWFrZUFycmF5KGRhdGEpOworCisJCWlmICggdHlwZS5pbmRleE9mKCIhIikgPj0gMCApIHsKKwkJ CXR5cGUgPSB0eXBlLnNsaWNlKDAsIC0xKTsKKwkJCXZhciBleGNsdXNpdmUgPSB0cnVlOworCQl9 CisKKwkJLy8gSGFuZGxlIGEgZ2xvYmFsIHRyaWdnZXIKKwkJaWYgKCAhZWxlbSApIHsKKwkJCS8v IE9ubHkgdHJpZ2dlciBpZiB3ZSd2ZSBldmVyIGJvdW5kIGFuIGV2ZW50IGZvciBpdAorCQkJaWYg KCB0aGlzLmdsb2JhbFt0eXBlXSApCisJCQkJalF1ZXJ5KCIqIikuYWRkKFt3aW5kb3csIGRvY3Vt ZW50XSkudHJpZ2dlcih0eXBlLCBkYXRhKTsKKworCQkvLyBIYW5kbGUgdHJpZ2dlcmluZyBhIHNp bmdsZSBlbGVtZW50CisJCX0gZWxzZSB7CisJCQkvLyBkb24ndCBkbyBldmVudHMgb24gdGV4dCBh bmQgY29tbWVudCBub2RlcworCQkJaWYgKCBlbGVtLm5vZGVUeXBlID09IDMgfHwgZWxlbS5ub2Rl VHlwZSA9PSA4ICkKKwkJCQlyZXR1cm4gdW5kZWZpbmVkOworCisJCQl2YXIgdmFsLCByZXQsIGZu ID0galF1ZXJ5LmlzRnVuY3Rpb24oIGVsZW1bIHR5cGUgXSB8fCBudWxsICksCisJCQkJLy8gQ2hl Y2sgdG8gc2VlIGlmIHdlIG5lZWQgdG8gcHJvdmlkZSBhIGZha2UgZXZlbnQsIG9yIG5vdAorCQkJ CWV2ZW50ID0gIWRhdGFbMF0gfHwgIWRhdGFbMF0ucHJldmVudERlZmF1bHQ7CisKKwkJCS8vIFBh c3MgYWxvbmcgYSBmYWtlIGV2ZW50CisJCQlpZiAoIGV2ZW50ICkgeworCQkJCWRhdGEudW5zaGlm dCh7CisJCQkJCXR5cGU6IHR5cGUsCisJCQkJCXRhcmdldDogZWxlbSwKKwkJCQkJcHJldmVudERl ZmF1bHQ6IGZ1bmN0aW9uKCl7fSwKKwkJCQkJc3RvcFByb3BhZ2F0aW9uOiBmdW5jdGlvbigpe30s CisJCQkJCXRpbWVTdGFtcDogbm93KCkKKwkJCQl9KTsKKwkJCQlkYXRhWzBdW2V4cGFuZG9dID0g dHJ1ZTsgLy8gbm8gbmVlZCB0byBmaXggZmFrZSBldmVudAorCQkJfQorCisJCQkvLyBFbmZvcmNl IHRoZSByaWdodCB0cmlnZ2VyIHR5cGUKKwkJCWRhdGFbMF0udHlwZSA9IHR5cGU7CisJCQlpZiAo IGV4Y2x1c2l2ZSApCisJCQkJZGF0YVswXS5leGNsdXNpdmUgPSB0cnVlOworCisJCQkvLyBUcmln Z2VyIHRoZSBldmVudCwgaXQgaXMgYXNzdW1lZCB0aGF0ICJoYW5kbGUiIGlzIGEgZnVuY3Rpb24K KwkJCXZhciBoYW5kbGUgPSBqUXVlcnkuZGF0YShlbGVtLCAiaGFuZGxlIik7CisJCQlpZiAoIGhh bmRsZSApCisJCQkJdmFsID0gaGFuZGxlLmFwcGx5KCBlbGVtLCBkYXRhICk7CisKKwkJCS8vIEhh bmRsZSB0cmlnZ2VyaW5nIG5hdGl2ZSAub25mb28gaGFuZGxlcnMgKGFuZCBvbiBsaW5rcyBzaW5j ZSB3ZSBkb24ndCBjYWxsIC5jbGljaygpIGZvciBsaW5rcykKKwkJCWlmICggKCFmbiB8fCAoalF1 ZXJ5Lm5vZGVOYW1lKGVsZW0sICdhJykgJiYgdHlwZSA9PSAiY2xpY2siKSkgJiYgZWxlbVsib24i K3R5cGVdICYmIGVsZW1bIm9uIit0eXBlXS5hcHBseSggZWxlbSwgZGF0YSApID09PSBmYWxzZSAp CisJCQkJdmFsID0gZmFsc2U7CisKKwkJCS8vIEV4dHJhIGZ1bmN0aW9ucyBkb24ndCBnZXQgdGhl IGN1c3RvbSBldmVudCBvYmplY3QKKwkJCWlmICggZXZlbnQgKQorCQkJCWRhdGEuc2hpZnQoKTsK KworCQkJLy8gSGFuZGxlIHRyaWdnZXJpbmcgb2YgZXh0cmEgZnVuY3Rpb24KKwkJCWlmICggZXh0 cmEgJiYgalF1ZXJ5LmlzRnVuY3Rpb24oIGV4dHJhICkgKSB7CisJCQkJLy8gY2FsbCB0aGUgZXh0 cmEgZnVuY3Rpb24gYW5kIHRhY2sgdGhlIGN1cnJlbnQgcmV0dXJuIHZhbHVlIG9uIHRoZSBlbmQg Zm9yIHBvc3NpYmxlIGluc3BlY3Rpb24KKwkJCQlyZXQgPSBleHRyYS5hcHBseSggZWxlbSwgdmFs ID09IG51bGwgPyBkYXRhIDogZGF0YS5jb25jYXQoIHZhbCApICk7CisJCQkJLy8gaWYgYW55dGhp bmcgaXMgcmV0dXJuZWQsIGdpdmUgaXQgcHJlY2VkZW5jZSBhbmQgaGF2ZSBpdCBvdmVyd3JpdGUg dGhlIHByZXZpb3VzIHZhbHVlCisJCQkJaWYgKHJldCAhPT0gdW5kZWZpbmVkKQorCQkJCQl2YWwg PSByZXQ7CisJCQl9CisKKwkJCS8vIFRyaWdnZXIgdGhlIG5hdGl2ZSBldmVudHMgKGV4Y2VwdCBm b3IgY2xpY2tzIG9uIGxpbmtzKQorCQkJaWYgKCBmbiAmJiBkb25hdGl2ZSAhPT0gZmFsc2UgJiYg dmFsICE9PSBmYWxzZSAmJiAhKGpRdWVyeS5ub2RlTmFtZShlbGVtLCAnYScpICYmIHR5cGUgPT0g ImNsaWNrIikgKSB7CisJCQkJdGhpcy50cmlnZ2VyZWQgPSB0cnVlOworCQkJCXRyeSB7CisJCQkJ CWVsZW1bIHR5cGUgXSgpOworCQkJCS8vIHByZXZlbnQgSUUgZnJvbSB0aHJvd2luZyBhbiBlcnJv ciBmb3Igc29tZSBoaWRkZW4gZWxlbWVudHMKKwkJCQl9IGNhdGNoIChlKSB7fQorCQkJfQorCisJ CQl0aGlzLnRyaWdnZXJlZCA9IGZhbHNlOworCQl9CisKKwkJcmV0dXJuIHZhbDsKKwl9LAorCisJ aGFuZGxlOiBmdW5jdGlvbihldmVudCkgeworCQkvLyByZXR1cm5lZCB1bmRlZmluZWQgb3IgZmFs c2UKKwkJdmFyIHZhbCwgcmV0LCBuYW1lc3BhY2UsIGFsbCwgaGFuZGxlcnM7CisKKwkJZXZlbnQg PSBhcmd1bWVudHNbMF0gPSBqUXVlcnkuZXZlbnQuZml4KCBldmVudCB8fCB3aW5kb3cuZXZlbnQg KTsKKworCQkvLyBOYW1lc3BhY2VkIGV2ZW50IGhhbmRsZXJzCisJCW5hbWVzcGFjZSA9IGV2ZW50 LnR5cGUuc3BsaXQoIi4iKTsKKwkJZXZlbnQudHlwZSA9IG5hbWVzcGFjZVswXTsKKwkJbmFtZXNw YWNlID0gbmFtZXNwYWNlWzFdOworCQkvLyBDYWNoZSB0aGlzIG5vdywgYWxsID0gdHJ1ZSBtZWFu cywgYW55IGhhbmRsZXIKKwkJYWxsID0gIW5hbWVzcGFjZSAmJiAhZXZlbnQuZXhjbHVzaXZlOwor CisJCWhhbmRsZXJzID0gKCBqUXVlcnkuZGF0YSh0aGlzLCAiZXZlbnRzIikgfHwge30gKVtldmVu dC50eXBlXTsKKworCQlmb3IgKCB2YXIgaiBpbiBoYW5kbGVycyApIHsKKwkJCXZhciBoYW5kbGVy ID0gaGFuZGxlcnNbal07CisKKwkJCS8vIEZpbHRlciB0aGUgZnVuY3Rpb25zIGJ5IGNsYXNzCisJ CQlpZiAoIGFsbCB8fCBoYW5kbGVyLnR5cGUgPT0gbmFtZXNwYWNlICkgeworCQkJCS8vIFBhc3Mg aW4gYSByZWZlcmVuY2UgdG8gdGhlIGhhbmRsZXIgZnVuY3Rpb24gaXRzZWxmCisJCQkJLy8gU28g dGhhdCB3ZSBjYW4gbGF0ZXIgcmVtb3ZlIGl0CisJCQkJZXZlbnQuaGFuZGxlciA9IGhhbmRsZXI7 CisJCQkJZXZlbnQuZGF0YSA9IGhhbmRsZXIuZGF0YTsKKworCQkJCXJldCA9IGhhbmRsZXIuYXBw bHkoIHRoaXMsIGFyZ3VtZW50cyApOworCisJCQkJaWYgKCB2YWwgIT09IGZhbHNlICkKKwkJCQkJ dmFsID0gcmV0OworCisJCQkJaWYgKCByZXQgPT09IGZhbHNlICkgeworCQkJCQlldmVudC5wcmV2 ZW50RGVmYXVsdCgpOworCQkJCQlldmVudC5zdG9wUHJvcGFnYXRpb24oKTsKKwkJCQl9CisJCQl9 CisJCX0KKworCQlyZXR1cm4gdmFsOworCX0sCisKKwlmaXg6IGZ1bmN0aW9uKGV2ZW50KSB7CisJ CWlmICggZXZlbnRbZXhwYW5kb10gPT0gdHJ1ZSApCisJCQlyZXR1cm4gZXZlbnQ7CisKKwkJLy8g c3RvcmUgYSBjb3B5IG9mIHRoZSBvcmlnaW5hbCBldmVudCBvYmplY3QKKwkJLy8gYW5kICJjbG9u ZSIgdG8gc2V0IHJlYWQtb25seSBwcm9wZXJ0aWVzCisJCXZhciBvcmlnaW5hbEV2ZW50ID0gZXZl bnQ7CisJCWV2ZW50ID0geyBvcmlnaW5hbEV2ZW50OiBvcmlnaW5hbEV2ZW50IH07CisJCXZhciBw cm9wcyA9ICJhbHRLZXkgYXR0ckNoYW5nZSBhdHRyTmFtZSBidWJibGVzIGJ1dHRvbiBjYW5jZWxh YmxlIGNoYXJDb2RlIGNsaWVudFggY2xpZW50WSBjdHJsS2V5IGN1cnJlbnRUYXJnZXQgZGF0YSBk ZXRhaWwgZXZlbnRQaGFzZSBmcm9tRWxlbWVudCBoYW5kbGVyIGtleUNvZGUgbWV0YUtleSBuZXdW YWx1ZSBvcmlnaW5hbFRhcmdldCBwYWdlWCBwYWdlWSBwcmV2VmFsdWUgcmVsYXRlZE5vZGUgcmVs YXRlZFRhcmdldCBzY3JlZW5YIHNjcmVlblkgc2hpZnRLZXkgc3JjRWxlbWVudCB0YXJnZXQgdGlt ZVN0YW1wIHRvRWxlbWVudCB0eXBlIHZpZXcgd2hlZWxEZWx0YSB3aGljaCIuc3BsaXQoIiAiKTsK KwkJZm9yICggdmFyIGk9cHJvcHMubGVuZ3RoOyBpOyBpLS0gKQorCQkJZXZlbnRbIHByb3BzW2ld IF0gPSBvcmlnaW5hbEV2ZW50WyBwcm9wc1tpXSBdOworCisJCS8vIE1hcmsgaXQgYXMgZml4ZWQK KwkJZXZlbnRbZXhwYW5kb10gPSB0cnVlOworCisJCS8vIGFkZCBwcmV2ZW50RGVmYXVsdCBhbmQg c3RvcFByb3BhZ2F0aW9uIHNpbmNlCisJCS8vIHRoZXkgd2lsbCBub3Qgd29yayBvbiB0aGUgY2xv bmUKKwkJZXZlbnQucHJldmVudERlZmF1bHQgPSBmdW5jdGlvbigpIHsKKwkJCS8vIGlmIHByZXZl bnREZWZhdWx0IGV4aXN0cyBydW4gaXQgb24gdGhlIG9yaWdpbmFsIGV2ZW50CisJCQlpZiAob3Jp Z2luYWxFdmVudC5wcmV2ZW50RGVmYXVsdCkKKwkJCQlvcmlnaW5hbEV2ZW50LnByZXZlbnREZWZh dWx0KCk7CisJCQkvLyBvdGhlcndpc2Ugc2V0IHRoZSByZXR1cm5WYWx1ZSBwcm9wZXJ0eSBvZiB0 aGUgb3JpZ2luYWwgZXZlbnQgdG8gZmFsc2UgKElFKQorCQkJb3JpZ2luYWxFdmVudC5yZXR1cm5W YWx1ZSA9IGZhbHNlOworCQl9OworCQlldmVudC5zdG9wUHJvcGFnYXRpb24gPSBmdW5jdGlvbigp IHsKKwkJCS8vIGlmIHN0b3BQcm9wYWdhdGlvbiBleGlzdHMgcnVuIGl0IG9uIHRoZSBvcmlnaW5h bCBldmVudAorCQkJaWYgKG9yaWdpbmFsRXZlbnQuc3RvcFByb3BhZ2F0aW9uKQorCQkJCW9yaWdp bmFsRXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7CisJCQkvLyBvdGhlcndpc2Ugc2V0IHRoZSBjYW5j ZWxCdWJibGUgcHJvcGVydHkgb2YgdGhlIG9yaWdpbmFsIGV2ZW50IHRvIHRydWUgKElFKQorCQkJ b3JpZ2luYWxFdmVudC5jYW5jZWxCdWJibGUgPSB0cnVlOworCQl9OworCisJCS8vIEZpeCB0aW1l U3RhbXAKKwkJZXZlbnQudGltZVN0YW1wID0gZXZlbnQudGltZVN0YW1wIHx8IG5vdygpOworCisJ CS8vIEZpeCB0YXJnZXQgcHJvcGVydHksIGlmIG5lY2Vzc2FyeQorCQlpZiAoICFldmVudC50YXJn ZXQgKQorCQkJZXZlbnQudGFyZ2V0ID0gZXZlbnQuc3JjRWxlbWVudCB8fCBkb2N1bWVudDsgLy8g Rml4ZXMgIzE5MjUgd2hlcmUgc3JjRWxlbWVudCBtaWdodCBub3QgYmUgZGVmaW5lZCBlaXRoZXIK KworCQkvLyBjaGVjayBpZiB0YXJnZXQgaXMgYSB0ZXh0bm9kZSAoc2FmYXJpKQorCQlpZiAoIGV2 ZW50LnRhcmdldC5ub2RlVHlwZSA9PSAzICkKKwkJCWV2ZW50LnRhcmdldCA9IGV2ZW50LnRhcmdl dC5wYXJlbnROb2RlOworCisJCS8vIEFkZCByZWxhdGVkVGFyZ2V0LCBpZiBuZWNlc3NhcnkKKwkJ aWYgKCAhZXZlbnQucmVsYXRlZFRhcmdldCAmJiBldmVudC5mcm9tRWxlbWVudCApCisJCQlldmVu dC5yZWxhdGVkVGFyZ2V0ID0gZXZlbnQuZnJvbUVsZW1lbnQgPT0gZXZlbnQudGFyZ2V0ID8gZXZl bnQudG9FbGVtZW50IDogZXZlbnQuZnJvbUVsZW1lbnQ7CisKKwkJLy8gQ2FsY3VsYXRlIHBhZ2VY L1kgaWYgbWlzc2luZyBhbmQgY2xpZW50WC9ZIGF2YWlsYWJsZQorCQlpZiAoIGV2ZW50LnBhZ2VY ID09IG51bGwgJiYgZXZlbnQuY2xpZW50WCAhPSBudWxsICkgeworCQkJdmFyIGRvYyA9IGRvY3Vt ZW50LmRvY3VtZW50RWxlbWVudCwgYm9keSA9IGRvY3VtZW50LmJvZHk7CisJCQlldmVudC5wYWdl WCA9IGV2ZW50LmNsaWVudFggKyAoZG9jICYmIGRvYy5zY3JvbGxMZWZ0IHx8IGJvZHkgJiYgYm9k eS5zY3JvbGxMZWZ0IHx8IDApIC0gKGRvYy5jbGllbnRMZWZ0IHx8IDApOworCQkJZXZlbnQucGFn ZVkgPSBldmVudC5jbGllbnRZICsgKGRvYyAmJiBkb2Muc2Nyb2xsVG9wIHx8IGJvZHkgJiYgYm9k eS5zY3JvbGxUb3AgfHwgMCkgLSAoZG9jLmNsaWVudFRvcCB8fCAwKTsKKwkJfQorCisJCS8vIEFk ZCB3aGljaCBmb3Iga2V5IGV2ZW50cworCQlpZiAoICFldmVudC53aGljaCAmJiAoKGV2ZW50LmNo YXJDb2RlIHx8IGV2ZW50LmNoYXJDb2RlID09PSAwKSA/IGV2ZW50LmNoYXJDb2RlIDogZXZlbnQu a2V5Q29kZSkgKQorCQkJZXZlbnQud2hpY2ggPSBldmVudC5jaGFyQ29kZSB8fCBldmVudC5rZXlD b2RlOworCisJCS8vIEFkZCBtZXRhS2V5IHRvIG5vbi1NYWMgYnJvd3NlcnMgKHVzZSBjdHJsIGZv ciBQQydzIGFuZCBNZXRhIGZvciBNYWNzKQorCQlpZiAoICFldmVudC5tZXRhS2V5ICYmIGV2ZW50 LmN0cmxLZXkgKQorCQkJZXZlbnQubWV0YUtleSA9IGV2ZW50LmN0cmxLZXk7CisKKwkJLy8gQWRk IHdoaWNoIGZvciBjbGljazogMSA9PSBsZWZ0OyAyID09IG1pZGRsZTsgMyA9PSByaWdodAorCQkv LyBOb3RlOiBidXR0b24gaXMgbm90IG5vcm1hbGl6ZWQsIHNvIGRvbid0IHVzZSBpdAorCQlpZiAo ICFldmVudC53aGljaCAmJiBldmVudC5idXR0b24gKQorCQkJZXZlbnQud2hpY2ggPSAoZXZlbnQu YnV0dG9uICYgMSA/IDEgOiAoIGV2ZW50LmJ1dHRvbiAmIDIgPyAzIDogKCBldmVudC5idXR0b24g JiA0ID8gMiA6IDAgKSApKTsKKworCQlyZXR1cm4gZXZlbnQ7CisJfSwKKworCXByb3h5OiBmdW5j dGlvbiggZm4sIHByb3h5ICl7CisJCS8vIFNldCB0aGUgZ3VpZCBvZiB1bmlxdWUgaGFuZGxlciB0 byB0aGUgc2FtZSBvZiBvcmlnaW5hbCBoYW5kbGVyLCBzbyBpdCBjYW4gYmUgcmVtb3ZlZAorCQlw cm94eS5ndWlkID0gZm4uZ3VpZCA9IGZuLmd1aWQgfHwgcHJveHkuZ3VpZCB8fCB0aGlzLmd1aWQr KzsKKwkJLy8gU28gcHJveHkgY2FuIGJlIGRlY2xhcmVkIGFzIGFuIGFyZ3VtZW50CisJCXJldHVy biBwcm94eTsKKwl9LAorCisJc3BlY2lhbDogeworCQlyZWFkeTogeworCQkJc2V0dXA6IGZ1bmN0 aW9uKCkgeworCQkJCS8vIE1ha2Ugc3VyZSB0aGUgcmVhZHkgZXZlbnQgaXMgc2V0dXAKKwkJCQli aW5kUmVhZHkoKTsKKwkJCQlyZXR1cm47CisJCQl9LAorCisJCQl0ZWFyZG93bjogZnVuY3Rpb24o KSB7IHJldHVybjsgfQorCQl9LAorCisJCW1vdXNlZW50ZXI6IHsKKwkJCXNldHVwOiBmdW5jdGlv bigpIHsKKwkJCQlpZiAoIGpRdWVyeS5icm93c2VyLm1zaWUgKSByZXR1cm4gZmFsc2U7CisJCQkJ alF1ZXJ5KHRoaXMpLmJpbmQoIm1vdXNlb3ZlciIsIGpRdWVyeS5ldmVudC5zcGVjaWFsLm1vdXNl ZW50ZXIuaGFuZGxlcik7CisJCQkJcmV0dXJuIHRydWU7CisJCQl9LAorCisJCQl0ZWFyZG93bjog ZnVuY3Rpb24oKSB7CisJCQkJaWYgKCBqUXVlcnkuYnJvd3Nlci5tc2llICkgcmV0dXJuIGZhbHNl OworCQkJCWpRdWVyeSh0aGlzKS51bmJpbmQoIm1vdXNlb3ZlciIsIGpRdWVyeS5ldmVudC5zcGVj aWFsLm1vdXNlZW50ZXIuaGFuZGxlcik7CisJCQkJcmV0dXJuIHRydWU7CisJCQl9LAorCisJCQlo YW5kbGVyOiBmdW5jdGlvbihldmVudCkgeworCQkJCS8vIElmIHdlIGFjdHVhbGx5IGp1c3QgbW91 c2VkIG9uIHRvIGEgc3ViLWVsZW1lbnQsIGlnbm9yZSBpdAorCQkJCWlmICggd2l0aGluRWxlbWVu dChldmVudCwgdGhpcykgKSByZXR1cm4gdHJ1ZTsKKwkJCQkvLyBFeGVjdXRlIHRoZSByaWdodCBo YW5kbGVycyBieSBzZXR0aW5nIHRoZSBldmVudCB0eXBlIHRvIG1vdXNlZW50ZXIKKwkJCQlldmVu dC50eXBlID0gIm1vdXNlZW50ZXIiOworCQkJCXJldHVybiBqUXVlcnkuZXZlbnQuaGFuZGxlLmFw cGx5KHRoaXMsIGFyZ3VtZW50cyk7CisJCQl9CisJCX0sCisKKwkJbW91c2VsZWF2ZTogeworCQkJ c2V0dXA6IGZ1bmN0aW9uKCkgeworCQkJCWlmICggalF1ZXJ5LmJyb3dzZXIubXNpZSApIHJldHVy biBmYWxzZTsKKwkJCQlqUXVlcnkodGhpcykuYmluZCgibW91c2VvdXQiLCBqUXVlcnkuZXZlbnQu c3BlY2lhbC5tb3VzZWxlYXZlLmhhbmRsZXIpOworCQkJCXJldHVybiB0cnVlOworCQkJfSwKKwor CQkJdGVhcmRvd246IGZ1bmN0aW9uKCkgeworCQkJCWlmICggalF1ZXJ5LmJyb3dzZXIubXNpZSAp IHJldHVybiBmYWxzZTsKKwkJCQlqUXVlcnkodGhpcykudW5iaW5kKCJtb3VzZW91dCIsIGpRdWVy eS5ldmVudC5zcGVjaWFsLm1vdXNlbGVhdmUuaGFuZGxlcik7CisJCQkJcmV0dXJuIHRydWU7CisJ CQl9LAorCisJCQloYW5kbGVyOiBmdW5jdGlvbihldmVudCkgeworCQkJCS8vIElmIHdlIGFjdHVh bGx5IGp1c3QgbW91c2VkIG9uIHRvIGEgc3ViLWVsZW1lbnQsIGlnbm9yZSBpdAorCQkJCWlmICgg d2l0aGluRWxlbWVudChldmVudCwgdGhpcykgKSByZXR1cm4gdHJ1ZTsKKwkJCQkvLyBFeGVjdXRl IHRoZSByaWdodCBoYW5kbGVycyBieSBzZXR0aW5nIHRoZSBldmVudCB0eXBlIHRvIG1vdXNlbGVh dmUKKwkJCQlldmVudC50eXBlID0gIm1vdXNlbGVhdmUiOworCQkJCXJldHVybiBqUXVlcnkuZXZl bnQuaGFuZGxlLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7CisJCQl9CisJCX0KKwl9Cit9OworCitq UXVlcnkuZm4uZXh0ZW5kKHsKKwliaW5kOiBmdW5jdGlvbiggdHlwZSwgZGF0YSwgZm4gKSB7CisJ CXJldHVybiB0eXBlID09ICJ1bmxvYWQiID8gdGhpcy5vbmUodHlwZSwgZGF0YSwgZm4pIDogdGhp cy5lYWNoKGZ1bmN0aW9uKCl7CisJCQlqUXVlcnkuZXZlbnQuYWRkKCB0aGlzLCB0eXBlLCBmbiB8 fCBkYXRhLCBmbiAmJiBkYXRhICk7CisJCX0pOworCX0sCisKKwlvbmU6IGZ1bmN0aW9uKCB0eXBl LCBkYXRhLCBmbiApIHsKKwkJdmFyIG9uZSA9IGpRdWVyeS5ldmVudC5wcm94eSggZm4gfHwgZGF0 YSwgZnVuY3Rpb24oZXZlbnQpIHsKKwkJCWpRdWVyeSh0aGlzKS51bmJpbmQoZXZlbnQsIG9uZSk7 CisJCQlyZXR1cm4gKGZuIHx8IGRhdGEpLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKTsKKwkJfSk7 CisJCXJldHVybiB0aGlzLmVhY2goZnVuY3Rpb24oKXsKKwkJCWpRdWVyeS5ldmVudC5hZGQoIHRo aXMsIHR5cGUsIG9uZSwgZm4gJiYgZGF0YSk7CisJCX0pOworCX0sCisKKwl1bmJpbmQ6IGZ1bmN0 aW9uKCB0eXBlLCBmbiApIHsKKwkJcmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbigpeworCQkJalF1 ZXJ5LmV2ZW50LnJlbW92ZSggdGhpcywgdHlwZSwgZm4gKTsKKwkJfSk7CisJfSwKKworCXRyaWdn ZXI6IGZ1bmN0aW9uKCB0eXBlLCBkYXRhLCBmbiApIHsKKwkJcmV0dXJuIHRoaXMuZWFjaChmdW5j dGlvbigpeworCQkJalF1ZXJ5LmV2ZW50LnRyaWdnZXIoIHR5cGUsIGRhdGEsIHRoaXMsIHRydWUs IGZuICk7CisJCX0pOworCX0sCisKKwl0cmlnZ2VySGFuZGxlcjogZnVuY3Rpb24oIHR5cGUsIGRh dGEsIGZuICkgeworCQlyZXR1cm4gdGhpc1swXSAmJiBqUXVlcnkuZXZlbnQudHJpZ2dlciggdHlw ZSwgZGF0YSwgdGhpc1swXSwgZmFsc2UsIGZuICk7CisJfSwKKworCXRvZ2dsZTogZnVuY3Rpb24o IGZuICkgeworCQkvLyBTYXZlIHJlZmVyZW5jZSB0byBhcmd1bWVudHMgZm9yIGFjY2VzcyBpbiBj bG9zdXJlCisJCXZhciBhcmdzID0gYXJndW1lbnRzLCBpID0gMTsKKworCQkvLyBsaW5rIGFsbCB0 aGUgZnVuY3Rpb25zLCBzbyBhbnkgb2YgdGhlbSBjYW4gdW5iaW5kIHRoaXMgY2xpY2sgaGFuZGxl cgorCQl3aGlsZSggaSA8IGFyZ3MubGVuZ3RoICkKKwkJCWpRdWVyeS5ldmVudC5wcm94eSggZm4s IGFyZ3NbaSsrXSApOworCisJCXJldHVybiB0aGlzLmNsaWNrKCBqUXVlcnkuZXZlbnQucHJveHko IGZuLCBmdW5jdGlvbihldmVudCkgeworCQkJLy8gRmlndXJlIG91dCB3aGljaCBmdW5jdGlvbiB0 byBleGVjdXRlCisJCQl0aGlzLmxhc3RUb2dnbGUgPSAoIHRoaXMubGFzdFRvZ2dsZSB8fCAwICkg JSBpOworCisJCQkvLyBNYWtlIHN1cmUgdGhhdCBjbGlja3Mgc3RvcAorCQkJZXZlbnQucHJldmVu dERlZmF1bHQoKTsKKworCQkJLy8gYW5kIGV4ZWN1dGUgdGhlIGZ1bmN0aW9uCisJCQlyZXR1cm4g YXJnc1sgdGhpcy5sYXN0VG9nZ2xlKysgXS5hcHBseSggdGhpcywgYXJndW1lbnRzICkgfHwgZmFs c2U7CisJCX0pKTsKKwl9LAorCisJaG92ZXI6IGZ1bmN0aW9uKGZuT3ZlciwgZm5PdXQpIHsKKwkJ cmV0dXJuIHRoaXMuYmluZCgnbW91c2VlbnRlcicsIGZuT3ZlcikuYmluZCgnbW91c2VsZWF2ZScs IGZuT3V0KTsKKwl9LAorCisJcmVhZHk6IGZ1bmN0aW9uKGZuKSB7CisJCS8vIEF0dGFjaCB0aGUg bGlzdGVuZXJzCisJCWJpbmRSZWFkeSgpOworCisJCS8vIElmIHRoZSBET00gaXMgYWxyZWFkeSBy ZWFkeQorCQlpZiAoIGpRdWVyeS5pc1JlYWR5ICkKKwkJCS8vIEV4ZWN1dGUgdGhlIGZ1bmN0aW9u IGltbWVkaWF0ZWx5CisJCQlmbi5jYWxsKCBkb2N1bWVudCwgalF1ZXJ5ICk7CisKKwkJLy8gT3Ro ZXJ3aXNlLCByZW1lbWJlciB0aGUgZnVuY3Rpb24gZm9yIGxhdGVyCisJCWVsc2UKKwkJCS8vIEFk ZCB0aGUgZnVuY3Rpb24gdG8gdGhlIHdhaXQgbGlzdAorCQkJalF1ZXJ5LnJlYWR5TGlzdC5wdXNo KCBmdW5jdGlvbigpIHsgcmV0dXJuIGZuLmNhbGwodGhpcywgalF1ZXJ5KTsgfSApOworCisJCXJl dHVybiB0aGlzOworCX0KK30pOworCitqUXVlcnkuZXh0ZW5kKHsKKwlpc1JlYWR5OiBmYWxzZSwK KwlyZWFkeUxpc3Q6IFtdLAorCS8vIEhhbmRsZSB3aGVuIHRoZSBET00gaXMgcmVhZHkKKwlyZWFk eTogZnVuY3Rpb24oKSB7CisJCS8vIE1ha2Ugc3VyZSB0aGF0IHRoZSBET00gaXMgbm90IGFscmVh ZHkgbG9hZGVkCisJCWlmICggIWpRdWVyeS5pc1JlYWR5ICkgeworCQkJLy8gUmVtZW1iZXIgdGhh dCB0aGUgRE9NIGlzIHJlYWR5CisJCQlqUXVlcnkuaXNSZWFkeSA9IHRydWU7CisKKwkJCS8vIElm IHRoZXJlIGFyZSBmdW5jdGlvbnMgYm91bmQsIHRvIGV4ZWN1dGUKKwkJCWlmICggalF1ZXJ5LnJl YWR5TGlzdCApIHsKKwkJCQkvLyBFeGVjdXRlIGFsbCBvZiB0aGVtCisJCQkJalF1ZXJ5LmVhY2go IGpRdWVyeS5yZWFkeUxpc3QsIGZ1bmN0aW9uKCl7CisJCQkJCXRoaXMuY2FsbCggZG9jdW1lbnQg KTsKKwkJCQl9KTsKKworCQkJCS8vIFJlc2V0IHRoZSBsaXN0IG9mIGZ1bmN0aW9ucworCQkJCWpR dWVyeS5yZWFkeUxpc3QgPSBudWxsOworCQkJfQorCisJCQkvLyBUcmlnZ2VyIGFueSBib3VuZCBy ZWFkeSBldmVudHMKKwkJCWpRdWVyeShkb2N1bWVudCkudHJpZ2dlckhhbmRsZXIoInJlYWR5Iik7 CisJCX0KKwl9Cit9KTsKKwordmFyIHJlYWR5Qm91bmQgPSBmYWxzZTsKKworZnVuY3Rpb24gYmlu ZFJlYWR5KCl7CisJaWYgKCByZWFkeUJvdW5kICkgcmV0dXJuOworCXJlYWR5Qm91bmQgPSB0cnVl OworCisJLy8gTW96aWxsYSwgT3BlcmEgKHNlZSBmdXJ0aGVyIGJlbG93IGZvciBpdCkgYW5kIHdl YmtpdCBuaWdodGxpZXMgY3VycmVudGx5IHN1cHBvcnQgdGhpcyBldmVudAorCWlmICggZG9jdW1l bnQuYWRkRXZlbnRMaXN0ZW5lciAmJiAhalF1ZXJ5LmJyb3dzZXIub3BlcmEpCisJCS8vIFVzZSB0 aGUgaGFuZHkgZXZlbnQgY2FsbGJhY2sKKwkJZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lciggIkRP TUNvbnRlbnRMb2FkZWQiLCBqUXVlcnkucmVhZHksIGZhbHNlICk7CisKKwkvLyBJZiBJRSBpcyB1 c2VkIGFuZCBpcyBub3QgaW4gYSBmcmFtZQorCS8vIENvbnRpbnVhbGx5IGNoZWNrIHRvIHNlZSBp ZiB0aGUgZG9jdW1lbnQgaXMgcmVhZHkKKwlpZiAoIGpRdWVyeS5icm93c2VyLm1zaWUgJiYgd2lu ZG93ID09IHRvcCApIChmdW5jdGlvbigpeworCQlpZiAoalF1ZXJ5LmlzUmVhZHkpIHJldHVybjsK KwkJdHJ5IHsKKwkJCS8vIElmIElFIGlzIHVzZWQsIHVzZSB0aGUgdHJpY2sgYnkgRGllZ28gUGVy aW5pCisJCQkvLyBodHRwOi8vamF2YXNjcmlwdC5ud2JveC5jb20vSUVDb250ZW50TG9hZGVkLwor CQkJZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmRvU2Nyb2xsKCJsZWZ0Iik7CisJCX0gY2F0Y2go IGVycm9yICkgeworCQkJc2V0VGltZW91dCggYXJndW1lbnRzLmNhbGxlZSwgMCApOworCQkJcmV0 dXJuOworCQl9CisJCS8vIGFuZCBleGVjdXRlIGFueSB3YWl0aW5nIGZ1bmN0aW9ucworCQlqUXVl cnkucmVhZHkoKTsKKwl9KSgpOworCisJaWYgKCBqUXVlcnkuYnJvd3Nlci5vcGVyYSApCisJCWRv Y3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoICJET01Db250ZW50TG9hZGVkIiwgZnVuY3Rpb24gKCkg eworCQkJaWYgKGpRdWVyeS5pc1JlYWR5KSByZXR1cm47CisJCQlmb3IgKHZhciBpID0gMDsgaSA8 IGRvY3VtZW50LnN0eWxlU2hlZXRzLmxlbmd0aDsgaSsrKQorCQkJCWlmIChkb2N1bWVudC5zdHls ZVNoZWV0c1tpXS5kaXNhYmxlZCkgeworCQkJCQlzZXRUaW1lb3V0KCBhcmd1bWVudHMuY2FsbGVl LCAwICk7CisJCQkJCXJldHVybjsKKwkJCQl9CisJCQkvLyBhbmQgZXhlY3V0ZSBhbnkgd2FpdGlu ZyBmdW5jdGlvbnMKKwkJCWpRdWVyeS5yZWFkeSgpOworCQl9LCBmYWxzZSk7CisKKwlpZiAoIGpR dWVyeS5icm93c2VyLnNhZmFyaSApIHsKKwkJdmFyIG51bVN0eWxlczsKKwkJKGZ1bmN0aW9uKCl7 CisJCQlpZiAoalF1ZXJ5LmlzUmVhZHkpIHJldHVybjsKKwkJCWlmICggZG9jdW1lbnQucmVhZHlT dGF0ZSAhPSAibG9hZGVkIiAmJiBkb2N1bWVudC5yZWFkeVN0YXRlICE9ICJjb21wbGV0ZSIgKSB7 CisJCQkJc2V0VGltZW91dCggYXJndW1lbnRzLmNhbGxlZSwgMCApOworCQkJCXJldHVybjsKKwkJ CX0KKwkJCWlmICggbnVtU3R5bGVzID09PSB1bmRlZmluZWQgKQorCQkJCW51bVN0eWxlcyA9IGpR dWVyeSgic3R5bGUsIGxpbmtbcmVsPXN0eWxlc2hlZXRdIikubGVuZ3RoOworCQkJaWYgKCBkb2N1 bWVudC5zdHlsZVNoZWV0cy5sZW5ndGggIT0gbnVtU3R5bGVzICkgeworCQkJCXNldFRpbWVvdXQo IGFyZ3VtZW50cy5jYWxsZWUsIDAgKTsKKwkJCQlyZXR1cm47CisJCQl9CisJCQkvLyBhbmQgZXhl Y3V0ZSBhbnkgd2FpdGluZyBmdW5jdGlvbnMKKwkJCWpRdWVyeS5yZWFkeSgpOworCQl9KSgpOwor CX0KKworCS8vIEEgZmFsbGJhY2sgdG8gd2luZG93Lm9ubG9hZCwgdGhhdCB3aWxsIGFsd2F5cyB3 b3JrCisJalF1ZXJ5LmV2ZW50LmFkZCggd2luZG93LCAibG9hZCIsIGpRdWVyeS5yZWFkeSApOwor fQorCitqUXVlcnkuZWFjaCggKCJibHVyLGZvY3VzLGxvYWQscmVzaXplLHNjcm9sbCx1bmxvYWQs Y2xpY2ssZGJsY2xpY2ssIiArCisJIm1vdXNlZG93bixtb3VzZXVwLG1vdXNlbW92ZSxtb3VzZW92 ZXIsbW91c2VvdXQsY2hhbmdlLHNlbGVjdCwiICsKKwkic3VibWl0LGtleWRvd24sa2V5cHJlc3Ms a2V5dXAsZXJyb3IiKS5zcGxpdCgiLCIpLCBmdW5jdGlvbihpLCBuYW1lKXsKKworCS8vIEhhbmRs ZSBldmVudCBiaW5kaW5nCisJalF1ZXJ5LmZuW25hbWVdID0gZnVuY3Rpb24oZm4peworCQlyZXR1 cm4gZm4gPyB0aGlzLmJpbmQobmFtZSwgZm4pIDogdGhpcy50cmlnZ2VyKG5hbWUpOworCX07Cit9 KTsKKworLy8gQ2hlY2tzIGlmIGFuIGV2ZW50IGhhcHBlbmVkIG9uIGFuIGVsZW1lbnQgd2l0aGlu IGFub3RoZXIgZWxlbWVudAorLy8gVXNlZCBpbiBqUXVlcnkuZXZlbnQuc3BlY2lhbC5tb3VzZWVu dGVyIGFuZCBtb3VzZWxlYXZlIGhhbmRsZXJzCit2YXIgd2l0aGluRWxlbWVudCA9IGZ1bmN0aW9u KGV2ZW50LCBlbGVtKSB7CisJLy8gQ2hlY2sgaWYgbW91c2Uob3ZlcnxvdXQpIGFyZSBzdGlsbCB3 aXRoaW4gdGhlIHNhbWUgcGFyZW50IGVsZW1lbnQKKwl2YXIgcGFyZW50ID0gZXZlbnQucmVsYXRl ZFRhcmdldDsKKwkvLyBUcmF2ZXJzZSB1cCB0aGUgdHJlZQorCXdoaWxlICggcGFyZW50ICYmIHBh cmVudCAhPSBlbGVtICkgdHJ5IHsgcGFyZW50ID0gcGFyZW50LnBhcmVudE5vZGU7IH0gY2F0Y2go ZXJyb3IpIHsgcGFyZW50ID0gZWxlbTsgfQorCS8vIFJldHVybiB0cnVlIGlmIHdlIGFjdHVhbGx5 IGp1c3QgbW91c2VkIG9uIHRvIGEgc3ViLWVsZW1lbnQKKwlyZXR1cm4gcGFyZW50ID09IGVsZW07 Cit9OworCisvLyBQcmV2ZW50IG1lbW9yeSBsZWFrcyBpbiBJRQorLy8gQW5kIHByZXZlbnQgZXJy b3JzIG9uIHJlZnJlc2ggd2l0aCBldmVudHMgbGlrZSBtb3VzZW92ZXIgaW4gb3RoZXIgYnJvd3Nl cnMKKy8vIFdpbmRvdyBpc24ndCBpbmNsdWRlZCBzbyBhcyBub3QgdG8gdW5iaW5kIGV4aXN0aW5n IHVubG9hZCBldmVudHMKK2pRdWVyeSh3aW5kb3cpLmJpbmQoInVubG9hZCIsIGZ1bmN0aW9uKCkg eworCWpRdWVyeSgiKiIpLmFkZChkb2N1bWVudCkudW5iaW5kKCk7Cit9KTsKK2pRdWVyeS5mbi5l eHRlbmQoeworCS8vIEtlZXAgYSBjb3B5IG9mIHRoZSBvbGQgbG9hZAorCV9sb2FkOiBqUXVlcnku Zm4ubG9hZCwKKworCWxvYWQ6IGZ1bmN0aW9uKCB1cmwsIHBhcmFtcywgY2FsbGJhY2sgKSB7CisJ CWlmICggdHlwZW9mIHVybCAhPSAnc3RyaW5nJyApCisJCQlyZXR1cm4gdGhpcy5fbG9hZCggdXJs ICk7CisKKwkJdmFyIG9mZiA9IHVybC5pbmRleE9mKCIgIik7CisJCWlmICggb2ZmID49IDAgKSB7 CisJCQl2YXIgc2VsZWN0b3IgPSB1cmwuc2xpY2Uob2ZmLCB1cmwubGVuZ3RoKTsKKwkJCXVybCA9 IHVybC5zbGljZSgwLCBvZmYpOworCQl9CisKKwkJY2FsbGJhY2sgPSBjYWxsYmFjayB8fCBmdW5j dGlvbigpe307CisKKwkJLy8gRGVmYXVsdCB0byBhIEdFVCByZXF1ZXN0CisJCXZhciB0eXBlID0g IkdFVCI7CisKKwkJLy8gSWYgdGhlIHNlY29uZCBwYXJhbWV0ZXIgd2FzIHByb3ZpZGVkCisJCWlm ICggcGFyYW1zICkKKwkJCS8vIElmIGl0J3MgYSBmdW5jdGlvbgorCQkJaWYgKCBqUXVlcnkuaXNG dW5jdGlvbiggcGFyYW1zICkgKSB7CisJCQkJLy8gV2UgYXNzdW1lIHRoYXQgaXQncyB0aGUgY2Fs bGJhY2sKKwkJCQljYWxsYmFjayA9IHBhcmFtczsKKwkJCQlwYXJhbXMgPSBudWxsOworCisJCQkv LyBPdGhlcndpc2UsIGJ1aWxkIGEgcGFyYW0gc3RyaW5nCisJCQl9IGVsc2UgeworCQkJCXBhcmFt cyA9IGpRdWVyeS5wYXJhbSggcGFyYW1zICk7CisJCQkJdHlwZSA9ICJQT1NUIjsKKwkJCX0KKwor CQl2YXIgc2VsZiA9IHRoaXM7CisKKwkJLy8gUmVxdWVzdCB0aGUgcmVtb3RlIGRvY3VtZW50CisJ CWpRdWVyeS5hamF4KHsKKwkJCXVybDogdXJsLAorCQkJdHlwZTogdHlwZSwKKwkJCWRhdGFUeXBl OiAiaHRtbCIsCisJCQlkYXRhOiBwYXJhbXMsCisJCQljb21wbGV0ZTogZnVuY3Rpb24ocmVzLCBz dGF0dXMpeworCQkJCS8vIElmIHN1Y2Nlc3NmdWwsIGluamVjdCB0aGUgSFRNTCBpbnRvIGFsbCB0 aGUgbWF0Y2hlZCBlbGVtZW50cworCQkJCWlmICggc3RhdHVzID09ICJzdWNjZXNzIiB8fCBzdGF0 dXMgPT0gIm5vdG1vZGlmaWVkIiApCisJCQkJCS8vIFNlZSBpZiBhIHNlbGVjdG9yIHdhcyBzcGVj aWZpZWQKKwkJCQkJc2VsZi5odG1sKCBzZWxlY3RvciA/CisJCQkJCQkvLyBDcmVhdGUgYSBkdW1t eSBkaXYgdG8gaG9sZCB0aGUgcmVzdWx0cworCQkJCQkJalF1ZXJ5KCI8ZGl2Lz4iKQorCQkJCQkJ CS8vIGluamVjdCB0aGUgY29udGVudHMgb2YgdGhlIGRvY3VtZW50IGluLCByZW1vdmluZyB0aGUg c2NyaXB0cworCQkJCQkJCS8vIHRvIGF2b2lkIGFueSAnUGVybWlzc2lvbiBEZW5pZWQnIGVycm9y cyBpbiBJRQorCQkJCQkJCS5hcHBlbmQocmVzLnJlc3BvbnNlVGV4dC5yZXBsYWNlKC88c2NyaXB0 KC58XHMpKj9cL3NjcmlwdD4vZywgIiIpKQorCisJCQkJCQkJLy8gTG9jYXRlIHRoZSBzcGVjaWZp ZWQgZWxlbWVudHMKKwkJCQkJCQkuZmluZChzZWxlY3RvcikgOgorCisJCQkJCQkvLyBJZiBub3Qs IGp1c3QgaW5qZWN0IHRoZSBmdWxsIHJlc3VsdAorCQkJCQkJcmVzLnJlc3BvbnNlVGV4dCApOwor CisJCQkJc2VsZi5lYWNoKCBjYWxsYmFjaywgW3Jlcy5yZXNwb25zZVRleHQsIHN0YXR1cywgcmVz XSApOworCQkJfQorCQl9KTsKKwkJcmV0dXJuIHRoaXM7CisJfSwKKworCXNlcmlhbGl6ZTogZnVu Y3Rpb24oKSB7CisJCXJldHVybiBqUXVlcnkucGFyYW0odGhpcy5zZXJpYWxpemVBcnJheSgpKTsK Kwl9LAorCXNlcmlhbGl6ZUFycmF5OiBmdW5jdGlvbigpIHsKKwkJcmV0dXJuIHRoaXMubWFwKGZ1 bmN0aW9uKCl7CisJCQlyZXR1cm4galF1ZXJ5Lm5vZGVOYW1lKHRoaXMsICJmb3JtIikgPworCQkJ CWpRdWVyeS5tYWtlQXJyYXkodGhpcy5lbGVtZW50cykgOiB0aGlzOworCQl9KQorCQkuZmlsdGVy KGZ1bmN0aW9uKCl7CisJCQlyZXR1cm4gdGhpcy5uYW1lICYmICF0aGlzLmRpc2FibGVkICYmCisJ CQkJKHRoaXMuY2hlY2tlZCB8fCAvc2VsZWN0fHRleHRhcmVhL2kudGVzdCh0aGlzLm5vZGVOYW1l KSB8fAorCQkJCQkvdGV4dHxoaWRkZW58cGFzc3dvcmQvaS50ZXN0KHRoaXMudHlwZSkpOworCQl9 KQorCQkubWFwKGZ1bmN0aW9uKGksIGVsZW0peworCQkJdmFyIHZhbCA9IGpRdWVyeSh0aGlzKS52 YWwoKTsKKwkJCXJldHVybiB2YWwgPT0gbnVsbCA/IG51bGwgOgorCQkJCXZhbC5jb25zdHJ1Y3Rv ciA9PSBBcnJheSA/CisJCQkJCWpRdWVyeS5tYXAoIHZhbCwgZnVuY3Rpb24odmFsLCBpKXsKKwkJ CQkJCXJldHVybiB7bmFtZTogZWxlbS5uYW1lLCB2YWx1ZTogdmFsfTsKKwkJCQkJfSkgOgorCQkJ CQl7bmFtZTogZWxlbS5uYW1lLCB2YWx1ZTogdmFsfTsKKwkJfSkuZ2V0KCk7CisJfQorfSk7CisK Ky8vIEF0dGFjaCBhIGJ1bmNoIG9mIGZ1bmN0aW9ucyBmb3IgaGFuZGxpbmcgY29tbW9uIEFKQVgg ZXZlbnRzCitqUXVlcnkuZWFjaCggImFqYXhTdGFydCxhamF4U3RvcCxhamF4Q29tcGxldGUsYWph eEVycm9yLGFqYXhTdWNjZXNzLGFqYXhTZW5kIi5zcGxpdCgiLCIpLCBmdW5jdGlvbihpLG8pewor CWpRdWVyeS5mbltvXSA9IGZ1bmN0aW9uKGYpeworCQlyZXR1cm4gdGhpcy5iaW5kKG8sIGYpOwor CX07Cit9KTsKKwordmFyIGpzYyA9IG5vdygpOworCitqUXVlcnkuZXh0ZW5kKHsKKwlnZXQ6IGZ1 bmN0aW9uKCB1cmwsIGRhdGEsIGNhbGxiYWNrLCB0eXBlICkgeworCQkvLyBzaGlmdCBhcmd1bWVu dHMgaWYgZGF0YSBhcmd1bWVudCB3YXMgb21taXRlZAorCQlpZiAoIGpRdWVyeS5pc0Z1bmN0aW9u KCBkYXRhICkgKSB7CisJCQljYWxsYmFjayA9IGRhdGE7CisJCQlkYXRhID0gbnVsbDsKKwkJfQor CisJCXJldHVybiBqUXVlcnkuYWpheCh7CisJCQl0eXBlOiAiR0VUIiwKKwkJCXVybDogdXJsLAor CQkJZGF0YTogZGF0YSwKKwkJCXN1Y2Nlc3M6IGNhbGxiYWNrLAorCQkJZGF0YVR5cGU6IHR5cGUK KwkJfSk7CisJfSwKKworCWdldFNjcmlwdDogZnVuY3Rpb24oIHVybCwgY2FsbGJhY2sgKSB7CisJ CXJldHVybiBqUXVlcnkuZ2V0KHVybCwgbnVsbCwgY2FsbGJhY2ssICJzY3JpcHQiKTsKKwl9LAor CisJZ2V0SlNPTjogZnVuY3Rpb24oIHVybCwgZGF0YSwgY2FsbGJhY2sgKSB7CisJCXJldHVybiBq UXVlcnkuZ2V0KHVybCwgZGF0YSwgY2FsbGJhY2ssICJqc29uIik7CisJfSwKKworCXBvc3Q6IGZ1 bmN0aW9uKCB1cmwsIGRhdGEsIGNhbGxiYWNrLCB0eXBlICkgeworCQlpZiAoIGpRdWVyeS5pc0Z1 bmN0aW9uKCBkYXRhICkgKSB7CisJCQljYWxsYmFjayA9IGRhdGE7CisJCQlkYXRhID0ge307CisJ CX0KKworCQlyZXR1cm4galF1ZXJ5LmFqYXgoeworCQkJdHlwZTogIlBPU1QiLAorCQkJdXJsOiB1 cmwsCisJCQlkYXRhOiBkYXRhLAorCQkJc3VjY2VzczogY2FsbGJhY2ssCisJCQlkYXRhVHlwZTog dHlwZQorCQl9KTsKKwl9LAorCisJYWpheFNldHVwOiBmdW5jdGlvbiggc2V0dGluZ3MgKSB7CisJ CWpRdWVyeS5leHRlbmQoIGpRdWVyeS5hamF4U2V0dGluZ3MsIHNldHRpbmdzICk7CisJfSwKKwor CWFqYXhTZXR0aW5nczogeworCQl1cmw6IGxvY2F0aW9uLmhyZWYsCisJCWdsb2JhbDogdHJ1ZSwK KwkJdHlwZTogIkdFVCIsCisJCXRpbWVvdXQ6IDAsCisJCWNvbnRlbnRUeXBlOiAiYXBwbGljYXRp b24veC13d3ctZm9ybS11cmxlbmNvZGVkIiwKKwkJcHJvY2Vzc0RhdGE6IHRydWUsCisJCWFzeW5j OiB0cnVlLAorCQlkYXRhOiBudWxsLAorCQl1c2VybmFtZTogbnVsbCwKKwkJcGFzc3dvcmQ6IG51 bGwsCisJCWFjY2VwdHM6IHsKKwkJCXhtbDogImFwcGxpY2F0aW9uL3htbCwgdGV4dC94bWwiLAor CQkJaHRtbDogInRleHQvaHRtbCIsCisJCQlzY3JpcHQ6ICJ0ZXh0L2phdmFzY3JpcHQsIGFwcGxp Y2F0aW9uL2phdmFzY3JpcHQiLAorCQkJanNvbjogImFwcGxpY2F0aW9uL2pzb24sIHRleHQvamF2 YXNjcmlwdCIsCisJCQl0ZXh0OiAidGV4dC9wbGFpbiIsCisJCQlfZGVmYXVsdDogIiovKiIKKwkJ fQorCX0sCisKKwkvLyBMYXN0LU1vZGlmaWVkIGhlYWRlciBjYWNoZSBmb3IgbmV4dCByZXF1ZXN0 CisJbGFzdE1vZGlmaWVkOiB7fSwKKworCWFqYXg6IGZ1bmN0aW9uKCBzICkgeworCQkvLyBFeHRl bmQgdGhlIHNldHRpbmdzLCBidXQgcmUtZXh0ZW5kICdzJyBzbyB0aGF0IGl0IGNhbiBiZQorCQkv LyBjaGVja2VkIGFnYWluIGxhdGVyIChpbiB0aGUgdGVzdCBzdWl0ZSwgc3BlY2lmaWNhbGx5KQor CQlzID0galF1ZXJ5LmV4dGVuZCh0cnVlLCBzLCBqUXVlcnkuZXh0ZW5kKHRydWUsIHt9LCBqUXVl cnkuYWpheFNldHRpbmdzLCBzKSk7CisKKwkJdmFyIGpzb25wLCBqc3JlID0gLz1cPygmfCQpL2cs IHN0YXR1cywgZGF0YSwKKwkJCXR5cGUgPSBzLnR5cGUudG9VcHBlckNhc2UoKTsKKworCQkvLyBj b252ZXJ0IGRhdGEgaWYgbm90IGFscmVhZHkgYSBzdHJpbmcKKwkJaWYgKCBzLmRhdGEgJiYgcy5w cm9jZXNzRGF0YSAmJiB0eXBlb2Ygcy5kYXRhICE9ICJzdHJpbmciICkKKwkJCXMuZGF0YSA9IGpR dWVyeS5wYXJhbShzLmRhdGEpOworCisJCS8vIEhhbmRsZSBKU09OUCBQYXJhbWV0ZXIgQ2FsbGJh Y2tzCisJCWlmICggcy5kYXRhVHlwZSA9PSAianNvbnAiICkgeworCQkJaWYgKCB0eXBlID09ICJH RVQiICkgeworCQkJCWlmICggIXMudXJsLm1hdGNoKGpzcmUpICkKKwkJCQkJcy51cmwgKz0gKHMu dXJsLm1hdGNoKC9cPy8pID8gIiYiIDogIj8iKSArIChzLmpzb25wIHx8ICJjYWxsYmFjayIpICsg Ij0/IjsKKwkJCX0gZWxzZSBpZiAoICFzLmRhdGEgfHwgIXMuZGF0YS5tYXRjaChqc3JlKSApCisJ CQkJcy5kYXRhID0gKHMuZGF0YSA/IHMuZGF0YSArICImIiA6ICIiKSArIChzLmpzb25wIHx8ICJj YWxsYmFjayIpICsgIj0/IjsKKwkJCXMuZGF0YVR5cGUgPSAianNvbiI7CisJCX0KKworCQkvLyBC dWlsZCB0ZW1wb3JhcnkgSlNPTlAgZnVuY3Rpb24KKwkJaWYgKCBzLmRhdGFUeXBlID09ICJqc29u IiAmJiAocy5kYXRhICYmIHMuZGF0YS5tYXRjaChqc3JlKSB8fCBzLnVybC5tYXRjaChqc3JlKSkg KSB7CisJCQlqc29ucCA9ICJqc29ucCIgKyBqc2MrKzsKKworCQkJLy8gUmVwbGFjZSB0aGUgPT8g c2VxdWVuY2UgYm90aCBpbiB0aGUgcXVlcnkgc3RyaW5nIGFuZCB0aGUgZGF0YQorCQkJaWYgKCBz LmRhdGEgKQorCQkJCXMuZGF0YSA9IChzLmRhdGEgKyAiIikucmVwbGFjZShqc3JlLCAiPSIgKyBq c29ucCArICIkMSIpOworCQkJcy51cmwgPSBzLnVybC5yZXBsYWNlKGpzcmUsICI9IiArIGpzb25w ICsgIiQxIik7CisKKwkJCS8vIFdlIG5lZWQgdG8gbWFrZSBzdXJlCisJCQkvLyB0aGF0IGEgSlNP TlAgc3R5bGUgcmVzcG9uc2UgaXMgZXhlY3V0ZWQgcHJvcGVybHkKKwkJCXMuZGF0YVR5cGUgPSAi c2NyaXB0IjsKKworCQkJLy8gSGFuZGxlIEpTT05QLXN0eWxlIGxvYWRpbmcKKwkJCXdpbmRvd1sg anNvbnAgXSA9IGZ1bmN0aW9uKHRtcCl7CisJCQkJZGF0YSA9IHRtcDsKKwkJCQlzdWNjZXNzKCk7 CisJCQkJY29tcGxldGUoKTsKKwkJCQkvLyBHYXJiYWdlIGNvbGxlY3QKKwkJCQl3aW5kb3dbIGpz b25wIF0gPSB1bmRlZmluZWQ7CisJCQkJdHJ5eyBkZWxldGUgd2luZG93WyBqc29ucCBdOyB9IGNh dGNoKGUpe30KKwkJCQlpZiAoIGhlYWQgKQorCQkJCQloZWFkLnJlbW92ZUNoaWxkKCBzY3JpcHQg KTsKKwkJCX07CisJCX0KKworCQlpZiAoIHMuZGF0YVR5cGUgPT0gInNjcmlwdCIgJiYgcy5jYWNo ZSA9PSBudWxsICkKKwkJCXMuY2FjaGUgPSBmYWxzZTsKKworCQlpZiAoIHMuY2FjaGUgPT09IGZh bHNlICYmIHR5cGUgPT0gIkdFVCIgKSB7CisJCQl2YXIgdHMgPSBub3coKTsKKwkJCS8vIHRyeSBy ZXBsYWNpbmcgXz0gaWYgaXQgaXMgdGhlcmUKKwkJCXZhciByZXQgPSBzLnVybC5yZXBsYWNlKC8o XD98JilfPS4qPygmfCQpLywgIiQxXz0iICsgdHMgKyAiJDIiKTsKKwkJCS8vIGlmIG5vdGhpbmcg d2FzIHJlcGxhY2VkLCBhZGQgdGltZXN0YW1wIHRvIHRoZSBlbmQKKwkJCXMudXJsID0gcmV0ICsg KChyZXQgPT0gcy51cmwpID8gKHMudXJsLm1hdGNoKC9cPy8pID8gIiYiIDogIj8iKSArICJfPSIg KyB0cyA6ICIiKTsKKwkJfQorCisJCS8vIElmIGRhdGEgaXMgYXZhaWxhYmxlLCBhcHBlbmQgZGF0 YSB0byB1cmwgZm9yIGdldCByZXF1ZXN0cworCQlpZiAoIHMuZGF0YSAmJiB0eXBlID09ICJHRVQi ICkgeworCQkJcy51cmwgKz0gKHMudXJsLm1hdGNoKC9cPy8pID8gIiYiIDogIj8iKSArIHMuZGF0 YTsKKworCQkJLy8gSUUgbGlrZXMgdG8gc2VuZCBib3RoIGdldCBhbmQgcG9zdCBkYXRhLCBwcmV2 ZW50IHRoaXMKKwkJCXMuZGF0YSA9IG51bGw7CisJCX0KKworCQkvLyBXYXRjaCBmb3IgYSBuZXcg c2V0IG9mIHJlcXVlc3RzCisJCWlmICggcy5nbG9iYWwgJiYgISBqUXVlcnkuYWN0aXZlKysgKQor CQkJalF1ZXJ5LmV2ZW50LnRyaWdnZXIoICJhamF4U3RhcnQiICk7CisKKwkJLy8gTWF0Y2hlcyBh biBhYnNvbHV0ZSBVUkwsIGFuZCBzYXZlcyB0aGUgZG9tYWluCisJCXZhciByZW1vdGUgPSAvXig/ Olx3KzopP1wvXC8oW15cLz8jXSspLzsKKworCQkvLyBJZiB3ZSdyZSByZXF1ZXN0aW5nIGEgcmVt b3RlIGRvY3VtZW50CisJCS8vIGFuZCB0cnlpbmcgdG8gbG9hZCBKU09OIG9yIFNjcmlwdCB3aXRo IGEgR0VUCisJCWlmICggcy5kYXRhVHlwZSA9PSAic2NyaXB0IiAmJiB0eXBlID09ICJHRVQiCisJ CQkJJiYgcmVtb3RlLnRlc3Qocy51cmwpICYmIHJlbW90ZS5leGVjKHMudXJsKVsxXSAhPSBsb2Nh dGlvbi5ob3N0ICl7CisJCQl2YXIgaGVhZCA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1l KCJoZWFkIilbMF07CisJCQl2YXIgc2NyaXB0ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgic2Ny aXB0Iik7CisJCQlzY3JpcHQuc3JjID0gcy51cmw7CisJCQlpZiAocy5zY3JpcHRDaGFyc2V0KQor CQkJCXNjcmlwdC5jaGFyc2V0ID0gcy5zY3JpcHRDaGFyc2V0OworCisJCQkvLyBIYW5kbGUgU2Ny aXB0IGxvYWRpbmcKKwkJCWlmICggIWpzb25wICkgeworCQkJCXZhciBkb25lID0gZmFsc2U7CisK KwkJCQkvLyBBdHRhY2ggaGFuZGxlcnMgZm9yIGFsbCBicm93c2VycworCQkJCXNjcmlwdC5vbmxv YWQgPSBzY3JpcHQub25yZWFkeXN0YXRlY2hhbmdlID0gZnVuY3Rpb24oKXsKKwkJCQkJaWYgKCAh ZG9uZSAmJiAoIXRoaXMucmVhZHlTdGF0ZSB8fAorCQkJCQkJCXRoaXMucmVhZHlTdGF0ZSA9PSAi bG9hZGVkIiB8fCB0aGlzLnJlYWR5U3RhdGUgPT0gImNvbXBsZXRlIikgKSB7CisJCQkJCQlkb25l ID0gdHJ1ZTsKKwkJCQkJCXN1Y2Nlc3MoKTsKKwkJCQkJCWNvbXBsZXRlKCk7CisJCQkJCQloZWFk LnJlbW92ZUNoaWxkKCBzY3JpcHQgKTsKKwkJCQkJfQorCQkJCX07CisJCQl9CisKKwkJCWhlYWQu YXBwZW5kQ2hpbGQoc2NyaXB0KTsKKworCQkJLy8gV2UgaGFuZGxlIGV2ZXJ5dGhpbmcgdXNpbmcg dGhlIHNjcmlwdCBlbGVtZW50IGluamVjdGlvbgorCQkJcmV0dXJuIHVuZGVmaW5lZDsKKwkJfQor CisJCXZhciByZXF1ZXN0RG9uZSA9IGZhbHNlOworCisJCS8vIENyZWF0ZSB0aGUgcmVxdWVzdCBv YmplY3Q7IE1pY3Jvc29mdCBmYWlsZWQgdG8gcHJvcGVybHkKKwkJLy8gaW1wbGVtZW50IHRoZSBY TUxIdHRwUmVxdWVzdCBpbiBJRTcsIHNvIHdlIHVzZSB0aGUgQWN0aXZlWE9iamVjdCB3aGVuIGl0 IGlzIGF2YWlsYWJsZQorCQl2YXIgeGhyID0gd2luZG93LkFjdGl2ZVhPYmplY3QgPyBuZXcgQWN0 aXZlWE9iamVjdCgiTWljcm9zb2Z0LlhNTEhUVFAiKSA6IG5ldyBYTUxIdHRwUmVxdWVzdCgpOwor CisJCS8vIE9wZW4gdGhlIHNvY2tldAorCQkvLyBQYXNzaW5nIG51bGwgdXNlcm5hbWUsIGdlbmVy YXRlcyBhIGxvZ2luIHBvcHVwIG9uIE9wZXJhICgjMjg2NSkKKwkJaWYoIHMudXNlcm5hbWUgKQor CQkJeGhyLm9wZW4odHlwZSwgcy51cmwsIHMuYXN5bmMsIHMudXNlcm5hbWUsIHMucGFzc3dvcmQp OworCQllbHNlCisJCQl4aHIub3Blbih0eXBlLCBzLnVybCwgcy5hc3luYyk7CisKKwkJLy8gTmVl ZCBhbiBleHRyYSB0cnkvY2F0Y2ggZm9yIGNyb3NzIGRvbWFpbiByZXF1ZXN0cyBpbiBGaXJlZm94 IDMKKwkJdHJ5IHsKKwkJCS8vIFNldCB0aGUgY29ycmVjdCBoZWFkZXIsIGlmIGRhdGEgaXMgYmVp bmcgc2VudAorCQkJaWYgKCBzLmRhdGEgKQorCQkJCXhoci5zZXRSZXF1ZXN0SGVhZGVyKCJDb250 ZW50LVR5cGUiLCBzLmNvbnRlbnRUeXBlKTsKKworCQkJLy8gU2V0IHRoZSBJZi1Nb2RpZmllZC1T aW5jZSBoZWFkZXIsIGlmIGlmTW9kaWZpZWQgbW9kZS4KKwkJCWlmICggcy5pZk1vZGlmaWVkICkK KwkJCQl4aHIuc2V0UmVxdWVzdEhlYWRlcigiSWYtTW9kaWZpZWQtU2luY2UiLAorCQkJCQlqUXVl cnkubGFzdE1vZGlmaWVkW3MudXJsXSB8fCAiVGh1LCAwMSBKYW4gMTk3MCAwMDowMDowMCBHTVQi ICk7CisKKwkJCS8vIFNldCBoZWFkZXIgc28gdGhlIGNhbGxlZCBzY3JpcHQga25vd3MgdGhhdCBp dCdzIGFuIFhNTEh0dHBSZXF1ZXN0CisJCQl4aHIuc2V0UmVxdWVzdEhlYWRlcigiWC1SZXF1ZXN0 ZWQtV2l0aCIsICJYTUxIdHRwUmVxdWVzdCIpOworCisJCQkvLyBTZXQgdGhlIEFjY2VwdHMgaGVh ZGVyIGZvciB0aGUgc2VydmVyLCBkZXBlbmRpbmcgb24gdGhlIGRhdGFUeXBlCisJCQl4aHIuc2V0 UmVxdWVzdEhlYWRlcigiQWNjZXB0Iiwgcy5kYXRhVHlwZSAmJiBzLmFjY2VwdHNbIHMuZGF0YVR5 cGUgXSA/CisJCQkJcy5hY2NlcHRzWyBzLmRhdGFUeXBlIF0gKyAiLCAqLyoiIDoKKwkJCQlzLmFj Y2VwdHMuX2RlZmF1bHQgKTsKKwkJfSBjYXRjaChlKXt9CisKKwkJLy8gQWxsb3cgY3VzdG9tIGhl YWRlcnMvbWltZXR5cGVzCisJCWlmICggcy5iZWZvcmVTZW5kICYmIHMuYmVmb3JlU2VuZCh4aHIs IHMpID09PSBmYWxzZSApIHsKKwkJCS8vIGNsZWFudXAgYWN0aXZlIHJlcXVlc3QgY291bnRlcgor CQkJcy5nbG9iYWwgJiYgalF1ZXJ5LmFjdGl2ZS0tOworCQkJLy8gY2xvc2Ugb3BlbmRlZCBzb2Nr ZXQKKwkJCXhoci5hYm9ydCgpOworCQkJcmV0dXJuIGZhbHNlOworCQl9CisKKwkJaWYgKCBzLmds b2JhbCApCisJCQlqUXVlcnkuZXZlbnQudHJpZ2dlcigiYWpheFNlbmQiLCBbeGhyLCBzXSk7CisK KwkJLy8gV2FpdCBmb3IgYSByZXNwb25zZSB0byBjb21lIGJhY2sKKwkJdmFyIG9ucmVhZHlzdGF0 ZWNoYW5nZSA9IGZ1bmN0aW9uKGlzVGltZW91dCl7CisJCQkvLyBUaGUgdHJhbnNmZXIgaXMgY29t cGxldGUgYW5kIHRoZSBkYXRhIGlzIGF2YWlsYWJsZSwgb3IgdGhlIHJlcXVlc3QgdGltZWQgb3V0 CisJCQlpZiAoICFyZXF1ZXN0RG9uZSAmJiB4aHIgJiYgKHhoci5yZWFkeVN0YXRlID09IDQgfHwg aXNUaW1lb3V0ID09ICJ0aW1lb3V0IikgKSB7CisJCQkJcmVxdWVzdERvbmUgPSB0cnVlOworCisJ CQkJLy8gY2xlYXIgcG9sbCBpbnRlcnZhbAorCQkJCWlmIChpdmFsKSB7CisJCQkJCWNsZWFySW50 ZXJ2YWwoaXZhbCk7CisJCQkJCWl2YWwgPSBudWxsOworCQkJCX0KKworCQkJCXN0YXR1cyA9IGlz VGltZW91dCA9PSAidGltZW91dCIgJiYgInRpbWVvdXQiIHx8CisJCQkJCSFqUXVlcnkuaHR0cFN1 Y2Nlc3MoIHhociApICYmICJlcnJvciIgfHwKKwkJCQkJcy5pZk1vZGlmaWVkICYmIGpRdWVyeS5o dHRwTm90TW9kaWZpZWQoIHhociwgcy51cmwgKSAmJiAibm90bW9kaWZpZWQiIHx8CisJCQkJCSJz dWNjZXNzIjsKKworCQkJCWlmICggc3RhdHVzID09ICJzdWNjZXNzIiApIHsKKwkJCQkJLy8gV2F0 Y2ggZm9yLCBhbmQgY2F0Y2gsIFhNTCBkb2N1bWVudCBwYXJzZSBlcnJvcnMKKwkJCQkJdHJ5IHsK KwkJCQkJCS8vIHByb2Nlc3MgdGhlIGRhdGEgKHJ1bnMgdGhlIHhtbCB0aHJvdWdoIGh0dHBEYXRh IHJlZ2FyZGxlc3Mgb2YgY2FsbGJhY2spCisJCQkJCQlkYXRhID0galF1ZXJ5Lmh0dHBEYXRhKCB4 aHIsIHMuZGF0YVR5cGUsIHMuZGF0YUZpbHRlciApOworCQkJCQl9IGNhdGNoKGUpIHsKKwkJCQkJ CXN0YXR1cyA9ICJwYXJzZXJlcnJvciI7CisJCQkJCX0KKwkJCQl9CisKKwkJCQkvLyBNYWtlIHN1 cmUgdGhhdCB0aGUgcmVxdWVzdCB3YXMgc3VjY2Vzc2Z1bCBvciBub3Rtb2RpZmllZAorCQkJCWlm ICggc3RhdHVzID09ICJzdWNjZXNzIiApIHsKKwkJCQkJLy8gQ2FjaGUgTGFzdC1Nb2RpZmllZCBo ZWFkZXIsIGlmIGlmTW9kaWZpZWQgbW9kZS4KKwkJCQkJdmFyIG1vZFJlczsKKwkJCQkJdHJ5IHsK KwkJCQkJCW1vZFJlcyA9IHhoci5nZXRSZXNwb25zZUhlYWRlcigiTGFzdC1Nb2RpZmllZCIpOwor CQkJCQl9IGNhdGNoKGUpIHt9IC8vIHN3YWxsb3cgZXhjZXB0aW9uIHRocm93biBieSBGRiBpZiBo ZWFkZXIgaXMgbm90IGF2YWlsYWJsZQorCisJCQkJCWlmICggcy5pZk1vZGlmaWVkICYmIG1vZFJl cyApCisJCQkJCQlqUXVlcnkubGFzdE1vZGlmaWVkW3MudXJsXSA9IG1vZFJlczsKKworCQkJCQkv LyBKU09OUCBoYW5kbGVzIGl0cyBvd24gc3VjY2VzcyBjYWxsYmFjaworCQkJCQlpZiAoICFqc29u cCApCisJCQkJCQlzdWNjZXNzKCk7CisJCQkJfSBlbHNlCisJCQkJCWpRdWVyeS5oYW5kbGVFcnJv cihzLCB4aHIsIHN0YXR1cyk7CisKKwkJCQkvLyBGaXJlIHRoZSBjb21wbGV0ZSBoYW5kbGVycwor CQkJCWNvbXBsZXRlKCk7CisKKwkJCQkvLyBTdG9wIG1lbW9yeSBsZWFrcworCQkJCWlmICggcy5h c3luYyApCisJCQkJCXhociA9IG51bGw7CisJCQl9CisJCX07CisKKwkJaWYgKCBzLmFzeW5jICkg eworCQkJLy8gZG9uJ3QgYXR0YWNoIHRoZSBoYW5kbGVyIHRvIHRoZSByZXF1ZXN0LCBqdXN0IHBv bGwgaXQgaW5zdGVhZAorCQkJdmFyIGl2YWwgPSBzZXRJbnRlcnZhbChvbnJlYWR5c3RhdGVjaGFu Z2UsIDEzKTsKKworCQkJLy8gVGltZW91dCBjaGVja2VyCisJCQlpZiAoIHMudGltZW91dCA+IDAg KQorCQkJCXNldFRpbWVvdXQoZnVuY3Rpb24oKXsKKwkJCQkJLy8gQ2hlY2sgdG8gc2VlIGlmIHRo ZSByZXF1ZXN0IGlzIHN0aWxsIGhhcHBlbmluZworCQkJCQlpZiAoIHhociApIHsKKwkJCQkJCS8v IENhbmNlbCB0aGUgcmVxdWVzdAorCQkJCQkJeGhyLmFib3J0KCk7CisKKwkJCQkJCWlmKCAhcmVx dWVzdERvbmUgKQorCQkJCQkJCW9ucmVhZHlzdGF0ZWNoYW5nZSggInRpbWVvdXQiICk7CisJCQkJ CX0KKwkJCQl9LCBzLnRpbWVvdXQpOworCQl9CisKKwkJLy8gU2VuZCB0aGUgZGF0YQorCQl0cnkg eworCQkJeGhyLnNlbmQocy5kYXRhKTsKKwkJfSBjYXRjaChlKSB7CisJCQlqUXVlcnkuaGFuZGxl RXJyb3IocywgeGhyLCBudWxsLCBlKTsKKwkJfQorCisJCS8vIGZpcmVmb3ggMS41IGRvZXNuJ3Qg ZmlyZSBzdGF0ZWNoYW5nZSBmb3Igc3luYyByZXF1ZXN0cworCQlpZiAoICFzLmFzeW5jICkKKwkJ CW9ucmVhZHlzdGF0ZWNoYW5nZSgpOworCisJCWZ1bmN0aW9uIHN1Y2Nlc3MoKXsKKwkJCS8vIElm IGEgbG9jYWwgY2FsbGJhY2sgd2FzIHNwZWNpZmllZCwgZmlyZSBpdCBhbmQgcGFzcyBpdCB0aGUg ZGF0YQorCQkJaWYgKCBzLnN1Y2Nlc3MgKQorCQkJCXMuc3VjY2VzcyggZGF0YSwgc3RhdHVzICk7 CisKKwkJCS8vIEZpcmUgdGhlIGdsb2JhbCBjYWxsYmFjaworCQkJaWYgKCBzLmdsb2JhbCApCisJ CQkJalF1ZXJ5LmV2ZW50LnRyaWdnZXIoICJhamF4U3VjY2VzcyIsIFt4aHIsIHNdICk7CisJCX0K KworCQlmdW5jdGlvbiBjb21wbGV0ZSgpeworCQkJLy8gUHJvY2VzcyByZXN1bHQKKwkJCWlmICgg cy5jb21wbGV0ZSApCisJCQkJcy5jb21wbGV0ZSh4aHIsIHN0YXR1cyk7CisKKwkJCS8vIFRoZSBy ZXF1ZXN0IHdhcyBjb21wbGV0ZWQKKwkJCWlmICggcy5nbG9iYWwgKQorCQkJCWpRdWVyeS5ldmVu dC50cmlnZ2VyKCAiYWpheENvbXBsZXRlIiwgW3hociwgc10gKTsKKworCQkJLy8gSGFuZGxlIHRo ZSBnbG9iYWwgQUpBWCBjb3VudGVyCisJCQlpZiAoIHMuZ2xvYmFsICYmICEgLS1qUXVlcnkuYWN0 aXZlICkKKwkJCQlqUXVlcnkuZXZlbnQudHJpZ2dlciggImFqYXhTdG9wIiApOworCQl9CisKKwkJ Ly8gcmV0dXJuIFhNTEh0dHBSZXF1ZXN0IHRvIGFsbG93IGFib3J0aW5nIHRoZSByZXF1ZXN0IGV0 Yy4KKwkJcmV0dXJuIHhocjsKKwl9LAorCisJaGFuZGxlRXJyb3I6IGZ1bmN0aW9uKCBzLCB4aHIs IHN0YXR1cywgZSApIHsKKwkJLy8gSWYgYSBsb2NhbCBjYWxsYmFjayB3YXMgc3BlY2lmaWVkLCBm aXJlIGl0CisJCWlmICggcy5lcnJvciApIHMuZXJyb3IoIHhociwgc3RhdHVzLCBlICk7CisKKwkJ Ly8gRmlyZSB0aGUgZ2xvYmFsIGNhbGxiYWNrCisJCWlmICggcy5nbG9iYWwgKQorCQkJalF1ZXJ5 LmV2ZW50LnRyaWdnZXIoICJhamF4RXJyb3IiLCBbeGhyLCBzLCBlXSApOworCX0sCisKKwkvLyBD b3VudGVyIGZvciBob2xkaW5nIHRoZSBudW1iZXIgb2YgYWN0aXZlIHF1ZXJpZXMKKwlhY3RpdmU6 IDAsCisKKwkvLyBEZXRlcm1pbmVzIGlmIGFuIFhNTEh0dHBSZXF1ZXN0IHdhcyBzdWNjZXNzZnVs IG9yIG5vdAorCWh0dHBTdWNjZXNzOiBmdW5jdGlvbiggeGhyICkgeworCQl0cnkgeworCQkJLy8g SUUgZXJyb3Igc29tZXRpbWVzIHJldHVybnMgMTIyMyB3aGVuIGl0IHNob3VsZCBiZSAyMDQgc28g dHJlYXQgaXQgYXMgc3VjY2Vzcywgc2VlICMxNDUwCisJCQlyZXR1cm4gIXhoci5zdGF0dXMgJiYg bG9jYXRpb24ucHJvdG9jb2wgPT0gImZpbGU6IiB8fAorCQkJCSggeGhyLnN0YXR1cyA+PSAyMDAg JiYgeGhyLnN0YXR1cyA8IDMwMCApIHx8IHhoci5zdGF0dXMgPT0gMzA0IHx8IHhoci5zdGF0dXMg PT0gMTIyMyB8fAorCQkJCWpRdWVyeS5icm93c2VyLnNhZmFyaSAmJiB4aHIuc3RhdHVzID09IHVu ZGVmaW5lZDsKKwkJfSBjYXRjaChlKXt9CisJCXJldHVybiBmYWxzZTsKKwl9LAorCisJLy8gRGV0 ZXJtaW5lcyBpZiBhbiBYTUxIdHRwUmVxdWVzdCByZXR1cm5zIE5vdE1vZGlmaWVkCisJaHR0cE5v dE1vZGlmaWVkOiBmdW5jdGlvbiggeGhyLCB1cmwgKSB7CisJCXRyeSB7CisJCQl2YXIgeGhyUmVz ID0geGhyLmdldFJlc3BvbnNlSGVhZGVyKCJMYXN0LU1vZGlmaWVkIik7CisKKwkJCS8vIEZpcmVm b3ggYWx3YXlzIHJldHVybnMgMjAwLiBjaGVjayBMYXN0LU1vZGlmaWVkIGRhdGUKKwkJCXJldHVy biB4aHIuc3RhdHVzID09IDMwNCB8fCB4aHJSZXMgPT0galF1ZXJ5Lmxhc3RNb2RpZmllZFt1cmxd IHx8CisJCQkJalF1ZXJ5LmJyb3dzZXIuc2FmYXJpICYmIHhoci5zdGF0dXMgPT0gdW5kZWZpbmVk OworCQl9IGNhdGNoKGUpe30KKwkJcmV0dXJuIGZhbHNlOworCX0sCisKKwlodHRwRGF0YTogZnVu Y3Rpb24oIHhociwgdHlwZSwgZmlsdGVyICkgeworCQl2YXIgY3QgPSB4aHIuZ2V0UmVzcG9uc2VI ZWFkZXIoImNvbnRlbnQtdHlwZSIpLAorCQkJeG1sID0gdHlwZSA9PSAieG1sIiB8fCAhdHlwZSAm JiBjdCAmJiBjdC5pbmRleE9mKCJ4bWwiKSA+PSAwLAorCQkJZGF0YSA9IHhtbCA/IHhoci5yZXNw b25zZVhNTCA6IHhoci5yZXNwb25zZVRleHQ7CisKKwkJaWYgKCB4bWwgJiYgZGF0YS5kb2N1bWVu dEVsZW1lbnQudGFnTmFtZSA9PSAicGFyc2VyZXJyb3IiICkKKwkJCXRocm93ICJwYXJzZXJlcnJv ciI7CisJCQkKKwkJLy8gQWxsb3cgYSBwcmUtZmlsdGVyaW5nIGZ1bmN0aW9uIHRvIHNhbml0aXpl IHRoZSByZXNwb25zZQorCQlpZiggZmlsdGVyICkKKwkJCWRhdGEgPSBmaWx0ZXIoIGRhdGEsIHR5 cGUgKTsKKworCQkvLyBJZiB0aGUgdHlwZSBpcyAic2NyaXB0IiwgZXZhbCBpdCBpbiBnbG9iYWwg Y29udGV4dAorCQlpZiAoIHR5cGUgPT0gInNjcmlwdCIgKQorCQkJalF1ZXJ5Lmdsb2JhbEV2YWwo IGRhdGEgKTsKKworCQkvLyBHZXQgdGhlIEphdmFTY3JpcHQgb2JqZWN0LCBpZiBKU09OIGlzIHVz ZWQuCisJCWlmICggdHlwZSA9PSAianNvbiIgKQorCQkJZGF0YSA9IGV2YWwoIigiICsgZGF0YSAr ICIpIik7CisKKwkJcmV0dXJuIGRhdGE7CisJfSwKKworCS8vIFNlcmlhbGl6ZSBhbiBhcnJheSBv ZiBmb3JtIGVsZW1lbnRzIG9yIGEgc2V0IG9mCisJLy8ga2V5L3ZhbHVlcyBpbnRvIGEgcXVlcnkg c3RyaW5nCisJcGFyYW06IGZ1bmN0aW9uKCBhICkgeworCQl2YXIgcyA9IFtdOworCisJCS8vIElm IGFuIGFycmF5IHdhcyBwYXNzZWQgaW4sIGFzc3VtZSB0aGF0IGl0IGlzIGFuIGFycmF5CisJCS8v IG9mIGZvcm0gZWxlbWVudHMKKwkJaWYgKCBhLmNvbnN0cnVjdG9yID09IEFycmF5IHx8IGEuanF1 ZXJ5ICkKKwkJCS8vIFNlcmlhbGl6ZSB0aGUgZm9ybSBlbGVtZW50cworCQkJalF1ZXJ5LmVhY2go IGEsIGZ1bmN0aW9uKCl7CisJCQkJcy5wdXNoKCBlbmNvZGVVUklDb21wb25lbnQodGhpcy5uYW1l KSArICI9IiArIGVuY29kZVVSSUNvbXBvbmVudCggdGhpcy52YWx1ZSApICk7CisJCQl9KTsKKwor CQkvLyBPdGhlcndpc2UsIGFzc3VtZSB0aGF0IGl0J3MgYW4gb2JqZWN0IG9mIGtleS92YWx1ZSBw YWlycworCQllbHNlCisJCQkvLyBTZXJpYWxpemUgdGhlIGtleS92YWx1ZXMKKwkJCWZvciAoIHZh ciBqIGluIGEgKQorCQkJCS8vIElmIHRoZSB2YWx1ZSBpcyBhbiBhcnJheSB0aGVuIHRoZSBrZXkg bmFtZXMgbmVlZCB0byBiZSByZXBlYXRlZAorCQkJCWlmICggYVtqXSAmJiBhW2pdLmNvbnN0cnVj dG9yID09IEFycmF5ICkKKwkJCQkJalF1ZXJ5LmVhY2goIGFbal0sIGZ1bmN0aW9uKCl7CisJCQkJ CQlzLnB1c2goIGVuY29kZVVSSUNvbXBvbmVudChqKSArICI9IiArIGVuY29kZVVSSUNvbXBvbmVu dCggdGhpcyApICk7CisJCQkJCX0pOworCQkJCWVsc2UKKwkJCQkJcy5wdXNoKCBlbmNvZGVVUklD b21wb25lbnQoaikgKyAiPSIgKyBlbmNvZGVVUklDb21wb25lbnQoIGpRdWVyeS5pc0Z1bmN0aW9u KGFbal0pID8gYVtqXSgpIDogYVtqXSApICk7CisKKwkJLy8gUmV0dXJuIHRoZSByZXN1bHRpbmcg c2VyaWFsaXphdGlvbgorCQlyZXR1cm4gcy5qb2luKCImIikucmVwbGFjZSgvJTIwL2csICIrIik7 CisJfQorCit9KTsKK2pRdWVyeS5mbi5leHRlbmQoeworCXNob3c6IGZ1bmN0aW9uKHNwZWVkLGNh bGxiYWNrKXsKKwkJcmV0dXJuIHNwZWVkID8KKwkJCXRoaXMuYW5pbWF0ZSh7CisJCQkJaGVpZ2h0 OiAic2hvdyIsIHdpZHRoOiAic2hvdyIsIG9wYWNpdHk6ICJzaG93IgorCQkJfSwgc3BlZWQsIGNh bGxiYWNrKSA6CisKKwkJCXRoaXMuZmlsdGVyKCI6aGlkZGVuIikuZWFjaChmdW5jdGlvbigpewor CQkJCXRoaXMuc3R5bGUuZGlzcGxheSA9IHRoaXMub2xkYmxvY2sgfHwgIiI7CisJCQkJaWYgKCBq UXVlcnkuY3NzKHRoaXMsImRpc3BsYXkiKSA9PSAibm9uZSIgKSB7CisJCQkJCXZhciBlbGVtID0g alF1ZXJ5KCI8IiArIHRoaXMudGFnTmFtZSArICIgLz4iKS5hcHBlbmRUbygiYm9keSIpOworCQkJ CQl0aGlzLnN0eWxlLmRpc3BsYXkgPSBlbGVtLmNzcygiZGlzcGxheSIpOworCQkJCQkvLyBoYW5k bGUgYW4gZWRnZSBjb25kaXRpb24gd2hlcmUgY3NzIGlzIC0gZGl2IHsgZGlzcGxheTpub25lOyB9 IG9yIHNpbWlsYXIKKwkJCQkJaWYgKHRoaXMuc3R5bGUuZGlzcGxheSA9PSAibm9uZSIpCisJCQkJ CQl0aGlzLnN0eWxlLmRpc3BsYXkgPSAiYmxvY2siOworCQkJCQllbGVtLnJlbW92ZSgpOworCQkJ CX0KKwkJCX0pLmVuZCgpOworCX0sCisKKwloaWRlOiBmdW5jdGlvbihzcGVlZCxjYWxsYmFjayl7 CisJCXJldHVybiBzcGVlZCA/CisJCQl0aGlzLmFuaW1hdGUoeworCQkJCWhlaWdodDogImhpZGUi LCB3aWR0aDogImhpZGUiLCBvcGFjaXR5OiAiaGlkZSIKKwkJCX0sIHNwZWVkLCBjYWxsYmFjaykg OgorCisJCQl0aGlzLmZpbHRlcigiOnZpc2libGUiKS5lYWNoKGZ1bmN0aW9uKCl7CisJCQkJdGhp cy5vbGRibG9jayA9IHRoaXMub2xkYmxvY2sgfHwgalF1ZXJ5LmNzcyh0aGlzLCJkaXNwbGF5Iik7 CisJCQkJdGhpcy5zdHlsZS5kaXNwbGF5ID0gIm5vbmUiOworCQkJfSkuZW5kKCk7CisJfSwKKwor CS8vIFNhdmUgdGhlIG9sZCB0b2dnbGUgZnVuY3Rpb24KKwlfdG9nZ2xlOiBqUXVlcnkuZm4udG9n Z2xlLAorCisJdG9nZ2xlOiBmdW5jdGlvbiggZm4sIGZuMiApeworCQlyZXR1cm4galF1ZXJ5Lmlz RnVuY3Rpb24oZm4pICYmIGpRdWVyeS5pc0Z1bmN0aW9uKGZuMikgPworCQkJdGhpcy5fdG9nZ2xl LmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKSA6CisJCQlmbiA/CisJCQkJdGhpcy5hbmltYXRlKHsK KwkJCQkJaGVpZ2h0OiAidG9nZ2xlIiwgd2lkdGg6ICJ0b2dnbGUiLCBvcGFjaXR5OiAidG9nZ2xl IgorCQkJCX0sIGZuLCBmbjIpIDoKKwkJCQl0aGlzLmVhY2goZnVuY3Rpb24oKXsKKwkJCQkJalF1 ZXJ5KHRoaXMpWyBqUXVlcnkodGhpcykuaXMoIjpoaWRkZW4iKSA/ICJzaG93IiA6ICJoaWRlIiBd KCk7CisJCQkJfSk7CisJfSwKKworCXNsaWRlRG93bjogZnVuY3Rpb24oc3BlZWQsY2FsbGJhY2sp eworCQlyZXR1cm4gdGhpcy5hbmltYXRlKHtoZWlnaHQ6ICJzaG93In0sIHNwZWVkLCBjYWxsYmFj ayk7CisJfSwKKworCXNsaWRlVXA6IGZ1bmN0aW9uKHNwZWVkLGNhbGxiYWNrKXsKKwkJcmV0dXJu IHRoaXMuYW5pbWF0ZSh7aGVpZ2h0OiAiaGlkZSJ9LCBzcGVlZCwgY2FsbGJhY2spOworCX0sCisK KwlzbGlkZVRvZ2dsZTogZnVuY3Rpb24oc3BlZWQsIGNhbGxiYWNrKXsKKwkJcmV0dXJuIHRoaXMu YW5pbWF0ZSh7aGVpZ2h0OiAidG9nZ2xlIn0sIHNwZWVkLCBjYWxsYmFjayk7CisJfSwKKworCWZh ZGVJbjogZnVuY3Rpb24oc3BlZWQsIGNhbGxiYWNrKXsKKwkJcmV0dXJuIHRoaXMuYW5pbWF0ZSh7 b3BhY2l0eTogInNob3cifSwgc3BlZWQsIGNhbGxiYWNrKTsKKwl9LAorCisJZmFkZU91dDogZnVu Y3Rpb24oc3BlZWQsIGNhbGxiYWNrKXsKKwkJcmV0dXJuIHRoaXMuYW5pbWF0ZSh7b3BhY2l0eTog ImhpZGUifSwgc3BlZWQsIGNhbGxiYWNrKTsKKwl9LAorCisJZmFkZVRvOiBmdW5jdGlvbihzcGVl ZCx0byxjYWxsYmFjayl7CisJCXJldHVybiB0aGlzLmFuaW1hdGUoe29wYWNpdHk6IHRvfSwgc3Bl ZWQsIGNhbGxiYWNrKTsKKwl9LAorCisJYW5pbWF0ZTogZnVuY3Rpb24oIHByb3AsIHNwZWVkLCBl YXNpbmcsIGNhbGxiYWNrICkgeworCQl2YXIgb3B0YWxsID0galF1ZXJ5LnNwZWVkKHNwZWVkLCBl YXNpbmcsIGNhbGxiYWNrKTsKKworCQlyZXR1cm4gdGhpc1sgb3B0YWxsLnF1ZXVlID09PSBmYWxz ZSA/ICJlYWNoIiA6ICJxdWV1ZSIgXShmdW5jdGlvbigpeworCQkJaWYgKCB0aGlzLm5vZGVUeXBl ICE9IDEpCisJCQkJcmV0dXJuIGZhbHNlOworCisJCQl2YXIgb3B0ID0galF1ZXJ5LmV4dGVuZCh7 fSwgb3B0YWxsKSwgcCwKKwkJCQloaWRkZW4gPSBqUXVlcnkodGhpcykuaXMoIjpoaWRkZW4iKSwg c2VsZiA9IHRoaXM7CisKKwkJCWZvciAoIHAgaW4gcHJvcCApIHsKKwkJCQlpZiAoIHByb3BbcF0g PT0gImhpZGUiICYmIGhpZGRlbiB8fCBwcm9wW3BdID09ICJzaG93IiAmJiAhaGlkZGVuICkKKwkJ CQkJcmV0dXJuIG9wdC5jb21wbGV0ZS5jYWxsKHRoaXMpOworCisJCQkJaWYgKCBwID09ICJoZWln aHQiIHx8IHAgPT0gIndpZHRoIiApIHsKKwkJCQkJLy8gU3RvcmUgZGlzcGxheSBwcm9wZXJ0eQor CQkJCQlvcHQuZGlzcGxheSA9IGpRdWVyeS5jc3ModGhpcywgImRpc3BsYXkiKTsKKworCQkJCQkv LyBNYWtlIHN1cmUgdGhhdCBub3RoaW5nIHNuZWFrcyBvdXQKKwkJCQkJb3B0Lm92ZXJmbG93ID0g dGhpcy5zdHlsZS5vdmVyZmxvdzsKKwkJCQl9CisJCQl9CisKKwkJCWlmICggb3B0Lm92ZXJmbG93 ICE9IG51bGwgKQorCQkJCXRoaXMuc3R5bGUub3ZlcmZsb3cgPSAiaGlkZGVuIjsKKworCQkJb3B0 LmN1ckFuaW0gPSBqUXVlcnkuZXh0ZW5kKHt9LCBwcm9wKTsKKworCQkJalF1ZXJ5LmVhY2goIHBy b3AsIGZ1bmN0aW9uKG5hbWUsIHZhbCl7CisJCQkJdmFyIGUgPSBuZXcgalF1ZXJ5LmZ4KCBzZWxm LCBvcHQsIG5hbWUgKTsKKworCQkJCWlmICggL3RvZ2dsZXxzaG93fGhpZGUvLnRlc3QodmFsKSAp CisJCQkJCWVbIHZhbCA9PSAidG9nZ2xlIiA/IGhpZGRlbiA/ICJzaG93IiA6ICJoaWRlIiA6IHZh bCBdKCBwcm9wICk7CisJCQkJZWxzZSB7CisJCQkJCXZhciBwYXJ0cyA9IHZhbC50b1N0cmluZygp Lm1hdGNoKC9eKFsrLV09KT8oW1xkKy0uXSspKC4qKSQvKSwKKwkJCQkJCXN0YXJ0ID0gZS5jdXIo dHJ1ZSkgfHwgMDsKKworCQkJCQlpZiAoIHBhcnRzICkgeworCQkJCQkJdmFyIGVuZCA9IHBhcnNl RmxvYXQocGFydHNbMl0pLAorCQkJCQkJCXVuaXQgPSBwYXJ0c1szXSB8fCAicHgiOworCisJCQkJ CQkvLyBXZSBuZWVkIHRvIGNvbXB1dGUgc3RhcnRpbmcgdmFsdWUKKwkJCQkJCWlmICggdW5pdCAh PSAicHgiICkgeworCQkJCQkJCXNlbGYuc3R5bGVbIG5hbWUgXSA9IChlbmQgfHwgMSkgKyB1bml0 OworCQkJCQkJCXN0YXJ0ID0gKChlbmQgfHwgMSkgLyBlLmN1cih0cnVlKSkgKiBzdGFydDsKKwkJ CQkJCQlzZWxmLnN0eWxlWyBuYW1lIF0gPSBzdGFydCArIHVuaXQ7CisJCQkJCQl9CisKKwkJCQkJ CS8vIElmIGEgKz0vLT0gdG9rZW4gd2FzIHByb3ZpZGVkLCB3ZSdyZSBkb2luZyBhIHJlbGF0aXZl IGFuaW1hdGlvbgorCQkJCQkJaWYgKCBwYXJ0c1sxXSApCisJCQkJCQkJZW5kID0gKChwYXJ0c1sx XSA9PSAiLT0iID8gLTEgOiAxKSAqIGVuZCkgKyBzdGFydDsKKworCQkJCQkJZS5jdXN0b20oIHN0 YXJ0LCBlbmQsIHVuaXQgKTsKKwkJCQkJfSBlbHNlCisJCQkJCQllLmN1c3RvbSggc3RhcnQsIHZh bCwgIiIgKTsKKwkJCQl9CisJCQl9KTsKKworCQkJLy8gRm9yIEpTIHN0cmljdCBjb21wbGlhbmNl CisJCQlyZXR1cm4gdHJ1ZTsKKwkJfSk7CisJfSwKKworCXF1ZXVlOiBmdW5jdGlvbih0eXBlLCBm bil7CisJCWlmICggalF1ZXJ5LmlzRnVuY3Rpb24odHlwZSkgfHwgKCB0eXBlICYmIHR5cGUuY29u c3RydWN0b3IgPT0gQXJyYXkgKSkgeworCQkJZm4gPSB0eXBlOworCQkJdHlwZSA9ICJmeCI7CisJ CX0KKworCQlpZiAoICF0eXBlIHx8ICh0eXBlb2YgdHlwZSA9PSAic3RyaW5nIiAmJiAhZm4pICkK KwkJCXJldHVybiBxdWV1ZSggdGhpc1swXSwgdHlwZSApOworCisJCXJldHVybiB0aGlzLmVhY2go ZnVuY3Rpb24oKXsKKwkJCWlmICggZm4uY29uc3RydWN0b3IgPT0gQXJyYXkgKQorCQkJCXF1ZXVl KHRoaXMsIHR5cGUsIGZuKTsKKwkJCWVsc2UgeworCQkJCXF1ZXVlKHRoaXMsIHR5cGUpLnB1c2go IGZuICk7CisKKwkJCQlpZiAoIHF1ZXVlKHRoaXMsIHR5cGUpLmxlbmd0aCA9PSAxICkKKwkJCQkJ Zm4uY2FsbCh0aGlzKTsKKwkJCX0KKwkJfSk7CisJfSwKKworCXN0b3A6IGZ1bmN0aW9uKGNsZWFy UXVldWUsIGdvdG9FbmQpeworCQl2YXIgdGltZXJzID0galF1ZXJ5LnRpbWVyczsKKworCQlpZiAo Y2xlYXJRdWV1ZSkKKwkJCXRoaXMucXVldWUoW10pOworCisJCXRoaXMuZWFjaChmdW5jdGlvbigp eworCQkJLy8gZ28gaW4gcmV2ZXJzZSBvcmRlciBzbyBhbnl0aGluZyBhZGRlZCB0byB0aGUgcXVl dWUgZHVyaW5nIHRoZSBsb29wIGlzIGlnbm9yZWQKKwkJCWZvciAoIHZhciBpID0gdGltZXJzLmxl bmd0aCAtIDE7IGkgPj0gMDsgaS0tICkKKwkJCQlpZiAoIHRpbWVyc1tpXS5lbGVtID09IHRoaXMg KSB7CisJCQkJCWlmIChnb3RvRW5kKQorCQkJCQkJLy8gZm9yY2UgdGhlIG5leHQgc3RlcCB0byBi ZSB0aGUgbGFzdAorCQkJCQkJdGltZXJzW2ldKHRydWUpOworCQkJCQl0aW1lcnMuc3BsaWNlKGks IDEpOworCQkJCX0KKwkJfSk7CisKKwkJLy8gc3RhcnQgdGhlIG5leHQgaW4gdGhlIHF1ZXVlIGlm IHRoZSBsYXN0IHN0ZXAgd2Fzbid0IGZvcmNlZAorCQlpZiAoIWdvdG9FbmQpCisJCQl0aGlzLmRl cXVldWUoKTsKKworCQlyZXR1cm4gdGhpczsKKwl9CisKK30pOworCit2YXIgcXVldWUgPSBmdW5j dGlvbiggZWxlbSwgdHlwZSwgYXJyYXkgKSB7CisJaWYgKCBlbGVtICl7CisKKwkJdHlwZSA9IHR5 cGUgfHwgImZ4IjsKKworCQl2YXIgcSA9IGpRdWVyeS5kYXRhKCBlbGVtLCB0eXBlICsgInF1ZXVl IiApOworCisJCWlmICggIXEgfHwgYXJyYXkgKQorCQkJcSA9IGpRdWVyeS5kYXRhKCBlbGVtLCB0 eXBlICsgInF1ZXVlIiwgalF1ZXJ5Lm1ha2VBcnJheShhcnJheSkgKTsKKworCX0KKwlyZXR1cm4g cTsKK307CisKK2pRdWVyeS5mbi5kZXF1ZXVlID0gZnVuY3Rpb24odHlwZSl7CisJdHlwZSA9IHR5 cGUgfHwgImZ4IjsKKworCXJldHVybiB0aGlzLmVhY2goZnVuY3Rpb24oKXsKKwkJdmFyIHEgPSBx dWV1ZSh0aGlzLCB0eXBlKTsKKworCQlxLnNoaWZ0KCk7CisKKwkJaWYgKCBxLmxlbmd0aCApCisJ CQlxWzBdLmNhbGwoIHRoaXMgKTsKKwl9KTsKK307CisKK2pRdWVyeS5leHRlbmQoeworCisJc3Bl ZWQ6IGZ1bmN0aW9uKHNwZWVkLCBlYXNpbmcsIGZuKSB7CisJCXZhciBvcHQgPSBzcGVlZCAmJiBz cGVlZC5jb25zdHJ1Y3RvciA9PSBPYmplY3QgPyBzcGVlZCA6IHsKKwkJCWNvbXBsZXRlOiBmbiB8 fCAhZm4gJiYgZWFzaW5nIHx8CisJCQkJalF1ZXJ5LmlzRnVuY3Rpb24oIHNwZWVkICkgJiYgc3Bl ZWQsCisJCQlkdXJhdGlvbjogc3BlZWQsCisJCQllYXNpbmc6IGZuICYmIGVhc2luZyB8fCBlYXNp bmcgJiYgZWFzaW5nLmNvbnN0cnVjdG9yICE9IEZ1bmN0aW9uICYmIGVhc2luZworCQl9OworCisJ CW9wdC5kdXJhdGlvbiA9IChvcHQuZHVyYXRpb24gJiYgb3B0LmR1cmF0aW9uLmNvbnN0cnVjdG9y ID09IE51bWJlciA/CisJCQlvcHQuZHVyYXRpb24gOgorCQkJalF1ZXJ5LmZ4LnNwZWVkc1tvcHQu ZHVyYXRpb25dKSB8fCBqUXVlcnkuZnguc3BlZWRzLmRlZjsKKworCQkvLyBRdWV1ZWluZworCQlv cHQub2xkID0gb3B0LmNvbXBsZXRlOworCQlvcHQuY29tcGxldGUgPSBmdW5jdGlvbigpeworCQkJ aWYgKCBvcHQucXVldWUgIT09IGZhbHNlICkKKwkJCQlqUXVlcnkodGhpcykuZGVxdWV1ZSgpOwor CQkJaWYgKCBqUXVlcnkuaXNGdW5jdGlvbiggb3B0Lm9sZCApICkKKwkJCQlvcHQub2xkLmNhbGwo IHRoaXMgKTsKKwkJfTsKKworCQlyZXR1cm4gb3B0OworCX0sCisKKwllYXNpbmc6IHsKKwkJbGlu ZWFyOiBmdW5jdGlvbiggcCwgbiwgZmlyc3ROdW0sIGRpZmYgKSB7CisJCQlyZXR1cm4gZmlyc3RO dW0gKyBkaWZmICogcDsKKwkJfSwKKwkJc3dpbmc6IGZ1bmN0aW9uKCBwLCBuLCBmaXJzdE51bSwg ZGlmZiApIHsKKwkJCXJldHVybiAoKC1NYXRoLmNvcyhwKk1hdGguUEkpLzIpICsgMC41KSAqIGRp ZmYgKyBmaXJzdE51bTsKKwkJfQorCX0sCisKKwl0aW1lcnM6IFtdLAorCXRpbWVySWQ6IG51bGws CisKKwlmeDogZnVuY3Rpb24oIGVsZW0sIG9wdGlvbnMsIHByb3AgKXsKKwkJdGhpcy5vcHRpb25z ID0gb3B0aW9uczsKKwkJdGhpcy5lbGVtID0gZWxlbTsKKwkJdGhpcy5wcm9wID0gcHJvcDsKKwor CQlpZiAoICFvcHRpb25zLm9yaWcgKQorCQkJb3B0aW9ucy5vcmlnID0ge307CisJfQorCit9KTsK KworalF1ZXJ5LmZ4LnByb3RvdHlwZSA9IHsKKworCS8vIFNpbXBsZSBmdW5jdGlvbiBmb3Igc2V0 dGluZyBhIHN0eWxlIHZhbHVlCisJdXBkYXRlOiBmdW5jdGlvbigpeworCQlpZiAoIHRoaXMub3B0 aW9ucy5zdGVwICkKKwkJCXRoaXMub3B0aW9ucy5zdGVwLmNhbGwoIHRoaXMuZWxlbSwgdGhpcy5u b3csIHRoaXMgKTsKKworCQkoalF1ZXJ5LmZ4LnN0ZXBbdGhpcy5wcm9wXSB8fCBqUXVlcnkuZngu c3RlcC5fZGVmYXVsdCkoIHRoaXMgKTsKKworCQkvLyBTZXQgZGlzcGxheSBwcm9wZXJ0eSB0byBi bG9jayBmb3IgaGVpZ2h0L3dpZHRoIGFuaW1hdGlvbnMKKwkJaWYgKCB0aGlzLnByb3AgPT0gImhl aWdodCIgfHwgdGhpcy5wcm9wID09ICJ3aWR0aCIgKQorCQkJdGhpcy5lbGVtLnN0eWxlLmRpc3Bs YXkgPSAiYmxvY2siOworCX0sCisKKwkvLyBHZXQgdGhlIGN1cnJlbnQgc2l6ZQorCWN1cjogZnVu Y3Rpb24oZm9yY2UpeworCQlpZiAoIHRoaXMuZWxlbVt0aGlzLnByb3BdICE9IG51bGwgJiYgdGhp cy5lbGVtLnN0eWxlW3RoaXMucHJvcF0gPT0gbnVsbCApCisJCQlyZXR1cm4gdGhpcy5lbGVtWyB0 aGlzLnByb3AgXTsKKworCQl2YXIgciA9IHBhcnNlRmxvYXQoalF1ZXJ5LmNzcyh0aGlzLmVsZW0s IHRoaXMucHJvcCwgZm9yY2UpKTsKKwkJcmV0dXJuIHIgJiYgciA+IC0xMDAwMCA/IHIgOiBwYXJz ZUZsb2F0KGpRdWVyeS5jdXJDU1ModGhpcy5lbGVtLCB0aGlzLnByb3ApKSB8fCAwOworCX0sCisK KwkvLyBTdGFydCBhbiBhbmltYXRpb24gZnJvbSBvbmUgbnVtYmVyIHRvIGFub3RoZXIKKwljdXN0 b206IGZ1bmN0aW9uKGZyb20sIHRvLCB1bml0KXsKKwkJdGhpcy5zdGFydFRpbWUgPSBub3coKTsK KwkJdGhpcy5zdGFydCA9IGZyb207CisJCXRoaXMuZW5kID0gdG87CisJCXRoaXMudW5pdCA9IHVu aXQgfHwgdGhpcy51bml0IHx8ICJweCI7CisJCXRoaXMubm93ID0gdGhpcy5zdGFydDsKKwkJdGhp cy5wb3MgPSB0aGlzLnN0YXRlID0gMDsKKwkJdGhpcy51cGRhdGUoKTsKKworCQl2YXIgc2VsZiA9 IHRoaXM7CisJCWZ1bmN0aW9uIHQoZ290b0VuZCl7CisJCQlyZXR1cm4gc2VsZi5zdGVwKGdvdG9F bmQpOworCQl9CisKKwkJdC5lbGVtID0gdGhpcy5lbGVtOworCisJCWpRdWVyeS50aW1lcnMucHVz aCh0KTsKKworCQlpZiAoIGpRdWVyeS50aW1lcklkID09IG51bGwgKSB7CisJCQlqUXVlcnkudGlt ZXJJZCA9IHNldEludGVydmFsKGZ1bmN0aW9uKCl7CisJCQkJdmFyIHRpbWVycyA9IGpRdWVyeS50 aW1lcnM7CisKKwkJCQlmb3IgKCB2YXIgaSA9IDA7IGkgPCB0aW1lcnMubGVuZ3RoOyBpKysgKQor CQkJCQlpZiAoICF0aW1lcnNbaV0oKSApCisJCQkJCQl0aW1lcnMuc3BsaWNlKGktLSwgMSk7CisK KwkJCQlpZiAoICF0aW1lcnMubGVuZ3RoICkgeworCQkJCQljbGVhckludGVydmFsKCBqUXVlcnku dGltZXJJZCApOworCQkJCQlqUXVlcnkudGltZXJJZCA9IG51bGw7CisJCQkJfQorCQkJfSwgMTMp OworCQl9CisJfSwKKworCS8vIFNpbXBsZSAnc2hvdycgZnVuY3Rpb24KKwlzaG93OiBmdW5jdGlv bigpeworCQkvLyBSZW1lbWJlciB3aGVyZSB3ZSBzdGFydGVkLCBzbyB0aGF0IHdlIGNhbiBnbyBi YWNrIHRvIGl0IGxhdGVyCisJCXRoaXMub3B0aW9ucy5vcmlnW3RoaXMucHJvcF0gPSBqUXVlcnku YXR0ciggdGhpcy5lbGVtLnN0eWxlLCB0aGlzLnByb3AgKTsKKwkJdGhpcy5vcHRpb25zLnNob3cg PSB0cnVlOworCisJCS8vIEJlZ2luIHRoZSBhbmltYXRpb24KKwkJdGhpcy5jdXN0b20oMCwgdGhp cy5jdXIoKSk7CisKKwkJLy8gTWFrZSBzdXJlIHRoYXQgd2Ugc3RhcnQgYXQgYSBzbWFsbCB3aWR0 aC9oZWlnaHQgdG8gYXZvaWQgYW55CisJCS8vIGZsYXNoIG9mIGNvbnRlbnQKKwkJaWYgKCB0aGlz LnByb3AgPT0gIndpZHRoIiB8fCB0aGlzLnByb3AgPT0gImhlaWdodCIgKQorCQkJdGhpcy5lbGVt LnN0eWxlW3RoaXMucHJvcF0gPSAiMXB4IjsKKworCQkvLyBTdGFydCBieSBzaG93aW5nIHRoZSBl bGVtZW50CisJCWpRdWVyeSh0aGlzLmVsZW0pLnNob3coKTsKKwl9LAorCisJLy8gU2ltcGxlICdo aWRlJyBmdW5jdGlvbgorCWhpZGU6IGZ1bmN0aW9uKCl7CisJCS8vIFJlbWVtYmVyIHdoZXJlIHdl IHN0YXJ0ZWQsIHNvIHRoYXQgd2UgY2FuIGdvIGJhY2sgdG8gaXQgbGF0ZXIKKwkJdGhpcy5vcHRp b25zLm9yaWdbdGhpcy5wcm9wXSA9IGpRdWVyeS5hdHRyKCB0aGlzLmVsZW0uc3R5bGUsIHRoaXMu cHJvcCApOworCQl0aGlzLm9wdGlvbnMuaGlkZSA9IHRydWU7CisKKwkJLy8gQmVnaW4gdGhlIGFu aW1hdGlvbgorCQl0aGlzLmN1c3RvbSh0aGlzLmN1cigpLCAwKTsKKwl9LAorCisJLy8gRWFjaCBz dGVwIG9mIGFuIGFuaW1hdGlvbgorCXN0ZXA6IGZ1bmN0aW9uKGdvdG9FbmQpeworCQl2YXIgdCA9 IG5vdygpOworCisJCWlmICggZ290b0VuZCB8fCB0ID4gdGhpcy5vcHRpb25zLmR1cmF0aW9uICsg dGhpcy5zdGFydFRpbWUgKSB7CisJCQl0aGlzLm5vdyA9IHRoaXMuZW5kOworCQkJdGhpcy5wb3Mg PSB0aGlzLnN0YXRlID0gMTsKKwkJCXRoaXMudXBkYXRlKCk7CisKKwkJCXRoaXMub3B0aW9ucy5j dXJBbmltWyB0aGlzLnByb3AgXSA9IHRydWU7CisKKwkJCXZhciBkb25lID0gdHJ1ZTsKKwkJCWZv ciAoIHZhciBpIGluIHRoaXMub3B0aW9ucy5jdXJBbmltICkKKwkJCQlpZiAoIHRoaXMub3B0aW9u cy5jdXJBbmltW2ldICE9PSB0cnVlICkKKwkJCQkJZG9uZSA9IGZhbHNlOworCisJCQlpZiAoIGRv bmUgKSB7CisJCQkJaWYgKCB0aGlzLm9wdGlvbnMuZGlzcGxheSAhPSBudWxsICkgeworCQkJCQkv LyBSZXNldCB0aGUgb3ZlcmZsb3cKKwkJCQkJdGhpcy5lbGVtLnN0eWxlLm92ZXJmbG93ID0gdGhp cy5vcHRpb25zLm92ZXJmbG93OworCisJCQkJCS8vIFJlc2V0IHRoZSBkaXNwbGF5CisJCQkJCXRo aXMuZWxlbS5zdHlsZS5kaXNwbGF5ID0gdGhpcy5vcHRpb25zLmRpc3BsYXk7CisJCQkJCWlmICgg alF1ZXJ5LmNzcyh0aGlzLmVsZW0sICJkaXNwbGF5IikgPT0gIm5vbmUiICkKKwkJCQkJCXRoaXMu ZWxlbS5zdHlsZS5kaXNwbGF5ID0gImJsb2NrIjsKKwkJCQl9CisKKwkJCQkvLyBIaWRlIHRoZSBl bGVtZW50IGlmIHRoZSAiaGlkZSIgb3BlcmF0aW9uIHdhcyBkb25lCisJCQkJaWYgKCB0aGlzLm9w dGlvbnMuaGlkZSApCisJCQkJCXRoaXMuZWxlbS5zdHlsZS5kaXNwbGF5ID0gIm5vbmUiOworCisJ CQkJLy8gUmVzZXQgdGhlIHByb3BlcnRpZXMsIGlmIHRoZSBpdGVtIGhhcyBiZWVuIGhpZGRlbiBv ciBzaG93bgorCQkJCWlmICggdGhpcy5vcHRpb25zLmhpZGUgfHwgdGhpcy5vcHRpb25zLnNob3cg KQorCQkJCQlmb3IgKCB2YXIgcCBpbiB0aGlzLm9wdGlvbnMuY3VyQW5pbSApCisJCQkJCQlqUXVl cnkuYXR0cih0aGlzLmVsZW0uc3R5bGUsIHAsIHRoaXMub3B0aW9ucy5vcmlnW3BdKTsKKwkJCX0K KworCQkJaWYgKCBkb25lICkKKwkJCQkvLyBFeGVjdXRlIHRoZSBjb21wbGV0ZSBmdW5jdGlvbgor CQkJCXRoaXMub3B0aW9ucy5jb21wbGV0ZS5jYWxsKCB0aGlzLmVsZW0gKTsKKworCQkJcmV0dXJu IGZhbHNlOworCQl9IGVsc2UgeworCQkJdmFyIG4gPSB0IC0gdGhpcy5zdGFydFRpbWU7CisJCQl0 aGlzLnN0YXRlID0gbiAvIHRoaXMub3B0aW9ucy5kdXJhdGlvbjsKKworCQkJLy8gUGVyZm9ybSB0 aGUgZWFzaW5nIGZ1bmN0aW9uLCBkZWZhdWx0cyB0byBzd2luZworCQkJdGhpcy5wb3MgPSBqUXVl cnkuZWFzaW5nW3RoaXMub3B0aW9ucy5lYXNpbmcgfHwgKGpRdWVyeS5lYXNpbmcuc3dpbmcgPyAi c3dpbmciIDogImxpbmVhciIpXSh0aGlzLnN0YXRlLCBuLCAwLCAxLCB0aGlzLm9wdGlvbnMuZHVy YXRpb24pOworCQkJdGhpcy5ub3cgPSB0aGlzLnN0YXJ0ICsgKCh0aGlzLmVuZCAtIHRoaXMuc3Rh cnQpICogdGhpcy5wb3MpOworCisJCQkvLyBQZXJmb3JtIHRoZSBuZXh0IHN0ZXAgb2YgdGhlIGFu aW1hdGlvbgorCQkJdGhpcy51cGRhdGUoKTsKKwkJfQorCisJCXJldHVybiB0cnVlOworCX0KKwor fTsKKworalF1ZXJ5LmV4dGVuZCggalF1ZXJ5LmZ4LCB7CisJc3BlZWRzOnsKKwkJc2xvdzogNjAw LAorIAkJZmFzdDogMjAwLAorIAkJLy8gRGVmYXVsdCBzcGVlZAorIAkJZGVmOiA0MDAKKwl9LAor CXN0ZXA6IHsKKwkJc2Nyb2xsTGVmdDogZnVuY3Rpb24oZngpeworCQkJZnguZWxlbS5zY3JvbGxM ZWZ0ID0gZngubm93OworCQl9LAorCisJCXNjcm9sbFRvcDogZnVuY3Rpb24oZngpeworCQkJZngu ZWxlbS5zY3JvbGxUb3AgPSBmeC5ub3c7CisJCX0sCisKKwkJb3BhY2l0eTogZnVuY3Rpb24oZngp eworCQkJalF1ZXJ5LmF0dHIoZnguZWxlbS5zdHlsZSwgIm9wYWNpdHkiLCBmeC5ub3cpOworCQl9 LAorCisJCV9kZWZhdWx0OiBmdW5jdGlvbihmeCl7CisJCQlmeC5lbGVtLnN0eWxlWyBmeC5wcm9w IF0gPSBmeC5ub3cgKyBmeC51bml0OworCQl9CisJfQorfSk7CisvLyBUaGUgT2Zmc2V0IE1ldGhv ZAorLy8gT3JpZ2luYWxseSBCeSBCcmFuZG9uIEFhcm9uLCBwYXJ0IG9mIHRoZSBEaW1lbnNpb24g UGx1Z2luCisvLyBodHRwOi8vanF1ZXJ5LmNvbS9wbHVnaW5zL3Byb2plY3QvZGltZW5zaW9ucwor alF1ZXJ5LmZuLm9mZnNldCA9IGZ1bmN0aW9uKCkgeworCXZhciBsZWZ0ID0gMCwgdG9wID0gMCwg ZWxlbSA9IHRoaXNbMF0sIHJlc3VsdHM7CisKKwlpZiAoIGVsZW0gKSB3aXRoICggalF1ZXJ5LmJy b3dzZXIgKSB7CisJCXZhciBwYXJlbnQgICAgICAgPSBlbGVtLnBhcmVudE5vZGUsCisJCSAgICBv ZmZzZXRDaGlsZCAgPSBlbGVtLAorCQkgICAgb2Zmc2V0UGFyZW50ID0gZWxlbS5vZmZzZXRQYXJl bnQsCisJCSAgICBkb2MgICAgICAgICAgPSBlbGVtLm93bmVyRG9jdW1lbnQsCisJCSAgICBzYWZh cmkyICAgICAgPSBzYWZhcmkgJiYgcGFyc2VJbnQodmVyc2lvbikgPCA1MjIgJiYgIS9hZG9iZWFp ci9pLnRlc3QodXNlckFnZW50KSwKKwkJICAgIGNzcyAgICAgICAgICA9IGpRdWVyeS5jdXJDU1Ms CisJCSAgICBmaXhlZCAgICAgICAgPSBjc3MoZWxlbSwgInBvc2l0aW9uIikgPT0gImZpeGVkIjsK KworCQkvLyBVc2UgZ2V0Qm91bmRpbmdDbGllbnRSZWN0IGlmIGF2YWlsYWJsZQorCQlpZiAoIGVs ZW0uZ2V0Qm91bmRpbmdDbGllbnRSZWN0ICkgeworCQkJdmFyIGJveCA9IGVsZW0uZ2V0Qm91bmRp bmdDbGllbnRSZWN0KCk7CisKKwkJCS8vIEFkZCB0aGUgZG9jdW1lbnQgc2Nyb2xsIG9mZnNldHMK KwkJCWFkZChib3gubGVmdCArIE1hdGgubWF4KGRvYy5kb2N1bWVudEVsZW1lbnQuc2Nyb2xsTGVm dCwgZG9jLmJvZHkuc2Nyb2xsTGVmdCksCisJCQkJYm94LnRvcCAgKyBNYXRoLm1heChkb2MuZG9j dW1lbnRFbGVtZW50LnNjcm9sbFRvcCwgIGRvYy5ib2R5LnNjcm9sbFRvcCkpOworCisJCQkvLyBJ RSBhZGRzIHRoZSBIVE1MIGVsZW1lbnQncyBib3JkZXIsIGJ5IGRlZmF1bHQgaXQgaXMgbWVkaXVt IHdoaWNoIGlzIDJweAorCQkJLy8gSUUgNiBhbmQgNyBxdWlya3MgbW9kZSB0aGUgYm9yZGVyIHdp ZHRoIGlzIG92ZXJ3cml0YWJsZSBieSB0aGUgZm9sbG93aW5nIGNzcyBodG1sIHsgYm9yZGVyOiAw OyB9CisJCQkvLyBJRSA3IHN0YW5kYXJkcyBtb2RlLCB0aGUgYm9yZGVyIGlzIGFsd2F5cyAycHgK KwkJCS8vIFRoaXMgYm9yZGVyL29mZnNldCBpcyB0eXBpY2FsbHkgcmVwcmVzZW50ZWQgYnkgdGhl IGNsaWVudExlZnQgYW5kIGNsaWVudFRvcCBwcm9wZXJ0aWVzCisJCQkvLyBIb3dldmVyLCBpbiBJ RTYgYW5kIDcgcXVpcmtzIG1vZGUgdGhlIGNsaWVudExlZnQgYW5kIGNsaWVudFRvcCBwcm9wZXJ0 aWVzIGFyZSBub3QgdXBkYXRlZCB3aGVuIG92ZXJ3cml0aW5nIGl0IHZpYSBDU1MKKwkJCS8vIFRo ZXJlZm9yZSB0aGlzIG1ldGhvZCB3aWxsIGJlIG9mZiBieSAycHggaW4gSUUgd2hpbGUgaW4gcXVp cmtzbW9kZQorCQkJYWRkKCAtZG9jLmRvY3VtZW50RWxlbWVudC5jbGllbnRMZWZ0LCAtZG9jLmRv Y3VtZW50RWxlbWVudC5jbGllbnRUb3AgKTsKKworCQkvLyBPdGhlcndpc2UgbG9vcCB0aHJvdWdo IHRoZSBvZmZzZXRQYXJlbnRzIGFuZCBwYXJlbnROb2RlcworCQl9IGVsc2UgeworCisJCQkvLyBJ bml0aWFsIGVsZW1lbnQgb2Zmc2V0cworCQkJYWRkKCBlbGVtLm9mZnNldExlZnQsIGVsZW0ub2Zm c2V0VG9wICk7CisKKwkJCS8vIEdldCBwYXJlbnQgb2Zmc2V0cworCQkJd2hpbGUgKCBvZmZzZXRQ YXJlbnQgKSB7CisJCQkJLy8gQWRkIG9mZnNldFBhcmVudCBvZmZzZXRzCisJCQkJYWRkKCBvZmZz ZXRQYXJlbnQub2Zmc2V0TGVmdCwgb2Zmc2V0UGFyZW50Lm9mZnNldFRvcCApOworCisJCQkJLy8g TW96aWxsYSBhbmQgU2FmYXJpID4gMiBkb2VzIG5vdCBpbmNsdWRlIHRoZSBib3JkZXIgb24gb2Zm c2V0IHBhcmVudHMKKwkJCQkvLyBIb3dldmVyIE1vemlsbGEgYWRkcyB0aGUgYm9yZGVyIGZvciB0 YWJsZSBvciB0YWJsZSBjZWxscworCQkJCWlmICggbW96aWxsYSAmJiAhL150KGFibGV8ZHxoKSQv aS50ZXN0KG9mZnNldFBhcmVudC50YWdOYW1lKSB8fCBzYWZhcmkgJiYgIXNhZmFyaTIgKQorCQkJ CQlib3JkZXIoIG9mZnNldFBhcmVudCApOworCisJCQkJLy8gQWRkIHRoZSBkb2N1bWVudCBzY3Jv bGwgb2Zmc2V0cyBpZiBwb3NpdGlvbiBpcyBmaXhlZCBvbiBhbnkgb2Zmc2V0UGFyZW50CisJCQkJ aWYgKCAhZml4ZWQgJiYgY3NzKG9mZnNldFBhcmVudCwgInBvc2l0aW9uIikgPT0gImZpeGVkIiAp CisJCQkJCWZpeGVkID0gdHJ1ZTsKKworCQkJCS8vIFNldCBvZmZzZXRDaGlsZCB0byBwcmV2aW91 cyBvZmZzZXRQYXJlbnQgdW5sZXNzIGl0IGlzIHRoZSBib2R5IGVsZW1lbnQKKwkJCQlvZmZzZXRD aGlsZCAgPSAvXmJvZHkkL2kudGVzdChvZmZzZXRQYXJlbnQudGFnTmFtZSkgPyBvZmZzZXRDaGls ZCA6IG9mZnNldFBhcmVudDsKKwkJCQkvLyBHZXQgbmV4dCBvZmZzZXRQYXJlbnQKKwkJCQlvZmZz ZXRQYXJlbnQgPSBvZmZzZXRQYXJlbnQub2Zmc2V0UGFyZW50OworCQkJfQorCisJCQkvLyBHZXQg cGFyZW50IHNjcm9sbCBvZmZzZXRzCisJCQl3aGlsZSAoIHBhcmVudCAmJiBwYXJlbnQudGFnTmFt ZSAmJiAhL15ib2R5fGh0bWwkL2kudGVzdChwYXJlbnQudGFnTmFtZSkgKSB7CisJCQkJLy8gUmVt b3ZlIHBhcmVudCBzY3JvbGwgVU5MRVNTIHRoYXQgcGFyZW50IGlzIGlubGluZSBvciBhIHRhYmxl IHRvIHdvcmsgYXJvdW5kIE9wZXJhIGlubGluZS90YWJsZSBzY3JvbGxMZWZ0L1RvcCBidWcKKwkJ CQlpZiAoICEvXmlubGluZXx0YWJsZS4qJC9pLnRlc3QoY3NzKHBhcmVudCwgImRpc3BsYXkiKSkg KQorCQkJCQkvLyBTdWJ0cmFjdCBwYXJlbnQgc2Nyb2xsIG9mZnNldHMKKwkJCQkJYWRkKCAtcGFy ZW50LnNjcm9sbExlZnQsIC1wYXJlbnQuc2Nyb2xsVG9wICk7CisKKwkJCQkvLyBNb3ppbGxhIGRv ZXMgbm90IGFkZCB0aGUgYm9yZGVyIGZvciBhIHBhcmVudCB0aGF0IGhhcyBvdmVyZmxvdyAhPSB2 aXNpYmxlCisJCQkJaWYgKCBtb3ppbGxhICYmIGNzcyhwYXJlbnQsICJvdmVyZmxvdyIpICE9ICJ2 aXNpYmxlIiApCisJCQkJCWJvcmRlciggcGFyZW50ICk7CisKKwkJCQkvLyBHZXQgbmV4dCBwYXJl bnQKKwkJCQlwYXJlbnQgPSBwYXJlbnQucGFyZW50Tm9kZTsKKwkJCX0KKworCQkJLy8gU2FmYXJp IDw9IDIgZG91YmxlcyBib2R5IG9mZnNldHMgd2l0aCBhIGZpeGVkIHBvc2l0aW9uIGVsZW1lbnQv b2Zmc2V0UGFyZW50IG9yIGFic29sdXRlbHkgcG9zaXRpb25lZCBvZmZzZXRDaGlsZAorCQkJLy8g TW96aWxsYSBkb3VibGVzIGJvZHkgb2Zmc2V0cyB3aXRoIGEgbm9uLWFic29sdXRlbHkgcG9zaXRp b25lZCBvZmZzZXRDaGlsZAorCQkJaWYgKCAoc2FmYXJpMiAmJiAoZml4ZWQgfHwgY3NzKG9mZnNl dENoaWxkLCAicG9zaXRpb24iKSA9PSAiYWJzb2x1dGUiKSkgfHwKKwkJCQkobW96aWxsYSAmJiBj c3Mob2Zmc2V0Q2hpbGQsICJwb3NpdGlvbiIpICE9ICJhYnNvbHV0ZSIpICkKKwkJCQkJYWRkKCAt ZG9jLmJvZHkub2Zmc2V0TGVmdCwgLWRvYy5ib2R5Lm9mZnNldFRvcCApOworCisJCQkvLyBBZGQg dGhlIGRvY3VtZW50IHNjcm9sbCBvZmZzZXRzIGlmIHBvc2l0aW9uIGlzIGZpeGVkCisJCQlpZiAo IGZpeGVkICkKKwkJCQlhZGQoTWF0aC5tYXgoZG9jLmRvY3VtZW50RWxlbWVudC5zY3JvbGxMZWZ0 LCBkb2MuYm9keS5zY3JvbGxMZWZ0KSwKKwkJCQkJTWF0aC5tYXgoZG9jLmRvY3VtZW50RWxlbWVu dC5zY3JvbGxUb3AsICBkb2MuYm9keS5zY3JvbGxUb3ApKTsKKwkJfQorCisJCS8vIFJldHVybiBh biBvYmplY3Qgd2l0aCB0b3AgYW5kIGxlZnQgcHJvcGVydGllcworCQlyZXN1bHRzID0geyB0b3A6 IHRvcCwgbGVmdDogbGVmdCB9OworCX0KKworCWZ1bmN0aW9uIGJvcmRlcihlbGVtKSB7CisJCWFk ZCggalF1ZXJ5LmN1ckNTUyhlbGVtLCAiYm9yZGVyTGVmdFdpZHRoIiwgdHJ1ZSksIGpRdWVyeS5j dXJDU1MoZWxlbSwgImJvcmRlclRvcFdpZHRoIiwgdHJ1ZSkgKTsKKwl9CisKKwlmdW5jdGlvbiBh ZGQobCwgdCkgeworCQlsZWZ0ICs9IHBhcnNlSW50KGwsIDEwKSB8fCAwOworCQl0b3AgKz0gcGFy c2VJbnQodCwgMTApIHx8IDA7CisJfQorCisJcmV0dXJuIHJlc3VsdHM7Cit9OworCisKK2pRdWVy eS5mbi5leHRlbmQoeworCXBvc2l0aW9uOiBmdW5jdGlvbigpIHsKKwkJdmFyIGxlZnQgPSAwLCB0 b3AgPSAwLCByZXN1bHRzOworCisJCWlmICggdGhpc1swXSApIHsKKwkJCS8vIEdldCAqcmVhbCog b2Zmc2V0UGFyZW50CisJCQl2YXIgb2Zmc2V0UGFyZW50ID0gdGhpcy5vZmZzZXRQYXJlbnQoKSwK KworCQkJLy8gR2V0IGNvcnJlY3Qgb2Zmc2V0cworCQkJb2Zmc2V0ICAgICAgID0gdGhpcy5vZmZz ZXQoKSwKKwkJCXBhcmVudE9mZnNldCA9IC9eYm9keXxodG1sJC9pLnRlc3Qob2Zmc2V0UGFyZW50 WzBdLnRhZ05hbWUpID8geyB0b3A6IDAsIGxlZnQ6IDAgfSA6IG9mZnNldFBhcmVudC5vZmZzZXQo KTsKKworCQkJLy8gU3VidHJhY3QgZWxlbWVudCBtYXJnaW5zCisJCQkvLyBub3RlOiB3aGVuIGFu IGVsZW1lbnQgaGFzIG1hcmdpbjogYXV0byB0aGUgb2Zmc2V0TGVmdCBhbmQgbWFyZ2luTGVmdCAK KwkJCS8vIGFyZSB0aGUgc2FtZSBpbiBTYWZhcmkgY2F1c2luZyBvZmZzZXQubGVmdCB0byBpbmNv cnJlY3RseSBiZSAwCisJCQlvZmZzZXQudG9wICAtPSBudW0oIHRoaXMsICdtYXJnaW5Ub3AnICk7 CisJCQlvZmZzZXQubGVmdCAtPSBudW0oIHRoaXMsICdtYXJnaW5MZWZ0JyApOworCisJCQkvLyBB ZGQgb2Zmc2V0UGFyZW50IGJvcmRlcnMKKwkJCXBhcmVudE9mZnNldC50b3AgICs9IG51bSggb2Zm c2V0UGFyZW50LCAnYm9yZGVyVG9wV2lkdGgnICk7CisJCQlwYXJlbnRPZmZzZXQubGVmdCArPSBu dW0oIG9mZnNldFBhcmVudCwgJ2JvcmRlckxlZnRXaWR0aCcgKTsKKworCQkJLy8gU3VidHJhY3Qg dGhlIHR3byBvZmZzZXRzCisJCQlyZXN1bHRzID0geworCQkJCXRvcDogIG9mZnNldC50b3AgIC0g cGFyZW50T2Zmc2V0LnRvcCwKKwkJCQlsZWZ0OiBvZmZzZXQubGVmdCAtIHBhcmVudE9mZnNldC5s ZWZ0CisJCQl9OworCQl9CisKKwkJcmV0dXJuIHJlc3VsdHM7CisJfSwKKworCW9mZnNldFBhcmVu dDogZnVuY3Rpb24oKSB7CisJCXZhciBvZmZzZXRQYXJlbnQgPSB0aGlzWzBdLm9mZnNldFBhcmVu dDsKKwkJd2hpbGUgKCBvZmZzZXRQYXJlbnQgJiYgKCEvXmJvZHl8aHRtbCQvaS50ZXN0KG9mZnNl dFBhcmVudC50YWdOYW1lKSAmJiBqUXVlcnkuY3NzKG9mZnNldFBhcmVudCwgJ3Bvc2l0aW9uJykg PT0gJ3N0YXRpYycpICkKKwkJCW9mZnNldFBhcmVudCA9IG9mZnNldFBhcmVudC5vZmZzZXRQYXJl bnQ7CisJCXJldHVybiBqUXVlcnkob2Zmc2V0UGFyZW50KTsKKwl9Cit9KTsKKworCisvLyBDcmVh dGUgc2Nyb2xsTGVmdCBhbmQgc2Nyb2xsVG9wIG1ldGhvZHMKK2pRdWVyeS5lYWNoKCBbJ0xlZnQn LCAnVG9wJ10sIGZ1bmN0aW9uKGksIG5hbWUpIHsKKwl2YXIgbWV0aG9kID0gJ3Njcm9sbCcgKyBu YW1lOworCQorCWpRdWVyeS5mblsgbWV0aG9kIF0gPSBmdW5jdGlvbih2YWwpIHsKKwkJaWYgKCF0 aGlzWzBdKSByZXR1cm47CisKKwkJcmV0dXJuIHZhbCAhPSB1bmRlZmluZWQgPworCisJCQkvLyBT ZXQgdGhlIHNjcm9sbCBvZmZzZXQKKwkJCXRoaXMuZWFjaChmdW5jdGlvbigpIHsKKwkJCQl0aGlz ID09IHdpbmRvdyB8fCB0aGlzID09IGRvY3VtZW50ID8KKwkJCQkJd2luZG93LnNjcm9sbFRvKAor CQkJCQkJIWkgPyB2YWwgOiBqUXVlcnkod2luZG93KS5zY3JvbGxMZWZ0KCksCisJCQkJCQkgaSA/ IHZhbCA6IGpRdWVyeSh3aW5kb3cpLnNjcm9sbFRvcCgpCisJCQkJCSkgOgorCQkJCQl0aGlzWyBt ZXRob2QgXSA9IHZhbDsKKwkJCX0pIDoKKworCQkJLy8gUmV0dXJuIHRoZSBzY3JvbGwgb2Zmc2V0 CisJCQl0aGlzWzBdID09IHdpbmRvdyB8fCB0aGlzWzBdID09IGRvY3VtZW50ID8KKwkJCQlzZWxm WyBpID8gJ3BhZ2VZT2Zmc2V0JyA6ICdwYWdlWE9mZnNldCcgXSB8fAorCQkJCQlqUXVlcnkuYm94 TW9kZWwgJiYgZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50WyBtZXRob2QgXSB8fAorCQkJCQlkb2N1 bWVudC5ib2R5WyBtZXRob2QgXSA6CisJCQkJdGhpc1swXVsgbWV0aG9kIF07CisJfTsKK30pOwor Ly8gQ3JlYXRlIGlubmVySGVpZ2h0LCBpbm5lcldpZHRoLCBvdXRlckhlaWdodCBhbmQgb3V0ZXJX aWR0aCBtZXRob2RzCitqUXVlcnkuZWFjaChbICJIZWlnaHQiLCAiV2lkdGgiIF0sIGZ1bmN0aW9u KGksIG5hbWUpeworCisJdmFyIHRsID0gaSA/ICJMZWZ0IiAgOiAiVG9wIiwgIC8vIHRvcCBvciBs ZWZ0CisJCWJyID0gaSA/ICJSaWdodCIgOiAiQm90dG9tIjsgLy8gYm90dG9tIG9yIHJpZ2h0CisK KwkvLyBpbm5lckhlaWdodCBhbmQgaW5uZXJXaWR0aAorCWpRdWVyeS5mblsiaW5uZXIiICsgbmFt ZV0gPSBmdW5jdGlvbigpeworCQlyZXR1cm4gdGhpc1sgbmFtZS50b0xvd2VyQ2FzZSgpIF0oKSAr CisJCQludW0odGhpcywgInBhZGRpbmciICsgdGwpICsKKwkJCW51bSh0aGlzLCAicGFkZGluZyIg KyBicik7CisJfTsKKworCS8vIG91dGVySGVpZ2h0IGFuZCBvdXRlcldpZHRoCisJalF1ZXJ5LmZu WyJvdXRlciIgKyBuYW1lXSA9IGZ1bmN0aW9uKG1hcmdpbikgeworCQlyZXR1cm4gdGhpc1siaW5u ZXIiICsgbmFtZV0oKSArCisJCQludW0odGhpcywgImJvcmRlciIgKyB0bCArICJXaWR0aCIpICsK KwkJCW51bSh0aGlzLCAiYm9yZGVyIiArIGJyICsgIldpZHRoIikgKworCQkJKG1hcmdpbiA/CisJ CQkJbnVtKHRoaXMsICJtYXJnaW4iICsgdGwpICsgbnVtKHRoaXMsICJtYXJnaW4iICsgYnIpIDog MCk7CisJfTsKKworfSk7fSkoKTsKZGlmZiAtLWdpdCBhL3d1aS9zcmMvcHVibGljL2phdmFzY3Jp cHRzL2pxdWVyeS0xLjIuNi5taW4uanMgYi93dWkvc3JjL3B1YmxpYy9qYXZhc2NyaXB0cy9qcXVl cnktMS4yLjYubWluLmpzCm5ldyBmaWxlIG1vZGUgMTAwNjQ0CmluZGV4IDAwMDAwMDAuLjgyYjk4 ZTEKLS0tIC9kZXYvbnVsbAorKysgYi93dWkvc3JjL3B1YmxpYy9qYXZhc2NyaXB0cy9qcXVlcnkt MS4yLjYubWluLmpzCkBAIC0wLDAgKzEsMzIgQEAKKy8qCisgKiBqUXVlcnkgMS4yLjYgLSBOZXcg V2F2ZSBKYXZhc2NyaXB0CisgKgorICogQ29weXJpZ2h0IChjKSAyMDA4IEpvaG4gUmVzaWcgKGpx dWVyeS5jb20pCisgKiBEdWFsIGxpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgKE1JVC1MSUNFTlNFLnR4 dCkKKyAqIGFuZCBHUEwgKEdQTC1MSUNFTlNFLnR4dCkgbGljZW5zZXMuCisgKgorICogJERhdGU6 IDIwMDgtMDUtMjQgMTQ6MjI6MTcgLTA0MDAgKFNhdCwgMjQgTWF5IDIwMDgpICQKKyAqICRSZXY6 IDU2ODUgJAorICovCisoZnVuY3Rpb24oKXt2YXIgX2pRdWVyeT13aW5kb3cualF1ZXJ5LF8kPXdp bmRvdy4kO3ZhciBqUXVlcnk9d2luZG93LmpRdWVyeT13aW5kb3cuJD1mdW5jdGlvbihzZWxlY3Rv cixjb250ZXh0KXtyZXR1cm4gbmV3IGpRdWVyeS5mbi5pbml0KHNlbGVjdG9yLGNvbnRleHQpO307 dmFyIHF1aWNrRXhwcj0vXltePF0qKDwoLnxccykrPilbXj5dKiR8XiMoXHcrKSQvLGlzU2ltcGxl PS9eLlteOiNcW1wuXSokLyx1bmRlZmluZWQ7alF1ZXJ5LmZuPWpRdWVyeS5wcm90b3R5cGU9e2lu aXQ6ZnVuY3Rpb24oc2VsZWN0b3IsY29udGV4dCl7c2VsZWN0b3I9c2VsZWN0b3J8fGRvY3VtZW50 O2lmKHNlbGVjdG9yLm5vZGVUeXBlKXt0aGlzWzBdPXNlbGVjdG9yO3RoaXMubGVuZ3RoPTE7cmV0 dXJuIHRoaXM7fWlmKHR5cGVvZiBzZWxlY3Rvcj09InN0cmluZyIpe3ZhciBtYXRjaD1xdWlja0V4 cHIuZXhlYyhzZWxlY3Rvcik7aWYobWF0Y2gmJihtYXRjaFsxXXx8IWNvbnRleHQpKXtpZihtYXRj aFsxXSlzZWxlY3Rvcj1qUXVlcnkuY2xlYW4oW21hdGNoWzFdXSxjb250ZXh0KTtlbHNle3ZhciBl bGVtPWRvY3VtZW50LmdldEVsZW1lbnRCeUlkKG1hdGNoWzNdKTtpZihlbGVtKXtpZihlbGVtLmlk IT1tYXRjaFszXSlyZXR1cm4galF1ZXJ5KCkuZmluZChzZWxlY3Rvcik7cmV0dXJuIGpRdWVyeShl bGVtKTt9c2VsZWN0b3I9W107fX1lbHNlCityZXR1cm4galF1ZXJ5KGNvbnRleHQpLmZpbmQoc2Vs ZWN0b3IpO31lbHNlIGlmKGpRdWVyeS5pc0Z1bmN0aW9uKHNlbGVjdG9yKSlyZXR1cm4galF1ZXJ5 KGRvY3VtZW50KVtqUXVlcnkuZm4ucmVhZHk/InJlYWR5IjoibG9hZCJdKHNlbGVjdG9yKTtyZXR1 cm4gdGhpcy5zZXRBcnJheShqUXVlcnkubWFrZUFycmF5KHNlbGVjdG9yKSk7fSxqcXVlcnk6IjEu Mi42IixzaXplOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMubGVuZ3RoO30sbGVuZ3RoOjAsZ2V0OmZ1 bmN0aW9uKG51bSl7cmV0dXJuIG51bT09dW5kZWZpbmVkP2pRdWVyeS5tYWtlQXJyYXkodGhpcyk6 dGhpc1tudW1dO30scHVzaFN0YWNrOmZ1bmN0aW9uKGVsZW1zKXt2YXIgcmV0PWpRdWVyeShlbGVt cyk7cmV0LnByZXZPYmplY3Q9dGhpcztyZXR1cm4gcmV0O30sc2V0QXJyYXk6ZnVuY3Rpb24oZWxl bXMpe3RoaXMubGVuZ3RoPTA7QXJyYXkucHJvdG90eXBlLnB1c2guYXBwbHkodGhpcyxlbGVtcyk7 cmV0dXJuIHRoaXM7fSxlYWNoOmZ1bmN0aW9uKGNhbGxiYWNrLGFyZ3Mpe3JldHVybiBqUXVlcnku ZWFjaCh0aGlzLGNhbGxiYWNrLGFyZ3MpO30saW5kZXg6ZnVuY3Rpb24oZWxlbSl7dmFyIHJldD0t MTtyZXR1cm4galF1ZXJ5LmluQXJyYXkoZWxlbSYmZWxlbS5qcXVlcnk/ZWxlbVswXTplbGVtLHRo aXMpO30sYXR0cjpmdW5jdGlvbihuYW1lLHZhbHVlLHR5cGUpe3ZhciBvcHRpb25zPW5hbWU7aWYo bmFtZS5jb25zdHJ1Y3Rvcj09U3RyaW5nKWlmKHZhbHVlPT09dW5kZWZpbmVkKXJldHVybiB0aGlz WzBdJiZqUXVlcnlbdHlwZXx8ImF0dHIiXSh0aGlzWzBdLG5hbWUpO2Vsc2V7b3B0aW9ucz17fTtv cHRpb25zW25hbWVdPXZhbHVlO31yZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uKGkpe2ZvcihuYW1l IGluIG9wdGlvbnMpalF1ZXJ5LmF0dHIodHlwZT90aGlzLnN0eWxlOnRoaXMsbmFtZSxqUXVlcnku cHJvcCh0aGlzLG9wdGlvbnNbbmFtZV0sdHlwZSxpLG5hbWUpKTt9KTt9LGNzczpmdW5jdGlvbihr ZXksdmFsdWUpe2lmKChrZXk9PSd3aWR0aCd8fGtleT09J2hlaWdodCcpJiZwYXJzZUZsb2F0KHZh bHVlKTwwKXZhbHVlPXVuZGVmaW5lZDtyZXR1cm4gdGhpcy5hdHRyKGtleSx2YWx1ZSwiY3VyQ1NT Iik7fSx0ZXh0OmZ1bmN0aW9uKHRleHQpe2lmKHR5cGVvZiB0ZXh0IT0ib2JqZWN0IiYmdGV4dCE9 bnVsbClyZXR1cm4gdGhpcy5lbXB0eSgpLmFwcGVuZCgodGhpc1swXSYmdGhpc1swXS5vd25lckRv Y3VtZW50fHxkb2N1bWVudCkuY3JlYXRlVGV4dE5vZGUodGV4dCkpO3ZhciByZXQ9IiI7alF1ZXJ5 LmVhY2godGV4dHx8dGhpcyxmdW5jdGlvbigpe2pRdWVyeS5lYWNoKHRoaXMuY2hpbGROb2Rlcyxm dW5jdGlvbigpe2lmKHRoaXMubm9kZVR5cGUhPTgpcmV0Kz10aGlzLm5vZGVUeXBlIT0xP3RoaXMu bm9kZVZhbHVlOmpRdWVyeS5mbi50ZXh0KFt0aGlzXSk7fSk7fSk7cmV0dXJuIHJldDt9LHdyYXBB bGw6ZnVuY3Rpb24oaHRtbCl7aWYodGhpc1swXSlqUXVlcnkoaHRtbCx0aGlzWzBdLm93bmVyRG9j dW1lbnQpLmNsb25lKCkuaW5zZXJ0QmVmb3JlKHRoaXNbMF0pLm1hcChmdW5jdGlvbigpe3ZhciBl bGVtPXRoaXM7d2hpbGUoZWxlbS5maXJzdENoaWxkKWVsZW09ZWxlbS5maXJzdENoaWxkO3JldHVy biBlbGVtO30pLmFwcGVuZCh0aGlzKTtyZXR1cm4gdGhpczt9LHdyYXBJbm5lcjpmdW5jdGlvbiho dG1sKXtyZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uKCl7alF1ZXJ5KHRoaXMpLmNvbnRlbnRzKCku d3JhcEFsbChodG1sKTt9KTt9LHdyYXA6ZnVuY3Rpb24oaHRtbCl7cmV0dXJuIHRoaXMuZWFjaChm dW5jdGlvbigpe2pRdWVyeSh0aGlzKS53cmFwQWxsKGh0bWwpO30pO30sYXBwZW5kOmZ1bmN0aW9u KCl7cmV0dXJuIHRoaXMuZG9tTWFuaXAoYXJndW1lbnRzLHRydWUsZmFsc2UsZnVuY3Rpb24oZWxl bSl7aWYodGhpcy5ub2RlVHlwZT09MSl0aGlzLmFwcGVuZENoaWxkKGVsZW0pO30pO30scHJlcGVu ZDpmdW5jdGlvbigpe3JldHVybiB0aGlzLmRvbU1hbmlwKGFyZ3VtZW50cyx0cnVlLHRydWUsZnVu Y3Rpb24oZWxlbSl7aWYodGhpcy5ub2RlVHlwZT09MSl0aGlzLmluc2VydEJlZm9yZShlbGVtLHRo aXMuZmlyc3RDaGlsZCk7fSk7fSxiZWZvcmU6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5kb21NYW5p cChhcmd1bWVudHMsZmFsc2UsZmFsc2UsZnVuY3Rpb24oZWxlbSl7dGhpcy5wYXJlbnROb2RlLmlu c2VydEJlZm9yZShlbGVtLHRoaXMpO30pO30sYWZ0ZXI6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5k b21NYW5pcChhcmd1bWVudHMsZmFsc2UsdHJ1ZSxmdW5jdGlvbihlbGVtKXt0aGlzLnBhcmVudE5v ZGUuaW5zZXJ0QmVmb3JlKGVsZW0sdGhpcy5uZXh0U2libGluZyk7fSk7fSxlbmQ6ZnVuY3Rpb24o KXtyZXR1cm4gdGhpcy5wcmV2T2JqZWN0fHxqUXVlcnkoW10pO30sZmluZDpmdW5jdGlvbihzZWxl Y3Rvcil7dmFyIGVsZW1zPWpRdWVyeS5tYXAodGhpcyxmdW5jdGlvbihlbGVtKXtyZXR1cm4galF1 ZXJ5LmZpbmQoc2VsZWN0b3IsZWxlbSk7fSk7cmV0dXJuIHRoaXMucHVzaFN0YWNrKC9bXis+XSBb Xis+XS8udGVzdChzZWxlY3Rvcil8fHNlbGVjdG9yLmluZGV4T2YoIi4uIik+LTE/alF1ZXJ5LnVu aXF1ZShlbGVtcyk6ZWxlbXMpO30sY2xvbmU6ZnVuY3Rpb24oZXZlbnRzKXt2YXIgcmV0PXRoaXMu bWFwKGZ1bmN0aW9uKCl7aWYoalF1ZXJ5LmJyb3dzZXIubXNpZSYmIWpRdWVyeS5pc1hNTERvYyh0 aGlzKSl7dmFyIGNsb25lPXRoaXMuY2xvbmVOb2RlKHRydWUpLGNvbnRhaW5lcj1kb2N1bWVudC5j cmVhdGVFbGVtZW50KCJkaXYiKTtjb250YWluZXIuYXBwZW5kQ2hpbGQoY2xvbmUpO3JldHVybiBq UXVlcnkuY2xlYW4oW2NvbnRhaW5lci5pbm5lckhUTUxdKVswXTt9ZWxzZQorcmV0dXJuIHRoaXMu Y2xvbmVOb2RlKHRydWUpO30pO3ZhciBjbG9uZT1yZXQuZmluZCgiKiIpLmFuZFNlbGYoKS5lYWNo KGZ1bmN0aW9uKCl7aWYodGhpc1tleHBhbmRvXSE9dW5kZWZpbmVkKXRoaXNbZXhwYW5kb109bnVs bDt9KTtpZihldmVudHM9PT10cnVlKXRoaXMuZmluZCgiKiIpLmFuZFNlbGYoKS5lYWNoKGZ1bmN0 aW9uKGkpe2lmKHRoaXMubm9kZVR5cGU9PTMpcmV0dXJuO3ZhciBldmVudHM9alF1ZXJ5LmRhdGEo dGhpcywiZXZlbnRzIik7Zm9yKHZhciB0eXBlIGluIGV2ZW50cylmb3IodmFyIGhhbmRsZXIgaW4g ZXZlbnRzW3R5cGVdKWpRdWVyeS5ldmVudC5hZGQoY2xvbmVbaV0sdHlwZSxldmVudHNbdHlwZV1b aGFuZGxlcl0sZXZlbnRzW3R5cGVdW2hhbmRsZXJdLmRhdGEpO30pO3JldHVybiByZXQ7fSxmaWx0 ZXI6ZnVuY3Rpb24oc2VsZWN0b3Ipe3JldHVybiB0aGlzLnB1c2hTdGFjayhqUXVlcnkuaXNGdW5j dGlvbihzZWxlY3RvcikmJmpRdWVyeS5ncmVwKHRoaXMsZnVuY3Rpb24oZWxlbSxpKXtyZXR1cm4g c2VsZWN0b3IuY2FsbChlbGVtLGkpO30pfHxqUXVlcnkubXVsdGlGaWx0ZXIoc2VsZWN0b3IsdGhp cykpO30sbm90OmZ1bmN0aW9uKHNlbGVjdG9yKXtpZihzZWxlY3Rvci5jb25zdHJ1Y3Rvcj09U3Ry aW5nKWlmKGlzU2ltcGxlLnRlc3Qoc2VsZWN0b3IpKXJldHVybiB0aGlzLnB1c2hTdGFjayhqUXVl cnkubXVsdGlGaWx0ZXIoc2VsZWN0b3IsdGhpcyx0cnVlKSk7ZWxzZQorc2VsZWN0b3I9alF1ZXJ5 Lm11bHRpRmlsdGVyKHNlbGVjdG9yLHRoaXMpO3ZhciBpc0FycmF5TGlrZT1zZWxlY3Rvci5sZW5n dGgmJnNlbGVjdG9yW3NlbGVjdG9yLmxlbmd0aC0xXSE9PXVuZGVmaW5lZCYmIXNlbGVjdG9yLm5v ZGVUeXBlO3JldHVybiB0aGlzLmZpbHRlcihmdW5jdGlvbigpe3JldHVybiBpc0FycmF5TGlrZT9q UXVlcnkuaW5BcnJheSh0aGlzLHNlbGVjdG9yKTwwOnRoaXMhPXNlbGVjdG9yO30pO30sYWRkOmZ1 bmN0aW9uKHNlbGVjdG9yKXtyZXR1cm4gdGhpcy5wdXNoU3RhY2soalF1ZXJ5LnVuaXF1ZShqUXVl cnkubWVyZ2UodGhpcy5nZXQoKSx0eXBlb2Ygc2VsZWN0b3I9PSdzdHJpbmcnP2pRdWVyeShzZWxl Y3Rvcik6alF1ZXJ5Lm1ha2VBcnJheShzZWxlY3RvcikpKSk7fSxpczpmdW5jdGlvbihzZWxlY3Rv cil7cmV0dXJuISFzZWxlY3RvciYmalF1ZXJ5Lm11bHRpRmlsdGVyKHNlbGVjdG9yLHRoaXMpLmxl bmd0aD4wO30saGFzQ2xhc3M6ZnVuY3Rpb24oc2VsZWN0b3Ipe3JldHVybiB0aGlzLmlzKCIuIitz ZWxlY3Rvcik7fSx2YWw6ZnVuY3Rpb24odmFsdWUpe2lmKHZhbHVlPT11bmRlZmluZWQpe2lmKHRo aXMubGVuZ3RoKXt2YXIgZWxlbT10aGlzWzBdO2lmKGpRdWVyeS5ub2RlTmFtZShlbGVtLCJzZWxl Y3QiKSl7dmFyIGluZGV4PWVsZW0uc2VsZWN0ZWRJbmRleCx2YWx1ZXM9W10sb3B0aW9ucz1lbGVt Lm9wdGlvbnMsb25lPWVsZW0udHlwZT09InNlbGVjdC1vbmUiO2lmKGluZGV4PDApcmV0dXJuIG51 bGw7Zm9yKHZhciBpPW9uZT9pbmRleDowLG1heD1vbmU/aW5kZXgrMTpvcHRpb25zLmxlbmd0aDtp PG1heDtpKyspe3ZhciBvcHRpb249b3B0aW9uc1tpXTtpZihvcHRpb24uc2VsZWN0ZWQpe3ZhbHVl PWpRdWVyeS5icm93c2VyLm1zaWUmJiFvcHRpb24uYXR0cmlidXRlcy52YWx1ZS5zcGVjaWZpZWQ/ b3B0aW9uLnRleHQ6b3B0aW9uLnZhbHVlO2lmKG9uZSlyZXR1cm4gdmFsdWU7dmFsdWVzLnB1c2go dmFsdWUpO319cmV0dXJuIHZhbHVlczt9ZWxzZQorcmV0dXJuKHRoaXNbMF0udmFsdWV8fCIiKS5y ZXBsYWNlKC9cci9nLCIiKTt9cmV0dXJuIHVuZGVmaW5lZDt9aWYodmFsdWUuY29uc3RydWN0b3I9 PU51bWJlcil2YWx1ZSs9Jyc7cmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbigpe2lmKHRoaXMubm9k ZVR5cGUhPTEpcmV0dXJuO2lmKHZhbHVlLmNvbnN0cnVjdG9yPT1BcnJheSYmL3JhZGlvfGNoZWNr Ym94Ly50ZXN0KHRoaXMudHlwZSkpdGhpcy5jaGVja2VkPShqUXVlcnkuaW5BcnJheSh0aGlzLnZh bHVlLHZhbHVlKT49MHx8alF1ZXJ5LmluQXJyYXkodGhpcy5uYW1lLHZhbHVlKT49MCk7ZWxzZSBp ZihqUXVlcnkubm9kZU5hbWUodGhpcywic2VsZWN0Iikpe3ZhciB2YWx1ZXM9alF1ZXJ5Lm1ha2VB cnJheSh2YWx1ZSk7alF1ZXJ5KCJvcHRpb24iLHRoaXMpLmVhY2goZnVuY3Rpb24oKXt0aGlzLnNl bGVjdGVkPShqUXVlcnkuaW5BcnJheSh0aGlzLnZhbHVlLHZhbHVlcyk+PTB8fGpRdWVyeS5pbkFy cmF5KHRoaXMudGV4dCx2YWx1ZXMpPj0wKTt9KTtpZighdmFsdWVzLmxlbmd0aCl0aGlzLnNlbGVj dGVkSW5kZXg9LTE7fWVsc2UKK3RoaXMudmFsdWU9dmFsdWU7fSk7fSxodG1sOmZ1bmN0aW9uKHZh bHVlKXtyZXR1cm4gdmFsdWU9PXVuZGVmaW5lZD8odGhpc1swXT90aGlzWzBdLmlubmVySFRNTDpu dWxsKTp0aGlzLmVtcHR5KCkuYXBwZW5kKHZhbHVlKTt9LHJlcGxhY2VXaXRoOmZ1bmN0aW9uKHZh bHVlKXtyZXR1cm4gdGhpcy5hZnRlcih2YWx1ZSkucmVtb3ZlKCk7fSxlcTpmdW5jdGlvbihpKXty ZXR1cm4gdGhpcy5zbGljZShpLGkrMSk7fSxzbGljZTpmdW5jdGlvbigpe3JldHVybiB0aGlzLnB1 c2hTdGFjayhBcnJheS5wcm90b3R5cGUuc2xpY2UuYXBwbHkodGhpcyxhcmd1bWVudHMpKTt9LG1h cDpmdW5jdGlvbihjYWxsYmFjayl7cmV0dXJuIHRoaXMucHVzaFN0YWNrKGpRdWVyeS5tYXAodGhp cyxmdW5jdGlvbihlbGVtLGkpe3JldHVybiBjYWxsYmFjay5jYWxsKGVsZW0saSxlbGVtKTt9KSk7 fSxhbmRTZWxmOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuYWRkKHRoaXMucHJldk9iamVjdCk7fSxk YXRhOmZ1bmN0aW9uKGtleSx2YWx1ZSl7dmFyIHBhcnRzPWtleS5zcGxpdCgiLiIpO3BhcnRzWzFd PXBhcnRzWzFdPyIuIitwYXJ0c1sxXToiIjtpZih2YWx1ZT09PXVuZGVmaW5lZCl7dmFyIGRhdGE9 dGhpcy50cmlnZ2VySGFuZGxlcigiZ2V0RGF0YSIrcGFydHNbMV0rIiEiLFtwYXJ0c1swXV0pO2lm KGRhdGE9PT11bmRlZmluZWQmJnRoaXMubGVuZ3RoKWRhdGE9alF1ZXJ5LmRhdGEodGhpc1swXSxr ZXkpO3JldHVybiBkYXRhPT09dW5kZWZpbmVkJiZwYXJ0c1sxXT90aGlzLmRhdGEocGFydHNbMF0p OmRhdGE7fWVsc2UKK3JldHVybiB0aGlzLnRyaWdnZXIoInNldERhdGEiK3BhcnRzWzFdKyIhIixb cGFydHNbMF0sdmFsdWVdKS5lYWNoKGZ1bmN0aW9uKCl7alF1ZXJ5LmRhdGEodGhpcyxrZXksdmFs dWUpO30pO30scmVtb3ZlRGF0YTpmdW5jdGlvbihrZXkpe3JldHVybiB0aGlzLmVhY2goZnVuY3Rp b24oKXtqUXVlcnkucmVtb3ZlRGF0YSh0aGlzLGtleSk7fSk7fSxkb21NYW5pcDpmdW5jdGlvbihh cmdzLHRhYmxlLHJldmVyc2UsY2FsbGJhY2spe3ZhciBjbG9uZT10aGlzLmxlbmd0aD4xLGVsZW1z O3JldHVybiB0aGlzLmVhY2goZnVuY3Rpb24oKXtpZighZWxlbXMpe2VsZW1zPWpRdWVyeS5jbGVh bihhcmdzLHRoaXMub3duZXJEb2N1bWVudCk7aWYocmV2ZXJzZSllbGVtcy5yZXZlcnNlKCk7fXZh ciBvYmo9dGhpcztpZih0YWJsZSYmalF1ZXJ5Lm5vZGVOYW1lKHRoaXMsInRhYmxlIikmJmpRdWVy eS5ub2RlTmFtZShlbGVtc1swXSwidHIiKSlvYmo9dGhpcy5nZXRFbGVtZW50c0J5VGFnTmFtZSgi dGJvZHkiKVswXXx8dGhpcy5hcHBlbmRDaGlsZCh0aGlzLm93bmVyRG9jdW1lbnQuY3JlYXRlRWxl bWVudCgidGJvZHkiKSk7dmFyIHNjcmlwdHM9alF1ZXJ5KFtdKTtqUXVlcnkuZWFjaChlbGVtcyxm dW5jdGlvbigpe3ZhciBlbGVtPWNsb25lP2pRdWVyeSh0aGlzKS5jbG9uZSh0cnVlKVswXTp0aGlz O2lmKGpRdWVyeS5ub2RlTmFtZShlbGVtLCJzY3JpcHQiKSlzY3JpcHRzPXNjcmlwdHMuYWRkKGVs ZW0pO2Vsc2V7aWYoZWxlbS5ub2RlVHlwZT09MSlzY3JpcHRzPXNjcmlwdHMuYWRkKGpRdWVyeSgi c2NyaXB0IixlbGVtKS5yZW1vdmUoKSk7Y2FsbGJhY2suY2FsbChvYmosZWxlbSk7fX0pO3Njcmlw dHMuZWFjaChldmFsU2NyaXB0KTt9KTt9fTtqUXVlcnkuZm4uaW5pdC5wcm90b3R5cGU9alF1ZXJ5 LmZuO2Z1bmN0aW9uIGV2YWxTY3JpcHQoaSxlbGVtKXtpZihlbGVtLnNyYylqUXVlcnkuYWpheCh7 dXJsOmVsZW0uc3JjLGFzeW5jOmZhbHNlLGRhdGFUeXBlOiJzY3JpcHQifSk7ZWxzZQoralF1ZXJ5 Lmdsb2JhbEV2YWwoZWxlbS50ZXh0fHxlbGVtLnRleHRDb250ZW50fHxlbGVtLmlubmVySFRNTHx8 IiIpO2lmKGVsZW0ucGFyZW50Tm9kZSllbGVtLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoZWxlbSk7 fWZ1bmN0aW9uIG5vdygpe3JldHVybituZXcgRGF0ZTt9alF1ZXJ5LmV4dGVuZD1qUXVlcnkuZm4u ZXh0ZW5kPWZ1bmN0aW9uKCl7dmFyIHRhcmdldD1hcmd1bWVudHNbMF18fHt9LGk9MSxsZW5ndGg9 YXJndW1lbnRzLmxlbmd0aCxkZWVwPWZhbHNlLG9wdGlvbnM7aWYodGFyZ2V0LmNvbnN0cnVjdG9y PT1Cb29sZWFuKXtkZWVwPXRhcmdldDt0YXJnZXQ9YXJndW1lbnRzWzFdfHx7fTtpPTI7fWlmKHR5 cGVvZiB0YXJnZXQhPSJvYmplY3QiJiZ0eXBlb2YgdGFyZ2V0IT0iZnVuY3Rpb24iKXRhcmdldD17 fTtpZihsZW5ndGg9PWkpe3RhcmdldD10aGlzOy0taTt9Zm9yKDtpPGxlbmd0aDtpKyspaWYoKG9w dGlvbnM9YXJndW1lbnRzW2ldKSE9bnVsbClmb3IodmFyIG5hbWUgaW4gb3B0aW9ucyl7dmFyIHNy Yz10YXJnZXRbbmFtZV0sY29weT1vcHRpb25zW25hbWVdO2lmKHRhcmdldD09PWNvcHkpY29udGlu dWU7aWYoZGVlcCYmY29weSYmdHlwZW9mIGNvcHk9PSJvYmplY3QiJiYhY29weS5ub2RlVHlwZSl0 YXJnZXRbbmFtZV09alF1ZXJ5LmV4dGVuZChkZWVwLHNyY3x8KGNvcHkubGVuZ3RoIT1udWxsP1td Ont9KSxjb3B5KTtlbHNlIGlmKGNvcHkhPT11bmRlZmluZWQpdGFyZ2V0W25hbWVdPWNvcHk7fXJl dHVybiB0YXJnZXQ7fTt2YXIgZXhwYW5kbz0ialF1ZXJ5Iitub3coKSx1dWlkPTAsd2luZG93RGF0 YT17fSxleGNsdWRlPS96LT9pbmRleHxmb250LT93ZWlnaHR8b3BhY2l0eXx6b29tfGxpbmUtP2hl aWdodC9pLGRlZmF1bHRWaWV3PWRvY3VtZW50LmRlZmF1bHRWaWV3fHx7fTtqUXVlcnkuZXh0ZW5k KHtub0NvbmZsaWN0OmZ1bmN0aW9uKGRlZXApe3dpbmRvdy4kPV8kO2lmKGRlZXApd2luZG93LmpR dWVyeT1falF1ZXJ5O3JldHVybiBqUXVlcnk7fSxpc0Z1bmN0aW9uOmZ1bmN0aW9uKGZuKXtyZXR1 cm4hIWZuJiZ0eXBlb2YgZm4hPSJzdHJpbmciJiYhZm4ubm9kZU5hbWUmJmZuLmNvbnN0cnVjdG9y IT1BcnJheSYmL15bXHNbXT9mdW5jdGlvbi8udGVzdChmbisiIik7fSxpc1hNTERvYzpmdW5jdGlv bihlbGVtKXtyZXR1cm4gZWxlbS5kb2N1bWVudEVsZW1lbnQmJiFlbGVtLmJvZHl8fGVsZW0udGFn TmFtZSYmZWxlbS5vd25lckRvY3VtZW50JiYhZWxlbS5vd25lckRvY3VtZW50LmJvZHk7fSxnbG9i YWxFdmFsOmZ1bmN0aW9uKGRhdGEpe2RhdGE9alF1ZXJ5LnRyaW0oZGF0YSk7aWYoZGF0YSl7dmFy IGhlYWQ9ZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoImhlYWQiKVswXXx8ZG9jdW1lbnQu ZG9jdW1lbnRFbGVtZW50LHNjcmlwdD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJzY3JpcHQiKTtz Y3JpcHQudHlwZT0idGV4dC9qYXZhc2NyaXB0IjtpZihqUXVlcnkuYnJvd3Nlci5tc2llKXNjcmlw dC50ZXh0PWRhdGE7ZWxzZQorc2NyaXB0LmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZVRleHRO b2RlKGRhdGEpKTtoZWFkLmluc2VydEJlZm9yZShzY3JpcHQsaGVhZC5maXJzdENoaWxkKTtoZWFk LnJlbW92ZUNoaWxkKHNjcmlwdCk7fX0sbm9kZU5hbWU6ZnVuY3Rpb24oZWxlbSxuYW1lKXtyZXR1 cm4gZWxlbS5ub2RlTmFtZSYmZWxlbS5ub2RlTmFtZS50b1VwcGVyQ2FzZSgpPT1uYW1lLnRvVXBw ZXJDYXNlKCk7fSxjYWNoZTp7fSxkYXRhOmZ1bmN0aW9uKGVsZW0sbmFtZSxkYXRhKXtlbGVtPWVs ZW09PXdpbmRvdz93aW5kb3dEYXRhOmVsZW07dmFyIGlkPWVsZW1bZXhwYW5kb107aWYoIWlkKWlk PWVsZW1bZXhwYW5kb109Kyt1dWlkO2lmKG5hbWUmJiFqUXVlcnkuY2FjaGVbaWRdKWpRdWVyeS5j YWNoZVtpZF09e307aWYoZGF0YSE9PXVuZGVmaW5lZClqUXVlcnkuY2FjaGVbaWRdW25hbWVdPWRh dGE7cmV0dXJuIG5hbWU/alF1ZXJ5LmNhY2hlW2lkXVtuYW1lXTppZDt9LHJlbW92ZURhdGE6ZnVu Y3Rpb24oZWxlbSxuYW1lKXtlbGVtPWVsZW09PXdpbmRvdz93aW5kb3dEYXRhOmVsZW07dmFyIGlk PWVsZW1bZXhwYW5kb107aWYobmFtZSl7aWYoalF1ZXJ5LmNhY2hlW2lkXSl7ZGVsZXRlIGpRdWVy eS5jYWNoZVtpZF1bbmFtZV07bmFtZT0iIjtmb3IobmFtZSBpbiBqUXVlcnkuY2FjaGVbaWRdKWJy ZWFrO2lmKCFuYW1lKWpRdWVyeS5yZW1vdmVEYXRhKGVsZW0pO319ZWxzZXt0cnl7ZGVsZXRlIGVs ZW1bZXhwYW5kb107fWNhdGNoKGUpe2lmKGVsZW0ucmVtb3ZlQXR0cmlidXRlKWVsZW0ucmVtb3Zl QXR0cmlidXRlKGV4cGFuZG8pO31kZWxldGUgalF1ZXJ5LmNhY2hlW2lkXTt9fSxlYWNoOmZ1bmN0 aW9uKG9iamVjdCxjYWxsYmFjayxhcmdzKXt2YXIgbmFtZSxpPTAsbGVuZ3RoPW9iamVjdC5sZW5n dGg7aWYoYXJncyl7aWYobGVuZ3RoPT11bmRlZmluZWQpe2ZvcihuYW1lIGluIG9iamVjdClpZihj YWxsYmFjay5hcHBseShvYmplY3RbbmFtZV0sYXJncyk9PT1mYWxzZSlicmVhazt9ZWxzZQorZm9y KDtpPGxlbmd0aDspaWYoY2FsbGJhY2suYXBwbHkob2JqZWN0W2krK10sYXJncyk9PT1mYWxzZSli cmVhazt9ZWxzZXtpZihsZW5ndGg9PXVuZGVmaW5lZCl7Zm9yKG5hbWUgaW4gb2JqZWN0KWlmKGNh bGxiYWNrLmNhbGwob2JqZWN0W25hbWVdLG5hbWUsb2JqZWN0W25hbWVdKT09PWZhbHNlKWJyZWFr O31lbHNlCitmb3IodmFyIHZhbHVlPW9iamVjdFswXTtpPGxlbmd0aCYmY2FsbGJhY2suY2FsbCh2 YWx1ZSxpLHZhbHVlKSE9PWZhbHNlO3ZhbHVlPW9iamVjdFsrK2ldKXt9fXJldHVybiBvYmplY3Q7 fSxwcm9wOmZ1bmN0aW9uKGVsZW0sdmFsdWUsdHlwZSxpLG5hbWUpe2lmKGpRdWVyeS5pc0Z1bmN0 aW9uKHZhbHVlKSl2YWx1ZT12YWx1ZS5jYWxsKGVsZW0saSk7cmV0dXJuIHZhbHVlJiZ2YWx1ZS5j b25zdHJ1Y3Rvcj09TnVtYmVyJiZ0eXBlPT0iY3VyQ1NTIiYmIWV4Y2x1ZGUudGVzdChuYW1lKT92 YWx1ZSsicHgiOnZhbHVlO30sY2xhc3NOYW1lOnthZGQ6ZnVuY3Rpb24oZWxlbSxjbGFzc05hbWVz KXtqUXVlcnkuZWFjaCgoY2xhc3NOYW1lc3x8IiIpLnNwbGl0KC9ccysvKSxmdW5jdGlvbihpLGNs YXNzTmFtZSl7aWYoZWxlbS5ub2RlVHlwZT09MSYmIWpRdWVyeS5jbGFzc05hbWUuaGFzKGVsZW0u Y2xhc3NOYW1lLGNsYXNzTmFtZSkpZWxlbS5jbGFzc05hbWUrPShlbGVtLmNsYXNzTmFtZT8iICI6 IiIpK2NsYXNzTmFtZTt9KTt9LHJlbW92ZTpmdW5jdGlvbihlbGVtLGNsYXNzTmFtZXMpe2lmKGVs ZW0ubm9kZVR5cGU9PTEpZWxlbS5jbGFzc05hbWU9Y2xhc3NOYW1lcyE9dW5kZWZpbmVkP2pRdWVy eS5ncmVwKGVsZW0uY2xhc3NOYW1lLnNwbGl0KC9ccysvKSxmdW5jdGlvbihjbGFzc05hbWUpe3Jl dHVybiFqUXVlcnkuY2xhc3NOYW1lLmhhcyhjbGFzc05hbWVzLGNsYXNzTmFtZSk7fSkuam9pbigi ICIpOiIiO30saGFzOmZ1bmN0aW9uKGVsZW0sY2xhc3NOYW1lKXtyZXR1cm4galF1ZXJ5LmluQXJy YXkoY2xhc3NOYW1lLChlbGVtLmNsYXNzTmFtZXx8ZWxlbSkudG9TdHJpbmcoKS5zcGxpdCgvXHMr LykpPi0xO319LHN3YXA6ZnVuY3Rpb24oZWxlbSxvcHRpb25zLGNhbGxiYWNrKXt2YXIgb2xkPXt9 O2Zvcih2YXIgbmFtZSBpbiBvcHRpb25zKXtvbGRbbmFtZV09ZWxlbS5zdHlsZVtuYW1lXTtlbGVt LnN0eWxlW25hbWVdPW9wdGlvbnNbbmFtZV07fWNhbGxiYWNrLmNhbGwoZWxlbSk7Zm9yKHZhciBu YW1lIGluIG9wdGlvbnMpZWxlbS5zdHlsZVtuYW1lXT1vbGRbbmFtZV07fSxjc3M6ZnVuY3Rpb24o ZWxlbSxuYW1lLGZvcmNlKXtpZihuYW1lPT0id2lkdGgifHxuYW1lPT0iaGVpZ2h0Iil7dmFyIHZh bCxwcm9wcz17cG9zaXRpb246ImFic29sdXRlIix2aXNpYmlsaXR5OiJoaWRkZW4iLGRpc3BsYXk6 ImJsb2NrIn0sd2hpY2g9bmFtZT09IndpZHRoIj9bIkxlZnQiLCJSaWdodCJdOlsiVG9wIiwiQm90 dG9tIl07ZnVuY3Rpb24gZ2V0V0goKXt2YWw9bmFtZT09IndpZHRoIj9lbGVtLm9mZnNldFdpZHRo OmVsZW0ub2Zmc2V0SGVpZ2h0O3ZhciBwYWRkaW5nPTAsYm9yZGVyPTA7alF1ZXJ5LmVhY2god2hp Y2gsZnVuY3Rpb24oKXtwYWRkaW5nKz1wYXJzZUZsb2F0KGpRdWVyeS5jdXJDU1MoZWxlbSwicGFk ZGluZyIrdGhpcyx0cnVlKSl8fDA7Ym9yZGVyKz1wYXJzZUZsb2F0KGpRdWVyeS5jdXJDU1MoZWxl bSwiYm9yZGVyIit0aGlzKyJXaWR0aCIsdHJ1ZSkpfHwwO30pO3ZhbC09TWF0aC5yb3VuZChwYWRk aW5nK2JvcmRlcik7fWlmKGpRdWVyeShlbGVtKS5pcygiOnZpc2libGUiKSlnZXRXSCgpO2Vsc2UK K2pRdWVyeS5zd2FwKGVsZW0scHJvcHMsZ2V0V0gpO3JldHVybiBNYXRoLm1heCgwLHZhbCk7fXJl dHVybiBqUXVlcnkuY3VyQ1NTKGVsZW0sbmFtZSxmb3JjZSk7fSxjdXJDU1M6ZnVuY3Rpb24oZWxl bSxuYW1lLGZvcmNlKXt2YXIgcmV0LHN0eWxlPWVsZW0uc3R5bGU7ZnVuY3Rpb24gY29sb3IoZWxl bSl7aWYoIWpRdWVyeS5icm93c2VyLnNhZmFyaSlyZXR1cm4gZmFsc2U7dmFyIHJldD1kZWZhdWx0 Vmlldy5nZXRDb21wdXRlZFN0eWxlKGVsZW0sbnVsbCk7cmV0dXJuIXJldHx8cmV0LmdldFByb3Bl cnR5VmFsdWUoImNvbG9yIik9PSIiO31pZihuYW1lPT0ib3BhY2l0eSImJmpRdWVyeS5icm93c2Vy Lm1zaWUpe3JldD1qUXVlcnkuYXR0cihzdHlsZSwib3BhY2l0eSIpO3JldHVybiByZXQ9PSIiPyIx IjpyZXQ7fWlmKGpRdWVyeS5icm93c2VyLm9wZXJhJiZuYW1lPT0iZGlzcGxheSIpe3ZhciBzYXZl PXN0eWxlLm91dGxpbmU7c3R5bGUub3V0bGluZT0iMCBzb2xpZCBibGFjayI7c3R5bGUub3V0bGlu ZT1zYXZlO31pZihuYW1lLm1hdGNoKC9mbG9hdC9pKSluYW1lPXN0eWxlRmxvYXQ7aWYoIWZvcmNl JiZzdHlsZSYmc3R5bGVbbmFtZV0pcmV0PXN0eWxlW25hbWVdO2Vsc2UgaWYoZGVmYXVsdFZpZXcu Z2V0Q29tcHV0ZWRTdHlsZSl7aWYobmFtZS5tYXRjaCgvZmxvYXQvaSkpbmFtZT0iZmxvYXQiO25h bWU9bmFtZS5yZXBsYWNlKC8oW0EtWl0pL2csIi0kMSIpLnRvTG93ZXJDYXNlKCk7dmFyIGNvbXB1 dGVkU3R5bGU9ZGVmYXVsdFZpZXcuZ2V0Q29tcHV0ZWRTdHlsZShlbGVtLG51bGwpO2lmKGNvbXB1 dGVkU3R5bGUmJiFjb2xvcihlbGVtKSlyZXQ9Y29tcHV0ZWRTdHlsZS5nZXRQcm9wZXJ0eVZhbHVl KG5hbWUpO2Vsc2V7dmFyIHN3YXA9W10sc3RhY2s9W10sYT1lbGVtLGk9MDtmb3IoO2EmJmNvbG9y KGEpO2E9YS5wYXJlbnROb2RlKXN0YWNrLnVuc2hpZnQoYSk7Zm9yKDtpPHN0YWNrLmxlbmd0aDtp KyspaWYoY29sb3Ioc3RhY2tbaV0pKXtzd2FwW2ldPXN0YWNrW2ldLnN0eWxlLmRpc3BsYXk7c3Rh Y2tbaV0uc3R5bGUuZGlzcGxheT0iYmxvY2siO31yZXQ9bmFtZT09ImRpc3BsYXkiJiZzd2FwW3N0 YWNrLmxlbmd0aC0xXSE9bnVsbD8ibm9uZSI6KGNvbXB1dGVkU3R5bGUmJmNvbXB1dGVkU3R5bGUu Z2V0UHJvcGVydHlWYWx1ZShuYW1lKSl8fCIiO2ZvcihpPTA7aTxzd2FwLmxlbmd0aDtpKyspaWYo c3dhcFtpXSE9bnVsbClzdGFja1tpXS5zdHlsZS5kaXNwbGF5PXN3YXBbaV07fWlmKG5hbWU9PSJv cGFjaXR5IiYmcmV0PT0iIilyZXQ9IjEiO31lbHNlIGlmKGVsZW0uY3VycmVudFN0eWxlKXt2YXIg Y2FtZWxDYXNlPW5hbWUucmVwbGFjZSgvXC0oXHcpL2csZnVuY3Rpb24oYWxsLGxldHRlcil7cmV0 dXJuIGxldHRlci50b1VwcGVyQ2FzZSgpO30pO3JldD1lbGVtLmN1cnJlbnRTdHlsZVtuYW1lXXx8 ZWxlbS5jdXJyZW50U3R5bGVbY2FtZWxDYXNlXTtpZighL15cZCsocHgpPyQvaS50ZXN0KHJldCkm Ji9eXGQvLnRlc3QocmV0KSl7dmFyIGxlZnQ9c3R5bGUubGVmdCxyc0xlZnQ9ZWxlbS5ydW50aW1l U3R5bGUubGVmdDtlbGVtLnJ1bnRpbWVTdHlsZS5sZWZ0PWVsZW0uY3VycmVudFN0eWxlLmxlZnQ7 c3R5bGUubGVmdD1yZXR8fDA7cmV0PXN0eWxlLnBpeGVsTGVmdCsicHgiO3N0eWxlLmxlZnQ9bGVm dDtlbGVtLnJ1bnRpbWVTdHlsZS5sZWZ0PXJzTGVmdDt9fXJldHVybiByZXQ7fSxjbGVhbjpmdW5j dGlvbihlbGVtcyxjb250ZXh0KXt2YXIgcmV0PVtdO2NvbnRleHQ9Y29udGV4dHx8ZG9jdW1lbnQ7 aWYodHlwZW9mIGNvbnRleHQuY3JlYXRlRWxlbWVudD09J3VuZGVmaW5lZCcpY29udGV4dD1jb250 ZXh0Lm93bmVyRG9jdW1lbnR8fGNvbnRleHRbMF0mJmNvbnRleHRbMF0ub3duZXJEb2N1bWVudHx8 ZG9jdW1lbnQ7alF1ZXJ5LmVhY2goZWxlbXMsZnVuY3Rpb24oaSxlbGVtKXtpZighZWxlbSlyZXR1 cm47aWYoZWxlbS5jb25zdHJ1Y3Rvcj09TnVtYmVyKWVsZW0rPScnO2lmKHR5cGVvZiBlbGVtPT0i c3RyaW5nIil7ZWxlbT1lbGVtLnJlcGxhY2UoLyg8KFx3KylbXj5dKj8pXC8+L2csZnVuY3Rpb24o YWxsLGZyb250LHRhZyl7cmV0dXJuIHRhZy5tYXRjaCgvXihhYmJyfGJyfGNvbHxpbWd8aW5wdXR8 bGlua3xtZXRhfHBhcmFtfGhyfGFyZWF8ZW1iZWQpJC9pKT9hbGw6ZnJvbnQrIj48LyIrdGFnKyI+ Ijt9KTt2YXIgdGFncz1qUXVlcnkudHJpbShlbGVtKS50b0xvd2VyQ2FzZSgpLGRpdj1jb250ZXh0 LmNyZWF0ZUVsZW1lbnQoImRpdiIpO3ZhciB3cmFwPSF0YWdzLmluZGV4T2YoIjxvcHQiKSYmWzEs IjxzZWxlY3QgbXVsdGlwbGU9J211bHRpcGxlJz4iLCI8L3NlbGVjdD4iXXx8IXRhZ3MuaW5kZXhP ZigiPGxlZyIpJiZbMSwiPGZpZWxkc2V0PiIsIjwvZmllbGRzZXQ+Il18fHRhZ3MubWF0Y2goL148 KHRoZWFkfHRib2R5fHRmb290fGNvbGd8Y2FwKS8pJiZbMSwiPHRhYmxlPiIsIjwvdGFibGU+Il18 fCF0YWdzLmluZGV4T2YoIjx0ciIpJiZbMiwiPHRhYmxlPjx0Ym9keT4iLCI8L3Rib2R5PjwvdGFi bGU+Il18fCghdGFncy5pbmRleE9mKCI8dGQiKXx8IXRhZ3MuaW5kZXhPZigiPHRoIikpJiZbMywi PHRhYmxlPjx0Ym9keT48dHI+IiwiPC90cj48L3Rib2R5PjwvdGFibGU+Il18fCF0YWdzLmluZGV4 T2YoIjxjb2wiKSYmWzIsIjx0YWJsZT48dGJvZHk+PC90Ym9keT48Y29sZ3JvdXA+IiwiPC9jb2xn cm91cD48L3RhYmxlPiJdfHxqUXVlcnkuYnJvd3Nlci5tc2llJiZbMSwiZGl2PGRpdj4iLCI8L2Rp dj4iXXx8WzAsIiIsIiJdO2Rpdi5pbm5lckhUTUw9d3JhcFsxXStlbGVtK3dyYXBbMl07d2hpbGUo d3JhcFswXS0tKWRpdj1kaXYubGFzdENoaWxkO2lmKGpRdWVyeS5icm93c2VyLm1zaWUpe3ZhciB0 Ym9keT0hdGFncy5pbmRleE9mKCI8dGFibGUiKSYmdGFncy5pbmRleE9mKCI8dGJvZHkiKTwwP2Rp di5maXJzdENoaWxkJiZkaXYuZmlyc3RDaGlsZC5jaGlsZE5vZGVzOndyYXBbMV09PSI8dGFibGU+ IiYmdGFncy5pbmRleE9mKCI8dGJvZHkiKTwwP2Rpdi5jaGlsZE5vZGVzOltdO2Zvcih2YXIgaj10 Ym9keS5sZW5ndGgtMTtqPj0wOy0tailpZihqUXVlcnkubm9kZU5hbWUodGJvZHlbal0sInRib2R5 IikmJiF0Ym9keVtqXS5jaGlsZE5vZGVzLmxlbmd0aCl0Ym9keVtqXS5wYXJlbnROb2RlLnJlbW92 ZUNoaWxkKHRib2R5W2pdKTtpZigvXlxzLy50ZXN0KGVsZW0pKWRpdi5pbnNlcnRCZWZvcmUoY29u dGV4dC5jcmVhdGVUZXh0Tm9kZShlbGVtLm1hdGNoKC9eXHMqLylbMF0pLGRpdi5maXJzdENoaWxk KTt9ZWxlbT1qUXVlcnkubWFrZUFycmF5KGRpdi5jaGlsZE5vZGVzKTt9aWYoZWxlbS5sZW5ndGg9 PT0wJiYoIWpRdWVyeS5ub2RlTmFtZShlbGVtLCJmb3JtIikmJiFqUXVlcnkubm9kZU5hbWUoZWxl bSwic2VsZWN0IikpKXJldHVybjtpZihlbGVtWzBdPT11bmRlZmluZWR8fGpRdWVyeS5ub2RlTmFt ZShlbGVtLCJmb3JtIil8fGVsZW0ub3B0aW9ucylyZXQucHVzaChlbGVtKTtlbHNlCityZXQ9alF1 ZXJ5Lm1lcmdlKHJldCxlbGVtKTt9KTtyZXR1cm4gcmV0O30sYXR0cjpmdW5jdGlvbihlbGVtLG5h bWUsdmFsdWUpe2lmKCFlbGVtfHxlbGVtLm5vZGVUeXBlPT0zfHxlbGVtLm5vZGVUeXBlPT04KXJl dHVybiB1bmRlZmluZWQ7dmFyIG5vdHhtbD0halF1ZXJ5LmlzWE1MRG9jKGVsZW0pLHNldD12YWx1 ZSE9PXVuZGVmaW5lZCxtc2llPWpRdWVyeS5icm93c2VyLm1zaWU7bmFtZT1ub3R4bWwmJmpRdWVy eS5wcm9wc1tuYW1lXXx8bmFtZTtpZihlbGVtLnRhZ05hbWUpe3ZhciBzcGVjaWFsPS9ocmVmfHNy Y3xzdHlsZS8udGVzdChuYW1lKTtpZihuYW1lPT0ic2VsZWN0ZWQiJiZqUXVlcnkuYnJvd3Nlci5z YWZhcmkpZWxlbS5wYXJlbnROb2RlLnNlbGVjdGVkSW5kZXg7aWYobmFtZSBpbiBlbGVtJiZub3R4 bWwmJiFzcGVjaWFsKXtpZihzZXQpe2lmKG5hbWU9PSJ0eXBlIiYmalF1ZXJ5Lm5vZGVOYW1lKGVs ZW0sImlucHV0IikmJmVsZW0ucGFyZW50Tm9kZSl0aHJvdyJ0eXBlIHByb3BlcnR5IGNhbid0IGJl IGNoYW5nZWQiO2VsZW1bbmFtZV09dmFsdWU7fWlmKGpRdWVyeS5ub2RlTmFtZShlbGVtLCJmb3Jt IikmJmVsZW0uZ2V0QXR0cmlidXRlTm9kZShuYW1lKSlyZXR1cm4gZWxlbS5nZXRBdHRyaWJ1dGVO b2RlKG5hbWUpLm5vZGVWYWx1ZTtyZXR1cm4gZWxlbVtuYW1lXTt9aWYobXNpZSYmbm90eG1sJiZu YW1lPT0ic3R5bGUiKXJldHVybiBqUXVlcnkuYXR0cihlbGVtLnN0eWxlLCJjc3NUZXh0Iix2YWx1 ZSk7aWYoc2V0KWVsZW0uc2V0QXR0cmlidXRlKG5hbWUsIiIrdmFsdWUpO3ZhciBhdHRyPW1zaWUm Jm5vdHhtbCYmc3BlY2lhbD9lbGVtLmdldEF0dHJpYnV0ZShuYW1lLDIpOmVsZW0uZ2V0QXR0cmli dXRlKG5hbWUpO3JldHVybiBhdHRyPT09bnVsbD91bmRlZmluZWQ6YXR0cjt9aWYobXNpZSYmbmFt ZT09Im9wYWNpdHkiKXtpZihzZXQpe2VsZW0uem9vbT0xO2VsZW0uZmlsdGVyPShlbGVtLmZpbHRl cnx8IiIpLnJlcGxhY2UoL2FscGhhXChbXildKlwpLywiIikrKHBhcnNlSW50KHZhbHVlKSsnJz09 Ik5hTiI/IiI6ImFscGhhKG9wYWNpdHk9Iit2YWx1ZSoxMDArIikiKTt9cmV0dXJuIGVsZW0uZmls dGVyJiZlbGVtLmZpbHRlci5pbmRleE9mKCJvcGFjaXR5PSIpPj0wPyhwYXJzZUZsb2F0KGVsZW0u ZmlsdGVyLm1hdGNoKC9vcGFjaXR5PShbXildKikvKVsxXSkvMTAwKSsnJzoiIjt9bmFtZT1uYW1l LnJlcGxhY2UoLy0oW2Etel0pL2lnLGZ1bmN0aW9uKGFsbCxsZXR0ZXIpe3JldHVybiBsZXR0ZXIu dG9VcHBlckNhc2UoKTt9KTtpZihzZXQpZWxlbVtuYW1lXT12YWx1ZTtyZXR1cm4gZWxlbVtuYW1l XTt9LHRyaW06ZnVuY3Rpb24odGV4dCl7cmV0dXJuKHRleHR8fCIiKS5yZXBsYWNlKC9eXHMrfFxz KyQvZywiIik7fSxtYWtlQXJyYXk6ZnVuY3Rpb24oYXJyYXkpe3ZhciByZXQ9W107aWYoYXJyYXkh PW51bGwpe3ZhciBpPWFycmF5Lmxlbmd0aDtpZihpPT1udWxsfHxhcnJheS5zcGxpdHx8YXJyYXku c2V0SW50ZXJ2YWx8fGFycmF5LmNhbGwpcmV0WzBdPWFycmF5O2Vsc2UKK3doaWxlKGkpcmV0Wy0t aV09YXJyYXlbaV07fXJldHVybiByZXQ7fSxpbkFycmF5OmZ1bmN0aW9uKGVsZW0sYXJyYXkpe2Zv cih2YXIgaT0wLGxlbmd0aD1hcnJheS5sZW5ndGg7aTxsZW5ndGg7aSsrKWlmKGFycmF5W2ldPT09 ZWxlbSlyZXR1cm4gaTtyZXR1cm4tMTt9LG1lcmdlOmZ1bmN0aW9uKGZpcnN0LHNlY29uZCl7dmFy IGk9MCxlbGVtLHBvcz1maXJzdC5sZW5ndGg7aWYoalF1ZXJ5LmJyb3dzZXIubXNpZSl7d2hpbGUo ZWxlbT1zZWNvbmRbaSsrXSlpZihlbGVtLm5vZGVUeXBlIT04KWZpcnN0W3BvcysrXT1lbGVtO31l bHNlCit3aGlsZShlbGVtPXNlY29uZFtpKytdKWZpcnN0W3BvcysrXT1lbGVtO3JldHVybiBmaXJz dDt9LHVuaXF1ZTpmdW5jdGlvbihhcnJheSl7dmFyIHJldD1bXSxkb25lPXt9O3RyeXtmb3IodmFy IGk9MCxsZW5ndGg9YXJyYXkubGVuZ3RoO2k8bGVuZ3RoO2krKyl7dmFyIGlkPWpRdWVyeS5kYXRh KGFycmF5W2ldKTtpZighZG9uZVtpZF0pe2RvbmVbaWRdPXRydWU7cmV0LnB1c2goYXJyYXlbaV0p O319fWNhdGNoKGUpe3JldD1hcnJheTt9cmV0dXJuIHJldDt9LGdyZXA6ZnVuY3Rpb24oZWxlbXMs Y2FsbGJhY2ssaW52KXt2YXIgcmV0PVtdO2Zvcih2YXIgaT0wLGxlbmd0aD1lbGVtcy5sZW5ndGg7 aTxsZW5ndGg7aSsrKWlmKCFpbnYhPSFjYWxsYmFjayhlbGVtc1tpXSxpKSlyZXQucHVzaChlbGVt c1tpXSk7cmV0dXJuIHJldDt9LG1hcDpmdW5jdGlvbihlbGVtcyxjYWxsYmFjayl7dmFyIHJldD1b XTtmb3IodmFyIGk9MCxsZW5ndGg9ZWxlbXMubGVuZ3RoO2k8bGVuZ3RoO2krKyl7dmFyIHZhbHVl PWNhbGxiYWNrKGVsZW1zW2ldLGkpO2lmKHZhbHVlIT1udWxsKXJldFtyZXQubGVuZ3RoXT12YWx1 ZTt9cmV0dXJuIHJldC5jb25jYXQuYXBwbHkoW10scmV0KTt9fSk7dmFyIHVzZXJBZ2VudD1uYXZp Z2F0b3IudXNlckFnZW50LnRvTG93ZXJDYXNlKCk7alF1ZXJ5LmJyb3dzZXI9e3ZlcnNpb246KHVz ZXJBZ2VudC5tYXRjaCgvLisoPzpydnxpdHxyYXxpZSlbXC86IF0oW1xkLl0rKS8pfHxbXSlbMV0s c2FmYXJpOi93ZWJraXQvLnRlc3QodXNlckFnZW50KSxvcGVyYTovb3BlcmEvLnRlc3QodXNlckFn ZW50KSxtc2llOi9tc2llLy50ZXN0KHVzZXJBZ2VudCkmJiEvb3BlcmEvLnRlc3QodXNlckFnZW50 KSxtb3ppbGxhOi9tb3ppbGxhLy50ZXN0KHVzZXJBZ2VudCkmJiEvKGNvbXBhdGlibGV8d2Via2l0 KS8udGVzdCh1c2VyQWdlbnQpfTt2YXIgc3R5bGVGbG9hdD1qUXVlcnkuYnJvd3Nlci5tc2llPyJz dHlsZUZsb2F0IjoiY3NzRmxvYXQiO2pRdWVyeS5leHRlbmQoe2JveE1vZGVsOiFqUXVlcnkuYnJv d3Nlci5tc2llfHxkb2N1bWVudC5jb21wYXRNb2RlPT0iQ1NTMUNvbXBhdCIscHJvcHM6eyJmb3Ii OiJodG1sRm9yIiwiY2xhc3MiOiJjbGFzc05hbWUiLCJmbG9hdCI6c3R5bGVGbG9hdCxjc3NGbG9h dDpzdHlsZUZsb2F0LHN0eWxlRmxvYXQ6c3R5bGVGbG9hdCxyZWFkb25seToicmVhZE9ubHkiLG1h eGxlbmd0aDoibWF4TGVuZ3RoIixjZWxsc3BhY2luZzoiY2VsbFNwYWNpbmcifX0pO2pRdWVyeS5l YWNoKHtwYXJlbnQ6ZnVuY3Rpb24oZWxlbSl7cmV0dXJuIGVsZW0ucGFyZW50Tm9kZTt9LHBhcmVu dHM6ZnVuY3Rpb24oZWxlbSl7cmV0dXJuIGpRdWVyeS5kaXIoZWxlbSwicGFyZW50Tm9kZSIpO30s bmV4dDpmdW5jdGlvbihlbGVtKXtyZXR1cm4galF1ZXJ5Lm50aChlbGVtLDIsIm5leHRTaWJsaW5n Iik7fSxwcmV2OmZ1bmN0aW9uKGVsZW0pe3JldHVybiBqUXVlcnkubnRoKGVsZW0sMiwicHJldmlv dXNTaWJsaW5nIik7fSxuZXh0QWxsOmZ1bmN0aW9uKGVsZW0pe3JldHVybiBqUXVlcnkuZGlyKGVs ZW0sIm5leHRTaWJsaW5nIik7fSxwcmV2QWxsOmZ1bmN0aW9uKGVsZW0pe3JldHVybiBqUXVlcnku ZGlyKGVsZW0sInByZXZpb3VzU2libGluZyIpO30sc2libGluZ3M6ZnVuY3Rpb24oZWxlbSl7cmV0 dXJuIGpRdWVyeS5zaWJsaW5nKGVsZW0ucGFyZW50Tm9kZS5maXJzdENoaWxkLGVsZW0pO30sY2hp bGRyZW46ZnVuY3Rpb24oZWxlbSl7cmV0dXJuIGpRdWVyeS5zaWJsaW5nKGVsZW0uZmlyc3RDaGls ZCk7fSxjb250ZW50czpmdW5jdGlvbihlbGVtKXtyZXR1cm4galF1ZXJ5Lm5vZGVOYW1lKGVsZW0s ImlmcmFtZSIpP2VsZW0uY29udGVudERvY3VtZW50fHxlbGVtLmNvbnRlbnRXaW5kb3cuZG9jdW1l bnQ6alF1ZXJ5Lm1ha2VBcnJheShlbGVtLmNoaWxkTm9kZXMpO319LGZ1bmN0aW9uKG5hbWUsZm4p e2pRdWVyeS5mbltuYW1lXT1mdW5jdGlvbihzZWxlY3Rvcil7dmFyIHJldD1qUXVlcnkubWFwKHRo aXMsZm4pO2lmKHNlbGVjdG9yJiZ0eXBlb2Ygc2VsZWN0b3I9PSJzdHJpbmciKXJldD1qUXVlcnku bXVsdGlGaWx0ZXIoc2VsZWN0b3IscmV0KTtyZXR1cm4gdGhpcy5wdXNoU3RhY2soalF1ZXJ5LnVu aXF1ZShyZXQpKTt9O30pO2pRdWVyeS5lYWNoKHthcHBlbmRUbzoiYXBwZW5kIixwcmVwZW5kVG86 InByZXBlbmQiLGluc2VydEJlZm9yZToiYmVmb3JlIixpbnNlcnRBZnRlcjoiYWZ0ZXIiLHJlcGxh Y2VBbGw6InJlcGxhY2VXaXRoIn0sZnVuY3Rpb24obmFtZSxvcmlnaW5hbCl7alF1ZXJ5LmZuW25h bWVdPWZ1bmN0aW9uKCl7dmFyIGFyZ3M9YXJndW1lbnRzO3JldHVybiB0aGlzLmVhY2goZnVuY3Rp b24oKXtmb3IodmFyIGk9MCxsZW5ndGg9YXJncy5sZW5ndGg7aTxsZW5ndGg7aSsrKWpRdWVyeShh cmdzW2ldKVtvcmlnaW5hbF0odGhpcyk7fSk7fTt9KTtqUXVlcnkuZWFjaCh7cmVtb3ZlQXR0cjpm dW5jdGlvbihuYW1lKXtqUXVlcnkuYXR0cih0aGlzLG5hbWUsIiIpO2lmKHRoaXMubm9kZVR5cGU9 PTEpdGhpcy5yZW1vdmVBdHRyaWJ1dGUobmFtZSk7fSxhZGRDbGFzczpmdW5jdGlvbihjbGFzc05h bWVzKXtqUXVlcnkuY2xhc3NOYW1lLmFkZCh0aGlzLGNsYXNzTmFtZXMpO30scmVtb3ZlQ2xhc3M6 ZnVuY3Rpb24oY2xhc3NOYW1lcyl7alF1ZXJ5LmNsYXNzTmFtZS5yZW1vdmUodGhpcyxjbGFzc05h bWVzKTt9LHRvZ2dsZUNsYXNzOmZ1bmN0aW9uKGNsYXNzTmFtZXMpe2pRdWVyeS5jbGFzc05hbWVb alF1ZXJ5LmNsYXNzTmFtZS5oYXModGhpcyxjbGFzc05hbWVzKT8icmVtb3ZlIjoiYWRkIl0odGhp cyxjbGFzc05hbWVzKTt9LHJlbW92ZTpmdW5jdGlvbihzZWxlY3Rvcil7aWYoIXNlbGVjdG9yfHxq UXVlcnkuZmlsdGVyKHNlbGVjdG9yLFt0aGlzXSkuci5sZW5ndGgpe2pRdWVyeSgiKiIsdGhpcyku YWRkKHRoaXMpLmVhY2goZnVuY3Rpb24oKXtqUXVlcnkuZXZlbnQucmVtb3ZlKHRoaXMpO2pRdWVy eS5yZW1vdmVEYXRhKHRoaXMpO30pO2lmKHRoaXMucGFyZW50Tm9kZSl0aGlzLnBhcmVudE5vZGUu cmVtb3ZlQ2hpbGQodGhpcyk7fX0sZW1wdHk6ZnVuY3Rpb24oKXtqUXVlcnkoIj4qIix0aGlzKS5y ZW1vdmUoKTt3aGlsZSh0aGlzLmZpcnN0Q2hpbGQpdGhpcy5yZW1vdmVDaGlsZCh0aGlzLmZpcnN0 Q2hpbGQpO319LGZ1bmN0aW9uKG5hbWUsZm4pe2pRdWVyeS5mbltuYW1lXT1mdW5jdGlvbigpe3Jl dHVybiB0aGlzLmVhY2goZm4sYXJndW1lbnRzKTt9O30pO2pRdWVyeS5lYWNoKFsiSGVpZ2h0Iiwi V2lkdGgiXSxmdW5jdGlvbihpLG5hbWUpe3ZhciB0eXBlPW5hbWUudG9Mb3dlckNhc2UoKTtqUXVl cnkuZm5bdHlwZV09ZnVuY3Rpb24oc2l6ZSl7cmV0dXJuIHRoaXNbMF09PXdpbmRvdz9qUXVlcnku YnJvd3Nlci5vcGVyYSYmZG9jdW1lbnQuYm9keVsiY2xpZW50IituYW1lXXx8alF1ZXJ5LmJyb3dz ZXIuc2FmYXJpJiZ3aW5kb3dbImlubmVyIituYW1lXXx8ZG9jdW1lbnQuY29tcGF0TW9kZT09IkNT UzFDb21wYXQiJiZkb2N1bWVudC5kb2N1bWVudEVsZW1lbnRbImNsaWVudCIrbmFtZV18fGRvY3Vt ZW50LmJvZHlbImNsaWVudCIrbmFtZV06dGhpc1swXT09ZG9jdW1lbnQ/TWF0aC5tYXgoTWF0aC5t YXgoZG9jdW1lbnQuYm9keVsic2Nyb2xsIituYW1lXSxkb2N1bWVudC5kb2N1bWVudEVsZW1lbnRb InNjcm9sbCIrbmFtZV0pLE1hdGgubWF4KGRvY3VtZW50LmJvZHlbIm9mZnNldCIrbmFtZV0sZG9j dW1lbnQuZG9jdW1lbnRFbGVtZW50WyJvZmZzZXQiK25hbWVdKSk6c2l6ZT09dW5kZWZpbmVkPyh0 aGlzLmxlbmd0aD9qUXVlcnkuY3NzKHRoaXNbMF0sdHlwZSk6bnVsbCk6dGhpcy5jc3ModHlwZSxz aXplLmNvbnN0cnVjdG9yPT1TdHJpbmc/c2l6ZTpzaXplKyJweCIpO307fSk7ZnVuY3Rpb24gbnVt KGVsZW0scHJvcCl7cmV0dXJuIGVsZW1bMF0mJnBhcnNlSW50KGpRdWVyeS5jdXJDU1MoZWxlbVsw XSxwcm9wLHRydWUpLDEwKXx8MDt9dmFyIGNoYXJzPWpRdWVyeS5icm93c2VyLnNhZmFyaSYmcGFy c2VJbnQoalF1ZXJ5LmJyb3dzZXIudmVyc2lvbik8NDE3PyIoPzpbXFx3Kl8tXXxcXFxcLikiOiIo PzpbXFx3XHUwMTI4LVx1RkZGRipfLV18XFxcXC4pIixxdWlja0NoaWxkPW5ldyBSZWdFeHAoIl4+ XFxzKigiK2NoYXJzKyIrKSIpLHF1aWNrSUQ9bmV3IFJlZ0V4cCgiXigiK2NoYXJzKyIrKSgjKSgi K2NoYXJzKyIrKSIpLHF1aWNrQ2xhc3M9bmV3IFJlZ0V4cCgiXihbIy5dPykoIitjaGFycysiKiki KTtqUXVlcnkuZXh0ZW5kKHtleHByOnsiIjpmdW5jdGlvbihhLGksbSl7cmV0dXJuIG1bMl09PSIq Inx8alF1ZXJ5Lm5vZGVOYW1lKGEsbVsyXSk7fSwiIyI6ZnVuY3Rpb24oYSxpLG0pe3JldHVybiBh LmdldEF0dHJpYnV0ZSgiaWQiKT09bVsyXTt9LCI6Ijp7bHQ6ZnVuY3Rpb24oYSxpLG0pe3JldHVy biBpPG1bM10tMDt9LGd0OmZ1bmN0aW9uKGEsaSxtKXtyZXR1cm4gaT5tWzNdLTA7fSxudGg6ZnVu Y3Rpb24oYSxpLG0pe3JldHVybiBtWzNdLTA9PWk7fSxlcTpmdW5jdGlvbihhLGksbSl7cmV0dXJu IG1bM10tMD09aTt9LGZpcnN0OmZ1bmN0aW9uKGEsaSl7cmV0dXJuIGk9PTA7fSxsYXN0OmZ1bmN0 aW9uKGEsaSxtLHIpe3JldHVybiBpPT1yLmxlbmd0aC0xO30sZXZlbjpmdW5jdGlvbihhLGkpe3Jl dHVybiBpJTI9PTA7fSxvZGQ6ZnVuY3Rpb24oYSxpKXtyZXR1cm4gaSUyO30sImZpcnN0LWNoaWxk IjpmdW5jdGlvbihhKXtyZXR1cm4gYS5wYXJlbnROb2RlLmdldEVsZW1lbnRzQnlUYWdOYW1lKCIq IilbMF09PWE7fSwibGFzdC1jaGlsZCI6ZnVuY3Rpb24oYSl7cmV0dXJuIGpRdWVyeS5udGgoYS5w YXJlbnROb2RlLmxhc3RDaGlsZCwxLCJwcmV2aW91c1NpYmxpbmciKT09YTt9LCJvbmx5LWNoaWxk IjpmdW5jdGlvbihhKXtyZXR1cm4halF1ZXJ5Lm50aChhLnBhcmVudE5vZGUubGFzdENoaWxkLDIs InByZXZpb3VzU2libGluZyIpO30scGFyZW50OmZ1bmN0aW9uKGEpe3JldHVybiBhLmZpcnN0Q2hp bGQ7fSxlbXB0eTpmdW5jdGlvbihhKXtyZXR1cm4hYS5maXJzdENoaWxkO30sY29udGFpbnM6ZnVu Y3Rpb24oYSxpLG0pe3JldHVybihhLnRleHRDb250ZW50fHxhLmlubmVyVGV4dHx8alF1ZXJ5KGEp LnRleHQoKXx8IiIpLmluZGV4T2YobVszXSk+PTA7fSx2aXNpYmxlOmZ1bmN0aW9uKGEpe3JldHVy biJoaWRkZW4iIT1hLnR5cGUmJmpRdWVyeS5jc3MoYSwiZGlzcGxheSIpIT0ibm9uZSImJmpRdWVy eS5jc3MoYSwidmlzaWJpbGl0eSIpIT0iaGlkZGVuIjt9LGhpZGRlbjpmdW5jdGlvbihhKXtyZXR1 cm4iaGlkZGVuIj09YS50eXBlfHxqUXVlcnkuY3NzKGEsImRpc3BsYXkiKT09Im5vbmUifHxqUXVl cnkuY3NzKGEsInZpc2liaWxpdHkiKT09ImhpZGRlbiI7fSxlbmFibGVkOmZ1bmN0aW9uKGEpe3Jl dHVybiFhLmRpc2FibGVkO30sZGlzYWJsZWQ6ZnVuY3Rpb24oYSl7cmV0dXJuIGEuZGlzYWJsZWQ7 fSxjaGVja2VkOmZ1bmN0aW9uKGEpe3JldHVybiBhLmNoZWNrZWQ7fSxzZWxlY3RlZDpmdW5jdGlv bihhKXtyZXR1cm4gYS5zZWxlY3RlZHx8alF1ZXJ5LmF0dHIoYSwic2VsZWN0ZWQiKTt9LHRleHQ6 ZnVuY3Rpb24oYSl7cmV0dXJuInRleHQiPT1hLnR5cGU7fSxyYWRpbzpmdW5jdGlvbihhKXtyZXR1 cm4icmFkaW8iPT1hLnR5cGU7fSxjaGVja2JveDpmdW5jdGlvbihhKXtyZXR1cm4iY2hlY2tib3gi PT1hLnR5cGU7fSxmaWxlOmZ1bmN0aW9uKGEpe3JldHVybiJmaWxlIj09YS50eXBlO30scGFzc3dv cmQ6ZnVuY3Rpb24oYSl7cmV0dXJuInBhc3N3b3JkIj09YS50eXBlO30sc3VibWl0OmZ1bmN0aW9u KGEpe3JldHVybiJzdWJtaXQiPT1hLnR5cGU7fSxpbWFnZTpmdW5jdGlvbihhKXtyZXR1cm4iaW1h Z2UiPT1hLnR5cGU7fSxyZXNldDpmdW5jdGlvbihhKXtyZXR1cm4icmVzZXQiPT1hLnR5cGU7fSxi dXR0b246ZnVuY3Rpb24oYSl7cmV0dXJuImJ1dHRvbiI9PWEudHlwZXx8alF1ZXJ5Lm5vZGVOYW1l KGEsImJ1dHRvbiIpO30saW5wdXQ6ZnVuY3Rpb24oYSl7cmV0dXJuL2lucHV0fHNlbGVjdHx0ZXh0 YXJlYXxidXR0b24vaS50ZXN0KGEubm9kZU5hbWUpO30saGFzOmZ1bmN0aW9uKGEsaSxtKXtyZXR1 cm4galF1ZXJ5LmZpbmQobVszXSxhKS5sZW5ndGg7fSxoZWFkZXI6ZnVuY3Rpb24oYSl7cmV0dXJu L2hcZC9pLnRlc3QoYS5ub2RlTmFtZSk7fSxhbmltYXRlZDpmdW5jdGlvbihhKXtyZXR1cm4galF1 ZXJ5LmdyZXAoalF1ZXJ5LnRpbWVycyxmdW5jdGlvbihmbil7cmV0dXJuIGE9PWZuLmVsZW07fSku bGVuZ3RoO319fSxwYXJzZTpbL14oXFspICpAPyhbXHctXSspICooWyEqJF5+PV0qKSAqKCc/Ij8p KC4qPylcNCAqXF0vLC9eKDopKFtcdy1dKylcKCI/Jz8oLio/KFwoLio/XCkpP1teKF0qPykiPyc/ XCkvLG5ldyBSZWdFeHAoIl4oWzouI10qKSgiK2NoYXJzKyIrKSIpXSxtdWx0aUZpbHRlcjpmdW5j dGlvbihleHByLGVsZW1zLG5vdCl7dmFyIG9sZCxjdXI9W107d2hpbGUoZXhwciYmZXhwciE9b2xk KXtvbGQ9ZXhwcjt2YXIgZj1qUXVlcnkuZmlsdGVyKGV4cHIsZWxlbXMsbm90KTtleHByPWYudC5y ZXBsYWNlKC9eXHMqLFxzKi8sIiIpO2N1cj1ub3Q/ZWxlbXM9Zi5yOmpRdWVyeS5tZXJnZShjdXIs Zi5yKTt9cmV0dXJuIGN1cjt9LGZpbmQ6ZnVuY3Rpb24odCxjb250ZXh0KXtpZih0eXBlb2YgdCE9 InN0cmluZyIpcmV0dXJuW3RdO2lmKGNvbnRleHQmJmNvbnRleHQubm9kZVR5cGUhPTEmJmNvbnRl eHQubm9kZVR5cGUhPTkpcmV0dXJuW107Y29udGV4dD1jb250ZXh0fHxkb2N1bWVudDt2YXIgcmV0 PVtjb250ZXh0XSxkb25lPVtdLGxhc3Qsbm9kZU5hbWU7d2hpbGUodCYmbGFzdCE9dCl7dmFyIHI9 W107bGFzdD10O3Q9alF1ZXJ5LnRyaW0odCk7dmFyIGZvdW5kVG9rZW49ZmFsc2UscmU9cXVpY2tD aGlsZCxtPXJlLmV4ZWModCk7aWYobSl7bm9kZU5hbWU9bVsxXS50b1VwcGVyQ2FzZSgpO2Zvcih2 YXIgaT0wO3JldFtpXTtpKyspZm9yKHZhciBjPXJldFtpXS5maXJzdENoaWxkO2M7Yz1jLm5leHRT aWJsaW5nKWlmKGMubm9kZVR5cGU9PTEmJihub2RlTmFtZT09IioifHxjLm5vZGVOYW1lLnRvVXBw ZXJDYXNlKCk9PW5vZGVOYW1lKSlyLnB1c2goYyk7cmV0PXI7dD10LnJlcGxhY2UocmUsIiIpO2lm KHQuaW5kZXhPZigiICIpPT0wKWNvbnRpbnVlO2ZvdW5kVG9rZW49dHJ1ZTt9ZWxzZXtyZT0vXihb Pit+XSlccyooXHcqKS9pO2lmKChtPXJlLmV4ZWModCkpIT1udWxsKXtyPVtdO3ZhciBtZXJnZT17 fTtub2RlTmFtZT1tWzJdLnRvVXBwZXJDYXNlKCk7bT1tWzFdO2Zvcih2YXIgaj0wLHJsPXJldC5s ZW5ndGg7ajxybDtqKyspe3ZhciBuPW09PSJ+Inx8bT09IisiP3JldFtqXS5uZXh0U2libGluZzpy ZXRbal0uZmlyc3RDaGlsZDtmb3IoO247bj1uLm5leHRTaWJsaW5nKWlmKG4ubm9kZVR5cGU9PTEp e3ZhciBpZD1qUXVlcnkuZGF0YShuKTtpZihtPT0ifiImJm1lcmdlW2lkXSlicmVhaztpZighbm9k ZU5hbWV8fG4ubm9kZU5hbWUudG9VcHBlckNhc2UoKT09bm9kZU5hbWUpe2lmKG09PSJ+IiltZXJn ZVtpZF09dHJ1ZTtyLnB1c2gobik7fWlmKG09PSIrIilicmVhazt9fXJldD1yO3Q9alF1ZXJ5LnRy aW0odC5yZXBsYWNlKHJlLCIiKSk7Zm91bmRUb2tlbj10cnVlO319aWYodCYmIWZvdW5kVG9rZW4p e2lmKCF0LmluZGV4T2YoIiwiKSl7aWYoY29udGV4dD09cmV0WzBdKXJldC5zaGlmdCgpO2RvbmU9 alF1ZXJ5Lm1lcmdlKGRvbmUscmV0KTtyPXJldD1bY29udGV4dF07dD0iICIrdC5zdWJzdHIoMSx0 Lmxlbmd0aCk7fWVsc2V7dmFyIHJlMj1xdWlja0lEO3ZhciBtPXJlMi5leGVjKHQpO2lmKG0pe209 WzAsbVsyXSxtWzNdLG1bMV1dO31lbHNle3JlMj1xdWlja0NsYXNzO209cmUyLmV4ZWModCk7fW1b Ml09bVsyXS5yZXBsYWNlKC9cXC9nLCIiKTt2YXIgZWxlbT1yZXRbcmV0Lmxlbmd0aC0xXTtpZiht WzFdPT0iIyImJmVsZW0mJmVsZW0uZ2V0RWxlbWVudEJ5SWQmJiFqUXVlcnkuaXNYTUxEb2MoZWxl bSkpe3ZhciBvaWQ9ZWxlbS5nZXRFbGVtZW50QnlJZChtWzJdKTtpZigoalF1ZXJ5LmJyb3dzZXIu bXNpZXx8alF1ZXJ5LmJyb3dzZXIub3BlcmEpJiZvaWQmJnR5cGVvZiBvaWQuaWQ9PSJzdHJpbmci JiZvaWQuaWQhPW1bMl0pb2lkPWpRdWVyeSgnW0BpZD0iJyttWzJdKyciXScsZWxlbSlbMF07cmV0 PXI9b2lkJiYoIW1bM118fGpRdWVyeS5ub2RlTmFtZShvaWQsbVszXSkpP1tvaWRdOltdO31lbHNl e2Zvcih2YXIgaT0wO3JldFtpXTtpKyspe3ZhciB0YWc9bVsxXT09IiMiJiZtWzNdP21bM106bVsx XSE9IiJ8fG1bMF09PSIiPyIqIjptWzJdO2lmKHRhZz09IioiJiZyZXRbaV0ubm9kZU5hbWUudG9M b3dlckNhc2UoKT09Im9iamVjdCIpdGFnPSJwYXJhbSI7cj1qUXVlcnkubWVyZ2UocixyZXRbaV0u Z2V0RWxlbWVudHNCeVRhZ05hbWUodGFnKSk7fWlmKG1bMV09PSIuIilyPWpRdWVyeS5jbGFzc0Zp bHRlcihyLG1bMl0pO2lmKG1bMV09PSIjIil7dmFyIHRtcD1bXTtmb3IodmFyIGk9MDtyW2ldO2kr KylpZihyW2ldLmdldEF0dHJpYnV0ZSgiaWQiKT09bVsyXSl7dG1wPVtyW2ldXTticmVhazt9cj10 bXA7fXJldD1yO310PXQucmVwbGFjZShyZTIsIiIpO319aWYodCl7dmFyIHZhbD1qUXVlcnkuZmls dGVyKHQscik7cmV0PXI9dmFsLnI7dD1qUXVlcnkudHJpbSh2YWwudCk7fX1pZih0KXJldD1bXTtp ZihyZXQmJmNvbnRleHQ9PXJldFswXSlyZXQuc2hpZnQoKTtkb25lPWpRdWVyeS5tZXJnZShkb25l LHJldCk7cmV0dXJuIGRvbmU7fSxjbGFzc0ZpbHRlcjpmdW5jdGlvbihyLG0sbm90KXttPSIgIitt KyIgIjt2YXIgdG1wPVtdO2Zvcih2YXIgaT0wO3JbaV07aSsrKXt2YXIgcGFzcz0oIiAiK3JbaV0u Y2xhc3NOYW1lKyIgIikuaW5kZXhPZihtKT49MDtpZighbm90JiZwYXNzfHxub3QmJiFwYXNzKXRt cC5wdXNoKHJbaV0pO31yZXR1cm4gdG1wO30sZmlsdGVyOmZ1bmN0aW9uKHQscixub3Qpe3ZhciBs YXN0O3doaWxlKHQmJnQhPWxhc3Qpe2xhc3Q9dDt2YXIgcD1qUXVlcnkucGFyc2UsbTtmb3IodmFy IGk9MDtwW2ldO2krKyl7bT1wW2ldLmV4ZWModCk7aWYobSl7dD10LnN1YnN0cmluZyhtWzBdLmxl bmd0aCk7bVsyXT1tWzJdLnJlcGxhY2UoL1xcL2csIiIpO2JyZWFrO319aWYoIW0pYnJlYWs7aWYo bVsxXT09IjoiJiZtWzJdPT0ibm90IilyPWlzU2ltcGxlLnRlc3QobVszXSk/alF1ZXJ5LmZpbHRl cihtWzNdLHIsdHJ1ZSkucjpqUXVlcnkocikubm90KG1bM10pO2Vsc2UgaWYobVsxXT09Ii4iKXI9 alF1ZXJ5LmNsYXNzRmlsdGVyKHIsbVsyXSxub3QpO2Vsc2UgaWYobVsxXT09IlsiKXt2YXIgdG1w PVtdLHR5cGU9bVszXTtmb3IodmFyIGk9MCxybD1yLmxlbmd0aDtpPHJsO2krKyl7dmFyIGE9cltp XSx6PWFbalF1ZXJ5LnByb3BzW21bMl1dfHxtWzJdXTtpZih6PT1udWxsfHwvaHJlZnxzcmN8c2Vs ZWN0ZWQvLnRlc3QobVsyXSkpej1qUXVlcnkuYXR0cihhLG1bMl0pfHwnJztpZigodHlwZT09IiIm JiEhenx8dHlwZT09Ij0iJiZ6PT1tWzVdfHx0eXBlPT0iIT0iJiZ6IT1tWzVdfHx0eXBlPT0iXj0i JiZ6JiYhei5pbmRleE9mKG1bNV0pfHx0eXBlPT0iJD0iJiZ6LnN1YnN0cih6Lmxlbmd0aC1tWzVd Lmxlbmd0aCk9PW1bNV18fCh0eXBlPT0iKj0ifHx0eXBlPT0ifj0iKSYmei5pbmRleE9mKG1bNV0p Pj0wKV5ub3QpdG1wLnB1c2goYSk7fXI9dG1wO31lbHNlIGlmKG1bMV09PSI6IiYmbVsyXT09Im50 aC1jaGlsZCIpe3ZhciBtZXJnZT17fSx0bXA9W10sdGVzdD0vKC0/KShcZCopbigoPzpcK3wtKT9c ZCopLy5leGVjKG1bM109PSJldmVuIiYmIjJuInx8bVszXT09Im9kZCImJiIybisxInx8IS9cRC8u dGVzdChtWzNdKSYmIjBuKyIrbVszXXx8bVszXSksZmlyc3Q9KHRlc3RbMV0rKHRlc3RbMl18fDEp KS0wLGxhc3Q9dGVzdFszXS0wO2Zvcih2YXIgaT0wLHJsPXIubGVuZ3RoO2k8cmw7aSsrKXt2YXIg bm9kZT1yW2ldLHBhcmVudE5vZGU9bm9kZS5wYXJlbnROb2RlLGlkPWpRdWVyeS5kYXRhKHBhcmVu dE5vZGUpO2lmKCFtZXJnZVtpZF0pe3ZhciBjPTE7Zm9yKHZhciBuPXBhcmVudE5vZGUuZmlyc3RD aGlsZDtuO249bi5uZXh0U2libGluZylpZihuLm5vZGVUeXBlPT0xKW4ubm9kZUluZGV4PWMrKztt ZXJnZVtpZF09dHJ1ZTt9dmFyIGFkZD1mYWxzZTtpZihmaXJzdD09MCl7aWYobm9kZS5ub2RlSW5k ZXg9PWxhc3QpYWRkPXRydWU7fWVsc2UgaWYoKG5vZGUubm9kZUluZGV4LWxhc3QpJWZpcnN0PT0w JiYobm9kZS5ub2RlSW5kZXgtbGFzdCkvZmlyc3Q+PTApYWRkPXRydWU7aWYoYWRkXm5vdCl0bXAu cHVzaChub2RlKTt9cj10bXA7fWVsc2V7dmFyIGZuPWpRdWVyeS5leHByW21bMV1dO2lmKHR5cGVv ZiBmbj09Im9iamVjdCIpZm49Zm5bbVsyXV07aWYodHlwZW9mIGZuPT0ic3RyaW5nIilmbj1ldmFs KCJmYWxzZXx8ZnVuY3Rpb24oYSxpKXtyZXR1cm4gIitmbisiO30iKTtyPWpRdWVyeS5ncmVwKHIs ZnVuY3Rpb24oZWxlbSxpKXtyZXR1cm4gZm4oZWxlbSxpLG0scik7fSxub3QpO319cmV0dXJue3I6 cix0OnR9O30sZGlyOmZ1bmN0aW9uKGVsZW0sZGlyKXt2YXIgbWF0Y2hlZD1bXSxjdXI9ZWxlbVtk aXJdO3doaWxlKGN1ciYmY3VyIT1kb2N1bWVudCl7aWYoY3VyLm5vZGVUeXBlPT0xKW1hdGNoZWQu cHVzaChjdXIpO2N1cj1jdXJbZGlyXTt9cmV0dXJuIG1hdGNoZWQ7fSxudGg6ZnVuY3Rpb24oY3Vy LHJlc3VsdCxkaXIsZWxlbSl7cmVzdWx0PXJlc3VsdHx8MTt2YXIgbnVtPTA7Zm9yKDtjdXI7Y3Vy PWN1cltkaXJdKWlmKGN1ci5ub2RlVHlwZT09MSYmKytudW09PXJlc3VsdClicmVhaztyZXR1cm4g Y3VyO30sc2libGluZzpmdW5jdGlvbihuLGVsZW0pe3ZhciByPVtdO2Zvcig7bjtuPW4ubmV4dFNp Ymxpbmcpe2lmKG4ubm9kZVR5cGU9PTEmJm4hPWVsZW0pci5wdXNoKG4pO31yZXR1cm4gcjt9fSk7 alF1ZXJ5LmV2ZW50PXthZGQ6ZnVuY3Rpb24oZWxlbSx0eXBlcyxoYW5kbGVyLGRhdGEpe2lmKGVs ZW0ubm9kZVR5cGU9PTN8fGVsZW0ubm9kZVR5cGU9PTgpcmV0dXJuO2lmKGpRdWVyeS5icm93c2Vy Lm1zaWUmJmVsZW0uc2V0SW50ZXJ2YWwpZWxlbT13aW5kb3c7aWYoIWhhbmRsZXIuZ3VpZCloYW5k bGVyLmd1aWQ9dGhpcy5ndWlkKys7aWYoZGF0YSE9dW5kZWZpbmVkKXt2YXIgZm49aGFuZGxlcjto YW5kbGVyPXRoaXMucHJveHkoZm4sZnVuY3Rpb24oKXtyZXR1cm4gZm4uYXBwbHkodGhpcyxhcmd1 bWVudHMpO30pO2hhbmRsZXIuZGF0YT1kYXRhO312YXIgZXZlbnRzPWpRdWVyeS5kYXRhKGVsZW0s ImV2ZW50cyIpfHxqUXVlcnkuZGF0YShlbGVtLCJldmVudHMiLHt9KSxoYW5kbGU9alF1ZXJ5LmRh dGEoZWxlbSwiaGFuZGxlIil8fGpRdWVyeS5kYXRhKGVsZW0sImhhbmRsZSIsZnVuY3Rpb24oKXtp Zih0eXBlb2YgalF1ZXJ5IT0idW5kZWZpbmVkIiYmIWpRdWVyeS5ldmVudC50cmlnZ2VyZWQpcmV0 dXJuIGpRdWVyeS5ldmVudC5oYW5kbGUuYXBwbHkoYXJndW1lbnRzLmNhbGxlZS5lbGVtLGFyZ3Vt ZW50cyk7fSk7aGFuZGxlLmVsZW09ZWxlbTtqUXVlcnkuZWFjaCh0eXBlcy5zcGxpdCgvXHMrLyks ZnVuY3Rpb24oaW5kZXgsdHlwZSl7dmFyIHBhcnRzPXR5cGUuc3BsaXQoIi4iKTt0eXBlPXBhcnRz WzBdO2hhbmRsZXIudHlwZT1wYXJ0c1sxXTt2YXIgaGFuZGxlcnM9ZXZlbnRzW3R5cGVdO2lmKCFo YW5kbGVycyl7aGFuZGxlcnM9ZXZlbnRzW3R5cGVdPXt9O2lmKCFqUXVlcnkuZXZlbnQuc3BlY2lh bFt0eXBlXXx8alF1ZXJ5LmV2ZW50LnNwZWNpYWxbdHlwZV0uc2V0dXAuY2FsbChlbGVtKT09PWZh bHNlKXtpZihlbGVtLmFkZEV2ZW50TGlzdGVuZXIpZWxlbS5hZGRFdmVudExpc3RlbmVyKHR5cGUs aGFuZGxlLGZhbHNlKTtlbHNlIGlmKGVsZW0uYXR0YWNoRXZlbnQpZWxlbS5hdHRhY2hFdmVudCgi b24iK3R5cGUsaGFuZGxlKTt9fWhhbmRsZXJzW2hhbmRsZXIuZ3VpZF09aGFuZGxlcjtqUXVlcnku ZXZlbnQuZ2xvYmFsW3R5cGVdPXRydWU7fSk7ZWxlbT1udWxsO30sZ3VpZDoxLGdsb2JhbDp7fSxy ZW1vdmU6ZnVuY3Rpb24oZWxlbSx0eXBlcyxoYW5kbGVyKXtpZihlbGVtLm5vZGVUeXBlPT0zfHxl bGVtLm5vZGVUeXBlPT04KXJldHVybjt2YXIgZXZlbnRzPWpRdWVyeS5kYXRhKGVsZW0sImV2ZW50 cyIpLHJldCxpbmRleDtpZihldmVudHMpe2lmKHR5cGVzPT11bmRlZmluZWR8fCh0eXBlb2YgdHlw ZXM9PSJzdHJpbmciJiZ0eXBlcy5jaGFyQXQoMCk9PSIuIikpZm9yKHZhciB0eXBlIGluIGV2ZW50 cyl0aGlzLnJlbW92ZShlbGVtLHR5cGUrKHR5cGVzfHwiIikpO2Vsc2V7aWYodHlwZXMudHlwZSl7 aGFuZGxlcj10eXBlcy5oYW5kbGVyO3R5cGVzPXR5cGVzLnR5cGU7fWpRdWVyeS5lYWNoKHR5cGVz LnNwbGl0KC9ccysvKSxmdW5jdGlvbihpbmRleCx0eXBlKXt2YXIgcGFydHM9dHlwZS5zcGxpdCgi LiIpO3R5cGU9cGFydHNbMF07aWYoZXZlbnRzW3R5cGVdKXtpZihoYW5kbGVyKWRlbGV0ZSBldmVu dHNbdHlwZV1baGFuZGxlci5ndWlkXTtlbHNlCitmb3IoaGFuZGxlciBpbiBldmVudHNbdHlwZV0p aWYoIXBhcnRzWzFdfHxldmVudHNbdHlwZV1baGFuZGxlcl0udHlwZT09cGFydHNbMV0pZGVsZXRl IGV2ZW50c1t0eXBlXVtoYW5kbGVyXTtmb3IocmV0IGluIGV2ZW50c1t0eXBlXSlicmVhaztpZigh cmV0KXtpZighalF1ZXJ5LmV2ZW50LnNwZWNpYWxbdHlwZV18fGpRdWVyeS5ldmVudC5zcGVjaWFs W3R5cGVdLnRlYXJkb3duLmNhbGwoZWxlbSk9PT1mYWxzZSl7aWYoZWxlbS5yZW1vdmVFdmVudExp c3RlbmVyKWVsZW0ucmVtb3ZlRXZlbnRMaXN0ZW5lcih0eXBlLGpRdWVyeS5kYXRhKGVsZW0sImhh bmRsZSIpLGZhbHNlKTtlbHNlIGlmKGVsZW0uZGV0YWNoRXZlbnQpZWxlbS5kZXRhY2hFdmVudCgi b24iK3R5cGUsalF1ZXJ5LmRhdGEoZWxlbSwiaGFuZGxlIikpO31yZXQ9bnVsbDtkZWxldGUgZXZl bnRzW3R5cGVdO319fSk7fWZvcihyZXQgaW4gZXZlbnRzKWJyZWFrO2lmKCFyZXQpe3ZhciBoYW5k bGU9alF1ZXJ5LmRhdGEoZWxlbSwiaGFuZGxlIik7aWYoaGFuZGxlKWhhbmRsZS5lbGVtPW51bGw7 alF1ZXJ5LnJlbW92ZURhdGEoZWxlbSwiZXZlbnRzIik7alF1ZXJ5LnJlbW92ZURhdGEoZWxlbSwi aGFuZGxlIik7fX19LHRyaWdnZXI6ZnVuY3Rpb24odHlwZSxkYXRhLGVsZW0sZG9uYXRpdmUsZXh0 cmEpe2RhdGE9alF1ZXJ5Lm1ha2VBcnJheShkYXRhKTtpZih0eXBlLmluZGV4T2YoIiEiKT49MCl7 dHlwZT10eXBlLnNsaWNlKDAsLTEpO3ZhciBleGNsdXNpdmU9dHJ1ZTt9aWYoIWVsZW0pe2lmKHRo aXMuZ2xvYmFsW3R5cGVdKWpRdWVyeSgiKiIpLmFkZChbd2luZG93LGRvY3VtZW50XSkudHJpZ2dl cih0eXBlLGRhdGEpO31lbHNle2lmKGVsZW0ubm9kZVR5cGU9PTN8fGVsZW0ubm9kZVR5cGU9PTgp cmV0dXJuIHVuZGVmaW5lZDt2YXIgdmFsLHJldCxmbj1qUXVlcnkuaXNGdW5jdGlvbihlbGVtW3R5 cGVdfHxudWxsKSxldmVudD0hZGF0YVswXXx8IWRhdGFbMF0ucHJldmVudERlZmF1bHQ7aWYoZXZl bnQpe2RhdGEudW5zaGlmdCh7dHlwZTp0eXBlLHRhcmdldDplbGVtLHByZXZlbnREZWZhdWx0OmZ1 bmN0aW9uKCl7fSxzdG9wUHJvcGFnYXRpb246ZnVuY3Rpb24oKXt9LHRpbWVTdGFtcDpub3coKX0p O2RhdGFbMF1bZXhwYW5kb109dHJ1ZTt9ZGF0YVswXS50eXBlPXR5cGU7aWYoZXhjbHVzaXZlKWRh dGFbMF0uZXhjbHVzaXZlPXRydWU7dmFyIGhhbmRsZT1qUXVlcnkuZGF0YShlbGVtLCJoYW5kbGUi KTtpZihoYW5kbGUpdmFsPWhhbmRsZS5hcHBseShlbGVtLGRhdGEpO2lmKCghZm58fChqUXVlcnku bm9kZU5hbWUoZWxlbSwnYScpJiZ0eXBlPT0iY2xpY2siKSkmJmVsZW1bIm9uIit0eXBlXSYmZWxl bVsib24iK3R5cGVdLmFwcGx5KGVsZW0sZGF0YSk9PT1mYWxzZSl2YWw9ZmFsc2U7aWYoZXZlbnQp ZGF0YS5zaGlmdCgpO2lmKGV4dHJhJiZqUXVlcnkuaXNGdW5jdGlvbihleHRyYSkpe3JldD1leHRy YS5hcHBseShlbGVtLHZhbD09bnVsbD9kYXRhOmRhdGEuY29uY2F0KHZhbCkpO2lmKHJldCE9PXVu ZGVmaW5lZCl2YWw9cmV0O31pZihmbiYmZG9uYXRpdmUhPT1mYWxzZSYmdmFsIT09ZmFsc2UmJiEo alF1ZXJ5Lm5vZGVOYW1lKGVsZW0sJ2EnKSYmdHlwZT09ImNsaWNrIikpe3RoaXMudHJpZ2dlcmVk PXRydWU7dHJ5e2VsZW1bdHlwZV0oKTt9Y2F0Y2goZSl7fX10aGlzLnRyaWdnZXJlZD1mYWxzZTt9 cmV0dXJuIHZhbDt9LGhhbmRsZTpmdW5jdGlvbihldmVudCl7dmFyIHZhbCxyZXQsbmFtZXNwYWNl LGFsbCxoYW5kbGVycztldmVudD1hcmd1bWVudHNbMF09alF1ZXJ5LmV2ZW50LmZpeChldmVudHx8 d2luZG93LmV2ZW50KTtuYW1lc3BhY2U9ZXZlbnQudHlwZS5zcGxpdCgiLiIpO2V2ZW50LnR5cGU9 bmFtZXNwYWNlWzBdO25hbWVzcGFjZT1uYW1lc3BhY2VbMV07YWxsPSFuYW1lc3BhY2UmJiFldmVu dC5leGNsdXNpdmU7aGFuZGxlcnM9KGpRdWVyeS5kYXRhKHRoaXMsImV2ZW50cyIpfHx7fSlbZXZl bnQudHlwZV07Zm9yKHZhciBqIGluIGhhbmRsZXJzKXt2YXIgaGFuZGxlcj1oYW5kbGVyc1tqXTtp ZihhbGx8fGhhbmRsZXIudHlwZT09bmFtZXNwYWNlKXtldmVudC5oYW5kbGVyPWhhbmRsZXI7ZXZl bnQuZGF0YT1oYW5kbGVyLmRhdGE7cmV0PWhhbmRsZXIuYXBwbHkodGhpcyxhcmd1bWVudHMpO2lm KHZhbCE9PWZhbHNlKXZhbD1yZXQ7aWYocmV0PT09ZmFsc2Upe2V2ZW50LnByZXZlbnREZWZhdWx0 KCk7ZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7fX19cmV0dXJuIHZhbDt9LGZpeDpmdW5jdGlvbihl dmVudCl7aWYoZXZlbnRbZXhwYW5kb109PXRydWUpcmV0dXJuIGV2ZW50O3ZhciBvcmlnaW5hbEV2 ZW50PWV2ZW50O2V2ZW50PXtvcmlnaW5hbEV2ZW50Om9yaWdpbmFsRXZlbnR9O3ZhciBwcm9wcz0i YWx0S2V5IGF0dHJDaGFuZ2UgYXR0ck5hbWUgYnViYmxlcyBidXR0b24gY2FuY2VsYWJsZSBjaGFy Q29kZSBjbGllbnRYIGNsaWVudFkgY3RybEtleSBjdXJyZW50VGFyZ2V0IGRhdGEgZGV0YWlsIGV2 ZW50UGhhc2UgZnJvbUVsZW1lbnQgaGFuZGxlciBrZXlDb2RlIG1ldGFLZXkgbmV3VmFsdWUgb3Jp Z2luYWxUYXJnZXQgcGFnZVggcGFnZVkgcHJldlZhbHVlIHJlbGF0ZWROb2RlIHJlbGF0ZWRUYXJn ZXQgc2NyZWVuWCBzY3JlZW5ZIHNoaWZ0S2V5IHNyY0VsZW1lbnQgdGFyZ2V0IHRpbWVTdGFtcCB0 b0VsZW1lbnQgdHlwZSB2aWV3IHdoZWVsRGVsdGEgd2hpY2giLnNwbGl0KCIgIik7Zm9yKHZhciBp PXByb3BzLmxlbmd0aDtpO2ktLSlldmVudFtwcm9wc1tpXV09b3JpZ2luYWxFdmVudFtwcm9wc1tp XV07ZXZlbnRbZXhwYW5kb109dHJ1ZTtldmVudC5wcmV2ZW50RGVmYXVsdD1mdW5jdGlvbigpe2lm KG9yaWdpbmFsRXZlbnQucHJldmVudERlZmF1bHQpb3JpZ2luYWxFdmVudC5wcmV2ZW50RGVmYXVs dCgpO29yaWdpbmFsRXZlbnQucmV0dXJuVmFsdWU9ZmFsc2U7fTtldmVudC5zdG9wUHJvcGFnYXRp b249ZnVuY3Rpb24oKXtpZihvcmlnaW5hbEV2ZW50LnN0b3BQcm9wYWdhdGlvbilvcmlnaW5hbEV2 ZW50LnN0b3BQcm9wYWdhdGlvbigpO29yaWdpbmFsRXZlbnQuY2FuY2VsQnViYmxlPXRydWU7fTtl dmVudC50aW1lU3RhbXA9ZXZlbnQudGltZVN0YW1wfHxub3coKTtpZighZXZlbnQudGFyZ2V0KWV2 ZW50LnRhcmdldD1ldmVudC5zcmNFbGVtZW50fHxkb2N1bWVudDtpZihldmVudC50YXJnZXQubm9k ZVR5cGU9PTMpZXZlbnQudGFyZ2V0PWV2ZW50LnRhcmdldC5wYXJlbnROb2RlO2lmKCFldmVudC5y ZWxhdGVkVGFyZ2V0JiZldmVudC5mcm9tRWxlbWVudClldmVudC5yZWxhdGVkVGFyZ2V0PWV2ZW50 LmZyb21FbGVtZW50PT1ldmVudC50YXJnZXQ/ZXZlbnQudG9FbGVtZW50OmV2ZW50LmZyb21FbGVt ZW50O2lmKGV2ZW50LnBhZ2VYPT1udWxsJiZldmVudC5jbGllbnRYIT1udWxsKXt2YXIgZG9jPWRv Y3VtZW50LmRvY3VtZW50RWxlbWVudCxib2R5PWRvY3VtZW50LmJvZHk7ZXZlbnQucGFnZVg9ZXZl bnQuY2xpZW50WCsoZG9jJiZkb2Muc2Nyb2xsTGVmdHx8Ym9keSYmYm9keS5zY3JvbGxMZWZ0fHww KS0oZG9jLmNsaWVudExlZnR8fDApO2V2ZW50LnBhZ2VZPWV2ZW50LmNsaWVudFkrKGRvYyYmZG9j LnNjcm9sbFRvcHx8Ym9keSYmYm9keS5zY3JvbGxUb3B8fDApLShkb2MuY2xpZW50VG9wfHwwKTt9 aWYoIWV2ZW50LndoaWNoJiYoKGV2ZW50LmNoYXJDb2RlfHxldmVudC5jaGFyQ29kZT09PTApP2V2 ZW50LmNoYXJDb2RlOmV2ZW50LmtleUNvZGUpKWV2ZW50LndoaWNoPWV2ZW50LmNoYXJDb2RlfHxl dmVudC5rZXlDb2RlO2lmKCFldmVudC5tZXRhS2V5JiZldmVudC5jdHJsS2V5KWV2ZW50Lm1ldGFL ZXk9ZXZlbnQuY3RybEtleTtpZighZXZlbnQud2hpY2gmJmV2ZW50LmJ1dHRvbilldmVudC53aGlj aD0oZXZlbnQuYnV0dG9uJjE/MTooZXZlbnQuYnV0dG9uJjI/MzooZXZlbnQuYnV0dG9uJjQ/Mjow KSkpO3JldHVybiBldmVudDt9LHByb3h5OmZ1bmN0aW9uKGZuLHByb3h5KXtwcm94eS5ndWlkPWZu Lmd1aWQ9Zm4uZ3VpZHx8cHJveHkuZ3VpZHx8dGhpcy5ndWlkKys7cmV0dXJuIHByb3h5O30sc3Bl Y2lhbDp7cmVhZHk6e3NldHVwOmZ1bmN0aW9uKCl7YmluZFJlYWR5KCk7cmV0dXJuO30sdGVhcmRv d246ZnVuY3Rpb24oKXtyZXR1cm47fX0sbW91c2VlbnRlcjp7c2V0dXA6ZnVuY3Rpb24oKXtpZihq UXVlcnkuYnJvd3Nlci5tc2llKXJldHVybiBmYWxzZTtqUXVlcnkodGhpcykuYmluZCgibW91c2Vv dmVyIixqUXVlcnkuZXZlbnQuc3BlY2lhbC5tb3VzZWVudGVyLmhhbmRsZXIpO3JldHVybiB0cnVl O30sdGVhcmRvd246ZnVuY3Rpb24oKXtpZihqUXVlcnkuYnJvd3Nlci5tc2llKXJldHVybiBmYWxz ZTtqUXVlcnkodGhpcykudW5iaW5kKCJtb3VzZW92ZXIiLGpRdWVyeS5ldmVudC5zcGVjaWFsLm1v dXNlZW50ZXIuaGFuZGxlcik7cmV0dXJuIHRydWU7fSxoYW5kbGVyOmZ1bmN0aW9uKGV2ZW50KXtp Zih3aXRoaW5FbGVtZW50KGV2ZW50LHRoaXMpKXJldHVybiB0cnVlO2V2ZW50LnR5cGU9Im1vdXNl ZW50ZXIiO3JldHVybiBqUXVlcnkuZXZlbnQuaGFuZGxlLmFwcGx5KHRoaXMsYXJndW1lbnRzKTt9 fSxtb3VzZWxlYXZlOntzZXR1cDpmdW5jdGlvbigpe2lmKGpRdWVyeS5icm93c2VyLm1zaWUpcmV0 dXJuIGZhbHNlO2pRdWVyeSh0aGlzKS5iaW5kKCJtb3VzZW91dCIsalF1ZXJ5LmV2ZW50LnNwZWNp YWwubW91c2VsZWF2ZS5oYW5kbGVyKTtyZXR1cm4gdHJ1ZTt9LHRlYXJkb3duOmZ1bmN0aW9uKCl7 aWYoalF1ZXJ5LmJyb3dzZXIubXNpZSlyZXR1cm4gZmFsc2U7alF1ZXJ5KHRoaXMpLnVuYmluZCgi bW91c2VvdXQiLGpRdWVyeS5ldmVudC5zcGVjaWFsLm1vdXNlbGVhdmUuaGFuZGxlcik7cmV0dXJu IHRydWU7fSxoYW5kbGVyOmZ1bmN0aW9uKGV2ZW50KXtpZih3aXRoaW5FbGVtZW50KGV2ZW50LHRo aXMpKXJldHVybiB0cnVlO2V2ZW50LnR5cGU9Im1vdXNlbGVhdmUiO3JldHVybiBqUXVlcnkuZXZl bnQuaGFuZGxlLmFwcGx5KHRoaXMsYXJndW1lbnRzKTt9fX19O2pRdWVyeS5mbi5leHRlbmQoe2Jp bmQ6ZnVuY3Rpb24odHlwZSxkYXRhLGZuKXtyZXR1cm4gdHlwZT09InVubG9hZCI/dGhpcy5vbmUo dHlwZSxkYXRhLGZuKTp0aGlzLmVhY2goZnVuY3Rpb24oKXtqUXVlcnkuZXZlbnQuYWRkKHRoaXMs dHlwZSxmbnx8ZGF0YSxmbiYmZGF0YSk7fSk7fSxvbmU6ZnVuY3Rpb24odHlwZSxkYXRhLGZuKXt2 YXIgb25lPWpRdWVyeS5ldmVudC5wcm94eShmbnx8ZGF0YSxmdW5jdGlvbihldmVudCl7alF1ZXJ5 KHRoaXMpLnVuYmluZChldmVudCxvbmUpO3JldHVybihmbnx8ZGF0YSkuYXBwbHkodGhpcyxhcmd1 bWVudHMpO30pO3JldHVybiB0aGlzLmVhY2goZnVuY3Rpb24oKXtqUXVlcnkuZXZlbnQuYWRkKHRo aXMsdHlwZSxvbmUsZm4mJmRhdGEpO30pO30sdW5iaW5kOmZ1bmN0aW9uKHR5cGUsZm4pe3JldHVy biB0aGlzLmVhY2goZnVuY3Rpb24oKXtqUXVlcnkuZXZlbnQucmVtb3ZlKHRoaXMsdHlwZSxmbik7 fSk7fSx0cmlnZ2VyOmZ1bmN0aW9uKHR5cGUsZGF0YSxmbil7cmV0dXJuIHRoaXMuZWFjaChmdW5j dGlvbigpe2pRdWVyeS5ldmVudC50cmlnZ2VyKHR5cGUsZGF0YSx0aGlzLHRydWUsZm4pO30pO30s dHJpZ2dlckhhbmRsZXI6ZnVuY3Rpb24odHlwZSxkYXRhLGZuKXtyZXR1cm4gdGhpc1swXSYmalF1 ZXJ5LmV2ZW50LnRyaWdnZXIodHlwZSxkYXRhLHRoaXNbMF0sZmFsc2UsZm4pO30sdG9nZ2xlOmZ1 bmN0aW9uKGZuKXt2YXIgYXJncz1hcmd1bWVudHMsaT0xO3doaWxlKGk8YXJncy5sZW5ndGgpalF1 ZXJ5LmV2ZW50LnByb3h5KGZuLGFyZ3NbaSsrXSk7cmV0dXJuIHRoaXMuY2xpY2soalF1ZXJ5LmV2 ZW50LnByb3h5KGZuLGZ1bmN0aW9uKGV2ZW50KXt0aGlzLmxhc3RUb2dnbGU9KHRoaXMubGFzdFRv Z2dsZXx8MCklaTtldmVudC5wcmV2ZW50RGVmYXVsdCgpO3JldHVybiBhcmdzW3RoaXMubGFzdFRv Z2dsZSsrXS5hcHBseSh0aGlzLGFyZ3VtZW50cyl8fGZhbHNlO30pKTt9LGhvdmVyOmZ1bmN0aW9u KGZuT3Zlcixmbk91dCl7cmV0dXJuIHRoaXMuYmluZCgnbW91c2VlbnRlcicsZm5PdmVyKS5iaW5k KCdtb3VzZWxlYXZlJyxmbk91dCk7fSxyZWFkeTpmdW5jdGlvbihmbil7YmluZFJlYWR5KCk7aWYo alF1ZXJ5LmlzUmVhZHkpZm4uY2FsbChkb2N1bWVudCxqUXVlcnkpO2Vsc2UKK2pRdWVyeS5yZWFk eUxpc3QucHVzaChmdW5jdGlvbigpe3JldHVybiBmbi5jYWxsKHRoaXMsalF1ZXJ5KTt9KTtyZXR1 cm4gdGhpczt9fSk7alF1ZXJ5LmV4dGVuZCh7aXNSZWFkeTpmYWxzZSxyZWFkeUxpc3Q6W10scmVh ZHk6ZnVuY3Rpb24oKXtpZighalF1ZXJ5LmlzUmVhZHkpe2pRdWVyeS5pc1JlYWR5PXRydWU7aWYo alF1ZXJ5LnJlYWR5TGlzdCl7alF1ZXJ5LmVhY2goalF1ZXJ5LnJlYWR5TGlzdCxmdW5jdGlvbigp e3RoaXMuY2FsbChkb2N1bWVudCk7fSk7alF1ZXJ5LnJlYWR5TGlzdD1udWxsO31qUXVlcnkoZG9j dW1lbnQpLnRyaWdnZXJIYW5kbGVyKCJyZWFkeSIpO319fSk7dmFyIHJlYWR5Qm91bmQ9ZmFsc2U7 ZnVuY3Rpb24gYmluZFJlYWR5KCl7aWYocmVhZHlCb3VuZClyZXR1cm47cmVhZHlCb3VuZD10cnVl O2lmKGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXImJiFqUXVlcnkuYnJvd3Nlci5vcGVyYSlkb2N1 bWVudC5hZGRFdmVudExpc3RlbmVyKCJET01Db250ZW50TG9hZGVkIixqUXVlcnkucmVhZHksZmFs c2UpO2lmKGpRdWVyeS5icm93c2VyLm1zaWUmJndpbmRvdz09dG9wKShmdW5jdGlvbigpe2lmKGpR dWVyeS5pc1JlYWR5KXJldHVybjt0cnl7ZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmRvU2Nyb2xs KCJsZWZ0Iik7fWNhdGNoKGVycm9yKXtzZXRUaW1lb3V0KGFyZ3VtZW50cy5jYWxsZWUsMCk7cmV0 dXJuO31qUXVlcnkucmVhZHkoKTt9KSgpO2lmKGpRdWVyeS5icm93c2VyLm9wZXJhKWRvY3VtZW50 LmFkZEV2ZW50TGlzdGVuZXIoIkRPTUNvbnRlbnRMb2FkZWQiLGZ1bmN0aW9uKCl7aWYoalF1ZXJ5 LmlzUmVhZHkpcmV0dXJuO2Zvcih2YXIgaT0wO2k8ZG9jdW1lbnQuc3R5bGVTaGVldHMubGVuZ3Ro O2krKylpZihkb2N1bWVudC5zdHlsZVNoZWV0c1tpXS5kaXNhYmxlZCl7c2V0VGltZW91dChhcmd1 bWVudHMuY2FsbGVlLDApO3JldHVybjt9alF1ZXJ5LnJlYWR5KCk7fSxmYWxzZSk7aWYoalF1ZXJ5 LmJyb3dzZXIuc2FmYXJpKXt2YXIgbnVtU3R5bGVzOyhmdW5jdGlvbigpe2lmKGpRdWVyeS5pc1Jl YWR5KXJldHVybjtpZihkb2N1bWVudC5yZWFkeVN0YXRlIT0ibG9hZGVkIiYmZG9jdW1lbnQucmVh ZHlTdGF0ZSE9ImNvbXBsZXRlIil7c2V0VGltZW91dChhcmd1bWVudHMuY2FsbGVlLDApO3JldHVy bjt9aWYobnVtU3R5bGVzPT09dW5kZWZpbmVkKW51bVN0eWxlcz1qUXVlcnkoInN0eWxlLCBsaW5r W3JlbD1zdHlsZXNoZWV0XSIpLmxlbmd0aDtpZihkb2N1bWVudC5zdHlsZVNoZWV0cy5sZW5ndGgh PW51bVN0eWxlcyl7c2V0VGltZW91dChhcmd1bWVudHMuY2FsbGVlLDApO3JldHVybjt9alF1ZXJ5 LnJlYWR5KCk7fSkoKTt9alF1ZXJ5LmV2ZW50LmFkZCh3aW5kb3csImxvYWQiLGpRdWVyeS5yZWFk eSk7fWpRdWVyeS5lYWNoKCgiYmx1cixmb2N1cyxsb2FkLHJlc2l6ZSxzY3JvbGwsdW5sb2FkLGNs aWNrLGRibGNsaWNrLCIrIm1vdXNlZG93bixtb3VzZXVwLG1vdXNlbW92ZSxtb3VzZW92ZXIsbW91 c2VvdXQsY2hhbmdlLHNlbGVjdCwiKyJzdWJtaXQsa2V5ZG93bixrZXlwcmVzcyxrZXl1cCxlcnJv ciIpLnNwbGl0KCIsIiksZnVuY3Rpb24oaSxuYW1lKXtqUXVlcnkuZm5bbmFtZV09ZnVuY3Rpb24o Zm4pe3JldHVybiBmbj90aGlzLmJpbmQobmFtZSxmbik6dGhpcy50cmlnZ2VyKG5hbWUpO307fSk7 dmFyIHdpdGhpbkVsZW1lbnQ9ZnVuY3Rpb24oZXZlbnQsZWxlbSl7dmFyIHBhcmVudD1ldmVudC5y ZWxhdGVkVGFyZ2V0O3doaWxlKHBhcmVudCYmcGFyZW50IT1lbGVtKXRyeXtwYXJlbnQ9cGFyZW50 LnBhcmVudE5vZGU7fWNhdGNoKGVycm9yKXtwYXJlbnQ9ZWxlbTt9cmV0dXJuIHBhcmVudD09ZWxl bTt9O2pRdWVyeSh3aW5kb3cpLmJpbmQoInVubG9hZCIsZnVuY3Rpb24oKXtqUXVlcnkoIioiKS5h ZGQoZG9jdW1lbnQpLnVuYmluZCgpO30pO2pRdWVyeS5mbi5leHRlbmQoe19sb2FkOmpRdWVyeS5m bi5sb2FkLGxvYWQ6ZnVuY3Rpb24odXJsLHBhcmFtcyxjYWxsYmFjayl7aWYodHlwZW9mIHVybCE9 J3N0cmluZycpcmV0dXJuIHRoaXMuX2xvYWQodXJsKTt2YXIgb2ZmPXVybC5pbmRleE9mKCIgIik7 aWYob2ZmPj0wKXt2YXIgc2VsZWN0b3I9dXJsLnNsaWNlKG9mZix1cmwubGVuZ3RoKTt1cmw9dXJs LnNsaWNlKDAsb2ZmKTt9Y2FsbGJhY2s9Y2FsbGJhY2t8fGZ1bmN0aW9uKCl7fTt2YXIgdHlwZT0i R0VUIjtpZihwYXJhbXMpaWYoalF1ZXJ5LmlzRnVuY3Rpb24ocGFyYW1zKSl7Y2FsbGJhY2s9cGFy YW1zO3BhcmFtcz1udWxsO31lbHNle3BhcmFtcz1qUXVlcnkucGFyYW0ocGFyYW1zKTt0eXBlPSJQ T1NUIjt9dmFyIHNlbGY9dGhpcztqUXVlcnkuYWpheCh7dXJsOnVybCx0eXBlOnR5cGUsZGF0YVR5 cGU6Imh0bWwiLGRhdGE6cGFyYW1zLGNvbXBsZXRlOmZ1bmN0aW9uKHJlcyxzdGF0dXMpe2lmKHN0 YXR1cz09InN1Y2Nlc3MifHxzdGF0dXM9PSJub3Rtb2RpZmllZCIpc2VsZi5odG1sKHNlbGVjdG9y P2pRdWVyeSgiPGRpdi8+IikuYXBwZW5kKHJlcy5yZXNwb25zZVRleHQucmVwbGFjZSgvPHNjcmlw dCgufFxzKSo/XC9zY3JpcHQ+L2csIiIpKS5maW5kKHNlbGVjdG9yKTpyZXMucmVzcG9uc2VUZXh0 KTtzZWxmLmVhY2goY2FsbGJhY2ssW3Jlcy5yZXNwb25zZVRleHQsc3RhdHVzLHJlc10pO319KTty ZXR1cm4gdGhpczt9LHNlcmlhbGl6ZTpmdW5jdGlvbigpe3JldHVybiBqUXVlcnkucGFyYW0odGhp cy5zZXJpYWxpemVBcnJheSgpKTt9LHNlcmlhbGl6ZUFycmF5OmZ1bmN0aW9uKCl7cmV0dXJuIHRo aXMubWFwKGZ1bmN0aW9uKCl7cmV0dXJuIGpRdWVyeS5ub2RlTmFtZSh0aGlzLCJmb3JtIik/alF1 ZXJ5Lm1ha2VBcnJheSh0aGlzLmVsZW1lbnRzKTp0aGlzO30pLmZpbHRlcihmdW5jdGlvbigpe3Jl dHVybiB0aGlzLm5hbWUmJiF0aGlzLmRpc2FibGVkJiYodGhpcy5jaGVja2VkfHwvc2VsZWN0fHRl eHRhcmVhL2kudGVzdCh0aGlzLm5vZGVOYW1lKXx8L3RleHR8aGlkZGVufHBhc3N3b3JkL2kudGVz dCh0aGlzLnR5cGUpKTt9KS5tYXAoZnVuY3Rpb24oaSxlbGVtKXt2YXIgdmFsPWpRdWVyeSh0aGlz KS52YWwoKTtyZXR1cm4gdmFsPT1udWxsP251bGw6dmFsLmNvbnN0cnVjdG9yPT1BcnJheT9qUXVl cnkubWFwKHZhbCxmdW5jdGlvbih2YWwsaSl7cmV0dXJue25hbWU6ZWxlbS5uYW1lLHZhbHVlOnZh bH07fSk6e25hbWU6ZWxlbS5uYW1lLHZhbHVlOnZhbH07fSkuZ2V0KCk7fX0pO2pRdWVyeS5lYWNo KCJhamF4U3RhcnQsYWpheFN0b3AsYWpheENvbXBsZXRlLGFqYXhFcnJvcixhamF4U3VjY2Vzcyxh amF4U2VuZCIuc3BsaXQoIiwiKSxmdW5jdGlvbihpLG8pe2pRdWVyeS5mbltvXT1mdW5jdGlvbihm KXtyZXR1cm4gdGhpcy5iaW5kKG8sZik7fTt9KTt2YXIganNjPW5vdygpO2pRdWVyeS5leHRlbmQo e2dldDpmdW5jdGlvbih1cmwsZGF0YSxjYWxsYmFjayx0eXBlKXtpZihqUXVlcnkuaXNGdW5jdGlv bihkYXRhKSl7Y2FsbGJhY2s9ZGF0YTtkYXRhPW51bGw7fXJldHVybiBqUXVlcnkuYWpheCh7dHlw ZToiR0VUIix1cmw6dXJsLGRhdGE6ZGF0YSxzdWNjZXNzOmNhbGxiYWNrLGRhdGFUeXBlOnR5cGV9 KTt9LGdldFNjcmlwdDpmdW5jdGlvbih1cmwsY2FsbGJhY2spe3JldHVybiBqUXVlcnkuZ2V0KHVy bCxudWxsLGNhbGxiYWNrLCJzY3JpcHQiKTt9LGdldEpTT046ZnVuY3Rpb24odXJsLGRhdGEsY2Fs bGJhY2spe3JldHVybiBqUXVlcnkuZ2V0KHVybCxkYXRhLGNhbGxiYWNrLCJqc29uIik7fSxwb3N0 OmZ1bmN0aW9uKHVybCxkYXRhLGNhbGxiYWNrLHR5cGUpe2lmKGpRdWVyeS5pc0Z1bmN0aW9uKGRh dGEpKXtjYWxsYmFjaz1kYXRhO2RhdGE9e307fXJldHVybiBqUXVlcnkuYWpheCh7dHlwZToiUE9T VCIsdXJsOnVybCxkYXRhOmRhdGEsc3VjY2VzczpjYWxsYmFjayxkYXRhVHlwZTp0eXBlfSk7fSxh amF4U2V0dXA6ZnVuY3Rpb24oc2V0dGluZ3Mpe2pRdWVyeS5leHRlbmQoalF1ZXJ5LmFqYXhTZXR0 aW5ncyxzZXR0aW5ncyk7fSxhamF4U2V0dGluZ3M6e3VybDpsb2NhdGlvbi5ocmVmLGdsb2JhbDp0 cnVlLHR5cGU6IkdFVCIsdGltZW91dDowLGNvbnRlbnRUeXBlOiJhcHBsaWNhdGlvbi94LXd3dy1m b3JtLXVybGVuY29kZWQiLHByb2Nlc3NEYXRhOnRydWUsYXN5bmM6dHJ1ZSxkYXRhOm51bGwsdXNl cm5hbWU6bnVsbCxwYXNzd29yZDpudWxsLGFjY2VwdHM6e3htbDoiYXBwbGljYXRpb24veG1sLCB0 ZXh0L3htbCIsaHRtbDoidGV4dC9odG1sIixzY3JpcHQ6InRleHQvamF2YXNjcmlwdCwgYXBwbGlj YXRpb24vamF2YXNjcmlwdCIsanNvbjoiYXBwbGljYXRpb24vanNvbiwgdGV4dC9qYXZhc2NyaXB0 Iix0ZXh0OiJ0ZXh0L3BsYWluIixfZGVmYXVsdDoiKi8qIn19LGxhc3RNb2RpZmllZDp7fSxhamF4 OmZ1bmN0aW9uKHMpe3M9alF1ZXJ5LmV4dGVuZCh0cnVlLHMsalF1ZXJ5LmV4dGVuZCh0cnVlLHt9 LGpRdWVyeS5hamF4U2V0dGluZ3MscykpO3ZhciBqc29ucCxqc3JlPS89XD8oJnwkKS9nLHN0YXR1 cyxkYXRhLHR5cGU9cy50eXBlLnRvVXBwZXJDYXNlKCk7aWYocy5kYXRhJiZzLnByb2Nlc3NEYXRh JiZ0eXBlb2Ygcy5kYXRhIT0ic3RyaW5nIilzLmRhdGE9alF1ZXJ5LnBhcmFtKHMuZGF0YSk7aWYo cy5kYXRhVHlwZT09Impzb25wIil7aWYodHlwZT09IkdFVCIpe2lmKCFzLnVybC5tYXRjaChqc3Jl KSlzLnVybCs9KHMudXJsLm1hdGNoKC9cPy8pPyImIjoiPyIpKyhzLmpzb25wfHwiY2FsbGJhY2si KSsiPT8iO31lbHNlIGlmKCFzLmRhdGF8fCFzLmRhdGEubWF0Y2goanNyZSkpcy5kYXRhPShzLmRh dGE/cy5kYXRhKyImIjoiIikrKHMuanNvbnB8fCJjYWxsYmFjayIpKyI9PyI7cy5kYXRhVHlwZT0i anNvbiI7fWlmKHMuZGF0YVR5cGU9PSJqc29uIiYmKHMuZGF0YSYmcy5kYXRhLm1hdGNoKGpzcmUp fHxzLnVybC5tYXRjaChqc3JlKSkpe2pzb25wPSJqc29ucCIranNjKys7aWYocy5kYXRhKXMuZGF0 YT0ocy5kYXRhKyIiKS5yZXBsYWNlKGpzcmUsIj0iK2pzb25wKyIkMSIpO3MudXJsPXMudXJsLnJl cGxhY2UoanNyZSwiPSIranNvbnArIiQxIik7cy5kYXRhVHlwZT0ic2NyaXB0Ijt3aW5kb3dbanNv bnBdPWZ1bmN0aW9uKHRtcCl7ZGF0YT10bXA7c3VjY2VzcygpO2NvbXBsZXRlKCk7d2luZG93W2pz b25wXT11bmRlZmluZWQ7dHJ5e2RlbGV0ZSB3aW5kb3dbanNvbnBdO31jYXRjaChlKXt9aWYoaGVh ZCloZWFkLnJlbW92ZUNoaWxkKHNjcmlwdCk7fTt9aWYocy5kYXRhVHlwZT09InNjcmlwdCImJnMu Y2FjaGU9PW51bGwpcy5jYWNoZT1mYWxzZTtpZihzLmNhY2hlPT09ZmFsc2UmJnR5cGU9PSJHRVQi KXt2YXIgdHM9bm93KCk7dmFyIHJldD1zLnVybC5yZXBsYWNlKC8oXD98JilfPS4qPygmfCQpLywi JDFfPSIrdHMrIiQyIik7cy51cmw9cmV0KygocmV0PT1zLnVybCk/KHMudXJsLm1hdGNoKC9cPy8p PyImIjoiPyIpKyJfPSIrdHM6IiIpO31pZihzLmRhdGEmJnR5cGU9PSJHRVQiKXtzLnVybCs9KHMu dXJsLm1hdGNoKC9cPy8pPyImIjoiPyIpK3MuZGF0YTtzLmRhdGE9bnVsbDt9aWYocy5nbG9iYWwm JiFqUXVlcnkuYWN0aXZlKyspalF1ZXJ5LmV2ZW50LnRyaWdnZXIoImFqYXhTdGFydCIpO3ZhciBy ZW1vdGU9L14oPzpcdys6KT9cL1wvKFteXC8/I10rKS87aWYocy5kYXRhVHlwZT09InNjcmlwdCIm JnR5cGU9PSJHRVQiJiZyZW1vdGUudGVzdChzLnVybCkmJnJlbW90ZS5leGVjKHMudXJsKVsxXSE9 bG9jYXRpb24uaG9zdCl7dmFyIGhlYWQ9ZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoImhl YWQiKVswXTt2YXIgc2NyaXB0PWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoInNjcmlwdCIpO3Njcmlw dC5zcmM9cy51cmw7aWYocy5zY3JpcHRDaGFyc2V0KXNjcmlwdC5jaGFyc2V0PXMuc2NyaXB0Q2hh cnNldDtpZighanNvbnApe3ZhciBkb25lPWZhbHNlO3NjcmlwdC5vbmxvYWQ9c2NyaXB0Lm9ucmVh ZHlzdGF0ZWNoYW5nZT1mdW5jdGlvbigpe2lmKCFkb25lJiYoIXRoaXMucmVhZHlTdGF0ZXx8dGhp cy5yZWFkeVN0YXRlPT0ibG9hZGVkInx8dGhpcy5yZWFkeVN0YXRlPT0iY29tcGxldGUiKSl7ZG9u ZT10cnVlO3N1Y2Nlc3MoKTtjb21wbGV0ZSgpO2hlYWQucmVtb3ZlQ2hpbGQoc2NyaXB0KTt9fTt9 aGVhZC5hcHBlbmRDaGlsZChzY3JpcHQpO3JldHVybiB1bmRlZmluZWQ7fXZhciByZXF1ZXN0RG9u ZT1mYWxzZTt2YXIgeGhyPXdpbmRvdy5BY3RpdmVYT2JqZWN0P25ldyBBY3RpdmVYT2JqZWN0KCJN aWNyb3NvZnQuWE1MSFRUUCIpOm5ldyBYTUxIdHRwUmVxdWVzdCgpO2lmKHMudXNlcm5hbWUpeGhy Lm9wZW4odHlwZSxzLnVybCxzLmFzeW5jLHMudXNlcm5hbWUscy5wYXNzd29yZCk7ZWxzZQoreGhy Lm9wZW4odHlwZSxzLnVybCxzLmFzeW5jKTt0cnl7aWYocy5kYXRhKXhoci5zZXRSZXF1ZXN0SGVh ZGVyKCJDb250ZW50LVR5cGUiLHMuY29udGVudFR5cGUpO2lmKHMuaWZNb2RpZmllZCl4aHIuc2V0 UmVxdWVzdEhlYWRlcigiSWYtTW9kaWZpZWQtU2luY2UiLGpRdWVyeS5sYXN0TW9kaWZpZWRbcy51 cmxdfHwiVGh1LCAwMSBKYW4gMTk3MCAwMDowMDowMCBHTVQiKTt4aHIuc2V0UmVxdWVzdEhlYWRl cigiWC1SZXF1ZXN0ZWQtV2l0aCIsIlhNTEh0dHBSZXF1ZXN0Iik7eGhyLnNldFJlcXVlc3RIZWFk ZXIoIkFjY2VwdCIscy5kYXRhVHlwZSYmcy5hY2NlcHRzW3MuZGF0YVR5cGVdP3MuYWNjZXB0c1tz LmRhdGFUeXBlXSsiLCAqLyoiOnMuYWNjZXB0cy5fZGVmYXVsdCk7fWNhdGNoKGUpe31pZihzLmJl Zm9yZVNlbmQmJnMuYmVmb3JlU2VuZCh4aHIscyk9PT1mYWxzZSl7cy5nbG9iYWwmJmpRdWVyeS5h Y3RpdmUtLTt4aHIuYWJvcnQoKTtyZXR1cm4gZmFsc2U7fWlmKHMuZ2xvYmFsKWpRdWVyeS5ldmVu dC50cmlnZ2VyKCJhamF4U2VuZCIsW3hocixzXSk7dmFyIG9ucmVhZHlzdGF0ZWNoYW5nZT1mdW5j dGlvbihpc1RpbWVvdXQpe2lmKCFyZXF1ZXN0RG9uZSYmeGhyJiYoeGhyLnJlYWR5U3RhdGU9PTR8 fGlzVGltZW91dD09InRpbWVvdXQiKSl7cmVxdWVzdERvbmU9dHJ1ZTtpZihpdmFsKXtjbGVhcklu dGVydmFsKGl2YWwpO2l2YWw9bnVsbDt9c3RhdHVzPWlzVGltZW91dD09InRpbWVvdXQiJiYidGlt ZW91dCJ8fCFqUXVlcnkuaHR0cFN1Y2Nlc3MoeGhyKSYmImVycm9yInx8cy5pZk1vZGlmaWVkJiZq UXVlcnkuaHR0cE5vdE1vZGlmaWVkKHhocixzLnVybCkmJiJub3Rtb2RpZmllZCJ8fCJzdWNjZXNz IjtpZihzdGF0dXM9PSJzdWNjZXNzIil7dHJ5e2RhdGE9alF1ZXJ5Lmh0dHBEYXRhKHhocixzLmRh dGFUeXBlLHMuZGF0YUZpbHRlcik7fWNhdGNoKGUpe3N0YXR1cz0icGFyc2VyZXJyb3IiO319aWYo c3RhdHVzPT0ic3VjY2VzcyIpe3ZhciBtb2RSZXM7dHJ5e21vZFJlcz14aHIuZ2V0UmVzcG9uc2VI ZWFkZXIoIkxhc3QtTW9kaWZpZWQiKTt9Y2F0Y2goZSl7fWlmKHMuaWZNb2RpZmllZCYmbW9kUmVz KWpRdWVyeS5sYXN0TW9kaWZpZWRbcy51cmxdPW1vZFJlcztpZighanNvbnApc3VjY2VzcygpO31l bHNlCitqUXVlcnkuaGFuZGxlRXJyb3Iocyx4aHIsc3RhdHVzKTtjb21wbGV0ZSgpO2lmKHMuYXN5 bmMpeGhyPW51bGw7fX07aWYocy5hc3luYyl7dmFyIGl2YWw9c2V0SW50ZXJ2YWwob25yZWFkeXN0 YXRlY2hhbmdlLDEzKTtpZihzLnRpbWVvdXQ+MClzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7aWYoeGhy KXt4aHIuYWJvcnQoKTtpZighcmVxdWVzdERvbmUpb25yZWFkeXN0YXRlY2hhbmdlKCJ0aW1lb3V0 Iik7fX0scy50aW1lb3V0KTt9dHJ5e3hoci5zZW5kKHMuZGF0YSk7fWNhdGNoKGUpe2pRdWVyeS5o YW5kbGVFcnJvcihzLHhocixudWxsLGUpO31pZighcy5hc3luYylvbnJlYWR5c3RhdGVjaGFuZ2Uo KTtmdW5jdGlvbiBzdWNjZXNzKCl7aWYocy5zdWNjZXNzKXMuc3VjY2VzcyhkYXRhLHN0YXR1cyk7 aWYocy5nbG9iYWwpalF1ZXJ5LmV2ZW50LnRyaWdnZXIoImFqYXhTdWNjZXNzIixbeGhyLHNdKTt9 ZnVuY3Rpb24gY29tcGxldGUoKXtpZihzLmNvbXBsZXRlKXMuY29tcGxldGUoeGhyLHN0YXR1cyk7 aWYocy5nbG9iYWwpalF1ZXJ5LmV2ZW50LnRyaWdnZXIoImFqYXhDb21wbGV0ZSIsW3hocixzXSk7 aWYocy5nbG9iYWwmJiEtLWpRdWVyeS5hY3RpdmUpalF1ZXJ5LmV2ZW50LnRyaWdnZXIoImFqYXhT dG9wIik7fXJldHVybiB4aHI7fSxoYW5kbGVFcnJvcjpmdW5jdGlvbihzLHhocixzdGF0dXMsZSl7 aWYocy5lcnJvcilzLmVycm9yKHhocixzdGF0dXMsZSk7aWYocy5nbG9iYWwpalF1ZXJ5LmV2ZW50 LnRyaWdnZXIoImFqYXhFcnJvciIsW3hocixzLGVdKTt9LGFjdGl2ZTowLGh0dHBTdWNjZXNzOmZ1 bmN0aW9uKHhocil7dHJ5e3JldHVybiF4aHIuc3RhdHVzJiZsb2NhdGlvbi5wcm90b2NvbD09ImZp bGU6Inx8KHhoci5zdGF0dXM+PTIwMCYmeGhyLnN0YXR1czwzMDApfHx4aHIuc3RhdHVzPT0zMDR8 fHhoci5zdGF0dXM9PTEyMjN8fGpRdWVyeS5icm93c2VyLnNhZmFyaSYmeGhyLnN0YXR1cz09dW5k ZWZpbmVkO31jYXRjaChlKXt9cmV0dXJuIGZhbHNlO30saHR0cE5vdE1vZGlmaWVkOmZ1bmN0aW9u KHhocix1cmwpe3RyeXt2YXIgeGhyUmVzPXhoci5nZXRSZXNwb25zZUhlYWRlcigiTGFzdC1Nb2Rp ZmllZCIpO3JldHVybiB4aHIuc3RhdHVzPT0zMDR8fHhoclJlcz09alF1ZXJ5Lmxhc3RNb2RpZmll ZFt1cmxdfHxqUXVlcnkuYnJvd3Nlci5zYWZhcmkmJnhoci5zdGF0dXM9PXVuZGVmaW5lZDt9Y2F0 Y2goZSl7fXJldHVybiBmYWxzZTt9LGh0dHBEYXRhOmZ1bmN0aW9uKHhocix0eXBlLGZpbHRlcil7 dmFyIGN0PXhoci5nZXRSZXNwb25zZUhlYWRlcigiY29udGVudC10eXBlIikseG1sPXR5cGU9PSJ4 bWwifHwhdHlwZSYmY3QmJmN0LmluZGV4T2YoInhtbCIpPj0wLGRhdGE9eG1sP3hoci5yZXNwb25z ZVhNTDp4aHIucmVzcG9uc2VUZXh0O2lmKHhtbCYmZGF0YS5kb2N1bWVudEVsZW1lbnQudGFnTmFt ZT09InBhcnNlcmVycm9yIil0aHJvdyJwYXJzZXJlcnJvciI7aWYoZmlsdGVyKWRhdGE9ZmlsdGVy KGRhdGEsdHlwZSk7aWYodHlwZT09InNjcmlwdCIpalF1ZXJ5Lmdsb2JhbEV2YWwoZGF0YSk7aWYo dHlwZT09Impzb24iKWRhdGE9ZXZhbCgiKCIrZGF0YSsiKSIpO3JldHVybiBkYXRhO30scGFyYW06 ZnVuY3Rpb24oYSl7dmFyIHM9W107aWYoYS5jb25zdHJ1Y3Rvcj09QXJyYXl8fGEuanF1ZXJ5KWpR dWVyeS5lYWNoKGEsZnVuY3Rpb24oKXtzLnB1c2goZW5jb2RlVVJJQ29tcG9uZW50KHRoaXMubmFt ZSkrIj0iK2VuY29kZVVSSUNvbXBvbmVudCh0aGlzLnZhbHVlKSk7fSk7ZWxzZQorZm9yKHZhciBq IGluIGEpaWYoYVtqXSYmYVtqXS5jb25zdHJ1Y3Rvcj09QXJyYXkpalF1ZXJ5LmVhY2goYVtqXSxm dW5jdGlvbigpe3MucHVzaChlbmNvZGVVUklDb21wb25lbnQoaikrIj0iK2VuY29kZVVSSUNvbXBv bmVudCh0aGlzKSk7fSk7ZWxzZQorcy5wdXNoKGVuY29kZVVSSUNvbXBvbmVudChqKSsiPSIrZW5j b2RlVVJJQ29tcG9uZW50KGpRdWVyeS5pc0Z1bmN0aW9uKGFbal0pP2Fbal0oKTphW2pdKSk7cmV0 dXJuIHMuam9pbigiJiIpLnJlcGxhY2UoLyUyMC9nLCIrIik7fX0pO2pRdWVyeS5mbi5leHRlbmQo e3Nob3c6ZnVuY3Rpb24oc3BlZWQsY2FsbGJhY2spe3JldHVybiBzcGVlZD90aGlzLmFuaW1hdGUo e2hlaWdodDoic2hvdyIsd2lkdGg6InNob3ciLG9wYWNpdHk6InNob3cifSxzcGVlZCxjYWxsYmFj ayk6dGhpcy5maWx0ZXIoIjpoaWRkZW4iKS5lYWNoKGZ1bmN0aW9uKCl7dGhpcy5zdHlsZS5kaXNw bGF5PXRoaXMub2xkYmxvY2t8fCIiO2lmKGpRdWVyeS5jc3ModGhpcywiZGlzcGxheSIpPT0ibm9u ZSIpe3ZhciBlbGVtPWpRdWVyeSgiPCIrdGhpcy50YWdOYW1lKyIgLz4iKS5hcHBlbmRUbygiYm9k eSIpO3RoaXMuc3R5bGUuZGlzcGxheT1lbGVtLmNzcygiZGlzcGxheSIpO2lmKHRoaXMuc3R5bGUu ZGlzcGxheT09Im5vbmUiKXRoaXMuc3R5bGUuZGlzcGxheT0iYmxvY2siO2VsZW0ucmVtb3ZlKCk7 fX0pLmVuZCgpO30saGlkZTpmdW5jdGlvbihzcGVlZCxjYWxsYmFjayl7cmV0dXJuIHNwZWVkP3Ro aXMuYW5pbWF0ZSh7aGVpZ2h0OiJoaWRlIix3aWR0aDoiaGlkZSIsb3BhY2l0eToiaGlkZSJ9LHNw ZWVkLGNhbGxiYWNrKTp0aGlzLmZpbHRlcigiOnZpc2libGUiKS5lYWNoKGZ1bmN0aW9uKCl7dGhp cy5vbGRibG9jaz10aGlzLm9sZGJsb2NrfHxqUXVlcnkuY3NzKHRoaXMsImRpc3BsYXkiKTt0aGlz LnN0eWxlLmRpc3BsYXk9Im5vbmUiO30pLmVuZCgpO30sX3RvZ2dsZTpqUXVlcnkuZm4udG9nZ2xl LHRvZ2dsZTpmdW5jdGlvbihmbixmbjIpe3JldHVybiBqUXVlcnkuaXNGdW5jdGlvbihmbikmJmpR dWVyeS5pc0Z1bmN0aW9uKGZuMik/dGhpcy5fdG9nZ2xlLmFwcGx5KHRoaXMsYXJndW1lbnRzKTpm bj90aGlzLmFuaW1hdGUoe2hlaWdodDoidG9nZ2xlIix3aWR0aDoidG9nZ2xlIixvcGFjaXR5OiJ0 b2dnbGUifSxmbixmbjIpOnRoaXMuZWFjaChmdW5jdGlvbigpe2pRdWVyeSh0aGlzKVtqUXVlcnko dGhpcykuaXMoIjpoaWRkZW4iKT8ic2hvdyI6ImhpZGUiXSgpO30pO30sc2xpZGVEb3duOmZ1bmN0 aW9uKHNwZWVkLGNhbGxiYWNrKXtyZXR1cm4gdGhpcy5hbmltYXRlKHtoZWlnaHQ6InNob3cifSxz cGVlZCxjYWxsYmFjayk7fSxzbGlkZVVwOmZ1bmN0aW9uKHNwZWVkLGNhbGxiYWNrKXtyZXR1cm4g dGhpcy5hbmltYXRlKHtoZWlnaHQ6ImhpZGUifSxzcGVlZCxjYWxsYmFjayk7fSxzbGlkZVRvZ2ds ZTpmdW5jdGlvbihzcGVlZCxjYWxsYmFjayl7cmV0dXJuIHRoaXMuYW5pbWF0ZSh7aGVpZ2h0OiJ0 b2dnbGUifSxzcGVlZCxjYWxsYmFjayk7fSxmYWRlSW46ZnVuY3Rpb24oc3BlZWQsY2FsbGJhY2sp e3JldHVybiB0aGlzLmFuaW1hdGUoe29wYWNpdHk6InNob3cifSxzcGVlZCxjYWxsYmFjayk7fSxm YWRlT3V0OmZ1bmN0aW9uKHNwZWVkLGNhbGxiYWNrKXtyZXR1cm4gdGhpcy5hbmltYXRlKHtvcGFj aXR5OiJoaWRlIn0sc3BlZWQsY2FsbGJhY2spO30sZmFkZVRvOmZ1bmN0aW9uKHNwZWVkLHRvLGNh bGxiYWNrKXtyZXR1cm4gdGhpcy5hbmltYXRlKHtvcGFjaXR5OnRvfSxzcGVlZCxjYWxsYmFjayk7 fSxhbmltYXRlOmZ1bmN0aW9uKHByb3Asc3BlZWQsZWFzaW5nLGNhbGxiYWNrKXt2YXIgb3B0YWxs PWpRdWVyeS5zcGVlZChzcGVlZCxlYXNpbmcsY2FsbGJhY2spO3JldHVybiB0aGlzW29wdGFsbC5x dWV1ZT09PWZhbHNlPyJlYWNoIjoicXVldWUiXShmdW5jdGlvbigpe2lmKHRoaXMubm9kZVR5cGUh PTEpcmV0dXJuIGZhbHNlO3ZhciBvcHQ9alF1ZXJ5LmV4dGVuZCh7fSxvcHRhbGwpLHAsaGlkZGVu PWpRdWVyeSh0aGlzKS5pcygiOmhpZGRlbiIpLHNlbGY9dGhpcztmb3IocCBpbiBwcm9wKXtpZihw cm9wW3BdPT0iaGlkZSImJmhpZGRlbnx8cHJvcFtwXT09InNob3ciJiYhaGlkZGVuKXJldHVybiBv cHQuY29tcGxldGUuY2FsbCh0aGlzKTtpZihwPT0iaGVpZ2h0Inx8cD09IndpZHRoIil7b3B0LmRp c3BsYXk9alF1ZXJ5LmNzcyh0aGlzLCJkaXNwbGF5Iik7b3B0Lm92ZXJmbG93PXRoaXMuc3R5bGUu b3ZlcmZsb3c7fX1pZihvcHQub3ZlcmZsb3chPW51bGwpdGhpcy5zdHlsZS5vdmVyZmxvdz0iaGlk ZGVuIjtvcHQuY3VyQW5pbT1qUXVlcnkuZXh0ZW5kKHt9LHByb3ApO2pRdWVyeS5lYWNoKHByb3As ZnVuY3Rpb24obmFtZSx2YWwpe3ZhciBlPW5ldyBqUXVlcnkuZngoc2VsZixvcHQsbmFtZSk7aWYo L3RvZ2dsZXxzaG93fGhpZGUvLnRlc3QodmFsKSllW3ZhbD09InRvZ2dsZSI/aGlkZGVuPyJzaG93 IjoiaGlkZSI6dmFsXShwcm9wKTtlbHNle3ZhciBwYXJ0cz12YWwudG9TdHJpbmcoKS5tYXRjaCgv XihbKy1dPSk/KFtcZCstLl0rKSguKikkLyksc3RhcnQ9ZS5jdXIodHJ1ZSl8fDA7aWYocGFydHMp e3ZhciBlbmQ9cGFyc2VGbG9hdChwYXJ0c1syXSksdW5pdD1wYXJ0c1szXXx8InB4IjtpZih1bml0 IT0icHgiKXtzZWxmLnN0eWxlW25hbWVdPShlbmR8fDEpK3VuaXQ7c3RhcnQ9KChlbmR8fDEpL2Uu Y3VyKHRydWUpKSpzdGFydDtzZWxmLnN0eWxlW25hbWVdPXN0YXJ0K3VuaXQ7fWlmKHBhcnRzWzFd KWVuZD0oKHBhcnRzWzFdPT0iLT0iPy0xOjEpKmVuZCkrc3RhcnQ7ZS5jdXN0b20oc3RhcnQsZW5k LHVuaXQpO31lbHNlCitlLmN1c3RvbShzdGFydCx2YWwsIiIpO319KTtyZXR1cm4gdHJ1ZTt9KTt9 LHF1ZXVlOmZ1bmN0aW9uKHR5cGUsZm4pe2lmKGpRdWVyeS5pc0Z1bmN0aW9uKHR5cGUpfHwodHlw ZSYmdHlwZS5jb25zdHJ1Y3Rvcj09QXJyYXkpKXtmbj10eXBlO3R5cGU9ImZ4Ijt9aWYoIXR5cGV8 fCh0eXBlb2YgdHlwZT09InN0cmluZyImJiFmbikpcmV0dXJuIHF1ZXVlKHRoaXNbMF0sdHlwZSk7 cmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbigpe2lmKGZuLmNvbnN0cnVjdG9yPT1BcnJheSlxdWV1 ZSh0aGlzLHR5cGUsZm4pO2Vsc2V7cXVldWUodGhpcyx0eXBlKS5wdXNoKGZuKTtpZihxdWV1ZSh0 aGlzLHR5cGUpLmxlbmd0aD09MSlmbi5jYWxsKHRoaXMpO319KTt9LHN0b3A6ZnVuY3Rpb24oY2xl YXJRdWV1ZSxnb3RvRW5kKXt2YXIgdGltZXJzPWpRdWVyeS50aW1lcnM7aWYoY2xlYXJRdWV1ZSl0 aGlzLnF1ZXVlKFtdKTt0aGlzLmVhY2goZnVuY3Rpb24oKXtmb3IodmFyIGk9dGltZXJzLmxlbmd0 aC0xO2k+PTA7aS0tKWlmKHRpbWVyc1tpXS5lbGVtPT10aGlzKXtpZihnb3RvRW5kKXRpbWVyc1tp XSh0cnVlKTt0aW1lcnMuc3BsaWNlKGksMSk7fX0pO2lmKCFnb3RvRW5kKXRoaXMuZGVxdWV1ZSgp O3JldHVybiB0aGlzO319KTt2YXIgcXVldWU9ZnVuY3Rpb24oZWxlbSx0eXBlLGFycmF5KXtpZihl bGVtKXt0eXBlPXR5cGV8fCJmeCI7dmFyIHE9alF1ZXJ5LmRhdGEoZWxlbSx0eXBlKyJxdWV1ZSIp O2lmKCFxfHxhcnJheSlxPWpRdWVyeS5kYXRhKGVsZW0sdHlwZSsicXVldWUiLGpRdWVyeS5tYWtl QXJyYXkoYXJyYXkpKTt9cmV0dXJuIHE7fTtqUXVlcnkuZm4uZGVxdWV1ZT1mdW5jdGlvbih0eXBl KXt0eXBlPXR5cGV8fCJmeCI7cmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbigpe3ZhciBxPXF1ZXVl KHRoaXMsdHlwZSk7cS5zaGlmdCgpO2lmKHEubGVuZ3RoKXFbMF0uY2FsbCh0aGlzKTt9KTt9O2pR dWVyeS5leHRlbmQoe3NwZWVkOmZ1bmN0aW9uKHNwZWVkLGVhc2luZyxmbil7dmFyIG9wdD1zcGVl ZCYmc3BlZWQuY29uc3RydWN0b3I9PU9iamVjdD9zcGVlZDp7Y29tcGxldGU6Zm58fCFmbiYmZWFz aW5nfHxqUXVlcnkuaXNGdW5jdGlvbihzcGVlZCkmJnNwZWVkLGR1cmF0aW9uOnNwZWVkLGVhc2lu ZzpmbiYmZWFzaW5nfHxlYXNpbmcmJmVhc2luZy5jb25zdHJ1Y3RvciE9RnVuY3Rpb24mJmVhc2lu Z307b3B0LmR1cmF0aW9uPShvcHQuZHVyYXRpb24mJm9wdC5kdXJhdGlvbi5jb25zdHJ1Y3Rvcj09 TnVtYmVyP29wdC5kdXJhdGlvbjpqUXVlcnkuZnguc3BlZWRzW29wdC5kdXJhdGlvbl0pfHxqUXVl cnkuZnguc3BlZWRzLmRlZjtvcHQub2xkPW9wdC5jb21wbGV0ZTtvcHQuY29tcGxldGU9ZnVuY3Rp b24oKXtpZihvcHQucXVldWUhPT1mYWxzZSlqUXVlcnkodGhpcykuZGVxdWV1ZSgpO2lmKGpRdWVy eS5pc0Z1bmN0aW9uKG9wdC5vbGQpKW9wdC5vbGQuY2FsbCh0aGlzKTt9O3JldHVybiBvcHQ7fSxl YXNpbmc6e2xpbmVhcjpmdW5jdGlvbihwLG4sZmlyc3ROdW0sZGlmZil7cmV0dXJuIGZpcnN0TnVt K2RpZmYqcDt9LHN3aW5nOmZ1bmN0aW9uKHAsbixmaXJzdE51bSxkaWZmKXtyZXR1cm4oKC1NYXRo LmNvcyhwKk1hdGguUEkpLzIpKzAuNSkqZGlmZitmaXJzdE51bTt9fSx0aW1lcnM6W10sdGltZXJJ ZDpudWxsLGZ4OmZ1bmN0aW9uKGVsZW0sb3B0aW9ucyxwcm9wKXt0aGlzLm9wdGlvbnM9b3B0aW9u czt0aGlzLmVsZW09ZWxlbTt0aGlzLnByb3A9cHJvcDtpZighb3B0aW9ucy5vcmlnKW9wdGlvbnMu b3JpZz17fTt9fSk7alF1ZXJ5LmZ4LnByb3RvdHlwZT17dXBkYXRlOmZ1bmN0aW9uKCl7aWYodGhp cy5vcHRpb25zLnN0ZXApdGhpcy5vcHRpb25zLnN0ZXAuY2FsbCh0aGlzLmVsZW0sdGhpcy5ub3cs dGhpcyk7KGpRdWVyeS5meC5zdGVwW3RoaXMucHJvcF18fGpRdWVyeS5meC5zdGVwLl9kZWZhdWx0 KSh0aGlzKTtpZih0aGlzLnByb3A9PSJoZWlnaHQifHx0aGlzLnByb3A9PSJ3aWR0aCIpdGhpcy5l bGVtLnN0eWxlLmRpc3BsYXk9ImJsb2NrIjt9LGN1cjpmdW5jdGlvbihmb3JjZSl7aWYodGhpcy5l bGVtW3RoaXMucHJvcF0hPW51bGwmJnRoaXMuZWxlbS5zdHlsZVt0aGlzLnByb3BdPT1udWxsKXJl dHVybiB0aGlzLmVsZW1bdGhpcy5wcm9wXTt2YXIgcj1wYXJzZUZsb2F0KGpRdWVyeS5jc3ModGhp cy5lbGVtLHRoaXMucHJvcCxmb3JjZSkpO3JldHVybiByJiZyPi0xMDAwMD9yOnBhcnNlRmxvYXQo alF1ZXJ5LmN1ckNTUyh0aGlzLmVsZW0sdGhpcy5wcm9wKSl8fDA7fSxjdXN0b206ZnVuY3Rpb24o ZnJvbSx0byx1bml0KXt0aGlzLnN0YXJ0VGltZT1ub3coKTt0aGlzLnN0YXJ0PWZyb207dGhpcy5l bmQ9dG87dGhpcy51bml0PXVuaXR8fHRoaXMudW5pdHx8InB4Ijt0aGlzLm5vdz10aGlzLnN0YXJ0 O3RoaXMucG9zPXRoaXMuc3RhdGU9MDt0aGlzLnVwZGF0ZSgpO3ZhciBzZWxmPXRoaXM7ZnVuY3Rp b24gdChnb3RvRW5kKXtyZXR1cm4gc2VsZi5zdGVwKGdvdG9FbmQpO310LmVsZW09dGhpcy5lbGVt O2pRdWVyeS50aW1lcnMucHVzaCh0KTtpZihqUXVlcnkudGltZXJJZD09bnVsbCl7alF1ZXJ5LnRp bWVySWQ9c2V0SW50ZXJ2YWwoZnVuY3Rpb24oKXt2YXIgdGltZXJzPWpRdWVyeS50aW1lcnM7Zm9y KHZhciBpPTA7aTx0aW1lcnMubGVuZ3RoO2krKylpZighdGltZXJzW2ldKCkpdGltZXJzLnNwbGlj ZShpLS0sMSk7aWYoIXRpbWVycy5sZW5ndGgpe2NsZWFySW50ZXJ2YWwoalF1ZXJ5LnRpbWVySWQp O2pRdWVyeS50aW1lcklkPW51bGw7fX0sMTMpO319LHNob3c6ZnVuY3Rpb24oKXt0aGlzLm9wdGlv bnMub3JpZ1t0aGlzLnByb3BdPWpRdWVyeS5hdHRyKHRoaXMuZWxlbS5zdHlsZSx0aGlzLnByb3Ap O3RoaXMub3B0aW9ucy5zaG93PXRydWU7dGhpcy5jdXN0b20oMCx0aGlzLmN1cigpKTtpZih0aGlz LnByb3A9PSJ3aWR0aCJ8fHRoaXMucHJvcD09ImhlaWdodCIpdGhpcy5lbGVtLnN0eWxlW3RoaXMu cHJvcF09IjFweCI7alF1ZXJ5KHRoaXMuZWxlbSkuc2hvdygpO30saGlkZTpmdW5jdGlvbigpe3Ro aXMub3B0aW9ucy5vcmlnW3RoaXMucHJvcF09alF1ZXJ5LmF0dHIodGhpcy5lbGVtLnN0eWxlLHRo aXMucHJvcCk7dGhpcy5vcHRpb25zLmhpZGU9dHJ1ZTt0aGlzLmN1c3RvbSh0aGlzLmN1cigpLDAp O30sc3RlcDpmdW5jdGlvbihnb3RvRW5kKXt2YXIgdD1ub3coKTtpZihnb3RvRW5kfHx0PnRoaXMu b3B0aW9ucy5kdXJhdGlvbit0aGlzLnN0YXJ0VGltZSl7dGhpcy5ub3c9dGhpcy5lbmQ7dGhpcy5w b3M9dGhpcy5zdGF0ZT0xO3RoaXMudXBkYXRlKCk7dGhpcy5vcHRpb25zLmN1ckFuaW1bdGhpcy5w cm9wXT10cnVlO3ZhciBkb25lPXRydWU7Zm9yKHZhciBpIGluIHRoaXMub3B0aW9ucy5jdXJBbmlt KWlmKHRoaXMub3B0aW9ucy5jdXJBbmltW2ldIT09dHJ1ZSlkb25lPWZhbHNlO2lmKGRvbmUpe2lm KHRoaXMub3B0aW9ucy5kaXNwbGF5IT1udWxsKXt0aGlzLmVsZW0uc3R5bGUub3ZlcmZsb3c9dGhp cy5vcHRpb25zLm92ZXJmbG93O3RoaXMuZWxlbS5zdHlsZS5kaXNwbGF5PXRoaXMub3B0aW9ucy5k aXNwbGF5O2lmKGpRdWVyeS5jc3ModGhpcy5lbGVtLCJkaXNwbGF5Iik9PSJub25lIil0aGlzLmVs ZW0uc3R5bGUuZGlzcGxheT0iYmxvY2siO31pZih0aGlzLm9wdGlvbnMuaGlkZSl0aGlzLmVsZW0u c3R5bGUuZGlzcGxheT0ibm9uZSI7aWYodGhpcy5vcHRpb25zLmhpZGV8fHRoaXMub3B0aW9ucy5z aG93KWZvcih2YXIgcCBpbiB0aGlzLm9wdGlvbnMuY3VyQW5pbSlqUXVlcnkuYXR0cih0aGlzLmVs ZW0uc3R5bGUscCx0aGlzLm9wdGlvbnMub3JpZ1twXSk7fWlmKGRvbmUpdGhpcy5vcHRpb25zLmNv bXBsZXRlLmNhbGwodGhpcy5lbGVtKTtyZXR1cm4gZmFsc2U7fWVsc2V7dmFyIG49dC10aGlzLnN0 YXJ0VGltZTt0aGlzLnN0YXRlPW4vdGhpcy5vcHRpb25zLmR1cmF0aW9uO3RoaXMucG9zPWpRdWVy eS5lYXNpbmdbdGhpcy5vcHRpb25zLmVhc2luZ3x8KGpRdWVyeS5lYXNpbmcuc3dpbmc/InN3aW5n IjoibGluZWFyIildKHRoaXMuc3RhdGUsbiwwLDEsdGhpcy5vcHRpb25zLmR1cmF0aW9uKTt0aGlz Lm5vdz10aGlzLnN0YXJ0KygodGhpcy5lbmQtdGhpcy5zdGFydCkqdGhpcy5wb3MpO3RoaXMudXBk YXRlKCk7fXJldHVybiB0cnVlO319O2pRdWVyeS5leHRlbmQoalF1ZXJ5LmZ4LHtzcGVlZHM6e3Ns b3c6NjAwLGZhc3Q6MjAwLGRlZjo0MDB9LHN0ZXA6e3Njcm9sbExlZnQ6ZnVuY3Rpb24oZngpe2Z4 LmVsZW0uc2Nyb2xsTGVmdD1meC5ub3c7fSxzY3JvbGxUb3A6ZnVuY3Rpb24oZngpe2Z4LmVsZW0u c2Nyb2xsVG9wPWZ4Lm5vdzt9LG9wYWNpdHk6ZnVuY3Rpb24oZngpe2pRdWVyeS5hdHRyKGZ4LmVs ZW0uc3R5bGUsIm9wYWNpdHkiLGZ4Lm5vdyk7fSxfZGVmYXVsdDpmdW5jdGlvbihmeCl7ZnguZWxl bS5zdHlsZVtmeC5wcm9wXT1meC5ub3crZngudW5pdDt9fX0pO2pRdWVyeS5mbi5vZmZzZXQ9ZnVu Y3Rpb24oKXt2YXIgbGVmdD0wLHRvcD0wLGVsZW09dGhpc1swXSxyZXN1bHRzO2lmKGVsZW0pd2l0 aChqUXVlcnkuYnJvd3Nlcil7dmFyIHBhcmVudD1lbGVtLnBhcmVudE5vZGUsb2Zmc2V0Q2hpbGQ9 ZWxlbSxvZmZzZXRQYXJlbnQ9ZWxlbS5vZmZzZXRQYXJlbnQsZG9jPWVsZW0ub3duZXJEb2N1bWVu dCxzYWZhcmkyPXNhZmFyaSYmcGFyc2VJbnQodmVyc2lvbik8NTIyJiYhL2Fkb2JlYWlyL2kudGVz dCh1c2VyQWdlbnQpLGNzcz1qUXVlcnkuY3VyQ1NTLGZpeGVkPWNzcyhlbGVtLCJwb3NpdGlvbiIp PT0iZml4ZWQiO2lmKGVsZW0uZ2V0Qm91bmRpbmdDbGllbnRSZWN0KXt2YXIgYm94PWVsZW0uZ2V0 Qm91bmRpbmdDbGllbnRSZWN0KCk7YWRkKGJveC5sZWZ0K01hdGgubWF4KGRvYy5kb2N1bWVudEVs ZW1lbnQuc2Nyb2xsTGVmdCxkb2MuYm9keS5zY3JvbGxMZWZ0KSxib3gudG9wK01hdGgubWF4KGRv Yy5kb2N1bWVudEVsZW1lbnQuc2Nyb2xsVG9wLGRvYy5ib2R5LnNjcm9sbFRvcCkpO2FkZCgtZG9j LmRvY3VtZW50RWxlbWVudC5jbGllbnRMZWZ0LC1kb2MuZG9jdW1lbnRFbGVtZW50LmNsaWVudFRv cCk7fWVsc2V7YWRkKGVsZW0ub2Zmc2V0TGVmdCxlbGVtLm9mZnNldFRvcCk7d2hpbGUob2Zmc2V0 UGFyZW50KXthZGQob2Zmc2V0UGFyZW50Lm9mZnNldExlZnQsb2Zmc2V0UGFyZW50Lm9mZnNldFRv cCk7aWYobW96aWxsYSYmIS9edChhYmxlfGR8aCkkL2kudGVzdChvZmZzZXRQYXJlbnQudGFnTmFt ZSl8fHNhZmFyaSYmIXNhZmFyaTIpYm9yZGVyKG9mZnNldFBhcmVudCk7aWYoIWZpeGVkJiZjc3Mo b2Zmc2V0UGFyZW50LCJwb3NpdGlvbiIpPT0iZml4ZWQiKWZpeGVkPXRydWU7b2Zmc2V0Q2hpbGQ9 L15ib2R5JC9pLnRlc3Qob2Zmc2V0UGFyZW50LnRhZ05hbWUpP29mZnNldENoaWxkOm9mZnNldFBh cmVudDtvZmZzZXRQYXJlbnQ9b2Zmc2V0UGFyZW50Lm9mZnNldFBhcmVudDt9d2hpbGUocGFyZW50 JiZwYXJlbnQudGFnTmFtZSYmIS9eYm9keXxodG1sJC9pLnRlc3QocGFyZW50LnRhZ05hbWUpKXtp ZighL15pbmxpbmV8dGFibGUuKiQvaS50ZXN0KGNzcyhwYXJlbnQsImRpc3BsYXkiKSkpYWRkKC1w YXJlbnQuc2Nyb2xsTGVmdCwtcGFyZW50LnNjcm9sbFRvcCk7aWYobW96aWxsYSYmY3NzKHBhcmVu dCwib3ZlcmZsb3ciKSE9InZpc2libGUiKWJvcmRlcihwYXJlbnQpO3BhcmVudD1wYXJlbnQucGFy ZW50Tm9kZTt9aWYoKHNhZmFyaTImJihmaXhlZHx8Y3NzKG9mZnNldENoaWxkLCJwb3NpdGlvbiIp PT0iYWJzb2x1dGUiKSl8fChtb3ppbGxhJiZjc3Mob2Zmc2V0Q2hpbGQsInBvc2l0aW9uIikhPSJh YnNvbHV0ZSIpKWFkZCgtZG9jLmJvZHkub2Zmc2V0TGVmdCwtZG9jLmJvZHkub2Zmc2V0VG9wKTtp ZihmaXhlZClhZGQoTWF0aC5tYXgoZG9jLmRvY3VtZW50RWxlbWVudC5zY3JvbGxMZWZ0LGRvYy5i b2R5LnNjcm9sbExlZnQpLE1hdGgubWF4KGRvYy5kb2N1bWVudEVsZW1lbnQuc2Nyb2xsVG9wLGRv Yy5ib2R5LnNjcm9sbFRvcCkpO31yZXN1bHRzPXt0b3A6dG9wLGxlZnQ6bGVmdH07fWZ1bmN0aW9u IGJvcmRlcihlbGVtKXthZGQoalF1ZXJ5LmN1ckNTUyhlbGVtLCJib3JkZXJMZWZ0V2lkdGgiLHRy dWUpLGpRdWVyeS5jdXJDU1MoZWxlbSwiYm9yZGVyVG9wV2lkdGgiLHRydWUpKTt9ZnVuY3Rpb24g YWRkKGwsdCl7bGVmdCs9cGFyc2VJbnQobCwxMCl8fDA7dG9wKz1wYXJzZUludCh0LDEwKXx8MDt9 cmV0dXJuIHJlc3VsdHM7fTtqUXVlcnkuZm4uZXh0ZW5kKHtwb3NpdGlvbjpmdW5jdGlvbigpe3Zh ciBsZWZ0PTAsdG9wPTAscmVzdWx0cztpZih0aGlzWzBdKXt2YXIgb2Zmc2V0UGFyZW50PXRoaXMu b2Zmc2V0UGFyZW50KCksb2Zmc2V0PXRoaXMub2Zmc2V0KCkscGFyZW50T2Zmc2V0PS9eYm9keXxo dG1sJC9pLnRlc3Qob2Zmc2V0UGFyZW50WzBdLnRhZ05hbWUpP3t0b3A6MCxsZWZ0OjB9Om9mZnNl dFBhcmVudC5vZmZzZXQoKTtvZmZzZXQudG9wLT1udW0odGhpcywnbWFyZ2luVG9wJyk7b2Zmc2V0 LmxlZnQtPW51bSh0aGlzLCdtYXJnaW5MZWZ0Jyk7cGFyZW50T2Zmc2V0LnRvcCs9bnVtKG9mZnNl dFBhcmVudCwnYm9yZGVyVG9wV2lkdGgnKTtwYXJlbnRPZmZzZXQubGVmdCs9bnVtKG9mZnNldFBh cmVudCwnYm9yZGVyTGVmdFdpZHRoJyk7cmVzdWx0cz17dG9wOm9mZnNldC50b3AtcGFyZW50T2Zm c2V0LnRvcCxsZWZ0Om9mZnNldC5sZWZ0LXBhcmVudE9mZnNldC5sZWZ0fTt9cmV0dXJuIHJlc3Vs dHM7fSxvZmZzZXRQYXJlbnQ6ZnVuY3Rpb24oKXt2YXIgb2Zmc2V0UGFyZW50PXRoaXNbMF0ub2Zm c2V0UGFyZW50O3doaWxlKG9mZnNldFBhcmVudCYmKCEvXmJvZHl8aHRtbCQvaS50ZXN0KG9mZnNl dFBhcmVudC50YWdOYW1lKSYmalF1ZXJ5LmNzcyhvZmZzZXRQYXJlbnQsJ3Bvc2l0aW9uJyk9PSdz dGF0aWMnKSlvZmZzZXRQYXJlbnQ9b2Zmc2V0UGFyZW50Lm9mZnNldFBhcmVudDtyZXR1cm4galF1 ZXJ5KG9mZnNldFBhcmVudCk7fX0pO2pRdWVyeS5lYWNoKFsnTGVmdCcsJ1RvcCddLGZ1bmN0aW9u KGksbmFtZSl7dmFyIG1ldGhvZD0nc2Nyb2xsJytuYW1lO2pRdWVyeS5mblttZXRob2RdPWZ1bmN0 aW9uKHZhbCl7aWYoIXRoaXNbMF0pcmV0dXJuO3JldHVybiB2YWwhPXVuZGVmaW5lZD90aGlzLmVh Y2goZnVuY3Rpb24oKXt0aGlzPT13aW5kb3d8fHRoaXM9PWRvY3VtZW50P3dpbmRvdy5zY3JvbGxU byghaT92YWw6alF1ZXJ5KHdpbmRvdykuc2Nyb2xsTGVmdCgpLGk/dmFsOmpRdWVyeSh3aW5kb3cp LnNjcm9sbFRvcCgpKTp0aGlzW21ldGhvZF09dmFsO30pOnRoaXNbMF09PXdpbmRvd3x8dGhpc1sw XT09ZG9jdW1lbnQ/c2VsZltpPydwYWdlWU9mZnNldCc6J3BhZ2VYT2Zmc2V0J118fGpRdWVyeS5i b3hNb2RlbCYmZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50W21ldGhvZF18fGRvY3VtZW50LmJvZHlb bWV0aG9kXTp0aGlzWzBdW21ldGhvZF07fTt9KTtqUXVlcnkuZWFjaChbIkhlaWdodCIsIldpZHRo Il0sZnVuY3Rpb24oaSxuYW1lKXt2YXIgdGw9aT8iTGVmdCI6IlRvcCIsYnI9aT8iUmlnaHQiOiJC b3R0b20iO2pRdWVyeS5mblsiaW5uZXIiK25hbWVdPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXNbbmFt ZS50b0xvd2VyQ2FzZSgpXSgpK251bSh0aGlzLCJwYWRkaW5nIit0bCkrbnVtKHRoaXMsInBhZGRp bmciK2JyKTt9O2pRdWVyeS5mblsib3V0ZXIiK25hbWVdPWZ1bmN0aW9uKG1hcmdpbil7cmV0dXJu IHRoaXNbImlubmVyIituYW1lXSgpK251bSh0aGlzLCJib3JkZXIiK3RsKyJXaWR0aCIpK251bSh0 aGlzLCJib3JkZXIiK2JyKyJXaWR0aCIpKyhtYXJnaW4/bnVtKHRoaXMsIm1hcmdpbiIrdGwpK251 bSh0aGlzLCJtYXJnaW4iK2JyKTowKTt9O30pO30pKCk7ClwgTm8gbmV3bGluZSBhdCBlbmQgb2Yg ZmlsZQpkaWZmIC0tZ2l0IGEvd3VpL3NyYy9wdWJsaWMvamF2YXNjcmlwdHMvanF1ZXJ5LXRyZWV2 aWV3L2pxdWVyeS50cmVldmlldy5hc3luYy5qcyBiL3d1aS9zcmMvcHVibGljL2phdmFzY3JpcHRz L2pxdWVyeS10cmVldmlldy9qcXVlcnkudHJlZXZpZXcuYXN5bmMuanMKaW5kZXggZDI3N2EzMi4u N2Q1ZWIyZiAxMDA2NDQKLS0tIGEvd3VpL3NyYy9wdWJsaWMvamF2YXNjcmlwdHMvanF1ZXJ5LXRy ZWV2aWV3L2pxdWVyeS50cmVldmlldy5hc3luYy5qcworKysgYi93dWkvc3JjL3B1YmxpYy9qYXZh c2NyaXB0cy9qcXVlcnktdHJlZXZpZXcvanF1ZXJ5LnRyZWV2aWV3LmFzeW5jLmpzCkBAIC00OSwz MSArNDksMjcgQEAgZnVuY3Rpb24gbG9hZChzZXR0aW5ncywgcGFyYW1zLCBjaGlsZCwgY29udGFp bmVyKSB7CiAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAg ICAgICAgICAgICBjdXJyZW50Lmh0bWwoIjxzcGFuIGNsYXNzPVwiIiArIHNldHRpbmdzLnNwYW5f Y2xhc3MgKyAiXCIiICsgc3Bhbl9vbmNsaWNrICsgIj4iICsgbGlua19vcGVuICsgdGhpcy50ZXh0 ICsgbGlua19jbG9zZSArICI8L3NwYW4+IikKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAu YXBwZW5kVG8ocGFyZW50KTsKLSAgICAgICAgICAgICAgICAgICAgICAgICAgJCgnbGkgIycgKyB0 aGlzLmlkICsgJyBzcGFuID4gYScpCi0gICAgICAgICAgICAgICAgICAgICAgICAgICAgLmJpbmQo J2NsaWNrJywgZnVuY3Rpb24oKSB7ICAgICAgICAgICAgCisvLyAgICAgICAgICAgICAgICAgICAg ICAgICAgJCgnbGkgIycgKyB0aGlzLmlkICsgJyBzcGFuID4gYScpCisvLyAgICAgICAgICAgICAg ICAgICAgICAgICAgICAuYmluZCgnY2xpY2snLCBmdW5jdGlvbigpIHsgCiAvLyAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICQuYWpheCh7CiAvLyAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgdXJsOiB0aGlzLmhyZWYsCiAvLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg dHlwZTogJ0dFVCcsCiAvLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YToge2Fq YXg6dHJ1ZX0sCiAvLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YVR5cGU6ICdo dG1sJywKLS8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWNjZXNzOiBmdW5jdGlv bihkYXRhKSB7IGFsZXJ0KGRhdGEpO30sCisvLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgc3VjY2VzczogZnVuY3Rpb24oZGF0YSkgeyAKKy8vICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgIHZhciB3cmFwcGVkX2RhdGEgPSAkKGRhdGEpLm5vdCgnZGl2I3NpZGUtdG9vbGJh cicpOy8vLmZpbmQoJyNuYXZpZ2F0aW9uLXRhYnMnKTsKKy8vICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICQoJyNzaWRlLXRvb2xiYXInKS5odG1sKCQoZGF0YSkuZmluZCgnZGl2LnRv b2xiYXInKSk7CisvLyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkKCcjdGFicy1h bmQtY29udGVudC1jb250YWluZXInKS5odG1sKCQoZGF0YSkubm90KCdkaXYjc2lkZS10b29sYmFy JykpOworLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sCiAvLyAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgZXJyb3I6IGZ1bmN0aW9uKHhocikge2FsZXJ0KHhoci5zdGF0 dXMgKyAnICcgKyB4aHIuc3RhdHVzVGV4dCk7fQogLy8gICAgICAgICAgICAgICAgICAgICAgICAg ICAgICB9KQotICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJCgnI2NvbnRlbnQtYXJlYScp LmxvYWQodGhpcy5ocmVmLHthamF4OnRydWV9KTsKLSAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgIHZhciBuZXdfaWQgPSAkKHRoaXMpLnBhcmVudCgpLnBhcmVudCgpLmdldCgwKS5pZDsKLSAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICQoJ3VsW2NsYXNzPXRhYl9uYXZdIGEnKS5lYWNo KGZ1bmN0aW9uKCl7Ci0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuaHJlZiA9 IHRoaXMuaHJlZi5zbGljZSgwLHRoaXMuaHJlZi5sYXN0SW5kZXhPZignLycrMSkpICsgbmV3X2lk OwotICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7Ci0gICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAkKCd1bFtjbGFzcz10YWJfbmF2XSBsaScpLmVhY2goZnVuY3Rpb24oKXsKLSAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJCh0aGlzKS5yZW1vdmVDbGFzcygnY3VycmVu dCcpOwotICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7Ci0gICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAkKCcjbmF2X3N1bW1hcnknKS5hZGRDbGFzcygnY3VycmVudCcpOworICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgLy92YXIgbmV3X2lkID0gJCh0aGlzKS5wYXJlbnQo KS5wYXJlbnQoKS5nZXQoMCkuaWQ7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvL3Zh ciBjdXJyZW50X2UgPSAkKCdzcGFuW2NsYXNzXj1jdXJyZW50X10nKTsKICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgIC8vY3VycmVudF9lLnJlbW92ZUNsYXNzKGN1cnJlbnRfZS5hdHRyKCdj bGFzcycpKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vJCh0aGlzKS5hZGRDbGFz cygnY3VycmVudF9mb2xkZXInKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vdmFy IG15X2NvbnRhaW5lciA9ICQoY29udGFpbmVyKTsKLSAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgIHJldHVybiBmYWxzZTsKLSAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTsKKy8vICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOworLy8gICAgICAgICAgICAg ICAgICAgICAgICAgICAgfSk7CiAKICAgICAgICAgICAgICAgICAgICAgICAgIH0KIAkJCWlmICh0 aGlzLmNsYXNzZXMpIHsKZGlmZiAtLWdpdCBhL3d1aS9zcmMvcHVibGljL2phdmFzY3JpcHRzL2px dWVyeS10cmVldmlldy9vdmlydC50cmVldmlldy5jc3MgYi93dWkvc3JjL3B1YmxpYy9qYXZhc2Ny aXB0cy9qcXVlcnktdHJlZXZpZXcvb3ZpcnQudHJlZXZpZXcuY3NzCmluZGV4IDJjNGQzODYuLjU4 YTc5MmUgMTAwNjQ0Ci0tLSBhL3d1aS9zcmMvcHVibGljL2phdmFzY3JpcHRzL2pxdWVyeS10cmVl dmlldy9vdmlydC50cmVldmlldy5jc3MKKysrIGIvd3VpL3NyYy9wdWJsaWMvamF2YXNjcmlwdHMv anF1ZXJ5LXRyZWV2aWV3L292aXJ0LnRyZWV2aWV3LmNzcwpAQCAtMzEsMTEgKzMxLDEzIEBACiAu dHJlZXZpZXcgYS5zZWxlY3RlZCB7CiAJYmFja2dyb3VuZC1jb2xvcjogI0RFRTdFQjsKIH0KKy50 cmVldmlldyBhIHt0ZXh0LWRlY29yYXRpb246bm9uZTt9CiAKKy50cmVldmlldyBhOnZpc2l0ZWR7 Y29sb3I6IzAwMDBGRjt9CiAKICN0cmVlY29udHJvbCB7IG1hcmdpbjogMWVtIDA7IGRpc3BsYXk6 IG5vbmU7IH0KIAotLnRyZWV2aWV3IC5ob3ZlciB7IGJhY2tncm91bmQ6I0RFRTdFQjsgY3Vyc29y OiBwb2ludGVyOyB9CisvKi50cmVldmlldyAuaG92ZXIgeyBiYWNrZ3JvdW5kOiNERUU3RUI7IGN1 cnNvcjogcG9pbnRlcjsgfSovCiAKIC50cmVldmlldyBsaSB7IGJhY2tncm91bmQ6IHVybChpbWFn ZXMvdHJlZXZpZXctZGVmYXVsdC1saW5lLmdpZikgMCAwIG5vLXJlcGVhdDsgfQogLnRyZWV2aWV3 IGxpLmNvbGxhcHNhYmxlLCAudHJlZXZpZXcgbGkuZXhwYW5kYWJsZSB7IGJhY2tncm91bmQtcG9z aXRpb246IDAgLTE3NnB4OyB9CkBAIC02NywxMCArNjksMTAgQEAKIC5maWxldHJlZSBzcGFuLmZp bGUuaG92ZXIgeyBiYWNrZ3JvdW5kOiAjREVFN0VCIHVybChpbWFnZXMvaWNvbl92bXBvb2wucG5n KSAwIDAgbm8tcmVwZWF0OyB9CiAKIC5jdXJyZW50X2ZvbGRlciwgLmN1cnJlbnRfZm9sZGVyLmhv dmVyIHsgcGFkZGluZzogNnB4IDBwdCA1cHggMjhweDsgYmFja2dyb3VuZDojNjk4RkE2IHVybChp bWFnZXMvaWNvbl9oZHdhcmVwb29sLnBuZykgNHB4IDJweCBuby1yZXBlYXQ7IGNvbG9yOiNGRkZG RkY7IGRpc3BsYXk6YmxvY2s7IH0KLS5jdXJyZW50X2ZvbGRlciBhIHtjb2xvcjojRkZGRkZGOyB9 CisuY3VycmVudF9mb2xkZXIgYSwgLmN1cnJlbnRfZm9sZGVyIGE6dmlzaXRlZCB7Y29sb3I6I0ZG RkZGRjsgfQogCiAuY3VycmVudF9maWxlLCAuY3VycmVudF9maWxlLmhvdmVyIHsgcGFkZGluZzog NnB4IDBwdCA1cHggMjhweDsgYmFja2dyb3VuZDojNjk4RkE2IHVybChpbWFnZXMvaWNvbl92bXBv b2wucG5nKSA0cHggMnB4IG5vLXJlcGVhdDsgY29sb3I6I0ZGRkZGRjsgZGlzcGxheTpibG9jazsg fQotLmN1cnJlbnRfZmlsZSBhIHtjb2xvcjojRkZGRkZGO30KKy5jdXJyZW50X2ZpbGUgYSwgLmN1 cnJlbnRfZmlsZSBhOnZpc2l0ZWQge2NvbG9yOiNGRkZGRkY7fQogCiAuZGlzYWJsZWRfZm9sZGVy LCAuZGlzYWJsZWRfZm9sZGVyLmhvdmVyIHsgCiAgICAgcGFkZGluZzogNHB4IDBwdCA1cHggMjRw eDsgCmRpZmYgLS1naXQgYS93dWkvc3JjL3B1YmxpYy9qYXZhc2NyaXB0cy9qcXVlcnkubGl2ZXF1 ZXJ5LmpzIGIvd3VpL3NyYy9wdWJsaWMvamF2YXNjcmlwdHMvanF1ZXJ5LmxpdmVxdWVyeS5qcwpp bmRleCBkZmVkOWZlLi5lZTdjNWYxIDEwMDY0NAotLS0gYS93dWkvc3JjL3B1YmxpYy9qYXZhc2Ny aXB0cy9qcXVlcnkubGl2ZXF1ZXJ5LmpzCisrKyBiL3d1aS9zcmMvcHVibGljL2phdmFzY3JpcHRz L2pxdWVyeS5saXZlcXVlcnkuanMKQEAgLTIsNyArMiw3IEBACiAgKiBEdWFsIGxpY2Vuc2VkIHVu ZGVyIHRoZSBNSVQgKGh0dHA6Ly93d3cub3BlbnNvdXJjZS5vcmcvbGljZW5zZXMvbWl0LWxpY2Vu c2UucGhwKSAKICAqIGFuZCBHUEwgKGh0dHA6Ly93d3cub3BlbnNvdXJjZS5vcmcvbGljZW5zZXMv Z3BsLWxpY2Vuc2UucGhwKSBsaWNlbnNlcy4KICAqCi0gKiBWZXJzaW9uOiBAVkVSU0lPTgorICog VmVyc2lvbjogMS4wLjIKICAqIFJlcXVpcmVzIGpRdWVyeSAxLjEuMysKICAqIERvY3M6IGh0dHA6 Ly9kb2NzLmpxdWVyeS5jb20vUGx1Z2lucy9saXZlcXVlcnkKICAqLwpkaWZmIC0tZ2l0IGEvd3Vp L3NyYy9wdWJsaWMvamF2YXNjcmlwdHMvanF1ZXJ5LmxpdmVxdWVyeS5taW4uanMgYi93dWkvc3Jj L3B1YmxpYy9qYXZhc2NyaXB0cy9qcXVlcnkubGl2ZXF1ZXJ5Lm1pbi5qcwpuZXcgZmlsZSBtb2Rl IDEwMDY0NAppbmRleCAwMDAwMDAwLi45OTNiNGQzCi0tLSAvZGV2L251bGwKKysrIGIvd3VpL3Ny Yy9wdWJsaWMvamF2YXNjcmlwdHMvanF1ZXJ5LmxpdmVxdWVyeS5taW4uanMKQEAgLTAsMCArMSwx MSBAQAorLyogQ29weXJpZ2h0IChjKSAyMDA3IEJyYW5kb24gQWFyb24gKGJyYW5kb24uYWFyb25A Z21haWwuY29tIHx8IGh0dHA6Ly9icmFuZG9uYWFyb24ubmV0KQorICogRHVhbCBsaWNlbnNlZCB1 bmRlciB0aGUgTUlUIChodHRwOi8vd3d3Lm9wZW5zb3VyY2Uub3JnL2xpY2Vuc2VzL21pdC1saWNl bnNlLnBocCkgCisgKiBhbmQgR1BMIChodHRwOi8vd3d3Lm9wZW5zb3VyY2Uub3JnL2xpY2Vuc2Vz L2dwbC1saWNlbnNlLnBocCkgbGljZW5zZXMuCisgKgorICogVmVyc2lvbjogMS4wLjIKKyAqIFJl cXVpcmVzIGpRdWVyeSAxLjEuMysKKyAqIERvY3M6IGh0dHA6Ly9kb2NzLmpxdWVyeS5jb20vUGx1 Z2lucy9saXZlcXVlcnkKKyAqLworKGZ1bmN0aW9uKCQpeyQuZXh0ZW5kKCQuZm4se2xpdmVxdWVy eTpmdW5jdGlvbih0eXBlLGZuLGZuMil7dmFyIHNlbGY9dGhpcyxxO2lmKCQuaXNGdW5jdGlvbih0 eXBlKSlmbjI9Zm4sZm49dHlwZSx0eXBlPXVuZGVmaW5lZDskLmVhY2goJC5saXZlcXVlcnkucXVl cmllcyxmdW5jdGlvbihpLHF1ZXJ5KXtpZihzZWxmLnNlbGVjdG9yPT1xdWVyeS5zZWxlY3RvciYm c2VsZi5jb250ZXh0PT1xdWVyeS5jb250ZXh0JiZ0eXBlPT1xdWVyeS50eXBlJiYoIWZufHxmbi4k bHFndWlkPT1xdWVyeS5mbi4kbHFndWlkKSYmKCFmbjJ8fGZuMi4kbHFndWlkPT1xdWVyeS5mbjIu JGxxZ3VpZCkpcmV0dXJuKHE9cXVlcnkpJiZmYWxzZTt9KTtxPXF8fG5ldyAkLmxpdmVxdWVyeSh0 aGlzLnNlbGVjdG9yLHRoaXMuY29udGV4dCx0eXBlLGZuLGZuMik7cS5zdG9wcGVkPWZhbHNlOyQu bGl2ZXF1ZXJ5LnJ1bihxLmlkKTtyZXR1cm4gdGhpczt9LGV4cGlyZTpmdW5jdGlvbih0eXBlLGZu LGZuMil7dmFyIHNlbGY9dGhpcztpZigkLmlzRnVuY3Rpb24odHlwZSkpZm4yPWZuLGZuPXR5cGUs dHlwZT11bmRlZmluZWQ7JC5lYWNoKCQubGl2ZXF1ZXJ5LnF1ZXJpZXMsZnVuY3Rpb24oaSxxdWVy eSl7aWYoc2VsZi5zZWxlY3Rvcj09cXVlcnkuc2VsZWN0b3ImJnNlbGYuY29udGV4dD09cXVlcnku Y29udGV4dCYmKCF0eXBlfHx0eXBlPT1xdWVyeS50eXBlKSYmKCFmbnx8Zm4uJGxxZ3VpZD09cXVl cnkuZm4uJGxxZ3VpZCkmJighZm4yfHxmbjIuJGxxZ3VpZD09cXVlcnkuZm4yLiRscWd1aWQpJiYh dGhpcy5zdG9wcGVkKSQubGl2ZXF1ZXJ5LnN0b3AocXVlcnkuaWQpO30pO3JldHVybiB0aGlzO319 KTskLmxpdmVxdWVyeT1mdW5jdGlvbihzZWxlY3Rvcixjb250ZXh0LHR5cGUsZm4sZm4yKXt0aGlz LnNlbGVjdG9yPXNlbGVjdG9yO3RoaXMuY29udGV4dD1jb250ZXh0fHxkb2N1bWVudDt0aGlzLnR5 cGU9dHlwZTt0aGlzLmZuPWZuO3RoaXMuZm4yPWZuMjt0aGlzLmVsZW1lbnRzPVtdO3RoaXMuc3Rv cHBlZD1mYWxzZTt0aGlzLmlkPSQubGl2ZXF1ZXJ5LnF1ZXJpZXMucHVzaCh0aGlzKS0xO2ZuLiRs cWd1aWQ9Zm4uJGxxZ3VpZHx8JC5saXZlcXVlcnkuZ3VpZCsrO2lmKGZuMilmbjIuJGxxZ3VpZD1m bjIuJGxxZ3VpZHx8JC5saXZlcXVlcnkuZ3VpZCsrO3JldHVybiB0aGlzO307JC5saXZlcXVlcnku cHJvdG90eXBlPXtzdG9wOmZ1bmN0aW9uKCl7dmFyIHF1ZXJ5PXRoaXM7aWYodGhpcy50eXBlKXRo aXMuZWxlbWVudHMudW5iaW5kKHRoaXMudHlwZSx0aGlzLmZuKTtlbHNlIGlmKHRoaXMuZm4yKXRo aXMuZWxlbWVudHMuZWFjaChmdW5jdGlvbihpLGVsKXtxdWVyeS5mbjIuYXBwbHkoZWwpO30pO3Ro aXMuZWxlbWVudHM9W107dGhpcy5zdG9wcGVkPXRydWU7fSxydW46ZnVuY3Rpb24oKXtpZih0aGlz LnN0b3BwZWQpcmV0dXJuO3ZhciBxdWVyeT10aGlzO3ZhciBvRWxzPXRoaXMuZWxlbWVudHMsZWxz PSQodGhpcy5zZWxlY3Rvcix0aGlzLmNvbnRleHQpLG5FbHM9ZWxzLm5vdChvRWxzKTt0aGlzLmVs ZW1lbnRzPWVscztpZih0aGlzLnR5cGUpe25FbHMuYmluZCh0aGlzLnR5cGUsdGhpcy5mbik7aWYo b0Vscy5sZW5ndGg+MCkkLmVhY2gob0VscyxmdW5jdGlvbihpLGVsKXtpZigkLmluQXJyYXkoZWws ZWxzKTwwKSQuZXZlbnQucmVtb3ZlKGVsLHF1ZXJ5LnR5cGUscXVlcnkuZm4pO30pO31lbHNle25F bHMuZWFjaChmdW5jdGlvbigpe3F1ZXJ5LmZuLmFwcGx5KHRoaXMpO30pO2lmKHRoaXMuZm4yJiZv RWxzLmxlbmd0aD4wKSQuZWFjaChvRWxzLGZ1bmN0aW9uKGksZWwpe2lmKCQuaW5BcnJheShlbCxl bHMpPDApcXVlcnkuZm4yLmFwcGx5KGVsKTt9KTt9fX07JC5leHRlbmQoJC5saXZlcXVlcnkse2d1 aWQ6MCxxdWVyaWVzOltdLHF1ZXVlOltdLHJ1bm5pbmc6ZmFsc2UsdGltZW91dDpudWxsLGNoZWNr UXVldWU6ZnVuY3Rpb24oKXtpZigkLmxpdmVxdWVyeS5ydW5uaW5nJiYkLmxpdmVxdWVyeS5xdWV1 ZS5sZW5ndGgpe3ZhciBsZW5ndGg9JC5saXZlcXVlcnkucXVldWUubGVuZ3RoO3doaWxlKGxlbmd0 aC0tKSQubGl2ZXF1ZXJ5LnF1ZXJpZXNbJC5saXZlcXVlcnkucXVldWUuc2hpZnQoKV0ucnVuKCk7 fX0scGF1c2U6ZnVuY3Rpb24oKXskLmxpdmVxdWVyeS5ydW5uaW5nPWZhbHNlO30scGxheTpmdW5j dGlvbigpeyQubGl2ZXF1ZXJ5LnJ1bm5pbmc9dHJ1ZTskLmxpdmVxdWVyeS5ydW4oKTt9LHJlZ2lz dGVyUGx1Z2luOmZ1bmN0aW9uKCl7JC5lYWNoKGFyZ3VtZW50cyxmdW5jdGlvbihpLG4pe2lmKCEk LmZuW25dKXJldHVybjt2YXIgb2xkPSQuZm5bbl07JC5mbltuXT1mdW5jdGlvbigpe3ZhciByPW9s ZC5hcHBseSh0aGlzLGFyZ3VtZW50cyk7JC5saXZlcXVlcnkucnVuKCk7cmV0dXJuIHI7fX0pO30s cnVuOmZ1bmN0aW9uKGlkKXtpZihpZCE9dW5kZWZpbmVkKXtpZigkLmluQXJyYXkoaWQsJC5saXZl cXVlcnkucXVldWUpPDApJC5saXZlcXVlcnkucXVldWUucHVzaChpZCk7fWVsc2UKKyQuZWFjaCgk LmxpdmVxdWVyeS5xdWVyaWVzLGZ1bmN0aW9uKGlkKXtpZigkLmluQXJyYXkoaWQsJC5saXZlcXVl cnkucXVldWUpPDApJC5saXZlcXVlcnkucXVldWUucHVzaChpZCk7fSk7aWYoJC5saXZlcXVlcnku dGltZW91dCljbGVhclRpbWVvdXQoJC5saXZlcXVlcnkudGltZW91dCk7JC5saXZlcXVlcnkudGlt ZW91dD1zZXRUaW1lb3V0KCQubGl2ZXF1ZXJ5LmNoZWNrUXVldWUsMjApO30sc3RvcDpmdW5jdGlv bihpZCl7aWYoaWQhPXVuZGVmaW5lZCkkLmxpdmVxdWVyeS5xdWVyaWVzW2lkXS5zdG9wKCk7ZWxz ZQorJC5lYWNoKCQubGl2ZXF1ZXJ5LnF1ZXJpZXMsZnVuY3Rpb24oaWQpeyQubGl2ZXF1ZXJ5LnF1 ZXJpZXNbaWRdLnN0b3AoKTt9KTt9fSk7JC5saXZlcXVlcnkucmVnaXN0ZXJQbHVnaW4oJ2FwcGVu ZCcsJ3ByZXBlbmQnLCdhZnRlcicsJ2JlZm9yZScsJ3dyYXAnLCdhdHRyJywncmVtb3ZlQXR0cics J2FkZENsYXNzJywncmVtb3ZlQ2xhc3MnLCd0b2dnbGVDbGFzcycsJ2VtcHR5JywncmVtb3ZlJyk7 JChmdW5jdGlvbigpeyQubGl2ZXF1ZXJ5LnBsYXkoKTt9KTt2YXIgaW5pdD0kLnByb3RvdHlwZS5p bml0OyQucHJvdG90eXBlLmluaXQ9ZnVuY3Rpb24oYSxjKXt2YXIgcj1pbml0LmFwcGx5KHRoaXMs YXJndW1lbnRzKTtpZihhJiZhLnNlbGVjdG9yKXIuY29udGV4dD1hLmNvbnRleHQsci5zZWxlY3Rv cj1hLnNlbGVjdG9yO2lmKHR5cGVvZiBhPT0nc3RyaW5nJylyLmNvbnRleHQ9Y3x8ZG9jdW1lbnQs ci5zZWxlY3Rvcj1hO3JldHVybiByO307JC5wcm90b3R5cGUuaW5pdC5wcm90b3R5cGU9JC5wcm90 b3R5cGU7fSkoalF1ZXJ5KTsKXCBObyBuZXdsaW5lIGF0IGVuZCBvZiBmaWxlCmRpZmYgLS1naXQg YS93dWkvc3JjL3B1YmxpYy9qYXZhc2NyaXB0cy9qcXVlcnkubGl2ZXF1ZXJ5LnBhY2suanMgYi93 dWkvc3JjL3B1YmxpYy9qYXZhc2NyaXB0cy9qcXVlcnkubGl2ZXF1ZXJ5LnBhY2suanMKbmV3IGZp bGUgbW9kZSAxMDA2NDQKaW5kZXggMDAwMDAwMC4uNzQ4NTY1NwotLS0gL2Rldi9udWxsCisrKyBi L3d1aS9zcmMvcHVibGljL2phdmFzY3JpcHRzL2pxdWVyeS5saXZlcXVlcnkucGFjay5qcwpAQCAt MCwwICsxLDkgQEAKKy8qIENvcHlyaWdodCAoYykgMjAwNyBCcmFuZG9uIEFhcm9uIChicmFuZG9u LmFhcm9uQGdtYWlsLmNvbSB8fCBodHRwOi8vYnJhbmRvbmFhcm9uLm5ldCkKKyAqIER1YWwgbGlj ZW5zZWQgdW5kZXIgdGhlIE1JVCAoaHR0cDovL3d3dy5vcGVuc291cmNlLm9yZy9saWNlbnNlcy9t aXQtbGljZW5zZS5waHApIAorICogYW5kIEdQTCAoaHR0cDovL3d3dy5vcGVuc291cmNlLm9yZy9s aWNlbnNlcy9ncGwtbGljZW5zZS5waHApIGxpY2Vuc2VzLgorICoKKyAqIFZlcnNpb246IDEuMC4y CisgKiBSZXF1aXJlcyBqUXVlcnkgMS4xLjMrCisgKiBEb2NzOiBodHRwOi8vZG9jcy5qcXVlcnku Y29tL1BsdWdpbnMvbGl2ZXF1ZXJ5CisgKi8KK2V2YWwoZnVuY3Rpb24ocCxhLGMsayxlLHIpe2U9 ZnVuY3Rpb24oYyl7cmV0dXJuKGM8YT8nJzplKHBhcnNlSW50KGMvYSkpKSsoKGM9YyVhKT4zNT9T dHJpbmcuZnJvbUNoYXJDb2RlKGMrMjkpOmMudG9TdHJpbmcoMzYpKX07aWYoIScnLnJlcGxhY2Uo L14vLFN0cmluZykpe3doaWxlKGMtLSlyW2UoYyldPWtbY118fGUoYyk7az1bZnVuY3Rpb24oZSl7 cmV0dXJuIHJbZV19XTtlPWZ1bmN0aW9uKCl7cmV0dXJuJ1xcdysnfTtjPTF9O3doaWxlKGMtLSlp ZihrW2NdKXA9cC5yZXBsYWNlKG5ldyBSZWdFeHAoJ1xcYicrZShjKSsnXFxiJywnZycpLGtbY10p O3JldHVybiBwfSgnKDQoJCl7JC5SKCQuNyx7Mzo0KGMsYixkKXs5IGU9MixxOzUoJC5PKGMpKWQ9 YixiPWMsYz16OyQuaCgkLjMuaiw0KGksYSl7NShlLjg9PWEuOCYmZS5nPT1hLmcmJmM9PWEubSYm KCFifHxiLiQ2PT1hLjcuJDYpJiYoIWR8fGQuJDY9PWEuby4kNikpbChxPWEpJiZ2fSk7cT1xfHxZ ICQuMygyLjgsMi5nLGMsYixkKTtxLnU9djskLjMucyhxLkYpO2wgMn0sVDo0KGMsYixkKXs5IGU9 Mjs1KCQuTyhjKSlkPWIsYj1jLGM9ejskLmgoJC4zLmosNChpLGEpezUoZS44PT1hLjgmJmUuZz09 YS5nJiYoIWN8fGM9PWEubSkmJighYnx8Yi4kNj09YS43LiQ2KSYmKCFkfHxkLiQ2PT1hLm8uJDYp JiYhMi51KSQuMy55KGEuRil9KTtsIDJ9fSk7JC4zPTQoZSxjLGEsYixkKXsyLjg9ZTsyLmc9Y3x8 UzsyLm09YTsyLjc9YjsyLm89ZDsyLnQ9W107Mi51PXY7Mi5GPSQuMy5qLksoMiktMTtiLiQ2PWIu JDZ8fCQuMy5JKys7NShkKWQuJDY9ZC4kNnx8JC4zLkkrKztsIDJ9OyQuMy5wPXt5OjQoKXs5IGI9 Mjs1KDIubSkyLnQuMTYoMi5tLDIuNyk7RSA1KDIubykyLnQuaCg0KGksYSl7Yi5vLngoYSl9KTsy LnQ9W107Mi51PVF9LHM6NCgpezUoMi51KWw7OSBiPTI7OSBjPTIudCx3PSQoMi44LDIuZyksSD13 LjExKGMpOzIudD13OzUoMi5tKXtILjEwKDIubSwyLjcpOzUoYy5DPjApJC5oKGMsNChpLGEpezUo JC5CKGEsdyk8MCkkLlouUChhLGIubSxiLjcpfSl9RXtILmgoNCgpe2IuNy54KDIpfSk7NSgyLm8m JmMuQz4wKSQuaChjLDQoaSxhKXs1KCQuQihhLHcpPDApYi5vLngoYSl9KX19fTskLlIoJC4zLHtJ OjAsajpbXSxrOltdLEE6dixEOlgsTjo0KCl7NSgkLjMuQSYmJC4zLmsuQyl7OSBhPSQuMy5rLkM7 VyhhLS0pJC4zLmpbJC4zLmsuVigpXS5zKCl9fSxVOjQoKXskLjMuQT12fSxNOjQoKXskLjMuQT1R OyQuMy5zKCl9LEw6NCgpeyQuaChHLDQoaSxuKXs1KCEkLjdbbl0pbDs5IGE9JC43W25dOyQuN1tu XT00KCl7OSByPWEueCgyLEcpOyQuMy5zKCk7bCByfX0pfSxzOjQoYil7NShiIT16KXs1KCQuQihi LCQuMy5rKTwwKSQuMy5rLksoYil9RSAkLmgoJC4zLmosNChhKXs1KCQuQihhLCQuMy5rKTwwKSQu My5rLksoYSl9KTs1KCQuMy5EKTFqKCQuMy5EKTskLjMuRD0xaSgkLjMuTiwxaCl9LHk6NChiKXs1 KGIhPXopJC4zLmpbYl0ueSgpO0UgJC5oKCQuMy5qLDQoYSl7JC4zLmpbYV0ueSgpfSl9fSk7JC4z LkwoXCcxZ1wnLFwnMWZcJyxcJzFlXCcsXCcxYlwnLFwnMWFcJyxcJzE5XCcsXCcxOFwnLFwnMTdc JyxcJzFjXCcsXCcxNVwnLFwnMWRcJyxcJ1BcJyk7JCg0KCl7JC4zLk0oKX0pOzkgZj0kLnAuSjsk LnAuSj00KGEsYyl7OSByPWYueCgyLEcpOzUoYSYmYS44KXIuZz1hLmcsci44PWEuODs1KDE0IGE9 PVwnMTNcJylyLmc9Y3x8UyxyLjg9YTtsIHJ9OyQucC5KLnA9JC5wfSkoMTIpOycsNjIsODIsJ3x8 dGhpc3xsaXZlcXVlcnl8ZnVuY3Rpb258aWZ8bHFndWlkfGZufHNlbGVjdG9yfHZhcnx8fHx8fHxj b250ZXh0fGVhY2h8fHF1ZXJpZXN8cXVldWV8cmV0dXJufHR5cGV8fGZuMnxwcm90b3R5cGV8fHxy dW58ZWxlbWVudHN8c3RvcHBlZHxmYWxzZXxlbHN8YXBwbHl8c3RvcHx1bmRlZmluZWR8cnVubmlu Z3xpbkFycmF5fGxlbmd0aHx0aW1lb3V0fGVsc2V8aWR8YXJndW1lbnRzfG5FbHN8Z3VpZHxpbml0 fHB1c2h8cmVnaXN0ZXJQbHVnaW58cGxheXxjaGVja1F1ZXVlfGlzRnVuY3Rpb258cmVtb3ZlfHRy dWV8ZXh0ZW5kfGRvY3VtZW50fGV4cGlyZXxwYXVzZXxzaGlmdHx3aGlsZXxudWxsfG5ld3xldmVu dHxiaW5kfG5vdHxqUXVlcnl8c3RyaW5nfHR5cGVvZnx0b2dnbGVDbGFzc3x1bmJpbmR8YWRkQ2xh c3N8cmVtb3ZlQXR0cnxhdHRyfHdyYXB8YmVmb3JlfHJlbW92ZUNsYXNzfGVtcHR5fGFmdGVyfHBy ZXBlbmR8YXBwZW5kfDIwfHNldFRpbWVvdXR8Y2xlYXJUaW1lb3V0Jy5zcGxpdCgnfCcpLDAse30p KQpcIE5vIG5ld2xpbmUgYXQgZW5kIG9mIGZpbGUKLS0gCjEuNS40LjEKCi== --=-FeeZJ3ybHM80BpIC4CGc Content-Disposition: attachment; filename=0003-facebox.close-not-needed-anywhere.patch Content-Type: application/mbox; name=0003-facebox.close-not-needed-anywhere.patch Content-Transfer-Encoding: 7bit From jguiditt at redhat.com Fri May 30 20:02:38 2008 From: jguiditt at redhat.com (Jason Guiditta) Date: Fri, 30 May 2008 16:02:38 -0400 Subject: [Ovirt-devel] [PATCH] facebox.close not needed anywhere Message-ID: Signed-off-by: Jason Guiditta --- wui/src/app/views/layouts/redux.rhtml | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/wui/src/app/views/layouts/redux.rhtml b/wui/src/app/views/layouts/redux.rhtml index 9b906f0..00ec126 100644 --- a/wui/src/app/views/layouts/redux.rhtml +++ b/wui/src/app/views/layouts/redux.rhtml @@ -44,7 +44,6 @@ action_type: "hyperlink" }) $('a[rel*=facebox]').livequery(function(){$(this).facebox();},function(){}); - $('a[rel*=close]').trigger('close.facebox'); $('#side a').livequery(function(){ $(this).bind('click', function(){ $('#side span').each(function(){ -- 1.5.4.1 --=-FeeZJ3ybHM80BpIC4CGc-- From mmorsi at redhat.com Fri May 30 22:31:04 2008 From: mmorsi at redhat.com (Mohammed Morsi) Date: Fri, 30 May 2008 18:31:04 -0400 Subject: [Ovirt-devel] [PATCH] small merge fixes Message-ID: Signed-off-by: Mohammed Morsi --- wui/src/app/views/hardware/show.html.erb | 3 ++- wui/src/app/views/hardware/show_vms.rhtml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/wui/src/app/views/hardware/show.html.erb b/wui/src/app/views/hardware/show.html.erb index 2952f23..1c8092a 100644 --- a/wui/src/app/views/hardware/show.html.erb +++ b/wui/src/app/views/hardware/show.html.erb @@ -11,6 +11,8 @@ <%= render_component :controller=> 'graph', :action => 'history_graphs', :id => @pool.id %> +<%= render_component :controller=> 'graph', :action => 'snapshot_graph', :id => @pool.id %> +
          Hardware pool quota details.
          @@ -25,4 +27,3 @@ <%- end -%> -<%= render_component :controller=> 'graph', :action => 'snapshot_graph', :id => @pool.id %> diff --git a/wui/src/app/views/hardware/show_vms.rhtml b/wui/src/app/views/hardware/show_vms.rhtml index 7703e44..378a0c2 100644 --- a/wui/src/app/views/hardware/show_vms.rhtml +++ b/wui/src/app/views/hardware/show_vms.rhtml @@ -32,7 +32,7 @@ } if (selected_ids.length == 1) { - $('#vmpools_selection').load('<%= url_for :controller => "resources", :action => "quick_summary" %>/' + parseInt(selected_ids[0].substring(3))); + $('#vmpool_selection').load('<%= url_for :controller => "resources", :action => "quick_summary" %>/' + parseInt(selected_ids[0].substring(3))); } } -- 1.5.4.1 >From b7f52a4d09a1cb3f22070284392fa37aa5bd210e Mon Sep 17 00:00:00 2001 From: Hugh O. Brock Date: Tue, 3 Jun 2008 12:10:54 -0400 Subject: [PATCH] Comment out a 'require' that was pulling in stats.rb before we were ready for it (coming later). Also added a javascript hack from mmorsi to get flexigrid working again. Signed-off-by: Hugh O. Brock --- wui/src/app/controllers/graph_controller.rb | 2 +- wui/src/app/views/graph/_load_graph.rhtml | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/wui/src/app/controllers/graph_controller.rb b/wui/src/app/controllers/graph_controller.rb index 205b418..4333649 100644 --- a/wui/src/app/controllers/graph_controller.rb +++ b/wui/src/app/controllers/graph_controller.rb @@ -1,4 +1,4 @@ -require 'util/stats/Stats' +# require 'util/stats/Stats' class GraphController < ApplicationController layout nil diff --git a/wui/src/app/views/graph/_load_graph.rhtml b/wui/src/app/views/graph/_load_graph.rhtml index 7cf61e1..1cb81ba 100644 --- a/wui/src/app/views/graph/_load_graph.rhtml +++ b/wui/src/app/views/graph/_load_graph.rhtml @@ -26,7 +26,9 @@ function load_widget(div, target){ svg.graph.redraw(); } ); - $(div).children().filter("svg").attr('height', 25).attr('width', 200); +// $(div).children().filter("svg").attr('height', 25).attr('width', 200); + $(div).children().filter("svg").attr("height").baseVal.value = 25; + $(div).children().filter("svg").attr("width").baseVal.value = 200; }; // invoked when a row containing a load widgit is selected -- 1.5.4.1