From 6cf1c3511f5dafa95bf859e4387aa22097090e7c Mon Sep 17 00:00:00 2001 From: xiaoyan-5800X Date: Mon, 7 Nov 2022 01:42:32 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E6=89=B9=E9=87=8F=E5=8C=B9=E9=85=8D=E7=9A=84=E8=A7=84=E5=88=92?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../activity/AutoTakePictureActivity.java | 116 ++++++++++++++++++ .../com/navinfo/outdoor/api/Constant.java | 1 + .../outdoor/fragment/GatherGetFragment.java | 31 +---- .../outdoor/fragment/TreasureFragment.java | 100 ++++++++++++++- .../com/navinfo/outdoor/util/NaviUtils.java | 71 +++++++++-- .../res/drawable/selector_navi_distance.xml | 14 +++ .../layout/activity_auto_take_pictures.xml | 14 ++- app/src/main/res/layout/treasure_fragment.xml | 16 ++- .../mipmap-xxhdpi/navi_distance_disable.png | Bin 0 -> 3746 bytes .../mipmap-xxhdpi/navi_distance_normal.png | Bin 0 -> 2976 bytes build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 12 files changed, 323 insertions(+), 44 deletions(-) create mode 100644 app/src/main/res/drawable/selector_navi_distance.xml create mode 100644 app/src/main/res/mipmap-xxhdpi/navi_distance_disable.png create mode 100644 app/src/main/res/mipmap-xxhdpi/navi_distance_normal.png diff --git a/app/src/main/java/com/navinfo/outdoor/activity/AutoTakePictureActivity.java b/app/src/main/java/com/navinfo/outdoor/activity/AutoTakePictureActivity.java index 342ba3a..a4d7167 100644 --- a/app/src/main/java/com/navinfo/outdoor/activity/AutoTakePictureActivity.java +++ b/app/src/main/java/com/navinfo/outdoor/activity/AutoTakePictureActivity.java @@ -71,6 +71,7 @@ import com.navinfo.outdoor.util.Geohash; import com.navinfo.outdoor.util.GeometryTools; import com.navinfo.outdoor.util.Gps; import com.navinfo.outdoor.util.MyTecentLocationSource; +import com.navinfo.outdoor.util.NaviUtils; import com.navinfo.outdoor.util.PreserveUtils; import com.navinfo.outdoor.util.SystemTTS; import com.navinfo.outdoor.util.TencentMarkerUtils; @@ -87,6 +88,12 @@ import com.otaliastudios.cameraview.size.AspectRatio; import com.otaliastudios.cameraview.size.SizeSelector; import com.otaliastudios.cameraview.size.SizeSelectors; import com.tencent.map.geolocation.TencentLocation; +import com.tencent.map.navi.TencentNaviManager; +import com.tencent.map.navi.TencentRouteSearchCallback; +import com.tencent.map.navi.car.TencentCarNaviManager; +import com.tencent.map.navi.data.CalcRouteResult; +import com.tencent.map.navi.data.NaviPoi; +import com.tencent.map.navi.data.RouteData; import com.tencent.tencentmap.mapsdk.maps.CameraUpdate; import com.tencent.tencentmap.mapsdk.maps.CameraUpdateFactory; import com.tencent.tencentmap.mapsdk.maps.TencentMap; @@ -103,6 +110,7 @@ import com.tencent.tencentmap.mapsdk.maps.model.MyLocationStyle; import com.tencent.tencentmap.mapsdk.maps.model.Polyline; import com.tencent.tencentmap.mapsdk.maps.model.PolylineOptions; import com.tencent.tencentmap.mapsdk.maps.model.TencentMapGestureListener; +import com.umeng.commonsdk.debug.UMLogCommon; import com.umeng.commonsdk.internal.crash.UMCrashManager; import com.umeng.umcrash.UMCrash; import org.locationtech.jts.algorithm.Angle; @@ -137,6 +145,7 @@ import java.util.Objects; import java.util.Optional; import java.util.Timer; import java.util.TimerTask; +import java.util.function.Predicate; import java.util.stream.Collectors; import io.reactivex.BackpressureStrategy; @@ -203,6 +212,7 @@ public class AutoTakePictureActivity extends BaseActivity implements View.OnClic private ImageView imgViewSettingHook; // 调起隐藏设置的按钮 private TencentLocation oldCurrentLocation = null; private MediaPlayer mediaPlayer; + private ImageView imgNaviDistance; // 自动规划到距离最近的数据开关 @Override protected void onCreate(@Nullable Bundle savedInstanceState) { @@ -252,6 +262,7 @@ public class AutoTakePictureActivity extends BaseActivity implements View.OnClic ivPicVideoImage = findViewById(R.id.iv_pic_video); btnClearMatch = findViewById(R.id.clear_all_match_data); btnStopPicture = findViewById(R.id.btn_stop_picture); + imgNaviDistance = findViewById(R.id.img_navi_distance); //获取地图 tencentMap = tvMapView.getMap(); @@ -410,6 +421,13 @@ public class AutoTakePictureActivity extends BaseActivity implements View.OnClic lastClickTime = System.currentTimeMillis(); } }); + + imgNaviDistance.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + imgNaviDistance.setSelected(!imgNaviDistance.isSelected()); + } + }); } private long lastClickTime = 0; private int settingHookClickCount = 1; @@ -774,6 +792,8 @@ public class AutoTakePictureActivity extends BaseActivity implements View.OnClic // 语音提示用户 mediaPlayer.start(); systemTTS.playText("拍摄完成"); + // 此时自动规划距离最近的任务路径 + } } @@ -808,6 +828,102 @@ public class AutoTakePictureActivity extends BaseActivity implements View.OnClic } } + /** + * 导航到最近的POIEntity + * */ + @RequiresApi(api = Build.VERSION_CODES.N) + private void navi2NearestPoiEntity() { + if (removables == null || removables.isEmpty()) { + SystemTTS.getInstance(this).playText("附近当前没有可匹配的任务"); + return; + } + Geometry currentGeometry = GeometryTools.createGeometry(new double[]{Constant.currentLocation.getLongitude(), Constant.currentLocation.getLatitude()}); + Removable minRemoveable = removables.stream().filter(new Predicate() { + @Override + public boolean test(Removable removable) { + if (removable instanceof Marker) { + return true; + } + return false; + } + }).min((removable, t1) -> { + Marker marker1 = (Marker) removable; + Marker marker2 = (Marker) t1; + // 判断距离用户当前位置的距离 + JobSearchBean.BodyBean.ListBean bean1 = (JobSearchBean.BodyBean.ListBean) marker1.getTag(); + JobSearchBean.BodyBean.ListBean bean2 = (JobSearchBean.BodyBean.ListBean) marker2.getTag(); + // 转换geo + Geometry geometry1 = GeometryTools.createGeometry(Geohash.getInstance().decode(bean1.getGeo())); + Geometry geometry2 = GeometryTools.createGeometry(Geohash.getInstance().decode(bean2.getGeo())); + if (currentGeometry.distance(geometry1) arrayList) { + NaviUtils.getInstance().addRoutes(arrayList, tencentMap); + NaviUtils.getInstance().zoomToRoute(arrayList.get(0), tencentMap); + if (tencentNaviManager!=null) { + if (Constant.currentNaviType == Constant.NAV_TYPE.CAR) { + ((TencentCarNaviManager)tencentNaviManager).startNavi(0); + } else if (Constant.currentNaviType == Constant.NAV_TYPE.RIDE) { + + } else { + + } + } + } + + @Override + public void onCalcRouteSuccess(CalcRouteResult calcRouteResult) { + + } + + @Override + public void onCalcRouteFailure(CalcRouteResult calcRouteResult) { + + } + }; + /** * 初始化领取任务的管理栈 * */ diff --git a/app/src/main/java/com/navinfo/outdoor/api/Constant.java b/app/src/main/java/com/navinfo/outdoor/api/Constant.java index 95aa557..b950c14 100644 --- a/app/src/main/java/com/navinfo/outdoor/api/Constant.java +++ b/app/src/main/java/com/navinfo/outdoor/api/Constant.java @@ -274,4 +274,5 @@ public class Constant { } public static NAV_TYPE currentNaviType; // 当前的导航方式 + public static boolean NAV_NEAREST_POI = false; } diff --git a/app/src/main/java/com/navinfo/outdoor/fragment/GatherGetFragment.java b/app/src/main/java/com/navinfo/outdoor/fragment/GatherGetFragment.java index af8f52e..5c75fa0 100644 --- a/app/src/main/java/com/navinfo/outdoor/fragment/GatherGetFragment.java +++ b/app/src/main/java/com/navinfo/outdoor/fragment/GatherGetFragment.java @@ -204,45 +204,18 @@ public class GatherGetFragment extends BaseFragment implements View.OnClickListe public void selectNaviType(Constant.NAV_TYPE nav_type) { // 显示导航类型选择的对话框 Constant.currentNaviType = nav_type; - startNav(); + NaviUtils.getInstance().startNav(getActivity(), new LatLng(Constant.currentLocation.getLatitude(), Constant.currentLocation.getLongitude()), new LatLng(Double.parseDouble(poiEntity.getY()), Double.parseDouble(poiEntity.getX()))); } }); } else { // 已选择导航方式 - startNav(); + NaviUtils.getInstance().startNav(getActivity(), new LatLng(Constant.currentLocation.getLatitude(), Constant.currentLocation.getLongitude()), new LatLng(Double.parseDouble(poiEntity.getY()), Double.parseDouble(poiEntity.getX()))); } } }); } } - /** - * 开始路径规划 - * */ - private void startNav() { - if (Constant.currentLocation == null) { - ToastUtils.Message(getActivity(), "无法获取当前位置,请检查是否授权应用获取位置权限!"); - return; - } - if (poiEntity == null || poiEntity.getX() == null || poiEntity.getY() == null) { - ToastUtils.Message(getActivity(), "无法获取当前数据的位置,请重新打开此数据尝试!"); - return; - } - // 跳转到指定的Activity - Class toClass = null; - if (Constant.currentNaviType == Constant.NAV_TYPE.CAR) { - toClass = NaviCarActivity.class; - } else if (Constant.currentNaviType == Constant.NAV_TYPE.RIDE) { - toClass = NaviRideActivity.class; - } else { - toClass = NaviWalkActivity.class; - } - Intent naviIntent = new Intent(getActivity(), toClass); - // 使用当前数据起点作为导航的终点,规划路径 - naviIntent.putExtra("start", new LatLng(Constant.currentLocation.getLatitude(), Constant.currentLocation.getLongitude())); - naviIntent.putExtra("end", new LatLng(Double.parseDouble(poiEntity.getY()), Double.parseDouble(poiEntity.getX()))); - getActivity().startActivity(naviIntent); - } /** * diff --git a/app/src/main/java/com/navinfo/outdoor/fragment/TreasureFragment.java b/app/src/main/java/com/navinfo/outdoor/fragment/TreasureFragment.java index 17ba24b..d23ddce 100644 --- a/app/src/main/java/com/navinfo/outdoor/fragment/TreasureFragment.java +++ b/app/src/main/java/com/navinfo/outdoor/fragment/TreasureFragment.java @@ -84,6 +84,7 @@ import com.navinfo.outdoor.util.MapManager; import com.navinfo.outdoor.util.MyTecentLocationSource; import com.navinfo.outdoor.util.NaviUtils; import com.navinfo.outdoor.util.NetWorkUtils; +import com.navinfo.outdoor.util.SystemTTS; import com.navinfo.outdoor.util.TencentMarkerUtils; import com.navinfo.outdoor.util.TimestampUtil; import com.navinfo.outdoor.util.ToastUtils; @@ -110,6 +111,8 @@ import com.tencent.tencentmap.mapsdk.maps.model.Polyline; import com.tencent.tencentmap.mapsdk.maps.model.PolylineOptions; import com.umeng.message.UmengNotificationClickHandler; import com.umeng.message.entity.UMessage; + +import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.geom.MultiPoint; import org.locationtech.jts.geom.Point; @@ -123,11 +126,13 @@ import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; +import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.function.Predicate; /** * 寻宝的Fragment @@ -143,9 +148,9 @@ public class TreasureFragment extends BaseFragment implements View.OnClickListen private FrameLayout frameLayout; private GatherGetFragment gatherGetFragment; private String centerEncode; - private List removables; - private List removableScreenMarker; - private List removablesLocality; + private List removables; //存储网络数据的marker数据(线,面,点) + private List removablesLocality; // 存储本地数据的marker数据(线,面,点) + private List removableScreenMarker; // 存储屏幕数据的marker数据(线,面,点) private final int MARKER_BIG = 4; /* * bitmapDescriptor1 @@ -177,6 +182,7 @@ public class TreasureFragment extends BaseFragment implements View.OnClickListen private TextView tvTenantGaps; private TencentMarkerUtils tencentMarkerUtils; private ImageView imgAutoMatchRoad; // 自动匹配道路 + private ImageView ivNaviDistance; // 按距离自动导航 public static TreasureFragment newInstance(Bundle bundle) { TreasureFragment fragment = new TreasureFragment(); @@ -351,6 +357,79 @@ public class TreasureFragment extends BaseFragment implements View.OnClickListen // }).setFullScreen(true); } }); + ivNaviDistance = findViewById(R.id.img_navi_distance); + + ivNaviDistance.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Constant.NAV_NEAREST_POI = !view.isSelected(); + view.setSelected(Constant.NAV_NEAREST_POI); + // 如果是被选中,则发送导航到最近POI的指令 + if (Constant.NAV_NEAREST_POI) { + SystemTTS.getInstance(getContext()).playText("开始自动规划"); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + handler.postDelayed(autoNaviRunnable, 2000); + } + } else { + SystemTTS.getInstance(getContext()).playText("停止自动规划"); + handler.removeCallbacks(autoNaviRunnable); + } + } + }); + } + + /** + * 导航到最近的POIEntity + * */ + @RequiresApi(api = Build.VERSION_CODES.N) + private void navi2NearestPoiEntity() { + if (removables == null || removables.isEmpty()) { + SystemTTS.getInstance(getContext()).playText("无法获取任务数据"); + ivNaviDistance.setSelected(false); + return; + } + Geometry currentGeometry = GeometryTools.createGeometry(new double[]{Constant.currentLocation.getLongitude(), Constant.currentLocation.getLatitude()}); + Removable minRemoveable = removables.stream().filter(new Predicate() { + @Override + public boolean test(Removable removable) { + if (removable instanceof Marker) { + return true; + } + return false; + } + }).min((removable, t1) -> { + Marker marker1 = (Marker) removable; + Marker marker2 = (Marker) t1; + // 判断距离用户当前位置的距离 + JobSearchBean.BodyBean.ListBean bean1 = (JobSearchBean.BodyBean.ListBean) marker1.getTag(); + JobSearchBean.BodyBean.ListBean bean2 = (JobSearchBean.BodyBean.ListBean) marker2.getTag(); + // 转换geo + Geometry geometry1 = GeometryTools.createGeometry(Geohash.getInstance().decode(bean1.getGeo())); + Geometry geometry2 = GeometryTools.createGeometry(Geohash.getInstance().decode(bean2.getGeo())); + if (currentGeometry.distance(geometry1)= Build.VERSION_CODES.N) { + navi2NearestPoiEntity(); + } + } + }; @Subscribe public void onEvent(Message data) { @@ -849,6 +936,13 @@ public class TreasureFragment extends BaseFragment implements View.OnClickListen removableScreenMarker.get(i).remove(); } removableScreenMarker.clear(); + + // 抽屉隐藏,如果当前自动规划按钮被选中 + if (ivNaviDistance.isSelected()) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + handler.postDelayed(autoNaviRunnable, 3000); + } + } } } else if (data.what == Constant.MAIN_BUTTON_VISITABLE) {//控制主界面各个按钮显隐状态的what值 setMainButtonVisitable((Integer) data.obj); diff --git a/app/src/main/java/com/navinfo/outdoor/util/NaviUtils.java b/app/src/main/java/com/navinfo/outdoor/util/NaviUtils.java index 39a6fa2..7072f54 100644 --- a/app/src/main/java/com/navinfo/outdoor/util/NaviUtils.java +++ b/app/src/main/java/com/navinfo/outdoor/util/NaviUtils.java @@ -2,6 +2,7 @@ package com.navinfo.outdoor.util; import android.app.Activity; import android.content.Context; +import android.content.Intent; import android.util.Log; import android.view.View; import android.widget.RadioButton; @@ -13,6 +14,9 @@ import androidx.appcompat.app.AppCompatActivity; import com.kongzue.dialog.v3.CustomDialog; import com.navinfo.outdoor.R; +import com.navinfo.outdoor.activity.NaviCarActivity; +import com.navinfo.outdoor.activity.NaviRideActivity; +import com.navinfo.outdoor.activity.NaviWalkActivity; import com.navinfo.outdoor.api.Constant; import com.tencent.map.navi.CalcRouteCallback; import com.tencent.map.navi.INaviView; @@ -437,6 +441,26 @@ public class NaviUtils { } } + /** + * 仅进行路径规划,无需导航 + * */ + public TencentNaviManager searchRouteOnly(Activity mContext, Constant.NAV_TYPE nav_type, NaviPoi start, NaviPoi end, TencentRouteSearchCallback routeSearchCallback) throws Exception { + TencentNaviManager naviManager = null; + if (nav_type == Constant.NAV_TYPE.CAR) { + naviManager = new TencentCarNaviManager(mContext); + CarRouteSearchOptions options = CarRouteSearchOptions.create(); + ((TencentCarNaviManager)naviManager).searchRoute(start, end, new ArrayList<>(), options, routeSearchCallback); + } else if (nav_type == Constant.NAV_TYPE.RIDE) { + naviManager = new TencentRideNaviManager(mContext); + RideRouteSearchOptions options = RideRouteSearchOptions.create(); + ((TencentRideNaviManager)naviManager).searchRoute(start, end, options, routeSearchCallback); + } else { + naviManager = new TencentWalkNaviManager(mContext); + ((TencentWalkNaviManager)naviManager).searchRoute(start, end, routeSearchCallback); + } + return naviManager; + } + /** * 算路回调 */ @@ -450,8 +474,8 @@ public class NaviUtils { @Override public void onRouteSearchSuccess(ArrayList arrayList) { // 添加道路Route到地图,默认选取第一条 - addRoutes(arrayList); - zoomToRoute(arrayList.get(0)); + addRoutes(arrayList, tencentMap); + zoomToRoute(arrayList.get(0), tencentMap); try { // 自动开始导航 if (Constant.currentNaviType == Constant.NAV_TYPE.CAR) { @@ -512,7 +536,7 @@ public class NaviUtils { } } - private void addRoutes(ArrayList mRouteDatas) { + public void addRoutes(ArrayList mRouteDatas, TencentMap map) { RouteData routeData = mRouteDatas.get(0); ArrayList traffics = getTrafficItemsFromList(routeData.getTrafficIndexList()); List mRoutePoints = routeData.getRoutePoints(); @@ -550,11 +574,13 @@ public class NaviUtils { .arrow(true) .colors(trafficColors, trafficColorsIndex) .zIndex(10); - - Polyline polyline = tencentMap.addPolyline(options); + if (map == null) { + map = tencentMap; + } + Polyline polyline = map.addPolyline(options); } - private void zoomToRoute(RouteData routeData) { + public void zoomToRoute(RouteData routeData, TencentMap map) { int marginLeft = mContext.getResources().getDimensionPixelSize(R.dimen.navigation_line_margin_left); int marginTop = mContext.getResources().getDimensionPixelSize(R.dimen.navigation_line_margin_top); int marginRight = mContext.getResources().getDimensionPixelSize(R.dimen.navigation_line_margin_right); @@ -563,7 +589,10 @@ public class NaviUtils { builder.include(routeData.getRoutePoints()); LatLngBounds bounds = builder.build(); - tencentMap.moveCamera(CameraUpdateFactory.newLatLngBoundsRect(bounds, marginLeft, marginRight, marginTop, marginBottom)); + if (map == null) { + map = tencentMap; + } + map.moveCamera(CameraUpdateFactory.newLatLngBoundsRect(bounds, marginLeft, marginRight, marginTop, marginBottom)); } @@ -622,6 +651,34 @@ public class NaviUtils { } } + /** + * 开始路径规划 + * */ + public void startNav(Activity mContext, LatLng startLatlng, LatLng endLatlng) { + if (Constant.currentLocation == null) { + ToastUtils.Message(mContext, "无法获取当前位置,请检查是否授权应用获取位置权限!"); + return; + } + if (startLatlng == null || endLatlng == null) { + ToastUtils.Message(mContext, "无法获取个人位置或数据位置信息,请重新打开此数据尝试!"); + return; + } + // 跳转到指定的Activity + Class toClass = null; + if (Constant.currentNaviType == Constant.NAV_TYPE.CAR) { + toClass = NaviCarActivity.class; + } else if (Constant.currentNaviType == Constant.NAV_TYPE.RIDE) { + toClass = NaviRideActivity.class; + } else { + toClass = NaviWalkActivity.class; + } + Intent naviIntent = new Intent(mContext, toClass); + // 使用当前数据起点作为导航的终点,规划路径 + naviIntent.putExtra("start", startLatlng); + naviIntent.putExtra("end", endLatlng); + mContext.startActivity(naviIntent); + } + private TencentNaviManager getNaviManager() { if (naviManager!=null) { return naviManager; diff --git a/app/src/main/res/drawable/selector_navi_distance.xml b/app/src/main/res/drawable/selector_navi_distance.xml new file mode 100644 index 0000000..576723b --- /dev/null +++ b/app/src/main/res/drawable/selector_navi_distance.xml @@ -0,0 +1,14 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_auto_take_pictures.xml b/app/src/main/res/layout/activity_auto_take_pictures.xml index db870fa..17093ac 100644 --- a/app/src/main/res/layout/activity_auto_take_pictures.xml +++ b/app/src/main/res/layout/activity_auto_take_pictures.xml @@ -129,7 +129,7 @@ android:id="@+id/btn_switch" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginTop="20dp" + android:layout_marginTop="25dp" android:layout_marginEnd="25dp" android:src="@mipmap/switcher" android:padding="@dimen/default_widget_padding" @@ -158,6 +158,18 @@ app:layout_constraintTop_toBottomOf="@id/btn_setting" app:layout_constraintRight_toRightOf="parent"> + + + + + android:layout_marginTop="15dp" + app:layout_constraintLeft_toLeftOf="@id/img_navi_distance" + app:layout_constraintTop_toBottomOf="@id/img_navi_distance"/> ;000oSvqfCu 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xxhdpi/navi_distance_normal.png b/app/src/main/res/mipmap-xxhdpi/navi_distance_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..a20dd390b377a161a458ac55db670060c91083c6 GIT binary patch literal 2976 zcmV;R3t#k!P)Px=T1iAfRCr$Pop;P_MHR&tR#X&4Vvn)LDE5lI5*53kh*6`)F4()q8d0$$*n0tu z1yE7J0`@K_*bDZqv1^PiKR6f9yYIel)|As{C-<+jXU@!CcjnCO*?Y}SsxoT}>@@4% z)y}B`Jo7(61-Jq{a|_J8dvyd?fM;%jnRl;_;0o}}Eim)$)e&3)p1B2P-n}}4hXME| zYp*?_t7cSyyRz)|_1;X{9<%EQ(3d$`U#=mm+&Npx#N+c{4lpN=XmStmBO072tGB z-mU@l4w80FuV%ZFM@iz3Qba1iab~<@11jL2C$6Zi{TfLRu(bn<72vQX`IfRsx~-&h zht;z+4wCfb>{^-%D!|)Y5}N=hzgzbNYP%ITl~inBTme4av}bMr-KPO{mr^4rvYuZ{ zx?p6PE!CF{@Yz}`Uqh57LU^_)?~ z5&&jo@;$x1B%Baq19b()uOwZlB)HTySAf~V0P1a;Zz?0VZ~2;}cT2jPq{|yGKeX{j z8>+s_oB+mygd?A+m*3958H#CsS<-tNV81Qtijqz?YrnCiPnf#4+SCC)zoga57f{b` z_q?3q=Nmv7tv^_+_F0miV!Y~?k}hoMMXO8^;0rXaJOJgJIs~YnYCvVQ{&)+ke@D_~ z4OCtx>0yRmw8~TfX7PcW5I_NzEl%HZd~5psh4J#MN;=WdL*+)2K56Pksf`)ni?&w2 zfO^)bo|REPR??BpX#H(umCu#*c%#hECDGSTWNZLmytVQL)U$Nb>m676FG(M2KxO*< zL&p10m2?TC{2`JaZs;Yci~(SbzW#*q)G z?`sxI|LO4kKQe)Psia4A*pALUS(j<8d>N^I{-Lnj&l*tQFNsKrKID3mK5f3}1`)bu zmD{RyVQ>z`@7)@$UA$wf&a${+q#o1!k_?kkh*9b6X&L3tA}pgRlhvyD z!ng$i^#hWQi!WZZ1mD$*88yB{(jyJMER~X@>uHjnp4FPT!uWUrl^=oQV-WnwZZyXA zC4HvrMwbGZt<86Pm~y@%>4OcZooy{LjQ(;nesV+HB4dRneS)3`umdDKK3G|048eTh{P7NrC_x34WF`b!sLY9yx8<|6|qGrfC-Vo z_jfow{4uqH0n4$#WT6=n z0svA6L8$JH&r1T#3)lzqJx-N>OS*aK(9u?7@EifeTP1xjwUHaj5fMqGNl0EK>Cqvj zlFv&6Oxy5cz2i*TgZ>6r#~0r0A$fSlv9 zk{BJivZGag36S3;>0U+yzh#Ec8ddo!T>@NU%Kn|C{Um+V@6vXfp)Fi4$iLaZxv{Ca zoDn}JqaR5{y9T(_l#Np!?@z3Rz+Kgs3Nopsgv&azr=;FJaeV+>YRZ1Iq^C;an9UIv z+*Muok@QBV;+D=^Bte`K64-P02q|^(yib5jOxdh_iGbj&cPmL*&2tJwZf=YaX-V*X zNM0c6u_2`{p7#wfeJHWYeqwX(yvZgh;8IWQ2xe{Yb`uo(>;~bPReEYe0K95h?kXET zDN;i?>|aSLxbJ9^#5}8=uEqQBZWQ3$`pSl0Cn`e%OovhdSs8;2zGpTIoz%Jj%K47A z0pR?bAU=l&>tHhgewF~2nzEmf=s{yq#nc=t{2^FiIdW}DUvw0^&>4CJxBHYkWyjhl zhpvc|GfvP#@>NOXC=DiK0=UGK?HckGk{;qJuj!FY&e5PlentQy3&O!KgJQWuVk4n=MqSfP4-m zVDAYDzyk2#G9`d9R_c_!e}r3cN1)(y=Agr2#KXhJ!N}k;HGos6Y$7&U7@d@1aYAC* zJ3Dd>Nn~LRE>i?Jb;>4%G$%Npb6?JXL&Bj#P9#gH{;20u2AGZ#q!*J&o_cHt11$MO z4r5-)Z+;Y*o0O*x@Fh2pkA;jvoY!kZN^8$yV1JcahQ04-(ru;=FgAaXBwUZK;AVtv z06(!SP$|LF6%tnZL{5%I<^V9pgz_lnA`3{(xTwkzlDUZ_aTxUo6XN)CG%^=}F(~v$ zF;v0s^)(Nagsvl_nx1L!oB)Q*6V|vGVR{dJTj9@wYdR!k>yx!VDwz|&7&hjl2mL=w zx|$?XIyVWaF60wAG>Wjw;u0N|%ne|Sd$=S#SFR9kLDa=2;RZ5j864q{lH*8m-Vv=c zM}RQ`84=E9kSl|cezGY$&}A-wDHg`q(aBr^CK&Gbk=9@d-?)dG3Z8pZ`Srj<8vZVlwJzSbW*LLWUF~||*Xk|$N0|JKz z5R;b@F1{KyY1`5OroW|_-l3I%zHrpCG=Kpkm(ObjD0D~!(vMn}2rz&EOfDHW`(^gc zqn4!t3@E2$@Mgd&&rC3SSu((Y^WQ{-QdxfzUzc8N=>W%2@VBiD-z1){(aX{S2B3o? zb9kXXCTMRGk^(S%Rrd_^j?fumnQ+)oLCE1H8^ICo8Fby4PJQU`Jtyufbj{AI8@syo zTF&%#WiYC`+>r-H9JkpG?oiSB9>Y|(R}<<}vMC2h;tpX)ARTuxhz6KYQisyf`Q68ma^m=WxzP?jP*33YOg&)Mga-Wn1D@~wQS7=R(w zbU2U6B#B z7=XzRaA<^__g0-e3;f-stB3(OHpeHg3$^rC7T_v*$YFvK12E~4gWVny?8&keY=3kN zz~teKHcfI__?~tqZC&CO127y=xGPDLt}>hjqRysc03NPO_07o^r~oIMZW;wEz|+7f zxs?^*WYbNfU5T0-S8RX%wsgPXnjqR#t$MO*f5#72s*$l-$Y+aI)#9QSg7u W@}G#9iP53}0000