From b0caada215c3ca0bcdd40e5b9735e9f26f454b83 Mon Sep 17 00:00:00 2001
From: Botond Baranyi <botond.baranyi@ericsson.com>
Date: Wed, 29 Jun 2016 14:18:33 +0200
Subject: [PATCH] implemented the Main Controller's 'reconf' command
 (artf468488)

Change-Id: Ie84819f7e01d73b0735aaab24207117e4adef28b
Signed-off-by: Botond Baranyi <botond.baranyi@ericsson.com>
---
 core/Communication.cc        |  23 ++++++--
 core/Communication.hh        |   2 +-
 core/Message_types.hh        |  12 +++-
 core/Runtime.hh              |   8 +--
 mctr2/cli/Cli.cc             |  45 +++++++++++---
 mctr2/cli/Cli.h              |   1 +
 mctr2/mctr/MainController.cc | 110 +++++++++++++++++++++++++++++++----
 mctr2/mctr/MainController.h  |   9 ++-
 usrguide/userguide.doc       | Bin 968192 -> 966656 bytes
 9 files changed, 174 insertions(+), 36 deletions(-)

diff --git a/core/Communication.cc b/core/Communication.cc
index 44352b934..6c4df1c2b 100644
--- a/core/Communication.cc
+++ b/core/Communication.cc
@@ -572,7 +572,7 @@ void TTCN_Communication::process_all_messages_hc()
       process_error();
       break;
     case MSG_CONFIGURE:
-      process_configure(msg_end);
+      process_configure(msg_end, false);
       break;
     case MSG_CREATE_MTC:
       process_create_mtc();
@@ -704,6 +704,9 @@ void TTCN_Communication::process_all_messages_tc()
         case MSG_EXIT_MTC:
           process_exit_mtc();
           break;
+        case MSG_CONFIGURE:
+          process_configure(msg_end, true);
+          break;
         default:
           process_unsupported_message(msg_type, msg_end);
         }
@@ -1263,20 +1266,28 @@ void TTCN_Communication::send_message(Text_Buf& text_buf)
   }
 }
 
-void TTCN_Communication::process_configure(int msg_end)
+void TTCN_Communication::process_configure(int msg_end, bool to_mtc)
 {
   switch (TTCN_Runtime::get_state()) {
   case TTCN_Runtime::HC_IDLE:
   case TTCN_Runtime::HC_ACTIVE:
   case TTCN_Runtime::HC_OVERLOADED:
-    break;
+    if (!to_mtc) {
+      break;
+    }
+    // no break
+  case TTCN_Runtime::MTC_IDLE:
+    if (to_mtc) {
+      break;
+    }
+    // no break
   default:
     incoming_buf.cut_message();
     send_error("Message CONFIGURE arrived in invalid state.");
     return;
   }
 
-  TTCN_Runtime::set_state(TTCN_Runtime::HC_CONFIGURING);
+  TTCN_Runtime::set_state(to_mtc ? TTCN_Runtime::MTC_CONFIGURING : TTCN_Runtime::HC_CONFIGURING);
   TTCN_Logger::log_configdata(TitanLoggerApiSimple::ExecutorConfigdata_reason::received__from__mc);
 
   // take the config string directly from the buffer for efficiency reasons
@@ -1311,12 +1322,12 @@ void TTCN_Communication::process_configure(int msg_end)
 
   if (success) {
     send_configure_ack();
-    TTCN_Runtime::set_state(TTCN_Runtime::HC_ACTIVE);
+    TTCN_Runtime::set_state(to_mtc ? TTCN_Runtime::MTC_IDLE : TTCN_Runtime::HC_ACTIVE);
     TTCN_Logger::log_configdata(
       TitanLoggerApiSimple::ExecutorConfigdata_reason::processing__succeeded);
   } else {
     send_configure_nak();
-    TTCN_Runtime::set_state(TTCN_Runtime::HC_IDLE);
+    TTCN_Runtime::set_state(to_mtc ? TTCN_Runtime::MTC_IDLE : TTCN_Runtime::HC_IDLE);
   }
 
   incoming_buf.cut_message();
diff --git a/core/Communication.hh b/core/Communication.hh
index 3cf058ebf..1cf41e27c 100644
--- a/core/Communication.hh
+++ b/core/Communication.hh
@@ -182,7 +182,7 @@ private:
   /** @name Handlers of various messages
   *   @{
   */
-  static void process_configure(int msg_end);
+  static void process_configure(int msg_end, bool to_mtc);
   static void process_create_mtc();
   static void process_create_ptc();
   static void process_kill_process();
diff --git a/core/Message_types.hh b/core/Message_types.hh
index b8873d663..cb718983b 100644
--- a/core/Message_types.hh
+++ b/core/Message_types.hh
@@ -34,7 +34,6 @@
 
 /* Messages from MC to HC (down) */
 
-#define MSG_CONFIGURE		1
 #define MSG_CREATE_MTC		2
 #define MSG_CREATE_PTC		3
 #define MSG_KILL_PROCESS	4
@@ -42,8 +41,6 @@
 
 /* Messages from HC to MC (up) */
 
-#define MSG_CONFIGURE_ACK	2
-#define MSG_CONFIGURE_NAK	3
 #define MSG_CREATE_NAK		4
 #define MSG_HC_READY		5
 
@@ -128,4 +125,13 @@
 
 #define MSG_DEBUG_RETURN_VALUE	100
 
+/* Messages from MC to HC or MTC (down) */
+
+#define MSG_CONFIGURE		200
+
+/* Messages from HC or MTC to MC (up) */
+
+#define MSG_CONFIGURE_ACK	200
+#define MSG_CONFIGURE_NAK	201
+
 #endif
diff --git a/core/Runtime.hh b/core/Runtime.hh
index 282a531a5..10e67fcc6 100644
--- a/core/Runtime.hh
+++ b/core/Runtime.hh
@@ -50,11 +50,11 @@ public:
     MTC_TERMINATING_TESTCASE, MTC_TERMINATING_EXECUTION, MTC_PAUSED, // 14-16
     MTC_CREATE, MTC_START, MTC_STOP, MTC_KILL, MTC_RUNNING, MTC_ALIVE, // 17-22
     MTC_DONE, MTC_KILLED, MTC_CONNECT, MTC_DISCONNECT, MTC_MAP, MTC_UNMAP, // 23-28
-    MTC_EXIT, // 29
+    MTC_CONFIGURING, MTC_EXIT, // 30
 
-    PTC_INITIAL, PTC_IDLE, PTC_FUNCTION, PTC_CREATE, PTC_START, PTC_STOP, // 30-35
-    PTC_KILL, PTC_RUNNING, PTC_ALIVE, PTC_DONE, PTC_KILLED, PTC_CONNECT, // 36-41
-    PTC_DISCONNECT, PTC_MAP, PTC_UNMAP, PTC_STOPPED, PTC_EXIT // 42-46
+    PTC_INITIAL, PTC_IDLE, PTC_FUNCTION, PTC_CREATE, PTC_START, PTC_STOP, // 31-36
+    PTC_KILL, PTC_RUNNING, PTC_ALIVE, PTC_DONE, PTC_KILLED, PTC_CONNECT, // 37-42
+    PTC_DISCONNECT, PTC_MAP, PTC_UNMAP, PTC_STOPPED, PTC_EXIT // 43-47
   };
 private:
   static executor_state_enum executor_state;
diff --git a/mctr2/cli/Cli.cc b/mctr2/cli/Cli.cc
index b4818ac18..6a4886ab9 100644
--- a/mctr2/cli/Cli.cc
+++ b/mctr2/cli/Cli.cc
@@ -195,12 +195,14 @@ Cli::Cli()
     perror("Cli::Cli: pthread_cond_init failed.");
     exit(EXIT_FAILURE);
   }
+  cfg_file_name = NULL;
 }
 
 Cli::~Cli()
 {
   pthread_mutex_destroy(&mutex);
   pthread_cond_destroy(&cond);
+  Free(cfg_file_name);
 }
 
 //----------------------------------------------------------------------------
@@ -217,8 +219,9 @@ int Cli::enterLoop(int argc, char *argv[])
   printWelcome();
 
   if (argc == 2) {
-    printf("Using configuration file: %s\n", argv[1]);
-    if (process_config_read_file(argv[1], &mycfg)) {
+    cfg_file_name = mcopystr(argv[1]);
+    printf("Using configuration file: %s\n", cfg_file_name);
+    if (process_config_read_file(cfg_file_name, &mycfg)) {
       puts("Error was found in the configuration file. Exiting.");
       cleanUp();
       return EXIT_FAILURE;
@@ -728,12 +731,37 @@ void Cli::infoCallback(const char *arguments)
 
 void Cli::reconfCallback(const char *arguments)
 {
-  if(*arguments == 0) { // reconf called without its optional argument
-    puts("Reconfiguration of MC and HCs using original configuration "
-      "data\n -- not supported, yet.");
-  } else { // reconf called with config_file argument
-    puts("Reconfiguration of MC and HCs using configuration file"
-      "specified in\ncommand line argument -- not supported, yet.");
+  if (!MainController::start_reconfiguring()) {
+    return;
+  }
+  if (*arguments != 0) {
+    Free(cfg_file_name);
+    cfg_file_name = mcopystr(arguments);
+  }
+  
+  printf("Using configuration file: %s\n", cfg_file_name);
+  if (process_config_read_file(cfg_file_name, &mycfg)) {
+    puts("Error was found in the configuration file. Exiting.");
+    cleanUp();
+    puts("exit");
+    exitCallback("");
+  }
+  else {
+    MainController::set_kill_timer(mycfg.kill_timer);
+
+    for (int i = 0; i < mycfg.group_list_len; ++i) {
+      MainController::add_host(mycfg.group_list[i].group_name,
+        mycfg.group_list[i].host_name);
+    }
+
+    for (int i = 0; i < mycfg.component_list_len; ++i) {
+      MainController::assign_component(mycfg.component_list[i].host_or_group,
+        mycfg.component_list[i].component);
+    }
+    
+    if (MainController::get_state() == mctr::MC_RECONFIGURING) {
+      MainController::configure(mycfg.config_read_buffer);
+    }
   }
 }
 
@@ -800,6 +828,7 @@ void Cli::exitCallback(const char *arguments)
   if (*arguments == 0) {
     switch (MainController::get_state()) {
     case mctr::MC_READY:
+    case mctr::MC_RECONFIGURING:
       MainController::exit_mtc();
       waitMCState(WAIT_MTC_TERMINATED);
     case mctr::MC_LISTENING:
diff --git a/mctr2/cli/Cli.h b/mctr2/cli/Cli.h
index 190de8f7e..5485f0e18 100644
--- a/mctr2/cli/Cli.h
+++ b/mctr2/cli/Cli.h
@@ -191,6 +191,7 @@ private:
    */
   int executeListIndex;
 
+  char* cfg_file_name;
   config_data mycfg;
 };
 
diff --git a/mctr2/mctr/MainController.cc b/mctr2/mctr/MainController.cc
index 0af653164..8ff32588c 100644
--- a/mctr2/mctr/MainController.cc
+++ b/mctr2/mctr/MainController.cc
@@ -688,20 +688,37 @@ void MainController::configure_host(host_struct *host, boolean should_notify)
         host->hostname);
     }
     send_configure(host, config_str);
-    send_debug_setup(host);
+    if (mc_state != MC_RECONFIGURING) {
+      send_debug_setup(host);
+    }
+  }
+}
+
+void MainController::configure_mtc()
+{
+  if (config_str == NULL) {
+    fatal_error("MainController::configure_mtc: no config file");
+  }
+  if (mtc->tc_state != TC_IDLE) {
+    error("MainController::configure_mtc(): MTC is in wrong state.");
+  }
+  else {
+    mtc->tc_state = MTC_CONFIGURING;
+    send_configure_mtc(config_str);
   }
 }
 
 void MainController::check_all_hc_configured()
 {
+  bool reconf = mc_state == MC_RECONFIGURING;
   if (is_hc_in_state(HC_CONFIGURING) ||
     is_hc_in_state(HC_CONFIGURING_OVERLOADED)) return;
   if (is_hc_in_state(HC_IDLE)) {
     error("There were errors during configuring HCs.");
-    mc_state = MC_HC_CONNECTED;
+    mc_state = reconf ? MC_READY : MC_HC_CONNECTED;
   } else if (is_hc_in_state(HC_ACTIVE) || is_hc_in_state(HC_OVERLOADED)) {
     notify("Configuration file was processed on all HCs.");
-    mc_state = MC_ACTIVE;
+    mc_state = reconf ? MC_READY : MC_ACTIVE;
   } else {
     error("There is no HC connection after processing the configuration "
       "file.");
@@ -2782,6 +2799,7 @@ void MainController::handle_hc_data(host_struct *hc, boolean recv_from_socket)
       if (all_hc_in_state(HC_DOWN)) mc_state = MC_LISTENING;
       break;
     case MC_CONFIGURING:
+    case MC_RECONFIGURING:
       check_all_hc_configured();
       break;
     case MC_ACTIVE:
@@ -2901,6 +2919,12 @@ void MainController::handle_tc_data(component_struct *tc,
             case MSG_MTC_READY:
               process_mtc_ready();
               break;
+            case MSG_CONFIGURE_ACK:
+              process_configure_ack_mtc();
+              break;
+            case MSG_CONFIGURE_NAK:
+              process_configure_nak_mtc();
+              break;
             default:
               error("Invalid message type (%d) was received "
                 "from the MTC at %s [%s].", message_type,
@@ -3538,6 +3562,15 @@ void MainController::send_exit_mtc()
   send_message(mtc->tc_fd, text_buf);
 }
 
+void MainController::send_configure_mtc(const char* config_file)
+{
+  Text_Buf text_buf;
+  text_buf.push_int(MSG_CONFIGURE);
+  text_buf.push_string(config_file);
+  send_message(mtc->tc_fd, text_buf);
+}
+
+
 void MainController::send_cancel_done_ptc(component_struct *tc,
   component component_reference)
 {
@@ -3840,7 +3873,8 @@ void MainController::process_configure_ack(host_struct *hc)
       "received.");
     return;
   }
-  if (mc_state == MC_CONFIGURING) check_all_hc_configured();
+  if (mc_state == MC_CONFIGURING || mc_state == MC_RECONFIGURING)
+    check_all_hc_configured();
   else notify("Host %s was configured successfully.", hc->hostname);
   status_change();
 }
@@ -3857,7 +3891,8 @@ void MainController::process_configure_nak(host_struct *hc)
       "received.");
     return;
   }
-  if (mc_state == MC_CONFIGURING) check_all_hc_configured();
+  if (mc_state == MC_CONFIGURING || mc_state == MC_RECONFIGURING)
+    check_all_hc_configured();
   else notify("Processing of configuration file failed on host %s.",
     hc->hostname);
   status_change();
@@ -5766,6 +5801,26 @@ void MainController::process_mtc_ready()
   status_change();
 }
 
+void MainController::process_configure_ack_mtc()
+{
+  if (mtc->tc_state != MTC_CONFIGURING) {
+    send_error_str(mtc->tc_fd, "Unexpected message CONFIGURE_ACK was received.");
+    return;
+  }
+  mtc->tc_state = TC_IDLE;
+  notify("Configuration file was processed on the MTC.");
+}
+
+void MainController::process_configure_nak_mtc()
+{
+  if (mtc->tc_state != MTC_CONFIGURING) {
+    send_error_str(mtc->tc_fd, "Unexpected message CONFIGURE_NAK was received.");
+    return;
+  }
+  mtc->tc_state = TC_IDLE;
+  notify("Processing of configuration file failed on the MTC.");
+}
+
 void MainController::process_stopped(component_struct *tc, int message_end)
 {
   switch (tc->tc_state) {
@@ -6049,12 +6104,20 @@ void MainController::destroy_host_groups()
 void MainController::set_kill_timer(double timer_val)
 {
   lock();
-  if (mc_state != MC_INACTIVE)
+  switch (mc_state) {
+  case MC_INACTIVE:
+  case MC_LISTENING:
+  case MC_HC_CONNECTED:
+  case MC_RECONFIGURING:
+    if (timer_val < 0.0)
+      error("MainController::set_kill_timer: setting a negative kill timer "
+        "value.");
+    else kill_timer = timer_val;
+    break;
+  default:
     error("MainController::set_kill_timer: called in wrong state.");
-  else if (timer_val < 0.0)
-    error("MainController::set_kill_timer: setting a negative kill timer "
-      "value.");
-  else kill_timer = timer_val;
+    break;
+  }
   unlock();
 }
 
@@ -6309,6 +6372,8 @@ void MainController::configure(const char *config_file)
   case MC_LISTENING_CONFIGURED:
     mc_state = MC_LISTENING_CONFIGURED;
     break;
+  case MC_RECONFIGURING:
+    break;
   default:
     error("MainController::configure: called in wrong state.");
     unlock();
@@ -6316,14 +6381,35 @@ void MainController::configure(const char *config_file)
   }
   Free(config_str);
   config_str = mcopystr(config_file);
-  if(mc_state == MC_CONFIGURING) {
+  if (mc_state == MC_CONFIGURING || mc_state == MC_RECONFIGURING) {
     notify("Downloading configuration file to all HCs.");
     for (int i = 0; i < n_hosts; i++) configure_host(hosts[i], FALSE);
   }
+  if (mc_state == MC_RECONFIGURING) {
+    notify("Downloading configuration file to the MTC.");
+    configure_mtc();
+  }
   status_change();
   unlock();
 }
 
+bool MainController::start_reconfiguring()
+{
+  switch (mc_state) {
+  case MC_READY:
+    mc_state = MC_RECONFIGURING;
+    return true;
+  case MC_LISTENING:
+  case MC_HC_CONNECTED:
+    return true;
+  default:
+    lock();
+    error("MainController::start_reconfiguring: called in wrong state.");
+    unlock();
+    return false;
+  }
+}
+
 void MainController::create_mtc(int host_index)
 {
   lock();
@@ -6415,7 +6501,7 @@ void MainController::create_mtc(int host_index)
 void MainController::exit_mtc()
 {
   lock();
-  if (mc_state != MC_READY) {
+  if (mc_state != MC_READY && mc_state != MC_RECONFIGURING) {
     error("MainController::exit_mtc: called in wrong state.");
     unlock();
     return;
diff --git a/mctr2/mctr/MainController.h b/mctr2/mctr/MainController.h
index 561c665a3..c670f01f6 100644
--- a/mctr2/mctr/MainController.h
+++ b/mctr2/mctr/MainController.h
@@ -63,7 +63,7 @@ enum mc_state_enum {
   MC_INACTIVE, MC_LISTENING, MC_LISTENING_CONFIGURED, MC_HC_CONNECTED,
   MC_CONFIGURING, MC_ACTIVE, MC_SHUTDOWN, MC_CREATING_MTC, MC_READY,
   MC_TERMINATING_MTC, MC_EXECUTING_CONTROL, MC_EXECUTING_TESTCASE,
-  MC_TERMINATING_TESTCASE, MC_PAUSED
+  MC_TERMINATING_TESTCASE, MC_PAUSED, MC_RECONFIGURING
 };
 
 /** Data structure for unknown incoming connections (before receiving
@@ -164,7 +164,7 @@ enum tc_state_enum { TC_INITIAL, TC_IDLE, TC_CREATE, TC_START, TC_STOP, TC_KILL,
   MTC_CONTROLPART, MTC_TESTCASE, MTC_ALL_COMPONENT_STOP,
   MTC_ALL_COMPONENT_KILL, MTC_TERMINATING_TESTCASE, MTC_PAUSED,
   PTC_FUNCTION, PTC_STARTING, PTC_STOPPED, PTC_KILLING, PTC_STOPPING_KILLING,
-  PTC_STALE, TC_SYSTEM };
+  PTC_STALE, TC_SYSTEM, MTC_CONFIGURING };
 
 /** Data structure for each TC */
 struct component_struct {
@@ -345,6 +345,7 @@ class MainController {
   static boolean is_hc_in_state(hc_state_enum checked_state);
   static boolean all_hc_in_state(hc_state_enum checked_state);
   static void configure_host(host_struct *host, boolean should_notify);
+  static void configure_mtc();
   static void check_all_hc_configured();
   static void add_component_to_host(host_struct *host,
     component_struct *comp);
@@ -544,6 +545,7 @@ private:
   static void send_ptc_verdict(boolean continue_execution);
   static void send_continue();
   static void send_exit_mtc();
+  static void send_configure_mtc(const char *config_file);
 
   /** Messages to PTCs */
   static void send_cancel_done_ptc(component_struct *tc,
@@ -607,6 +609,8 @@ private:
   static void process_testcase_started();
   static void process_testcase_finished();
   static void process_mtc_ready();
+  static void process_configure_ack_mtc();
+  static void process_configure_nak_mtc();
 
   /* Incoming messages from PTCs */
   static void process_stopped(component_struct *tc, int message_end);
@@ -629,6 +633,7 @@ public:
   static void shutdown_session();
 
   static void configure(const char *config_file);
+  static bool start_reconfiguring();
 
   static void create_mtc(int host_index);
   static void exit_mtc();
diff --git a/usrguide/userguide.doc b/usrguide/userguide.doc
index a440e5d62ec66b7e9d4ddd52d11b68c603476180..430e53215fdb5c788ae9dae09b4307ef7ff58387 100644
GIT binary patch
delta 16436
zcmciJ2Y3|K-uUrzW<v^OhXfKrLT^F9g!BSP2|e@{ER+yMxgZFl7f@h9Kv6-#6$Y-N
zVE3wsqKwj{DB`_d`V|$uf<Z!&6iSem{J&>sH`&dG|Lc98_j!}&lbJnp=9J%=nVmhe
znYX0lym=j$CB)tpB&?q>Ax5z-c~w?kUak_edEF2FgO+C}nTb2}neqj#p<Xsd3SHz)
z%$vCD^<A$!+iEd2*M1{}QkLx;sC}u$?QlledJTC03n4VhS<h1a{F!A-^40oEh>zKE
z+t)(u;PoN)k8~~%sO#Kp>#804!g<4%7F$4KJvMfKkU!NdFOC%A&QRx_0nO{Ec6k4E
zf6&+&sHMfLEb7O9yOpkr&bA3L^;02U)YLxNj=fu~ZN*)zC7~);Yq=*9ekeb9P=(L+
z<4Ny#pAeTw3HVHiEcZ6GSVfy6Sl(orz%p(JfB5M|z9*=2&R*+vm+{o^e!Wl#o7lTW
zHDq9tCxewuh}o&unrh$ycF4*RqBBYJSl-UE`-9F-fdgx*SgIeQxI7>>@WTmo&BkhT
zXWQWVYT#}JZrA4Q-MBT#Q6nfNGd(#WG1Hl4Z&R_p!`{?dPfBpEwl@uQ<w<f*vo~`m
zCpru4v7Y2FDw30&9rYx4mLz9oDap>4^xNF&$<79~J*B5OOY|1*^c1i3RA*LgcWaVT
zo&T!HpXOX$JI+(>wA#&TTMbKZ-c&{;#ixWgcg99KXV(qa-RVt7O<+r!^PnE>t|h}c
zIIO>WbB47!!)tS<^B-X?+?zA~HYX=I8-!<CC9!@_xVs<8iOwg&-Th<zqwr>SR|Arh
zRKqHp<=!*N8Cu63$mC>aN}UX=N6F4wb(*`gq&Q!y<EbdcD|@QbRyWq2C)Jry*HcWI
z^Uk`dRy2~+tac}*SN1D8-MO`HNB4f|&a#UAGMupyt=#Du&h-(V@-m%|MYsc<>>Lu&
z+$uUHLG>p!J}JbIt!1QhWkk5OZ%Tr*R-}91ltgE8WW0NaM5`@quNZ=qB<HfoB=`0t
z_x41u?a9uPin5Y7M%P<&VB@h<{btHUv-Mc{g4B{S%`LgImoyFpYOPF}C$~%6npz#q
zUH8iNH5^kr|19cF;I&A|?j}YA%SbJFzHMT0geC%mrL~3B`jHbR#FV;o4&nkZ1mm)~
z*feqFpKj%koN$ZsO6&TTSKBsGopJRdTvby+1Fs4UeUhx#f0ngNHARM1O%u^paaGeP
zH_+7uV?&;dHp>4ZZ`4&?t){*v!*0>?ll6RCZuR#8E47*my&GrDn<OL0xoh-v+0$dI
zWkTFKv=LQ{ADkT^s_Cm)I!W53r)N=Kdl{jVWrL84o*4;~Wt79+p8vL9tK;|7cZI{N
z4$pz(>5q2+T-${A*oxGY;Q8JM(5;8gJ7C7O$?{xC#UW@EPLa19u{{l{8?nAtYBde_
zZm^O2kc{+1$h!gRnDO-Rzm43jyJ*F9P>gR(wOSpF(ud@JuYub)RW?hm7)MXYt#fsA
zBj5fu_3ES1b&jkT`{x>LjF~2*{VxdK;i+ys|LkyjqE|JlRws5ev^o)>P7m|iG$|_%
zXz#<v(5K5Lw+h7iCcc62K7Wkd=`y;#Uj+R-=N&6!`wSV?(Ql{!e@{MXT-gfa+H`sI
zFYXi08tmv6uFYO!<U5)#H?Q1X9dy=SO{~;v_VVt5k^AWX{n6X1nQw<Udd<>DWt8+k
zl&qnCrd4%4v|Fjw^w8RCSxeu&ya(46LD$96idJ1$-XvK~Vcy}gj%L3BZ}q1J+`KkJ
zUe<1PD9&x|+giVK(&1gL@V+3r-%+Ji!k_BGtuHWE>=wrQwuVzM-Szfc^}VS2pn9Kx
zX5r&9ME3PLq>I|Pim#@rR`m~C+beD+ss<x^h;PKbM)LA)w<`Ki4CEcY#d0!Lf9;uR
zRZ`JD>-;v$=EzyHg}bL!_w<g5>wd-9;E*ByHF~ZU{>}9tG_%wphvtTxCxuA=O^B8S
zLJYxWW9M=1Ue>%O?WW_nyeb_k#};?4p5%Ptln{S|+T(WjUZYvYpBAD${))%Y@{AC-
zAs6@K0Zc;Uv)soa7mM*0-pBdl=Z}Bq^4;;>tf^m8jG|v<Py@B`b9jC?{C&gmwfrs>
z!WdgaYis*u)}zLeqq3dREnh|&g{Nh#@qWG>)-PRkN;OS2OEpO~M>QjyDu-hmYMv8f
z9M<DHp8Q>iP3MK!i=-kUzAF);w8Z%6OWDTQ@g<R&cT&!i4%O-pP=j4m5e?7^qo9g=
z7pllosA4sW4aF90!(Lp#MX2g_VYj>5Z&()K5*{feqS%0q_zas1g+r{PZEv7vF?V)&
z51ViV|3(z;t`F7z0-Q!6icpHa7l;8yqB#G6*YBRK`Frv=ez0*53+wlFmRs|e@k{at
z8}kp$lfwArjBIKw%9m}8z6G+o@q2-+YxJ{et&Lv)k}<}T0@=ioqzcc)Q&@sYr9wQ2
z$ykeZ_zHVagkpqUVStc^bmU+p=3p+~#9P>p1IYh_sSm_o;~2yc3`hU#!x;JN?0~oM
z$_*j5<1mh({!JlbF%RnS`|g|1Ua$Il{BOsf;=r3z@yn<6Hs+6~Wer)UjS8dc$pWmx
zS~L8tERx}#p1nodXZXqt|6Qefdb*Fad=wd^zi)0Ul-*^xr~8-KP?K(jnc>B1Cr>z{
zNQ*<78Gb>fd&1L+wEoC3!!N0HPq;>r_Aus{;iW3w6TU^Hy@WT-@IO?#C!8OUwj2A+
z@N1;oJ>fk_T65EWLtd13H7CrTa3>Jr0q*F{XZa<H%Y=A`S*%b^idMLWjR8{R1xoQW
z+5}56xTX}dYe})zF2(sUDV_?K;-s;!Om;O_m&pgDLk)*2>}UK3NlfviA`_i38e=d6
zGcgOZF$XshOamUrTz5mFXheN9MKh>|J!_L<38HCSEL!6ZbPkZ3=<?}&%^@9Kcs(BX
zV<G;Am+&gqVrUI1hCy|1DyHFa%*H}2g6i}SIEMe=7v$p<en%nh38D;qiXAwN6G1YM
zo=El4STsj#e2h==1$JUD{(+}Mq<9AJ;xn8_A%ci<2qLftzd{Qo9g%2ep3t-=($S3d
z=IDq{xC2?}j(4#UyRi?4aW^A(AC}_<yb3j%A7K~1#8<e609}gP(GiQW9Cd3;(FE<0
zSzBg{uB>#!Wn6>KVNn;)<3+5(%Xo}KWf8*bNYN0DF{-W<_6R8&prQFqfR--f)FE{N
zYI_rOz*xM9i%|PCB7YlnG~)ub!_v`^b(Pi$rz52(MhQecDI{v48R9Vslko+1;V1lt
zE6}0{I2s`i3FwW%xD&aUfyeO-R-#^g*;~ZaC+g^rK^Tfjcn}%UbOJrm4}&od^Y8=~
z-~`S^n|p$_4$|Jy-ILBNM;rD~?W9>!Q>!iQqe&QpT+B4ta8ZWLWPKJMH$p<S(`JcI
z#+5op%J=R)!_=PNlj8>*L%DlH9krpH1VN-U^f2ua6sh-My(fBOdZeL;YWZeKJ#y>Q
zNqGc+#d6P<`fAH^QeMD|*yY(0qqgiKWjFSqAkx$uY8T|nhFWl>8k9T&sA6D`A?SF|
zY}8oGmyUC!{q9cJNw0&t?mTB$mLj16M<CwA``C!Ah8+3mhgb0x4&ys~j~{RX2OCLo
z2uJZ~V+Iuqun?yj%O;|bl_C`5Is%$V(E^D$+r)gOsg@@ls%BNADp{5ID;cj~pDPm=
zsHPm&h{rI*G~?XIeJ!L|hA;3_OAdFeh~*r_c@)FmT8bo$#6onvjk49<xaa4JFdfac
z`O<Ng+KNz&G6Ygn2t2hnW1ShsidKwZJqKej7mIKjXP{cx5RK3hw__^)igi$}zl<x;
zno~z}SyMD-r8(M~Pq)-&NJm@N+u>EbjfQly3A!T>^YH{cA^3{*Bj`jJa<K$|!*QI!
zS)4<YR-BdSOL#_N9L8fR9)k+srdXLJOjh<_AAZ8mIF1wW#P>4mrLYm(8VE*BxZ-Z^
zjMchGhl+m+Qqc+B&;xy;#^o;Djq#WWHBL|BDLjui@E&$yH)=D6VNhe4h3?44P}FY2
zHbf&2liJ8(;vrUMVjbSbHtfP)974^uyj>#}t#KQ=Aq(Bn3%$_?huU%aw=)mjrp3#9
zR10R|F$&qohLbSkI9Cu8&-fz&CRVg(+!LhuBbm3;6owU@QaOh3&on8bGC1Eb4EJP6
zBfOo~z!=a%vm0}VYIbv3TWzXz9HWAt@H0;10>W=+Oc6|_b=;MoW_cDRxC%)FYzROg
zf)IkLjr^Rn&De_5xO~3gnCth;zw^7&blk2^6}9CoRF@2_!dh&_ZhVXV=u3BpL3MjK
zzQlk;x{L`)Qap?~aNrq~;5t$XQ5WQ45>&{p;X1SwnI`HGyYWzQoPfVzDrQ2(^<DHN
zuD#G712Dt<G+yf`9Wz*;i|6n%Y7_f<7>FUb3wL809>vpGhTrfzx}<YpU<dYK6ytR-
zOninfF)@?&;3d3_zhhztI@3Wq#7tJ~9f>^};9L9)=WrbjJ8>OA8q%>DTd);-ao-)h
z^WtM{g4UUF#S$#Vb6AZ_g|6THqlE{pwZeZEZrx~>C1{$obA(m4+_WdDH!SZSyp(C`
zNt%trFjXtE`}D)Kr>WfT{<ylcrISJKhGyFg?K`P^H+E@f_m&Q7i+A%Dbaij(#1@BY
z@IjQ|25ust3+FQG;Z>}~2Uw3!uo+vh7ym%Bu3Rwj1QuW+mg6MO;t!M|rW=7rQ#3<-
zH%4U!D>E?%bFm0Z@f@63fp4%Mw`FnPgzo5x6?h#VViU%9=g`D7Jb|@XhmWxpS`W@f
zTq!ws<+m%pTsi!kS=O0R(Y;&UCd)Gd-L#@;Rb5+nih7q~KEjj6wEkMOF||LJh%Q;$
zPN}QZ%8EQ?^wf%UPqm>`eXfV8_u>}9q1s_3aCozR70>qMXu^7I!Otkh1vKr&brRjt
z69X{_!!ZJRm<tDX_vUoKLF8k8A7TXqui=e81paeYw%}W2_T?TACvg_PWb@XAas4P5
z_u^4(#x8t~f8u-mf_eQpU$Gi5V>`aakiopuU>$bh5KiLMV6&``3j8^G?dko6p6&xP
zn*;L>)#r;CM*Cl(NrT+g)EYqCP#>{KM-FD<Nvu@MiouC78KGrzl1hCG1-OL7fs}}`
zcoFMx9H&r<mV?NHsaTIf#L@76P@TGp4~Gyy1P+zr0epZXL#46&9r=ebc`@@4a|US(
z9H+>7#l4G0_BZhk)b1Ow8LAk;?h>lF+YyI;7>7LEk4NCd+js}6${V<eGL%CM<A_B(
z+7FZIB8ipzFdmaJ1rK2=4&g8ga2jWD7UjdtO@p;;IgSpwN>)3m4BdzGArt#Y5dIua
zKMWj60Pkd2?&c82RrDIgTQ~Y58~rf=gD@CFF$}}aaYMCNrK6m(gD5u(s*WD$iN~Sp
zn}fM{7V8m8{dW8nGq4P+un($j2XGKaa2yvAOj}!`6;#_><2F2y!|5=Mm4#S@rC5R2
zpgQ;l-o#rlu@ArD6fWTkZr~<b5{y<D02P=)7>p0G0ksKK7-nJ?)?(eA$yCP5>(K7v
zB834Mh|!pc*YOVC$A{QtB#zMbJ2tUuVmJ2VFpi=YgP;b)4jt3+2%do&q$OC2(<s3o
zPy=@j*Kzkf+z#PWY{Cz?g8B?vG<t$T&T)-$A6}?Y?gur>1EEHF2wbDgas+ZP5>H?O
z7U4-eg~fOppJJ2o?;LID2sJBRZ^G8D)72xQ$$dn?6in~aD1dq9%5B}V`8rLgcZ!Jg
zJSnftrRK$5d5qa3wH9{ukd-7Ru30l)8KLzsibrZ;ZH803r=<&7_q0&8ZaXgG66%?4
z?$nM-$0pXdVjI-<FK`M4D8U7I_PNY@ImBp288*~FAi@xix`;qBQjm&K7>#Lo7}N0x
z-Wbhs`z9-2U<Y<$7fNvjf1ueI?rM;VG^8T~V=xxuaX%iw1U!o+SP27H3k!Zc^y5E%
zJXBCvP`KxF_4kv{3*KYFmO_VX@tS&VsMiHcTz}bCbqwkTeysvtWn}VF-d3sp<5?vo
zREQAk$;FdxW&O(0b$A^hY!RLZ5!O(<zsb=tcz(rebujVTs|ZgCq|%Z<bs$w7Y-<{E
zgr?Uc%u#3$&$y{E+G$3Q(h6iF&#)XLEgz@xJJc|JYz!I0eZ=4~T8zn`4Kl_vcxs^3
zpsd0kl#DTBa<x;^p+-d|uEq}R#FzLAD&yBELNQ8k0he$YrMQAWa23~Z9XD_j>KlGn
zT_dahUj60R(Zkm7{ym-#?q=o$%`S~q_iB+gb?$7qSBrCfm%tjIs^jiHdn-bwUPpPF
zb&=}+Y||e1G(at9`Mxj*-$&>|JUzH#4q2`LCe6YJw4pYww*9HBNg8Zs)}(+p>eNaR
znIc^z^X<FDm6Jjy7zZ2yHLFbwsmN(0EDm_2%1f_Zl8oXP0v`5DuvhFal0=emVqU=1
zYLdK)UH6PnE$XFDq2pFmsl_j0@PaBiRDxFx&oA|<LA~^8Qo4UDt)$8_Rxa}{LcI!d
z_tR+qqWwWvIQ>(+`jKpu%<*ZZl~7rOG3^EKDqJtUTAA!0OHYzdElr=TQj1FPs%7j7
zpIX#QpZ%-EGTHD;SiZDM4JyH>rGD{D7FLo^O*<D=DMuxEwX|$v$V69Mt4s4LDWz&;
zt4XMGq^7tIU9UE$_(#{1<Wp0X=%yGOUbIg!rc4T%qy9t~Kd%fpsm{IKMgVFc5JBc{
zBY4ff)rP#uA*hL32sQI2+gGQv!Myo~J-U;Agy*JFJTHys(Op@N(ei|SRE;uju%eAc
zC+tN-)iY4_gik%OQBO<Mg9J5?uBKkql%kr&Qxjln=0?q%sObmwVOM?bQn%#lhEv@;
zsW)(SMJ*d+?)lZuouGPds~)bY2Wje|nR+&+o`b1pUh4UldX}Z0Td8MM>Y0?9@K;mb
zYIa-AX0L&ouU1pjYARYyI;-hrHIZBZHS4P8uhdL{`sA-Z<Ezi~>eD-)(>n_FVN`wW
zR39kSM@RJ;NqrhppJCMPxVlAAZ#n91MZH<5i>Y<xGrv1&zdImlG%cHn*@)#?V`sdI
zW&zB6Aq%YuPZoNiEXT|{V^0e3ItUU)rm^n4y`5K5l1MPZ3+)YzOXuxjKIw@ny`9&=
zkz~{^v^O&DE3A?+*_cm8pM6uTGLMke>)8INl-+9<+3Wb^O|$a$D5_Fyx;d_hc~74P
zj4h&s4aN5Ryh<H%m9!2e_E)@0<z2uyalsyKmX+97YCanh&2^V3)+a5=_^8+(W&D2G
z-rpxZS*1rB@h{qgjhw6Y`o?3W_IRHhDMq&|1n)qpPvetCs*!k!^x!M@+kNt<ndCQo
zYv;;AQ;o7e?Ac!3D!D|rrd+khd!;2_ByE>(+PKT?Tj!d6pjSO9BGHgnsekb`pZe7q
zzw?^?UZ1SVX5w{ws^-Y&3BN}uPhyokp1vxl?VN6IdL2G`c=@#+&luc(YRH7D+rAcj
zr1H`!j^osA10VgpZRsnc1b<utnWFdrM^K()-neOBZ*$zFbsjBgnX;IcDK&K_o!!(!
zJa476%%g;sdF0bFZzE`#$7UMhtwuI?<oDAWMYZfOZlIhCS9y5=cP)Wp`{ThfT<|f#
z_38_sS37tWR<UiT*S7dwTngQiS*jA%kIj|a=K6OF8?TIaG(AEi8rwBJQU<K;^|@vq
zwdr?ifww=yebX~Ma?~eEN1b<sxEJE@T*0sy7cg?Y5I^D=PGkB<d<6uvF(3DQ%)bp_
z1>VNBPxyKX|0OYfGgs>^e6InqxQ32f`Dy}wK=E$AQiA5+3NiLu{);4+mC2Zig~pK}
z-RW5KlMtVRFKde)$oYk@w4m_`_QPAh@`WAL$mi1lMj;pP;sb0e<l#M@xGcnKti=cT
z2%ljKcA+2FMfGKl9#{D$3i@0ZV#Ia6))IY#ov;oc<DkX};%gg|3DCH31|kUE(F23A
z4~MWgkk3xI9K>BTbUshi!Siq;t|n7$=!4-HfiakjSv4KZcCa!B&%lY-upY7&ALOAU
z3MY8aIfwV^^4t(vyw~)@LEc}EVm8O}0-Qo2uEQ3^hdVfN7Dc#<G6dG=v4n#^brFpm
zjK*9n!gE-GJ2)}A;yBKr6y@mKn0>GZ|H481h^KfbehzQoJ$!;KsNIa21ms~Ncn~KX
zz4_A@qj0zt*AbjW39drMGB=Gtgdhf=;d89wt^QSPg?d&spbd|_F@v*p4r+4?5Q(Sp
zJbuGDbZt-c5RuH88^bhA!xZLla5Ig{()py6L5T1nZ_%HkX=f&nklmB9#{^74gI?T&
zU}PU6hj1<pQMenqxS35k=rx>)G4w??`eOhF4R=r=D?>31Iaq+j*oN)6fJ?BAVCDc3
zNWsIHjvcsyv>ZO@<9;x^B@C>>SJ;DMs0k}|5eX6vEyg>w^dZJwx*lq*sil7=ZN`*P
zJ<9k?sJ^zRjVx8UcdJNOudB;bk!EzRrT3#)7RjwtYIP;}q#3W&((h4C3R6wW2=NqE
z!_alTpE018-cV}Bc3qDO51>4cAl8G7wT<*9p_=O=$vvTHD2+3^-eGKRJHFDhTZlpU
zp9jTvOh!}_{}N(&y)vFgS%luAji;g3QX?+jJnak+HY2dU{*7biF)oDI^pnM8siboi
zRMZ`vy6;qXbLs-6?&Q=3NZrM$v&Pep`<ZiB4i4Z=5yx>6!2>y{5$pC4%V}7O6$3f)
zUuQ*m6K}!9K3u{TsQK_#7{EmJK#ajeybd*){XW!$_9mFvjr}-`?{J3u))J^GUH_w>
zBYzMZypMhrY0nw(B<t0k1yLO7RgeB-q@DgR&Vmb!+@+dc!`C@RpJWV((d(P<#^~|d
z|Ju-~bAL*|%JW}EL7o4KI^DfH?A6(k|EuS`nyj|Ydt+%M{d?8VFmrrkegB|H-Zwda
z)Hm3K;LEnIpYulFDSA6wr!Jw!^eOr_*FRLXe@I`W1?}s5S*XdMe@@fmdaAAox~6{A
z-}0`Z^Q>2{Bv-2MYrgZ?S_^Y;RUhj13iFPK_4pdY5`&l27sUs(lK~T4yUgF*v-NZ5
zdOdKdL)-g<MF_iWN#$P}BY86wX*ShlTiC;aRZ~@p`WY7>io?vr30kIX`)1&dpijgn
zVjfSit*xHFdwbIWsGn_zyVX<wW|`u?a;UV>By-#>{Z&o<Z`r6#v-Ovy%rMr>(fc>O
zw9Qoi`bj%zj=C4K8lsk}i8eJ4^`U0wuGZI9^VjG)LEF1>iT>~Udvw>ns@ZB^)iJf)
zYo1@CpVn;YqM`Bq^Ll2Z%K4-e=C7<wY;<LQ-uTb+da_TJq$*jS_Ro@7CCdW;ED04^
z8n`N&Q#DI6^J$*8SXpNHXUV9NWtxAM^eR~<`DaP1l4ZPq77h<rGt-6Dma+a>)cC9T
zda~T*pQSRoRw={$vs6ac$}+$|OJ#JeEWQ1+R7N+()uwJ$vm|*%*UHk-KTBnFtt_ej
zSt_GzWohr9r82r!mNx!bDx+&<Y2lxxGP+ilM*dkUqibb}^3PHkT`Nntf0oMVT3KrO
zXQ_;Cv@5zbTv@z6)vAe(R}B5A`Ulb(tMtiD?@<2(-!X`<`{E9CMi+ENH>mC1S@u9r
z^g?g+L0=>8bG>``-K^dNl~oyI%>P_>EMFVCa<l$mNY{X5*FTJpHXq%r+oUGHF&^8Z
zUy~h-N4M$@nPptwsz1~_x4fMzSJi(n=dcyK#BMQEd@s6*AJJRv5Ix06{>glp7%s9!
zFY&FoOXP@y;;7hRythry)O`yxFKpBAtI;wcIXxpeC8JwhLRz<kxRlh4gt&~vl+3u~
Wq?FXG#EjJR#2!7($9C&aYX1+!i^4Ae

delta 17478
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

-- 
GitLab