From: Tomas Sedovic <tsedovic(a)redhat.com>
https://www.aeolusproject.org/redmine/issues/2523
---
src/app/controllers/deployments_controller.rb | 55 +++++++++--
src/app/stylesheets/custom.scss | 107 +++++++++++++++++++-
src/app/stylesheets/layout.scss | 12 ++
src/app/util/deployable-rng.xml | 3 +
src/app/util/deployable_xml.rb | 8 +-
src/app/views/deployments/_launch_new.html.haml | 2 +-
src/app/views/deployments/_new.html.haml | 5 +-
src/app/views/deployments/_parameters.haml | 12 --
src/app/views/deployments/_services.haml | 13 ---
.../views/deployments/launch_time_params.html.haml | 67 ++++++++++++
src/config/locales/en.yml | 3 +
src/config/routes.rb | 1 +
src/features/deployment.feature | 16 ++--
src/public/images/filled_out_params_indicator.png | Bin 0 -> 524 bytes
src/public/images/services_bg.png | Bin 0 -> 1902 bytes
15 files changed, 256 insertions(+), 48 deletions(-)
delete mode 100644 src/app/views/deployments/_parameters.haml
delete mode 100644 src/app/views/deployments/_services.haml
create mode 100644 src/app/views/deployments/launch_time_params.html.haml
create mode 100644 src/public/images/filled_out_params_indicator.png
create mode 100644 src/public/images/services_bg.png
diff --git a/src/app/controllers/deployments_controller.rb
b/src/app/controllers/deployments_controller.rb
index 4b10b6f..52b0d80 100644
--- a/src/app/controllers/deployments_controller.rb
+++ b/src/app/controllers/deployments_controller.rb
@@ -56,22 +56,47 @@ class DeploymentsController < ApplicationController
end
end
+ def launch_time_params
+ @deployment = Deployment.new(params[:deployment])
+ @pool = @deployment.pool
+ require_privilege(Privilege::CREATE, Deployment, @pool)
+ @catalog_entries = CatalogEntry.list_for_user(current_user, Privilege::USE)
+
+ url = get_deployable_url
+ unless @deployment.accessible_and_valid_deployable_xml?(url)
+ init_new_deployment_attrs
+ render 'launch_new' and return
+ end
+
+ @services = []
+ @deployment.deployable_xml.assemblies.each do |assembly|
+ assembly.services.each do |service|
+ @services << [service, assembly.name]
+ end
+ end
+
+ if @services.empty? or @services.all? {|s, a| s.parameters.empty?}
+ # we can skip the launch-time parameters screen
+ check_assemblies_for_errors
+ render 'new' and return
+ end
+ end
+
# launch_new will post here, but you can use this RESTfully as well
def new
@deployment = Deployment.new(params[:deployment])
@pool = @deployment.pool
@catalog_entries = CatalogEntry.list_for_user(current_user,
Privilege::USE).select{|ce| ce.catalog.pool == @pool}
require_privilege(Privilege::CREATE, Deployment, @pool)
+
+ @launch_parameters_id = SecureRandom.hex(8)
+ session[:launch_parameters] ||= {}
+ session[:launch_parameters][@launch_parameters_id] = @deployment.launch_parameters
+
url = get_deployable_url
respond_to do |format|
if @deployment.accessible_and_valid_deployable_xml?(url)
- errors = @deployment.check_assemblies_matches(current_user)
- unless errors.empty?
- flash[:error] = {
- :summary => "Some assemblies will not be launched:",
- :failures => errors
- }
- end
+ check_assemblies_for_errors
format.html
format.js { render :partial => 'new' }
format.json { render :json => @deployment }
@@ -85,6 +110,12 @@ class DeploymentsController < ApplicationController
end
def create
+ launch_parameters_id = params.delete(:launch_parameters_id)
+ unless launch_parameters_id.blank?
+ session[:launch_parameters] ||= {}
+ params[:deployment][:launch_parameters] =
session[:launch_parameters].delete(launch_parameters_id)
+ end
+
@deployment = Deployment.new(params[:deployment])
require_privilege(Privilege::CREATE, Deployment, @deployment.pool)
@deployment.owner = current_user
@@ -310,6 +341,16 @@ class DeploymentsController < ApplicationController
@deployment = Deployment.find(params[:id])
end
+ def check_assemblies_for_errors
+ errors = @deployment.check_assemblies_matches(current_user)
+ unless errors.empty?
+ flash[:error] = {
+ :summary => "Some assemblies will not be launched:",
+ :failures => errors
+ }
+ end
+ end
+
def init_new_deployment_attrs
@pools = Pool.list_for_user(current_user, Privilege::CREATE, :target_type =>
Deployment)
@realms = FrontendRealm.all
diff --git a/src/app/stylesheets/custom.scss b/src/app/stylesheets/custom.scss
index bc7e647..6600252 100644
--- a/src/app/stylesheets/custom.scss
+++ b/src/app/stylesheets/custom.scss
@@ -50,4 +50,109 @@ ul.deployment-array.small li.deployment {
.hidden {
display: none;
-}
\ No newline at end of file
+}
+
+
+.launch-time-params h2 {
+ font-size: 16px;
+ font-weight: normal;
+ text-align: center;
+}
+
+$services_width: 250px;
+$services_border: 1px solid #b0b0b0;
+$services_background: #efefef;
+
+form.generic section.services {
+ position: relative;
+ border: $services_border;
+ margin: 1em;
+ padding: 0 0 1em;
+ -webkit-border-radius: 1em;
+ -moz-border-radius: 1em;
+ border-radius: 1em;
+ min-height: 300px;
+ background: $services_background;
+ overflow: hidden;
+
+
+ h4.service {
+ font-size: 14px;
+ font-weight: normal;
+ position: relative;
+ z-index: 1;
+ $left_padding: 26px;
+ padding: 0.5em 0 0.5em $left_padding;
+ width: $services_width - $left_padding + 1px;
+ border-bottom: 1px solid transparent;
+
+ &:hover {
+ background: darken($services_background, 20%);
+ cursor: pointer;
+ }
+ &.selected {
+ background: $services_background;
+ border-bottom: $services_border;
+ cursor: default;
+ }
+ &.filled-out {
+ background-image: url('../../images/filled_out_params_indicator.png');
+ background-repeat: no-repeat;
+ background-position: 8px center;
+ }
+ }
+
+ .parameters {
+ display: none;
+ position: absolute;
+ top: 88px;
+ left: $services_width;
+ padding: 1em;
+ }
+
+ #service-headers {
+ position: absolute;
+ z-index: 0;
+ background: transparent url('../../images/services_bg.png') repeat top
center;
+ top: 0;
+ left: 0;
+ height: 100%;
+ border-right: $services_border;
+ width: $services_width;
+
+ $left-corners: 1em 0 0 1em;
+ -webkit-border-radius: $left-corners;
+ -moz-border-radius: $left-corners;
+ border-radius: $left-corners;
+ }
+
+
+ header {
+ background-image: none;
+ background: #dddddd;
+ margin-left: $services_width;
+ padding: 1em;
+ height: 40px;
+
+ $topright-corner: 0 1em 0 0;
+ -webkit-border-radius: $topright-corner;
+ -moz-border-radius: $topright-corner;
+ border-radius: $topright-corner;
+
+ h3 {
+ font-size: 22px;
+ font-weight: normal;
+ }
+ }
+
+ label {
+ display: block;
+ float: left;
+ min-width: 120px;
+ text-align: right;
+ padding: 6px 7px 5px 0px;
+ font-size: 14px;
+ text-shadow: 0px 1px 0px #ffffff;
+ font-weight: normal;
+ }
+}
diff --git a/src/app/stylesheets/layout.scss b/src/app/stylesheets/layout.scss
index b4d7e49..ed6a615 100644
--- a/src/app/stylesheets/layout.scss
+++ b/src/app/stylesheets/layout.scss
@@ -369,6 +369,18 @@
http://github.com/necolas/css3-github-buttons
padding: 0;
border: 0;
}
+.button.disabled, .button[disabled] {
+ cursor: default;
+ background: transparent;
+ opacity: 0.6;
+ /* @include no-box-shadow; */
+ &:hover {
+ background: transparent;
+ text-decoration: none;
+ color: inherit;
+ text-shadow: inherit;
+ }
+}
/* ------------------------------------------------------------------ Icons */
diff --git a/src/app/util/deployable-rng.xml b/src/app/util/deployable-rng.xml
index 3769377..ba74659 100644
--- a/src/app/util/deployable-rng.xml
+++ b/src/app/util/deployable-rng.xml
@@ -66,6 +66,9 @@
<oneOrMore>
<element name="service">
<attribute name="name"><text/></attribute>
+ <optional>
+ <element name="description"><text/></element>
+ </optional>
<ref name="service-configuration-definition"/>
</element>
</oneOrMore>
diff --git a/src/app/util/deployable_xml.rb b/src/app/util/deployable_xml.rb
index 19c6af9..4eb8397 100644
--- a/src/app/util/deployable_xml.rb
+++ b/src/app/util/deployable_xml.rb
@@ -82,13 +82,14 @@ class ParameterXML
end
class ServiceXML
- def initialize(name, executable, files, parameters)
+ def initialize(name, description, executable, files, parameters)
@name = name
+ @description = description
@executable = executable
@file_nodes = files || []
@parameter_nodes = parameters || []
end
- def name; @name; end
+ attr_reader :name, :description
def executable
@executable['url'] if @executable
@@ -176,10 +177,11 @@ class AssemblyXML
# collect the service level tooling
nil_if_empty((a)root.xpath("./services/service").collect do |service|
name = service['name']
+ description = service.at_xpath('./description')
exe = service.at_xpath("./executable")
files = service.xpath("./files/file")
parameters = service.xpath("./parameters/parameter")
- ServiceXML.new(name, exe, files, parameters)
+ ServiceXML.new(name, (description and description.text), exe, files, parameters)
end)
end
diff --git a/src/app/views/deployments/_launch_new.html.haml
b/src/app/views/deployments/_launch_new.html.haml
index 50a9daa..40f03d4 100644
--- a/src/app/views/deployments/_launch_new.html.haml
+++ b/src/app/views/deployments/_launch_new.html.haml
@@ -14,7 +14,7 @@
= t 'deployments.deployment_details'
.content
- = form_for :deployment, {:url => new_deployment_path, :method => :get, :html
=> {:class => 'generic'}} do
+ = form_for :deployment, {:url => launch_time_params_deployments_path, :method
=> :post, :html => {:class => 'generic'}} do
- if @deployment.errors.any?
= render 'layouts/error_messages', :object => @deployment
= hidden_field :deployment, :pool_id
diff --git a/src/app/views/deployments/_new.html.haml
b/src/app/views/deployments/_new.html.haml
index 6bf0a4b..4a9a040 100644
--- a/src/app/views/deployments/_new.html.haml
+++ b/src/app/views/deployments/_new.html.haml
@@ -9,6 +9,7 @@
= hidden_field :deployment, :name
= hidden_field :deployment, :pool_id
= hidden_field :deployment, :frontend_realm_id
+ = hidden_field_tag :launch_parameters_id, @launch_parameters_id
-# FIXME: Passing chunks of XML around in hidden form fields doesn't feel
right
= hidden_field :deployment, :deployable_xml
= submit_tag 'Launch this deployment', :class => 'button
primary', :id => 'launch_deployment'
@@ -65,9 +66,5 @@
%td= assembly.hwp
%td= assembly.image_id
%td= assembly.image_build
- -if not assembly.services.empty?
- %tr
- %td{:colspan => 4}
- = render 'deployments/services', :assembly => assembly
-# Quota checking to go here as well, once I understand how it works with new code
diff --git a/src/app/views/deployments/_parameters.haml
b/src/app/views/deployments/_parameters.haml
deleted file mode 100644
index d0dea80..0000000
--- a/src/app/views/deployments/_parameters.haml
+++ /dev/null
@@ -1,12 +0,0 @@
-- service.parameters.each do |parameter|
- %tr
- %td{:width => "30%", :style => "text-align:right"}
- = parameter.name
- %td{:style => "text-align:left"}
- - if not parameter.reference?
- - if service.name
- = text_field_tag
"deployment[launch_parameters][#{assembly}][#{service.name}][#{parameter.name}]",
parameter.value
- - else
- = text_field_tag
"deployment[launch_parameters][#{assembly}][##EMPTY##][#{parameter.name}]",
parameter.value
- - else
- = "Reference to #{parameter.reference_string}"
diff --git a/src/app/views/deployments/_services.haml
b/src/app/views/deployments/_services.haml
deleted file mode 100644
index 85d6881..0000000
--- a/src/app/views/deployments/_services.haml
+++ /dev/null
@@ -1,13 +0,0 @@
--# assumes at least one service
-%table{:width => "100%"}
- - if assembly.services.size > 1
- - assembly.services.each do |service|
- %tr
- %td
- service.name
- %tr
- %td
- %table
- = render :partial => 'deployments/parameters', :locals =>
{:assembly => assembly.name, :service => service}
- - else
- = render :partial => 'deployments/parameters', :locals => {:assembly
=> assembly.name, :service => assembly.services.first}
diff --git a/src/app/views/deployments/launch_time_params.html.haml
b/src/app/views/deployments/launch_time_params.html.haml
new file mode 100644
index 0000000..efaf1f1
--- /dev/null
+++ b/src/app/views/deployments/launch_time_params.html.haml
@@ -0,0 +1,67 @@
+= render :partial => 'layouts/nav_history'
+%header.page-header
+ %h1.deployments
+ = [@deployment.pool.name, "Pool"].join(' ')
+ .corner
+
+%section.content-section.deployments.launch-time-params
+ %h2= t('.configure_launch_time_params')
+ = form_for @deployment, :url => new_deployment_path, :html => {:method =>
:get, :class => 'generic'} do
+ = hidden_field :deployment, :name
+ = hidden_field :deployment, :pool_id
+ = hidden_field :deployment, :frontend_realm_id
+ = hidden_field_tag :catalog_entry_id, params[:catalog_entry_id]
+ = hidden_field_tag :deployable_url, params[:deployable_url]
+
+ %section.services
+ %header
+ %h3.service
+ %p.description
+
+ - @services.each do |service, assembly_name|
+ %h4.service= service.name.titleize
+ %p.hidden.description= service.description
+
+ .parameters
+ - service.parameters.each do |parameter|
+ .parameter
+ - if not parameter.reference?
+ - id =
"deployment[launch_parameters][#{assembly_name}][#{service.name}][#{parameter.name}]"
+ = label_tag id, parameter.name.titleize + ':'
+ = text_field_tag id, parameter.value
+ - else
+ = "Reference to #{parameter.reference_string}"
+
+ #service-headers
+
+ = submit_tag t('.finalize'), :class => 'button primary', :id =>
'submit_params'
+
+:javascript
+ (function () {
+ function selectService($service) {
+ $('.service.selected').next().next('.parameters').hide();
+ $('.service.selected').removeClass('selected');
+ $service.addClass('selected');
+ $service.next().next('.parameters').show();
+
+ $service.parents('.services').find('header
.service').text($service.text());
+ $service.parents('.services').find('header .description')
+ .text($service.next('.description').text());
+ }
+
+ var $services = $('.launch-time-params .services h4.service');
+ selectService($services.first());
+ $services.live('click', function(e) { selectService($(this)); });
+
+ $('#submit_params').attr('disabled', true);
+ $('.parameter input').live('keydown', function(e) {
+ $('.launch-time-params .parameters').each(function() {
+ var $parameters = $(this).find('.parameter input');
+ var filledOut = _.all($parameters, function(item) {
+ return ! _.isEmpty($(item).val());
+ });
+ $(this).prev().prev('.service').toggleClass('filled-out',
filledOut);
+ $('#submit_params').attr('disabled', !filledOut);
+ });
+ });
+ })();
diff --git a/src/config/locales/en.yml b/src/config/locales/en.yml
index aea12d3..f9f6b33 100644
--- a/src/config/locales/en.yml
+++ b/src/config/locales/en.yml
@@ -103,6 +103,9 @@ en:
other: "The deployments %{list} could not be deleted."
none_selected: "You must select one or more deployments."
state: State
+ launch_time_params:
+ configure_launch_time_params: "Configure launch-time parameters for your
deployment:"
+ finalize: Finalize
instances:
instances: Instances
updated:
diff --git a/src/config/routes.rb b/src/config/routes.rb
index 1e31d16..3b0aea4 100644
--- a/src/config/routes.rb
+++ b/src/config/routes.rb
@@ -105,6 +105,7 @@ Conductor::Application.routes.draw do
get 'multi_stop'
delete :multi_destroy
get 'launch_new'
+ post 'launch_time_params'
get 'check_name'
end
resources :instances
diff --git a/src/features/deployment.feature b/src/features/deployment.feature
index 58aa133..d8173cb 100644
--- a/src/features/deployment.feature
+++ b/src/features/deployment.feature
@@ -227,9 +227,9 @@ Feature: Manage Deployments
When I fill in "deployable_url" with
"http://localhost/deployables/deployable_with_launch_parameters.xml"
And I fill in "deployment_name" with
"deployment_with_launch_parameters"
And I press "Next"
- Then I should see "Deployable details"
- And I should see "parameter_1"
- And I should see "parameter_2"
+ Then I should see "Configure launch-time parameters"
+ And I should see "Parameter 1"
+ And I should see "Parameter 2"
Scenario: Verify that the launch parameters are required
Given a pool "mockpool" exists
@@ -243,9 +243,11 @@ Feature: Manage Deployments
When I fill in "deployable_url" with
"http://localhost/deployables/deployable_with_launch_parameters.xml"
And I fill in "deployment_name" with
"deployment_with_launch_parameters"
And I press "Next"
- Then I should see "Deployable details"
- And I should see "launch_parameter_1"
- And I should see "launch_parameter_2"
+ Then I should see "Configure launch-time parameters"
+ And I should see "Launch Parameter 1"
+ And I should see "Launch Parameter 2"
When I fill in
"deployment_launch_parameters_assembly_with_launch_parameters_service_with_launch_parameters_launch_parameter_1"
with "value_1"
- And I press "launch_deployment"
+ And I press "submit_params"
+ Then I should see "Deployable details"
+ When I press "launch_deployment"
Then I should see "launch_parameter_2 cannot be blank"
diff --git a/src/public/images/filled_out_params_indicator.png
b/src/public/images/filled_out_params_indicator.png
new file mode 100644
index 0000000000000000000000000000000000000000..356a0da87486a1b38e114338e1a4d3f593b9cac0
GIT binary patch
literal 524
zcmV+n0`vWeP)<h;3K|Lk000e1NJLTq000aC000aK1^@s6R&`wG00001b5ch_0Itp)
z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FZT01FZU(%pXi00007bV*G`2ipn?
z3nnUs5F45R000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}0004JNkl<Z
zD9?S-u}cDR6bJC{@4R22ARLLe{15~oQkS4SsGtNF{Rbkaq$S+iHIB?ip(&S$Yiej|
z(?1{*q@$J$3?T?14Dnj>mv?$i9$80k{(Rr#y+;Ov0lZ!>1QED-KQGmL#~H)yE(3r>
znVyylwe{exYFn^5=ODx35D+b>t;MEcb`x+Zi8A{z_T+&@Z9$;qU%VAMfu9D6+KP^e
zI3b=?o|W#5%d8vDg*9vh_mG&+LN~4mvBfu`)+=WKz~_+=m<!L~)xge7gL?0{Doz*7
zN3Id_Euqp*A|>xTcsTw*rJcm<=K}yh1c0?b4h#NG06;N%?{xf)0YH!_!);$fqkl0o
z-VIBX=|WmAlmS3{$vGi63;-Fqct*Y~P7WR;O~dT2OwZWpYk#mrnSK=SD1>tk+cP3+
zE9!(?9;d6(mI70p2%K}kqIN0vtZcK>yhNG)6J}X8UygSanBrtK8sQt7?xf_1t4w<U
O0000<MNUMnLSTYlk<cvw
literal 0
HcmV?d00001
diff --git a/src/public/images/services_bg.png b/src/public/images/services_bg.png
new file mode 100644
index 0000000000000000000000000000000000000000..8c5657d10114b0a9d12b52180c4ed782898dbe4b
GIT binary patch
literal 1902
zcmV-!2a))RP)<h;3K|Lk000e1NJLTq001Qb002V>1^@s68#ByA00001b5ch_0Itp)
z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FZT01FZU(%pXi00007bV*G`2ipn_
z4>By+1Nol-000?uMObu0Z*6U5Zgc=ca%Ew3Wn>_CX>@2HM@dakSAh-}000KbNkl<Z
zXx@dIZIas{5JX3a`yXu2Bp^SWN1i%3an;t^vIO(l(=+(``T1G*eb=0`uIs9*s@7VK
zF>0+<*LBr>->=X7Z>`l@t6FPSReKHA8Ds3vJm)p4s@7U{-*-LFQ^@gIt*Y+(uBxi*
zy6SnJy{WJBnZG$_t+ncT9+s)=x@wG3V~qXm7^CK#Tkw31G4^-&eOK?j@5Q-@1<(kM
zvC5otTZii?!Zizta43(JPWR6_t3A*2+Q{ZdAcRB#Hp%C3GaF$QEXOs6fZuPS@&+_!
z6I;Y)cD!XA+JY#B0w~M6xYnNPY}R{!`8k8wo7q)%tu2fPY*AZ@YfgYIu(d@iG{!Or
zkwH!7;67)U6~P+ZOI%q%<XCHcEagoyxLFL-V?jS-NWfM8-tOhqd;iPgJlmb7q<w2`
zTLhsHmU|sbj>!}TYZ4+TJm-9cjIG<z&cSwFSM}bvwH!NM2*K^Xj2VPSFcdUi@t(E2
zQ5Z{suD}2fWK3bzbhj;Tx7dZiOJ?R6;}huCG9dwzo`m=PpgiyMep@7y$cfcjt47_i
z*&V3(f6loV!ip$@>s`m3=IO59`zscCk22kX>@0I;IfGnyjbW^VwkTn1V_lSU7TdMW
zLGF^`%^j%TfcSEznQ3I%ad!SLys!EPjx}6|U%int%~m6p5F9I6xRbCbj*AI&vxwH(
z2RvQhY~D;+yBP2@YTM1k5%&Qxwy=|i5Ljz{z|(QSO{b!37aM~NthSCVlK`DriC5;F
zpX_shVkxfsl?=cc=I4`z`a9fxio;DVSrBk^P-hj#&8Dt=Z_3PPyOVo~BP?r{u_41O
z(wio}B<})m%-vn-Pu5MrvYhSjc#}LinS-@;@EfbrJqYPIBCAb>cEbR}wbWjWz$0bR
zCb7&2pWO`4x@wpeq=K7yVihDNWnF3#r_8akzB!I;y;Jv+E!<8R7Qr&6E7=rS2xrio
z^MzTs#r%u)lR6tdHqx_rVvb#uwAC&E7~KeDy)=A~<zSPQ+c@S6HmNnYWgK^A1%!Y(
zzCqY!%ic&%KgReIQ>XTabTxLlyl}5!z*&Tl|7*8cpJzK8k+ufSe7WbhTkW>YtOU>#
zg&{-PzbBtb@biMEv8PU#I7tHNxr57zuWu{${t?QtLp*qK1Eta4;F*1%i?*ASWUhQR
z9ctNbqoK=3)~{?D?CR`rUJXGs6aEe_-1q${Gj<7!v4C45HwW2Lk%>7$$!F|#Q<+zn
z<kZg8H`zn8WU97Wrn)i71=tF?&)i`GEp=A72q#Ol)&@|!%rx2UlkYoOce4-IvlJ-l
zj5!wqoAPE0eyW@9E8YLS#+AtejYrNtuE7|R(`S=mwsD$|X6(ND&TMaTKII9X>5Ruf
z8PqPm9s$@*IkI$I_RNah*r1xwknMf;iHUcnC^@)&Vc)4Rx(~De)Atz{o-cTE>})p7
z*ejmSw5)HAhh&DtlNT}V$yWT-Qznp_x4)(?$+L~lS^Yh~G$U{!Hx}iAK$b3hYBLX4
z>FiQ?2oh&Ep621^+DU=4!A+V(lC;+TSjs5vKu*ofD6-jLjeOoMRC>g&1H(FkU@0$P
z+WHM(J*Y4|c;g)8o@S$NwYsSTE^+^F@Jw3b>p5#OL?nfF18iZpay*pX#~#c4j;GU9
zIA@$L(k{-dgVM$|)9KxedhqJ%o?4!=GmlOZTC#z~8+o{7zP@8BM=~y&c5j~HnV{kB
zJOpq&*{WGdEMPk|0jE=iOo&8$YoEt&E?L>2I5GCrCFkF0Yl~%I8l`hanl#2eV3Nku
zfOeM|<BT;=P;-k;EZW6(r(?;9VJhQTa&ysh?EI}UKuA}8$BE;|M;@NKz(71VwF~!L
z)Iey`m40Wz(?NjU?%9N`b|Q|>Vso}`L`^`;5|AyDg~@4(*E2jMvpDsV-A5C)O#Un&
zPYx0w-G*g>b~q&d`PgpH8$2~}K$|xu1<BF2$A-?foRuf#$zknlKILvDk6usp>tqQB
zxwFl5*LZcRfjrx@bev8$odo_dgstE#Gk|6_$hh@hyCCP(<lFQPVZ3R^mJ=XPDsonp
z2L~^_`sOMs`|Hf4_tz+q`yF?uGr*ijIR*{TDASXI<ft%zH(-r&u9Z_`$B)O_DD6G|
zf&^E0kB}3s^RzuXmv3w}+xa|W_78sMoS&F7*KuLAd6Q$G%FM}~2Gf7Fb55piGiJKJ
zq*pe%AfJ8^kvz)3N5~<+C&oL0eA3`qLXtQiAoAZWer9V5>K@Sv;5pb%G7s3l9U$hc
o!0oxU&VwJ*ll(2!X+J*y0@yAo@+RVh2LJ#707*qoM6N<$f+doyFaQ7m
literal 0
HcmV?d00001
--
1.7.6.4