From 1b234de829cc981b9c654d7a95b38da298d92a31 Mon Sep 17 00:00:00 2001 From: Nuno Guedelha Date: Thu, 26 Nov 2020 09:31:01 +0100 Subject: [PATCH] WIP1: Add qpOASES as an alternative solver in the contacts computation - Add separated step_block_contacts MATLAB system block for computing the contacts (block is still unfinished) - Add shared configuration class StepBlockInit - Add option to select qpOASES insteas of quadprog --- init.m | 5 + lib/+wbs/@Contacts/Contacts.m | 35 +++++- lib/+wbs/@StepBlockInit/StepBlockInit.m | 33 +++++ .../+robotDynWC/ProcessQPOutputFCN.m | 31 +++++ .../+robotDynWC/step_block.m | 8 +- .../+robotDynWC/step_block_contacts.m | 114 ++++++++++++++++++ .../robotDynamicsWithContacts_lib.slx | Bin 30900 -> 48183 bytes 7 files changed, 216 insertions(+), 10 deletions(-) create mode 100644 lib/+wbs/@StepBlockInit/StepBlockInit.m create mode 100644 lib/RobotDynamicsWithContacts/+robotDynWC/ProcessQPOutputFCN.m create mode 100644 lib/RobotDynamicsWithContacts/+robotDynWC/step_block_contacts.m diff --git a/init.m b/init.m index 02a6684..b31c404 100644 --- a/init.m +++ b/init.m @@ -34,6 +34,10 @@ Config.GRAVITY_ACC = [0,0,-9.81]; Config.tStep = 0.001; +% Use qpOASES instead of quadprog, typically in the case where the optimization toolbox is not +% available. +Config.USE_QPOASES = true; + % Do you want to enable the Visualizer? confVisualizer.visualizeRobot = true; @@ -47,4 +51,5 @@ %% Init simulator core physics paramaters physics_config.GRAVITY_ACC = Config.GRAVITY_ACC; physics_config.TIME_STEP = Config.tStep; +physics_config.USE_QPOASES = Config.USE_QPOASES; robot_config.SIMULATE_MOTOR_REFLECTED_INERTIA = Config.SIMULATE_MOTOR_REFLECTED_INERTIA; diff --git a/lib/+wbs/@Contacts/Contacts.m b/lib/+wbs/@Contacts/Contacts.m index c684947..f4d7e9e 100644 --- a/lib/+wbs/@Contacts/Contacts.m +++ b/lib/+wbs/@Contacts/Contacts.m @@ -11,12 +11,13 @@ is_in_contact = ones(8, 1); % this vector says if the vertex is in contact (1) or not (0) S; % selector matrix for the robot torque mu; % friction coefficient + useQPoases; % Use the qpOASES solver instead of quadprog for the optim. prob. computing the reaction forces at the feet A; b; Aeq; beq; % matrix used in the optimization problem end methods - function obj = Contacts(foot_print, robot, friction_coefficient) + function obj = Contacts(foot_print, robot, friction_coefficient,useQPoases) %CONTACTS The Contact class needs the coordinates of the vertices of the foot % Arguments % foot_print - the coordinates of every vertex in xyz @@ -30,7 +31,8 @@ obj.S = [zeros(6, robot.NDOF); ... eye(robot.NDOF)]; obj.mu = friction_coefficient; - obj.prepare_optimization_matrix(); + obj.useQPoases = useQPoases; + obj.prepare_optimization_matrix_for_quadprog(); end function [generalized_total_wrench, wrench_left_foot, wrench_right_foot, base_pose_dot, s_dot] = ... @@ -233,8 +235,9 @@ end - function prepare_optimization_matrix(obj) - % prepare_optimization_matrix Fills the matrix used in the optimization problem + function prepare_optimization_matrix_for_quadprog(obj) + % prepare_optimization_matrix Fills the matrix used by the optimization problem solver + % quadprog: vertical concatenation of Ax <= b and -x <= 0. total_num_vertices = obj.num_vertices * 2; % number of vertex per foot * number feet num_variables = 3 * total_num_vertices; % number of unknowns - 3 forces per vertex @@ -258,6 +261,30 @@ function prepare_optimization_matrix(obj) end + function prepare_optimization_matrix_for_qpOASES(obj) + % prepare_optimization_matrix Fills the matrix used by the optimization problem solver + % qpOASES: lbA <= Ax <= ubA and the constraint on the output lb <= x <= ub. + + total_num_vertices = obj.num_vertices * 2; % number of vertex per foot * number feet + num_variables = 3 * total_num_vertices; % number of unknowns - 3 forces per vertex + num_constr = 5 * total_num_vertices; % number of constraint: simplified friction cone + non negativity of vertical force + % fill the optimization matrix + obj.A = zeros(num_constr, num_variables); + obj.b = zeros(num_constr, 1); + obj.Aeq = zeros(total_num_vertices, num_variables); + obj.beq = zeros(total_num_vertices, 1); + + constr_matrix = [1, 0, -obj.mu; ...% first 4 rows: simplified friction cone + 0, 1, -obj.mu; ... + -1, 0, -obj.mu; ... + 0, -1, -obj.mu; ... + 0, 0, -1]; ...% non negativity of vertical force + + % fill a block diagonal matrix with all the constraints + Ar = repmat(constr_matrix, 1, total_num_vertices); % Repeat Matrix for every vertex + Ac = mat2cell(Ar, size(constr_matrix, 1), repmat(size(constr_matrix, 2), 1, total_num_vertices)); % Create Cell Array Of Orignal Repeated Matrix + obj.A = blkdiag(Ac{:}); + end end end diff --git a/lib/+wbs/@StepBlockInit/StepBlockInit.m b/lib/+wbs/@StepBlockInit/StepBlockInit.m new file mode 100644 index 0000000..752beaa --- /dev/null +++ b/lib/+wbs/@StepBlockInit/StepBlockInit.m @@ -0,0 +1,33 @@ +classdef StepBlockInit < handle + % step_block_contacts This block takes as input the joint torques and the + % applied external forces and evolves the state of the robot + + properties (Access = private) + robot; contacts; state; + end + + properties (Constant = true) + sharedConfig = wbs.StepBlockInit(); + end + + methods (Static = true) + function setSharedConfig(obj) + theSingleton = wbs.StepBlockInit.sharedConfig; + theSingleton.robot = obj.robot; + theSingleton.contacts = obj.contacts; + theSingleton.state = obj.state; + end + + function obj = getSharedConfig(obj) + theSingleton = wbs.StepBlockInit.sharedConfig; + obj.robot = theSingleton.robot; + obj.contacts = theSingleton.contacts; + obj.state = theSingleton.state; + end + end + + methods (Access = protected) + function obj = StepBlockInit() + end + end +end diff --git a/lib/RobotDynamicsWithContacts/+robotDynWC/ProcessQPOutputFCN.m b/lib/RobotDynamicsWithContacts/+robotDynWC/ProcessQPOutputFCN.m new file mode 100644 index 0000000..b06e2ef --- /dev/null +++ b/lib/RobotDynamicsWithContacts/+robotDynWC/ProcessQPOutputFCN.m @@ -0,0 +1,31 @@ +function [qp_output, stop] = ProcessQPOutputFCN(qpStatus, qpSolution) + +persistent oldQPSolution; +persistent counter; + +coder.extrinsic('warning') +if isempty(oldQPSolution) + oldQPSolution = zeros(size(qpSolution)); +end + +if isempty(counter) + counter = 0.0 ; +end + +if(qpStatus == 0.0) + qp_output = qpSolution; + oldQPSolution = qpSolution; + counter = 0.0; + stop = 0.0; + +else + counter = counter +1.0; + qp_output = oldQPSolution; + stop = 0.0; + + warning("QPOasesError: Sending last feaseable solution") + if (counter>2.0) + stop = 1.0; + warning("QPOasesError: Stopping the Controller") + end +end diff --git a/lib/RobotDynamicsWithContacts/+robotDynWC/step_block.m b/lib/RobotDynamicsWithContacts/+robotDynWC/step_block.m index cebfca0..c89d426 100644 --- a/lib/RobotDynamicsWithContacts/+robotDynWC/step_block.m +++ b/lib/RobotDynamicsWithContacts/+robotDynWC/step_block.m @@ -13,18 +13,14 @@ end - properties (Access = private) + properties (Access = {?wbs.StepBlockInit}) robot; contacts; state; end methods (Access = protected) function setupImpl(obj) - obj.robot = wbs.Robot(obj.robot_config,obj.physics_config.GRAVITY_ACC); - obj.contacts = wbs.Contacts(obj.contact_config.foot_print, obj.robot, obj.contact_config.friction_coefficient); - obj.state = wbs.State(obj.physics_config.TIME_STEP); - obj.state.set(obj.robot_config.initialConditions.w_H_b, obj.robot_config.initialConditions.s, ... - obj.robot_config.initialConditions.base_pose_dot, obj.robot_config.initialConditions.s_dot); + obj = wbs.StepBlockInit.getSharedConfig(obj); end function [w_H_b, s, base_pose_dot, s_dot, wrench_left_foot, wrench_right_foot, kinDynOut] = stepImpl(obj, generalized_ext_wrench, torque, motorInertias) diff --git a/lib/RobotDynamicsWithContacts/+robotDynWC/step_block_contacts.m b/lib/RobotDynamicsWithContacts/+robotDynWC/step_block_contacts.m new file mode 100644 index 0000000..e138256 --- /dev/null +++ b/lib/RobotDynamicsWithContacts/+robotDynWC/step_block_contacts.m @@ -0,0 +1,114 @@ +classdef step_block_contacts < matlab.System & matlab.system.mixin.Propagates + % step_block_contacts This block takes as input the joint torques and the + % applied external forces and evolves the state of the robot + + properties (Nontunable) + robot_config; + contact_config; + physics_config; + OutputBusName = 'bus_name'; + end + + properties (DiscreteState) + + end + + properties (Access = {?wbs.StepBlockInit}) + robot; contacts; state; + end + + methods (Access = protected) + + function setupImpl(obj) + obj.robot = wbs.Robot(obj.robot_config,obj.physics_config.GRAVITY_ACC); + obj.contacts = wbs.Contacts(obj.contact_config.foot_print, obj.robot, obj.contact_config.friction_coefficient, obj.physics_config.USE_QPOASES); + obj.state = wbs.State(obj.physics_config.TIME_STEP); + obj.state.set(obj.robot_config.initialConditions.w_H_b, obj.robot_config.initialConditions.s, ... + obj.robot_config.initialConditions.base_pose_dot, obj.robot_config.initialConditions.s_dot); + wbs.StepBlockInit.setSharedConfig(obj); + end + + function [w_H_b, s, base_pose_dot, s_dot, wrench_left_foot, wrench_right_foot, kinDynOut] = stepImpl(obj, motorInertias, torque, generalized_ext_wrench) + % Implement algorithm. Calculate y as a function of input u and + % discrete states. + + % computes the contact quantites and the velocity after a possible impact + [generalized_total_wrench, wrench_left_foot, wrench_right_foot, base_pose_dot, s_dot] = ... + obj.contacts.compute_contact(obj.robot, torque, generalized_ext_wrench, motorInertias, obj.state.base_pose_dot, obj.state.s_dot); + % sets the velocity in the state + obj.state.set_velocity(base_pose_dot, s_dot); + % compute the robot acceleration + [base_pose_ddot, s_ddot] = obj.robot.forward_dynamics(torque, generalized_total_wrench,motorInertias); + % integrate the dynamics + [w_H_b, s, base_pose_dot, s_dot] = obj.state.ode_step(base_pose_ddot, s_ddot); + % update the robot state + obj.robot.set_robot_state(w_H_b, s, base_pose_dot, s_dot); + % Get feet contact state + [left_foot_in_contact, right_foot_in_contact] = obj.contacts.getFeetContactState(); + + % output the kinematic and dynamic variables + kinDynOut.w_H_b = w_H_b; + kinDynOut.s = s; + kinDynOut.nu = [base_pose_dot;s_dot]; + [kinDynOut.w_H_l_sole , kinDynOut.w_H_r_sole ] = obj.robot.get_feet_H(); + [kinDynOut.J_l_sole , kinDynOut.J_r_sole ] = obj.robot.get_feet_jacobians(); + [kinDynOut.JDot_l_sole_nu, kinDynOut.JDot_r_sole_nu] = obj.robot.get_feet_JDot_nu(); + kinDynOut.M = obj.robot.get_mass_matrix(motorInertias); + kinDynOut.h = obj.robot.get_bias_forces(); + kinDynOut.motorGrpI = zeros(obj.robot_config.N_DOF,1); + kinDynOut.fc = [wrench_left_foot;wrench_right_foot]; + kinDynOut.nuDot = [base_pose_ddot;s_ddot]; + kinDynOut.left_right_foot_in_contact = [left_foot_in_contact,right_foot_in_contact]; + end + + function resetImpl(obj) + + end + + function [out, out2, out3, out4, out5, out6, out7] = getOutputSizeImpl(obj) + % Return size for each output port + out = [4 4]; % homogeneous matrix dim + out2 = [double(obj.robot_config.N_DOF),1]; % joints position vector dim + out3 = [6 1]; % base velocity vector dim + out4 = [double(obj.robot_config.N_DOF),1]; % joints velocity vector dim + out5 = [6 1]; % wrench left foot vector dim + out6 = [6 1]; % wrench right foot vector dim + out7 = 1; + end + + function [out, out2, out3, out4, out5, out6, out7] = getOutputDataTypeImpl(obj) + % Return data type for each output port + out = "double"; + out2 = "double"; + out3 = "double"; + out4 = "double"; + out5 = "double"; + out6 = "double"; + out7 = obj.OutputBusName; + end + + function [out, out2, out3, out4, out5, out6, out7] = isOutputComplexImpl(~) + % Return true for each output port with complex data + out = false; + out2 = false; + out3 = false; + out4 = false; + out5 = false; + out6 = false; + out7 = false; + end + + function [out, out2, out3, out4, out5, out6, out7] = isOutputFixedSizeImpl(~) + % Return true for each output port with fixed size + out = true; + out2 = true; + out3 = true; + out4 = true; + out5 = true; + out6 = true; + out7 = true; + end + + end + +end diff --git a/lib/RobotDynamicsWithContacts/robotDynamicsWithContacts_lib.slx b/lib/RobotDynamicsWithContacts/robotDynamicsWithContacts_lib.slx index 04dd22ddf9e5e2a1412f14ce8a893a4a4e5972ac..fab00f3b0072c550b305c59646fd24fa67dd2861 100644 GIT binary patch delta 26143 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 Q6FZ=qkpcjy%99%Z2ZlgMrT_o{ delta 9634 zcmZ{K1yCKq((b|C-Q6`nkPrv~g1ftWaQDUC!ogjF2R*nX!6gvf-Q5WiBtPN4_x{SQ zdQ-J$wr9G(vok&0)6>08x6t+HP=Jyw3@k1P1VRKg6Iv+K4rN`eL4iP&NFWf-bE~eH zgT1S{y{n;`m!r9hKD(!#ZEwnQ+yW zgPY%r6<3jLRT*P@*wysBeJ#Fn#|aIc?F{ajp+O}>1bi|rSfN<-^KFv>h(o+bFa~QU zqb*fEBmn}SK*v|OZn_DDBh#1$F^_qo*=0;Mf-U|TT$DWlM?=jf*4vT5q6`J3nxD3~ z@&?5Q&&?PWuEWYGAEw24oHx4uOtSv9qQQFiAikd6=|1Aa6>_5^jU_!W+j#q(8#(SKJIrb2#7#8!6XF;TR}ap}i&14|Kw|U5iaBYR@RFbiwPL zyI@Nij%ye7axRn~%zBqWsu=^+k~+!_zyhgjX-0ADeVkw5C8xBJg|##URqNq{Od0cF zw^`#Pu%5y14HVDP_n!Rk?jPV-i<=yL?Z(?+_M=93hrzbz&PbrlbtCNnE zy&HaCC7+G&Y?oGsh)At@tTSbX9vsAe8}Ougzcfp*@a+M!{-_23OHieo(H3u|tjLWf zUc=iV!}!dj>K}Y_SePM82s@GB@{5$_(QWd@$o_r%@pi)DpNR+S!acz}&pTKT{_$@O z(L;cRdbu%0JZ41us}TXNUx&8O?<)sb{}n4RwdxSWiHUFqgkJfnr9Q@4W%c#+uvxSo zIhAdPgiRzGq?-bd<+{|AtmznUoo|Y6qz7LS`V~*ygMvjX0CI<^G9mzr z7zS2o@A<=JB~{^Iwb82`W05|Y&*4KVJD-$#bh&W?(WKlxC3H}3?K4pDh_bZwSXZpU zd82MJ%AZ?snY|{cq{8>RH6n4LtFj61gh&UQ07gA4*_L=S$JcRO;6@eUq|YJ=;(N&mU*{?tHsJRdhs zQsz~+ijbPom9jmt@u>}|dv)QPw$Heo{1pEe=}>1X-mvtI@jWt8>rnF|g~Lur+U)C{ z!7KU=h0-y%U7L#dR+aOIQ%}RqBnAPb%7@+X)qhl_oYQg|4JP3}MgOZ6dQvv;N_Y@R zh7e51LjmYIEb`*|pH^dDjg>S=!=uh=^oN@C%LmZ%QuD#<;KIq1E$UgR&@c&}RIdtr zKANlDqwnRsGWK))a3DyKBbYpMAKoH|Z}esCfJey7CyPF>nLQ*Ur#LyY{Z7bl)qna8 zIAhfVE|Zw|v@1k?V*a{<)_R-e(8v;n4`C23vm3B}V?>ws6)TU_g^|)uwix+`Q=1!) z6*NXYUP${4+-Ext0Wv6bO*&|1mQDdqtY^cQCBG%x$8hzZ!e3hiJ%r7jhIke`%oh{ zLO}pKG_&Z~Fg~6n#04hrjgAetF_n9rSno{w&@0|aG676a4`Y{w0e3$xDmf|(ySmrl zLNYqRVZ5t;X!XwQ;LHZSAcvRpwOO6cU9H)Jzu_3s$;ldZ_z|)G4!6dhxwz?XvOLr@ z)1_j&qLHjYKP^QTNk!{>=q>21wJ$_T(GCDE2HMW&CK}Aid5<158yPCRU?n{``3&eS zQQQP$>XC8Tx9FGb&C9oS?{(vw@%s{-n#fvrJ2Z;bMwm9HQ0#j6-V%Y+aaHkH*^D=? zdshOf7VTlO*)vgpQS=Xv;()Zio>Xup^$1J{`yuXp)SOePo5m#9vk+7{yGI8*$Ls(R zq-W#Nfv>C9SQc%0OPR^@noCC~ZMj9K%*(MH%WASx;mFtVwHa+nd2B**wo0*+jU)cs&mCGrF*5+3QIi&2T> zm&NABC*IzH8prD%&Gx)>G~byW{soBSp_O1OdFFw{0GRfi1LqHk+Pezd{^y|qcB}GC zs8B>la!ys`huiKI)q1G{5)Z&wv-Q2o$almW%R26UI}e@8lMp97Fyo{2dqjP@;^QLb zR|z+-$!?dy5$@*O-pL!T$jp9i*dF<_&=|k(WRKW<_|LA*CBEmiRa^E&ys^s4^R@V7 z-m8x*EiHFhMKBLbdG8A6uAFf*zU4qH@79kx-J>VR_nWWNnU{kO6)qW=vyd2oLJ`>` zuf6nP_guCjylblL;nW<}(ErXa&biRNp@(xTIkFzfsm9ElAQTXkp`TZ)Trd_`-$UIb z$V3)5aA@n9oE~N@6 zw}#lVJRiMpFaA#u47sn`I?akmvM8(dIVz7~;h`xxpEv&A(1Bp~$dNPwxZ_*@8eL14 z=B5?3>ZXK)e(ftItbJpj;@7cCv9(AR?6zcSJkYVj*LIss6Z!xm=kOWPvS<6JiZK^% zrp$=2sXFe=^hbPFJkm`=&EH{2LgWYmhHm}LC3dxL)0xHHRPICF{V*MF*w*?G4vFXzf#B% zhPT7!G!p3G8twzTm?Kin+URr=pJAA@lzsAfXRTn@#HHu?dKl-XO3Z@BlaE&ROnSB| zqjY9atfhsn>fGc$z4j0A7TW!Td2S)>*Lb8id?`4|*{f31RAy#IwRFGm4tzb! zb-@_XwNmeRfR#8saBb$TWs35qMO4|KbxVIRa#a_7pKUw>+cDl#JPzBie;$H@`u%qh zQ7+9fV&94y9s=cKEgWR-ai$ig6APc^7xTnjsrwxVEYJK}a+qe_x~^@Z3QVzx#Hrpd z)9z!Z$ClImRp=+Ee|NaVUxbWJ&&Pr|b`XdN1Rk#=0eW>lIxO>?AyfZH1C>M?S?Z#y8cb91WkN)&>jD|qd~D$G!~YQ!|JRj6i_^Uuj*!9Y-CW3eeAK< z%2~npEfuaJr~VK5j#C~KwJb`i1_t=0Wz0x@B4>WjXg%k-pWWY}GT$?%Uo=#ZNBXgs z#8eIZhE}fc^9?J4O^w>~C{y)^B~QF1!Ad+wIP?5{=z%J+NR~zqcV0_9MX0vrOE~(P=U3dhQJ46>23wI#-DmF@mrNfuwubrCQ1tsb$6uOzOs2Jx zI=o5-_&Yju713F*-w0eH682d25bbT77Hu$H5{-t)QaOq+f#1lE?D1DnI@(iG!cYVT zw=;5eP(QpD4~gRX@krucf=M$LfPA=(>+?95NWG!DUM;^ zTa;bRziR6-gvq7M&rvMb2+e4kLnf6uYOVyMCREf>LUc_QBu>#sz8 zT#AKnl*A%FYrbO4im6(zosLUZ&9vz$^|mWtDuAGKuE;+3JxI(f_qWtspbP639Sxus zx6CLU(--yN8wz(RRwPmOT`}mCv#I-g)?B7DhD%|}J1m9>87ZwZ{H2e(WbD1c37&#M zGSYjj->a|y_jvsg*tnEi1Km8HRFU*=Zq%nG^}UGH;=*?%@nzqmj;4LBx(zA)ap37g z?7tlp{-nbuoSyzJYjv)RDrBG*BsK-KX2C{H$T<&W%cyAIBq5CuU4{=39xMGaXJiea zvh*+-9H3~6vPQqSOlYkIGi}9J8uUwwsjNKYVI~qtX`z2b^poBpiTmU+WMS5}8jlf` zF@W@4)DR)IrR|8ayk+{{6(E(FRl`MI))(nlz*_TZ);AH>AE8ADZQ?Fu7Ki}0X{2El zcv^VScmZf6&ZvW34xb#l=$a0o7*YZkQEGjN+^A-v*n30G1av#K%U^t#4>#!fq%V@>x%1)J8i-s1T1#OTZnLGCL{Wp ze&y4zM0ElSlO0Nz;ikBbdgtOm=_IW&aH8E`oBmq!kFMx>|29T}DXf+5$5;TYTQy%A z`fcNt)oAAXlf-+0`^aH^9tlGit=C4rlj<4znH7t1n;QFA1fz+doaF?-sON<7c78Fn zZsnEn$Fb5aTk}pU{m3^xWd}m@iJ7v?R?=Z`m@ZoRwJm$)Kid#uy>;ugwZem-YtN?` z^CiiStn;A^!*m@33OA)l?~IopJ*aL#s-}zm@i&r%x_5K<>jhB)T?Tvjym8+M z7jtN)Zx0`5#*NoEB4HR4#!WcX3wC7`5!T0e|Tv>n{q3pBuKQHEhr!u~}Jl%6-7Oo3gvNC?Dd zIL>4RkK=?QA{Y(~!;jH#&q^Q5W>i;f`Owk0fZp!bN!!;^SU3YuE(GX)H&qfw>eSv3 zm4j$ik@}NKE0QL(B3%sgQ8AbZX!9r0y7mx1l6%Zr1^yUQ3-t{vq`0WM}0rj=+@e>rt> zdZ<4X4arf&dWem&G#%QCxk{u%$LwjxkVz2OjrhQ{I`y@#@msz&izFR14-RuRi|NuF zXGjt{Pi9Gto@rD|oN9I0=97AxYBGT1Vz0itv`?Rv?Op*8@8=NV$;XZWUCg@h_7uV9 zl;IxgRjpJDf`aws>G_*U>G{8WhB-q9;dy0}%?DM8qi!5d5&GNu7YOYjYz1`~$xF3L zis?tCi^@=wFfL@jT)(=Ohbr`&U=xSP#5NLP>)H~F+psFn82I$>n|S}6=N0gBh>=?R z?)OKzk8>QbY5j(@9dJ$xQnhHrXQr??E!~>7LR&uF9f#;#DETy~?x=)x*C7%4W|$jxvbrl6<5c;3&v~Kk71=@~ zGdYT3M{wLL@m}exbMPh8?}YLOl+uRi(qRq3LZVy%tD(?_t5VCNIwSpqHsj@+Rkp8e zDR}1CWECr)_L{_@Io4ndJmoZ!>=- z0V>%()v2-L;`q-0V*wDI?~i?VHiW!o8PvX5c$J+6(JaY5)h}MGW?nHU>!^U0L#sZ3 zQ?IKb)kxFMmJqZV8>`5c;E8=*;dVIVknxinK%HcdiFB{PITpTn`=zdDAOO|K#9qkL} z!$CQH+{#NA_!=xzUy?p#r%GxTB$%&FXd*Y1vs~5Hul$miohtIRhy*21kE;ja zk|iK{2|USJRAK!MXh^f3d3eEsKvd))5GVLNl>=aRakre-vWwr~#e7;ZT(|hPBz9i#9*mqO3-V>hefBWJU}-Hb)Liv#>~G9)C9)HY1`)3Uc0T5BnIY z%!5(6u}D4iq5H`JUrdC2jYE3hIjP6xZ9Je>vT%A$Sm(tPwe7M$8e{3>+H4OxPxeZ} z2eame&aftWwLgiRBKiKvNM{Qf6?F-%@O%MI`MCb<}=ojh5}}TAp?2Kyn_{zS{-0( zFuZM|x4%iuU2-Tmch3zA2rQSqnopeESBXV?Ed)JH;*QfXc#M?B;lWMOtFCMP9{n;3pidD8Yg zWT4Wh=uYB0gbaNJZDS2CwV!HkHAAlhRDU+oT8gJWjvl=xQ8Txaz9f4p7sIOw%Y9yj zH~gAYrzVAw)0>9Twi?m>E<3U%7B61`+RfCW;qw&SAAh#a6?DWV_zim%|8gMTp?_aa z8zk=d4kd4iJ4mG%0&?GB4S0QnhfpA%EZeBeFI8F^!qtSbDcv^IEjk35O#ccGM~9bL zq$L~tjcA4Z3Cx=8i9NCbJ7g$chs#C&A-N;M(8zu%Y0E{Wjwbhmw7Kr|KF|Diyz@KU zeKoW>G}{w_HGBOFMC@Gys9+$V@lp?$+ECQzY}B@Y6P>a=h!zD_@3s;1G49~N4gX9Z z-*Y(%PC^-*nK^&>Sj%yu@`^5Mr zR+i%cJ45q4QB2oWiV~8!{f&3P5-G!N!!as3M8E$gZl{MeSbkk|Efk0;+#tl~u@`I( z$%S5t!%AYjO7<%(D|eUU-~V}uF1OY$6ImUBEO(09oaAu6#z8b_ssJB;ym@N#&~S#f z_q>=E@&Oh0C*i%e*|4v(%X(O6#b@{!S59Z6XD%s&rh98glby4!V_mOV|LQ9aouPx* zpW@A}rewI03;UWpurBrH!Hbn_38n<5EDnLq+V8Ec0>VTJ*2(d!0&g$B4@r(?BW>^V zm};5YKSY-BKi&yE`Z?iJWO#*CI|IeefW%&$LYeAUiZhR^I(b3&B`uqL3ncJE?xo+a zdveok7^wkJ9jO8|`Z? zRMLI9ZMz?a`NP#o(QbImnua)wQGbr61y&;ntV!wEsQmg9Qf*GiuPxZlX|m=ouDe`u zwq8v~<%JuZekJw)uOm4HomR5y^I#ERKp@ta0Yhiw0!4|2AA>n@dspw7f<|>4vRUkE znQXtJ_7S?(NJeHX7!4;c&5byG%bT_)@|)Ln=HKRoa{)MPRf z-4-n2?Z0n;lt4tH#JQIfaJn%@THM}<*G{nW&>D61*^5Wzc4g(fCrTlXvFoGC$o;|`U}Do^Pf%+lIAM2$u-S|FWLug+K3qBO6KTSp3~-KoPNbSBRVaW*zh2l-EeoG=Ih^*5w&EWR+^BLR;bXJ<;ml#fPx+2~&MsrRllR=NM}~a& zlcm*8i0ZLHU&a&YpAAyE4!>b{4@{cR4A^vYVt%-}L(cDD)vh&Rnfu8;_94H1q?Iv4 z*>-~6 zZ8TM%-!lgg2rO0*_TniF7i7QGwuPB5HS*`^mpbip<}cu7qCkyS=y={FWQjKK%uQWauYU?O2z+L3@D+?}GMQcR-S_EqnYOXqhO@x3 zL852xTavK^32Z4XApbIP#CGU)&p?~Uu*@;NcUCQ%4U^n>9IM62N#t|l(^K%J=le6Q zgqJO?g$FU&^Sl(FDlPa^CnA}TDw=wy(Nk!wEKJ_OpF@-U9H%U7GB`r&UqNG`Sw#o3 zcZ~^s5IP0o-D&ymZ8LCLmc8sRZt0KVBBQp8Ov{BL1o4XX}o)G~qEJ05Krt zuhm{;Z|D#}anHOK{P`Oa?M{)Hqb&q@Np7jx9}UuipW@Z+g;Ja~#c5j#I>Ov=*nivh zK5&KjTeZzzNBvq50I3y^dr500^z{2^j$`57Pt)$Ky9+4+h~0NB$7gC3RHf=NY9k`$ zbv_$hm%>Ln@-A)svYA#Np}E z_DYB z5Jv5rAkR*5yy(+Hnl~K>(iDs-D|mEGW-KP|T{?}YinhCVV^)*kg!cz+M?Pp zXYjHWMh~vSI>A$||9Aff%-b0u zy}*W`6VTDrZ-my-Gmr*o`BgK>$`V4~X8^H_@Olej&jWWI54;I?$M80yYToPYj#%7Y zSuTMl2!wRb_S_epl>oW^(xceC^AU>TJ*FQxw-oH0r{>#um$uEBFHBNH``?UI8Wesqm;d^KBnpsq>eAC<-2i6kD|>zafM-`eHYEPq>Vs3Qb=v?Zna3(F1@;}z=bTb|9=dNs?7dBUh6fx-f_ z)DTntJ?{Md&cWn)UmbWBCwVq>f6FuZTnb^pqcCLPks8z&u}{xp!r;mp))#82h6MT@ zJh-Zc1dLlt^wPvx``m=^(qvUjLh%=Tm47$2oe>1WXMVn3K>zQL1h}Aaet{;fBZ1!H0t?h}zdZB*=A1zwf`3F7xxq1YbT3T*#_<2c^&i}h zH_s7$h8N)bXW$BP@OxPzjQ^TJun2?%y4Ucz3m5EQfe7}3puWKVb3FX#zuk?%`Hk$H ze@~15g{AzDxAu>akomI^@w4;B@`C=4m-7#!fyE1>Xba^FYt8O8ICbI?)w{X3XP^~1;b=F|=R=yVqo}AGWt!Gi6=j&NVFXcZIq+$d1DP#uc zw*E)+RnKx~HsBwv>@P46&!qoHFi{)Z3n|@30*!17wrCT2LH*xN4+J9o2erW#j9fvC WuOtiitm(g