From c379f15a5cd65cf0327e46b304cc745ea44abf02 Mon Sep 17 00:00:00 2001 From: Caiyishuai <39987654+Caiyishuai@users.noreply.github.com> Date: Thu, 16 Nov 2023 15:28:08 +0800 Subject: [PATCH 1/6] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=BA=86=20=E5=AF=BC?= =?UTF-8?q?=E8=88=AA=E7=AE=97=E6=B3=95=20=E5=92=8C=20=E9=83=A8=E5=88=86?= =?UTF-8?q?=E5=8A=A8=E4=BD=9C=E8=8A=82=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- robowaiter/algos/explore/scene.py | 48 +++--- robowaiter/algos/navigate/discretize_map.py | 59 ------- robowaiter/algos/navigate/navigate.py | 158 ------------------ robowaiter/algos/navigate/readme.md | 52 ------ .../algos/{navigate => navigator}/__init__.py | 0 robowaiter/algos/navigator/costMap_3.pkl | Bin 0 -> 1557411 bytes robowaiter/algos/navigator/costMap_4.pkl | Bin 0 -> 876114 bytes robowaiter/algos/navigator/costMap_5.pkl | Bin 0 -> 562562 bytes robowaiter/algos/navigator/discretize_map.py | 90 ++++++++++ .../{navigate => navigator}/dstar_lite.py | 136 +++++++-------- robowaiter/algos/navigator/mag_5.png | Bin 0 -> 25292 bytes robowaiter/algos/navigator/map_3.pkl | Bin 0 -> 1557411 bytes robowaiter/algos/navigator/map_4.pkl | Bin 0 -> 876114 bytes .../algos/{navigate => navigator}/map_5.pkl | Bin robowaiter/algos/navigator/navigate.py | 115 +++++++++++++ robowaiter/algos/navigator/readme.md | 128 ++++++++++++++ .../algos/{navigate => navigator}/test.py | 38 +++-- robowaiter/behavior_lib/_base/Behavior.py | 11 +- robowaiter/behavior_lib/act/Make.py | 38 +++-- robowaiter/behavior_lib/act/MoveTo.py | 36 ++-- robowaiter/behavior_lib/act/PickUp.py | 34 +++- robowaiter/behavior_lib/act/PutDown.py | 1 + .../obtea/OptimalBTExpansionAlgorithm.py | 12 +- .../behavior_tree/obtea/opt_bt_exp_main.py | 8 +- robowaiter/robot/robot.py | 2 +- robowaiter/scene/scene.py | 21 ++- robowaiter/scene/tasks/VLM.py | 44 ++--- robowaiter/scene/tasks/VLN.py | 8 +- 28 files changed, 593 insertions(+), 446 deletions(-) delete mode 100644 robowaiter/algos/navigate/discretize_map.py delete mode 100644 robowaiter/algos/navigate/navigate.py delete mode 100644 robowaiter/algos/navigate/readme.md rename robowaiter/algos/{navigate => navigator}/__init__.py (100%) create mode 100644 robowaiter/algos/navigator/costMap_3.pkl create mode 100644 robowaiter/algos/navigator/costMap_4.pkl create mode 100644 robowaiter/algos/navigator/costMap_5.pkl create mode 100644 robowaiter/algos/navigator/discretize_map.py rename robowaiter/algos/{navigate => navigator}/dstar_lite.py (82%) create mode 100644 robowaiter/algos/navigator/mag_5.png create mode 100644 robowaiter/algos/navigator/map_3.pkl create mode 100644 robowaiter/algos/navigator/map_4.pkl rename robowaiter/algos/{navigate => navigator}/map_5.pkl (100%) create mode 100644 robowaiter/algos/navigator/navigate.py create mode 100644 robowaiter/algos/navigator/readme.md rename robowaiter/algos/{navigate => navigator}/test.py (72%) diff --git a/robowaiter/algos/explore/scene.py b/robowaiter/algos/explore/scene.py index 1113d5b..f975604 100644 --- a/robowaiter/algos/explore/scene.py +++ b/robowaiter/algos/explore/scene.py @@ -1,4 +1,5 @@ import time +import math import grpc import numpy as np @@ -358,29 +359,29 @@ class Scene: temp = stub.GetIKControlInfos(GrabSim_pb2.HandPostureInfos(scene=self.sceneID, handPostureObjects=HandPostureObject)) # 移动到进行操作任务的指定地点 - def move_task_area(self,op_type): - if op_type==11 or op_type==12: # 开关窗帘不需要移动 - return - scene = stub.Observe(GrabSim_pb2.SceneID(value=self.sceneID)) - walk_value = [scene.location.X, scene.location.Y, scene.rotation.Yaw] - - if op_type < 8: - v_list = self.op_v_list[op_type] - if op_type>=8 and op_type<=10: # 控灯 - v_list = self.op_v_list[6] - if op_type in [13,14,15]: # 空调 - v_list = [[240, -140.0]] # KongTiao [300.5, -140.0] # 250 - - print("------------------move_task_area----------------------") - print("Current Position:", walk_value,"开始任务:",self.op_dialog[op_type]) - for walk_v in v_list: - walk_v = walk_v + [scene.rotation.Yaw, 180, 0] - walk_v[2] = 0 if (op_type in [13,14,15]) else scene.rotation.Yaw # 空调操作朝向墙面 - action = GrabSim_pb2.Action( - scene=self.sceneID, action=GrabSim_pb2.Action.ActionType.WalkTo, values=walk_v - ) - scene = stub.Do(action) - print("After Walk Position:",[scene.location.X, scene.location.Y, scene.rotation.Yaw]) + # def move_task_area(self,op_type): + # if op_type==11 or op_type==12: # 开关窗帘不需要移动 + # return + # scene = stub.Observe(GrabSim_pb2.SceneID(value=self.sceneID)) + # walk_value = [scene.location.X, scene.location.Y, scene.rotation.Yaw] + # + # if op_type < 8: + # v_list = self.op_v_list[op_type] + # if op_type>=8 and op_type<=10: # 控灯 + # v_list = self.op_v_list[6] + # if op_type in [13,14,15]: # 空调 + # v_list = [[240, -140.0]] # KongTiao [300.5, -140.0] # 250 + # print("------------------error version----------------------") + # print("------------------move_task_area----------------------") + # print("Current Position:", walk_value,"开始任务:",self.op_dialog[op_type]) + # for walk_v in v_list: + # walk_v = walk_v + [scene.rotation.Yaw, 180, 0] + # walk_v[2] = 0 if (op_type in [13,14,15]) else scene.rotation.Yaw # 空调操作朝向墙面 + # action = GrabSim_pb2.Action( + # scene=self.sceneID, action=GrabSim_pb2.Action.ActionType.WalkTo, values=walk_v + # ) + # scene = stub.Do(action) + # print("After Walk Position:",[scene.location.X, scene.location.Y, scene.rotation.Yaw]) # 相应的行动,由主办方封装 def control_robot_action(self, type=0, action=0, message="你好"): @@ -512,3 +513,4 @@ class Scene: print(scene.info) + diff --git a/robowaiter/algos/navigate/discretize_map.py b/robowaiter/algos/navigate/discretize_map.py deleted file mode 100644 index f16dd92..0000000 --- a/robowaiter/algos/navigate/discretize_map.py +++ /dev/null @@ -1,59 +0,0 @@ -# !/usr/bin/env python3 -# -*- encoding: utf-8 -*- - - -import matplotlib.pyplot as plt -import numpy as np -import pickle -import os - - - - - -def draw_grid_map(grid_map): - # 生成新的地图图像 - plt.imshow(grid_map, cmap='binary', alpha=0.5, origin='lower') # 黑白网格 - - # 绘制坐标轴 - plt.xlabel('y', loc='right') - plt.ylabel('x', loc='top') - - # 显示网格线 - plt.grid(color='black', linestyle='-', linewidth=0.5) - - # 显示图像 - plt.show() - #plt.pause(0.01) - - - - -if __name__ == '__main__': - # control.init_world(scene_num=1, mapID=3) - # scene = control.Scene(sceneID=0) - # - # X = int(950/5) # 采点数量 - # Y = int(1850/5) - # map = np.zeros((X, Y)) - # - # for x in range(X): - # for y in range(Y): - # if not scene.reachable_check(x*5-350, y*5-400, Yaw=0): - # map[x, y] = 1 - # print(x, y) - # - # - # file_name = 'map_5.pkl' - # if not os.path.exists(file_name): - # open(file_name, 'w').close() - # with open(file_name, 'wb') as file: - # pickle.dump(map, file) - # print('保存成功') - - - file_name = 'map_5.pkl' - if os.path.exists(file_name): - with open(file_name, 'rb') as file: - map = pickle.load(file) - draw_grid_map(map) \ No newline at end of file diff --git a/robowaiter/algos/navigate/navigate.py b/robowaiter/algos/navigate/navigate.py deleted file mode 100644 index 9059c61..0000000 --- a/robowaiter/algos/navigate/navigate.py +++ /dev/null @@ -1,158 +0,0 @@ -#!/usr/bin/env python3 -# -*- encoding: utf-8 -*- -import math -import sys -import time - -import matplotlib.pyplot as plt -import numpy as np -from mpl_toolkits.axes_grid1 import make_axes_locatable -# from scene import control - -# from rrt import RRT -# from rrt_star import RRTStar -# from apf import APF -from robowaiter.algos.navigate.dstar_lite import DStarLite, euclidean_distance - -class Navigator: - ''' - 导航类 - ''' - - def __init__(self, scene, area_range, map, scale_ratio=5, step_length=150, velocity=150, react_radius=300): - self.scene = scene - self.area_range = area_range # 地图实际坐标范围 xmin, xmax, ymin, ymax - self.map = map # 缩放并离散化的地图 array(X,Y) - self.scale_ratio = scale_ratio # 地图缩放率 - self.step_length = step_length # 步长(单次移动) - self.step_num = self.step_length // self.scale_ratio # 单次移动地图格数 - self.v = velocity # 速度 - self.react_radius = react_radius # robot反应半径 - - # self.planner = RRTStar(rand_area=area_range, map=map, scale_ratio=scale_ratio, max_iter=400, search_until_max_iter=True) - self.planner = DStarLite(area_range=area_range, map=map, scale_ratio=scale_ratio) - - @staticmethod - def is_reached(pos: (float, float), goal: (float, float), dis_limit=30): - ''' - 判断是否到达目标 - ''' - dis = math.hypot(pos[0]-goal[0], pos[1]-goal[1]) - # dis = np.linalg.norm(pos - goal) - return dis < dis_limit - - @staticmethod - def get_yaw(pos: (float, float), goal: (float, float)): - ''' - 得到移动方向 - ''' - return math.degrees(math.atan2((goal[1] - pos[1]), (goal[0] - pos[0]))) - - def legalize_goal(self, goal: (float, float)): - ''' - TODO: 处理非法目标 - 目标在障碍物上:从目标开始方形向外扩展,直到找到可行点 - 目标在地图外面:起点和目标连线最靠近目标的可行点 - ''' - return goal - - def navigate(self, goal: (float, float), animation=True): - ''' - 单次导航,直到到达目标 - ''' - if not self.scene.reachable_check(goal[0], goal[1], 0): - goal = self.legalize_goal(goal) - - pos = (self.scene.status.location.X, self.scene.status.location.Y) # 机器人当前: 位置 和 朝向 - print('------------------navigation_start----------------------') - while not self.is_reached(pos, goal): - dyna_obs = [(walker.pose.X, walker.pose.Y) for walker in self.scene.status.walkers] # 动态障碍物(顾客)位置列表 - dyna_obs = [obs for obs in dyna_obs if euclidean_distance(obs, pos) < self.react_radius] # 过滤观测范围外的dyna_obs - # 周围有dyna_obs则步长减半 - if dyna_obs: - step_num = self.step_num // 2 - else: - step_num = self.step_num - path = self.planner.planning(pos, goal, dyna_obs) - if path: - if animation: - self.planner.draw_graph(step_num) # 画出搜索路径 - next_step = min(step_num, len(path)) - next_pos = path[next_step - 1] - # print('plan pos:', next_pos, end=' ') - yaw = self.get_yaw(pos, next_pos) - # print("yaw:",yaw) - self.scene.walk_to(next_pos[0], next_pos[1], Yaw=yaw, velocity=self.v, dis_limit=10) - # pos = (self.scene.status.location.X, self.scene.status.location.Y) - # if self.is_reached(pos, next_pos): - self.planner.path = self.planner.path[next_step - 1:] # 去除已走过的路径 - pos = (self.scene.status.location.X, self.scene.status.location.Y) - # print('reach pos:', pos) - - self.planner.reset() # 完成一轮导航,重置变量 - - if self.is_reached(pos, goal): - print('The robot has achieved goal !!') - - - - - - - - - - - # def navigate(self, goal: (float, float), path_smoothing=True, animation=True): - # pos = np.array((self.scene.status.location.X, self.scene.status.location.Y)) # 机器人当前: 位置 和 朝向 - # yaw = self.scene.status.rotation.Yaw - # print('------------------navigation_start----------------------') - # - # path = self.planner.planning(pos, goal, path_smoothing, animation) - # if path: - # self.planner.draw_graph(final_path=path) # 画出探索过程 - # for (x, y) in path: - # self.scene.walk_to(x, y, yaw, velocity=self.v) - # time.sleep(self.step_time) - # pos = np.array((self.scene.status.location.X, self.scene.status.location.Y)) - # - # self.planner.reset() - # - # if self.is_reached(pos, goal): - # print('The robot has achieved goal !!') - - '''APF势场法暂不可用''' - # while not self.is_reached(pos, goal): - # # 1. 路径规划 - # path = self.planner.planning(pos, goal, path_smoothing, animation) - # self.planner.draw_graph(final_path=path) # 画出探索过程 - # - # # 2. 使用APF导航到路径中的每个waypoint - # traj = [(pos[0], pos[1])] - # #self.planner.draw_graph(final_path=traj) # 画出探索过程 - # for i, waypoint in enumerate(path[1:]): - # print('waypoint [', i, ']:', waypoint) - # # if (not self.scene.reachable_check(waypoint[0], waypoint[1], yaw)) and self.map[self.planner.real2map(waypoint[0], waypoint[1])] == 0: - # # print('error') - # while not self.is_reached(pos, waypoint): - # # 2.1 计算next_step - # pos = np.array((self.scene.status.location.X, self.scene.status.location.Y)) - # Pobs = [] # 障碍物(顾客)位置数组 - # for walker in self.scene.status.walkers: - # Pobs.append((walker.pose.X, walker.pose.Y)) - # next_step, _ = APF(Pi=pos, Pg=waypoint, Pobs=Pobs, step_length=self.step_length) - # traj.append((next_step[0], next_step[1])) - # #self.planner.draw_graph(final_path=traj) # 画出探索过程 - # while not self.scene.reachable_check(next_step[0], next_step[1], yaw): # 取中点直到next_step可达 - # traj.pop() - # next_step = (pos + next_step) / 2 - # traj.append((next_step[0], next_step[1])) - # #self.planner.draw_graph(final_path=traj) # 画出探索过程 - # # 2.2 移动robot - # self.scene.walk_to(next_step[0], next_step[1], yaw, velocity=self.v) - # # print(self.scene.status.info) # print navigation info - # # print(self.scene.status.collision) - # time.sleep(self.step_time) - # # print(self.scene.status.info) # print navigation info - # # print(self.scene.status.collision) - # self.planner.reset() diff --git a/robowaiter/algos/navigate/readme.md b/robowaiter/algos/navigate/readme.md deleted file mode 100644 index 585e602..0000000 --- a/robowaiter/algos/navigate/readme.md +++ /dev/null @@ -1,52 +0,0 @@ -## 默认使用RRTStar+路径平滑 - -### apf.py: 势场法实现 - -### discretize_map.py: 地图离散化并压缩 - -### map_5.pkl: 地图文件(5倍压缩) - -### navigate.py: 导航类 - -### pathsmoothing.py: 路径平滑 - -### rrt.py: RRT实现 - -### rrt_star.py: RRTStar 实现 - -### test.py: 测试文件 - - - - -## TODO - -### 目标不合法 -#### 初始目标不合法 -目标在障碍物上:从目标开始方形向外扩展,直到找到可行点 -目标在地图外面:起点和目标连线最靠近目标的可行点 -对不合法的目标做单独处理,生成新的目标 - -#### 在移动过程中目标被占据 -给出目标但不会行移动,程序会继续运行,重新计算规划路径,给出新目标 - - -### 规划中断情况 - - -### 计算转向角 -`完成` - - -### 有些本来可达的位置却无法走到(系统bug?) -例如从初始位置(247, 500) 移动到(115, -10),无法到达 -`(已解决)将dis_limit设为小值5而非0` -#### 构型空间膨胀?? -`不需要` - -### 只考虑一定范围内的行人 -观测范围 / 反应半径 - -`完成` -#### 观测范围内有行人步长要减小 -`完成` diff --git a/robowaiter/algos/navigate/__init__.py b/robowaiter/algos/navigator/__init__.py similarity index 100% rename from robowaiter/algos/navigate/__init__.py rename to robowaiter/algos/navigator/__init__.py diff --git a/robowaiter/algos/navigator/costMap_3.pkl b/robowaiter/algos/navigator/costMap_3.pkl new file mode 100644 index 0000000000000000000000000000000000000000..cb70debc8e7582677956151cb7eb8e080d88276d GIT binary patch literal 1557411 zcmeFaz0x#Gm!8!lp+E*Mf$X%fWMjx!0Ui??gA*X6(GVg6jTFO-F%~!i6!Cf591$nP z834KOxp-%<_p9B1Ro(S-Jx1PNbysDsyw<%|XSd$1`CtE&|MTD9^7n`T{4f9J-~7A3 z{ilEaZ~y8q{^`H@oB!#r|HpsvSAX>{{`QwY{Ad6DU;V|O|J%R(pa1%={^rmB`j`Ls z%OC#HuQ&ekhyV01|5a}JkH7rs?ce|M-~7qH{N;cD<-hyozx>lb`RD)aPyYG8{s;ft zFaP=<{^1|}tH1u+fA<&jv48MC{8zvHhyNpY{KG%|$v^w$&;IPs{@efO|NHxO_|w~8 z|MD;Y!+(AIzy6EAi|7CTU-CaxIZOijKp*G>>%cx>ANXb;7#04gehd#e$YB!D2l_xC zSO@k2`+$AGK42fP57-Cn1NH&?fPKI|Fe-I`+84q@4sw_T^npIm2iAdoz&>Cfun*V= z>;v`z`+$AGK42fP4~()7tOM)7&qMoweZW3oAFvPD2kZm(0sDY`z&>Cfun*V=&eI1* z#m`+|t#jsi^?9F5KI9;WNkAXy1ASl}*az$b_5u5VeZW3oAFvPD2kZm(f&KJ>QSsxu zYF&q;9ON(w=mUMA53B?GfPKI|U>~p#*az$b_5u5VeZW3&o<1-ten$Vv-(5edJZE1B zM>)u063_?wKp$8K_5u5VeZW3oAFvPD2kZm(0sDY`;Cy{xRD9ikH~Ytb_j*_E<2n06 z_{l*IlYl;v`z`+$AGK42fP57-Cn1Lx}lqvC6n-^cpzW?b_=_uCi3 zPY!aJ1oVME&CfIBy>q6@T;l7|QQvD6ezBeIeZB zAcsjnALs*pU>(>8>;v`z`+$AGK42fP57-Cn1NMRQ_JL9HH_Gp1OUixrg>aLD93}yM zpbzwcbzmQ`57-Cn1NH&?fPKI|U>~p#*ayzv2S&x`kE(qkyyPHCfun*V=>;v`z`+$AGK42fP57-Cn1NH&?fPKI| zU>~p#*az$b_5u5VeZW3oAFvPD2kZm(0sDY`z&>Cfun*V=>;v`z`+$AGK42fP57-Cn z1NH&?fPKI|U>~p#*az$b_5u5VeZW3oAFvPD2kZm(0sDY`z&>Cfun*V=>;v`z`+$AG zK42fP4_v(uj7lFsug=5$#}9Il!z7>&^npIG4(tQ=0sDY`z&>Cfun*V=>;v`z`@ros zDn7WU)=N0aK@O9EKF|mHz&fxG*az$b_5u5VeZW3oAFvPD2kZmq?*pUabM&A5-E~*q z?`og8{rV>dIZOijKp*G>>%cx>AFvPD2kZm(0sDY`z&>Cfun(NC4~&Yh`|oA{c;R*K z<2ls+5RP(?!z7>&^npIG4(tQ=0sDY`z&>Cfun*V=>;v`z`@r%0z^M2b<##cDH(OHf zLwVl55T0_7!z7>&^npIG4(tQ=0sDY`z&>Cfun*V=>;v|JEB1j==gK?#;dd~U-_5ey zA0w}$+|N9y{UOZcAcsjnALs*pU>(>8>;v`z`+$AGK42fP57-Cn16Sw+qmt((Jz5>~ zeegRNzl)*S_0J>k^BmgeJsKC|O|Io2he<#m=mULV9oPr#1NH&?fPKI|U>~p#*az$b z&-8&&;l=MnD6hY(pYmgmlYOB4E|%RckKBjyJlfa!)c#y2Ig^7NCINk*5A=a`U>~p# z*az$b_5u5VeZW3oAFvO6q7RG;XO!QE)>7vEl%H9z$ItIzXm)*n~p#*az$b_JL3Ifl=Yye;4BSqF0sqn15?OvkuDo zJ^t+W`LWN#{H%v=y-(*)?&KhcNkAXy1ASl}*az$b_5u5VeZW3oAFvPD2kZk|_JL91 zi}HI=|D7mzJwEb0^D+O{er6rkMTzI}9sK^C%*XsF>!Vxm*ZGqtImlrW&Cfun*V=>;v`z`@j}`U{tvB`wz{CjROZ;q$IOqiE^(lV;{B2N zP}W0<1Kn!h&YN7yK@O9EKF|mHz&fxG*az$b_5u5VeZW3oAFvPD2iEKZqrwyAcOQNa zLUY&iBhNE0>ulv?=4U;WIG*3ZV^1(Y%DO0Vp!VqHyODKJ;y{US z?fpAnaw-QoOal5qALs+?z&>Cfun*V=>;v`z`+$AGK42eMqYsP%|<{gL^Ye^lmN%g4;e{3z?9S@rWH>k}7B++Ek=;ylT< z9ON(w=mUMA53B?GfPKI|U>~p#*az$b_5u5Vec+isFeCf zun#=b2S$Zg|NVyFck=FfBlEJ}sLcJUZ+RYNUX=B+%6>-T>Pp-w`$Avk~p#*az$b_5u5Vec+KkFe;o-ey{1j=j5*U$38FXvHr8ZecOlYl;v`z`+$AGK42fP57-BOuMdn0 zAAX-f`JE~6zCJQfSJpvCWsQ4&<-V@Wb2aT8yuSVV2Zwup^8N6VgB&ISeV`BYfpuUX zun*V=>;v`z`+$AGK42gCZ66qwYn0!e`tMx1>+!Ka&o%RRWqq{giPzQJuYdPAbiP-; z?wq=>ypEsbAcsjnALs*pU>(>8>;v`z`+$AGK42fP51g$Jj7nXvrTzC6e(%aE_ebvU z+UMnZDekl7>C^jJ;tF@P=jm+M>=W%=KAjiWOAnEQ93}yMpbzwcbzmQ`57-Cn1NH&? zfPKI|Fe-KMDdqQpwY2|^lHL3~_WQVAierg~eKTyg;?TJ-<%j&CKWF?HuMj`l_uF}F z#oc-17dgmb63_?wKp$8K_5u5VeZW3oAFvPD2aeMRM#Zn6(*C`D>uY{5SW83e$G9}_ z(!Q2B+c(4X(;Sxa(et;I=O0cu#{cU3==+4nr}N-?@sAwjFbU`beV`Al1N(q|z&>Cf zun*V=>;sSYfl=|xr?h{M-uk+KkKg(_G}jw@yi2^6@@GFxF80Qu=W8jiJ^$-D>oYU; z_}ORQ|K9RrJn@GdU4C>ros{+eMrFNEY5%^t^)=sfKc%7RxI}p$eq!lCDvym!SH=#qc-@;Y&% zeLsEQXUV7ghy&#yhe<#m=mULV9oPr#18eqyQSw}q=UVkiUeLAXb)L`qo&2q({rlh6 z*L?5%lqNfl-zGr5@fZHJe~p#{9Ydz6+ZV=ABEGmINZw*?|&;k*Zt%EATLYG_q4UNe;?fXI=gnf3IY6t zU-7l|9|v5819?aBLs$HQhSL5<;zRpB*e80GJiE_$RSt5P1oVME&=8%|8ijKmdQ@-%(lQs&#+$ zeUtyL_yff^UE`kpj6FW$N7?7q^X~rRSvkmI63_?wKp$8K_JL#ffl-NnNjV2DDd$Jt z@AK%7@ZFk2=T1J*o+n;M`}16H9rxMihvSmMe@V&PlHUB2z>W#vTl_sL!JfVD-QQz* z#t$ey>57lg%)XzIxKQF}U#PxF&g3A6NkAXy1ASl}*az$bd+r0HlAk5zytkyB3zxJ% z$2!(UxNpS)&S=lWQoeY--_JGkb=_(oN1wNI>ep~xQu48+H~&^4u*7$(*H;Ppz>~lg z-;c^>j$ZG^ziuA!MOS=-;wLmw>}Mn{;zj$u^iOgo2RTdv`amD(1M9#(U?2Eq9~c$> zOUij}Njd*5X=eX1_WPK(uWwz1*;*VrU$~<^FF!Jt|JC2;n&-Rr^|)SZKS!B|eJ^R} z*015bq&NS5m%tLYXJ7AmS^JuJes?n$coPor9hFTVrQVJ6JNd#VDE>k5RifL^NL(oK zqU;CNU&);ua=u&A%>MYuJbgXlvmV0oT@LU> zJ8$xUX4U&6_jm2{bItl)-`(F{p6~nW*KkHhE|j=Y_Ji(~zj4J=a*)F$pbzwcKClk# z1IO+IqY^*ou_fjFwxpTm{jtwaJfku^Sy&&N6_aiGuc=cxCy z-zA05l6J2B`nL1G9`CEyOMISveJKymzW%NsS&#TTmz}3|v+&>m7dXAk+vk(At8lbRTEG4<1Vjza@qDlHOMOTblpb*O&J3 z?CVRso_+n>{vzJKf4HuczQaw!{^0_rZ|BSPW2K{Tz&9vW_74v@9W~F! z9V35>1O7qr6+S}~<^D$ELy4dLpx@%_y77!0&N7%bAS&DHx#aDW_f>PK9u!{1MTs89rn+1faj9Je`{S@|Jm1{-Tztd zhZ}jLp3vLH{@6D>;B(geyRR60YYzAbU!nL7-D|lKA917X3*DNd^T#1_ki#UP5A=aP zunz14=jsEavLDV_DCe-eyPuJ`P~shx7*T!tTOM$M7Yau-PrW}fAIf?t@tCKu-kJlv zmz2DqOZPqd`qulp%KUIAKPdHeyVxK5h68-A;s^H`!>`Q&AEEdQ#dleKeL%)|ER>=^(uAH z_YD^mUTA2&KQbT6dT5X9D*14q@s=Fc;XoZxSJWGtRn9-MUpT-;pC$KlSce0?!e=P{ zL$licM&d(>A7y{2zDW+{AcsjnALs*pU>(>8>;sd)s5$;n&QYAN(A>5Ek$Blh*HPI6 zde%B%e`x0bCp1*vADIvB>kO zj>?|89=$I5e%LSCxrD-cBlEK!+T%JpXXB4&M+rre`LSxA1?YcxtGJb z9Pk&4@9-g-Rrfm*C(1t97pi}fLpjJ{63_?wKp$8K_JM2mfl=8v%DIVi6q>t^JF*Xy zeRhQddbGMAZnW=@{iC;)|CkqLed0ln#?^RZ6gljh1NBASQHN-vKkvvs**`q=ZE`M$ zZ8+dFe23ykG^_7-Bu?T-*&nKpl0!MjVG_^>`amC82ljz$^?^~@FXtqbb5!0v&&a;I zvTt-$_S|)^_0i*GA86licDLTx=Vx7%`1Z=rxZ(vl9Ge4mM%|&*XLfhqk$tjncYg zDt!Ru9K`tu&0W_W;ef)aD;&|S{lz+HkB4~C+sc2;i}v-23*DNB^C!V_ki#T^4@S+a z^Zeg~$!_kCy)TW*GhN}Nh7TM%r)RI3=jz(I_0LIs8v6Smi5KnrVZT?;yZeuqePA7&r4NisJ@@ku=c2sp2m!cs?fgdNiLPt;rqA2g@9`y?^+(p}>-YH9+PCv0 zhjNg^B=D#YM$Nl_{=chC{pQ{CjqI=YC$2|j&s`toder;+e(znw>rw6V9hKACad$58 z#HZ-(Ab-S*vY)=swK+aI-(KQ)G+ytE@#P?gNkAXy1ASl}?5z)sN?oFydpHN7xyx~h z0Gv=bc7-$gsvmeB?duQ+dfVua`BCB^F7(xX`dktx2RTdvYx!W*obAWIL!*AtynCLJ zeRZW@bsd$xcU_DB*7NkZ?_Kx(-@EP{`*nYw^|#*l(dLIs=hb=M4)RCbeLw6I-6~Ja ze^0ks-+6Dp{>ecOlYlLnj>?Q(@A<6X-{!M-iD zOal5qALs+?z&`NXJ}@fR{oKKMBkww{MF6f{JO5ExaY_6AeZD-s{@B;)arAhtx8y($ za+n16>Vr`;x*z`zt=DzK#4~$B^qMR%G zxg&QuZbhK;CJ&ElfBsu>j>^jDQR=`rlQ%hBn*(**`wsmjbR6N)wR2nRy03HZdaoJk zad$rW@9KRB4k(=9x7YkW8W;OO+26Cu^Gn*};l92OoUiUX_aDc|K@O9EKF|mHz&cp! z1EW$O{XD@rBkwwXiU8bS)veo%noT2deNMGDq zACG9?cXm#Eo{UP|=-%pM>v-5V3KtY^p>+I_{k*G>lIZKe72aFt*ZGqvImlrW&jR@wwmHom2g%cV&j;|7cBYfeGp515eFV2yJ93}yMpbzwcb?|5(7?pbA{D5+< z$h(eLCx9PNe1eV&p+|k^ee#+F^ufM;Fe>p;=O}$3?>b80Jp%X%#b@ZK%#WV6Z?Hd< z{lf(f4aav0z!T0W{Lkt$_Z8>JK@O9EKF|mHz&d!e4~$B^pqv{xPoTNW@u~#y0g6vh z{DVH~Kktj9Ixjaccs6?x1J?+!+<3>=R}G=+@k?IzN2jj*beE-VeQ&%Os!= z^npIG4(tQh>I0*)UzGC#%6S6K-HvA`K)zA@fZ`X_z7a>rK@O9^S$!~S?(WC$XY>R5 zMBa6jz`6wR7k)!WWgYaWbw~Ut`(xi|cI&tm0XU=NfxMtc^_g+UIdYK0B%lxUfj+Pf z-t7aUQb#D~29)yzn!6p(N`O3*e-wY9@A}T?;~+W6VG`K84@S)>{qHzK!SPcB_&h@S zJVHk$5_Io%M0~`HvLBTFW_OOCA^>;tfRZQjrzRtEki#UP5A=aPunw-;2S%m-QO*r0 z=L$4;JD!CAc}2-Pen78UAMQI&m&3I=&qJ4$~dUgAgD zADUe`eu@CxQSw5*(4+XwIO7~S$YB!D2l_xCSO;76fl;Y1l=B11xdP4Ijz=Xx9#Qg) z;)AXH=Dcx^9ON(w?A-^WW|aPSoT1?OX##vsq5X4eR3h4I9T6W&{OkwKE*!r_fIN^N zl)RyP^_g+SIdYK0B%lxUfj+PfKGg?CrQT4^4=CpgGbj7 z$YB!Ln-50KsQm9ZL&5P|1djH(H7cY~K4($(le-+hO@Mr$LIEW7=el$@#?u7t(LCG6RUeRy+%=P0OImlrW&kI-N8 zuA>CDC4k>he29+9`roP_)<=npc+o`ZxK{$?2_=sx`9;6wH`k4WePA8z zr4NisJ))c+P|g=w04y z)<=mCO;nCYBS8L8@{5xHu3P)g`Qs!x$YB!D2l_xCSOSETjR5)W+I_$^ zKIyuaADt%-lY<;40ezqk^nrD-_dYNxb&7Ic;9QY+9k(U`Z}^iBbniYgzBohho|^_Q(7v>!RPG;HsY{K)$=;i>{**Vb{I)ed9~s zePA8D+XqIajyNZ9j>xNyTN8jc{6}TQck}A=a-0P8fj;>AJ{T1q^c(t5 zUUihfcM0G}{E3cATx%)wvL2dM9Ir|MA9TepU6=gm=WZNyb`DGVU;Fj5b98^#s2B5W zo+p8`_+ZrBjsG4Y6h1$4PUBoQDlxpOXYr-`h!5l-he_aFAB>u__}_1ag5zEZ@Og;x zxww_G&R%&K*LMlvkFHC89F=&N^xZ!0^WnP}4&)g>aE&g-$@@IFq};cpOY{5s?bkm! z$YB!D2l`+OAB+lD`ZwobM^VqNN@!)>^(tXA2OUmrJ4!$T5|F^71n8ejx^ylZl@+?~<@3WhlAq3@=ZpOEdcS|^n)`Wv$v^#d?(fQc zOS%+?uit+ClY<;40ezqk9`V7baO!=Sew}w6_ey{~y{bL$&t8uTnOD_56@GG%!z8el z4@S+|{M{@R93>zD34ETw(z$HuoHZ&jc3tap!Fj^>T@K`jJaUabIzRU_4}Q5V{PBKQ zo?lYd>H27#-j{^PK@O9EKF|k~z^FO?{QvJ6{W=wv63_?N@WH6;lm1E{&Z~|R_$>ka@v7ppS9Mh4 zc~$Le;U|Z4ap?8X>#NsmcJC+w2}nQ!-y+caGS|I-b3H1NE~%gE;j=b}&U+~z&#ue7 z%t!vSi`Pfy>B>4wN<3Yk-Iw<#cXE)!B%lw@<%3b#4@y6!-{xIM39Lf^U%jgM^Hm*{ zeJtr!`rFd}dHpIJ&azMPhW7gC^>*`50uqpb1a?WF_iL_uU+>qWvYoDH`JDUqKH$2< z{nhyTyyQFCTyJFFCGGp-n)sIV)qVS1aw`WpOal7gSUwn)c9{v5L>$7q?+P->zdOmx--29V(1SBAVLlNkGykGae&-JKmvn!u- z{q?o4S?B25xh(O0b)U@7yyW-xp+DB^N<2$S++APg;B!g19ON(w=!1RxU{vCxKlc8a zcO4~gOak4{{Tkno%Kp%!_bv9(mHob|eZGEubZ$q9zjN>T>^{HwCjkjaKmw;C(EB{s z{qun9QQ3Z1-d{`m{73m*?Q!;fbUwV_pL_P2d6=I(-oEt5`b$cjUD?NyKFh`XV*okG zVG_^>`|`o4#6usXU*=Uu37nGvKF9aysOeTuldvahb}|55GF_v^my()H1}?k(QV zwdbMd^X8ufBp?9^T!KLF|6KRaiKT1qe^vXuqk_Hb-ac2C;vw$7FRpoi>G?-rXCCH- z|7~Y~#MPC!mz4c=eUy*)#Rzhc!z7>&zUzZgSs$hE(HHZsqXf=L0H34ye^mC1?zK-5 zUsv|gm3?;2ZkNY?f4}bQEM50F`}JNq?B@eW^i_^N7o*5Q4wHaB z*v1E=GH>r|^uN68D1mbm!0){dMrGf7=|9BNwa3jh`|6rqy+8JOm#&FtN&9}5uJ@9M zPsh=DbdH_-`rq(){q*N+UynFY;_S-%{rOj~nXj({ zKlFBxKjQ7$_t&rC(DhZWJ{QBtK@O9EK3K;GqcRWutM|FQ>nMS96X?FD9!6!~=%@P* z>vko+u6-X|XBVFzS$|1;{7ct;|NZ*YdHK|OeV?6A=lb~!yP^anAOQ(TV3|PwoZ`BF zo{h>JT|f1C%Q~#z&*7d=t%!ksS=wEr)Q3BT@fd5hIVpKSwYxN`M>&m)a ziK}a(JI~nn*RMO5rR&bMU$2$NwdU#Z^?h{?=gGJ`k$?mwAb~Ry;B%{go{h?G(X~ED zpPh&G(H`f$_@7Unu*A!=wDXFUF9A93}yMu#OK#WghwxO25jx zjuN;g0qTIdKu3kgt9^*)yE1=Q;^>+vt~YiLOV^!azwZ2(u3ydbv(NSQd%S(0*UP*+ zmVg8#Ab}$i;PZ>mwNcpx`t0ZB+V>L&@u9?x@;djUYsb^)V;$B92boL&!l6lYl;0#|NV_4}FO~h2~vH30#u^b%0VQqrwBd*N?cbEAw?_y{=i+@g9NB ztzUQEOV>SL{rXmsK4l zAOQ(TKmx}iz~>pCbE6Xfz0b+5-e-N3xKQFnd7b;wt>RmnmvvF%LWvi>9sG}dus`;F zkI&Nkz8*u!K@O9^Rz4UtXWwrAt>V5n@2I(}pTF1Br}D0&1SBvCP#0+b93M6B`cY4# z=GE=SeO;NSYo2oa7J;6Re%v_$HFx*p_cQtvns*%~Ac4P6fckh<|NdP5 z@AD9N)elS0orjD&k$?mwAOQ*d_;>t|{{FG{_oz|H0!kcc|2*b(l;_rtYpwZ+4<+ut zuiL@?di?B*eWGh|beKmrnwfCMBU0SQPz0`C*xdj{V- zMrF=dzt1c^$Gj-(btRr9<$mT_T5oT!6EDg>(7xZ>LH>H&?1z1#d&`IM#9(qbCkN_| zdPI5s-Mljo^FFFPcTXRUk9qp~^rf4B5|DrdBp?9^NI(J-kbneMBEa_yzJH9$#OR~n zW4Mp!mXvi+*6*4qe*W)Ed5-y6_b5u-DEmQ|IKX4CO5E%NWuHs=x%d9kbG{xY$UzR1 z06rKsuYUgbSdZ2t^W4)>bCsX}{TY3rE9>9WQFGQG@sFBUKVK8ysQK=XIQqJI*HHoz zkbndvAOQ(TKmrnw!21OFzR|zejLO_7-&asxU(!Bbzh+%DtNlFkKF{~{i05e9_rd;9 z_Kp5bW?!!mC(1thK980si_n4e_Y>Fp1-H8*Olj3 zhxJtnNI(J-kbndvAOQ(TKmuzK;QI#3_YibcR$5Z-TTmA}Hew6(!aliNe(sRC^{LA5*9H<+VdP93Xa^G5hVZOfJ?ZH3dyQj>5 zPnqYz<-JV;5|DrdBp?9^NI(J-kigRf_}+ou`<~L@=eZ?)HlRKa>y64xYkmLQ%RKB0 zWxt(6cE8`T$ICw07rGbj#t|>c;g}q#C+ZBnSBGomyRXl>q51yEe9!9pD?5V(Bp?9^ zNI(J-kbndvAc5Z}@a*@Le*f>!{`kAh%lAQaROVRg``_N?VSnrwg$Ei6`yGjs_)+$^ z#Qom;OV9awydZ~baG*|5>WjMT%KO~EmQR?E`C0eop9CZz0SQPz0uqpb1SB8<34DYA z-^2J`HY&@aYkmLQ+dS+KW&bE#&`{amNPH;qvoCaS{Ea7GlEXeZP&X)bg;H;c{^$Su zD?GPWewlA+ed16hAOQ(TKmrnwfCMBU0SQQ88v=X}n-zYp#IH94mpOLsw;zrrm)$;0o<54+0#(_GaZcyq9&1^qLUgv)1 zS&KXKF+c15h`|3P0SQPz0uqpb1SB8<2}nQ!TN2=V7~jiAWwo`w_Z@8>_K(5^g;yx; zZzMjHxY-Zd^Ro1Mzt8LBTn^{rfd5hIhB`vC>z_y7=Q-wC%O}jo{H%xm9Fea`Kmrnw zfCMBU0SQPz0uqqGngsa%#rLvNnSHJAeMg-K4k&!!g@)GtM&cuGl>HnvFUB3O$zdH1 z)B{SLpwv-TTOPTO=a_G;JTV{hqpZ6eneRwI0uqpb1SB8<2}nQ!5|F?e1o-~N_pwo# zb*=AxN1q2C@Im2*hT48c;zEg={h&QRORx9)yiTs=a7+&P9Hl-`>ITg&mq+g7dFEZq zAIyic4(l#Q<~tIQfCMBU0SQPz0uqpb1SGHq0lt6neQZ=_Mc4ZNchq^{fWird9~yf5 z8HtN{QTB7xycl;pCWqHJ;D71?rC!j?et+bC=3)M|^TWKX!@Bn)^bQF~KmrnwfCMBU z0SQPz0up$K0N=m(K8B9UtmxX`1CKTz98fr+a707z`y=t7#LGU=o{y#1`+Z&~$8tCZ z2YiiE57Y;m-8??>9P=^%TE1XDlyzA5@kqT>0uqpb1SB8<2}nQ!5|DrdULnBuFO=_P z=%~z!uJwKJsPn)9g%b)#H1xhd5)W~r?Bl5UFz$Fu4!_RPbf z?~lZT5-0JaJs(T2_xrp~j^(f~4)_?`o@ZXxd)E)lgEBwsq0dL`6B3Ys z1SB8<2}nQ!5|DrdB=8OazK@}NUqeS_cJ$rvhev-N4k(=9hlbkcN7hG)uPgDRN6(A# z$7@&T(0$G|^?<%xnasod@758|qs)u4-n()8yaXg50SQPz0uqpb1SB8<3A{&u?`J6A z+t5*&|LWh***`qsgTfCDwe3dM=}J5(@pffDYH}opV{_-xJSvKO9gvq3}aPZ@rOu zQP%BBeCWG*SZkhlyEK8KDd*2(+{yrSg&a3kbz58Q- zuFuOg>!N4p?f&8&IsBFb{{NQtd@RL5-J-qDvnxjlNI(J-kbndvAOQ(TKmrmt3W5H; zj_-TusO$vo-yg4b4F?oXC_F>$=aKij@;u7?UBAtnc)lHn>&IJi_$&wf-<7)U+Uq>g zI!ZtS5|DrdBp?9^NI(J-kibz1^zV87d*G<-488jIb~vE$>KsGucI&Tme^=&1ug=;1 z$3b$~7YFJS?RDJiJ<&T#KmrnwfCMBU0SQPz0uqqGSqSv+ef@jksO;45^WgxG&Z%?c zy5Gn1UF93Ta*)F$uvZ_9n$g{Eqvm+K_4=mn(cI-I0SQPz0uqpb1SB8<2}nQ!XCc7% zJ(TZ-qq0MEuitAw6&D;(INek3M?V$s*6W;YKU?#1{@bsAN9Ta=(O&=bQ8c@Dlz;>z zAOQ(TKmrnwfCMBUfwK_c`(FP(I4V0tkN*Al-T2{v-s8o6@2>0fw_pF{Acsld+dddI zqwwFOg@U65Bp?9^NI(J-kbndvAc5-;;P*51-tR)+{{H&y^+&}UOZx5jTtE4dgB&J- zt$Z+Q&hGDMq2MS12}nQ!5|DrdBp?9^NZ>jI`27s^ceLbw>HGJnypJy3xA)iAj(_d> z_Ri1vQU_P%fZx&HH|eKnXgNwi0uqpb1SB8<2}nQ!5|F^r3Gh7+?cWDSWryfhzc-&{ z-{cWJ%f8%4>QoM&;XwVMy>HS_(M07a0SQPz0uqpb1SB8<2}nQ!M<>AdJhXow9F-mV z{rs35$X{3UdCYv8w|(TT*HiDC^iwoZJ4!$T5|DrdBp?9^NI(J-kigLi@I4RZ`{1bT z4E6hacXXRCSFj??*Wzy8VLH4gY3rOr_LDVkLrB_II_NI(J-kbndv zAOQ(T;OGSSp2zn;bX0bR`h7b*_QrwypyY2!xv%Tq_GLV`U;pH=PY%6)dcDzC(d@!e z0uqqGG6DL98b)%E!z7>&^npIG4(tQl_JPdq_$Yzy$NoKVRAxf`J|7<6=0HBsp0|5> z<$j*;`tAL>{_WR4IqaK5uN&$L?RA*lI7&bQS0K>q|IusuhZ>j2K@O9EKF|mHz&fxG ztlJ0rxg@hYK1!hT>;4>-nNYvihsUQmz#r{->Umtc?$2?}yy#l{TYJ8>;&PtbuYYoQ zj|2WjsVB78VODdLfCP?2px5!E*YtsBbyVo6a+n14fj-a&)`5M%KCng~=;sm6GokDF zECKkTo$sj3i2A)dJhtWlZ?xxye4&Zz=aKij_W4++>(={p{^U#!$K=rKrPo!jyX?|Y z0uuNJfnJY~UiZ3w^mji!z7>&^npIG4(tQ3^?^}&4(0sP&p)}#@mT_$ zBYaV~>)(*wiUXWc_@g~fiRSUKKhL~fSs&eMzs{T7$>G=>s1vl;Q?I-1)=>fyc!xl* zt4FVUeLi|UD$zcx_V;j;gB&ISeV`BYfpuUX_-r2-mG%00hjUZjb$pco98oxr%8aPK z50AAtz!il%N&+4eT>hu47ko`8?ePA8f2lm|uMkPL!^HM)&nuDTpxD1mDb!1rjc3$90n$Fpi*4L3Q+ zVG_^>`amC82lfH`z$7qgjz5(17UwZEcR9XF0FEe}(NUQhwLZgRi36NaIHGVyGu!t@ z;y{VBEBis0_W$VXYt8fMdfpe0$zdA~_!*^ssH?2%D1mDb!1vSvIx73`YF`Q$ImlrW z&;w zaG(yT50p9z1xE>-lK?(P@&Bmo*FGqRNkAXy1ASl}*az$b_JQsDz^M2Pzs9N^OxjwpQ5%(kDAxVjQQ+V{zI=knL;r>O5mIX@HxImM`geE897V>`amD(1M9#(U>~p#e6A0Sir+Ywp`6?DuH#w+;0kAS zR8~OkgW<8n0Zu3!Q8;(atos>ze8k_CeWFWTd_B39!?`%%d+MUsO?K-jfpZbS=lFh9 z_J`W%!b1*nm<05JKF|l&fqlR}@QFS!Dx6WyX`I{8+~xQ#0eGVDM#%$e9|-X!4sb%@ z*cIMrX5G(7TwVJ<*k{)zKE9qD%i-7@@O!TZ>Lt5#l)yO%;A<4$kIMe+XL6VX^npIm z2iAdoz&>Cf_+B3v75{NgLpi_YUB|Tuz!ilzIw~un_Q&v8;sB?v@I>K_X4d_U#D@}p z*S_B+KKEW{o_qKCe!L=w&vL+@D0M)6BpOEvoPz+q#^>m$?9cuqhe<#m=mULV9oPr# z1NMRM^?_0GAIf=+a~ztx9M>WMR}}6j`9STHA%Bkpyij>%cx>ANXb;7#04U z+fdGPXzp@civV0vxTB-85^A3ak9!>8g~GEd+|kUwzmfRRz7MY1Z`XUgd_Ost!#+9S zXMB!Q4~g1Q0>>nPk5T+RD*Lf7$zc-E2l_xCSO@k2`+$95KYd_S{D^XXLpj&wF2}VA zz!!x(N?uU=XEJb)1H8Jz6@@#R+4naRUsv|gweR~Lul_#I_t(9SH{|dc4)_qo=hQ)> zaFoC?3E*RVjgHEG>@#wh1oVME&+H&GkKAzMq`SVILguExyL@XrgqKz_AG6Uwl0( z@uT*i@Q{NXCINk*5A=a`U>~p#?6D7wN?th6p`7#buH#k&;Eck*>!?J~)xHugOB_0{ z&XsHUqnUNTBXOeaqif$k*Gs&7Jvo=dcRAqG?q~d-=o}?*3;wDn1EbDJT!MXZbbmjUCBpR@`c)OlbIzBaO&E*cK(@lzhjS= z>%K3p`~JCJ;>PQb-pBoFJR^tKIN&!F|Kjh=>L`I@5Wu(i7#)@P?GtjC1oVME&^ME2X~IKT~sC)&AlomKWb5@%QT)s_8s z)lbQ>9KOo|U*g;D>qO@$fqfIexA=He;zjK<;UNb(Oal5qALs+?z&>CfI6@y7l{}%G z^EmgRxy$j>1mKU7AM%CTZ<3iuIlv8tYgf3VS!Mqt@pkR|;~EZ+>Z6>!FJ6(ua~$v? z{zUO}W^Cfun!!!4~&X`Ip?9A|Ipm!_-O+0 zCokxzM1tCf!{bp7aO(ZXXyG|Dv4tP|kz7%kk3$;E$3Ql)Tx8lbKgJ zz!8Nn3jeNI^*CdX|K2tGhs&#ceJ&o6!($xq8~*D)%`A=**cSnOif>0HKGgaT4>`zT z63_?wKp$8K_5u6Ak^8`?AX{5mS}S@&|71oVME&YSDe`G)G6ArKP^tpIK4v%rb zZzw**mzl*;0{b9UmqA1U!$A@IUl0A%kk3$ z;E$3Yl)Rz#>160#4)8?bjgpV9S^an;`(S_U`(2JcA1}z^F%I|+AL2_ivp7oNy9Dqf zJ{^^KQ0qNBePA8f2kZl9>;t2cSI&bd=fu40_$>nD0VO}^s6>X^r^4f1 z4)8?b-IctcS^YR8akDS>`z}A9j|b%N7zccZ4^jM?SsW$s9Rm0e#h;@Rk997GNkAXy z1ASl}*az$b_JQ;Ffl=`}%DIqpBAUA#zeRvNpyUZ9f2jRCnR=H4JiEdjB`;`J-~ULw z?1O#2%gyJLdpSJD0pFqc5r1YDM+tm~06xT*=%~bFoy%bo&ZuMkUWE=R}nAWA1YN zHUaX1k|&frcD0`+bMJEKT;bl8{GeHVKO=DwH~V^*kIyH^a(Ipd{=<(bKFw^768H=O ze23!4QCZ*mmct~V5A=aPunz14_5u6Ab^E}m_#frG$oUb?U5?)-Kt53N)s=jr_W5M) zT@LW<+WC_oG^>AqBp%{rAMbMU`Q%m(&vC$iD89s}naxoGpCN$n@F6-X>s#M)m<05J zKF|l&fqlR}U>~p#j7lAFUPL)h=3U3V5FjsI$s0N<5u^6|@K}ojTv52AJwIG0iqDU% zPkh9^77yo1PUY|%2YiSx@hO_w93`+V0sMv!M`bjye{N)5;v(*M_wVz`p&VZ0 zfDiE{ieEFUqXf1gfX`6;H!AB{*K(Ky^npIm2iAdoz&>Cfun+V;Fe-Jy`4Qz@nRgxc zN`O3};UaP@H%{+_Ov)c9}>k$ueKD$rvPp;&!4hMXQ;!pgVRU9R- z4FP;v`z`+$9*_kmHV3zTyt=SwtqIqsDJdFo0&QSyv- zKX{!CzsdowDBRJWAFi|N`XlqRK5@OeKc7pE`amC82lfH`fPLWSJ}@f2;5>;v|JdwpP3>ICIniE`e|U5-Z~K;BUDiIVTG_x$4falkzeoh#SyN68PG+20?T zk9Ao8UfjMP_Hx*k1AavDDZb6>juKdh0KUR!=%~zZy~|+|&6+P}ADM@BSodC>z8}_d z_zVYpiBIt@nkXD4@E!sDgwIB0KGb>-4>`zT63_?wKp$8K_5u5Vec~p#*au$i1EW$uDCbSipJ?uKJSqY5h>~ZN z{C9oTS3Vb~z@c;H8vZExK{Lz!k^7m4`B`5LLpgkx1HMG@EB;M%juLo{06xN3=%~zR z{mWqz&o1=VPdLC8 z?fl74*Ua+s$bHPiysW2&nH=`P0e|9G{EH?^M+rPf0RP~tQF$J<{=-8Ka+n14fj-a& z)`5M%K42esy$_6ve^Ab!oJY~z<#==gyvbX1<-oBxf+yi5Z6Kp*G>>%cx>AFvM`zYmOxk5SH{DCgAN<#;v% z`amC82lfH`fPG;7J}@f2LOGXmPDOK<<$8kOg)GdWBG`amD(1M9#(U>~p#*atq< z2S%mdIG3WFSJB+%cs2s$w<|tCM`h>er~G-9b>RA}UWJeQO#K~=1AeBD&}Xt6M+rPe z0N>!FQF-oJJzD)3Z}Kb$IZOijKp*G>>%cx>AJ{`57?nJroKI2Ct!VCcJSze6jN$_n zpLDgK#SwCl!z6HZAB>t5Znsf$yxr&@^p(8oD1pZa;2V7Otd7b$@9Nd-+Wp5za*)F$ zpbzwcKClk#1J~{Yqq2XrpHDfz<}Syx6CmGc_XF4X1+|aF8FG-rByd$9jGDXu@w*xQ zf_{>B9VPG>0ethU;=6ZsRN{PBui6jXcl;v>%cy6u0Aj-`$0K(_H%3Q zay&bMo_DVC1&Uu#`$C){2RTdvSMkB9x!dJ`cSirnU5*mih5$Z$SNVKePA8f2aeGPMkUUEZtUmL+~s%`0zLoTAEQD7wcf)+4sw_T&hCRz zbC>?Rvruq6DuMnv_v&^3e0=qKR7k$7XYW7mFFuij93}yMpbzwcbzmR(Y#$hv_0WFq z>*vYb?RXUeJ^$Sw_@=9M9EZq34wJxHd@yS6#(#Gf3XWGN&_5qvz3!i@uU?NzM&8x4 z^egufKgdB2lYlzO*I{?Slzlz;?2L4dk@SE*+;S(AetCINk* z5A=a`u-85?D)ou_y(~Pw&4GM$-}G}@qIJ9~f$oRy7kt$9+x~X_I93jFm;~$xYv8`a+H7sBp?9^NI(J-kbnf% zB+$>@oX1CH74+G2zW0aU+8oFSO1@C?nbjSyP5?i2#V;s+Lf7`K^TmmBki#VKst-oZ zr~P+lq2MS12}nQ!5|DrdBp`wB5a9bY->1=0i3ff4-0ySYxE2TUfs!xsh-Ots34{Q? zK=BPaD)*sl`PF&CRSt5P1fKQ5sQHxt?kp4>B_II_NI(J-kbndv@Ld9YpGNsUjgCru z=(Fd4?+?GVIgk(Xgpx-zt2;^{1n>olZ_rV>uj|_Wb-r+xgB&J-B_E8M@A~h~Lcvi2 z5|DrdBp?9^NI(MnAi(!&l<(8%sKmK+&iD1t@*y86c|yq}n&=!Q5CZrD#W!6?<$lyU z4-YxWVG`KN2czcf{=2hKaFl=qBp?9^NI(J-kib3(@O>KP`}C;9i*EJ3!Fj{^Q4Zt- zC0{6c%&d+Q_$>ka(G~xoqw*a3s6V|g+~gpKN#Ic*jGA}*@6JNOQ34W>fCMBU0SQPz z0{bSw_i4UAqoWcx`snuo?+drBIFJvNe33^qQ8-HAj}yQrC_X|*<+-j~`PzBITMpOY z(Cdo2qaM-FaFl=qBp?9^NI(J-kbngCK!9^P$~hh#l_*ia--XAwIgk(Xgpx-z(K<@t zj}yQrC_d^sD$k?e_P^^VA96S*2kNNT8FiRlIZEIh1n{+*e9A!%lYl%Dg8;tnejk+9y91WrJp`x?KG%I45d*P-i$zZ~Q+3FrfTpbxBr-UmjdF77Fx>-V&u2bQk0 z>hZ_Ezs{#~?fkut2R_Y#y!3qae7@??KF`v1Uw`SEc<<>FN1p5R6W6Qz^ts;>fag|9 z{>Ue~ly_fGe&q1`9PrUS-I^oo<8zdH$}Suwa1H|a8lR)1vcIkC&H3d#3FrfTpbxAA z`@p(=U{vP2r+n_;Q_c(bG^-wG?EC2)IzN4y+6dDE{io`(4-K*XL#Z?*E&A5;y^Y?rZ!$ zDw{*ssxRjWS2@UG63_?wKp$8K-|hpWQiu1H^T9ps=ZdB4th&Fk$J_S{r*G%Y_2V7# zf%bg$eD>>p|I#({-_x!0!umZ<_I2}bR|LpQ&lh>z+Aq!@JDiOJ{z1FHmVC#3JlFMA zPRzsnC~@5Ulfa1x;A?!2j>;xqts|e4-z1<9^npIG4(tQR?gOI||2^gWa8EgRENNEz z{@CMVU!8;gPOiSqq34BsJ*xfrrR%-!v->q!ar_p6o)3K3ef4cWxqcjS6b{`#_zLa5 z>(|`Zwa?4-JucjbGH+k^=AQ&kK%n~?zmLl1(0g^``{5-AIZOijKp*G>>)>jAU{vb< zo^sAu(ta+t6TO<09_9PyCAB{QC+4`1kyfx1LY0 zlO{R*aSr$f?Y_cqXlD5_@_N@k57(^IwdaTTc@AZr9})P!ByfBJ_!^(1qq4VNA70C4 z63_?wKp$8K_5u6AGksuGcr7XC50vu>ny0@v5(i40Xy2Fhkz9R?L(fOQ{#IOTuiN*9 zA5r|8Y&d?J0Q|{E&)3?1aK2>tY#h38@Dqy9&_{jF{au;2YmcK}bAO-j(RjR10(&OV zeU0BoC2I6+{m1`amC8 z2lfH`z&HEAsPIQQub`Y~(A@p`k@ZpHLx~@?u971;Y|8<^;X@RkW_8E43BVWLDEZL$ zAufmCa=;%bzCrO7nx`ElAb~9jP;V&pI4Y~6_OtMigB&ISeV`BYfpuUX_--EaEw~sLXC3lfxvS5A=aPunz14_JKY2fl+bh&hXdgAuES)z!&!vAKg=YcTcmrqXZ=IdjxtNQGcWI z6ly;U4>`zT63_?wKp$8K_JMu&fl-MIR)O5CVEOOE8Q4F`ON;zJal zW_8C`3BVDqDBSgT$jad{4*2Gt;$ZQjuJR0f$o3mW>ofz+Q-5}4sw_T^npIm2iAdo;23>iRN_QA z=b-%@l)FDa_BeQ|h2=cI_yEeG}-u#qXmM zH)`zT63_?wKp$8K_JL#ffl-Mc<@|&8^HJ{p{Mh3lKH^68V{#*hZ8+dF{D7Kaofk_FbU`beV`Al1N(q| z;Ea7>RPu`U^AP7GGePA8f2hQ0CMrB_p=OUEz5}La| zH?l5DTqtp)`ZT$b!@3;s7rsOBC7M+o;eo;nj;KD3SLARF4)~sWK&cZnG#n+c4+8iS zzoMfOpZ!Y?lYl z>%cy6tv)a+`$ah~p`4@8-2J(cby4CXUR2*ECvsSq1O7tsAAUr$>UBprzz1HazKl2I za7_->0ZN@vH)!ZMO5i&L@FD(0M^OFSs?qSkYAB8PQ3;4gfK;>)ady^;N+aDkUTj3?wEhe=@69B()31f_oRuA>CD zC4k?S6km=?9H@OPJmesUNkAXy1ASl}*az$blfbAs{!q?QXg_b|?(N6EF7cqF5(BEA z!$S`1aKKk6zU#isYS$UrKRi%4>A!eE4sw_TM$PeuQZLjIn!6k&@E8Gn^Q_{(B^{OZ z?O$@31oVME&6L5BQ+^FJ6#?93}yLFlt`;@6bZQu@j)LKCATMXLVE}SWwe5?=O5WO9N?ngl6yJG zVG`&*7&Tw@-=T%V`A7QXvr1omR!4>Dv)X;?bvVjF4wHaB&@$pCfbk z_G4eS$3?uT^^u&&;XMxc3GKeams#b!Bl~3k@IduhaxVutOak2pqvoqW|2s75iTcW2 zj$09c^Rr5xp4Cy=$+O!1<8?U7K@O9EKF|mHz&fxG*a!C52Sz0?Xg@dh^Jnhfe(dY^ zxQG|EzLFC;yvG4Qq4=)*F{_+!WS{ICg$Jt7l6yJGVG`&*7&Tx0`FAwx3(Z}Q_Xxo2 zS*3qHtD_Rpv)X;&bvVjF4wHaB&J)o<~D9ON(wbRUeGuP*=hoO##r9)YEP)ce!Y^{A}y ztoD3*9gcF4!z7>&^npIG4(tQ=0sFv@|M&7y@k2k4a*joF*Y+dpp~N*RYope2c*x;B z4)_VhZ}<<*D(4&7AIknwxS;wi9*~0^CINgfYF_>LT%~@fD>QdGE)jqe{6^)@XO+CD z;U@<Cfun)Z72S&w5DCbs`^DLUXw;x%LI8fq5?E}e$9Ny!ApYR!q z4>S9DNA`)be-u8bev236Acsi+AB>t;{yVf#cz*2tXH@2ZuPTp8Kp*G>ePA8f2kZm( z0sFwW`@pEwA|*(VAI6i%qVix=b|he=@69GCwc z8g-Ss93cP~`V2ZMcUWI?m<05JKF|l&fqlR}U>~p#?5z)sN?oFyV^PkzXzt!_WF3?^ zh!5QxN8^bnj=}*Sq4*5Nf7#XfNA`=t0fiHKlsp?}yeo%oI8YBL^@37QS=|u=a6#b( zNBtU7a*)F$pbzwcKClk#1NH&?!2bHcsQ41)Jd1M9MRWIdBkQm}N_?pOBsq}7YaH+q ziqG&Ln%U1kvR@P)D4bAz7f;CH+8n3{lzO3#&`@%O09@b&Kh(MkDLKet63_?wKp$8K z_5u5VePDlmU{rjGa;`-=@8+)UM%F=DA0gRsT1l44IM{# zpzwm9brg@tK@O9EKF|mHz&fxG*az$b`|ksz;#1DGDCb=?cWpPa4oV!OvLO^ItnQ{$YB!D2l_xC zSO@k2`+$95zkOg-{E2eDMLGAPxqG{jbyy!IKGeRF9LV804)_PfU-%Bqtk)aaKMEfd zZm9l?N91rV4)`CXKByZsR2<;}Clr3xPdp+AIZOijKp*G>>%cx>AFvPXzYmOxPf^ad zDCb`^cdtJ(Kg#+j@uBvYo|34k(=9XWhgba*)F$pbzwcKClk#1NH&?z;XJ(sQ4A-oQrb)MRWK1BlDxIj}jkh zpGgkn@E8YtgW@X`-(|Mzj&MNXgTfEhfANYOuE7D{qtpdT-GqiCJm3R2)VhgBePA8f2kZm(f#dXnQSmFvc^BmzjOOn3N9IRaA08 zg%b)tR3FAOa<~Que2-EW)C(FK*B#*i9~5rZOS~ZmIZOijKp*G>>%cx>AFvM`uMdoh zZ&A*>DCc1`cdtJ(Kg#;Vh1zGrUJlQ3z(4p3pJf(D2*3q}7YavIABLP9uE7D{Qx7Qh z5(?KH;ef&iZq`Y>AqP230{TE7=mYD(K42fP4;;4-jEa9z&b=t-VKjHIKQce-qQr&T zZ^B*CfIBp*p75}1~e^JiGXzpHbWL}hYQQ|`FH(@V_-{*i|@DcvXQ;tgn z;Do{tg)6ELLsAas=78U+1C%<+?yoz-0WK)qtdDp@4sw_T^npIm2iAdoz&>CfIDQ`( z6(6IVe^JiIXzpHbWL}hYQR1@Sgt;94I0t-!;vamKryTDQfENl!6uzi_3{g3plLJ0S zsRQZ*&F-%^vVRml@UkxA2|37N63_?wKp$8K_5u5Vec(KOU{w5!at=m0AEUW@y^(oQ z)+HX)z7yth_$>$gfp1X!l)D`tB>*=Ro+!Lg{TQ-xI41{uj{i~W1I_NQH?n`Yzzel5 z;t4s(VG_^>`amC82lfH`fPLURePC4ljB*}EIVb0?^+)DsJ(PG*`%c(jodbSA@e4je zL(B150`NoOi^3hfx*y$t9CkJi_#4IlDD{!uUvFgp@Ic{pHb1zZcw7#0m<05JKF|l& zfqlR}U>~^MM#Tpx=V8vtXzp5XWL}hYQQ|?Z*Ra1D2l9{N4;24|j^n!o;EBQ+B@gJ; z{OEq;u(NZ(-zfg4F3`}p&d9z|xWMV`zHoo>x*X&%3FrfTpbxAA`+$Am%6(u|^3Qn~ z<(!P>uJuOdMOhaem9?zTYjGg&D1Jck3mQ6(YY~7e3U`#epw?%|%i&xc@Hf6ksf+CP zdL#RX2b|P+VQUWdnQ)ea93}yMpbzwcbzmQ`4}7B!j0$&@b1}+!8O`16jm(R(F7cq& zN0^_T1Np`WDE>f0!*MGDa7M`kN}kZO`_lczX;YFe>8wc`>;sbnv zX7`StA^>-kyrAR@J)1AxPn>pD4)_|sqtrv_TxVq8YI43c2mFTO$E(((`;PDAAcsjn zALs*pU>(>8_R$AMB@UEx8`{r{x%>UG&&zr!@u2!8%#Y52e4^wV#TVJF_CQ5?F@-zC!UEIx6d+)@yjkK@O9EKF|mHz&fxG*ayDZ2S$ZI%J~iDe23=l_ebVK zS&ukS>m#i9&VhWP~p#*a!C02S&w@DCakn^BtPIUmuwVWgV0_Q2Rw#f13mOK*<+MKG8(& zcvJ%95hc$kK0v?iPuGvrUM+vM;0DqzQZ&cPnt?TfRgB&ISeV`BY zfpuUXun+8^4~$A4P|k5E=Q}iazdkY#$~q`ePA8f2kZlT=mVpY2b6Oh=Q}ia zy+1M^>!7TUS|4G(H3xX3)ZtYX&kMrcP4hMXTpYeHSca*@k z1n?V*57ALsAGPkoLk@D71oVME&DHH!trVZ$UlldQ2c|g?NjHAKp*G>ePA8f2kZm(f&KJ>QSl?n`3>cKhvx3rN9I9U2PF>sL>RBl0lx4?$p`v+ zhJEr(1n>ijUr_vnuI*Rni<{)|7zccKPw_9l&g_m7_$&eZhvLgoi37F%!$S^om<05J zKF|l&fqlR}u!lY{DtSOT$Dy3>(A@p{$UG?Pus&*igz>u^;EBQ;{%BTnl)!HZ;13l4 zprdj>`mSGnK0J@k0Y7|N@#Q_m&!O!of$tE&huyEE5)XRxeqj8`ryS%k3FrfTpbxAA z`@lK+z^Lp4?dLhpd1&r_ePo`#4(p@(D~zAz06(;IhJR*vl)z%OX`)2KX;KI>QS z55KKAke5$u_sOTO@##Gcbw>$&hd}pdua8lQ3*D+eIBz)1K@O9EKF|mHz&fxG*ax2J z1EazV?dQ3E-pk$3kA0rL4(p@(IE?RcfEU`icJ7(gQ38(<=>F;c8kKp_dw#v@`|$a+ z_I!Qny8Gr+*Kwnx1olm!*F&$%QHdYDYTtC<@qrxVFbU`beV`Al1N*?f`oO5fgZA@W zKkw!4=f^%zUx)QkeGjV$c5a`#?)m%F zbzI>n0SWvu0=*7~p#+-{@d1GJy#`gt#RKR@<) z`Z}y{U50Jv03Q^7ook+Ul)yR!y1(!pIx6d+-M4$YChkvb=lH4XWXDkg64(=gUjOu? zQHc`WTmLkkgGX48?!wsH}_bwSI~JTN+A^5|DrdZa4Z6eH0xPI_O^esc|Jwa*)F$pbzwc zKClk#1J~>Wqq1+5^Bl@~56#`rk37%3DC??W3J3V0@I!OAqXf1kfZtI3h>pto=-xg@ z5}l(2Bp`wB6QGZx^igzFVnp}WPmL$}k%Js20ezqk^nrC?AGmfO7?u5_oaa!^duZ-{ zeB?QldDSpn;s7u7apK-7f%ORBKeYRGRMtZG@_CY|93>zD3G9aeeH1-PKix}TH;#B& z4sw_T^npIm2iAdo;JbZbRMtoPxsLN*?s|UYc{S`F3y$%7o^FbU`beV`Al1N(q|;P?8# zsPN%?G1||2xyw-k61Wn9-UsLp=>OZEx!p)^LqYV*iQE7j!;Qr;IFxn122nm(K-l(n zt3|RO=ZA&SNThgfu|&>PhX%U(dy~;^B_II_ygmW)l>9`i^X};C9Cf_#mxCMz0ezqk z^nvTZ954s|F9)i_2W3Bpvfo2bsLsZ6zQ93A{c5@)IRL z(dx_rU6rGb6Yg@5!yup!^npHb9hd{=z&$xo9Zo3wIh6e#n!9Z!Ac1cp!1_nY2edjg z(AnRgjAknV2}t052#}vB`H5C%F6itWwg2#zgB%6{eV`BYf$P8=Fb5vVf$H!=+0UWu z_t4yJD**|769LvgNO8i;cu)><7zFfzKF|lQ19RXzbD%o&M%mY)?Dx>zZ7Tr@d=mlIKT1BJ)uDl2^*u?i zwi1wl1m2&(>ioPahwUfclY<-v0ezqk^nvTZ954q4f$GuzRL;dH`@XZ9-tTYEj^lG- z{B0cWcb0cPL*VEu@&T<*@94ANm-J>U0SQRp{Rynj&u8=3=i@m!$YBuB2l_xCxDLz# zbKqAwP#rEP=i;-N!o_~o{<{LKska7T|mtInwC+3!tyv6X-X zB=9)|$W3%sexA);pNrSzAcsLfALs*p;5sk|%z=AypgNq+D*Hk9hw1HS%k`u3+)>ZI zhtGxir*Xg^_$RZpT}=S~D0M-PzI*ihvwA*`CjkjaU=;y!6D2p%>bwd1XnuNs_{l*I zgMdEJ2l~KuU=ElAub2bXsSEo*_Jy~U`;JOKN7eV?`>h=C1Af6*p<=s>0ChmA4@%w8 zd;Pm>K8`B^2}ocS0df;1H___633_jSdSAH7K@Nj}KF|mHz;$2_m;O*BtN*zT%vbyKP^E0Ck~G z)a_AUzsh`k4+%&>0;>p+pC~zsR_9I7M|0Kt!%q%!7zFfzKF|lQ19QL}*qH;>;m5;$6eUm5>bx2HXuf)X z_{l*IgMdEJ2l~KuU=ElAJ93~p+;6GA3?Dh1bxQPXwG_n_{l*IgMdEJ2l~KuU=ElAD|4VayixrZ9&)&b1HR(i zz0+xG;h5>{Nx~qK|mkq1AX8+ zFbB*5bHE&U_Z+CsI_A8mH- z5|F^F6CiI~rBL2RRG^`amD(1J{8$U=ElA=D@q;Ky}tD=L60SxoW$M z0Ck`)Xm#G`tiN{6$8jYf0SUYd0rD3mf6?m91U;L_J{OL1ki#IL5A=aPa2=Qf=72e1 z4!n8}RA-%XF5tY7tG2rcPzUN#oi{j8>-y^lUEsTsX=> z4ugO`&iIaH1SBAVPa!}qqvSJMotdJ~=C#j0NI(LgMu40~$!WAYGoGc-eg}L$^^t=d1_6Db z5A=cSz#K3K%mH)Y-W;gTdSTzsc_3G9R}+9g^{CDpp!e4G)_v*CRss@`fCQc;KwhKd z_AIT=8}HUz-xsf^K5~%5AfONQfj)2@m;>g3Iq-QoP#s^h-{%~VtG25Nz@K_l=MApP z-_`SRJPAlZ0-sKR+@7U;4|Z#HD!E&)`X1U(>L~{~39OS_ft z;cl%?J$LI>`vLn&J>?*WK|mkq1AX8+FbB+mdvc&UoY43YCmE>siz#|FbL=aeV`9q2j;+g@l=+);n`wL$=$YBsT`k;DTo&SHFdvl(BTHeZbHUW4a>r*`XYw)GcvlV~M)}yay{haFAt|CAkXZvS&|E$AV`M9cHjw1mH zNI(J-kbndvAOQ(T;L`})I+s>wrnAm*_In>+>M&bZ{oMe+&DPMh{S*TD1)t7d54-!H zm5-m|2j?LH2}nQ!5|DrdBp?9^NMJPq&ZX$B^XaVf+_&^woywk7>M~pL!E6l;TM67p c06*gY>OA)?`SJWb|M}xT(m($G@z13kMJ)5m!Xyn1G-J85R!65weXDNcf=5cHjsCPL_7&<@?}DxDzDq z09@=2o*C5pcXxHw7|(dCsz3ev@L&G!U;o!BzhC^rKl$@N{Zf2PB4{^B?O>6hR8z2Ey6|L<>pUz^{Ze*WbT{_>ywuYdgy zei_dH{m=OaRStuIKF|mHz;&?IKG1sB7rNCvjvLN$ki#IL5A=aPa2>c0xDU7wxDU7w zxDVW6A86e=-=WU#XZl>9`(5Kc;6C6!;6C6!;6C6!;6Cu|KG6De>*v|`o{iJ@o~x7G zsoe z{N4H6zr2rfpMI{VaFc@^1_6Db5A=cSzAQVPT>Kr0^7my`o};{v zzB@k0o4)?!AcsLfALs*p;5u+0a363Va363Va3A>9eW3O5;P10%m2uwXFUCWOtNwkN z=%=aPr$5R#?~2cHLS7DX7zFfzKF|lQ1NQ;<0rvs-0rvs-fnVJRS`QDDzsu_1ZA;g@ z$2jlu8RIcNN<4}F$Cl?P?=c?wt~ebhHIRcG1_6Db5A=cSz;8<>`D&Ki+FSeP8t#61AU+mTnFw0?gQ=v?gQ=v_uL0sPu~39h4Ob^fcwC`_JP)uFUsFr{2hj- z*K$jL#$nvGzT!QU@lfVjj_B9-U>ub3QRYY2=3)QvmxCMz0ezqk^nvTZeZYOdeZYOd zec)dEKszGTi#=w*7NS8zM??a*)Fy zpbzwcK5!kl54aDw54aDw58PuPXgztN{9VQ0TWESMxAaFDkMSS%75#Z1W!z6I^P|Lv zKAM;PrmsIa$YBuB2l_xCxDMP0+y~qT+y~qTuDuVmp8WVb3gz#)Je_apSCw(l)-%SO zpLkxC_m8SI-m6{D)yw+`p<;9%s3(^{938diwg4gB%6{eV`BYf$PA1zkc0xDU7w?6(iJ9{+tx>-YQC*Y)p*wbyg;&GB+Si=UP_RDN@u zYrQi1_HCWF##iHC%Gc+qnH=OW23p>U)S&Jt*=A#I4$|Yxz^eJFSXi=L*-2!s!}I(YX>n8TH_(^t++Vu zw!V|EdscRj>UkYL zbNuT4Iga&yeedqql~29KhikQde{Ov}`P-BL^}`4F^OGHSfDGgeM%}f-do+AIdmaSMr_HId0tN zJ94c~C;6?->(%}z!Sc6Zk}rN}J&&%wZqAY)^{7g{Q0j=LitlR~7iC_w#&;IJ#u<;u zK@Nj}KF|mHV83*)2THojT>|DuXPAi9c4YxU+ z4*HvmckTVk4=*=;BnOTVO%LWbwa5hN?p_Y z{Vn68%!?8iYTZ%;ImlrU&yL+Ud}1!>zrnk`L@2tJgw&)^e+1m`J(VZ zE3Z)c*4F1-^FGS>XXQ%#b4s3b3YR(kM)doCn(M#z{#;yZ@6YAG_Wr9rU_RonJie!R z+$-WH5Au4IkMF1ETXUdZD0QT+Xrg(4%lIhsqr|l}2ggrseQ>;W(0Y7{ za!zu7&S~CyzGYnILy6<+`vrNTY2l=o4_N3X_}yyg@Ra|*X5oqK=n{kb^T z-ru{9#9Q-+<8+cA@sbC5?akNuW1vSlP&ev`QeSi{TQWY%{KSPmnveZbDLKet5YPwu zKp&ic9kd=Fb3US+n|b>Fmhn;MZ9Q|LSKDXE3ngz99%yL%*zz3ZeU$Oht8rY)hrH($ zPHS~;ytVh2;y?QHnlBvj<8+cA@e)6I9i6}N#b9utZYcFcsdL`iu4NwPMTrX~ZZ)-# zgB%6{eV`BY!S&Wb>+v*&_!6BC{v%G}C!e#|<*xBlKa{#sXLKuDGCs=uC~={8t&@4jfpU<; zAfONQ!Igc`dg{wLh;mNm>Gm!2p~TU8=0?xD9*G|%Ka{-DWIf-~kM~i=N6*U3xKsPH zaKLZ)5XGm-=D00!5;ysrg}-seTa^QKq^>CSMz?Y%+vnh`Nz44rq}0M<|Q7KIMK80JH(5U4@$o1wD6-J$~cUVo`sKbrr>AifbURz ziBFT|aa-afZt^&LUG5$~bwsHzO5L}1Ci9@oj}jkx_qv&X94QAm3T0{yLz6~6Q$179o^c6%!3jKN_WXsCasHv{ zwO>mdC~;OL4|MN!OB`s8mweD^;YUBTj>kOc-uXL!3VK%#_^|pE|Ax--TH+&a^0;dq zubMY?rOqhzN4It;^Pt2*eCSo{U|w;U9ON(v=mULlMIW@Dx^ljuoO^kCoR+w%5;xj< zVy^nBbzJ8qF0{s33)p43bZKh2@~62Ic-ymh>m_=uN0taEC06%N!D zrQRq$NY>l8%*XsF@u64YZyxcK9ON(v=mULlMIW@Dx}uzGoOft?9k(S;lsu}EC%V-F!gaRjH7e_?t(JB?mbS0{TE7T*(Kmr=FZ+DCbXo}8+_y1wgp z%!k&v62)@MdyIqD`Cg6R_frcwY{LP+;$IYhXV&Ai#6_Gac~m{CZ)zS(*OkLr^PY>F z{K*r=59qYiE7N#1)&w>Z!8^g1nhRjv8Ao}8=B?FY4A9k0%p(U;r$ULBWt=i>5y7|Y?99Plr`u6|F{ z$7ySPToZp)@~iqTKh|-Vu4{Zt*W@>+_5C{kyYk$7oSGMT!)5yLk9kqzL5cTKZuFm1 z#zpD(==k=VzW(GOhe1Fe=z}}?p!L)nzQ?%e^x%*F zXdRdNP~uSoSPtjlfPbsM@qMy5ZcCh1Yd&0)Z`JD8`h4k{@gLP1@6z>Dezkv{x5iuZ zJL@%hkuMwyo{wEJKT2H0iNc%fIpzH&<$cCgr>{Rb$YBuB2l_xCd|L;t#}D;f;oQp8 z`?Ta;weo2_Osdv?b)3Al+}8K%xOHClwJ?>#IXP56<9F6UvN}&o+*Qe|YR$i1*Zxb_ zb>5}xSIO4#YkcH$_Vq~~D0!0qs~lf_pE!sMCElt$pHs%GN`J;XdtHq`&Xa>21_6Db z58mm6*25F!{HW(jdfm6JJm9pX^}R<4*7xc>)C+ZA2w6E?g9EV;BAl=`AaUC+da561AVZi4_Xgjl=A}R96{6Db}IsKMyUfzo!l2v0Xf`*1HNY+ zus+aGusu2f>V;BIlsX@ET@xSiqU3`fy$r7o!ZLdeVE9vtvJ>j7oGgo5o^2v9eadQxZfDC?VeP~s(i zbh_z}{89M83q49bjUz^tgB%6{eV`Ba@ImY0j&g3GoF`~{+dfMGjwqZ_>VUd0gtQ#) z#R31LtPj>rXxN^O0QIAuD0N2nTJOw{5+6$ZlfSP7-~k^LetXr?d1FvH$YBuB2m0Vh zK4?AlKsh&1&J{GhZ6757Hx#ZY+)?+3kd?!|Ij|mBC#)YdbZpN;fV!d76{X(jr`JF8 z5)Vqe=vjDg9Va|cc)=09Xh^8@8vLDSoIi2%Idh{73l zUkFJ#$YBs@eYDfWdO=xFd1`w$0@M$su4wDY=u`Uu^P$8+d}yMwtpwl$Hx!=er|RiE zsgNAxFbL=aeQ;zSw4VB)oF6FX3!2`xl>mHD_`wx*KL|NF$YBt`2d$5*AOG%TJ>{wG zSqV@_^waxe>mi3SKT2HbWjjXzPAL3P_@bkudsYI}k^K>EJsF{M{&@C2<1!ygJZPe@ zT_ON46rL!&t3F#l-%Ca0AcsLfALxTC_@MRF5#{_qIbYJt79Q|H;fK0E#4B=;!yqu{ zgVx8>Z+~yHo>*sjYI{}!)Dfk=XzR%go%6|~_ZbIe9_B|gtL<6>@I&ES75-Hpt)u-? z89B&d5YPwu;7UGdJ@rI6KR8$N)D|A_ffwq&5Rb?~4uimw4_Y6+{Lj^f!gX8rO_co; zZ9Ta!`DN}o@1u;1GH+(FeU$(_tHQe~b*Va6Pw%Hfa*)FypbzxH6@Acp>dJY+d6K)f z@PJS2Vd8!uhe1FeJm-Vf^B(Jpb(XufS0O-MQR>}#GDO#|Bi>^?lzGt1V*73a@U2Q6 zs#342YwK?RR8kId7zFfzJ~)#PT2H+=A2>g9*A^b|X+2El)b$@ea*)FyP<_z)xa+^) z42Ao&bsv3nKW#mX=9F<5AI)2~pCSPFs??|ITs`Z4;dLtbE)H|txz9XYuT|bxr>{Rb z$YBuB2k}AcQO*O-i`=z^2YlwV^{{$Y^<((S;hG%kx~S`jb(ZXHuSS6SqP707UNi31 zxScg0>QQyB&aEfYs-6eo@-7aQFV}T^?$6b$-lu=nI$*>H-Fm3Z=~4E*qs8$oFW!Sc z^+^?`iR-HLpHs%IdNgjvlS<1$4uim}K4^W6;(w1S6h7D1{dw*6+&=#3{nnG~v-+y< zd_VlJ%AxwI`m*{xG;AdxfjbkZ`vTW>|ESlkhg#LE?yqa}s$95U8i#)HrXJJGkLPpB zI8~WvPM6~Jc?u#2ISc|v^+D?+x^MqplYM~wB2R6PLV&tFtJL>dZ9OEa9@XD-an<fs#eo?RM{=#+Z8LR5tzP0u~Z5V+ z9$eu+t^Dy`RmPoD=CAr_{Ps(s^3?Y11ZrK^UO##s?Cs~d z`CCr~tJb{g^SSG}dG30@a;jXb-zI+&kbnf9BvAJguIs+Tb?cdED?Qr2U-PUS9*viA zcpuK8`FzVbbIN>GiDyn9&C7nNogCya2z<&1t&iD${ChKZZSPLt(et47kouHwm*yd! zs`dO@dtJw?*Gq9-?Rm|=@~r-u{7FCp5_mI#y3cT3_oH`Tx1L0*?!C_w5BYM9J{lkW z83(TD^yVMqR%QM zs&nU4&130$ZXE8{dFQT|@;J-$njaj{%5(B30SQRpLj>yn^X_Z*xvH%v!K$Cy*Xz8* z$NjZ&@E+r!mFKk4ug+7iiKi-Y&*@qY_D_N3AcsLR;oo`BpyjWPKt52}s~v z1nU0Ab=?QKZaw*-TkYG7k1{{X{k8M+9?Ezq`J>Z^e#}>uxaO2Rs;=c?{}fsdau@`b ze9-#n_3iJ?x^DB-Rsugwp!$XVz4i1*mwfo>bH=O6yj5#_TqnBMTgF?`8dtrp`OIBE z%4w^9HLjXRCxOY&~&T-Fkm!{;I_B?EJis*6}Nc>BGM|f4#2p zk_SBMHTTsNQVwz$1fKOl>*MVo|K7}9TM0ZyfPH;wKVR$9)-!+AIuF;xQ8lA{zO8Z8 zYvNwgnt#1s%XMx4I$w>q=Jk2f&L{y1NMIiV?0N&GcGuTwBN$YBt8)d#JQQT*?1hJx*@1lY&Xx}Ue68J2uYzp9K^ zmHDb>w&S)n-nr|VZ@sRZ=B}5x&pof>)%k1O$0crL5|Drdwjsbi$o|-R=0WH7*H`Z| zKFa)6d5*q1FYhxRTIYq!bdVqM5GQey4?1_B=V}Tn2RRG^OFn3Q^!oPiHCcbG$2_%_ zz&Zl>2S1^$XPoLw?pNi#s*GPXqhF`3`PJ*nW$wCit=F|4T-Sbe{2I@7$eW1-Bp`ux z1lSMRCtJ_^?5A5P^Du8!o}*jG!92tP7j)YBM;ydQyjyW`+!S06_vXMlW8JY1(a^D# zz&Zl>2gP5lXPh~uUscAbn$hmpRt|I5m1Di0t3$nC->dW8uL5Q)0SQRpdjjl>?3bs9r{4EEwUfiX9Ois`w7L){>yC98dbSdH zjR1baUymy9Redd*`@CJb)$2#=Q2W(!?nBf}B_II_{CWcHkL;VRr~kXZ`xqBxzB#4e zyW^M}kNMCV7o5=P!$0P&aS`uaUfxfku~ZXfj1Dq zPtWQbLU4#*A@FP+>U+O3r2i-Z2}nQ!e?x$MlJBY3gJtP^?9u0phcXX3H$VL!o#$Qs zm=`5Zlz7qULqFz2iHA7R%3)4$pDGm({OpdDd|lZ%*mIq%{uuGcM~6o%~5a0uqpb1SB8<2|PrA?AEA?5HM4)_jT^63(H z#z7g6^?-7JNf~EOd7p77e-e;@1SB8<2}nQ!s|fHNh4OvXdWKn2`p+rj&MEIP&(ini zUeAdSCGMKn^r2s!mw1Q|-HVs=#t3)ifd5eZiE{s0KD^I(bv-Oy^WLM%c#}T~NI(J- zkbndvAc3a{@ICeD_gC%5`*T`@q95b5o*vJBe}3vc;v{aAe9&aGean2rff8rsGIziB z^E$PY!#WQ53&oFBdHyV4-e+9a!L;zB-?O?fypJUy0SQPz0uqpb1ZD_4`~6kln;HIZ zZ`b~OFSed8&whV?>OJB_i65=`C9Cb)Iv;TmANnai&XZc-l>>gmhbTVfntso6;(f+r z{Lr_RfCMBU0SQPz0us0@0lo|QPDEP|k!Qa@Km8u@qU3>+Cz|ZGYng}nQR1t7=I+;i zUZ-Yq`1Ks{6N>-vCCYvJJWCu2M7A>_vc>k z5jRR+DEXqv_Wdp6qs&iS=w6(hH#NT+2YiL%I}|^n+^7GuJb0h+7=Q970SQPz0uqpb z1SD{40(=+po!EMCJp0{wl=sL3B|ntBlkIjb^Dr+;T$R_{{o2p#)JzWHfNxNIhT_Aj zJm7iC_Q zxQ@chI8ytga=^8G zH?|%c=(FFWM|qDtQ1V2{A5HeJw~SYnd5NcTn!8{7d7TK`)hqif0S`h;s`Zc2}nQ!5|DrdBp?9^gaF@(DBq80 z>*CklsTz1-5jD&wKdSM}9=d_Oh1DhK@YZpDX7+~|kaII8bc4O;F>RIlSN6oWx zn7gj;F<#ZP@G#El>+dccs!!{6^>UB^*fXA&(cO1??ef^z{1O7p)|LcB`ENvwq0SQPz0uqpb1SIep0lqWq z_h;)F7d_keb&Z!i(5vTL^Y=P_zB>o}kJfd-et?FWtpp?>0SQPz0uqpb1fCeZ=-I#5$zx8>o}cl@uX6bH9IF58x@SK?Gn%agBp?9^NI(J-kbnf9BfxhhTE9PA z&$#H>zvr)#2X(kwKIEll-EGAI-=KBfvmc;|##RCnkbndvAOQ(TKmyMZ;JXs7-=D2# zTy(4N;Jc0sSM;tN%scDsQylOcTGu`M0h;J+B_II_NI(J-kbndv@EifYE7AJ>*?PwP z)c5e!=YeO{tLJTg$680#e|6onAE1feRss?j1Xvep{2&K8xGvlm+y}PV2Qun)+UgU& zKU+_ZsDC$v$65~XL+AMNeC_!3fAxLFQKzrJt8>6FD85ANz7Q(561WzD>hnjhStn}z zAO|@N0{TE7=!4hS0q0QMbiJ1R>VDCBaz(HH9saKT;DuJM^_qTF-xZJJOkaO;_?|=c zTlFRT0-CpNC2&jv_;jsS-#>cYdN`D#3J{it{c{uh)_vTJvu`Iiv0?-}8V==(iEFLiWxbnc{2>Q93bUdR?!rd6GX07xb>{l>AZnpq1k^^Q--Mzbf;fcja#0G168X@E2Nrh+h+htppw; zfN!dw9=&co^Q_ga)`{b$9&(VwAfONQfj)SC9kd?*)bo&Y6HTw{wd99Z4y`BWyX`aN zjaDx3LPKe}rGM2rKJ!++TOG_dp4y5-^%p*@{!A3M68LEX)i3y{_4Hq>Tlw8_Qx7@F zVGz&<`amCiZXL89zoDFyDCcN;UAHAql>Fg>UVVQePZSO)e9-B|ALF3RQ*TK8@f!4FGP|i)x zQ8c}-+ma{wqi{jr&42Il$O|QJ6fRY#H~s3kTr)pPd{y`6=ln6kSvgcc;WvDk>})0Q z(**DdzG*%E(6g=!<4zsrAcsLfALs*p@V<4>di=z>iE^Ii>2+K3M9Cj*J-MS-+keOl zCGV>6K||$zE#snfey)iVy;?oYC!YEg2YiIT@E@9JY$Xr^_yWZ@t>^iteCs^&9t8A( zKF|lQgR|@dt!KTWoS&ShXnI|@B~KI%D16Yf)c4Ui$*U^)qwqneH~$#7D)XZ?POjJH z`)GgrrO;R7fN$^>ivNH`J!+@TMq;DUHp$W4*8+vkHV*F=)AA3<1>F%;zWEqjA75D89mXiP}~I zA%HLNN$a_f9?jpzllsU(4ugO`&xMe28+Ma=xPJb^VrnQFx$mLa(}yksnI_ zRpEqAZ~ifE)fxwJR=sL{%qvEFl>>gkPt|9c#rCcQsvqzPzIoMuz8`1FK@Nj}KF|mH z;QH&J_4u6g6s_lNdR@P*dBX#3Jq*yR?vvzK6%J_S6*}*4>paX~wZ_Z!Qk@>{w=|B= zQ~RTHpx)I#_$*o2-jx78sQ$n=NB6h!#kq2j!yup!^npIue;u?QAENbq<=joL`?TbZ zRxa>DufCs=Ct7*Hsp|CRUmc(88V}dRi(b7><`=^)alj8Ke!))}#rCcQ@BzNSC+L#D zd>-e>K@Nj}KF|mHz;(br(0bMb$~nuqi>B9oTJlEWg2JmRT(71zPdHSC7rK>W7{6+b zr^e0o)#_tDaoVFC@Bx0QKFVmecOg*gk1z1aqrS3V93uxg3 zhe1Fe=mUN5zID)g{KUD7avtZYEj&;-p{<9}UG^vPMd45tUT7$7*D_Dl8dtq0k2$?d zU9X-e^`-vRC)+vGk&i&2)*Bz-i>v$J{Nh46$YBuB2l_xCd~O}I9>1ZSzx7;BFWbrm zUhqTjvX7B(Rk)y)+w`Gdowr^S-<*=yUFv!DJgH}`H@^6gEuCg30@S(IA75PE|K=Ct z$w3Z-fIiR%`rz~Hp!N8!p2M8aXnNVgqw;D!Y|y*yXXK4mK5(lVYM*QC{Pmi+$>VNy zylTGG6Q$17|8ov>racHyXX=g*(5w31yy7-F$YBuB2l_xC?6(eDkN;54W0Z3`y=>uu z!U=^VdbjubA@9OzdSL#gN(VcDR^lv6WT~X?e53cTa^NXS6 zAcsLfALs*pu>U$}Jw8M^mpP}=^s9EpA6(t<<`-khK@Nj}KF|mH;5h4`_4tu<8Rgv0Q(FkY1%(&d zdU~RF-S5aBg%1k9s-d@i%e=%xoOi9)Rr98vZ+J zsW0`W{^-VbbNG!3P)C$HQ}?U;+x%iMImlrU&tzQPNSUPd1_k;zz2mJ z+IrqV@463?e^of4a707z{Vn4&FLB+qK3C71`ciKcAH3gTj`&Fe)RDTP)cxxIHov${ z4ssX-^npIm2gh9pt;e4z=QZaznqIb*0DMsRp>VBw*L|^afD;PGs+Ie**Nn@2#B61AU+mj=v6Ck54(bQOWEV3yZG8XV?a5`VGz&<`amC?XC1U2zoMMuobPCQ z*)9=)7Ya`l&Q#hz3cu-{%GaIH9XPKn{VmI z`;32A&Uee3dQ*S=fX+L|Cr2PaolxpXUGL^+^NlOzAcsLfALs*paK3fWdVGs=u5-?# z>1F#U0k~C#FA8_`uKOtYSA`Q=c}_Dw`tcs)-j(m&@}}O@AH^3lw(<5s2v8^LhEmtN z`PqD9OgYG55YPwuKp&iU9kd?*a;~GC`*~{nECD#8@I_nC$mreoQ#hb-Lg8376sL*% z^kgL*NzRSt3( z1oVME&Kbl^)&k}$m3g@b=X9o1H`z-lat-Rog@|^eX%I~guQ+IrT zFD8G7CP1C28+E*^kIg%Fm4h4x0ezqk^uhVpLF@4`%6X6S9gtqOuM&V~Rd}P+1HJox z3kMWVb4tIvbGuvq)E!^2&L)3{CP1C28+E*!f6X^Gm4h4x0ezqk^uhJkLF@4~%DK;X z0GeL5?;-$K6z(YXK<~c)!r@W9JFmOtk1tq1tgFf2p$SkY>P8)x^ltt(-`H3Vau@{k zfj-a&=UoS_$G@EWDBlBUdfC2<09;YHqpfGAs_wVpA_qAP0961AU+mTnC@p2U^d1L+iQEcLAE-w(lYUSG4lyn);xh@`v-J z(sDQ!2i5_~I$<3pTHB)%piWClU0+pv@~XNI#8GmP!yup!^npHb9jx64TF<&c>-o-i zL3-J~n*e;P);drhbZwpOpUTPM+#K+KT_3EUWM_L;0@U$Ut^RoS8o#}&?mKa$9ON(v z=mUMA5AM4TT95xx&gXjWrZ!n3abjAr{O0+l~?sY>0@rF#236_mri9PlfOudDA9rL6=c zAOQ(TKmro@JORE-_)bAvPb{e4mEp0(0bX!K;f!W9+fNaIdsXU#Qa^O5-abzS<**M2 ze2RZje4eOmB_II_NI(J-kidQf_%1>DUO`(=Y^dLr;W5VnPAD8vIHMWO_R|F5k5V6$ z`k{06_I@fShtG1rmngo)&uF5um4E~!AOQ(TKmz*{;QIvS`vq-1G5THk7zcQva75vp z(QNl3Kpjx(gHpe$u7gxe4*PJxkN6bD$BD}J?ga3I8Yjp>4ugO`&0ifxJkoRZta*|@TKT+sJ?9_q$2UjiK;5^BkMU9bSN$1Ews$2^{eVyK4Z4+29XHOC zgB%6{eV`9s@j>h1x1{XzOIpu|x$DgO`L@PW^QjzMU#Za?hsvw+gm-;rd@^#&%21^{^g~GFPuGjQiQpR1< zr8s$B$6@{&-*oX`&G*@B_*Jg(R%4{2a;SBqo@jl}_1b)R4`ux7yUE|J2~=wv5YPwu;7mSfJ@r~r&Wk0j=S;oMZ0~F9_{3N9ab1S_5(l`!@loZyC0&|- z?Q`aNPvr*BwRNz6Fn^i@^+Ibs=dS5rbt!)O*KzUF&@G6H|FY1U=->N*XTF2v>IJri7zm7loyETF82YiBW zP<*AvE^?5=AfONQfj*dD2d&2+bIN&x*7GQDzuwkynGdb;xvs-}jzi_e^<4kG?-L*O zMyoH9^?lpQ15WVUyN=EuZ_aU`PAK(5Ykf1?w}0PMpYvW-#;;oYF&^`%_a=ZJs!#CI zoUgqf-^f7@gMdEJ2m0Xgb%7F{dJgNWaGH!yup! z^ueA!Xg&N<&LOm(Q|bMBTgPQS;y_&=VSN=2)D@-f)ep(~K5fk(E^tDx;)AQ?L0wSl zhSs`HPyXsSk6u4Hov&St0Di%jXzNMzD(lfatmh!05A=aPIPN-VJ^n;Fk5JAlG`(MM z8IO5T;y~R$!ul#4s4MkG@k6q`PfOl#K;d+ix?d#^>Vi@)lzJ}deH?D4dl0Dp!=LyT zy~?^YkGM<@au@{kfj&604_Z%sP|hcm^DDhxZy66|9+Wsx*H4(AodfkmsW(1AlkN3e z@`VFj(6iV3D)Cc~Ii-F}O1+nK@+W~82;i^k$JR6GRo10>SkFN~ALs*paK3fWdVGs= zUU7b*>GgWccqsFs#NmDt)>q*`U8ysQ4_Fgxl{#NN59+m~)OSho!;&7` z-A1<;f$AIlR{eSPb!mQapd92d2!@mU=EJ^b6v&}a*)Fypbzwc zKG=U9v>qR#_59*oL(}{9mhtL*#DTg`g!S1uP|sR#e1Im~^S9)Kk~bXCv)9%5!9`c4dom|Ip5Iqe!gWK zlzC9%K-~|*`m7wNBTAi7e2^^9-;xjcq2zzoIvRJp`ECyQVoC84iq8_2?bQiTZ|aZY zn|J%t@!}{s$YBuB2l_xCyl)+}9zUU+XDH_#n%>X1jDs={N*t)`J*>~lfjXkpnfjy2 z^1Lm1kRSP?XRV)c$CIDtfNxNIh0oALXL~gQ)EA}x_yPU2FP$$=lY<-v0ezqk^uhXd z(0Y7>a=xLQduVz;-!cx$JScIvp2PU;9H=MtMXCSuPTKcP;z!Age9vAt-@;qz3j5{9On*%;V@fW^B6Rqu82~fwX)SLRFd;8M) z<1{(QVGz&<`amB%zYbcDe^Aanw4RIU{d~)KjE^!u>bef&vvQ!0)EA}x$?iNYagzu6 zp=Yg=amRy4;eem;8H)cBt?f|=P?xnzU8_?6qxjJ{;xswPVGz&<`amDNz7ATCkI;G! z*7G#I*SB??IuG-suJ15D8wcu#Qs-L#WOw|QxXFXO&Q=%Wjn|IK0bil`4gaCZ!uH(+ z;Ja3-(^{p@RgdaVmBsjH;9)!$m^_iG4A;1s2uPYenasg`q@=*zS-ckR^h!?soPpTst=7To|l6h z1_6Db5A?zN*Fo#?69H<{keNpP4?2g+KCvlU{+3I1u z@z~Kh;4c*4q4+V`+@~e)wFgI8Z;7I#YKv*&VMXKH?@1^lbGo-gxZj9Pk&4|L`N4Y_8Li*POy( zt-^7w9^EI#7w^kK4ugO`&sQXD6pN#|cqpm3R zPgcikiH~?u@iHGHxxf+*7LXILw@A_Zk~=8ugF0T zgMdEJ2l~KuaI}4(^{h*j?*f$X1vI_ax4h4|DD$F6<6}Ij^&AK4hEiARjb@bNwZw-K zKT2Nc90%{GwsLrk1AapB8$Luc+Id^@AV2a&^-F3i2RRG^`amD(1J}XT_kq^4&QZP( zP`(?`^nSeMJ(O`#=0&g0`)c`7H|mK}Z}f4;e6}a?p~R1pA9}U=nNR%oX%6@apP~2= zO?2mLiJ!bs^8Pe$=ZlBrAcsLfALs*p;5yiAA80-659Rv+<@*6m@5fu-Lm3xkUUV-G z&YPM(%7J>J)DxxN8TGg=aiYYJk{|jgAN!@|a`>JDK0@&siVySF`C8&f$%}mTLux7q zISc~&Kp*G>*TLQPf!4F`QN9yUz8}!^e!S&9lyOn!y&Lzl=S$sC>Pel^$DOiIPvS($ z10_H7>~%B#_-ro@_z1;k_zz8#=WB_dyvP&Xi@Wp2OLCCIAfONQfj)2@?6nWHp7n?F zy@2u^fu{H4E$^X>%Y5iw`8#iFxt0TUqn;>r&Zx(4i5DdglswV3oa`SD$RQl?5&lB) zUwWOdC4TZj$=CX)rgD(OAfONQfj)2@+;tylJ?kIkdjaKp0!{D7Ti#sf~=-wi0=6KHxbxAaFD4`n`dZw}6%nl5pmUepn#&Kc!AEpemdgOV@0 z#K-5Uy&S&hfPe56itp0l4|$^cAT^bP90mb>pbzwc>)`JDKqR9ON(v=mUMA4_pUF*#}zBdPMntK>5B%ug6>7Lm7{G(4%lLj?{LJ1NEYg z)HQFNw<>O}phYob1XOFk%hqU4VrwNAzrFCK*h zenIgQir*6Td0OHo5As8g!rwUJDLKet5YPwuKp(gcjH-JqL*1xndR?a_FO+;yIH2%R;{iGRGza{G;wOBD=I!IR#7iD1`RRky zP!4h!1oVME&_M-;w?GIVGz&<`amDJ4))#$TF*K} z`JO=e&Op<9xurkKc+7+Do&VkErw%A}LaE<$@gI4j)8iTzAI3^H_-H6Zt2fBDD$9q=l|*a z;f_)ll)9nQO@8Ey!UKgD`sunkUyOJb4)_HBp!h4<9KR)A;z!9(O%2cDOXIX&gMdEJ z2l~Kuu-87&de$GxcLmCK2b$jVE&Wi&L74~LEAP9_3vcRxQYUo2ve$k>{wRD<_@Q_6 zkNL*`OC0bAihuAGn$eEi5+_O?YHCJ((IsE_Jly0Uhe1Fe=mULl-*wP>{Eyb}3cfqg z^qz0&ht~0!2X+4m%Xf2tFG?M#3!2$&;eo;ng(LdzdO2P^cy1K*(d3Qe}hZHZG& zji@6^ozb)V*7#FrImlrU&;?FnkvWxT5ez zsY_YJwzfwnK)q1vh*D?t?EW?WI8qLB7zFfz zKF|l-t%KI%FO+i?<=jQnd%mR~$~cUVx~{|USq^YS;f%r`&1|-F1mJ|i5rs4QY~6e> z6}TD)e1YN{{DdZZ+oKbpUMTfMsq@u*Y(8ym4h4x0ezqk^uhbqLF@4o%K3_N?xN}aW6N`t_ff`2UB_X#!~tF?JmHLH zG}~thz!8Nr3V(E|Zaz;XuFe5Jp!fwJp`l@W76R0bdZN@By}G~6FOHRi90mb>pbzxH z>+7KP_z2~EMLB=dYrdr)%KIqeyKcj9jsu)f_@VI4D7Nn+09O>=DD^<+>gWAbM@{wHTBNbCmZ{#z*hEPRSpI58Tkn-!25;k5V6$x}kUV@mcbwPFpFyz%P@(OAw%*D0Qwr zI?FmR&e&28au@{kfj-a&`>li4<3E)173JJT)BDGk=P2)^jDNTFPTnXyP z&>zWp=ST#o6I$y@ozcDg%=~M$=JTm*cz#+Ze-c$FFETXX`nf-rw5#yuQ!4=vDRy@wP5vc2n_1}6TKtHwaohRJoAcsLf zALs*paQ=1BdVGv>&Z6}kPVaARea?GV*P8b?BL35v3Dmk)AGewoWczxBT2_;HgQ61AU+mKDQ29kKfRG-f|A3>HV$c{@wH&0srYr1gekgdT2e_ zqFbF;nZ;HD68HpxqpbU__7lgAi{v1OK|mkq1AVaHI%qxqL+f{TJ&)7dRsz=~Q2k!l zL+i;KefRm5(QPFlflm_Hd)>c#A91|6M-Flr1oVME&f&is;vYhum=IwJ36=S-?iQyCsme%90mb>pbzxHebzzi@jJ?S%lV6@ zm#qY@O#r{6tOvC92~2}od10<3p*tM&fse&PFZi5%oG2O6$D|oLvl|SnNZ9P2DwdY{owv~VcjzD1R^}cq0 zuzy@32RRG^`amD(gX^q=*5hZC@9IaD^E#tU6W3KA9nXFt`DqT+i#pz2;epnAv>rm} zqvvAYvXy`YjzoZUj=pQXKe{j2FK&>790mb>pbzxHb=N`b@%N+3dCd7-mFHC-9p8TI z>hUZu>O=i9t1SfJg2D@}+?UQt##JRCf#VTioujOCwDrV{F0FT;hnF1WFbL=aeV`9q z2aoOpt!KS({?47tJg0xvN9VI&c)yzi^`K7FF|*lL0`NiMhQf2HPIX+bB_M(05n!F8 ztaG&W#EdSjd!L7w9ON(v=mUMA4_pUJ`#|eiC!D)gd0usCT%U*Qr#Mg_>c@9gqOhGK z04KPi@La0j+_>JCfCP?5fc1{D-qF?*GrF|?eI8zNki#IL5A=aPa2?F;1FdI$%$>J9 zpL^f?;kP#j>O>v+o=SAKa|GZ7H#nk8b)6g6`x21AaS5>QQPw}&dSXYH_5q)VmmK6U z2!NDy=XE$8l>_zTdx`I;L~T1q08Vg&Mi@ z0krkxfIhk}*e~4VAcsLfALs*p;5umCb#R4sKppu`;`=GpwXFo;gTf7tkDiZpT(2b{ zf%6eyA3)g;(AJX^`sn^(zi^X-90mb>pbzwc>%e{B-1|W5iJ$KyzMFE_wi193ywKLu z^U?KC$MsqQ5;!jb_63xE0c}0Gp^xqp_6s*T$YBuB2l_xCxDMP0&bbe?p1Aog;(IA~ zZ7Tuzz^nE2Kp$NPdCOJ;61Wlp_6L-G0&P9nqL1zu_6s*T$YBuB2l_xCxDMP0&b1G; zo_P5l;yWpKZ7Tuzz^nE2SnK;buGbQfz;y_)PoV4|VEDEkK5dU8kC?j!aOKRL)@ z5YPwuKp(gc+y{=i544`R`2OL$D0gik02er+t*6IYe>1Ks0SR260Q(2Z{(-h027Bw; zea!x;n;hgY2j&l7a5zw)-N1SD`L0_-Cw z`^nzgdaAIuuH8rNpSsCG4ugO`&pbzwc>!9uft!G{Ey}|cS?%Kiwg;VQc zQ+YmmEm;XjKmvOaU_aYi*-!V@)>DbS_0jXgeyNun61AU+mj=v6Ck54)8`TodV zTX?_+Z9QzB-RC4L0SQRpt_0Xu_g41vy|wi?L6yTGpbzfhgJ-`VeJ}oy!!bE5?O&X? zod3zf79Q}a9G~^OWF;U02}occ0_^L1E9Z(DAIL!tgTU2&(E7;o`2RlY+3#E5J9d3r zPkdYJ(mLk+O*FRffE)FBbv;Q|0uqpb1nx2mH9TF0JciyM4P9$5EbBkJiKFRex_!))^!q0SQPz0uqpb1okArcP!tL zXzPjU)$d8)|13x9wzcAutrdT6t*O#}E%|ND^IhZPuUFUie#D(w0uqpb1SB8<2}s}* z1o+NH`5tXOv!kzmSNi_PQpc?o-)ya+cik3#)N3nWynEbN*Y$NPYGx9UfCMBU z0SQPz0>4V2e(%=r-dDdX&;EYvq4h3>@779Px7N_HeU0kcGU;c+b{KYT+@UOo8>L31_U;N1*|M{Q&r(gc!FaP+L-~Q&?uYULY z#Baa)2Y>c&Ys%kz`}yg=eft+b`=f9F{r7MG{&#-$yZ`o= zfAtrCvOM+o{@p+Q_SgTjCj8E?e)iA4{lOpn!N2^!|Nr_v{QUIGZ-4aH|NMV{`@NsS z`9J@;{vjF;3xW6`K8O!~JO^XO7xBf9zDU2!xyZT5xkw*KA4nfaA4nf~O&=KZHT$HV z;k*!t58{LPAm<=`AblWxAbsHIePGNw=UtDUck-*cheJ3l1mc7EAU?=BNFPWaNFR8A z9~iTIcusR(i&Hp+!$KfFh!5g}oP+d%^nvt&^npk9fidem(SQ8YJ@xlT?U!|mcQ}N@ zLLfef58{KIgY<#)f%Jj&0exW1IuE|XslS^SEl%MO4hwat_i5(g)H9(gz;Z z2ga=Pw5E^RC+igFa0rKmKztA%#0NPC=>zEl=>zEl=>zEl=>zEl=>zEl=>zEl=>zEl z=>zEl=>zEl=>zEl=>zEl=>zEl=>zEl=>xCp17pT-@!RYCmj0gemh+bLmOhX^kUo$; zkUsG1ePGPGKd0eVoWda-76S1>d=MYx9HbAV52O#I4?L<5j9KT&{~wpGet*<{S*Li1 zLpUr1;)D1gKFB#pA4nfaA9!CM81udUvp@A6{(C>g<=*c!edF}~3Wso52*d~RL41&N zkUo$;kUp^AJ}_qa_gcO8-1q%_chmko?(hA%d*jISRsV1ZhlN0V5Ff+`IS1(j=>zEl zuj>P2mfxuF-E(UGz30_BeLvsfUHd%G-y27sKYhQ#AsiM0@j-kLALJaQ52O#I54^4q zj9Gr`-?{xe*u8n4yY;+!o?6#Fw4ytm+*9*CPj8JU&lTx#2#1A0d=MYR2RR4n1L*_l z1JCaRW0udT?_1xyv}S#M51Z$?ThFWKtw;O5_NRU~pIVRJ8dshx(%}#e3xW6`K8O!; z4$=qG2hsr`Dm?|Jw1l|C9OD zI@CV&(l|4(xQ9bHECk|%_#i&WIY=K!A4nf~d>#UtS zzjyWgtF_0mm-{uo`TObn6%OIB5Qq=rgZLolAblWxU=Mv@%&JrW4qp2n@AKSShj#z_ z``%Q3ThY$1bI$$g`xOr1un>q3;)D1g=OBF`ec+LOV9etAEcLzFzr+2#>slN~@%>tU zokQpKtoy!ikMAhllgH`%6%OIB5Qq=rgZLolAbsGnJ}_p@dzJR@vRB=&<@YH*>G`j5 z@89F)j@!q+Uf;LJ^(pm8p5>`<2#1A0d=MYR2RR2@?E_=h`Fxf3@1$qn_wTev-HUsT z+g9uSs<_s;;6~T#QLemx?CaTw_PAcfBl}b>!yz0N0`Wn75Fg|m?4=KkS?Bdt>U-r? z+P|BgeP1;1AH|82`s~G5?}`&AieFcJ>8%y>Jnj34<6S(mZ&fxN!eJp0AH)Y+@WGf> zhpwOE&z`sYPtPBR{vGk`d*3fx)6+&ST+~6GKE<#1=80EVJSomyueCvc-uiw2d-KZk zRhe)IhlN0V5Fc#W2V+)!*7Vcf6P?3a{^srde9L1^<-ex=yW-jRr*=JRzqS0<{%+qE z&f9LqBi=D9l)d}&UGd{baqWtG(Y}84d|%hT^j#dXZ`Cv$!eJp0AH)Zb@WGhHaZUUC zVC~-XNAsn;=vw~%ZeG`|a_MpQdwH#??}jx!-FU67ckSQT;=cCpolC#BUXSm_^dI(^ zc*G~}t@?2q3;)7@UV9esHkFTk|zoxay>E!pm zj(zs(XYtdXpS;(!&$kZUIu~)SY0t0UcP{<+TkqH6x%Tgm=HK_19}cHCU*Zs#cpuH- z)7Qh5;!V}zRy%l}T9?|FetJEUe>p82!eJp0A8f-1V^$ng|JK*nw4PcY`*YT{58aCo z#7pHvd%mZiE`K+VT8Hk1!&;p3SW|hg>DqJG{(UXJcmG`;^5+YBdedcpaf$QYypFm* zz7%(Lptst=^VIs(zDMPoyvjM@5Dp80_+Vc?7_;Kluc>}szurDt$GUXPT661u5hoQt zl^?CFzW)7yzngCzy7m0;jZdDJ>b?7I^?CX80p*X=n=bo{N1R*bc$Bzs#+|AMz10?; zr`ESGJqpj{QBDbma99Y$2mA8Dm=!P8uk~+Qvu+=)L+xW{$#Us9Famcz=W1K1eR9$NJ?W1+9OYKWjmtq_a;jj>h z58{JY`e4lBtv^%!yMBG#XkGizF>8;m?>Y}X4slX>(29Qje-HOuU-w=4W#6jUyEyOx zU+@v-r&p!W?s*SA0IaaL6M-@_kWhfi5=&2N0hU$0X8^1Jvxr5;|U)sr~6z z_#}?1d^m)|LLffaw-3gw_^JM@FVmX!y3xK=TwTRY@Aac~Xx~pf^wchY@6TC}-WzA0 zFYrg>z#sg>Pqear{%AjOh>PxxySUeM>-qG!)kU4?>CVeK)IL-kTj!Pd$_U{Q4hw`mhv*OfmseW9)zHbyqS8>uYE5@#u`mjG|UE24r-M+^DyXX44m&TKM#rD%U@C*M? z{`zv@}g^g^E>V9*oU6lGa^sy7r;=rbF}Z5 z^HS`>;W7^V!%y9BwaW9yzOQ?6brpA4b?<*aci-1PcQ3w6)p|V+@orVcD}MQ&9(-As z+K-BZ;^lr#Jx|T^eDw7F3Wso52*d}+^ud^w7u65-TUxXBGm4wa>ss|Z?F9Ut_Vsb4 zIY&h>9IoTQKiyw^SF62#w13wgr+ayH_4}pT_d9ogj*RE~{yomE`c|Ccm(RJpZ~fi+ z)V@?aUHyJeJ-1cfiL0Cw4&ks6hz}m)gE4EJ-XHbZ`gOmfJnq#_ps&~Yjag67__cV1 z!)+Y+i1HgB)~fFx#nV;1=d?d}?*363_kDVtxYMopSUgnR@;N>EvJbWYIW@nl=j5{$ z&WWRp6b|9A5Qq;R>w__CJ*p4({#dgzb^|YfMhj3U3#0Ssu!I-r!)d#8mNNaXR zJSbi`()hN#5)O~$z+Zev`LTA(crO7wDbD!Qclq1?;-ccE_i}jE^Wv3<{OG$lXWw!_ zIE2GOAU=4m55}zZseVZHNm{c%ZCa<@qYUpT19c*TMO8A0+?x`oKA)`XSXXX+?YdQN9!piWiNK%M;=7 zTn_xkhx|!v_l)-vz?0%l)qy_C_tvNOr{X*9^b$XnmwcbaHS3mPaKO8(-=n|ID?Gwu zA@D38jJd3SI*qxEr<1-&^-Ef_jyKAW%Abx|In!s=BkLCDaQJl&e8-QJUu$;8M-jl4 z;!V}#Sw6MC{it~8qw;;%I`WX8yy>&}X5Fed4tTGrdC_0z79QcT5O}l?##~nYyzg@F z1M0m%$6TmFFSseB?>x z|0u3mrwp^k0dLyt;O}&8o&5du{R)S0SP0zfgE5y?zP>-5OR9g?to@Jjkslqia-;Wh z&GW@G9PZ=5k9^9%wQ9y^5x^ODsvh)Ke|w%znoK{zv)fJ7ZQ(v~$UQ@d=0baNtXR<==`Xuf@5=Sf`s@Bj`J~@eE!TXIzi)%jm=y=V@^Ae$#u)5aE?=cFJ9sB zTn=N_`rebiU+S+JUqt|Ssvcuj1lOwPsda0$&l%-S@t~b+`b~M`(HuHw_x9=c{qJkP zn-@KOzrrCL76O<0V9aIq=X{Ur`*h4D`>*fvF_*g^?=R(x_50f2{ob|D&;9B96%OIB5IE<9 zF_&4#{~p)(Y487Q_hT+}e*8WkbNTDn-_LQ*@5L(|io=+{S-TJUwPt60H39q|t*_2w ztNV4X-Tz}&o> zwYseR-E&>f?U&zA->-1^3=aK#I8XXwQTV)3{^u00bJ{tt-RInu*N)1e*S-5@&2L2| zV+ec(fwgnc&&%5Vn8j&L*ZRxa{I$QYt+Tbi-y45_9{066`MY^t`+EI;Yy1+=>H8H9 z&*k78^z-68)$SQP0esGB=el;U4(BxIp(?Q#4r}%7KIlHGEHj2c2rLBp`B=N}=c?b2 zxvci}?}Nu&?tZ-Q&-ME;m#2PwZp`Jc=l}cASM{$kmuP;B^VQ;t?8JxM%QcO&HUmR4*TN3_s&N@Kb1|!YYB9YYxlUHQ*}D0Ie%5DcXQ}vS%sGgqJA@2%U_zH54E z9+_7K3WsfT;B)7|IjN{KK8pa(=Tu$JsXCt1oX4u@vp97Ay>4suuBbAGKnOgNz}k6x z^xykAcRyxj)Ad>X$GUyL9*=qF)HPwpG2c5E z6>Y|M5m1M7s&41B*L&?g=d>z*DTg(Vy&k=ewM)hj2!TBl=;zvfKmYE>tZdix(!R4c zudi!g>i4zh``^v?JeB9^!IyQ{)c#$?*|q1B`zlyCY>NZmc3(RO6>Y|?5>Tge+UvV^ z&kyG`=eQivIjwQ+^{J;bhCm1$kw8E1?$`Q*zmHiox?bCFJ#Ss=@AT4j&8OCr*Xc!< z{kn>$t9a?9`DR`fG#p;bflv9k`@EvbxK{$bo@@8&e@^-3oF4rg_xwAzHO_nWQQ{7P z5V)PdT0ii2{bS79gI?Q5Jx3q4t~mO-;-{wZL#7vkVszOE`| zJURjOKBxR~PWkCmwDag3kM5u37Xl%0I|2Pd9~raOy7v3XbJTj&->+S_&$o_ssXR_^ zzQjSrN5xNjez~s#ej0~&`@#N{U-`JIlJV0C@WVOfpHJ1!=hJ?^m_^oqL@2;1|?YT7{`MvAf`sP`WU+F1V2!ucggg^*{z|#nL-+B*^SzCE; zyI)h!b?x)5_b9b~-&a1Tja}lRJ#P8XM{&wJWrVG8P+!Ui?k|nge9xa#^UtYu`1F)3 z1VSJLLLdY};OPXscfE(ltS!6x{ZjS(rQa9V&a*xhmwZkey~IbwP31$c<&ybT_^onK zSM{d;ereq1d!C=V`u$q9PSMO50wE9rArJx~@Js^UyO+MN&F|{@F)Lbn>G#F0^Xy~) z9#=)Py|KqBekw0|E1x`9wSPAUb)@P{{r%E7&G$S%oqoF9->cS(hCm2}KnR3D2t1F# zt?z3QdER%ynDxu0-xc@Hv!DH`xM)SSy-|Er{8WDQUS4^=Jn$+G>PFSItKTn;%Y5tb z4?X1yfe;9R5D0+~_!t7-|Go>xtkf_4uDExe{iryo__|h<+ZlU&;-~VX_j1egRr_ag zP$#O6RK4AscWFH4d!AbNlq&>6AOu1n1VZ3r2zdYd9vHJyzx2D}QSGe}r>UZ-m-QRp_9qXQQg+K^|KnR3D2z(3y?|y zepfttp8dOukBXaC)Y}=wMa4~fevjsu^~wv^a_DtYFLmtdchB9rpLMKX(Ps>S5D0+~ z2!Rmz1Ondwz6Zvvtgrp9c-DOJP;pZ6cdabmKlZr9P31+O#WCxa7uGo7Pt}L2W36&J zx%a#0*4FQTH=kO^y7q~NKnR3D2!ucg9G`&qzwd!DE9d_G@a}tYQSo+_53Ow8KZ=L; zxaCFP&HGdK$D8)Ls24r`bh$U*^Otfn-}BVE_KAi-2!ucggg^)!pMdwj?}0HZ=S#mU zUOi8IUByr3MJucKkK&=?r9H1#^Zm5_aPO)<=hSoRc8;HU)bo9xQ?3vQfe;9R5D0;f zA>cc}cfpvI`nm6lt^6)tDi10@TG_pS6b}_Il@Hwt@1waz8Caeb7^cWpg&rM>>A zTpPz3}xa=GPArJx~5CS3aZUVjssPBa_D>AzG?TY z^<$5t$Jz7Pdwq@?f3H)oW3Th;ot7PsNTB=b();eu+?PATAsiM0@xf>Kp!dtl`uStu zxBG3(ilOV?zn^+OJ@3xNebIQ`XkXgn?0M|HE=P^O*QwW0ed+5QmYw!MfG@7q?z2np zyI*r(E(wQlSO~-i$Miw(kG{d;^p{=L`bsPXqY^*Z)Czs_OV>5&9_ z9s7N+`=$5YKbPJg^*kl7a&0(-!$KfFxXlM+)^k)p?tQyvy?*R*h>wb!9>oXpq4K4j z%jv~e-(Or*-1I1QIa(g-L)DL}^C{P^2&fxX&ox#5YxQX7A^DWe!yz0N0`b9nd@yG1 z+xxYCUcbI?6bJ2bj#;sF-MgQ9K0R+dx)zP+kA2@BUypz9^*Cz$y-w=b>-&61Wrs%) zP&aj?z0UpqsQyk~<*IN9hlN0Vux%fVS@BW*TVJO&>wTj*s5raIgYMmb@}NCm_qfp0 zi!S?7@lbKoz1QQY@vD!zQFVQhowCiH1k_9Y)Ri99zsakN6At095Qq=z+Z)A4#obkYbnm{F2krT~$AzAreA$PJgNm2#y$*Yi zUmd7AsoyErrUY`3m{r2v|#9u}Thj3U3#0Q`4 zgE1?AeV%#`)UVqg#Y^Qu$E+OaQG72SDqo66*P`+GvF{@eDo%QoI_xbE{MCi3-{YN; z6>lM+9_piRbZ@>(yyb#$2#1A0d=MY}T_22DJgC0!JwR*L_DAtj`A~Uw-TS%d`N+2` zF7#OywLa}}^mzBqe{b=3{_3M%&+W9C)pv(o*{t0dZ-iKi@y?Q6*?TkVIdG7#0S^-V9es>JwUx5 zXwBN+D1ItGI%efWk8*zGL*+~H=vp)$H}>`IFRr8T-b)_1Q}s}%$5lQnT|xkNsvhdI z7hfgLs&+Vp!$KfFh!1Y@!I;I3dLK~liJG2p^1D9I5w&_Xe$5#~I~C%iu zq4K48bUj^pdEUDAI||3W=AjPiqE7V6GH3dQ1n|Y3s>fdal(@?P;SdfBf%qUkc!Uqe zERNn2)O)0UJ>DokDsMVw<=l1e=dR}?->$gOqH%sS-+K1jJGZ^ZuMX-$)$4p^GvgKl z_~NY&bnm`O{N;*p2#1A0d=MYpAN4v@*8F@W0bD8G`0w3MiN6dH4&ks6h!5g}NBUsQ;_1CXy-#S( zI^HP1t~k&!D|dR7b0{AwU)s62FB)H?zkAMlN8z;hJk&#d)Qf&qGXHcB0X%W0`0w3E ziND+t4&ks6h!5g}NBUsQ;z_+fsP{|FI{qkMiUY-o9_2jBhsw7rF7))%<=%Yj9EH!` z^H2}V4wFRgS?VZO_;#Uuq3;)7@UV9es{ zeL}rw>etU1(hRp*?S0sNc;$3WuZQp)TsAZl_##5x@~wiuY0clRU~M z;SdfBf%qUkc%~1=EWXrx#ruZVtj`(c-4!2-8$HT-l@FCK#l^jON6G&vd8mszsoN>n zT?BB%6=!-B|0IvHNjQYVLLfef4_@JeF^jYJ3-#WiHS6<6`BQx8n8k!1<=o1L%D1cE zkCOLM@=zD`;@?xQy9nTjE6zvpP4XyvghMzi1mc7E;FUfYvv^bQ8S4F0vp#pkf#O5) z>$>;z-1Awx-+P`%i(j4ilW$MC?jnFAt~g(+NAp?oDLaKjI4lI>gZSVPJ{Yq&Qtun@ zA6m0Mcf^6>)D=gXb6TDWhu3i6JHF)C+CAf~1aQRlQdN(8HRq=)7Y^aD5Qq=rgCqN3 z%&KpH&v*~fn)SIO4qZF9F^dsR|0o{e@Ei_&M){FXYuAjo62S3N#s6Ma&wDlJt|}i6 z;jj>h58{I@`(Vtf5AE-f{vN8?89SHG4NsarP@V~g$8zAW?mzyl-7-F#0N(d%uj8%v zd~vVlyq0sqAsiM0@j-m>3LlJFoN0d#c+b?Vj0oUDJ2yPL=3E!SaJY>__Y>doA+6Oj zZk>R7-K%_XuXcasz8n+|;jj>h58ms8Px)@>KGWCxd!nk55rNJJx2~PeE7pFu#~@73<7+?RjCAsiM0@xgn2FlO!lsQ2hz){%GjU+?!tCnEx#kNeIM zU%D4xB+jbzyEyO*`^~z7!AI zeOi<N;n?s@PsQ@CpA=KC5gphCm2}KnR4uz6p4*dC$=?D=)g2_xHVV z%9r9n@hUnQ*9hQ5@uT>5y|;dOzACbJ4&4`g!%wubJgKhgjKRc(D#p}i%PxsN7 z70c1y`{(kJcjwW06`jk+{`}f~-*@f4KYw{7ubJ87bKmnBv*MxW>XYA#*HJjAJLM04 zp_TRaM)93fd7V=nx_Zt&&n96XYX2Tr?yC~v5Dp80_+Xnp(7(>9es@kQ%g2v>U-5Qd z9p(LhE{~o!9<=jPk^c9!d+VIj9*6t>oPETxRTU@gdC2cxJy+lSUJkjHgZkY1e1Fb* z-4A?H(Y|jK$2slsuieY{oZ@7j^?Dr7B4Z!>Qt^l{S``R~a99Y$2ix+&m=(`C)!)vk zzIaY+*V{+y_jr09pW?Tkcjtmv*FJCUzOTP_k9Yswx_$rC#;+c)JZ{y_1+Qos;ZYnq z=YD_fKK*(1@BXMPUN`pr-HY#>_Po~aFXiR=zOT5RMaKH}6$iaE{>-Zig+n+j1mc5j z`C!b7=bY+;=TzTZ)7tI)*q`tF_IN+VS3U2}W$nH{w|0LmN9*)`)$g>EOT5==&l`_x zIc9zt+!?s#g~0)kITLM&gr@QFa5pmBMxys3zPNjCyq4$NeKe=OpLo=Zo(^`&OTL}M zqd9;2dYv!s=d?fP9#8kwdg@D0FTU(69xBeR@_CioUtHpSG$!j(``Q0h`DUN0Y&e9& zLLffarVqxfxYktvr21+-b@}KyYQ4Vir}(7j?fzZ)+h1L%dePI)FL_XT%Ku&bkGe0e z6mO~yUH#tGI$irb>z!VF*_Vo|$NTPji${ForH{g9J^N7mzneq$uS$nQI4lI>gKhd? z%!-TZqxvhYS(lHVvmUh%jW3Gnt2p3J)rG2CMYZ2i9`d5{eiiSd?}I1BnX1F3>bY~; z*L$^7?cd|XVJmePPmfdlkK$%M``DLmg-7D3iibluECk|%ZTeu$ic3GG`Yf$k=STCY z_2`(j28}O@$E!HtPSr)dXhpT3QQTBs@}#fgeAIn#q&PoX)p1QvFTQ#l^2LE}rS9UP z;+4ngL6`NcZ@;Z@NE}t@a0rKmKzy)mAB|sr9J+;)`PWDh{|)^-w2TQEh(|uRP>MU&S^1lvl3h zpib&X)s@!juN&=4#U);PZN9IXFFtY0gWgKg^VX&IdsTkfrz#i@;jj>h502%7F)JUc z&r*Gu*6j16`P6#$q486(d=&@W)q|>2MYG*eoK*bsdKJg)Qy#gMgL+YQr0Pp+x95-c z69*ONt@*y{IdO`c%Ij8wp0}QT=&SO}K2^bR2#1A0d~i%3j9Gb6eV6LTv}T_l&9@G< z4~?&i<+C~9P1Qr4XhpNVQGDX2@_9DDtY4mZ6bE&q>Pgj`*6xoVtxxSQF8ZjvpS6xS zsXXL$y7BV7^{oG_JhE;TDjdRLArK#YrVqxfys7?6^<`SK*GKcHb*O!4d{-==%>i$9 zpz1^`n)i?5q2iSXeKxnOUtV}L2lb=sOVz!0fBa~D`%&>cI^SonCvJJj?^<%6qt>(j zv-8OMRk3gghlN0V@R>dsv+}0;Fx8)F&0ZhPqt>DJiQkIhvpL{R)q$#0Mf3hqJmRC` ze>ShIUmkci2lb@ttp2p3xqq}CwV(azv-5uR`r?+4{OG0R%(o7;{-fj0dR3Wl2#1A0 zd=MY}T_22DJg9z5^=n$Q*GKcHb*xY0!(#Ys4tP`bP#;>+yl)hT_{2+}%_-|w?O(+~ zUDccN0j;QRAFX43YX4W|`{;edFCQx3Yt{4CrH_s~>z%$|;SdfBf%qUk_)R_-v$#ab}&<_bVL2VIdG7#0S^-V9er0dw=(Sqc!`-(eJdcV|^N* z7Q<(8z?rIt`p}Bv^`rg8CC+E@$huYIcXLo@s{WKOXhnT~G~YVZKJU)^QTxm1(fX+P zvQBw59KvBC5Ff+`xAyRiE`rKKB>t#tN7k(xZ-s+;Q-0tNT2cQv`rUKXdRxge zaa8TXAsiM0@j-kLA6$M8#w@>hzftc$TC>(i^E^+-tY>J>XYqIz2b}Sz>O(7v=a2Ri z2NfrM7LTl3HQovb_2vW0C$yqIo!nFNtwXnxU*f3Bg+n+j1mc7EAU?SK9E@3hq271Y zdyv-bA4k7a&r|EuoYP|XXb$*N{HglX?$00XN5w(KNgvH4>s5`n!aUZk- zt>l$Bw&k>@<|-0?^ig4!$KfFh!5g}`_I9ce?R)3qBZ-+(eKnc)}=X5#qQA@@TK^x2d&*-H`d=MWz?;MO-{-WNG)b|vv**}hc_Z+n@ z&3P_%kLG|c?o?fB*Vm8sr{bdGrjO>5^{VDu;h@gyPyKx>aVCy!`6l&9Jr)A-L45ED zJ{Ys=OuZ+m?KIakH*Q5XCXZ1mc7E;FEkXX4RYeUZTFIXwCi_{hfM_S~usam_3>UzIaph_^Q-< z{z)8Ed{q4O(R{LA)&1QZ)R(?Hp6tI3U!)GH!$KfFh!5g}uX8YF`GNXgqQ0kS&Hftw zoqEoCH0Q3EJ&FUa6nAx~-QGWnhl-PmpFWCD)~VWWg+uDQt$J+57l|XjSO~-i@j-m> zbq>ZXKTzLG)b|vv*s1=+Zn}0#Y^QuAH^r@ln25g92Nrc zL3|J&d=MYx9HbBIyAO<6@l)SP)OQrE*{(VCs_@>|aX&J<_bIpe)|l^2yS#e?3;H_w$*!XX?M0`Wn75Fg|m zqz~+?4~$vyQr}6`cNDGJmw%Ukx*u?*xKdmxzDHB}QTbDR=%@Q8`PT^uhj3U3#0T*~ ze2{bSDScqfI`7nX67?NLYxeqgxpnBLaO`=?A4iHK#q;PYUy29Ci*}y5FNcIfI4lI> zgZLmm$T>(KIA$Lhv+|<8lc?_~TC=~t%gv+Kp`YR#`BFS^qo)tOO0Bz)0&z`Jx}-IAMsN8Q2C#7-9-RL ziZ8{V?!`ZevuqI#;jj>h58{LPAm<=`;J!XEWk=2>pn_+<%n>v`(?i1zQOes7-V_oCvaJ+GpY z@zDf2XZ&gRPtJE$ARNMBArK$L2k}A9LHfY4`@oo$AN74i`*)OkzwcG$L5o7hXA{7i zcK`4pP5-HighMzi1mc7EAU?=BNFO+M9~iUpqy0O{_tVj|vd;Kw0^LX5Z+uA8f2u;^ z5Dp80_#i%r4{{FD2aeqb#;p8k|4!=PQ8hbb2;4@X`>FeF%vzVG{}hjK2#1A0d=MYR z2RR4n1IO+IV^)5&e<$_tsG6NI1a2eH{nY(7X01!pe~L#qgu_B0K8O$EgPeo(fn)c9 zF)KgXzmxiRRPKw{UO80s?;AU}?l(T9=|5Gga0rKmKztA%#0NPC=>x~^17lWxw0|e9 z-JkouT6->kFW#@>(CbvYzi;gEbPjw-(|@W~;SdfBf%qUkh!1iO(g%*+2ga=Y&T0RC z>i6fK&+nIUzL!(4i|^pt{r#hOXpgt&pZ-%d3x{x62*d~RL41&NkUsF4ePGPW``mYv zdGSf{dNl|9se1YDr4`-#NAXbcil4rkWA-a=ghMzi1mc7EAU?=BNFUfn9~iUZSku(0 z_-uuPI{Ch(zI!X$?Tq3Qr}($RGjWtx!XX?M0`Wn75Fg|mqz}BO4~$v+($t}NY?XsL zQQx_~due6yzEK=hoZ{Xp-^5j(35Rf42*d~RL41&NkUo$;kUp^92gWRa_|B!if9u!x zjp7g&9kXJ}`3{GLKztA%#0NPC=>zEl=>zEld+h^b*7>ErcYO!bn)Uk8{^AlR-7ELR zU0w=@a99Y$2k}9CkaLhekUo$;a5{}yKJeX3eGk{KuOIC%o-r$ioZE0%2*d~RL41&N zkUo$;kUo$;aFjkUW}Rp1``7m{ty#|>?MKBUzN2tY9_6KQ2#1A0d=MYR2RR4n1L*_l z1KauE$@_PBzQ=Pub3XH)&U-q2AblWxAblWx;1l}5m{n)$JJ|Ozty#|-?PGuO(45C& z9}eNL5Qq=rgZLolAblWxAbsF?ePGP;weMl-JGp*+-e@2Dj#+!9--N?LAU=o>;)9%n z^nvt&^nvt&qxXR^>zq^H#lDki&3fEuU20!(9G!deD=&pZI4lI>gZLmm$T>(KNFPWa zc>RA*-oL~1J)U!zbC~yW-pAzEl=>zElpWFw=tol>m$G)4NrS`Ee&3UYPghMzi z1mc7EAU?=BNFPWaNFVr|J}_qa-FNb<)V}FA#XlUvVIdG7#0T*~&O!P>`at@?=kDw>A{n79LKkokq`2YX_ literal 0 HcmV?d00001 diff --git a/robowaiter/algos/navigator/discretize_map.py b/robowaiter/algos/navigator/discretize_map.py new file mode 100644 index 0000000..06c602b --- /dev/null +++ b/robowaiter/algos/navigator/discretize_map.py @@ -0,0 +1,90 @@ +# !/usr/bin/env python3 +# -*- encoding: utf-8 -*- + + +import matplotlib.pyplot as plt +import numpy as np +import pickle +import os + +from scipy.ndimage import binary_dilation + +from scene import scene + + +def draw_grid_map(grid_map): + # 生成新的地图图像 + plt.imshow(grid_map, cmap='binary', alpha=0.5, origin='lower') # 黑白网格 + + # 绘制坐标轴 + plt.xlabel('y', loc='right') + plt.ylabel('x', loc='top') + + # 显示网格线 + plt.grid(color='black', linestyle='-', linewidth=0.5) + + # 显示图像 + plt.show() + #plt.pause(0.01) + + +def discretize_map(scene, scale_ratio): + X = int(950 / scale_ratio) # 采点数量 + Y = int(1850 / scale_ratio) + map = np.zeros((X, Y)) + + for x in range(X): + for y in range(Y): + if not scene.reachable_check(x * scale_ratio - 350, y * scale_ratio - 400, Yaw=0): + map[x, y] = 1 + print(x, y) + + file_name = 'map_'+str(scale_ratio)+'.pkl' + if not os.path.exists(file_name): + open(file_name, 'w').close() + with open(file_name, 'wb') as file: + pickle.dump(map, file) + print('保存成功') + + +def expand_obstacles(scale_ratio, expand_range=1): + ''' + 障碍物边沿扩展 + TODO: 扩展后的地图不可用!!! + ''' + file_name = 'map_'+str(scale_ratio)+'.pkl' + dilated_file_name = 'map_'+str(scale_ratio)+'_e'+str(expand_range)+'.pkl' + + if os.path.exists(file_name): + with open(file_name, 'rb') as file: + map = pickle.load(file) + + dilated_map = binary_dilation(map, iterations=expand_range) + + if not os.path.exists(dilated_file_name): + open(dilated_file_name, 'w').close() + with open(dilated_file_name, 'wb') as file: + pickle.dump(dilated_map, file) + print('保存成功') + + +def show_map(file_name): + if os.path.exists(file_name): + with open(file_name, 'rb') as file: + map = pickle.load(file) + draw_grid_map(map) + + +if __name__ == '__main__': + # scene.init_world(scene_num=1, mapID=11) + # scene = scene.Scene(sceneID=0) + # + # # 离散化地图 + # discretize_map(scene, scale_ratio=4) + + # # 扩张构型空间 + # expand_obstacles(scale_ratio=3, expand_range=1) + + # 展示离散化地图 + file_name = 'costMap_4.pkl' + show_map(file_name) diff --git a/robowaiter/algos/navigate/dstar_lite.py b/robowaiter/algos/navigator/dstar_lite.py similarity index 82% rename from robowaiter/algos/navigate/dstar_lite.py rename to robowaiter/algos/navigator/dstar_lite.py index 9cb67c4..4d7edf4 100644 --- a/robowaiter/algos/navigate/dstar_lite.py +++ b/robowaiter/algos/navigator/dstar_lite.py @@ -5,8 +5,8 @@ ''' import math -import queue -from functools import partial +import os +import pickle import numpy as np import heapq @@ -115,13 +115,12 @@ class PriorityQueue: class DStarLite: def __init__(self, - map: np.array([int, int]), # [X, Y] - area_range, # [x_min, x_max, y_min, y_max] 实际坐标范围 - scale_ratio=5, # 地图缩放率 - dyna_obs_radius=30, # dyna_obs实际身位半径 + map: np.array([int, int]), + area_range, # [x_min, x_max, y_min, y_max] 实际坐标范围 + scale_ratio=5, # 地图缩放率 + dyna_obs_radius=36, # dyna_obs实际身位半径 ): - # self.area_bounds = area self.map = map self.background = map.copy() self.X = map.shape[0] @@ -145,9 +144,13 @@ class DStarLite: "obstacle": float('inf'), "dynamic obstacle": 100 } - self.cost_map = np.zeros_like(self.map) + + file_name = 'costMap_'+str(self.scale_ratio)+'.pkl' + if os.path.exists(file_name): + with open(file_name, 'rb') as file: + cost_map = pickle.load(file) + self.cost_map = cost_map self.cost_background = self.cost_map.copy() - self.compute_cost_map() self.s_start = None # (int,int) 必须是元组(元组可以直接当作矩阵索引) self.s_goal = None # (int,int) @@ -163,9 +166,11 @@ class DStarLite: # 设置map 和 cost_map # ''' # self.map = map_ + # self.background = map_.copy() # self.X = map_.shape[0] # self.Y = map_.shape[1] # self.compute_cost_map() + # self.cost_background = self.cost_map.copy() def reset(self): ''' @@ -299,11 +304,6 @@ class DStarLite: self.compute_shortest_path() self.path = self.get_path() return self.path - # TODO: 误差抖动使robot没有到达路径上的点,导致新起点的rhs=∞,可能导致get_path失败 ( 当前版本没有该问题 ) - # assert (self.rhs[self.s_start] != float('inf')), "There is no known path!" - # # debug - # if debug: - # pass def planning(self, s_start, s_goal, dyna_obs, debug=False): ''' @@ -311,7 +311,10 @@ class DStarLite: ''' # 实际坐标 -> 地图坐标 s_start = self.real2map(s_start) - s_goal = self.real2map(s_goal) + if self.s_goal is None: + s_goal = self.real2map(s_goal) + else: + s_goal = self.s_goal dyna_obs = [self.real2map(obs, reachable_assurance=False) for obs in dyna_obs] self._planning(s_start, s_goal, dyna_obs, debug) @@ -336,13 +339,6 @@ class DStarLite: succ = [s_ for s_ in self.get_neighbors(cur) if s_ not in path] # 避免抖动 (不可走重复的点) cur = succ[np.argmin([self.c(cur, s_) + self.g[s_] for s_ in succ])] path.append(cur) - # else: - # for i in range(step_num): - # if cur == self.s_goal: - # break - # succ = self.get_neighbors(cur) - # cur = succ[np.argmin([self.c(cur, s_) + self.g[s_] for s_ in succ])] - # path.append(cur) return path def in_bounds_without_obstacle(self, pos): @@ -357,8 +353,6 @@ class DStarLite: 获取邻居节点, 地图范围内 ''' (x_, y_) = pos - # results = [(x_+1,y_), (x_-1,y_), (x_, y_+1), (x_,y_-1)] - # if mode == 8: neighbors = [(x_ + 1, y_), (x_ - 1, y_), (x_, y_ + 1), (x_, y_ - 1), (x_ + 1, y_ + 1), (x_ - 1, y_ + 1), (x_ + 1, y_ - 1), (x_ - 1, y_ - 1)] neighbors = filter(self.in_bounds_without_obstacle, neighbors) # 确保位置在地图范围内 且 不是静态障碍物 @@ -366,17 +360,26 @@ class DStarLite: def compute_cost_map(self): # 计算当前地图的cost_map + self.cost_map = np.zeros_like(self.map) for idx, obj in self.idx_to_object.items(): self.cost_map[self.map == idx] = self.object_to_cost[obj] - # # TODO - # for x in range(self.X): - # for y in range(self.Y): - # if self.cost_map[x, y] > 0: - # neighbors = self.get_neighbors((x, y)) - # for (x_, y_) in neighbors: - # self.cost_map[x_, y_] = max(self.cost_map[x_, y_], self.cost_map[x, y] - 10) - + # 扩张静态障碍物影响范围 + obs_pos = np.where(self.map == self.object_to_idx['obstacle']) # 静态障碍物位置列表 + for (x, y) in zip(obs_pos[0], obs_pos[1]): + start_x, end_x = max(x - 1, 0), min(x + 1, self.X - 1) + start_y, end_y = max(y - 1, 0), min(y + 1, self.Y - 1) + for cost in range(9, 0, -3): + for x_ in range(start_x, end_x + 1): + self.cost_map[x_, start_y] = max(self.cost_map[x_, start_y], cost) + for y_ in range(start_y + 1, end_y + 1): + self.cost_map[end_x, y_] = max(self.cost_map[end_x, y_], cost) + for x_ in range(end_x - 1, start_x - 1, -1): + self.cost_map[x_, end_y] = max(self.cost_map[x_, end_y], cost) + for y_ in range(end_y - 1, start_y, -1): + self.cost_map[start_x, y_] = max(self.cost_map[start_x, y_], cost) + start_x, end_x = max(start_x - 1, 0), min(end_x + 1, self.X - 1) + start_y, end_y = max(start_y - 1, 0), min(end_y + 1, self.Y - 1) self.cost_background = self.cost_map.copy() @@ -388,8 +391,8 @@ class DStarLite: return: update_obj: 改变的位置列表 [(x, y, obj_idx, obj_idx_old), ...] ''' - # dyna_obs没有变化 (集合set可以忽略元素在列表中的位置) - if set(dyna_obs) == set(self.dyna_obs_list): + # dyna_obs没有变化 (集合set可以忽略元素在列表中的位置) 且 robot未在dyna_obs占用位置中 + if set(dyna_obs) == set(self.dyna_obs_list) and self.s_start not in self.dyna_obs_occupy: return [] # 当前dyna_obs占用位置列表 @@ -397,24 +400,10 @@ class DStarLite: for pos in dyna_obs: dyna_obs_occupy.extend(self.get_occupy_pos(pos)) dyna_obs_occupy = [pos for i, pos in enumerate(dyna_obs_occupy) if pos not in dyna_obs_occupy[:i]] # 去除重复位置 - # 转变为free 和 转变为obs的位置列表 + # 转变为free 和 转变为dyna_obs的位置列表 changed_free = [pos for pos in self.dyna_obs_occupy if pos not in dyna_obs_occupy] changed_obs = [pos for pos in dyna_obs_occupy if pos not in self.dyna_obs_occupy] - # # 新旧dyna_obs占用位置列表 - # old_obs_occupy = [] - # new_obs_occupy = [] - # for pos in self.dyna_obs_list: - # old_obs_occupy.extend(self.get_occupy_pos(pos)) - # for pos in dyna_obs: - # new_obs_occupy.extend(self.get_occupy_pos(pos)) - # old_obs_occupy = [pos for i, pos in enumerate(old_obs_occupy) if pos not in old_obs_occupy[:i]] # 去除重复位置 - # new_obs_occupy = [pos for i, pos in enumerate(new_obs_occupy) if pos not in new_obs_occupy[:i]] # 去除重复位置 - # - # # 转变为free 和 转变为obs的位置列表 - # changed_free = [pos for pos in old_obs_occupy if pos not in new_obs_occupy] - # changed_obs = [pos for pos in new_obs_occupy if pos not in old_obs_occupy] - # 更新地图,计算changed_pos changed_pos = [] for (x, y) in changed_free: @@ -430,21 +419,15 @@ class DStarLite: return changed_pos - - def get_occupy_pos(self, obs_pos): ''' 根据dyna_obs中心位置,计算其占用的所有网格位置 ''' (x, y) = obs_pos occupy_radius = min(self.dyna_obs_radius, int(euclidean_distance(obs_pos, self.s_start) - 1)) # 避免robot被dyna_obs的占用区域包裹住 - # for i in range(x - self.dyna_obs_radius, x + self.dyna_obs_radius + 1): # 方形区域 - # for j in range(y - self.dyna_obs_radius, y + self.dyna_obs_radius + 1): - # occupy_pos.append((i, j)) occupy_pos = [(i, j) for i in range(x - occupy_radius, x + occupy_radius + 1) # 圆形区域 for j in range(y - occupy_radius, y + occupy_radius + 1) if euclidean_distance((i, j), obs_pos) < occupy_radius] - occupy_pos = filter(self.in_bounds_without_obstacle, occupy_pos) # 确保位置在地图范围内 且 不是静态障碍物 return list(occupy_pos) @@ -497,21 +480,40 @@ class DStarLite: ''' x = round((pos[0] - self.x_min) / self.scale_ratio) y = round((pos[1] - self.y_min) / self.scale_ratio) - # 需要确保点可达 - if reachable_assurance and self.idx_to_object[self.map[x, y]] != 'free': - print('1') - x_ = math.floor((pos[0] - self.x_min) / self.scale_ratio) - y_ = math.floor((pos[1] - self.y_min) / self.scale_ratio) - candidates = [(x_, y_), (x_ + 1, y_), (x_, y_ + 1), (x_ + 1, y_ + 1)] - for (x, y) in candidates: - print(self.idx_to_object[self.map[x, y]]) - if self.idx_to_object[self.map[x, y]] == 'free': - print((x,y)) - return tuple((x, y)) - raise Exception('error') + # 确保点不在静态障碍物上,否则就不断向外圈扩展直到找到非静态障碍物位置 + if reachable_assurance: + return self.validate_pos((x, y)) else: return tuple((x, y)) + def validate_pos(self, pos): + ''' + 对于不合法的pos,找到周围距离最近的合法坐标 + ''' + (x, y) = pos + x = max(0, min(x, self.X - 1)) + y = max(0, min(y, self.Y - 1)) + if self.idx_to_object[self.map[x, y]] == 'obstacle': + start_x, end_x = max(x - 1, 0), min(x + 1, self.X - 1) + start_y, end_y = max(y - 1, 0), min(y + 1, self.Y - 1) + while True: + for x_ in range(start_x, end_x + 1): + if self.idx_to_object[self.map[x_, start_y]] != 'obstacle': + return tuple((x_, start_y)) + for y_ in range(start_y + 1, end_y + 1): + if self.idx_to_object[self.map[end_x, y_]] != 'obstacle': + return tuple((end_x, y_)) + for x_ in range(end_x - 1, start_x - 1, -1): + if self.idx_to_object[self.map[x_, end_y]] != 'obstacle': + return tuple((x_, end_y)) + for y_ in range(end_y - 1, start_y, -1): + if self.idx_to_object[self.map[start_x, y_]] != 'obstacle': + return tuple((start_x, y_)) + start_x, end_x = max(start_x - 1, 0), min(end_x + 1, self.X - 1) + start_y, end_y = max(start_y - 1, 0), min(end_y + 1, self.Y - 1) + # raise Exception('invalid pos!') + return tuple((x, y)) + def draw_graph(self, step_num): # 清空当前figure内容,保留figure对象 plt.clf() diff --git a/robowaiter/algos/navigator/mag_5.png b/robowaiter/algos/navigator/mag_5.png new file mode 100644 index 0000000000000000000000000000000000000000..2fcac52d13c08339cdc297229d5c47237d4829e6 GIT binary patch literal 25292 zcmeEucRbf^-}g@>Wm9G%Bq_VBj1*cLB-vy~LN*!EASnR*?X1s zyuY2-eLweoJ!qT^zd6v*`4hj%I;-k9pR>1gcDs1hf^_Plv%_V3=gXH&d0Z{7I$g5AA}JyxBDRmm z+S%E`NlsMM?mxdk#Qv(4=z+}a6#S6Q4##wzNF@4;#Q(`&DJ5MZkxXTet0-%^KN;`x zaNcTBtT>g_blh#>>D?RqZrt#@n{o50@^>DMKq}rl@qYfCa#5qMRnf6W3*FvaZ*maS1C%^gby=|=bCSDf!_=*j;3f$P&W!Pm{_v^_MvkT`-=Eqx3 z%)T5+%Qg4sq2l4i|2}0f7LbTPNC;CNB7P6LNaDwD_t^gDumAHj{%0}#f9wVQOzI4C zy)>5JzkfS8I$l>7U@q8>rDU^7nc=LVA+4{kZ)@wZSpzn56V{)DpLk)zqKS^dCRMm2Mq=K_YeLIc*XxoZ4{ushou)S;p|&^w3b+ zvGH+Ld}8&$)rE?ZOwq^x`RjPLC?(x?Dp66^_>7>+rLhF)V=(Rf_o7!r89}r>3UF+&fm6 z7ppk!3wO4~9Bi-oS>!Z3c*@|t0~!98k)5r2;>4DT?jqX};$a`-mx!i0kG(mOE`wnM=)(D2sJ z=sAJA12s{6A|iC+;^L%GPjA` zeMZgQ{e8otnU&S;;ijbA=z}lAa;q5_86%F*P4;ki6}UmtF_YJbU z_|%ZopCd(L_!Oxh5r6sI(ZMC^Esi6LqC&40hH zvblMiqM~BlSVv6_^~A&k{?MswPLjvFOFR=xhlN{hE>T`lF`O3l$vkasWp&cG#ZJ;^ zWr<}p*5}V9W?v?}#!)HLa;h(n51hR3t+dc;_DIGtPHWxv91DEPU$O`Gq2zUFD-P~Hxzlfm6w7JALJOa3W#xeg5m$Lh;|! zRa6G+YHMlZ)j~IrUNzh7-@l(kn&`|UPt)FOdC8JbNNCHOH*ZX%l+*5R_U8#SRJnkM zGS->LENS`0+GTZj>@|Ojnuj};l(-ib7V-y-eOC`0K76=$bTk+Xs&KK}i;9}M?8TAW z69wrBC!_ky=#?&Kb~ZFHVv!oI?fcFnDjH7zdrkU3xAMtJ>Z3=GQczOn=sbJ&EUdD! zk}lg~*xOO*#fuji+2gHwiFmc6UsE{_pFh8C%a$#34=?TKc$t(G|MsosTe9X6a+987 zZ$_-=ZF{xfwVgIK<-JA6b*H>sg@#??WwV{$L2@=Ww!r%Ov+|3bPEXfpzMGGJPkVIG z?ahCyDJLg`dwWg3#443k%zXZQg38|yPxW#~PMV>euBY+Jv+!{GXC8y>@ALCNRwkO| za+X(Cnl4UsQKqP-X~)OKZLs~GdR;A^jP$Lg#jNeE#XUMdZST!X)a+*9GcEAbV}O-)Ui7BwvLe}>|x78ca5UX|$f92KV7A^2@NS1^s==FOWQiCy%cn2)h9-b{KVZNEe6 zax00{nq$XFpJ$}rACD5N)wWDkk_cc+QKY=gbip@~ZWjnj+k(BhAx9J-T9Dh){j<@e}Ww#6`{v*|) zx@QX0L-FAszkWSEruiz;b)qxq%NO;`nhYu$KNLL=@8t#6SViypG=1s6*I{j4dXt*< zZe(P@$cRm5P3Aveb_siqP3kh6=lsYn*FE1h+hlWCSXjuQNB;UVN+O`@y?r+iUzhH7 zk1wlB*){7p-hNV>Y}52IZBF4eM9`wh{um@G8W!uWo6>$Xt&fpQ;2D5=sap* zu)S)+{7RISLIb-Nba^JpXx_R>^WlBPE@mle?VWB%?UteGTZo`Hm zabH$ZBNbOysn@Sxmy1;K5=AxQXKP0XA3r}uLqh|Xk3AL<2M0&U+4G}lq&NTk@pSj_ z`0(k|C-db47qBh`_wFrQTV1XYsfhdMn^82Wv8lOyV%6e5ygr|D*4Wto#_I`DadE~= zmo6>Ut*@MkoM_o@SbU9rd10KnfF`(QdbS&Fg5@)s2{p^ULx&ELP)=`m$Hc~l&yTho zNzi0Z&d+K7{@rxEJzH?k9!87xK^`=$q%*NB1vDw8lEfR>jIuJ+RUo}#!v;C|2~j>i za;((qni@$>7y85o>$_1=R*f}vgK;ljkX=YOQq|UG5!$=ALZnJajJW0Ib3zY>np0R4 zPd{x>UNp{k-hBM{amqKZokm7Ro@?Vxyw6V*_kA)_k->)LR6U|F|Lq(A3}XRJKx?6g zq*@4D!?2j`B_?KOM{H^=3prw0m}hU@vhf*u%F^%OF798r9VXw7=Gb-Ijg7UxF(Nk! z1o0|0wfx)}h34csi#=FyH&avhDfX37{rwOj4^PiHTP@deDTuy3B+Ai&F;5`R{ZfrH~t z)ef)JbA4yhwE3i^S-lp<#0#ccR1!2Vw!AUKOJpwC8o)$BHZU;Inr+Kk7RxwIgN3B~ z)asc>;>j~#TZ_D;??pz^>M&+s@bHlRo~p~|%B~%5MLZ1~)HwO&v8<{2`SEXj-H)xa z^@7>ma(vf)o+x-}k4ey&;v;aUH?&i>6>LqZBHowzHhFn@1|}x|`uh6QJ!~(UZ6fa7 zGu4RNF*`H!{H!2>P!zrY==?mj6MF=2^4OU(w*f{Awjb|h$2NKEo|BV9MNeNfH{4XP zbq#MR!|B&)josHKLa;5zx{El49(?Zq`V39vepJ+tq*$NBE-u-v1IH-qh}T`=HIes= zfq|huL5g^$lO^jrI6^BAosZTwG~`lTojdm>MwEe2&`;XQTcZMYTkD5KXccMioBD$)0=G^0Rdko zCO+;muY39cwawpuLuQS2q+XgD(4gkIa~gVjLaws+%p=G$a&lP6H_?@Uez144p!Qqx zIgPVtpD(xN+Q)YP*>&=v$*-?ZiQ;_vnS2lmqL8|mrxDWlk2nOC~xE_WBQ1N>2vt}Tz}Qqj$U<2vX{15`)6^ElPu zvjzsK`caP_1>U+vsU9t%n){`vhZ~4X22ahqLn~S9)$7-d%b8mNUO+6Qu-3{&ZU(-p ziHnbC+_r7w!Gi^-b0cD6g7H%yjYlfxA5Lk0JiuOB6p6u4b9~8?`is(CLcDSuN37Zsz>|Z zy~~hlRFvQBEo_*-mD^|OVlV;s42ze)JQ^Dt>+S6&DJdzLTUo^y7k67Pf3B%H623zr zyBe|dm)=yO-rX>e%mATRHRBe&^P9UR0KCc1*7 zC9S#_z5RLK{SKb#_L}UgmG1dg^yc;J!zLy?D=RBvZW9J&TkTDxq@>uyO>azG{*~`C zO4O})9&tHWx@>a1FWQU+TmJKlYn(b-oe~&!W%!KmNTbgI4qAN8osf_ak!-VLw-iM{ ztX{d9s;FZFqYo{Cq;+H$?eRG}GCG=hxlJN|qO4Qbg0!N5M?$e_6Q8g!EeS}II$JMv zX69^uy z*&`@;NK;cYhOC}x&(s? zz47G9c19sSUK=HSeSHcF3ShJiU^<32DT#@d{X3?=v!esYg`d2Ttc4a>h9>H`IAN$^ z`{Fx@kovJ>rQjgW=`oc9wWxE(-t*hu7#7?*6(jWm7}v+g2as+9&@3G*D{GgR;`)jc zo<)Ch(zC;;jsmA1-=O7`IwTSmvogyT5FAX6SJ5((k7~`s!$SgtN)AflG1Kk$@tAL^>r#G2{dGMlh@Bt$=`lS1v19 zRmYAUW5}lT6q{bx;tAkT@{z~FTPm&M-SglC%Ij65L%b3vnRlO7F*i3);-3DllBR72 zT!$x=^~cc~Oq!04F7D~ZtrTRN=(d;Q`t;Sa)CO;p)t}fO`kPbC#IM`1WYNslHuyup zrZONPie^T}?C`WSyW7PzJFxe9X9jAt*Q>=*&F6+1j=Ymy|7LRlYKY_S8H@Y(?+0p< zyM$mvCO$MUFqryCE$Y1FJt$^$Bk)yFOpJa~ag81ymH+vk@nwCiriyo$npE0yd8h=1 zggyc&sJ1D&(2+kcS6H2EB39I|jr_a~p*s{f2#~Jh1+>yy;#<-nP%O>r^y{nY*|T@8 zmzA7{7(@*7`PlB{F8_FwS~YJv{`qqf zr_^P!-#(ula836M3J$XD(;-<|S!JFSf93e2@*+fvr=F9Er((|P>Dlz&39NnuvNQz% z&H1xn3@s5zJA>?XT+VhG2NICgwgQ?FUdlt%D4@51VauAEn@#M5wr)X3+4!q2_Na$P z-iP+_K>XwvXJQqft{Hrv*~-eB?BMEJiDE*#VEDbh-ekV1X#eIdTMnC>zZA4u2NK~I z&uMITq+_7o3P!3NK*|2@6n1IIcG8^*#je3?I{*NHdjQ+3 z=NU)se)0PCXC6D<4G;`yxa73PB&z+zN%xxF@yNuk{ydgh!xQJa^n-hyN?KYvAUoHr zitdSw<42S6hSi`0ZTs0-M9K6Y{hs|5@3lCgX1o4rcWgP-8W~X@M)sSzxzf+P7jy$U zr>RNV+1WY;uEMWVQfM2W?Q$QCwqjso6Kr3@dSJx!;Pze7c*pT-6c74FWF#{X?)3>Y zqTg+g>>R-tTICH?R7#o)-0bD&>W?_Mxk(@MLOnfp;>2N9)tk!gl5Qswn6Nglmy{@N z-@aWXr3`GsgzQ;)*~wBC2sWD`6cBonMwv0Qm)Ek$8Q~^IKsqqcL9^k&)JFt=S)2^V zPUB3iU0J#IM9H_?WIXy{f@V;rS=HkTonMKQc1CnL1}m&B8$vh^Y&oN}`tH+0OVSzc zeFpFA&98r{s@g;phsemt;|oVs5~Y3Dt_5^WDfiDVE>@+a7YmI<9~9H)j zp2ph8x7pbhgane2DVNv}g~9Ovvu;X8h8Q907#SH+7Q{W*OlIKb4lgW}KVGY9Wp8hP zcXtBAfj;&_d`@m|lZ|YfGb=0F+S`c=SN-Wz#21n+uf%rza1}K**J0U#k_*Ph;r;!l z+Yh>aF|pIzaN)v*tU}o{0+AoUYdJzGAvBC#eHFk)3azfJq!cY#d3*dyCl9a0ZfaJM z{Yw@-coO~fFOE>!H8Fj8da&hHldsD|b%8PWIZq2wzE};I%uNW|Vs0bPY)+9Fp+BCji26n*~VDRVR z*}FHmZi@hK2)EJ>g7CLoxpIZlZoR)ESjK5EM7d-C{T|dpAT;z;aMLQTN?bhih#eifMESnS%Y3}v z=(`#k8p4(HfQBFH>goiS3$G4r0S*I5FulJ}@VU13)MVD;WKT)O+35CmJ%bXTqB1*r zHZc+in&F#<`|tg&LA~|#eX0PW4dvl_db;Snd-tXY?2g7}_f;HsF!xdA{Q2`qqo3>Q zs(!`#hDrBa%TlG1^PCg>icLS9Q-Ld-CM*(^0{7WkX_uNG{rwK}Bj+`2{-B`*0y*@R zUMG(mi>)REqingb@N?dsW@csq=-j!s)n}oF&KJ|i>@zOjjty5S82+lu+<#a1!#|vO ziwE5%%0t*C^-^sievP$dML_&As|w5Z*llb2Z*uKJ5yLxx&lwe02~n7W!uhoib~SLX z@{6<2GcwLzaMMq!A0HbtvA3u9^<6(b-t_2etWvt0$NTKMIL+jweH zP+sCEe)!DH%%~`wvpwC)TKgqg^xCy+dg@xDc!REqlZ!p9rA3n=V9nrXP$we4H5h>z z4s{nDynn(XYJ;O~tnkjAWS|&+v9a8+h=ipaT3TA-Q&VXG37%dl+gieR>OvY;l(5Z1 z>LYL4CH?M}-4m(FZ=Ca&jE7bzaSzTUxr>(1h(= zfow+K?Yr)+v0!)QpF1QvGRj?0&U%lpG2y@o3)k-Bo@ark0y&6)8-n9!p2#q+Pp+>j zsXviv5FC$bL}&0vzjOPus-Jshys;#CTmy{-N4zVlsx2!IWnn5brd zxE|__0hB?Ac~j`qk!KWxh}MP0d`m69!BB60Ztlk67l%AO<#H~!`5)!>-im#5?DXkM zefy%D01IYc9*LWJr_${a6|I8kbB9>BdwZD}qqBg4;!;!9;S(udy?QmnV|LKh&bE)Q zhQAC|@9^ObsHV@ox}0@gy9+&Z@|}|>?tOf&95C1IHaDa}6wv>tify71$u%1l5}0~3 zFLcq?6q^N-S*3MTmyZ9^k~{i&!1|yLJG63CTKm~U*XoryfD7@TjzsOc12>0f-@Y$D zXW5w;*$-oY1u7W)2N2m=rwbrEoa6gR5HC5ui(1L{eBxgPI{A-+Ho}bJQTb#6cKdL zz*k*9e};E!oj)IKSDFFU{yjTO{t2+3g2`fn*1pqAYg;SXSq7bM?^z9vovxczRJiWN z#MnM;x(SczFI;qTg4`JS`pp|PH8sk{rY2lixyWsGKeGBe*r9@3w*)^`?tXmSnF@YQ-{A}K~mV=X%s50;0%VeJ1$!tn`$FyzRwxzkI zGt-SHMT6wBl(Jto+hkrHIPtByImqyiH9l&3v1HwFOybLi<$fd5{;Di>Xg-ywR=eD) zCUJvMA$eWd%}pESKBpO&nZ@g_owrLn{Y2(E#Gf8FZzH1}#mf^1VH}|o9S=`JE4EYY z(L2$~Iyj6DtOg5!pLq=n%sHI9wx%X>ZZT5p_>W^zcd@QXi#ujcb6wEY4f6N*ceRUo z{J7nclnN2o#^&{l6MVdUGmDG2OG-*$t*BhNB66j>@YCe(AT!cCiRHz~s-cE>*k8h~ zdn^-*0%|2CB<6OUKBMxz?)!Ib3AYug{rh`CNvf->849*Cv6J)Y7D3)i)ya%AjFNHR z{PdU}RHv!f_2043PfVjso#CAuUz^^jCG?;*;V!!gi9f}$x0FmvTRTUmyR}vDcY#RI zs{}tk5(+vcN~N}v*I}T3$b$iJ05ldR2M2HMIhXh@Uqn`xy(QgP+EKNfbWA%QFbZOg zps+B6Uf#DP*d0S1x#_JIYm7st@m*U-i^x8FfRM1@`tyVzV zD3Oc+NOx-n;+mBgt4P)so{JO0!?L8Vt}f&m>IYY@sqh=3&p~!@aB#qL4rsF8Paq>$ zW_N;vRg-s$i7`O91>g@13E7%JX~Ru<=&cak{G)I*ikJGSu}FC(%^`3otxbn(yJ){2 zmavDUB4yvbuiaT2-+D%2ek`Z$M6d{)Kat*319C1t>+L!BpQuopQ8rHn8- zi6U&V{>_obPx~XxS17HwQc_az+!&*G!CX5Z<#S$W+rnf|_{Wcj8wMB2{lMR!8<+TK zH|J`WlB{>Zo}i@Pu@5%ahwtB6;0+223R*An^#)ew|6W=ut*JQ)^*%8_p93Kfs19!h zmoErC$e$jhSD0gf9Kd&i>zfCSpScS#R0h;fD4ra^4S--OmOKIilnP!8Tj7u}P>?|_ zA@m9B15gA^*H(VVjmPGP5zbn*KcNiAeRUQC>Y-s1JM?Zf@}d|??>hQ>_mwj$-?o4| z1Mcgu4D^JA&=6&bbXG@4uzkBPur?Jf?SQ+|UXzHr53>KK+|Eitb}~xj=06Nnj4=4= zA8Y@+=&m=`=?KYd#Wr|Ohlx&EjZu_>O-9$IRbjhm zjPjIaR-Y_Ib_3w{lFL(kU4O9XR7=U)Hc6|m6r{_Y?-_BuRp=YjGc}^H)0tq5mqD`= z$95nsR%#K3EVz;T&xoVy3%YnCG6eBHy2FD)N{Yqf4LJ}cp%d8H+N!pdAVFi~J%1h* zy0u-;+~B#C&Y-<2r-Y;=0s2u8h8{v|3*nR|yg5n|zkmSzHf4KGD77&7hH@^2o=AYf z|DZd(6(u~NyT~ipkdiS%mtFCi3>M<$%qSmJHV3p^tqT`MpUqu7L2M?V>D#wA85kP& z4Gme(a8$of6={?{wM>K`iUx3VM_pZWu5jKwOh!*1&eHMjfL(PJw{OT_d^rQmceyJ+ zJ0-#GGbC>~ODb({w!o6%Xm^=4^~q4YFI`F&Bu|9zq;gQ?3+-|o`*K{g_;UZxPmwGx z@gJe25L~g#?YxD>F6i{C$rZ3Ef#?av`S`*GJ-s{k?lE=Qo?8iXcptTmvQ(gidvPb# zNAfCvdFvS9KzjS)--#10u-#*~3LhX(h38aT#A#JRLEeZmr(JplhUw^qZgKV#MDoW6oX9}FFf956I*7|?^ za2#tD|9c_-iYKUb-OkI(Ck;VL@9oxAM9t`$0a)(RRfe>LObDE@(We{tL72men(W8{ zjUnmq@=98wLPZ&Qe(D!leHayG27D0ronQ`FKV@BAhTr6>_orT=F*$aO3S7`}sD5Xc z1f+T(8pHR&ckcLur*}&s7y~WHMw0ZH84w?}HR1;XOFm^#Cm>X_xHNr)w4ibBT)gzT zn|sh1O#91&2-z7*`9&+M-6y!r^&ZZ0&Tt+$aNxbm=)(yYIGrNK#We8wDK>7r`03uR zCD`%x(4Xcex;VML=NPwhak(Vj@9ONF!UpJ1%kB1$iekl&n?_ECPeMY|?LtPLlY>Jk z+GK@D886|jKzs*YKxSYoqHPjPpdeWsOtU=DQ(%M2_^uTSIxUkeURhw1cNatYMWxLb zilDWd?8&F9l%=4!>W{>f7xOO}05Z1EuMhPJjq`&z=6e*|e9SN#%Q?py(1q?ew8BT1N-*TpkBlo3W0%C<@WgCrESqzIK#q0N_Ydn`A^423kijI zxl>-=U`(Q23lX>Sa+R%Hw;oE+jJ~#xUIlW0OI;uU!Z054DI;fV~fnxdCgSp|YJJqVJQr#QTB*v!B%w!h^mCcDqe>tNQp9cRTM+{I-8_ z{JrB36|NC2K%~)@bUtx$D3C)tC=cBWfrZ5bh6WB#01F8QNbH5vm7JFAUwR zBohSQ8>mg5T~4yTh@#fi&tCb>2W&w^L?rIi`x7d+m;v{1bNlFwN$A0q{D>T+6{!KVu;CEXSZwTw%BCD3N=5(FTn?3XF0#gu}LNuumkt`<3|7( zDKZd2iUJaQ_fo^okDK3^jprVXEGI&P6p+URT=!_#pt6R`&s2N2q%_-f=DVcS{-T;q zH{fj|6zAY7SDXDDU2Vl!-F>**xNm*Ey?%fR>W}vyzrVV!ZD%J;WFZiAg0G}N!cW(K zXU*8z*;y`fq!CDGZ7xZv%dH5hl%Dl9H`G67ZB_nLfT%ie&4Y%l@<_c{5fIh_S}l5` zt)3|#I^@@CafpFpWz=}RpSzsJpR8Wp!^4Ak$#4Kz3bt-&U#U_Pi890X7Z%wWEAPQX zIC#iCL2^=wru46V4E5IZ+ba!AMxs1N+`kViW_f<}wnn@f*?YI&7seF#p!kAJ|9-iP z`XkBu7Q!n;Ny}Oa4%?v)akmGe*HySRkVtSLL?#PloL9?g2dQ!1A zw(tlAIZ22I1%WZL)EIk>A4t{9 z-U8963I_N5_fRx7G>P%4Vm#TKZrvV9T^*Ahx%4Poi2oVgUQ|_4`EJqo@g|`$w_3b= z-e8?^?e|s1?%ET&cBDdwKL74LE69)n)0-hmoo@lTs{%r@OZvg9ER(tB66}}lI(i=X z^FRk==<#0UBAE=;zd*9fEotGDii#mCTojlSkrPdb`GzZ?H_OX^xw6k)S(z+syR1Lh zDV`T!W;>}BQM{rS1Z9s{TMOdSlk^j{g!)EDZAThOodpkyhifV;DmD_Uq%A8+Fq?t# zxS@}aA{75qIZCL4b0f{v5X}WTth@jQcH-G$S1}cAmEfJttEdiy)Lp!~pkD|d*VEVH z{|Kk-JK;@)5@5h0JEzj7#K;(ZD=kf!U={9DCWy)e8lI-cUY7Bg;Sb{`BpP#bZ7<5H z-2VQ4h$h#8I!7N?l$V>}5mC|6so~8N>L0;T@pHl9({kdW_wFDWoj-4p!7)2KJB@PP zA1dA5TZnX(b~W5DSU(h`tjGNc$IZ<6s#cB%sx#Qe@iBV>=mQ70KWQj}pNiE-R)?;`7#4eDOc^}eq2*beCJtP6Rmh(zM5}f{@-o_UINQ;O^A2Sfoj? zMr7-_#Yr4xu;@YvpZf3Mi8I2_L{)M<~Xs8j-`iJ}IiG)*o}O&x;qL8}wdhh#F5 zPJ$Q;{ZfKY+nYI1R;;q?d|LMJ4y*0Vj2g3U7G5RX1v3hAmS5Pq-iZ!EwgqArg~v(M z4oMn6wSOs+@|Y?>e~SIku7DZ<+@?SF$(hsu1XZXrP%52FngGUD!CKXgGzV{gkQmGIMokIRAAp4Hb+ z@v;m2y(uU#^%QD>kdRP@eUD;So5DZZN-hW0z}4U0vCX!ZuJja#0_Vpo_B`6hN&b8@ z9ww~L9Z-f4?zD620E~w4J8WbO$5?cXkx^qA2}^zfff1vQwzd~gmZqksFS*27A`b@6 zkH>|4Te0CXzWG2(p7F^OC+QmooF{hiBgJ+F&vzAspJ8rc(T6JdNXF4LSp0ebB`rdM z)h zsYx+(W8*xhtILj(Iaeviq(DW^qrr-|ld7NlrlPBL&|NzRZxRy>A69J^=6pWN&9-UrL{E>@@YR>387@qeMe2~ONcW1h;fj{k;~NBxQ~>4iz9^WOVIJA z-io@g;X^iIOe2>~nxD$Q;#9>fARDiQ1k<@hbw)6?_&lFgIXZ4dno{|7p3&D3%~K5v zSYWCFrLY7dSp})$2Rw`lBw}lA?qx*py9nyHIiXvF%Vu ziG{rT%rm6F_{mK+ZT9!WlVYh6HO#-!*=fKiBoT_my>;6*G7>UFCbqWJKu5&Ku%&6I zEFTfZw#PS*X&r==`5tcl%IYdCG7DGf6S$kr&v7GQ#^OIC zdr?L+Pcqh`%wpK-I;uI)x5n*n$g(%TK2LcGcS()NR3)TsYOwo&cb5dCL<~P-u%?_y znBWI}#tU(Puv27#a@g3He%!`JNITsq6w?KVMWTWY=`>;hnQsv!^iM$y`s?`=?Y;_D z;~PaqMamtgAyLfs6#3ZWaMk7(SZ2r8D8-PiTcl>Tu5BN+dhOxiP}twkgO647a{nFbE%`k zARtW3a(HxP#9?j4gLDY&tt6%T6*6e*kin3CL;jTqt`wlMJ{OfYvc+MM!#tsC#D)At zv`9#8f+U~CNw4}aDK74?sNhpMmn|Tr`I0k){O;mXG`SqJAwKiK#zTlsVP2sOSPsBJ zmDmxpWLy0GplMVO%xK37ce3CIW7r4wi^c^Vo!0&>8zVBIFh`@{m>{PIc@bPLG8uu5 zJKOe_i3sJs+DwwU$_6FD*Zx@XbC|l>d=D8b5~)h69aH6 zs;Vy5+(Z}yTZ)VX@u2nHrE^I(yGCeW1PB5-*-!7^7OKXldEk3GoDyO$#)m83K~^}k zW+ydd?Lcg+Az@|;GUy`Pl6lJry%;hZ8d$vkAf!X+n%j|p8#=2WBW({Q`9Mj*F)ax2 zIZRAUNEppMOh`)lfnLIUp8ph{77-K#puGrB5>0bffUyxCAt8QNR;p=fY3bBXS|ez3 zI#w|hjji2l_Zm>L{RmG3(7Zvu z^B%>OsUt-egbIsB?&oE!gRt{Xgj@suC4i-9ryX8jTdfeh(72!DR7%t>0IamD3qB{E zkvkyy8HgO6>@MmX9IUMQNYUFJ%7EQOfTHG`k5Txx%U-2`KX(gBKZs0(Voi*M6&4!U zcig|f6)D@H4JI&9u#90WA*A0;yH91X)P|gggsDQ~MK&Iirhb#OQ5=Ad`IZ!FFW^*wB`+CK1+E2GXG!gf@xGvP>C$<~1S9e8J2BDDrQZ$|BGd zbAt$>RiId=9h}w0S^+{Ke=p5P9wD2B;de9axd2!l&?%>2fMNoKoJ6D(Ai?|%$fqHs zj=t#t+h#c@2^os>=Mxsqt{@PKJTbp3`#2K=11U}0_FghqpnAeT6GLfhxU&}(@3l|z zQ*FQ!a~S$&)r?-&Ye3`#IxVCXAg#IR@Xv6(yNDD)8H$yCGyn79c9VFu2=Yl>kY658j?r%Y4gpT&X z(2(QBWH`hc1_mJz4VJH*L+Tix_$WiD43jR%3gP1>W+u~it%SjtzJd5rW#Yi^duZ=a zFxbqM9@euan%*f!#0k?UN3pMCX3ywJrqKG8T+r7ighWE`WdrjkybNR%p>Pf7=t6S> zBgph!U(@bDKl1b~x^VtHVGRU7 zK!(W9!y~w3cuT|Cna1R3IQ2;a6r(A}L9D7BM>`FH==tcCP+3iNbt$YI+Qx^(Jq%nW zW{A^H&%i?L>f2*7QN{G-_w@PR`}%m*mgS8*f+>hIk5LidR_pl(b03a9FPZ zEL&t@mc2VbEKysVm&G>$(tISQv*~@G?u`6IjI|X4H#s;vLn`;g;9eL46pp7$dyttg z1vP7WQ(#h4QizM9&sFvtx($IX zk1NVE-rvj@MFyq|^4{id#7UlKrQ`Xguez_yv8fFG4=g_L7Fx3V)2qDnz zff@pJxHMXH#tln}ls(3D!jM4*T>WA1yUYohT+F^(9&3U?+=RCPCpZ*j;RmXs-)3fEo+U}itBt}MH#lI6;dsOD^vC0S=;N_ZFaA;^V z=dXO2<6ZZqnb_sdXn(aK?*)2jHxP~dl;J$A3G?9F{*CPQy&nPy_cMjsx3p+o^r6f{ zjV+KS5vQ!(?Y9yG4(8V5eH$r;)49`#y_!JH2cZ))v8Y7Iq(bDwOQ<;5j?VPV@11_p z1#s(b!>0K@f)wUq0#+ubXG$Sz&xQabM#^N5zhifFcE)`Ogr)(pVMq{c=`d1fNgbas z7lR2WC{gtY_L6HKGeqocBOdeE*k#B(5?i26GvmPn5n|s9ArKA8jvS~J34{mV-t$TL zVtR~Vde0QRXd1hTIS51zvS|H)r8J{_Vy48en2)DUa`5VgMj89)GDU8Rv;gv<_gU)O zgdZ4rhmzHQ#MrpYQrMA`7HFx^U)5t34aYS3?J+7(jKLDK#wejv znI^;-9p(aUY;0)S-@G_xx56E<6`11@s5e}s&xl0 zQ6V2GE88YmN3yrJKBT60YvQUHV?-uYeZV8W(LE-G)t&a7Sa7$n56w_NSNzhL5una%;5lQa)Pm#Ncu`JwM9vr^Sm=0$u zpkZpm4h{g+i=2?e_)x6(LUeQI10w{(d{=&O7nVIZ_R*a+V`HODwxzFCD&Bq=*FooX z6J&7+Eh0_vY*EqAt9j?YdRu=b1TLpRbqKS8dPk80zA|PDN`jywB75IPav<&pD#wO7 ztt>fq7J4-CmpC;gojHmbjL`gWBxIfd<5BaIY==EZ1FJE=DOGf%fbSF(;^W}1i_3X3m~|s^0Cv3=YTq9vR3vOY<$ph&?&=*ddtoV$l;@eY@L9^8_~1Cm#I3OvtSSC6hhc zj$TR}DS%q-;%SUiE!-Eo+%Pn3gV>jAK9|H9P!BbbtPdS&a4nISYahvnsEpV?yJro- zz`-M)zj^buH+$t7lGeod_38DCb37o?gruY;bpCcXSd!I!&%k5XVERp96MaCXR`Gsl zP3W=QN?~ZGu!p4TzJQ5h%%UIiVku@eG3C?Kw+ag1+SaxcNs%Z~KXOzIlxB@lbwNd0*#Bdfvypbg<#fx*2n;tFe znDLItW3@y*dnWSvxt%h@-G~UXH0@xtXH@-n%SGsg$P20wrwKqRl$Opt-AoL};yOXg zXRoO7p#iGmzn;n|fxr@Z>iUcq5)f+9J?Vt%M;zP`pKW~p{7rDi_)WUJZ})*&!kYnH zjtp&Pq##2@$GE^~WAtNSd6SWE$!v1Y)=9SEfq_I^MEi}wr>t$}jv?Mw1#0m~ehFb1 z&-R@+Lxe^D6AtZOAVp$44j&G$hA2IhdFpOUQx}PljG;{#hQuZdXX&5=6d2G)>|tN_ zXaPL0z-tcquE?k>@{H`=29D6gvVekvuQM|liM9jmN{o0c@ZSUI#~U!M3gdF0YdCsP zK>+CFYSsh5F9|^(qh;A_8{+m4t?S z&8QS~9<7%!}Q>voN7myTtR5i zIzY5+WMyP{BqSOI?SPPmeT;(wCx~Gyz_CiR6L*GT8M!$hun2c|cOKY7kN^plTr;8e z^5x4!NUH0a2WlGn008m$o01|kZoA8u88|sR-q;~KBPV|}4n_kkC!49PYUjH9d(Jr^ zP9&nhTp%p;;Evf^;44Fdhoh^4QPHxHaQs8Wg9jFObJ|nz0YP`+z=V&_vng@ zUz{ZzG9u-st^H8rnGlk2&%G{38Hf&u8R38KKR?D=x*0R_IT6q1Iug6lj2B1AYzzUHc##Ehhz(suCKjK zCd9lUaXLlA*M7DWkR;kyZxc8dQe)n_=zfylR&7X8ZO(1XT7jDhrHMEWQWw)xP(S_VbW z#ck*8SnS19u=9bRH~1}gQ+?Zp0~X3LyGYY5!l)|^9E2CD0|Swm2*I2G%MbCAP^M{s z%e!1*hcz$Pw6R55si$RTYS?c-i+E@^`8d>a?xnHb#H=l*J*QH%QwUZAYD~~VyESr8 zbkwfxH}OE!(nisyi114HQZ?R8@QjY)k)bau!E+|WDLf$C^Tkdy$;0&gnd@iycx%kE z$sEAXJ=2lmq{qw?#N2))S-%S-=|{-6E*=8skrDt)?iz)e0Rnwwu^oXGqeG7_O z;g1lyGw2Y+6mp~<@?F5;^R3<+6<=$6=|oCQN*XP4b#!bfxP0aG?4O8Xv}p{3F=7!P zxkWQP6{ubwc zC%ic2L7%HPo$%lCzB>{Ipi0^1bX41XXCD1HbaJ`|769jT5N;o>1iieB1DB z?NGn%yU!- zkX7;LzaF%cS?ij>59*AW1!Qcprk0Bxu3jCPVLJ!sT2wUs%|pwp|8nX&I+2_oT6^_6 zIXUx@qa6xIzW9B-J$m`3j%UTzCxOqP0X7XU#xVQ*9Xyv*HAXihgcg`LW#>Y5sZ;3v z>Fa;eSw{c+`8$+p9h(0#&@f_|WfD@1rh4F53=oJw zQQsa^HLRp7iwls$%WzX95+0!C!Do#yEzx~O>brW8Xy_3V7OsHGiOgf(>7t&_seh7r zd;SnQE^OUMXVSa&lcktdh3i=g9RTsSOxK$wkd1y04r1may?Gup6l1@9_(rwilHRTA ztc_LT2I!-FRV_nIPeAk{k+f5FuD^XN5wX|iIHDXM{5J{|1$g3M5^bl2@W66Z6^H5m ziq?FWy*Qp@Bft(?=mru(C6F-v0RD)$6+%b;m>a>cGhUH>`1Sj4p!Q8x*+G#z@&=zH%cmp$|I($kWjNF(a=n;#p>QU40;9x!PUO)Qrou zLlH;Zuw%YEu|^U>Fk;!_5#2_|hFEHboysMe9}Ji~mv~Ad2WuMxN1Ou@w~%m#`_H}q zT?3v|Z#Wg-y?YQ+pU8W>HSBo!@ZpHv=-6221gW(g1_b2R3TRLo`ufypSA>m$_iLya zbLkD5A#(KoVA>#QynD^~T**{ap2BJifGE)TdiUY(w-(gUAw^x;Rm^Xu&emD-O4#C@ zpQGB^ENE6u135&<9=9xW@SxjJbORSU)Jb6jyJl69GZ$t-^YzWOYEsd5W+;Bo>#}z z%7eWZh$**>$AN)gXmKw=BS@V>m6EcKvB}OaJ5!73G#KxDcnei4IHiUd+DLIidW=vk z>7OvHi}VH9V<*p+yBabiydg+Y<$Hb5q`B|hFi(qUx$yvI%ON1I9PCVwyJ4`(wp~TEm zFfld+;BcY{-K&m{ABYjPea7hW_;3wY;&bsi+)K61aYd33B22{iT~Uz&qTdev<(o54^4{AI?*_}Y%QjmtZLzGtBPcNcbYqks zl!q|HpLzi@%O8oGWq^4h`T>H^4nx&6>L~wl;#4c(Fqd@V$S;(ku2EnD@y|HmMhJ(C zfr+ydL2qK5lSGg)oRC1igfpt9fIET>xFYtC1E0gET+D|iE;^@xGrR~}9?Pm+Fg&nY z=$I7gH4X$qOUFSNS=}>8X!nABr4=7d&>TLcq=B;djU(tKc0@|;JT}1^c6%I2WPN3TLz|;nYU`eIToT7+TR7&E5*#1xH)p zM5nCMVr$FlVgze;LjfUH_}vBd(5nA9+40=mO%y>yT3|%?4h~v=^N!y8X;Uer05gQ; z@(0k~*Mspfm`hEl@bdAc6hosUVDs@Jq{z*6FlP=)5N%K6*a8!Ri_$na5IL3khbYg) z)H`l3S?h4J)`$^a3m={~zV`?wY7ou{)yv8wl2kb5WO>6_aF6MKoVJ29S0v9HW6%UJ z@3?VMGhp^(N%9+m$J>-^irUKt^FKCAWpbSlsM2xrGTd%PDSZrPS-+x)& zDZV?B&?9h<){itb7-Qd`_v=|1xV^Z|H^EfhEJ|3_1aBx8359M}ZOzX``t>C`0G*2% z@|DK%cZ6Ap4C+pVJI5OFHGv^&jbscYLiQ_MXt#apQvx|3qpZ)RrOv+oCnf&h|Cz|w zR^W$&&jMebn5iR9f#SW#@$X0BmWmKY6(bYV2H4Orulj&@O{2`6ftYS$WOsRbe!e;F z--jsNF%oE4euwrK4()iP=q(2y6ap~=D{E42u|lk2f@UAuu^(Ov6dbUUU|_MBsdH?V z0e|N{gu^0%g-7hnXuYSghRxu~5QmE*L~QxxQA5A@Jxy7W_9j;RlhlhQ_z?u(dA2PS z^Zg|&Gr?Diw8E%+KX~s<`0??H7|FE}dpy(p6VqQ14Im-rI;KNxu-&_ljx~n7fdr5A zZv846=c(KY%o2XEiuJyQ&Cw6^1#C+kE{dY4n%XJ`Iq82N>Nx&;45tu%KwTuT7n&av zQt1Dyz4H%hvX0~UGs2vZI)(EQML_CMeol=u4-o~o1Om(z6M;ZTMUFHP0Ywp-gQO`G zbS6ifl2fLs=!vjqOcdsjEEIG?h>OTGU?L_kVncg>ptHaHufMwff#dcE&-1}=Td&oAh&o}(?jesUb9|(Dh>0PA z6GOE{zCF6KoX;fMvkdy;Y@#Z{$xPrpoXHMZ=Hw3=iW-wSzDhpRZO?8J9t}epLfPNw zUh%tUFTzv(50^h*C;u#@3y?=1fF`XyK43UPW3oaK)Zz&&5Q}m|nl;)R>vHO*H^YS# ze7k0AQ$mG8!NcTKx~09Uy9$$38#Ito%o|Hir>!()Vy`=q)o7>riT1I{A?c9}-5Vzx zkODqeQduC=8*`ijjmpixB0vSrUfiq|7M)P@EFIYRPP^JLSZh$b)T475IJ6qKN-VaM zZY@DC6`^YO0^T$8t*u|*F}}0gZ#NRb7%&Y~Juw7{rv2v0S7Q@scKGwkg4@R1I;>!0N! z(=67d-NSZzsRvKo#-jR!OQqiNS^q@5nwZb~l5a)EGR;f9$X5lMZy9P;q+MITOPPm% zRc`Gm^6~1s%VrPcTc=!MS|=$jbyiCtWi37TqPg?2Gay$}CKHM31kXT^`0z z9UZkI!&gIl(q5!S^y#yc9zc%9%oUtV&N;Q3KxXG)wu3>&7Gw|A1CcM?=b7_EU06++ zbYBBuNkg$5%&Ox5{Nq94i_fn{<4KkvO$Emqo*j9$886D2Fxmu$=K=jkSS11`ji*fp zM?m6y9rVW@)A40TmO+Jtfit5WxdhmyuJ@SA|G_$~UzUl{YE0H>D*A#~DAyktxc`2J z>l}7!k4zWQo1DB{;)FCqP>)i1qNx)~Z2-pe#6^pPV_E|9b6*NSswxEL9h)>m>s)&25LCqyN*9PO!M`vSM#1LTyo&uM6 zO>PP_a?T3b5$wN7lAG$Ln6+!?(T2YycOxl@N^Zi742`kX*K&s0)lbHT)>pRKWZ|TVHkQ<9#piWb2U$% z63q>0&zyS^M@56BKQAO*O(NC)`fCeekQE4~*P&tuH*z5bNdJ{T#R-^Nf}STq*BRxP zr1S87Zhq<*tu5?fp_kX~gd zykVgo|8RS1ss;tjF9rk3=uM#iwf%kRVu&X=U1tOz7a2r1UgdKDEBzuI#DqG`pq?NF z>5MuIaK34m-nek3WCbpv!ELhLB1<%2!cfb3yKYaP&U;L-v{l#zo`nUh>```WkH{XBx`!7HI{2wp; z^20y>?VrabfB)r|-~H{EfB&;zfBBzZ{^OT_{mY;I>7V@UPyh0d{>PWU{No>f{^#HS z;cxz;-S$WS`QLo`yZ;qe{P7Pz`;#xf`qi)g!~gyN|NUe6<#*qI`SsuZyYK$@zxtjf zpRf6nFZq%$<$xTJ19CtP$N@PZ2jqYpkOTd4Ak=ic@*_X;V?RIg6F>12Kgj_(AP3}t z9FPNYKn}0QPyUnxazGBq0XZNCC)f7bC+Yi5H7@#%`Qv~?BR~gqKnHvv2jqYpkOOi+4#)vH zAP3~Yo*W2T*VVi9c-;v;U-_={*(c_J0}hP<9nb+C@PQnV19CtP$N@PZ2jqYpkOOz* zKv2HE-lga3PxA2&cb(5Z!5;@48UZ?>13KUXIUon*fE6o2ZHW>^=duecam*8 zU435b#~g6Lp%I`1I-mnSkOOi+4#)vHAP3}t9FPNY;EEgws`u5abbQ|lj_q{Sxvd-X zzyXIwfDY(@4){P0$N@PZ2jqYpkOOi+4#-YW>oZGSY`K=f8zyXIwfDY(@4){P0 z$N@PZ2jqYpkOOi+4#@b)m}OtcY;1U_u^okm{wpfE295!L=Qn<>UUC4-Pmq0(3wJbifC4Kn}_|EU`;3y~e#hh@!p%I`1I-mnSkOOi+4#)vHAP3}t9FPNYU`q}Jr95@7Zu4|L zwv)ZwTp#no0f$C_4(Nam_&^TG0XZNCG@J>&@ zk167SLnA;3bU+7uAP3}t9FPNYKn}{wpfE^ZF z61=K#*f-tzudXsTeb(}sd6`!uKnHX{2Yet06CK(>dnyr+J!ZBR~gqKnHvv2Xf>J+N1Xe2d_WY1s-@b0(3wJbifC4Kn~2112M(pl@G@F;P}MG^t-A~ z&d$mG2vjDps_$1ncV*3<>3#LNJAbGL2OJs!I-mnO-~%~OI|ris>neTRqmQd5XnyDB zchy|1i$G-pawVp>I)};{KGOT@^LBo|Zv^Oo4(NanyNu9YMvj@ z^X@s=4}r=A!b^G*#7ha739nb+C@PQnV1K;LA(5O@Cw~v0aPkfd+ zXXmUx1S%7lB`2ICRCpDK${OF(`&Im`d#yh4#kUcl13I7sK9B=7av-{_SLy4RzOqkx zmAPi0gZ_>YIIG`dyRLiJS>Ems?X1FK6{oB+Pv>0AzvgY;jQ}0c0Uhwcs2m9Q)vcqr zRoyrHq^ol6-FNmm&E8+{dG1|rcD}vOx0kQ$V*;yk=&ir3>#aIp=U&_2=5PLu03FZ) z9q_?bIS}ruU$5db%evVoJPYTm&yjtOS^B$r4p*Wc90+&LQ?qg&-BE)bW@WZbWpaVLf13r)gbLT*uZk@V{o~ulBm3cVl z+&Oype5?3-RG)Xx!+vx7dz6kx?Mu&d>)CwGw-KNNI-mnSkOTX2Ag*4w&Z?Ix6P=a6 zbM4C^ypHjz;`32`($z6t;r21NQ92&AFCBcW16*)v1n7Vc=ztI8z?wM_r&b>Xs{7z^ zj_j}1IqN?ZhQnA6*?m5`Kl&W2&sq78*7e={&pJovk`Ijl9nb+C@PQnV16y(+D5>f^f*qA)C*$^h39~bz6NtS#*9^AJylje|gXd&;cFL0UyW#IdCKg zf||OOKvth^?SJ%jS^4QJlz~HS4x{~@b$`09t?TUb%c}dU`^r8S{qcPxKnHX{2Yet0 z&+I<9s=uuB&==n~0(3wJ zbifC4Ko0cCfuN}NB5=1ad-Z+SI(PH2UrZKni*3L0=y{&mG?%^L^&C%6mHa zu@3OSqY^I#sP;$fDY(@4)|b}90)h7cM<5No4fk$wNI~eTPG%h z0}hSARviQ_bt{3bT&rHUl|!%Vs&eYxcQ2mR*6Gc0>w3?ew%+HuAcq4EjQ}0c0Uhvx z9EcoH#}YWI!?9iO-~H%0-50EJz@ZW7rGucU?j_KR|JCd4J=a~=Uw!Us>)*va+dfy# zY3n(!+TXe{0UU5>1n7Vc=ztGq&4F;YnuWkSon`5BYaj2<RAGJ z&Fitx*?zO!|2WU;uUY0Xs*j`dKiluoecc!2aloMwpaVLf13p+S2g3DgRszp@%-ZL> zzMjwFeGtO|helwO4uZbgo50a|_U@y~dPjN9c3+iwUDfBSdEUL>t3G@llfVIoMt~0J zfDZUz)f@=-s|Z{}U{zl^cjyU+8XT^1zf}>~M?hZexsvq2E~4t-O=Y6zSouv!kCqvh_i1Xk0V^M+z@z@ZVK13I7sK6sY{ z;Sv>rz69Rs&iBC^2OJuKtU8G4s0idBkku!>`^rIE7rp0dz0ed6I5YxuKnHZd2UT+* z+^Ztchd@;y=sV_*0}hSALkB@aMIaY}hdyU}%|%%^v+2uuLen_l&;52$0}hP<9nb+C@Iloa z2=}T8^dV5y2l|fr^~66@kwQ+@(kR#2j$Ip%KWUgP4YjKu!W#eDbc3ob+_HmB73C`aVeFfI}ld z2XsIOd@y?sgv(U~eoSC?-8)~*8wVU3fmb>RIw}IW3B1zp=+ARg)7@SIqxEF}m>3Q? zGy-%$2Xw#(qjMl!s3H&qM(ff3=FkYx!B`!{?kWN`2xQ5N8nkqIlt31p=_4kH0}hP< z9nb+C@WH4Y2=}S05*VdB`-b9hz@ZVyrh}M@ia-qlqy1BZk}l5@7_Bq=#{_Y}p%I`1 zI-mnS7@Y&*LUk1aqxEM0P#O+6Gy>Ul5K~bRs6k+qe`?UtWp4tb^k(0fBn~(<0(3wJ zbifB$avG}dU5_HrTYuJzN#cM*BR~gqKnHw~ zJqN<2YBd7cb)~;h6b?8v0@-vBQ&AD9NuZaXYMx%#*$DK~qjh4kIN;C-&;cFL0Uu<~ zfpDpsoj`US=`R$70}hQqb{)i&R0L`gIP0&Pr`C0L0%vvU{+KWhI5YxuKnHZd2ibEV zT&iXxkX<+W3&r4oLnBZ{2Qe)b0R#|0;3@)Deh>5+3OLH)D*ZgKd$d3IotrOy_%#A_ zKnEY`AgHLb5a9EeBn~(<0(1~MP!T`?0R+Yp@Ou>eXW{TpO|Q=R?!K+xzgpktbLq@H z&9f1pgIqd@Zq(HY@MSJvnumEb0%vs)6jcNeKmdVk1kUEW`(vVab9kqtcm2G(|LFJc z_VxW3z2J^}BR~gp=pas^B5;m?JP3X`;Lr$U(Lqc@MF0T=5U4^R%kPIiLNU)A-s$N1 z`d9DYt<(GaSAF>W<2mDkOCvxBbnuZ5f{Kd37y@!BxZ{9BBhX6+K~qHl0R#}JPN3KC zf^|X(XF0sn)7JIht#kGFTl;ifAKl=HVifOtaQ(eH#2fEMfDXp$Aa+*~Sc8DPi8y!u}fB*uo2>4wOGQByx;{E*j-hH3%&-#Avxm+KU!~us!fDY!;L7YZK0D(qem3(_Q z?NvC;a?W@2^gRLyAb`M{1ZMf28-0#<>N(oqyLGdFfArk$i^<}ELnA;3wR8~Ost6#^ z2+W#ay{9`Xr)uZwJy+`?fB*sr%uV3&J9qUdANy2)-OB0cIk&D~<+`IB+!qtZ0f$C_ z4sz=tx>FHA;9COKbL-o)-1+C~+^Y0{=S=N|00IagfWT1#Reo2W``mio=lk})-?~rr z>-KVSeM}q&92x;S$fbkmMnwRDZwXY(sc(DF{O4+1v-O*Kwt7PV0R#|0;2nW%zpJnM zd3TP-_pk2X`uSs>)n2#qaa||_2OJs!IvA^i*j+^cfzJqJ&8g3NuJ~P6&RP1ZI8!|% zfB*srAn=YrmfzV&AMg5o{{C^_(bwnoR)2q#qx(WRIN;C-(7`o2h*ebt5crHhmi+mw z#}&TIGKahSSYfu#hyVfzAb`N#zpu~x?VZ5${YT&L-FLO?k8*WiC<1n$nAEj_tr-robWMF0T=5I|sM0@?rG)vLdiXT0a^y?9$EsN;Y`BR~iHbP!jo z2q3V9z}5M(r3csSCvf%Ldau9#gzi890R#|0U>*X!e^=kFca+?_b@zUMw2xKpd+>am z_wn9q5WxY5Mt}~k(Lt=LB7ndV0=;tS$lmVhN1)dnd#%&&WL81|0R#|0pbmjvzoUEC zIZJ5oep|0U+t;l3Z{_E@Pyh}%Gy-(cM+dQriU0yf2pr9!BYU}L9D$>A-h1D;6WSR8 z1Q0*~fpG-({$BRJ{_M$n_w&5o+5Tp`{}rF-&%KYyw%ztfNJxU1jCJ|B0n z-lq>9&#w;>&!2lAWN^Tt5x80hLHYW9u0F@}`j2yYMF0T=5I_I{1Q0*~0R-+Q@cevo z*ZZ^QysOVw`<(56miu4v@p()b2OJuKyLAxM@89?8b3V@H6#)bgKmY**5I_I{1Q58J zz}3$?&+GR(-}Abo-uF6B)pcHRf1Kyl_dX9oIN;C-^wL4l{91dhn`ND^C-Wx+5I_I{ z1Q0*~0R#|0;9dfEJs0&l)m{DW-KW?2s;;w_m+NEFIN;C-oYg^4{As;v-N#O6*WY{p zV_&ZbAbikvK%{CAHgmQ40lf%1QI6L=u>!1C8Ykz0=aX$hGAbDT#o<( z2q1s}0tg_000IagFowX{=f5oXkD)hi*H_#h9liSA=RpVu92$X#4uZ!1`ndn>>;9eH zfdB#sAb+<&KmY** z5I_I{1Q0*~fqMw_dj89{&OP+T@A8WKqqA4v`#cEYur`N>PmaF!($CTT-G=}I2q1s} z0tg_000Iaga1ViA&wtt0xrbh!U9$1lPiO;&oE&;Nx7U1o^a4(16&h0h7-hEjQ0R#|0009ILKmY**5I~?0fnLvj z)z;}lFaIjfb9r?9{JHl*28X#hJoMlDwU=&s_hmf<5I_I{1Q0*~0R#|00D(RPdOi15 zU8fJlysK25i@rlsIP~FgwL^Q&>FPeMj{pJ)Abzt#P_wMI;JUV^;-1{JdLv9Wa z{f>G)tB+BA+ZO=@5I_I{1Q0*~0R#|0pf7>5&xh6T?@Ke!YSrhW|IpIv97a3pDF4xY z+aCc05I_I{1Q0*~0R#|0pf7==&xf4tJ}j*ZCfO_gc?7 zWAumn$J`(K_KE-k2q1s}0tg_000IagfWSutJWmIet2unce#B>2pVRvH=n3a*IFIn8 zJrO`)ZUXW;=8FRkjQ}0c0Uhvx95|K(ahE!p0R0}*?^bT3=lg2^t^K?1T7BS~lkY3v z_#6QQ5RluU0UU5>1n7Vc=ztI8z`Z#TyQ!lI(0yOskDlk={m;(-vESKs+}~G+c%I|= z(6v_t5SW*MoQ&DxfI}ld2XsIOd>{vM=RkC)W+A{Y=lqgojz{}2|8w)lZ%%$k{p3Cb z5V)U!91i9<;Lr%r0Ugi*AIO0@b0AKoW+A|5`+SyVZoT`UgMB){Yi?e>{bfA_5O_~O zt_C98KQqqkik{Bu;L+3Bb=?2C9`U({&qL2%5kO!+ z0XY@SaKNDvpaVLf13r)ga^Or31U)qy0ltojJUC>V&)xkzIC%ZBF7Q~3$KAfO9|9E# z$iP4psQvh!1pncXAarsG^(FxE?eI}`rUfH>ps>YF86YI z=+-L&2>g_QJPIZ_;Lr%r0Ugi*AIJeYa7PXVWi=ZC{*Q^g;*f1#clYy(i_bsT4L&vb z-0d&>Ay9#UJc}vefI}ld2XsIOd>{wpz#Tadl+~;RIySuMfe0=`7e(-lr z+{&T)yhr!Hm9y*i=@PHe%CO;Mc_UHd>*WEz@ZVK13I7sK9B=)pkfZh)YR$(13KUXIWTt)#Oc&o2=Hqkzs{nEv*)0v zK6=7&8^^PHbw2_b2=IGM0S6o!0Xm=qI^Y92AO~j5ftac~3jsM5lRV2|7Cjt2$60>v z@1w(2I3Crh`w+-LU=^P_XQ&Ma92x;SpaVMK139o}4#cU|*$D7+A3x8gi>>FOpFaA* zaT~|2x^x`^842)tOa%uV8UZ?>13KUXIUomC$bp!$IvWA`6%*~nVK#ldI!`ZN*6FLi z*?GRwqt6k@Okj3jI$x*{2OJs!I-mnO-~%}z2ZDgQ0s(&SaGPzRA>x}>% z&;cFrfgF$na^Q6iggVq!3CPEod@l}Fbkys-*6FLC)p%C%i$2#Pu$m8@SB^IVbU+7m zzz1?b4#aZw`1hQD@x!kXpaVLf13r)ga$w~gi0P{cd`v(-2A8uO zKBjy9r)T?if1ml|c)ix`fWSKfd>Djqz@ZVK13I7sK9B=)Kn@(wfl!Z%z{dpSYjEks z;bY4EKke18b^6YKb)Nl|Zbby%6Ik7M&L0}V0f$C_4(Nam_&^TGfipP}^i%{sCm?5n zPcIIi(?0)guRg8QckZk6Jg;mkAh4al>V9+n&b(BJeo@ zxf6VParm6}@o#(eXPv(DUY+N0MY|J${RCF`oAZZeaKNDvpaVLf13r)ga-e4p1Wgrz zeFWrC@an~3AN|)?_v*(wedmkkYt8xwf!+l8Er{ZPLnA;3bU+7uAP3}t9O$0|p(+)D zeFWrj@an~3AN`+R-K!7l^qni7Kh>&F5a>;S&w?lpI5YxuKnHZd2Xa6T$bsu~AXKIz zu#bRz4qm-D?4$qn>R$U>r|&%R{HjrZLLdtPzKluWfI}ld2XsIOd>{wpfE?JL1ECrf zfpY}pZ}7tbhelv^9fS&01m+^Jy04u-^o#=zjQ}0c0Uhvx99TOC;`Ay4=LpD=;D-Ya zjlilpi0P{cAn+}LRrA2PLj^eC&7%(Vy{B`{j&_K(TofI}nj&_U2p5kLR|1Q0*~0R#|0paOx% z-{ZZ;v_^5LpcOsVCooFi_8prq_~+tZKS`Vb0R#|0009ILKmdVt33$GW*^lP1t^%EW z1cA|dw||b@F^7BSFv9EhL;wK<5I_I{1Q0*~fj$I0KLy9p9QsVtDhTW&Fk1Kak9pxR zH-~+$bTtA9Ab>qll&f!_rcc15ZfA0}M z;Jfec_M!bkbvWSA2+#o?&;cJj=RmkZy^FvzfA53*-5l)Ld5Xv~j?p z5ugJ)paVXrngiip^%a4tbDgd4SM%xp`Dkvv&ttu@1V-!0{xSb59PU=@J1%$kV?P8c z5P0Vs-^Ubjz@ZVK13I7sK3FXW!u9HEbI*F-vr5c*uIIkap40tf2|Ul!`w z=BxB`kA7C?JfCysJkjbpb^ed@ za89*56#{b;kY_Pp9B^m^=ztFBfDh!rm>h^*=d1KIMo+78pU*jSoM<&2I`6i;n?v1B zfxwys*&bck;=2ExQAg~qz zIT!QB0f$C_4(Nam_&^Ti%7N%+o=RW2^fl`|=5b8zlgz3w=Q@^SwbiV91Q2Kh@VXAP4g1K&W$`DsSY?m3cFdQ)-`t&-r|h&ugn)_Xx~QK%U2ZaloMwpaVLf z13r)gHF6-joTt)V4c%3p(>zY8d6KHS(Ra>Vs_6nJ^jCFG^EoE>iK^;E-?einw<~mqKurR2G3JH?4vhdE&;cFrfgGrr1JU(7 zl@4p_u*%%#aY~JoRMCY#*UFt5?$IRzxd_O~mZI3(vuvd>?Ca-|VCs)L-a(-i{O5IE`+_r*MLz@ZVK13I7sK9B>sb0E5#r_x() zy;YshJPyfqlB#;px14DN_Ua&)`*edq9|C)Q;QHW>0}hP<9nb+C@PQntnFG;v{Yrl| z^_P8a^_`LH1li}UKRMC}^wvQx7wQIqJ_LIE#CkCo9B^m^=ztFBfDhzA?i`5j>Q_3; zt+T50sqc&&C#X7qean?b;H(aExKI}eoFj172ksC4IN;C-&;cFL0UyYL+Bp#2*ROO~ zTZdWaSKk?9PLOq;`jQikz}-3+<3hV4(1*a?ez9N74F?<=0Xm=qI^Y92kTVCOtNN9` za_Xz13KUXIgmRCqPx14 zzH;lU+I;Fd;oi=x%~ij0q7k@D2lu+sZU}56aF_n=6Z60Uhem)7=ztFRKn~2A197Ul zl`iMh<*2#Vb;3QJkD7~p`MeRRqJw+fXqQz9RPlj6L!mg}&AWl)g z(&HR@96iVSPPpd;qvvFQes2V_>fjz1+GQ33S#_+hP#6w4Gy-%$2Xw#(azGAzn*%|k zex+-={#MsV^-$jl_nhD;U-$8851(e&(LFA-OEv=8b*aBl3=TLn0(3wJbifC4Kn|SA zfuL8n(m(y5(f_l4>N?@x&Y!t?&xbvISY1!|y3uaE2~^jg{zDNs;Lr%r0Ugi*AIJeY za77LT)w-20_@aj|>N;Rd=X}R^J$yHtj>fpruCEBprZ4A-N#lS+BR~gqKnHvv2jsxW z90>Y#EC29M5C7D4z?jbYj_-Q-ZZ;i_apU~E&ZZORk)QI@^S>OB19CtP$bs595Z%|U z^jBMdqvuyw`C~gDJvaOFeIt-X2V>nh|L$4ltdGzd4mdOdbU+7mzz1?b4y>F5G5va# zZ~3-|Z|f;PN5}lfe?9y+i;i-*a=tER(T8)$OL^(v8{~i-kOOi+4$PGUahiIS4(HP0 z-Se!c_*@;|Jumz5dn1rd2f181PdC}-te?;p4mdOdbU+7mzz1?b4#MvazGBq0XZNC=FEXORlQ1&bL#P~xzDCoyw`H&Bf_^`Te za=Wr#ch&Wve>u2f4$?i{)4hK;lLK;K#w+y9hkUrlht>5`!IPDGtgZ+B z%fFTKkKXB>-u?TT9FPNY;A;+q8tPR3<=-Rzt)uW-o$@0;9`R#U-PCet-fpYTU*Ga> zrM#nedZ+iV&&&M45B$In&p8mTs8gT&_g=1T$+bEPuhl94@!uBz&7zZ9?#$QiEIM!w zxwlg8(L24D<2~$N@PZ2Y#9Zp^E&KfBE+_|K?ZloE`EdUw-Dx>iU?|wfCK>`uz1T z-)7D?`lfIC{^@fuU+@KA@Ws{~2)E>~ThHUVwel~&a_8=l-`4WmYV)4kz1N>^HN7~m zJZuE$fDY(@59ELxkOTAQK&U)_l}GX@ze?BZkT3bN5tvN}>p8jaiD%P;^MpQdz@ZVK z13I7sK9B=)Kn{ckDpY=5)2|h@xpI$uxu!2?pZm(5K6Ccjb>V#St`VREI-mnSkOOi+ z4#{wpz{ng3`gtpV z)bvMQMd|Dc0(@H2r{;Er8?1@IH3axIxZ;3ABR~gqKnHvv2jsxW90>Y(D}U7RM_vW# z><$8aTEnO2^zoeT@Q6JSI7@(kgCGt#Gy-%$2Xw#(azGA@%z>bvxAI3$f8OK_$04Fbe4etpXTtX zIqaK52Jh$rfp-M>Itbx_LnA;3bU+7uAP3|?h8&0~mY&y4vhdE&;cFrfgF$n8FC<|kgxK`7=Pqbf{rQ>;MXyJ#r+uf3ZBv< z0uKUw9wczUp%I`1I-mnSkOOicLk`3g@>Tx0#~=A7ucL|t`1KyY;@pRGMUUxuT>^aH z$M-nm*a*-89nb+E$N@RfBL{+FzDnQM=sVw}buKp4-z=w&S$&HeA~yj)j7_rac4u|ZUWWwK>wi_9B^m^=ztFB zfDh!r961oD$XDs>n7;B&Qb#Kh;M-%qy^7mP+H+O}W+iY{K3F#tg98qY03FZ)9q@r1 zkOO;iAZX>Qbi7T+`6j2Ml?m|e$G%-z6V8qR0_OH%4vhdE&;cFrfgF$n8FC<| zkgxK`=l;kyF&!aL=Xc$#5I_Kd>;(KhC?%~R!BwR0I$};5>m*zcc4Mw*mqPAdrK=s2sI#%pV6F8UZ?>13KUXIUol<%YmSyB7gt_ z=Ly{Xdvm^HDoul@P`Qv~?BR~gqKnHvv2jswKIS_PI1Q0-=AA!4mclvc~ zB?J&aAQyqVa@0OCcN}nN1n7Vc=ztI8fE?J813^he009L05xDyIr(dU5LI42-auT>Y zN39=o#{q{%fDY(@4){P0$bmgM5VTYT5I~?GfvbLp`gLd}1Q0+VCxNT-)4DNl9B^m^ z=ztFBfDhz=95|B$K~F^h0R;LH=>5CYuQMwlfB*uy3G~iS>&3irz@ZVK13I7sK9B=) zphpe_MHK-A5a>ss*Y8umj;w?L0tnO~&?`T!6Z6Iahem)7=ztFRKn}=(o;eUSRRj<~ zpdW#=zf=7>u@V9ZAW)0I+5B{W%o_(B8UZ?>13KUXIUonF$bq1$B7gt_{RkZWz3SJ2 zl@LGxftm!4=BN8&-Zs~qEGvy9u+`Tid$czK2q2J|z}6gfT}%-N z92x;SpaVMK134fEGUY%_<9MZKdj3q$$Cc&I3RPAz0&I*y>3^QD>D+<>-UUj&=Ud(Adr#3-h6d^Oc4hh8UZ?> z13KUXIUol{tlL2;Lr%r0Ugi* zAIJeYaAyt#?XQ*o=&z^#zADR~DiYY62Nln#X9N&HAOnHDdF%R^8V)!#0(3wJbifC4 zKn}{wpfEC;($XVKnHX{2Yet0`fup(X zzL+o$I5YxuKnHZd2Xa6T$N@Q!H3!0-Y83)!byVe?`a}Q$1ga7^o73)($>V@SBR~gq zKnHvv2jqYpkONtAAl#@{A#heVRnDnT1Q0-=I)Sr!?fy^z4mdOdbU+7mzz1?b4#)vH zFggdqg=!T7XZ2F$occrn0R#~En84ZJ0rv-29B^m^=ztFBfDhz=9FPNYU~3M9ThuB9 zw$Am{byd!(PXrJ^0D+tYUj4rKJm!T14vhdE&;cFrfgF$na$vq32vw`u3G~X}?B~=U z0tg_000N&8==FPOouG^Z4vhdE&;cFrfgF$na^QUqgi6%x1bXFJ_H*hF0R#|00D;T| zdi@?-C#H-84vhdE&;cFrfgF$n6>=b^q-H13D^IeYQ-25`fB*srAn=+%ufGpiCm7>^ zLnA;3bU+7uAP3~YmK+F5YIXv>{G9!q`a=K#1Q0*~fxHBI{e8qbF=HHXXawkh4(Nan zpAs>00IagfB*srAbHKZxTn2Zz1>aXkV(3G~j9p1oNM0R#|0009ILKmY**5J2Fk z|DR0n=Q!(y%5XTxfmacjk-$~CFe58xLI42-5I_I{1Q0*~0R%=8xa#@Mx-r#NIE>V= zy%DHN;HrG6%0u4>Abz^+5I_I{1Q0*~ n0R-kFaP)c2ee-F-i4e#_K)%Ez-gEeepa0X$zI^}X*T49G4O~+e literal 0 HcmV?d00001 diff --git a/robowaiter/algos/navigator/map_4.pkl b/robowaiter/algos/navigator/map_4.pkl new file mode 100644 index 0000000000000000000000000000000000000000..54890954e6185ee05c32644808895301f6ae1c65 GIT binary patch literal 876114 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 h_sY@Vuf^Fp2z*Rn^tsuu|2N0;&>8>$ literal 0 HcmV?d00001 diff --git a/robowaiter/algos/navigate/map_5.pkl b/robowaiter/algos/navigator/map_5.pkl similarity index 100% rename from robowaiter/algos/navigate/map_5.pkl rename to robowaiter/algos/navigator/map_5.pkl diff --git a/robowaiter/algos/navigator/navigate.py b/robowaiter/algos/navigator/navigate.py new file mode 100644 index 0000000..a9d37b4 --- /dev/null +++ b/robowaiter/algos/navigator/navigate.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 +# -*- encoding: utf-8 -*- +import math +import os +import pickle + + +import matplotlib.pyplot as plt +import numpy as np +from robowaiter.scene import scene + +from robowaiter.algos.navigator.dstar_lite import DStarLite, euclidean_distance + + + +class Navigator: + ''' + 导航类 + ''' + + def __init__(self, scene, area_range, map, scale_ratio=5, step_length=150, velocity=150, react_radius=300): + self.scene = scene + self.area_range = area_range # 地图实际坐标范围 xmin, xmax, ymin, ymax + self.map = map # 缩放并离散化的地图 array(X,Y) + self.scale_ratio = scale_ratio # 地图缩放率 + self.step_length = step_length # 步长(单次移动) + self.step_num = self.step_length // self.scale_ratio # 单次移动地图格数 + self.v = velocity # 速度 + self.react_radius = react_radius # robot反应半径 + + self.planner = DStarLite(area_range=area_range, map=map, scale_ratio=scale_ratio) + + def validate_goal(self, goal): + ''' + 目标合法化 + ''' + return self.planner.map2real(self.planner.real2map(goal)) + + @staticmethod + def is_reached(pos: (float, float), goal: (float, float), dis_limit=50): + ''' + 判断是否到达目标 + ''' + dis = math.hypot(pos[0]-goal[0], pos[1]-goal[1]) + # dis = np.linalg.norm(pos - goal) + return dis < dis_limit + + @staticmethod + def get_yaw(pos: (float, float), goal: (float, float)): + ''' + 得到移动方向 + ''' + # return math.degrees(math.atan2(goal[0] - pos[0], -(goal[1] - pos[1]))) + return math.degrees(math.atan2((goal[1] - pos[1]), (goal[0] - pos[0]))) + + def navigate(self, goal: (float, float), animation=True): + ''' + 单次导航,直到到达目标 + ''' + goal = self.validate_goal(goal) # 目标合法化 + pos = (self.scene.status.location.X, self.scene.status.location.Y) # 机器人当前: 位置 和 朝向 + print('------------------navigation_start----------------------') + while not self.is_reached(pos, goal): + dyna_obs = [(walker.pose.X, walker.pose.Y) for walker in self.scene.status.walkers] # 动态障碍物(顾客)位置列表 + dyna_obs = [obs for obs in dyna_obs if euclidean_distance(obs, pos) < self.react_radius] # 过滤观测范围外的dyna_obs + # 周围有dyna_obs则步长减半 + if dyna_obs: + step_num = self.step_num // 2 + else: + step_num = self.step_num + path = self.planner.planning(pos, goal, dyna_obs) + if path: + if animation: + self.planner.draw_graph(step_num) # 画出搜索路径 + next_step = min(step_num, len(path)) + next_pos = path[next_step - 1] + print('plan pos:', next_pos, end=' ') + yaw = self.get_yaw(pos, next_pos) + self.scene.walk_to(next_pos[0], next_pos[1], yaw, velocity=self.v, dis_limit=10) + self.planner.path = self.planner.path[next_step - 1:] # 去除已走过的路径 + pos = (self.scene.status.location.X, self.scene.status.location.Y) + print('reach pos:', pos) + + self.planner.reset() # 完成一轮导航,重置变量 + + if self.is_reached(pos, goal): + print('The robot has achieved goal !!') + + + + + + +if __name__ == '__main__': + + # 根据map计算并保存cost_map + + file_name = 'map_4.pkl' + if os.path.exists(file_name): + with open(file_name, 'rb') as file: + map = pickle.load(file) + + scene.init_world(1, 11) + scene = scene.Scene(sceneID=0) + + navigator = Navigator(scene=scene, area_range=[-350, 600, -400, 1450], map=map, scale_ratio=4) + + navigator.planner.compute_cost_map() + + file_name = 'costMap_4.pkl' + if not os.path.exists(file_name): + open(file_name, 'w').close() + with open(file_name, 'wb') as file: + pickle.dump(navigator.planner.cost_map, file) + print('保存成功') \ No newline at end of file diff --git a/robowaiter/algos/navigator/readme.md b/robowaiter/algos/navigator/readme.md new file mode 100644 index 0000000..8a7a61e --- /dev/null +++ b/robowaiter/algos/navigator/readme.md @@ -0,0 +1,128 @@ +# D_star Lite 机器人任务规划 +## 目录结构 +### 坐标离散化 +`discretize_map.py` + +### 地图文件(选择缩放倍率) +`map_3.pkl` +`map_4.pkl` +`map_5.pkl` + + ### 导航类 +`navigate.py` + +### D_star Lite 算法实现 +`dstar_lite.py` + +### 测试文件 +`test.py` + +--- + +## 世界地图 + +### 实际坐标范围 + +`X: -350 ~ 600` + +`Y: -400 ~ 1450` + +### 5倍缩放后坐标范围 + +`X: -70 ~ 120` + +`Y: -80 ~ 290` + +### 网格地图 + +| Idx | Obj | +|-----|------------------| +| 0 | free | +| 1 | obstacle | +| 2 | dynamic obstacle | + +### 代价地图 +| Cost | Obj | +|---------|-----------------| +| 0 | free | +| 15-10-5 | obs周围3格 | +| inf | obstacle | +| 100 | dynamic obstacle | + + +--- + + +## 参数 +`机器人步长`: 150 + +`机器人速度`: 150 + +`机器人观测范围`: 300 + +`行人半径`: 36 + +`目标判达距离`: 50 + +`机器人移动dis_limit`: 10 + +--- + +## 使用方法 +```python +# 选择缩放合适的地图:3、4、5 +file_name = 'map_4.pkl' +if os.path.exists(file_name): + with open(file_name, 'rb') as file: + map = pickle.load(file) + +# 初始化场景 +scene.init_world(1, 11) +scene = scene.Scene(sceneID=0) + +# 舒适化导航类 +# (需要传入:场景、实际地图范围、离散化地图、缩放比例) +navigator = Navigator(scene=scene, area_range=[-350, 600, -400, 1450], map=map, scale_ratio=4) + +# 设置目标 +goal = (0, 0) + +# 导航 +# (animation: 选择是否画出导航过程) +navigator.navigate(goal, animation=False) + +``` + + +--- + +## 可靠性保证 + +`目标合法性保证`: + +- 目标在地图外:重置目标为最近的地图内位置 +- 目标在静态障碍物:从当前位置不断向外圈扩展直到找到合法位置,重置目标为该位置 + +`规划sbgoal合法性保证`: + +- 规划subgoal被动态障碍物占据:重新规划路径 + + +`起点合法性保证`: + +- 起点在静态障碍物:从当前位置不断向外圈扩展直到找到合法位置,重置起点为该位置 +- 起点在动态障碍物范围内:缩小动态障碍物半径,保证起点位置为空闲 + + +`机器人朝向保证`: + +- 机器人始终朝向每一步的移动方向 + + +`规划抖动解决`: + +- 规划路径不允许有重复点 + +`避免机器人沿障碍物行走`: + +- 障碍物扩张:在代价地图`cost_map`中,静态障碍物周围的空位也会受到影响,并产生cost diff --git a/robowaiter/algos/navigate/test.py b/robowaiter/algos/navigator/test.py similarity index 72% rename from robowaiter/algos/navigate/test.py rename to robowaiter/algos/navigator/test.py index c27eb1b..92c3883 100644 --- a/robowaiter/algos/navigate/test.py +++ b/robowaiter/algos/navigator/test.py @@ -1,22 +1,19 @@ import os import pickle -import time -import random -import math import matplotlib.pyplot as plt import numpy as np from robowaiter.scene import scene -# from navigate import Navigator -from robowaiter.algos.navigate.navigate import Navigator +from robowaiter.algos.navigator.navigate import Navigator + if __name__ == '__main__': -# def navigate_test(scene): - file_name = 'map_5.pkl' + # 选择缩放合适的地图:3、4、5 + file_name = 'map_4.pkl' if os.path.exists(file_name): with open(file_name, 'rb') as file: map = pickle.load(file) @@ -24,21 +21,25 @@ if __name__ == '__main__': scene.init_world(1, 11) scene = scene.Scene(sceneID=0) - navigator = Navigator(scene=scene, area_range=[-350, 600, -400, 1450], map=map) + navigator = Navigator(scene=scene, area_range=[-350, 600, -400, 1450], map=map, scale_ratio=4) '''场景1: 无行人环境 robot到达指定目标''' - # goal = np.array((-100, 700)) + # goal = (-100, 700) + # goal = (590, 1370) + # goal = (290, -240) + # goal = (-200, -200) + # goal = (-200, -50) '''场景2: 静止行人环境 robot到达指定目标''' # scene.clean_walker() # scene.add_walker(50, 300, 0) # scene.add_walker(-50, 500, 0) - # goal = np.array((-100, 700)) + # goal = (-100, 700) '''场景3: 移动行人环境 robot到达指定目标''' - scene.walk_to(100, 0, -90, dis_limit=10) + scene.walk_to(100, 0, -90, dis_limit=5) scene.clean_walker() - scene.add_walkers([[50, 300],[-50, 500],[0, 700]]) + scene.add_walkers([[50, 300], [-50, 500], [0, 700]]) # scene.add_walker(50, 300, 0) # scene.add_walker(-50, 500, 0) # scene.add_walker(0, 700, 0) @@ -47,12 +48,13 @@ if __name__ == '__main__': scene.control_walker([scene.walker_control_generator(walkerID=2, autowalk=False, speed=50, X=0, Y=0, Yaw=0)]) # goal = (-100, 700) - # goal = (-300) - # goal = (340.0, 900.0) + # goal = (-200, 700) # 目标在障碍物测试 + # goal = (-400, 700) # 目标在地图外测试 + goal = (10000, 10000) # 目标在地图外测试 + # goal = (-220, 300) + # goal = (-280, 400) + # goal = (-230, 600) - # goal = (240.0, 1000.0) - # goal = (340.0, 900.0) - goal = (240.0, 1160.0) '''场景4: 行人自由移动 robot到达指定目标''' # # TODO: autowalk=True仿真器会闪退 ??? @@ -62,7 +64,7 @@ if __name__ == '__main__': # scene.control_walker([scene.walker_control_generator(walkerID=0, autowalk=True, speed=20, X=0, Y=0, Yaw=0)]) # scene.control_walker([scene.walker_control_generator(walkerID=1, autowalk=True, speed=20, X=0, Y=0, Yaw=0)]) # time.sleep(5) - # goal = np.array((-100, 700)) + # goal = (-100, 700) navigator.navigate(goal, animation=True) diff --git a/robowaiter/behavior_lib/_base/Behavior.py b/robowaiter/behavior_lib/_base/Behavior.py index ccf6c26..1bd0182 100644 --- a/robowaiter/behavior_lib/_base/Behavior.py +++ b/robowaiter/behavior_lib/_base/Behavior.py @@ -13,12 +13,12 @@ class Bahavior(ptree.behaviour.Behaviour): ''' scene = None print_name_prefix = "" - all_place = {'Bar', 'Bar2', 'WaterTable', 'CoffeeTable', 'Table1', 'Table2', 'Table3'} + # all_place = {'Bar', 'Bar2', 'WaterTable', 'CoffeeTable', 'Table1', 'Table2', 'Table3'} # all_object = {'Coffee', 'Water', 'Dessert', 'Softdrink', 'BottledDrink', 'Yogurt', 'ADMilk', 'MilkDrink', 'Milk', # 'VacuumCup'} - # all_place = {'Bar', 'WaterTable', 'CoffeeTable'} + all_place = {'Bar', 'WaterTable', 'CoffeeTable'} # all_object = {'Coffee', 'Water', 'Dessert', 'Softdrink', 'Yogurt'} - all_object = {'Coffee'} + all_object = {'Coffee', 'Water'} place_xyz_dic={ 'Bar': (247.0, 520.0, 100.0), 'Bar2': (240.0, 40.0, 70.0), @@ -28,6 +28,11 @@ class Bahavior(ptree.behaviour.Behaviour): 'Table2': (-55.0, 0.0, 107), 'Table3':(-55.0, 150.0, 107) } + container_dic={ + 'Coffee':'CoffeeCup', + 'Water': 'Glass', + 'Dessert':'Plate' + } @classmethod def get_ins_name(cls,*args): diff --git a/robowaiter/behavior_lib/act/Make.py b/robowaiter/behavior_lib/act/Make.py index bc58583..a730820 100644 --- a/robowaiter/behavior_lib/act/Make.py +++ b/robowaiter/behavior_lib/act/Make.py @@ -14,11 +14,11 @@ class Make(Act): super().__init__(*args) self.target_obj = self.args[0] self.op_type = 1 - if self.target_obj=="Coffee": + if self.target_obj==self.valid_args[0]: self.op_type = 1 - elif self.target_obj=="Water": + elif self.target_obj==self.valid_args[1]: self.op_type = 2 - elif self.target_obj=="Dessert": + elif self.target_obj==self.valid_args[2]: self.op_type = 3 @@ -28,12 +28,12 @@ class Make(Act): info["pre"]= {f'Holding(Nothing)'} info['del_set'] = set() info['add'] = {f'Exist({arg})'} - if arg == "Coffee": - info["add"] |= {f'On(Coffee,CoffeeTable)'} - elif arg == "Water": - info["add"] |= {f'On(Water,WaterTable)'} - elif arg == "Dessert": - info["add"] |= {f'On(Dessert,Bar)'} + if arg == cls.valid_args[0]: + info["add"] |= {f'On({arg},CoffeeTable)'} + elif arg == cls.valid_args[1]: + info["add"] |= {f'On({arg},WaterTable)'} + elif arg == cls.valid_args[2]: + info["add"] |= {f'On({arg},Bar)'} return info def _update(self) -> ptree.common.Status: @@ -43,16 +43,20 @@ class Make(Act): # self.scene.gen_obj(type=40) - obj_dict = self.scene.status.objects - if len(obj_dict) != 0: - # 获取obj_id - for id, obj in enumerate(obj_dict): - if obj.name == "Coffee": - obj_info = obj_dict[id] - obj_x, obj_y, obj_z = obj_info.location.X, obj_info.location.Y, obj_info.location.Z - print(id,obj.name,obj_x,obj_y,obj_z) + # obj_dict = self.scene.status.objects + # if len(obj_dict) != 0: + # # 获取obj_id + # for id, obj in enumerate(obj_dict): + # print("id:",id,"obj",obj.name) + + # if obj.name == "Coffee": + # obj_info = obj_dict[id] + # obj_x, obj_y, obj_z = obj_info.location.X, obj_info.location.Y, obj_info.location.Z + # print(id,obj.name,obj_x,obj_y,obj_z) self.scene.state["condition_set"] |= (self.info["add"]) self.scene.state["condition_set"] -= self.info["del_set"] + print("condition_set:",self.scene.state["condition_set"]) + return Status.RUNNING \ No newline at end of file diff --git a/robowaiter/behavior_lib/act/MoveTo.py b/robowaiter/behavior_lib/act/MoveTo.py index db1cb7f..fec8526 100644 --- a/robowaiter/behavior_lib/act/MoveTo.py +++ b/robowaiter/behavior_lib/act/MoveTo.py @@ -1,6 +1,6 @@ import py_trees as ptree from robowaiter.behavior_lib._base.Act import Act -from robowaiter.algos.navigate.navigate import Navigator +from robowaiter.algos.navigate_old.navigate import Navigator class MoveTo(Act): can_be_expanded = True @@ -21,6 +21,7 @@ class MoveTo(Act): info['pre'] |= {f'Exist({arg})'} info["add"] = {f'At(Robot,{arg})'} info["del_set"] = {f'At(Robot,{place})' for place in cls.valid_args if place != arg} + info['cost']=5 return info @@ -29,30 +30,41 @@ class MoveTo(Act): # navigator = Navigator(scene=self.scene, area_range=[-350, 600, -400, 1450], map=self.scene.state["map"]["2d"]) # goal = self.scene.state['map']['obj_pos'][self.args[0]] - # navigator.navigate(goal, animation=False) + # navigator.navigate_old(goal, animation=False) # 走到固定的地点 if self.target_place in Act.place_xyz_dic: goal = Act.place_xyz_dic[self.target_place] - self.scene.walk_to(goal[0],goal[1]) - else: # 走到物品边上 + self.scene.walk_to(goal[0]+1,goal[1]) + # 走到物品边上 + else: + # 是否用容器装好 + if self.target_place in Act.container_dic: + target_name = Act.container_dic[self.target_place] + else: + target_name = self.target_place + # 根据物体名字找到最近的这类物体对应的位置 obj_id = -1 min_dis = float('inf') obj_dict = self.scene.status.objects if len(obj_dict)!=0: # 获取obj_id for id,obj in enumerate(obj_dict): - if obj.name == self.target_place: - obj_id = id - # obj_info = obj_dict[id] - # obj_x, obj_y, obj_z = obj_info.location.X, obj_info.location.Y, obj_info.location.Z - # ginger_x,ginger_y,ginger_z = [int(self.scene.location.X), int(self.scene.location.Y), int(self.scene.rotation.Yaw)] - break - if self.target_place == "CoffeeCup": - obj_id = 273 + if obj.name == target_name: + obj_info = obj_dict[id] + dis = self.scene.cal_distance_to_robot(obj_info.location.X, obj_info.location.Y, obj_info.location.Z) + if id==275: + print("275'dis:",dis) + if dis ptree.common.Status: # self.scene.test_move() - op_type=16 - obj_id = 0 + # op_type=16 + # 遍历场景里的所有物品,根据名字匹配位置最近的 obj-id + # 是否用容器装好 + if self.target_obj in Act.container_dic: + target_name = Act.container_dic[self.target_obj] + else: + target_name = self.target_obj + # 根据物体名字找到最近的这类物体对应的位置 + obj_id = -1 + min_dis = float('inf') + obj_dict = self.scene.status.objects + if len(obj_dict) != 0: + # 获取obj_id + for id, obj in enumerate(obj_dict): + if obj.name == target_name: + obj_info = obj_dict[id] + dis = self.scene.cal_distance_to_robot(obj_info.location.X, obj_info.location.Y, + obj_info.location.Z) + if dis < min_dis: + min_dis = dis + obj_id = id + # if self.target_place == "CoffeeCup": + # # obj_id = 273 + # obj_id = 275 + if obj_id == -1: + return ptree.common.Status.FAILURE - if self.args=="Coffee": - obj_id = 273 - - self.scene.op_task_execute(op_type, obj_id=obj_id) + self.scene.move_task_area(op_type=16, obj_id=obj_id) + self.scene.op_task_execute(op_type=16, obj_id=obj_id) self.scene.state["condition_set"] |= (self.info["add"]) self.scene.state["condition_set"] -= self.info["del_set"] diff --git a/robowaiter/behavior_lib/act/PutDown.py b/robowaiter/behavior_lib/act/PutDown.py index a7da726..6457868 100644 --- a/robowaiter/behavior_lib/act/PutDown.py +++ b/robowaiter/behavior_lib/act/PutDown.py @@ -31,6 +31,7 @@ class PutDown(Act): release_pos = list(Act.place_xyz_dic[self.target_place]) # # 原始吧台处:[247.0, 520.0, 100.0], 空调开关旁吧台:[240.0, 40.0, 70.0], 水杯桌:[-70.0, 500.0, 107] # # 桌子2:[-55.0, 0.0, 107],桌子3:[-55.0, 150.0, 107] + self.scene.move_task_area(op_type, release_pos=release_pos) self.scene.op_task_execute(op_type, release_pos=release_pos) self.scene.state["condition_set"] |= (self.info["add"]) diff --git a/robowaiter/behavior_tree/obtea/OptimalBTExpansionAlgorithm.py b/robowaiter/behavior_tree/obtea/OptimalBTExpansionAlgorithm.py index c0212df..6a69783 100644 --- a/robowaiter/behavior_tree/obtea/OptimalBTExpansionAlgorithm.py +++ b/robowaiter/behavior_tree/obtea/OptimalBTExpansionAlgorithm.py @@ -2,6 +2,8 @@ import copy import random from robowaiter.behavior_tree.obtea.BehaviorTree import Leaf,ControlBT + + class CondActPair: def __init__(self, cond_leaf,act_leaf): self.cond_leaf = cond_leaf @@ -54,7 +56,10 @@ class OptBTExpAlgorithm: self.conditions_index = [] #运行规划算法,从初始状态、目标状态和可用行动,计算行为树self.bt - def run_algorithm(self,goal,actions): + def run_algorithm(self,goal,actions,scene): + + self.scene = scene + if self.verbose: print("\n算法开始!") @@ -99,8 +104,13 @@ class OptBTExpAlgorithm: sequence_structure.add_child( [copy.deepcopy(pair_node.cond_leaf), copy.deepcopy(pair_node.act_leaf)]) subtree.add_child([copy.deepcopy(sequence_structure)]) # subtree 是回不断变化的,它的父亲是self.bt + # 增加实时条件判断,满足条件就不再扩展 + if c <= self.scene.state["condition_set"]: + return True else: subtree.add_child([copy.deepcopy(pair_node.act_leaf)]) + + if self.verbose: print("完成扩展 a_node= %s,对应的新条件 c_attr= %s,mincost=%d" \ % (cond_anc_pair.act_leaf.content.name, cond_anc_pair.cond_leaf.content, diff --git a/robowaiter/behavior_tree/obtea/opt_bt_exp_main.py b/robowaiter/behavior_tree/obtea/opt_bt_exp_main.py index ca40d53..aa07b5d 100644 --- a/robowaiter/behavior_tree/obtea/opt_bt_exp_main.py +++ b/robowaiter/behavior_tree/obtea/opt_bt_exp_main.py @@ -6,7 +6,7 @@ from robowaiter.behavior_tree.obtea.examples import * # 封装好的主接口 class BTOptExpInterface: - def __init__(self, action_list): + def __init__(self, action_list,scene): """ Initialize the BTOptExpansion with a list of actions. :param action_list: A list of actions to be used in the behavior tree. @@ -22,6 +22,8 @@ class BTOptExpInterface: self.actions = action_list self.has_processed = False + self.scene = scene + def process(self, goal): """ Process the input sets and return a string result. @@ -29,9 +31,9 @@ class BTOptExpInterface: :return: A PTML string representing the outcome of the behavior tree. """ self.goal = goal - self.algo = OptBTExpAlgorithm(verbose=False) + self.algo = OptBTExpAlgorithm(verbose=True) self.algo.clear() - self.algo.run_algorithm(self.goal, self.actions) # 调用算法得到行为树保存至 algo.bt + self.algo.run_algorithm(self.goal, self.actions,self.scene) # 调用算法得到行为树保存至 algo.bt self.ptml_string = self.algo.get_ptml() self.has_processed = True # algo.print_solution() # print behavior tree diff --git a/robowaiter/robot/robot.py b/robowaiter/robot/robot.py index 6a1ae38..bcbce01 100644 --- a/robowaiter/robot/robot.py +++ b/robowaiter/robot/robot.py @@ -62,7 +62,7 @@ class Robot(object): print("--------------------\n") - algo = BTOptExpInterface(self.action_list) + algo = BTOptExpInterface(self.action_list,self.scene) ptml_string = algo.process(goal) diff --git a/robowaiter/scene/scene.py b/robowaiter/scene/scene.py index 13e20ef..2873bd2 100644 --- a/robowaiter/scene/scene.py +++ b/robowaiter/scene/scene.py @@ -397,8 +397,12 @@ class Scene: walk_v = [obj_x + 40, obj_y - 35, 130, 180, 0] obj_x += 3 obj_y += 2.5 + walk_v[0]+=1 + print("walk:",walk_v) action = GrabSim_pb2.Action(scene=self.sceneID, action=GrabSim_pb2.Action.ActionType.WalkTo, values=walk_v) scene = stub.Do(action) + print("After Walk Position:", [scene.location.X, scene.location.Y, scene.rotation.Yaw]) + # 移动到进行操作任务的指定地点 def move_task_area(self,op_type,obj_id=0, release_pos=[247.0, 520.0, 100.0]): @@ -428,7 +432,7 @@ class Scene: walk_v = release_pos[:-1] + [180, 180, 0] if release_pos == [340.0, 900.0, 99.0]: walk_v[2] = 130 - + print("walk_v:",walk_v) action = GrabSim_pb2.Action(scene=self.sceneID, action=GrabSim_pb2.Action.ActionType.WalkTo, values=walk_v) scene = stub.Do(action) print("After Walk Position:", [scene.location.X, scene.location.Y, scene.rotation.Yaw]) @@ -527,7 +531,7 @@ class Scene: return True # 执行过程:输出"开始(任务名)" -> 按步骤数执行任务 -> Robot输出成功或失败的对话 - def op_task_execute(self,op_type,obj_id=0,release_pos=[240,-140]): + def op_task_execute(self,op_type,obj_id=0,release_pos=[247.0, 520.0, 100.0]): self.control_robot_action(0, 1, "开始"+self.op_dialog[op_type]) # 开始制作咖啡 if op_type<8: result = self.control_robot_action(op_type, 1) if op_type>=8 and op_type<=12: result = self.control_robot_action(self.op_typeToAct[op_type][0], self.op_typeToAct[op_type][1]) @@ -633,3 +637,16 @@ class Scene: return False + def cal_distance_to_robot(self,objx,objy,objz): + scene = self.status + ginger_x, ginger_y, ginger_z = [int(scene.location.X), int(scene.location.Y),100] + return math.sqrt((ginger_x - objx) ** 2 + (ginger_y - objy) ** 2 + (ginger_z - objz) ** 2) + + def test(self): + walk_v = [247.0, 480.0, 180.0, 180, 0] + action = GrabSim_pb2.Action(scene=self.sceneID, action=GrabSim_pb2.Action.ActionType.WalkTo, values=walk_v) + scene = stub.Do(action) + time.sleep(4) + walk_v = [247.0, 500.0, 0.0, 180, 0] + action = GrabSim_pb2.Action(scene=self.sceneID, action=GrabSim_pb2.Action.ActionType.WalkTo, values=walk_v) + scene = stub.Do(action) \ No newline at end of file diff --git a/robowaiter/scene/tasks/VLM.py b/robowaiter/scene/tasks/VLM.py index aba572c..be4c993 100644 --- a/robowaiter/scene/tasks/VLM.py +++ b/robowaiter/scene/tasks/VLM.py @@ -35,6 +35,7 @@ class SceneVLM(Scene): def _run(self, op_type=10): + # 共17个操作 # "制作咖啡","倒水","夹点心","拖地","擦桌子","开筒灯","搬椅子", # 1-7 # "关筒灯","开大厅灯","关大厅灯","关闭窗帘","打开窗帘", # 8-12 @@ -58,27 +59,28 @@ class SceneVLM(Scene): # 流程测试 # 抓握放置:抓吧台前生成的酸奶,放到抹布桌上 self.gen_obj() - self.move_task_area(16, obj_id=0) - self.op_task_execute(16, obj_id=0) - pos = [340.0, 900.0, 99.0] - self.move_task_area(17, release_pos=pos) - self.op_task_execute(17, release_pos=pos) + # self.move_task_area(16, obj_id=0) + # self.op_task_execute(16, obj_id=0) + # pos = [340.0, 900.0, 99.0] + # self.move_task_area(17, release_pos=pos) + # self.op_task_execute(17, release_pos=pos) + # + # # 做咖啡:做完的咖啡放到水杯桌上 + # self.move_task_area(1) + # self.op_task_execute(1) + # + # self.find_obj("CoffeeCup") + # + # self.move_task_area(16, obj_id=275) + # self.op_task_execute(16, obj_id=275) + # pos = [-70.0, 500.0, 107] + # self.move_task_area(17, release_pos=pos) + # self.op_task_execute(17, release_pos=pos) + # + # # 倒水:倒完的水放到旁边桌子上 + # self.move_task_area(2) + # self.op_task_execute(2) - # 做咖啡:做完的咖啡放到水杯桌上 - self.move_task_area(1) - self.op_task_execute(1) - - self.find_obj("CoffeeCup") - - self.move_task_area(16, obj_id=275) - self.op_task_execute(16, obj_id=275) - pos = [-70.0, 500.0, 107] - self.move_task_area(17, release_pos=pos) - self.op_task_execute(17, release_pos=pos) - - # 倒水:倒完的水放到旁边桌子上 - self.move_task_area(2) - self.op_task_execute(2) # # self.move_task_area(16, obj_id=190) # self.op_task_execute(16, obj_id=190) @@ -86,6 +88,8 @@ class SceneVLM(Scene): # self.move_task_area(17, release_pos=pos) # self.op_task_execute(17, release_pos=pos) + # self.test() + pass def _step(self): diff --git a/robowaiter/scene/tasks/VLN.py b/robowaiter/scene/tasks/VLN.py index 448fecf..ce59d79 100644 --- a/robowaiter/scene/tasks/VLN.py +++ b/robowaiter/scene/tasks/VLN.py @@ -16,8 +16,8 @@ from robowaiter.scene.scene import Scene,init_world # TODO: 文件名改成Scen from robowaiter.scene.scene import Scene from robowaiter.utils import get_root_path -from robowaiter.algos.navigate.navigate import Navigator -from robowaiter.algos.navigate import test +from robowaiter.algos.navigator.navigate import Navigator +from robowaiter.algos.navigator import test class SceneVLN(Scene): def __init__(self, robot): @@ -29,7 +29,7 @@ class SceneVLN(Scene): def _reset(self): root_path = get_root_path() - file_name = os.path.join(root_path,'robowaiter/algos/navigate/map_5.pkl') + file_name = os.path.join(root_path,'robowaiter/algos/navigator/map_5.pkl') with open(file_name, 'rb') as file: map = pickle.load(file) @@ -37,7 +37,7 @@ class SceneVLN(Scene): self.state['map']['obj_pos']['Table'] = np.array((-100, 700)) def _run(self): - file_name = '../../algos/navigate/map_5.pkl' + file_name = '../../algos/navigator/map_5.pkl' if os.path.exists(file_name): with open(file_name, 'rb') as file: map = pickle.load(file) From d1e2049ecc8a1b9c63b81ad067ee4387715f58ef Mon Sep 17 00:00:00 2001 From: Caiyishuai <39987654+Caiyishuai@users.noreply.github.com> Date: Thu, 16 Nov 2023 15:29:56 +0800 Subject: [PATCH 2/6] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=AF=BC=E8=88=AA?= =?UTF-8?q?=E5=8A=A8=E4=BD=9C=E8=8A=82=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- robowaiter/behavior_lib/act/MoveTo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/robowaiter/behavior_lib/act/MoveTo.py b/robowaiter/behavior_lib/act/MoveTo.py index fec8526..43cef8b 100644 --- a/robowaiter/behavior_lib/act/MoveTo.py +++ b/robowaiter/behavior_lib/act/MoveTo.py @@ -1,6 +1,6 @@ import py_trees as ptree from robowaiter.behavior_lib._base.Act import Act -from robowaiter.algos.navigate_old.navigate import Navigator +from robowaiter.algos.navigator.navigate import Navigator class MoveTo(Act): can_be_expanded = True From 311a0cc2b97cb98aad63581c0f34144d4f914e33 Mon Sep 17 00:00:00 2001 From: Caiyishuai <39987654+Caiyishuai@users.noreply.github.com> Date: Thu, 16 Nov 2023 15:31:38 +0800 Subject: [PATCH 3/6] =?UTF-8?q?=E5=88=A0=E9=99=A4=E8=BD=AC=E5=90=91?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=9A=84=E9=97=AE=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- robowaiter/scene/scene.py | 16 ++++++++-------- robowaiter/scene/tasks/VLM.py | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/robowaiter/scene/scene.py b/robowaiter/scene/scene.py index 2873bd2..0333473 100644 --- a/robowaiter/scene/scene.py +++ b/robowaiter/scene/scene.py @@ -642,11 +642,11 @@ class Scene: ginger_x, ginger_y, ginger_z = [int(scene.location.X), int(scene.location.Y),100] return math.sqrt((ginger_x - objx) ** 2 + (ginger_y - objy) ** 2 + (ginger_z - objz) ** 2) - def test(self): - walk_v = [247.0, 480.0, 180.0, 180, 0] - action = GrabSim_pb2.Action(scene=self.sceneID, action=GrabSim_pb2.Action.ActionType.WalkTo, values=walk_v) - scene = stub.Do(action) - time.sleep(4) - walk_v = [247.0, 500.0, 0.0, 180, 0] - action = GrabSim_pb2.Action(scene=self.sceneID, action=GrabSim_pb2.Action.ActionType.WalkTo, values=walk_v) - scene = stub.Do(action) \ No newline at end of file + # def test_yaw(self): + # walk_v = [247.0, 480.0, 180.0, 180, 0] + # action = GrabSim_pb2.Action(scene=self.sceneID, action=GrabSim_pb2.Action.ActionType.WalkTo, values=walk_v) + # scene = stub.Do(action) + # time.sleep(4) + # walk_v = [247.0, 500.0, 0.0, 180, 0] + # action = GrabSim_pb2.Action(scene=self.sceneID, action=GrabSim_pb2.Action.ActionType.WalkTo, values=walk_v) + # scene = stub.Do(action) \ No newline at end of file diff --git a/robowaiter/scene/tasks/VLM.py b/robowaiter/scene/tasks/VLM.py index be4c993..23cd3af 100644 --- a/robowaiter/scene/tasks/VLM.py +++ b/robowaiter/scene/tasks/VLM.py @@ -88,7 +88,7 @@ class SceneVLM(Scene): # self.move_task_area(17, release_pos=pos) # self.op_task_execute(17, release_pos=pos) - # self.test() + # self.test_yaw() pass From 7181d84743cc043450d75cb8a26c12f5a74458b0 Mon Sep 17 00:00:00 2001 From: liwang zhang <2638950452@qq.com> Date: Thu, 16 Nov 2023 16:37:11 +0800 Subject: [PATCH 4/6] =?UTF-8?q?=E5=B7=B2=E6=9B=B4=E6=96=B0AEM?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- robowaiter/proto/camera.py | 2 +- robowaiter/proto/map_1.pkl | Bin 0 -> 9920163 bytes robowaiter/scene/scene.py | 50 ++++++++++++++++++++++++++++------ robowaiter/scene/tasks/AEM.py | 21 ++++++++++++-- 4 files changed, 62 insertions(+), 11 deletions(-) create mode 100644 robowaiter/proto/map_1.pkl diff --git a/robowaiter/proto/camera.py b/robowaiter/proto/camera.py index 503e735..8780bbb 100644 --- a/robowaiter/proto/camera.py +++ b/robowaiter/proto/camera.py @@ -240,7 +240,7 @@ def get_semantic_map(camera, cur_objs, objs_name): scene = Observe(0) objs = scene.objects img_data = get_camera([camera]) - show_image(img_data, scene) + # show_image(img_data, scene) objs_name = save_obj_info(img_data, objs_name) for obj_name in list(objs_name): for obj in objs: diff --git a/robowaiter/proto/map_1.pkl b/robowaiter/proto/map_1.pkl new file mode 100644 index 0000000000000000000000000000000000000000..323c387d23663c9657c8eb45600ec549feb4c2f1 GIT binary patch literal 9920163 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 zIKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G z-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$ zfCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h0 z0S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K0 z2ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`2 z9N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8 zaDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0W zzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h z00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70 z103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh1 z4sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4 zIKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G z-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$ zfCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h0 z0S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K0 z2ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`2 z9N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8 zaDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0W zzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h z00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70 z103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh1 z4sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4 zIKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G z-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$ zfCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h0 z0S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K0 z2ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`2 z9N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8 zaDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0W zzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h z00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70 z103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh1 z4sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4 zIKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G z-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$ zfCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h0 z0S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K0 z2ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`2 z9N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8 zaDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0W zzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h z00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70 z103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh1 z4sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4 zIKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G z-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$ zfCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h0 z0S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K0 z2ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`2 z9N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8 zaDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0W zzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h z00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70 z103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh1 z4sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4 zIKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G z-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$ zfCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h0 z0S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K0 z2ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`2 z9N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8 zaDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0W zzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h z00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70 z103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh1 z4sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4 zIKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G z-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$ zfCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h0 z0S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K0 z2ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`2 z9N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8 zaDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0W zzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h z00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70 z103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh1 z4sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4 zIKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G z-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$ zfCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h0 z0S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K0 z2ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`2 z9N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8 zaDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0W zzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h z00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70 z103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh1 z4sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4 zIKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G z-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$ zfCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h0 z0S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K0 z2ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`2 z9N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8 zaDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0W zzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h z00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70 z103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh1 z4sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4 zIKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G z-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$ zfCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h0 z0S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K0 z2ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`2 z9N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8 zaDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0W zzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h z00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70 z103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh1 z4sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4 zIKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G z-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$ zfCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h0 z0S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K0 z2ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`2 z9N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8 zaDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0W zzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h z00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70 z103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh1 z4sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4 zIKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G z-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$ zfCC)h00%h00S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h0 z0S<70103K02ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K0 z2ROh14sd`29N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103K02ROh14sd`2 z9N+*4IKTl8aDW3G-~b0WzyS_$fCC)h00%h00S<70103MM9uEBXpM8@5`0GD^{rg}4 E1IUtL761SM literal 0 HcmV?d00001 diff --git a/robowaiter/scene/scene.py b/robowaiter/scene/scene.py index 13e20ef..3bb279e 100644 --- a/robowaiter/scene/scene.py +++ b/robowaiter/scene/scene.py @@ -1,3 +1,4 @@ +import sys import time import grpc import numpy as np @@ -108,6 +109,7 @@ class Scene: self.visited = set() self.all_frontier_list = set() self.semantic_map = semantic_map + self.auto_map = np.ones((800, 1550)) def reset(self): @@ -574,7 +576,7 @@ class Scene: # v_list = [[0.0, 0.0]] for walk_v in v_list: - walk_v = walk_v + [scene.rotation.Yaw - 90, 250, 60] + walk_v = walk_v + [scene.rotation.Yaw - 90, 250, 10] print("walk_v", walk_v) action = GrabSim_pb2.Action(scene=scene_id, action=GrabSim_pb2.Action.ActionType.WalkTo, values=walk_v) scene = stub.Do(action) @@ -583,7 +585,7 @@ class Scene: print(scene.info) return cur_objs, objs_name_set - def isOutMap(self, pos, min_x=-350, max_x=600, min_y=-400, max_y=1450): + def isOutMap(self, pos, min_x=-200, max_x=600, min_y=-250, max_y=1300): if pos[0] <= min_x or pos[0] >= max_x or pos[1] <= min_y or pos[1] >= max_y: return True return False @@ -594,11 +596,13 @@ class Scene: ''' # x = round((x - self.min_x) / self.scale_ratio) # y = round((y - self.min_y) / self.scale_ratio) - x = math.floor((x + 350) / 5) - y = math.floor((y + 400) / 5) + x = math.floor((x + 200)) + y = math.floor((y + 250)) return x, y - def explore(self, map, cur_pos, explore_range): + def explore(self, map, explore_range): + scene = stub.Observe(GrabSim_pb2.SceneID(value=0)) + cur_pos = [int(scene.location.X), int(scene.location.Y)] for i in range(cur_pos[0] - explore_range, cur_pos[0] + explore_range + 1): for j in range(cur_pos[1] - explore_range, cur_pos[1] + explore_range + 1): if self.isOutMap((i, j)): @@ -606,6 +610,7 @@ class Scene: x, y = self.real2map(i, j) if map[x, y] == 0: self.visited.add((i, j)) + self.auto_map[x][y] = 0 for i in range(cur_pos[0] - explore_range, cur_pos[0] + explore_range + 1): for j in range(cur_pos[1] - explore_range, cur_pos[1] + explore_range + 1): if self.isOutMap((i, j)): @@ -614,11 +619,26 @@ class Scene: if map[x, y] == 0: if self.isNewFrontier((i, j), map): self.all_frontier_list.add((i, j)) - if len(self.all_frontier_list) <= 400: + if len(self.all_frontier_list) == 0: free_list = list(self.visited) free_array = np.array(free_list) - print(f"探索完成!以下是场景中可以到达的点:{free_array};其余点均是障碍物不可达") + print(f"主动探索完成!以下是场景中可以到达的点:{free_array};其余点均是障碍物不可达") + + # 画地图: X行Y列,第一行在下面 + plt.clf() + plt.imshow(self.auto_map, cmap='binary', alpha=0.5, origin='lower', + extent=(-250, 1300, + -200, 600)) + plt.show() + print("已绘制完成地图!!!") + return None + # 画地图: X行Y列,第一行在下面 + plt.imshow(self.auto_map, cmap='binary', alpha=0.5, origin='lower', + extent=(-250, 1300, + -200, 600)) + plt.show() + print("已绘制部分地图!") return self.getNearestFrontier(cur_pos, self.all_frontier_list) def isNewFrontier(self, pos, map): @@ -626,10 +646,24 @@ class Scene: for node in around_nodes: x, y = self.real2map(node[0], node[1]) - if node not in self.visited and map[x, y] == 0: + if not self.isOutMap((node[0], node[1])) and node not in self.visited and map[x, y] == 0: return True if (pos[0], pos[1]) in self.all_frontier_list: self.all_frontier_list.remove((pos[0], pos[1])) return False + def getDistance(self, pos1, pos2): + return math.sqrt((pos1[0] - pos2[0]) ** 2 + (pos1[1] - pos2[1]) ** 2) + + def getNearestFrontier(self, cur_pos, frontiers): + dis_min = sys.maxsize + frontier_best = None + for frontier in frontiers: + dis = self.getDistance(frontier, cur_pos) + if dis <= dis_min: + dis_min = dis + frontier_best = frontier + return frontier_best + + diff --git a/robowaiter/scene/tasks/AEM.py b/robowaiter/scene/tasks/AEM.py index 82870d7..fb04a0f 100644 --- a/robowaiter/scene/tasks/AEM.py +++ b/robowaiter/scene/tasks/AEM.py @@ -2,6 +2,7 @@ 环境主动探索和记忆 要求输出探索结果(语义地图)对环境重点信息记忆。生成环境的语义拓扑地图,和不少于10个环境物品的识别和位置记忆,可以是图片或者文字或者格式化数据。 """ +import pickle from robowaiter.scene.scene import Scene class SceneAEM(Scene): @@ -12,9 +13,25 @@ class SceneAEM(Scene): pass def _run(self): cur_objs = [] + objs_name_set = set() + file_name = '../../proto/map_1.pkl' + if os.path.exists(file_name): + with open(file_name, 'rb') as file: + map = pickle.load(file) print('------------ 自主探索 ------------') - cur_objs = self.semantic_map.navigation_move(cur_objs, 0, 11) - print("物品列表如下:") + # cur_objs = self.semantic_map.navigation_move(cur_objs, 0, 11) + # print("物品列表如下:") + # print(cur_objs) + # cur_pos = [int(scene.location.X), int(scene.location.Y)] + # print(reachable([237,490])) + # navigation_move([[237,490]], i, map_id) + # navigation_test(i,map_id) + while True: + goal = self.explore(map, 120) # cur_pos 指的是当前机器人的位置,场景中应该也有接口可以获取 + if goal is None: + break + cur_objs, objs_name_set = self.navigation_move(cur_objs, objs_name_set, [[goal[0], goal[1]]], 0, 11) + print("------------物品信息--------------") print(cur_objs) pass From 8d40d43c5a47896ddf91dcef9dc75a1939d0b4b0 Mon Sep 17 00:00:00 2001 From: Caiyishuai <39987654+Caiyishuai@users.noreply.github.com> Date: Thu, 16 Nov 2023 17:57:27 +0800 Subject: [PATCH 5/6] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20VLM=20=E5=9C=BA?= =?UTF-8?q?=E6=99=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- robowaiter/behavior_lib/_base/Behavior.py | 2 + robowaiter/behavior_lib/act/Make.py | 2 +- robowaiter/behavior_lib/act/MoveTo.py | 6 +- robowaiter/behavior_lib/act/PutDown.py | 4 + robowaiter/behavior_lib/cond/On.py | 3 + .../obtea/OptimalBTExpansionAlgorithm.py | 30 +++-- .../behavior_tree/obtea/opt_bt_exp_main.py | 2 +- robowaiter/llm_client/data/test_questions.txt | 2 +- .../llm_client/data_raw/test_questions.csv | 2 +- robowaiter/llm_client/data_tools/csv2dict.py | 1 - robowaiter/scene/tasks/{ => VLM}/VLM.py | 5 +- robowaiter/scene/tasks/VLM/VLM2.py | 123 ++++++++++++++++++ robowaiter/scene/tasks/VLM/__init__.py | 0 sub_task.ptml | 7 +- 14 files changed, 168 insertions(+), 21 deletions(-) rename robowaiter/scene/tasks/{ => VLM}/VLM.py (95%) create mode 100644 robowaiter/scene/tasks/VLM/VLM2.py create mode 100644 robowaiter/scene/tasks/VLM/__init__.py diff --git a/robowaiter/behavior_lib/_base/Behavior.py b/robowaiter/behavior_lib/_base/Behavior.py index 1bd0182..78fa48a 100644 --- a/robowaiter/behavior_lib/_base/Behavior.py +++ b/robowaiter/behavior_lib/_base/Behavior.py @@ -33,6 +33,8 @@ class Bahavior(ptree.behaviour.Behaviour): 'Water': 'Glass', 'Dessert':'Plate' } + + @classmethod def get_ins_name(cls,*args): diff --git a/robowaiter/behavior_lib/act/Make.py b/robowaiter/behavior_lib/act/Make.py index a730820..88f828e 100644 --- a/robowaiter/behavior_lib/act/Make.py +++ b/robowaiter/behavior_lib/act/Make.py @@ -57,6 +57,6 @@ class Make(Act): self.scene.state["condition_set"] |= (self.info["add"]) self.scene.state["condition_set"] -= self.info["del_set"] - print("condition_set:",self.scene.state["condition_set"]) + # print("condition_set:",self.scene.state["condition_set"]) return Status.RUNNING \ No newline at end of file diff --git a/robowaiter/behavior_lib/act/MoveTo.py b/robowaiter/behavior_lib/act/MoveTo.py index 43cef8b..6c31ad5 100644 --- a/robowaiter/behavior_lib/act/MoveTo.py +++ b/robowaiter/behavior_lib/act/MoveTo.py @@ -21,7 +21,7 @@ class MoveTo(Act): info['pre'] |= {f'Exist({arg})'} info["add"] = {f'At(Robot,{arg})'} info["del_set"] = {f'At(Robot,{place})' for place in cls.valid_args if place != arg} - info['cost']=5 + info['cost']=10 return info @@ -53,8 +53,6 @@ class MoveTo(Act): if obj.name == target_name: obj_info = obj_dict[id] dis = self.scene.cal_distance_to_robot(obj_info.location.X, obj_info.location.Y, obj_info.location.Z) - if id==275: - print("275'dis:",dis) if dis ptree.common.Status: # if self.scene.status? + # print("self.name:",self.name) + # print("On: condition_set:",self.scene.state["condition_set"]) + if self.name in self.scene.state["condition_set"]: return ptree.common.Status.SUCCESS else: diff --git a/robowaiter/behavior_tree/obtea/OptimalBTExpansionAlgorithm.py b/robowaiter/behavior_tree/obtea/OptimalBTExpansionAlgorithm.py index 6a69783..cf88a21 100644 --- a/robowaiter/behavior_tree/obtea/OptimalBTExpansionAlgorithm.py +++ b/robowaiter/behavior_tree/obtea/OptimalBTExpansionAlgorithm.py @@ -105,8 +105,8 @@ class OptBTExpAlgorithm: [copy.deepcopy(pair_node.cond_leaf), copy.deepcopy(pair_node.act_leaf)]) subtree.add_child([copy.deepcopy(sequence_structure)]) # subtree 是回不断变化的,它的父亲是self.bt # 增加实时条件判断,满足条件就不再扩展 - if c <= self.scene.state["condition_set"]: - return True + # if c <= self.scene.state["condition_set"]: + # return True else: subtree.add_child([copy.deepcopy(pair_node.act_leaf)]) @@ -138,14 +138,14 @@ class OptBTExpAlgorithm: break if valid: - # 把符合条件的动作节点都放到列表里 - if self.verbose: - print("———— -- %s 符合条件放入列表" % actions[i].name) c_attr_node = Leaf(type='cond', content=c_attr, mincost=current_mincost + actions[i].cost) a_attr_node = Leaf(type='act', content=actions[i], mincost=current_mincost + actions[i].cost) cond_anc_pair = CondActPair(cond_leaf=c_attr_node, act_leaf=a_attr_node) self.nodes.append(copy.deepcopy(cond_anc_pair)) # condition node list self.traversed.append(c_attr) # 重点 the set of expanded conditions + # 把符合条件的动作节点都放到列表里 + if self.verbose: + print("———— -- %s 符合条件放入列表,对应的c为 %s" % (actions[i].name,c_attr)) if self.verbose: print("算法结束!\n") @@ -188,13 +188,23 @@ class OptBTExpAlgorithm: # 树的dfs - def dfs_ptml(self,parnode): + def dfs_ptml(self,parnode,is_root=False): for child in parnode.children: if isinstance(child, Leaf): if child.type == 'cond': - self.ptml_string += "cond " - c_set_str = '\n cond '.join(map(str, child.content)) + "\n" - self.ptml_string += c_set_str + + if is_root and len(child.content) > 1: + # 把多个 cond 串起来 + self.ptml_string += "sequence{\n" + self.ptml_string += "cond " + c_set_str = '\n cond '.join(map(str, child.content)) + "\n" + self.ptml_string += c_set_str + self.ptml_string += '}\n' + else: + self.ptml_string += "cond " + c_set_str = '\n cond '.join(map(str, child.content)) + "\n" + self.ptml_string += c_set_str + elif child.type == 'act': if '(' not in child.content.name: self.ptml_string += 'act ' + child.content.name + "()\n" @@ -212,7 +222,7 @@ class OptBTExpAlgorithm: def get_ptml(self): self.ptml_string = "selector{\n" - self.dfs_ptml(self.bt.children[0]) + self.dfs_ptml(self.bt.children[0],is_root=True) self.ptml_string += '}\n' return self.ptml_string diff --git a/robowaiter/behavior_tree/obtea/opt_bt_exp_main.py b/robowaiter/behavior_tree/obtea/opt_bt_exp_main.py index aa07b5d..9a7829f 100644 --- a/robowaiter/behavior_tree/obtea/opt_bt_exp_main.py +++ b/robowaiter/behavior_tree/obtea/opt_bt_exp_main.py @@ -31,7 +31,7 @@ class BTOptExpInterface: :return: A PTML string representing the outcome of the behavior tree. """ self.goal = goal - self.algo = OptBTExpAlgorithm(verbose=True) + self.algo = OptBTExpAlgorithm(verbose=False) self.algo.clear() self.algo.run_algorithm(self.goal, self.actions,self.scene) # 调用算法得到行为树保存至 algo.bt self.ptml_string = self.algo.get_ptml() diff --git a/robowaiter/llm_client/data/test_questions.txt b/robowaiter/llm_client/data/test_questions.txt index e0d8ea9..fe0c3bd 100644 --- a/robowaiter/llm_client/data/test_questions.txt +++ b/robowaiter/llm_client/data/test_questions.txt @@ -1 +1 @@ -{"测试VLM:做一杯咖啡": {"Answer": "测试VLM:做一杯咖啡", "Goal": "{\"On(Coffee,CoffeeTable)\"}"}, "测试VLM:做一杯咖啡放到吧台上": {"Answer": "测试VLM:做一杯咖啡放到吧台上", "Goal": "{\"On(Coffee,Bar)\"}"}, "测试VLM:做一杯咖啡放到水杯桌上并倒水": {"Answer": "测试VLM:做一杯咖啡放到水杯桌上并倒水", "Goal": "{\"On(Coffee,WaterTable)\"}"}, "测试VLN:前往2号桌": {"Answer": "测试VLN:前往2号桌", "Goal": "{\"At(Robot,Table2)\"}"}, "测试AEM": {"Answer": "测试AEM", "Goal": "{\"EnvExplored()\"}"}, "测试VLM:倒一杯水": {"Answer": "测试VLM:倒一杯水", "Goal": "{\"On(Water,WaterTable)\"}"}, "测试VLM:开空调": {"Answer": "测试VLM:开空调", "Goal": "{\"Is(AC,On)\"}"}, "测试VLM:关空调": {"Answer": "测试VLM:关空调", "Goal": "{\"Is(AC,Off)\"}"}, "测试VLM:关大厅灯": {"Answer": "测试VLM:关大厅灯", "Goal": "{\"Is(HallLight,Off)\"}"}, "测试VLM:开大厅灯": {"Answer": "测试VLM:开大厅灯", "Goal": "{\"Is(HallLight,On)\"}"}, "测试VLM:关筒灯": {"Answer": "测试VLM:关筒灯", "Goal": "{\"Is(TubeLight,Off)\"}"}, "测试VLM:开筒灯": {"Answer": "测试VLM:开筒灯", "Goal": "{\"Is(TubeLight,On)\"}"}, "测试VLM:关窗帘": {"Answer": "测试VLM:关窗帘", "Goal": "{\"Is(Curtain,Off)\"}"}, "测试VLM:开窗帘": {"Answer": "测试VLM:开窗帘", "Goal": "{\"Is(Curtain,On)\"}"}, "测试VLM:拖地": {"Answer": "测试VLM:拖地", "Goal": "{\"Is(Floor,Clean)\"}"}, "测试VLM:擦桌子": {"Answer": "测试VLM:擦桌子", "Goal": "{\"Is(Table1,Clean)\"}"}, "测试VLM:整理椅子": {"Answer": "测试VLM:整理椅子", "Goal": "{\"Is(Chairs,Clean)\"}"}, "测试VLM:把冰红茶放到Table2": {"Answer": "测试VLM:把冰红茶放到Table2", "Goal": "{\"On(BottledDrink,Table2)\"}"}, "我有点热,能开个空调吗?": {"Answer": "当然可以,我现在就开!", "Goal": "{\"Is(AC,On)\"}"}, "可以带我去吗": {"Answer": "当然可以,前往一号桌", "Goal": "{\"At(Robot,Table1)\"}"}} +{"测试VLM:做一杯咖啡": {"Answer": "测试VLM:做一杯咖啡", "Goal": "{\"On(Coffee,CoffeeTable)\"}"}, "测试VLM:做一杯咖啡放到吧台上": {"Answer": "测试VLM:做一杯咖啡放到吧台上", "Goal": "{\"On(Coffee,Bar)\"}"}, "测试VLM:做一杯咖啡放到水杯桌上,再倒一杯水": {"Answer": "测试VLM:做一杯咖啡放到水杯桌上,再倒一杯水", "Goal": "{\"On(Coffee,WaterTable)\",\"On(Water,WaterTable)\"}"}, "测试VLN:前往2号桌": {"Answer": "测试VLN:前往2号桌", "Goal": "{\"At(Robot,Table2)\"}"}, "测试AEM": {"Answer": "测试AEM", "Goal": "{\"EnvExplored()\"}"}, "测试VLM:倒一杯水": {"Answer": "测试VLM:倒一杯水", "Goal": "{\"On(Water,WaterTable)\"}"}, "测试VLM:开空调": {"Answer": "测试VLM:开空调", "Goal": "{\"Is(AC,On)\"}"}, "测试VLM:关空调": {"Answer": "测试VLM:关空调", "Goal": "{\"Is(AC,Off)\"}"}, "测试VLM:关大厅灯": {"Answer": "测试VLM:关大厅灯", "Goal": "{\"Is(HallLight,Off)\"}"}, "测试VLM:开大厅灯": {"Answer": "测试VLM:开大厅灯", "Goal": "{\"Is(HallLight,On)\"}"}, "测试VLM:关筒灯": {"Answer": "测试VLM:关筒灯", "Goal": "{\"Is(TubeLight,Off)\"}"}, "测试VLM:开筒灯": {"Answer": "测试VLM:开筒灯", "Goal": "{\"Is(TubeLight,On)\"}"}, "测试VLM:关窗帘": {"Answer": "测试VLM:关窗帘", "Goal": "{\"Is(Curtain,Off)\"}"}, "测试VLM:开窗帘": {"Answer": "测试VLM:开窗帘", "Goal": "{\"Is(Curtain,On)\"}"}, "测试VLM:拖地": {"Answer": "测试VLM:拖地", "Goal": "{\"Is(Floor,Clean)\"}"}, "测试VLM:擦桌子": {"Answer": "测试VLM:擦桌子", "Goal": "{\"Is(Table1,Clean)\"}"}, "测试VLM:整理椅子": {"Answer": "测试VLM:整理椅子", "Goal": "{\"Is(Chairs,Clean)\"}"}, "测试VLM:把冰红茶放到Table2": {"Answer": "测试VLM:把冰红茶放到Table2", "Goal": "{\"On(BottledDrink,Table2)\"}"}, "我有点热,能开个空调吗?": {"Answer": "当然可以,我现在就开!", "Goal": "{\"Is(AC,On)\"}"}, "可以带我去吗": {"Answer": "当然可以,前往一号桌", "Goal": "{\"At(Robot,Table1)\"}"}} diff --git a/robowaiter/llm_client/data_raw/test_questions.csv b/robowaiter/llm_client/data_raw/test_questions.csv index 3bb7a86..19b8af4 100644 --- a/robowaiter/llm_client/data_raw/test_questions.csv +++ b/robowaiter/llm_client/data_raw/test_questions.csv @@ -1,7 +1,7 @@ Question,Answer,Goal VLMһ,VLMһ,"{""On(Coffee,CoffeeTable)""}" VLMһȷŵ̨,VLMһȷŵ̨,"{""On(Coffee,Bar)""}" -VLMһȷŵˮϲˮ,VLMһȷŵˮϲˮ,"{""On(Coffee,WaterTable)""}" +VLMһȷŵˮϣٵһˮ,VLMһȷŵˮϣٵһˮ,"{""On(Coffee,WaterTable)"",""On(Water,WaterTable)""}" VLNǰ2,VLNǰ2,"{""At(Robot,Table2)""}" AEM,AEM,"{""EnvExplored()""}" VLMһˮ,VLMһˮ,"{""On(Water,WaterTable)""}" diff --git a/robowaiter/llm_client/data_tools/csv2dict.py b/robowaiter/llm_client/data_tools/csv2dict.py index 31feb97..6660c79 100644 --- a/robowaiter/llm_client/data_tools/csv2dict.py +++ b/robowaiter/llm_client/data_tools/csv2dict.py @@ -24,4 +24,3 @@ with open(csv_file_path, mode='r', encoding='gbk') as csv_file, \ json_str = json.dumps(output_dict, ensure_ascii=False) # 将JSON字符串写入JSONL文件,并添加换行符 jsonl_file.write(json_str + '\n') -s \ No newline at end of file diff --git a/robowaiter/scene/tasks/VLM.py b/robowaiter/scene/tasks/VLM/VLM.py similarity index 95% rename from robowaiter/scene/tasks/VLM.py rename to robowaiter/scene/tasks/VLM/VLM.py index 23cd3af..04e2caf 100644 --- a/robowaiter/scene/tasks/VLM.py +++ b/robowaiter/scene/tasks/VLM/VLM.py @@ -22,7 +22,10 @@ class SceneVLM(Scene): # (5, self.create_chat_event("测试VLM:把冰红茶放到Table2")), # (5, self.create_chat_event("测试VLM:关大厅灯")) # (5, self.create_chat_event("测试VLM:做一杯咖啡放到吧台上")), - (5, self.create_chat_event("测试VLM:做一杯咖啡放到水杯桌上并倒水")), + (5, self.create_chat_event("测试VLM:做一杯咖啡放到水杯桌上,再倒一杯水")), + (10, self.create_chat_event("测试VLM:关窗帘")), + # (5, self.create_chat_event("测试VLN:前往2号桌")), + ] def _reset(self): diff --git a/robowaiter/scene/tasks/VLM/VLM2.py b/robowaiter/scene/tasks/VLM/VLM2.py new file mode 100644 index 0000000..6872edd --- /dev/null +++ b/robowaiter/scene/tasks/VLM/VLM2.py @@ -0,0 +1,123 @@ +""" +视觉语言操作 +机器人根据指令人的指令调节空调,自主探索环境导航到目标点,通过手臂的运动规划能力操作空调,比如开关按钮、调温按钮、显示面板 +""" + +import time +from robowaiter.scene.scene import Scene + +class SceneVLM(Scene): + def __init__(self, robot): + super().__init__(robot) + # 在这里加入场景中发生的事件, (事件发生的时间,事件函数) + self.event_list = [ + # (5, self.create_chat_event("测试VLM:做一杯咖啡")), + # (5, self.create_chat_event("测试VLM:倒一杯水")), + # (5, self.create_chat_event("测试VLM:开空调")), + # (5, self.create_chat_event("测试VLM:关空调")), + # (5, self.create_chat_event("测试VLM:开大厅灯")), + # (5, self.create_chat_event("测试VLM:拖地")), + # (7, self.create_chat_event("测试VLM:擦桌子")), + # (5, self.create_chat_event("测试VLM:整理椅子")), + # (5, self.create_chat_event("测试VLM:把冰红茶放到Table2")), + # (5, self.create_chat_event("测试VLM:关大厅灯")) + # (5, self.create_chat_event("测试VLM:做一杯咖啡放到吧台上")), + # (5, self.create_chat_event("测试VLM:做一杯咖啡放到水杯桌上并倒水")), + # (8, self.create_chat_event("测试VLN:前往1号桌")), + + ] + + def _reset(self): + + # self.gen_obj(type=5) + # self.gen_obj(type=9) + # self.op_task_execute(op_type=16, obj_id=0) + # self.move_task_area(op_type=4) + pass + + def _run(self, op_type=10): + # 一个行人从门口走到 吧台 + # 打招呼需要什么 + # 行人说 哪里有位置,想晒个太阳 + # 带领行人去有太阳的地方 + # 行人说 有点热 + # 好的,这就去开空调 + + scene = self.add_walkers([[0, 0]]) + self.control_walker( + [self.walker_control_generator(walkerID=1, autowalk=False, speed=50, X=100, Y=150, Yaw=0)]) + + cont = scene.walkers[0].name+":我有点热,能开个空调吗?" + self.control_robot_action(0,3,cont) + + + # 共17个操作 + # "制作咖啡","倒水","夹点心","拖地","擦桌子","开筒灯","搬椅子", # 1-7 + # "关筒灯","开大厅灯","关大厅灯","关闭窗帘","打开窗帘", # 8-12 + # "调整空调开关","调高空调温度","调低空调温度", # 13-15 + # "抓握物体","放置物体" # 16-17 + + # self.gen_obj() + # if op_type <=15: + # self.move_task_area(op_type) + # self.op_task_execute(op_type) + # if op_type == 16: # 16: 抓操作需要传入物品id + # self.move_task_area(op_type, obj_id=0) + # self.op_task_execute(op_type, obj_id=0) + # # 原始吧台处:[247.0, 520.0, 100.0], 空调开关旁吧台:[240.0, 40.0, 100.0], 水杯桌:[-70.0, 500.0, 107] + # # 桌子1:[-55.0, 0.0, 107],抹布桌:[340.0, 900.0, 99.0] # 桌子2:[-55.0, 150.0, 107], + # if op_type == 17: # 17: 放操作需要传入放置位置周围的可达区域 + # pos = [240.0, 40.0, 100.0] + # self.move_task_area(op_type, release_pos=pos) + # self.op_task_execute(op_type, release_pos=pos) # [325.0, 860.0, 100] + + # 流程测试 + # 抓握放置:抓吧台前生成的酸奶,放到抹布桌上 + self.gen_obj() + # self.move_task_area(16, obj_id=0) + # self.op_task_execute(16, obj_id=0) + # pos = [340.0, 900.0, 99.0] + # self.move_task_area(17, release_pos=pos) + # self.op_task_execute(17, release_pos=pos) + # + # # 做咖啡:做完的咖啡放到水杯桌上 + # self.move_task_area(1) + # self.op_task_execute(1) + # + # self.find_obj("CoffeeCup") + # + # self.move_task_area(16, obj_id=275) + # self.op_task_execute(16, obj_id=275) + # pos = [-70.0, 500.0, 107] + # self.move_task_area(17, release_pos=pos) + # self.op_task_execute(17, release_pos=pos) + # + # # 倒水:倒完的水放到旁边桌子上 + # self.move_task_area(2) + # self.op_task_execute(2) + + # + # self.move_task_area(16, obj_id=190) + # self.op_task_execute(16, obj_id=190) + # pos = [-55.0, 0.0, 107] + # self.move_task_area(17, release_pos=pos) + # self.op_task_execute(17, release_pos=pos) + + # self.test_yaw() + + pass + + def _step(self): + pass + + +if __name__ == '__main__': + import os + from robowaiter.robot.robot import Robot + + robot = Robot() + + # create task + task = SceneVLM(robot) + task.reset() + task.run() diff --git a/robowaiter/scene/tasks/VLM/__init__.py b/robowaiter/scene/tasks/VLM/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/sub_task.ptml b/sub_task.ptml index bc19507..33895cd 100644 --- a/sub_task.ptml +++ b/sub_task.ptml @@ -1,5 +1,10 @@ selector{ -cond On(Coffee,CoffeeTable) + +sequence{ + cond On(Coffee,CoffeeTable) + cond On(Coffee,CoffeeTable) + } + sequence{ cond Holding(Nothing) act Make(Coffee) From 439e0dce685dd0ffb2c41188aea0f97efe4fd322 Mon Sep 17 00:00:00 2001 From: wuziji <2193177243@qq.com> Date: Thu, 16 Nov 2023 20:07:01 +0800 Subject: [PATCH 6/6] =?UTF-8?q?NEW:=20=E6=96=B0=E5=A2=9Echatglm=E7=9A=84?= =?UTF-8?q?=E8=AF=84=E6=B5=8B=E6=95=B0=E6=8D=AE=E9=9B=86=E3=80=81=E8=AF=84?= =?UTF-8?q?=E5=88=86=E6=A0=87=E5=87=86=E3=80=81=E8=AF=84=E6=B5=8B=E8=84=9A?= =?UTF-8?q?=E6=9C=AC=E4=BB=A5=E5=8F=8A=E8=AF=84=E6=B5=8B=E7=BB=93=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- requirements.txt | 15 ++++-- robowaiter/llm_client/test_llm/__init__.py | 0 .../llm_client/test_llm/llm测试效果.xlsx | Bin 0 -> 26982 bytes .../llm_client/test_llm/validate_data.txt | 40 ++++++++++++++ .../llm_client/test_llm/validate_llm.py | 19 +++++++ .../llm_client/test_llm/validate_llm_1.txt | 40 ++++++++++++++ robowaiter/llm_client/tool_api.py | 49 ++++++++++++++++-- 7 files changed, 153 insertions(+), 10 deletions(-) create mode 100644 robowaiter/llm_client/test_llm/__init__.py create mode 100644 robowaiter/llm_client/test_llm/llm测试效果.xlsx create mode 100644 robowaiter/llm_client/test_llm/validate_data.txt create mode 100644 robowaiter/llm_client/test_llm/validate_llm.py create mode 100644 robowaiter/llm_client/test_llm/validate_llm_1.txt diff --git a/requirements.txt b/requirements.txt index 7659ed1..5dc0fee 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,15 +1,20 @@ antlr4-python3-runtime py_trees -shortuuid +shortuuid~=1.0.11 protobuf==3.20.0 gym==0.21.0 grpcio==1.53.0 -requests -urllib3 -tabulate +requests~=2.31.0 +urllib3~=2.0.7 +tabulate~=0.9.0 autopep8 pytorch==1.11.0 torchvision==0.12.0 torchaudio==0.11.0 cudatoolkit=11.3 -loguru \ No newline at end of file +loguru~=0.5.3 +matplotlib~=3.8.0 +numpy~=1.26.0 +setuptools~=68.0.0 +pydot~=1.4.2 +colorama~=0.4.6 \ No newline at end of file diff --git a/robowaiter/llm_client/test_llm/__init__.py b/robowaiter/llm_client/test_llm/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/robowaiter/llm_client/test_llm/llm测试效果.xlsx b/robowaiter/llm_client/test_llm/llm测试效果.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..48a65af96908a0c4821a49a3d8a4b6c1ce15fcac GIT binary patch literal 26982 zcmeFY^Lu4Yv@ROkPF8H&=yYt`ww-ir+qTV)?R0G0Haj`_zP<0==RSMizu=ttL#_Ed zRW%FieaEO8ke31lLj!^Uf&u~pA_AJPST2qS1_DZg00Ke^u_i141EI_V0{L$Lf1m$@cVJLON(z(-sT=k)luYfk`Iv@|VQtNakeqdyP5Ye)usr^dq!-UFYya-kc`!2NBcJEBJwd*7LbMHuewf~ud zNxNE3*FTmsz|Lx4?)nowac<^6HMu!i|H3$9I#n{KQS8a);A{8VUD$9x;8MM*T^Etv z#Bz~ud|mkd?C5BUtf;cI9=5jYzeC2_wV540TyFj}>mv?&ee zeuMDq3lvEH|HI^F6-JVW?;7cEqQZVNSN&ff~x zBTdt*;XtDn!RMB61+IMndhZ|C3}uz;64%&zjuj=B zHKU8PAW|FKc2~-JCdePY+gt>p1BD{-01jpG;R&Q&J^*%;wEOtDL>T>)+#gV5agp() zgU%wN_F@z~mmfZySx!uN4nNp{@{)+glPW+a5+p=niJ#p?q{5=wD8mAZ)6^SKl8TrM zmC@S{S6b}QgObg|k;0bsZ*J4bnnn^e1f-h5kXb2UP9~yM8U$z(mV42KrOlGlZwf%d zkSEgHs|Df}NCkWq9R)+W3YIZY{Z?;Fr^^9HtjMhB>_`qh%TCliIjsg!WTZA**7!6s5)Fn1? z6>qZO8s(U%EOGQw=~-6c_qqe8_BNo3!Kw&T+R(E7-*}iB+0EIIAQ19Z>vI+b66U*ZLaT7(`FRvw>v3nq|}&ObF&8 zw3bbXLA<<|2R2un_^d_w*4Z~H17h~v>E>hiQ}9G$;BP&VNInR6jY}F-1lXLzw9B?+ zPhd4zk*y(FQf$pPRx1YScbfWJ?O-);ZTemaxnqy`z0hOPs)^Z#s?RJTW1w__qdRnWM@ zpFSY2lajGiKCJ_&TQE|7QQ;rMd))6cC0<_5H_h_=vdl`38-^A(Z>GV~l5pqa)!7sh zuCmV8G*b|a1?%{@GklM#-n$7qD=DOGRZoy-aYGc0tC^*Y&osqnG|%Ur#nEyq!Hw6qqm*g+kEAf=jNABZE8qoi+@N zHs}%3!G`@1zLNf%(dHn`h^eB$fHjhJHG`F4ilAKdAlx)b94_0MD&ry703&g=3Rb*n&3}qwCvy`MXD5b#f0+J}$yrJ3F>8!SA=fmIc(mJzsG&N<{T0-j zE^1w6zdG5cg472cEHe`;x;;n8p_RocHNmh^-`~HmJrjoJ6;zE8*Pv9)SP_UN^Ny%7 zAIS^(yZK}BshCn0xhj?6vHAS-CLHiOR4vbEFtyS0!*9b_3^pS8vQm5YEbrIX_mJoYw(fszyz;-}e-%g|fUm1O zRdRcQ)Kk%sGeaj(VO+OUOv=$P;;v(Kf!0oZ1J0dHv2_HoBL>f#H*6y%#w~Vx%w;DE zrJF@{Oz$#Ds!EK>D7Kw@{WX-(bt}-GmoV1o;zr}vWbWp6)!3Xv|N-tCIxqMN20ql;$vvn-(UZ@b*I7LHNsJuMdEu#uNk zE&v?Tdv@#7HCJfc`0E=+U;j~5Xywk|+%QCZmNS%WMT7-`rcTZ0x++S@sx zZnW6xDP$p=O+{H;7x)J3?8F`6Cfo}szTe%CJYVEZu)eWl{{etE66 z>-p0DeAZgw^L~*#>FN4>dj2Z8=GW`_`aHj%zcTWAySvM1^PM=DmfM^U1^;Tx^Yvcs z@_IX;m?%{<%%UYRA2!EUU{N%<7^)o%EXjgBB&75%rP8A-=CK?fIt9N-hdHG5EnDu= zhBbM0LnV9CpVQ{-B40%I)g(8{jE7>mGdktK|AF9kM9%U4u@GtCM@%sRq%_w!XHx9xz=p~x^{zwI$iEuO0n4<>mnU)@fCi{Z19`H zS-)u(`&5aofc|Cw;6GziOO$t9&==Yg@LyefBy7lz{nM99;QAssFq!%Hgc zW8s0wbe#jc#~4(z`|R-_1gem;w4}}n2+!2cw(JB<|9T)rUBM!^?Ls@kn1}LV4m8=M zt9L)2)VKIgBg6^&@40q@&sMr2(wn%7Gbtw|xMA;i986w1<3`m@%cX!wSvSF{>z6YY z#R<5#vFUJQ%CaC~M8E_I3>Gx!N)eUkkw1Nmr^8T;${-Jp>qw|EOI`W5g07pzqE!T0 zCSa^@?e{vdG=n2yA&Y~LVxM8u2VkinXNk)oDshevfYn1p?k&WtqUyYeuCWUU=%eb> zpTrrq#>3J(ed2pNu@p0akbsl}y;D;)0My~|%s8aT1u8N6z3Cb<>ET5#F=^rUYLX{VjZ7*_C9DERxAtOd{`J0Yc;?CTNZn5xS4q(G6skI^Ej--oBJ4t0r zP1$u`T0-p-yaZ;Z@S_g23d;$|z`(=d(JDhVl;Ld``V_qBSHCu;}ZcTg(JY&C=NvhkULr7sEhuE zs}LqXvq|v?4Z7^*m;-S2Kgo&dW*dKbmoC6@PNm~KRam0WYEMUL#dmL>XTq?d8Lx=) z|MRzZPWN$oQ~%7I3gvWM$Cb8~BR%y*7(QGlP8NlJ@7qv!H>rSn(R8Vmz1+UIlUdEM zBTjKvj))N_j=|X6z*L}XE5d%X->iBRJX>H6S#ikEjch0lba;{V=ILF~E~jX&0lljJ z29NvxAKL4~FQKVM*TM)b!9iiH@3G1E!em3g#X~5U<0HZ3r98V!8&)D8-t6&BT+lQT zlqx?)3qDPRld!kJF?vhv#!7lSJBILh)c4phonpL#`id-9C=wzIB)_o9#{$m7AfY~- z6wR1r$v98o%q+{iJ2;VMxjjWLGrOd9ne2Z?9fwiGf}+IYLk>y}Dul~`nK_UvA~^l_ zMvdpr-pP~^0IzbE%^$!Gf2&Z7RlCwTRK=3|hAp3l?(X}jh1^rs8&vU5r6R{pPYW@up^Jo!_ z#x+fzN4k zw4u<`Y^uvu7b&23aOpn++Y5%wn37eR$*r0OMj}$^7S7*>cQv*GuDOP^*H1r&l$$~l zp=QzPx(~QmDn0b2Nxk(qGH1>Sa97~9GuB$GZ(2#u%HaQHTRwZ)Baq7nA0<+YadcG}XY@zm&VUQw=>(ORyz#8=orWVE_jY5k~h{}9<9 zUt(yMG*H;KjsBi$d<)Y;Q*{FSIxQ>H!AeN7sMD4s5p3-Y5;i;qa)C9?lugE4NG_}he$?oqDek3F?!Z^USI(0wpX)WbW~w%8mY5b0(4{Zmbgy^OJj zZCRq0tb82pSpLhInaN5f>%qrUsbM}{>6hRE)-AR31E;&B9PX**xLvajyi>((nDj#9 zzU5ZZqBD6Vk#Lqg_V*-HE=V-sepqAWC0MGL{gAgk7$}1j5Au#Y{>XP4$k2aEV2nE zu_;6oZN;%nxmLF`V@p=HDXa;qG)Qq_>vA*YqJ3{Zm0ebS-4gOr3eaEuRIr8iIjEVtd!3@jSQ97IVwi8KdyiTE~@Nb^t+5w#S$U{6t8jFgw9f(6)R##TV3g&1&P5HIP~`1scJOd5U4JqCWum0 z2@uab)b}7F3Dr;Cl}_pn-S!jXw|HhcuMH(_X@W(KwLO;vl|(zM(%uYxLTi!BvJnDA zPw3h(bavM|?bXh_uzTp!sI7Ro$f3Nrx_uwj6*g=v^kT4mbQebU|JvogB}htDV&- zWQU6bQ+e`;AtjCP_M$$t^O=l-ah!1265cgv`ohv?d2zp=oqa1!F_kW)s-n(Lv77pi zJDxbafxlXAnK6DRCI=$zO>_3cGDTq2Ke{mgmN`yBCZA6c>&Anov1n%69aCK*a|X;` zY^397Ec(!4Ee1~HpjZz+b{z&UwlV9sHq(Llv2R39UJip2SSr;&QZ1cOe~;b6aW76T zM4F)6m9{xWFV%^;Jm<-FL4v&}AJeOX4ZC~r0A%*SiKQD(GEnJZA%u&qd+YQ3Eq-_$ z_eO81nY-`!N(TC#ztr~3Lt}#bE*jbadVFxY$nRnN%qACWiPT2$2~Y~3P`QBYbke`^ z$(vM0o`oGsLwkVSa9`Os+7I15NzxTE^`Z8vD^YYFca@7xzmAqUhu);ReVMQ4yZ1{D+gI+e)z-abLs;1E)^P%Q@W|kH_P=_omD(ciP_K_xYllCq-G> z^89L{M%As>STZBXx1R%p}xpvB8R_YfFaCiZdJuJvtbYmcW-q zA_Q=5mZi9KcE$S#c|8ZWQ>dT8w}zEm{aSskotCMhVT*r}f9rw&zwR5>^D?pnj7Z=+ zmFho$$b7*HN)j$rFvZ3B1k6jr7nfSHsGwx0t@7*iUF&|_Jr$Q)>liArkk=+hw?IzhuFnu!k`Id(Lk9Rl5ET@ zsWO9CB&FdU3RYlNshI$S;f6F1$f%rQiH+!-N)fBy4Fd&CC>^+p(bfd3D8E0)L`lAU zR^`q_N!lF?4eKBXM;SmD*Mj8vbK^Jd=a2hEW*H`=_e&|&cP#g=bC-N{U(z#|F!~UV z@y6KQyTcNLqGO`iAAiooJwNcD-KterW9Ki^joPo+HM>NQ+}o?kaa@xaDkTe*4%YWd zuR>n3lyOiFqrZgjDXI;h(A@Q#u3aM1?{~2Oa>pilbam)X?(rQB@FL%y!TwLifdLGr zSt?Kj*4eLh7cBn+AslOyA#Lo@8wbLXfI_axgdzv$tl%KZZ$ z052huKU7fwdKzN@>jwdK*WlM}le;cj*gLm}2VR}(ea=7lE6mc^fY8WAVpxiaw0djo z((}hNg7j(0aGr|}7&v8cjk=Fh|C!gS=V=CLv3FZs&Q0&&aXz8>9nFRN&kgggdm24? z4$-1uh#)t~UMAd~hBeQR={)9)gGkmV?g#1zA1`E`=k8C_02JzOyA3z*4-iK!9$sOK zq^Np>>$FZ@hCY}kYE>k%92)09BrgcbHkPr=GM+=&PkcQvVpuYfsOmU$Gz_#glKTXhH z)BmiTl8R+0P3xv+Lo~$5lKCyh?ve+V-W{osS=j=z+BhiKlDeGNq`bf3Ph1ORHYYkw zZk1#1)N_-Ng{93II4ASInS`;9hGVf0cgtbci1%~yx8%gn=2EQ}M0hfDc7O%z%uL1M zq61IX&Z_l6eDA>2zzDv?jWzq-hbKSaD*WE-dh^LVz^pMoG{9%UW746AyRUI|^xjkR zeewJ^zLe0&Rq`asKiSN?NGn$5?zv*W*;c4heeXoJ38AbvRic>Vviy*Znk*qAW< zTmEZyyU>`nTW3e>MqK$KJh{?rAzMW_Lu;|7uu5z(-$3A-W4Ec#7Zxf?#1Zk=al>ZJ z1Gr+>ts@Nhfvj7k{^g)+xr$vOA=5IJ=J*>AvN?kVMSA8LOR(+v_9C=w$17Xr6v85_ zzUE-H%)8uo8YCmZeck#jHXu3S()#lhO(A73rlWtOtN!cNYAr`A&m@U?b`&4gdp&hp$=!Oz$?#bPBrw5A!X(;U3wCRy&lKen(*BaUoZ0vqx9N zGZ-12$C|Ap|BdDXCh*ik=P`Y9BvaO#|7PH7xCcbOJ{rIZxl6e5q6Ea6-Yf1z-#(qU zeDxRzQt5vu6?yH`xLtBJGo4_f=P&DR%}A6FDf^ z{*v0`^Y<>6U+)-ySQBD*=y_W2^Ydc}ar@(Of+h0VHe{IFOBm%(_WH|4+XxC)Mle6V znVlI^1Tqt?JX|+j4I~mLp1Wso8T|5qDHMTm9s~PM-(7s)Bk5F1fcmd)bP9-@G^RD9 zbT**h#(J7TViV4`*SuP1t)5WXt8X##mZa`=+J1E?nG=-55R)Bf#UPUo5y2$6^-586 zg`VPJ$je5|V_0S^yS${bh{#srqQ=%}iWbh|D5DeOqDYE1gGVp^^F|BoXFq;TyW$K{YN&H1vM$x@-6&Bi9Bi2ML-3m(0f?`O5Ggm)uOPty zr`_66SAkV$N#h{#aw+L#sgP;u*ZUDuNUGGJ6?S1Bf^$;Ie*;P&2{h*~&%D4bZQVY8 zaBoe9J=$=0=52M@e+f)p6`K6Q9I$HOGxJWkkW0Ayye9Kp?(ljP)Ujk4b#42hR{3ar zZ0IdY$%jl65!y#E>B4n-%fNsv*u-?L8(#FsN1?8BIYj9vD?OH*t_AbI)g4P5xZi=59|q?#i&zH1H{Sa8jpn)xmzX zDC=7DG-3rZ_hch({(XGI!9baGAu--{Azc`)2@+ZFFCg2jRcfBvBS-sblZdX)%vCpY z*6N>o{nr2xOqnyzdpH7geldQaZBgO|o_K~1bROygo|JAYRl^fXA(ooD1~6VD%umjg z5TqHvl5tSTelr+TIcnD_S;(Uhs`mj%;!G}ujy9vk!>;{Q(xEax%W~VOL+zK5k*L_CC8pNbtiskvZ7<2d!?iFszF~W9sk(un@gZ0+N8LB*ub7Q zaYYme2cOJ<+exzLyemJP%|hWE*nrZ|@WmuA5p;bN5>^rN;3uPEWD&oa4ffTVZm*I!k*jEu?Z#Wq~=5$T4PBH7>EBpDguzjr~UP ze9fvlP_TIlCG}6c9V3zX!uS-NWx{O>oYW+}ri`UpE8z?=@>STnX-u8yo{pJMU59$J zV}N=sjmmCiEZ*BQ6uS@D-fU>%HW|8hF-kYPF%*XP>#74i;3k3>V+aSiCd)*W`wEre z)U~1<@M*m9uiVEg@N~qZIh=#@#YBvjZe>VMN?s&+G(glBmae% zKqa5o8MhhCg&QEA06{ak4nqW;|AF+cYRBBe`D4xYMGJ(_vqgQBfBf;C!XQY0rTgXA z|9B>3k!>(=|8^yDf4eK;|3hgxIeS=}IQ?@FywH@2U1vw?#ys&wa(+HD7_-7o33TrQ z0Vxvk-vsHJLoq>}9mqS0&Mx?^`zH14jPInlr$pRWG&IS0BAK9J$E%dGGIs02Whr>TiA1*ltf~rA3 zSVz(%eiBPsdrYku=23?8j1Wm)?SaSaL=wy+F}WABkZH(Abp|2AfQqOs=AaOxj8O#( zoTw6^5Wg9;owPc%{*02A__?AvlTbW^*O@88Br*?_SHlY0HYa(mprbkKg)*y|K|x9% zow#D=_ERm~JGZqJZds8QyiH5;XB$4*q_VPi=rek?#F#v#50SR_o%zWKvJ@$YuIQf> zc%X3+#uua^0+LW)5O}jL(Sd`+hX4@sSz{Ac=Y7Hw6wpQg17WEk!K|m3yAeCR&yUFG zI|cCom$iy}i2RExE%BcZoeH~*ij3LS{-@uDB{6 z?=bhdBvYDIuo4u6mMCC=F1NObd;?Z6NP{#{gii6*`}<$OFfqNUN;2U-6u+h^HLcn; zynmuV4(?N$B8oIN7>6U_L(;N0&oZ zYF@!=66_S&6dL$>Lkx?LSx@73Pc0(8kF3!gCQQ;6hIjRe81G8phHJ z5oWf_np!1}h&?KtDDKW1H!9HnBIxFtQZ0^@Yq zxPb9uKQ`2`RD>GqKuXxoG~HgH-Sp#+2g`xGs+i+KR#hf*qQTUEpE?0Uysp-0!BZl4(AVY%X0?ryM5861A~ZlG9FpEH6w+rPzQc6vOQyAyD=8cFaq z!}AOmeldi${(i)2W^bDzx({-ks2<{9y9~D0v~aWY*7k}FQHYRRV>nc7ox>RoRgIb} zS@$7I-K$=@?n@1C@&LbYPWL(VDp&PdA?=?Sgi8JCJ~^Ktddpsa&koZXesYB3SDQ}9 z8vZ+;GGC$hG8!47y6N#bz*M&4td#BYhm)ViESJn4J?{8R!f8p zum}x!^fto)RY^>%c6&AC#jwf8mKKdAWGHVVzSeL17jKu@$TOUUc^Hw7?1asd7xG)4 zvX+nM{bRS)9lAL|IR__xVpp3dru!Kh4Wjkyrice{(ztx8ak@_!(4)q=cR+$SsrhfjcY6& zYgbw)-qW<<0e5BxS`{?{A1ZBUpCL9g2L`~ITLzOjNGqHSiz&;E+&a4!eP_{4a4zTt zv8&W|xt)y6C8v(cITqi-^@FEQ<9=Gkk5lY@v3VxgmC20dd=-)TxyVJ_PA+}YLEvyl zokJYzmVktvM<`Uu8fX*GQ}2iWIb`Hd8(dc_CJ>OhG7u2je~M^x14k2MC1*zqTeE*9 z^`N$u9jZmjXZPG^C^11uw{c!3ezhnIYgovottj8-A9kMVWK~OS#=$fF#+G^7`NjmN zdQ=LBEI=DlDAFi;*rm2OE>Fytlw6m}q1;EX_mpSFIC=+4*hFPAlA`spC)afw?=jbL zb!6(-yHDv|BR?*5P(bc)?_XDm>_Y^dc)XGn;>#G^N0zZ+-uUf2 z4`Q2ix*w*$oS9I$cq}=60XOuHABaZpJ9S96!4mkgSz#L)!ypr`LbHKQyuz(_p>S(toLZ9`s-PEW4f> zlG>jdJ|t*{oenKV9v7z4=akC*k&7Il&)vEaDg3mr`yBE8d$j%*`>>dRrHu;eVPl|d zeD|oQ7w&Uom#>v?{w_wa?8S)0%gWxi^JNp428xfes?opOf zcRO@#yTnfg;aX4M9LJPG^SGT3P~31UN_`tV0gBc7Dq`mx6*4p}oMRA`B#uXMl52iF z6pi=&&>0xRe$~CaMSzvqBtR)78R7N1-#_18jy>^Gzg{m6mD@NNStg0jxHo&94MaHc zWwn17RsY^e(b{eQ<|e9HF+_c|zL`b&8P6=q|Sdi>cMr+i7rJg zl%=_s*Oo}{<7WGK*2&i*MNg0V>jM5Vh`3_ns704PPa6jA*(@zhXQ!qY6;^K}J*yAW)^+BrO2@AxRcrB}D7{HAQ{q-R z&!hPi&D0(>rtLcBsVGIV_Ry}0_0hG}h;V)Vgpf1rL361u@wX6!ATr*juHEw1kRRm?7A%dWe7yzz+ zD8iGfG&LNS{M{WtD0b$f-HMOaJrBXr99^WF5!@?m08S!sc4h$1a+a8B=>S$}Y1bY- zpbICxCwH8Of7XXe7kD3DKE%Z(mUSosAkFrOCJ6J=P}WTsi^o?%JZ_SPu|*HWYU3ke zmppDsL8)JL%L-RWpA}6J`K6ipr@RZ1)mAohOdu;QS}iEoa$xfb z$o^wK$6lMX)Dy7R8`SteAS&UCd zOpvU-WyXVwxubR&BT*u>)e)sadk!E=c^K^W?oW*~&{_0wssK$lWWN2zwLstG=s-FN*Z{W>rWXv2yP~tZ9 z^EAqn6EnOsXR|5Tdlezv&6s4IZsV3~!>bB<}Eq17!`p$tvyt0k$J2ygIlR3@OFmHh*&!2{T~Vj5jIbmk{b-P3RnKE%q9VCboT1BY+yOtAUG)jG4uY}tAdp@jrQOd zTbT=-_yvbsgW6@FP!04q&a~Y90bsy*-6V~sR%C>PCUo*D=^l~c=$Pdj_hP;ekiMTx zNS%NRx0&C4&LV&LMcZxvVm*rZSdQXPOpgXZ-Vt~858H+$kJA<)6mzq+ZlhS0fC(H$ zTm9+2sUHxH&n9fU4PqdN7*tM2+dj4N2QtP5pZkt7*YZou6Q;*srr0Lz^8b0@9&ehOyz*!^nnAha z<|8LVwV)X`Ax93GPxg(j@>^x)IN()MotNcYK%(t|-%d@A(h{XadJ|*aAjC!NpX@lV zItU2<^j0-owXXV+;i2@IBVlN)pgpvs4le@(QN%FGMWV%}WXGHkIKLw5_fUq=+?W*b z(WDTk4ru|!SPq81=q^Be{VUpK!lVSx-2U|E#Xvn>;3;Yjf-={xVcy*VQdY$>pVq;X zZ_t%XaACC8XYm!}<{9WK=8!7RFX7DUl#2dL#jqEnou3s`R><;%s z_3f|Poj)q#Lez~=M+brabBFb~JSZYG68U}Q{qswR)^;!J@=c&kJtLPA?b1@R=3~5y z=q&>5gozwUxKw0p%-I$yRTTyl_F@SKjnG0lVJFQwY?*;f4d?P!Ox&Ux$`;}b#aINn zJj*+=Ho)G<5u!YQ-LfQiZam2K>5RdVjIFaSA&{kWSBCiaMY8VV_neHd*uXN;Y?u7i zZ-Wl3EI?+{k}lfJEW=S^3t9g&%wdJ z9GAq4`1%C*22&^Ovo)=^WRantHHVnr>VP+I2h~mSFiI9k#rD%mc@!HAa_Rw?!T99R z8^ux5@v}wZ{(ZVLk>JEH4TKk{gElMSVEwfxzT^lw9uGDytMxxp!6`XdVA_oS=9yn0 zfy0s~c7?Xl9e@$)#v#!@s^n6XvA60Wdxj?Qr0SYGq4O-7AM`bM$yD3-5^*=tHx z#exCp<<*^aL~~>D@O8NfT~tTB#9?JwnQ0(5iL`rh$^f}JFKR{Xh+?jgfzc@$i};N* zzD_20p)Q>ew|{iTd;XD#7w_3Y0r%pPWEW3~QqSUxc?~Rw8wVH{#ds4~0S zF0qjtahSDsM5q*6o}5pDC_UImF~(6GQ1wp3F*P&8|XQ zxO}!@#Y8S7Rhpm2XOKe1`QHou6=6yrax?kW8Ptk`)JD_pndO4S8R&_aM*^-6Rc9kYUv49sIroKhGD zuTABA57LSe-7qJB=_JZ)IC#ztG#kT=X_V)=CvMCc7^qgGGGYdd?P1AMSKLR{A@d2# z?tX}K8WXw3Dut*Ha4b<&hvx>ZYHkY`;AZ(LQ~^?`4$v`?l>=?<%q=r>G+SMlVYSt!IRnOkqLH{*p zsENPk_{T-3?bp2Tmp}hSq-*fs%Vj~tz^xrOnZ>0@O3H{Xx~`-nc&2E01JE;n)Pvd^ zKyws|Yk!B_p+?-$T<813kYBt9{dM5Fc{8#M%P5JalB&)HF&vLOCLd{}z2K{>ya-0m z{@{H|LZd2c1H^*TlHcWKAr}LIJq%W6BO5n-W+94jX#Iah01h)!QY))jih-!-q`Q5tui^lbwG`FOVAHn2)`Oarg% z9h8&9g<*Q4iO(uFOz?Uwc>k=}$ZBz5%h^$9^b;OIoJL7=0hpwNG90Lb5RjB>q&gp` ztpx)^=9%eFY(QBITtjP?R-P$SFA||*`eNT>gmtZI*m+?b*W2jEFHiBDM^EElhoj_t z$c-b=VC}sfeK^h8w)H(^Z$>A{EN736&&|BwG&>nbIi85%c zbzN{Y;Y!uXYoz%j&glFnV_G~GKTDC<6%P&z#>U3fN%D=lTU;(63`|S^3i*{#aYk)R zG&KBO{{itf2?wPlFw#1dvDdz`Cp~o9l$J@crFh4QHPfdx0b@*qb)J~Mu~uGMnkD9w zL|g0hGbN_uSI3%1VJIvaL?lK2rvmdYYip>jm^?noN-2j`$K{!AF{V$;PzI!!CcVpt z_o}ojQ49qi+S?Fp&SE*Hzo&Cj2jMX*7aL*G#5i@9IyHx^G3`h)SAvHAXS8eKv&$J` z{Mn<5=Rn-8e#jdE>9nyC#i?tk5A(=9kn#1QRW?KY4)_*#!&UWDAThmiDFs<;G99r2 zKT}BzV4whR7&`4amYNvrLZiZS)ViWP{?UX^NmUqWaCR>8<9-&+IRMrRm~Nen=LSYI zzRZ*nHo;gv{)TywA**=z{nMoId`Wj~;3UEf@}aqs`T_5Y$zk<2lADN=I<$fJ6TGLU ziZ!t1aGl$ioX?2y~v(!nfcHO>)z^II=(6f5G5~wbhZ0rg!b8TWHLBU|zXzXE05dMiha;$8<&<5$=v;CnYj`B6eZk0AHgO)>)D4VgeshTT_ zy8%Y0%MC3n-q=aH=IkKRf!|PqpoIoQ?fzS_ z6+LOl9Yp@#X|MXwUst+@@R(m=ZlJNO(87O<^oyYBfV+F9}I<6o5*)l%h&qN zrCv7x6IhZbWz8~C8ysLAm7#t>}oM8U$aGa7JL;a1cS^vlQ&Yp@Ua>-!4 zppA5_he8HSiR@Ze@pC#`LbcxDPmc@9}IbGk1DGMvmkMxNqxF-;w}~Z8ai~{UBiSZ+jh;{Z|VYXOfN)8gH+;d zm3?wovrR7&%$=~$3!Ctn{T~+P%dXJP==X%@rMiZ$M|1v-m>|cIUPv)espI$hG^-Dh>6Rs3DM(K@w!eS&kQ)UNF;+-1`Ei-s2rgyvn!QKFLS0uqdR zM5!dg!37ylT)B%=T_?h2ub8V$voUY&y=S#DQ#?+L-4#^?%?i8{Fe3x0Y ze)MbqlX!21!dZF@3tNfku+Yx?Wak~QFC67=bf4~RwYARFvxJ9 zMm&S~ponXahWD=Y=u_~Z7dLIKD{7u=xQqIxo;|VL266F*g05llp?VMRX2cp&Xt&rQ zRyC&Cth>Jyc*AZ$CNJ9Rp@VE2FbwyeT7l082p%C~IY*Et%N0bN3`D{4+6HByY2@{Y zJf;g!EHoUeB#J*#pKj%9B$92|PG&g1IcP`uL0ESR|G_ zEGCkiH|}+DIKT5tfh6e-2W9?d`U3XLnC~k`_ALMBCT2L;2_MsJ&)1ReLoAH)`}vH} zkQ>cH@DWilYEzOPaIwp(ie7dzawtOk9RWsVfqSWZckJ6$7b2wB1j#Yctj$Y ze)Sm}1=zwQt!LM)kn5W9pYRSCfUFsrsL~rXm&?QRYBk%*bz<)?yqO6h>nau~v+#)D zgX#X0wZNQXSHmS#u&DuQDy)ucIjd2|I-)-g5de>}6Qb&7XUjIm;~s;qPqN;V3UfaUOPWCuyh6WSzO& zwQiWnHj*Rqjwdcwtz&SEYtl8#O$M!@XPsE*Ycul~xw@5Jq{lOBuj|A;7_x?#v;~dW zw}^`b(C(p|SD$wlb}LLmfz567B#As!@Xfl}BRaZhs*-*r( zR!DO+OlDr1R?xPwRA3bt>L0kyq^cbLz8Zxp-+0=D+0oHL28Unz2;qGA2*Ia3IT3s? zzl?ch6JC;epO3vHT5RcRxIbbyOVC|$k;qKjsGY1K2!_OcbC~c)W#C5WRw9NbBA0s^ zXEosfu!L>vk~(<>Ija7}qRx`PwyN+koYPw<3yh;g9rN$Zc4SubTXwx|w%emVfUW=Y zY{Ya;^Gfw**^Ib=4%XMnkW)Q;lT!mi!}RHlH%Lo&zv=z1qbd5u-oqcMTV-J2mFalcK0^hjmw4FvGU^EUmeRBy4*nMZ=NMq@a0qQ{1f01O!&;8IXl z&<`c=0`UG(uUPxNl_ zlj*+ic9*&iQb&+!yKqsl=UZO&s;vh3jeYW%1HadC>N4s`NC4SF=AY-qoNYu|l>z!W zVlMKl##zHB<2$7W->f#|V=Zbin>mD9HxJ6GK!wml`4C+2?O?hddcN)W|2=|;$A(#| z@4H6uJL!|;KP>(Kq=o)x_TGQwiT+m(-@jR+L9u-i{fuZL&!C?|?w*ND!Ei!K9K@|E z$DoF9YY^+HanERfJsWXNdJhlnrw`dP-+9XcrU>!03+*7m2S%9YbvK@CbUgy~oM#(o z&~&_U2J`gY8KAPVlHnt9>gcfb!3v~*u?BnwSLT;)bLbP>52VqmwN(E#*^LK!?kgMxbx`a7$e%P@OP&tfXYypR7yicm;x(}Qg zz!E@ho(I`Qd*5*H`Fa20x{lbQ4pAa3KJG-IiH-`AK*3x5IujbpVYuM;lRB%EbD!&W zmp%SQ;P|Q9wf{bgRFWX^CyV3hK)j;JJfkr)G28?UgLsV_gf?TUz9ZK0TpO#)eKoDTQ=O4?1@157z64i8LDTnjm)w2j+rqqG}M z3wm!sjE5F$bRunNEQ4wZu}~Gku(QwN-n?Sc@w2>E_}@Q}2^oj5W$KADHHO(AT_uf) z%@tbKLPsDw_`9zNeAjvYI=Xw^oSK{2eLfauyRpoiu5*}$Udy>Y_gr^|{ItPr7e)sW zfCw-LK23x@UUMg)*w5cd{P_5h?YgFix}#W!xD1v%mjvZ|s5YWnhbt5DzuLRbs3z8S zizuK7A|f3EN>_T3UIZl~(nLUd6X``lk(P)es2~U^AP_(VL8|oLRC)&?(h_Tz9Se|I4qLAA4u!nf=bZ^FGhBr^`k2E4bC=`F-0jeFB#+5r+&#+d}%< zwF@26oPY{@!Cl7X*|*Z-E;@N%56irT66lNqN6Zl)6UWYk29|vzk2Opoml5t|k z_9aB^oITdw_THY;zt~Q4KFIB}6F%+nP~xJA9jo?SyRP=I!n?MxPmHof$L)^u63IW2e^ z?7mf{f~!7AUzs~?HDsE+CJVqvJ!2{aMAra5^v*-1+>0pe7ZdK!Db}u8i2CR5+!Kgo zjlXm%?8*7_dNQ)iTYr^!3X<9Tf_yyP@4LH+ zIr})c|0?n1&g3N%%-}wR|KGp0R7XP|tx7dyj@z2atPYP_60~t6IB^ zcihDmyd@-HKm>L@(bA9&u1)l1#aB61V>-JscrG*A;YGw)Qz_(u;h3nue;FSfHulIb zB_zi`dFH8Nbl{yx_6?Hf?sJ&T96*W~fZltJJmX)KgiOYom=T$z(ua4m2T6VPb9%+M zE8}(Ai(k5lOmu97K2XU24(;4ingywvckn+p?oRIca)Q!i+G|(3i-qNrgg~i$WAApF z&2EDm_f@Ja^QcFOMrEvRDiqr%iVj^YO1j3*uUE1VPVdFoXHhJ&=lGsj!Z&h08xg#h zYWH1UGi?SGiGw}CUzrFC8o~(%oq`!;{3J(;?5Cc@I9K+TX;$hYcmn&V9I&D2E9Ns} z^pC9vK~Eix+V-g{?Z-|_8vu;=;LJ(78Xwrl6P|jQjB)>{%K)Afj4snk6W$B~C~$~t zFuwXxbDMB7P-!4Abg(k%^Vi_vV1`*KtCM4rJa6sMmR=TQDQwt;H(^H0!KY7Q)dIUQ zLDNkw@eZ1S^B}JKRnuzE^ga(qOa_NiS4GwIBq=saw;xQPYbdK!HqM>cIf>9~3E=03 zQYC0DSF~7Oslb64=4v7Pd3@dR<@=5JS3mRj)S01I`A4=Q$x3W$fHZALyCbwOD!WVgD? z%_u5;xeLe;m)|Pd{V?l5(C*QkaC}A#sqe1em~Ij82L||2Mq4k3d_S-@wU4mzZ!W$f zF8C})4RlgDJajtty$GchPn>9iN3^Qc zili+EE2%#*6nvtV{L=4BA=mC)M>XZqg1(q6?Ie3{BSKB~Gy%VI$$@gYgig+>SoFz*rzJV>9bS35Xy8PFahfUfc$G5nLMQXS$B;4YyYeNa{!eC-)tyG}@_igj z)0-W^6KVmpMH6bd0FG&_bBDt-L{KpEzVa8N?T2<*p86sYa|B7b)@36><4|?%rY%P` z6)S{swdZRCaHDHo-b@4p;aC=p6&DI&s8x#^$-3>qS3Rd-$N-gWWUnj!p?@07yXwk{wi6vdALBIM$ zy86p2Nftxfr>m3eTLU92wMzi(2WDh(@`4!&hNP;jNJKykaKsEZJ7%+I^6{& z&)(Q+zPz#1BT234+AP~C=3o2cc#TQxJBXA-=TtXEZH0|ESTz?7LaC5U-r_S9^eF)Nro?>S z{hf-v`|kFMgAt~m5$QOUAv(Imj5p)n(Wr6xpmKA~r5_)1Dm|5@r_Pja5DTq--uPM$ zNI|pTyp~mmA7xrkai7!HHre5R!>K%`6V&nZ0&@0zfK@m=zo&RAxEbX;ecyJ?U{N(A z9o0Hus#D|)DUgB*diq8u#BJxv)Sf{ke6v0ea37}iT9rXztra}a)VG3Iag(8<4%0)B z!KYR?UH-qZHlpiczJqTJI17W81-Z=ddnL^{hTNPw`~c7 zLdL<}9sQ#H72jkvh{+#{yKR~Mit9VSNHi!uug|Rk1{9K)S#4Ua#kg3`2(=l((WXo@ zFBRO198f5-Vk81L#T;*ukOZOp>G`HxYrM8dcctO`UT2ke@ycjo;QhY3bG$_#Z+C=_ z=6Zh++p7VL!!%Cr3o`TVyC@BXnu6!U1lY}@O*Ye_cA!oRitxy4UWSecgIxp1X< zq(GqnECydhT;SP$%)AE&i7c*%f5iJU2GlJ$3B(Ch&uWPOH_|CJeo)vzNwCLWxVJ%Z@8vOg`_!BAuvDi-7@_qjnJG7=mG)gVZKFb!|0b zG+<*S#7HqmRy8gp78%O5)xfq>onC{$Y7ATSXFYN$#LVv85L=IMnP|i{;=XG~*7V(} z7;tpvy4zpGGczmHfSuU$CTY)4Vse{4DNThziwJMfEt+fb-5+8qNN>+#C$n-q?GTks z>%$5`x;daP!-~oQL+Rt2xP3?fG_t8g61N^$J!iQ#+~yeK!NEV)su>&)U2L3IfS<)1 z;`Uw~Alq3MMk0b~i;0NO*5%mvsnlf@Td)q?rP&t%{<6s$8o*^)LCT8X&GbtIhvIw8 zw{*a_8tI5hF|EPl6dOycRUQG>NFkWxfQh0$WLDxJm~e?eaCl%ZazHP2a@#gOAB#y$ zo^j3PL2E4TH86sL-M9u2xACw1@>SGk`gh}+LTr-h6lFT++84aI59kP0lEy{eRxV>a z8?Iu=?1rSe3rJ&9U+zmJUICp#4_LYH_yF@hc9L@sbj6RJ5U}`rGU9J zz67t;?JcjS;|qC%=h@zuJGi`lhhPUYqK|pwu|o7KcyG1II)}`P1m933_0LxM3^&EK zulrcN+$-Mt+J|54bU`mKYLw6|%cgy#ixP89*J&x7nf8Nx=TdCfUZ3RZsq4^&`Ibh+ zSt5yOku~1A_x&?&VZJplz6Y)75boYGYo4 z8~pB=LE7}Qd$l44 z3SOKzc-s_B@{fRv8_J!B1*{F>USuFtcYuZ*cSwF$4z~50@Y(g#6ELIe{;nK7(ne!d zlb+t-q|RGSy`nkzaqmhgS$7XPOnxbG-u$G_>PYhQi*&-XXVMQ`W4H+LYORkBRb~|4 zx^XAA{Qr(2j-{?iBg^3wtd))q@bJXgiDkD=QSE7#6Ta9&-tJ@F4b4?>&n9G5Zm_ zj}tN6ZMLFmt3lonD}oJYzLERXBMM}2!8ex}#|6ywn@Sl{8+0qW~3F-t3Hu-JwK(t$Eg&Hh!Q9&*VYx2u$H56%Hi zxtA_>6^QM0a^+(mEB7C`u1K;5$bpPM13dVO+B@{d)2Dz_Ife1~_W`?0I6^)AlfTt) zAUv~gGX%GE8RA^Ad&3+KtoukF{dr?LR(@L{)tU#gjyu!un_bHbGor1LE`CTv)ZdLe z>v~<8RMH)?) zy)e)j^Ii#QBsObWpsT1dV$K|Z;icPeNYe_m%E?g1Pa^7Gg%oTF(@mPTZ{JPZcOXfO zLp-q4cKa}6OCK$hdWRZR%r(nIwY{Sd}B+*!z<>vWt5XuMWo{SCek+N_b% zwI`%3nOY>a*2KHopomT9^40G`tH3}rfp$HxiGp<*#-~pLdKDu)g6}I1ybX%5TJgCL z=A`Rip?3wJzruE6tGtEgp6Y{Okx3n|`^`X(=q22kq`j+#!RI`R;4t5^w!Hd}IgZ1| z@}zgVpYZ7yTf0HEt=*7Qa-Mi-p97OS|N9n*>gM;rmsJAGjl%n} zn-`d8Iet{-zCinw=d36L9~3n7EqVQDWIj*h-yFYe+M`M#o3+dR(~@3jG8>|L5In7L znm0d~>trc~(sldXwCVzlg}bRBtME_5Hr3S1RI{gEkbJ&qbO(b;8fs#rkf#F^J5fOj zR~y=r(w+dgM;~PS(JDj@tK&9Rtr}0Y03fl>)EMg7(n%(g?#?9} z8y8r3mL?W#yEDG(1jdiGc;$%tN0K z-@uN+?%cQ(icgU3rt4y)s{W=@(qYg2zZd*pT;>m*J6tDHI9yX?`PX`qzPG0r=>N5- z^gyr9<q(OMBF_EqtCKrBnDD2b_wW-2c;lkMY^QUpxj;z`&vxnhOU=Yqn z3O8`c3{Bqk^yHw`j1xhpc><}Xr)C!iek&Cy(#&H~+aBQ;wPe80%0L;SGah^AXK-=D zlj2f1s{3KC;8Jh&#yOds-e&gkojF5Ghd8c$Pj2~f#}q-E+s^V*Oe0y)C<@VW$3Yt} zNe31Wn%5<_vAM=MA$DW)%|DXors`5YOzaGsf<;yVkGDuGrj&r+yxd3Fs}0 z8m=Wnn(elGe)A8iJ8WP7LjW%)a!cPj44&;_&Vc^VPV<4M{jaEr*?W3B{MEvC=+gXO z7tO=a1;<(HedE3uj?y`xqs4L#)ZWyZ-~+F9@$rv3)$@2&$}rs~Ti-=xuN%8QtPjI3 z%*=$j)tLCADMpQ6_t8V?FNQL`EI4!7#?=9ezhG{Z4Y;HWdTh=LfVjo8@asga62Vw+X+| zPYs%zIeYGey-8J>A|KhSCvrQoY`&6XUyA@ztMp+?-{N~cp2+xvIUhEBR)Yih8+L>@ z0|_UnC8^cj22}ZqSEfR0)NiUUEAdAr^=Jq7F4Jlk!|U=PP}HdiTHlL%iAh-!*%Fp- zrEPf~K$4fz$Zm%BtK8f=Y>xc*_-#ndJ6mulKZ!$Ejq|_D&(_Q9zv??$08fo?@%ZtV zqsXm#jrkzh7=@A3LbbZNJ{`C5xI3yyYV1C5rGwr_%f8%&OLEO8Ua|vq>uJp~5=p!+ z$=OuA9#T6oU`Sd?YiDIq9HqK+-$OSAEmLyiy2+n9ZGEuf7^^S5nWZ&(sn4U<=O#o4lw;obxC9P+*{Mrulb zNygyRSMQ7&g*)yu<-OwG)3}}*>Jm|TkN<`cTdHiv;B($&I_XMQZBe5zCIS1`)S9Ne z1(k(*wbk47&n8I+yLi}AT`__}prP1zrrMVyWyyO~M&Ik_Pc}3MFUN%t;@kn2EW9+hnQHILe_qE-q|(k!RE7nr9K0Wd{414+p+`Uq`IQIL~OH+kRrVCX1&& zt5GHtQgy6s@rEP}!GSU@T=3e1 zLk<61;XbPJfnN_Vq~M{-0f!1d%6R;pj{Z;Hu-5QEtGJHj>5+r3dcG2u4K*asf}O zE}=%4E=Im?fC^=X3P`TiEo3UsxMd4(%`@a@-nb_IG7CDo#!r)Q^)^fQgA9&>w~{dm zrv4Q?tGaWc|eBeZ1`=12={F1`&1YL*1 z`&&%EG;|zz++F?%iaIP3IOa8f9Q;qa?IS1|89Vha@ZW#@FZ1o=JjZ>NkC*~!{&Nuj zTc>eUp>dq$xB=4ugWQedG5Gu99L4jG`Z!)PazvT;wPH%pPuUP*E|KG{Zar8eQ9lxWy?S4OnKRrnFwJ8n<_g`~*dNRnNRsP_E HzxMtI0qO|4 literal 0 HcmV?d00001 diff --git a/robowaiter/llm_client/test_llm/validate_data.txt b/robowaiter/llm_client/test_llm/validate_data.txt new file mode 100644 index 0000000..396cf6a --- /dev/null +++ b/robowaiter/llm_client/test_llm/validate_data.txt @@ -0,0 +1,40 @@ +你能到另一个吧台这边来吗? create_sub_task {At(Robot,Bar2)} 当然可以,我现在过去,请您稍等 +哈喽!服务员,在吧台那里借用下充电宝行不行? create_sub_task {At(Robot,Bar)} 没问题!我马上就过去. +麻烦拿个空杯子过来。 create_sub_task {At(Robot,WaterTable)} 没问题,马上给您拿一个空杯子过来。 +你好,我想点一杯咖啡。 create_sub_task {At(Robot,Table3)} 当然,请稍等片刻,我马上为您准备。 +你好,请问有没有空位? create_sub_task {At(Robot,Table1)} 是的,我们还有空座位。请随意选择一个位置坐下即可。 +Hi! there! Could you bring me a milkdrink? Thankyou! create_sub_task {On(MilkDrink,CoffeeTable)} Certainly! I will bring it to you right away. +请将甜点和牛奶饮料放到2号桌上。 create_sub_task {On(Dessert,Table2),On(MilkDrink,Table2)} 好的,甜点和牛奶饮料将马上送到2号桌上。 +请把AD钙奶放到咖啡台上。 create_sub_task {On(ADMilk,CoffeeTable)} 好的,马上为您放置AD钙奶。 +请给我一瓶瓶装冰红茶,我在旁边的吧台这里。 create_sub_task {On(BottledDrink,Bar2)} 好的,我会马上为您准备一瓶瓶装冰红茶。 +请给我来杯酸奶,在吧台处。 create_sub_task {On(Yogurt,Bar)} 当然可以,请稍等片刻,我们将为您准备杯酸奶并放置于吧台处。 +可以打开大厅灯并且关掉筒灯吗? create_sub_task {Is(HallLight,On),Is(TubeLight,Off)} 当然,我会打开大厅的灯并关闭筒灯. +请打开空调并调低温度。 create_sub_task {Is(AC,On),Is(ACTemperature,Down)} 好的,空调已经打开,并且温度已经调低了。 +你好,能不能给我整理一下这边的椅子? create_sub_task {Is(Chairs,Clean)} 当然,请稍等片刻。 +可以帮我打开空调吗?这里太热了。 create_sub_task {Is(AC,On)} 当然可以,我会为您打开空调并将温度降低到适宜的程度。 +这里太暗了,你能帮我打开筒灯吗? create_sub_task {Is(TubeLight,On)} 当然可以,请稍等片刻。马上为您打开筒灯。 +请给我一个酸奶。 create_sub_task {Holding(Yogurt)} 好的,请稍等片刻,马上就会有酸奶送到您手中。 +我想要酸奶和牛奶饮料/真果粒 create_sub_task {Holding(Yogurt),Holding(MilkDrink)} 当然可以。这是您的酸奶和牛奶饮料/真果粒。享用吧! +抱歉打扰了,请问有什么推荐的甜点吗? create_sub_task {Holding(Nothing)} 当然!我们有很多美味的甜点供您选择。让我向您介绍一下... +可以帮忙递给我那瓶瓶装冰红茶吗? create_sub_task {Holding(BottledDrink)} 没问题,这是您要的瓶装冰红茶。 +你能给我一个保温杯吗? create_sub_task {Holding(VacuumCup)} 当然,这是您的保温杯。 +只需要打扫地板就行了,在这里喝我的咖啡。 create_sub_task {On(Coffee,Bar2),Is(Floor,Dirty)} 当然没问题!让我们先打扫地板再享受你的美味咖啡吧! +在这个桌子上放置我的咖啡之前能帮忙把它清理下吗? create_sub_task {On(Coffee,Bar2),Is(Table1,Dirty)} 当然没问题!让我们先将桌子清洁干净再放置您的咖啡。 +你好!可以给我一个甜点吗? create_sub_task {On(Dessert,CoffeeTable)} 当然!我会为您准备一个甜点. +你好,请给我来杯咖啡。可以从吧台那里拿过来吗? create_sub_task {On(Coffee,Bar)} 当然,请稍等片刻。让我为您准备一杯咖啡并放在吧台上供您享用。 +嘿,在吧台那里有甜点。麻烦拿一个过来。 create_sub_task {On(Dessert,Bar)} 当然,请稍等片刻,我会为您取一个甜点过来。 +请问这里有没有牙膏? get_env_info 牙膏,None 不好意思,我们是咖啡厅,暂时没有提供牙膏。如果您需要的话,可以去附近的超市购买。 +你们这里卫生纸用完了吗?我需要拿几张。 get_env_info 卫生纸,柜台 非常抱歉,目前我们暂时缺货。但是您可以在柜台处领取湿巾来代替使用。给您带来不便深感抱歉。 +我想要一杯Bernachon牛奶热巧克力,这里能做得到吧? get_env_info Bernachon牛奶热巧克力,咖啡机 非常抱歉,我们的咖啡机暂时不支持制作Bernachon牛奶热巧克力。但是您可以尝试其他口味的饮品或者选择其他喜欢的热巧克力。 +请问我可以用洗手间吗? get_env_info 洗手间(卫生间) 卫生间门旁边的走廊上方指示牌上标注了“卫生间”字样。当然可以,请沿着卫生间门旁边的走廊前行即可看到指示牌。 +请问这里有面包卖吗? get_env_info 面包,橱柜 是的,我们这里有面包出售。您可以去橱柜那边看看,选择自己喜欢口感和口味的面包哦! +我要买蛋糕,能告诉我蛋糕柜在哪里吗? get_env_info 蛋糕柜,吧台 当然可以!如果您想要购买蛋糕,我们的蛋糕柜就位于咖啡厅的吧台旁边.您只需要沿着吧台走一小段路,就能找到我们精心准备的美味甜点了.希望您享受这个愉快而甜蜜的时刻! +请问冰箱在哪里?我需要存放我的食物。 get_env_info 冰箱,橱柜 非常抱歉,我们咖啡厅并没有提供冰箱来为客人存放食物。不过您可以将食物交给服务员,并告知他们需要保存的时间和要求,他们会为您做好安排。 +我想找一个舒适的沙发坐一下,能告诉我在哪里吗? get_env_info 沙发,休闲区 当然可以!我们咖啡厅内设有专门供客人使用的舒适沙发,您可以前往咖啡厅中央附近的休闲区寻找。 +你们这里提供免费Wi-Fi服务吗?我需要上网工作。 get_env_info 无线网络,服务台 当然!我们提供免费Wi-Fi服务给所有顾客使用。最接近无线网络信号强度最高处是在服务台周围,如果您需要连接互联网进行工作或其他事情,请尽管前去。 +请问这里有没有香柜? get_env_info 香柜 非常抱歉,我们这里暂时没有提供香柜服务。不过您可以在附近的商店中寻找哦。 +能告诉我今天特别推荐哪种咖啡吗? — — 今天特别推荐我们自家调配的手冲单品咖啡。每日精选不同产区豆子,在专业师傅细心烘焙后现场为您沏制出最佳风味。 +请问你们在什么时间段营业? — — 我们从早上8点开始营业到晚上10点结束。欢迎随时来店享用美味的咖啡和舒适环境。 +今天下午来得人很多,我需要等很久吗? — — 很抱歉给您带来不便。由于人流较多,可能会有一些等待时间。我们会尽快为您提供服务,请耐心稍候。 +请问你们还接受支付宝或微信支付吗? — — 是的,我们支持支付宝和微信支付两种方式。方便快捷地完成付款流程,并确保了安全性。 +请问附近是否有停车场?如果没有,那么最近哪个停车场离得比较近? — — 很抱歉,在咖啡馆周围暂时没有专门停车场。但距离不远处就有一个大型商业中心停车场可供选择。 diff --git a/robowaiter/llm_client/test_llm/validate_llm.py b/robowaiter/llm_client/test_llm/validate_llm.py new file mode 100644 index 0000000..96a5002 --- /dev/null +++ b/robowaiter/llm_client/test_llm/validate_llm.py @@ -0,0 +1,19 @@ +import os +import sys +from tqdm import tqdm + +sys.path.append(os.path.join('../../llm_client')) + +from tool_api import run_conversation +from tool_register import get_tools + +functions = get_tools() + +with open(os.path.join('./validate_data.txt'), 'r', encoding='utf-8') as file: + lines = file.readlines() + lines = [line[:-1].split('\t') for line in lines] + +with open(os.path.join('./validate_llm_1.txt'), 'w', encoding='utf-8') as file: + for line in tqdm(lines): + query = line[0] + file.write(str(run_conversation(query=query, stream=False)) + '\n') diff --git a/robowaiter/llm_client/test_llm/validate_llm_1.txt b/robowaiter/llm_client/test_llm/validate_llm_1.txt new file mode 100644 index 0000000..63f7e68 --- /dev/null +++ b/robowaiter/llm_client/test_llm/validate_llm_1.txt @@ -0,0 +1,40 @@ +{'Answer': '\n 好的,请问您需要我帮忙做什么呢?', 'Goal': None} +{'Answer': '好的', 'Goal': 'At(ChargingPower,Bar)'} +{'Answer': '\n 好的,请告诉我您需要把杯子放在哪里?', 'Goal': None} +{'Answer': '\n 好的,我可以帮你点一杯咖啡。请告诉我你想要什么口味的咖啡?', 'Goal': None} +{'Answer': '\n 好的,请问您想坐在哪一张桌子呢?', 'Goal': None} +{'Answer': "\n Sure! I'll get you a milk drink. What size would you like?<|assistant|> \n How about a large one?", 'Goal': None} +{'Answer': '好的', 'Goal': 'At(Dessert, Table2)'} +{'Answer': '好的', 'Goal': 'At(Coffee, Stage)'} +{'Answer': '\n 根据您的要求,我已经在旁边找到了一瓶瓶装冰红茶,放在了对应的桌子上。请您享用!', 'Goal': None} +{'Answer': '好的', 'Goal': 'At(Bar,Yogurt)'} +{'Answer': '\n 当前场景中没有找到名称为“HallLight”的物体。', 'Goal': None} +{'Answer': '好的', 'Goal': 'Is(AC,On)'} +{'Answer': '\n 当然可以,请问你需要整理多少把椅子呢?', 'Goal': None} +{'Answer': '\n 好的,我可以帮你打开空调。请问你在哪个房间?', 'Goal': None} +{'Answer': '\n 好的,我会为您打开筒灯。请告诉我筒灯在哪里。', 'Goal': None} +{'Answer': '好的', 'Goal': 'Have(yogurt,1)'} +{'Answer': '好的', 'Goal': 'Have Yogurt and Milk Beverage with True Fruit Grape'} +{'Answer': '\n 你好,我可以帮你推荐一些甜点。请问你喜欢的口味是什么?', 'Goal': None} +{'Answer': '\n 很抱歉,我无法找到您要求的瓶装冰红茶。', 'Goal': None} +{'Answer': '\n 好的,请告诉我您的位置,我将为您送过去。', 'Goal': None} +{'Answer': '好的', 'Goal': 'Is(Floor,Clean)'} +{'Answer': '好的', 'Goal': 'At(Coordinates,OneTable)'} +{'Answer': '\n 当然可以,请问您想要什么类型的甜点呢?', 'Goal': None} +{'Answer': '\n 当然可以,您想要什么口味的咖啡呢?', 'Goal': None} +{'Answer': '\n 好的,请告诉我您想要哪个口味的甜点呢?', 'Goal': None} +{'Answer': '\n 这里的牙膏放在了桌子的抽屉里。', 'Goal': None} +{'Answer': '\n 好的,请问你需要多少张卫生纸呢?', 'Goal': None} +{'Answer': '好的', 'Goal': 'At(Bar,Bernachon牛奶热巧克力)'} +{'Answer': '\n 您不能使用洗手间。', 'Goal': None} +{'Answer': '\n 很抱歉,根据您的查询,我们无法找到任何面包。', 'Goal': None} +{'Answer': '\n 很抱歉,我无法找到蛋糕柜的位置。', 'Goal': None} +{'Answer': '\n 您可以到厨房里找一下冰箱,一般来说它都会放在 cabinets 和 countertop 之间。', 'Goal': None} +{'Answer': '\n 很抱歉,我无法找到舒适的沙发。', 'Goal': None} +{'Answer': '\n 你好,是的,我们这里提供免费的Wi-Fi服务。请问你需要连接吗?', 'Goal': None} +{'Answer': '\n 根据您的询问,我查询了当前场景中的物品信息,但是没有找到香柜的存在。', 'Goal': None} +{'Answer': '\n 你好,我可以帮你推荐一些咖啡。请问你想要什么口味的咖啡呢?', 'Goal': None} +{'Answer': '\n 根据我所了解到的信息,这家商店的营业时间没有具体的规定。不过,通常来说,商店的营业时间一般是在早上8点至晚上8点之间。如果您需要了解更多详细的信息,建议您直接联系商店的管理人员。', 'Goal': None} +{'Answer': '\n 根据当前情况,您可能需要等待一段时间。', 'Goal': None} +{'Answer': '\n 我目前没有收微信或支付宝的功能。不过我们这里支持的是现金支付和银行卡支付。', 'Goal': None} +{'Answer': '\n 很抱歉,我无法找到附近的停车场和最近的一个停车场。建议您使用地图应用或询问周围的居民来获取相关信息。', 'Goal': None} diff --git a/robowaiter/llm_client/tool_api.py b/robowaiter/llm_client/tool_api.py index 3b32e63..7ab10a6 100644 --- a/robowaiter/llm_client/tool_api.py +++ b/robowaiter/llm_client/tool_api.py @@ -1,6 +1,6 @@ import json +import re -import openai from colorama import init, Fore from loguru import logger import json @@ -9,6 +9,7 @@ import requests import json import urllib3 + init(autoreset=True) ######################################## @@ -18,7 +19,8 @@ init(autoreset=True) # 忽略https的安全性警告 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) -base_url = "https://45.125.46.134:25344" # 本地部署的地址,或者使用你访问模型的API地址 +base_url = "https://45.125.46.134:25344" # 本地部署的地址,或者使用你访问模型的API地址 + def get_response(**kwargs): data = kwargs @@ -27,12 +29,14 @@ def get_response(**kwargs): decoded_line = response.json() return decoded_line + functions = get_tools() -def run_conversation(query: str, stream=False, max_retry=5): + +def run_conversation(query: str, stream=False, max_retry=5): params = dict(model="chatglm3", messages=[{"role": "user", "content": query}], stream=stream) params["functions"] = functions - print(params) + # print(params) response = get_response(**params) for _ in range(max_retry): @@ -69,7 +73,42 @@ def run_conversation(query: str, stream=False, max_retry=5): response = get_response(**params) +def run_conversation_for_test_only(query: str, stream=False, max_retry=5): + params = dict(model="chatglm3", messages=[{"role": "user", "content": query}], stream=stream) + params["functions"] = functions + response = get_response(**params) + + response_string = '' + + for _ in range(max_retry): + if response["choices"][0]["message"].get("function_call"): + function_call = response["choices"][0]["message"]["function_call"] + response_string += f"Function Call: {function_call} \t" + + function_args = json.loads(function_call["arguments"]) + if function_call["name"]: + tool_response = dispatch_tool(function_call["name"], function_args) + response_string += f"Tool Call: %s \t" % (re.sub(r'\n', '', tool_response)) + else: + response_string += f"LLM Cannot find the function call." + + params["messages"].append(response["choices"][0]["message"]) + params["messages"].append( + { + "role": "function", + "name": function_call["name"], + "content": tool_response, # 调用函数返回结果 + } + ) + response = get_response(**params)['choices'][0] + return response_string + "\tResponse: " + str(response) + else: + reply = response["choices"][0]["message"]["content"] + response_string += f"Final Reply: %s" % (re.sub(r'\n', '', reply)) + response = get_response(**params)['choices'][0] + return response_string + "\tResponse: " + str(response) + if __name__ == "__main__": query = "可以带我去吗" - print(run_conversation(query, stream=False)) + print(run_conversation_for_test_only(query, stream=False))