From cd14469d7910c637ae2c42d9c6bbb4c0962f0571 Mon Sep 17 00:00:00 2001 From: userGyl Date: Thu, 12 Mar 2026 13:27:08 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=E5=AE=9A=E4=BD=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../android/app/src/main/AndroidManifest.xml | 12 +- .../com/lnkj/ln_jq_app/NativeMapView.java | 642 ++++++++++++++++-- .../app/src/main/res/drawable/amap_loc.xml | 10 - .../android/app/src/main/res/drawable/car.png | Bin 0 -> 6754 bytes .../src/main/res/drawable/ic_end_marker.xml | 10 - .../app/src/main/res/drawable/ic_location.xml | 10 - .../app/src/main/res/drawable/ic_route.xml | 13 - .../src/main/res/drawable/ic_start_marker.xml | 10 - .../main/res/drawable/ic_station_marker.xml | 10 - .../app/src/main/res/drawable/ic_tag.png | Bin 0 -> 3468 bytes 10 files changed, 608 insertions(+), 109 deletions(-) delete mode 100644 ln_jq_app/android/app/src/main/res/drawable/amap_loc.xml create mode 100644 ln_jq_app/android/app/src/main/res/drawable/car.png delete mode 100644 ln_jq_app/android/app/src/main/res/drawable/ic_end_marker.xml delete mode 100644 ln_jq_app/android/app/src/main/res/drawable/ic_location.xml delete mode 100644 ln_jq_app/android/app/src/main/res/drawable/ic_route.xml delete mode 100644 ln_jq_app/android/app/src/main/res/drawable/ic_start_marker.xml delete mode 100644 ln_jq_app/android/app/src/main/res/drawable/ic_station_marker.xml create mode 100644 ln_jq_app/android/app/src/main/res/drawable/ic_tag.png diff --git a/ln_jq_app/android/app/src/main/AndroidManifest.xml b/ln_jq_app/android/app/src/main/AndroidManifest.xml index 7a6ef64..c7cf8d3 100644 --- a/ln_jq_app/android/app/src/main/AndroidManifest.xml +++ b/ln_jq_app/android/app/src/main/AndroidManifest.xml @@ -14,7 +14,12 @@ - + + + + + + @@ -30,6 +35,11 @@ + + stationMarkers = new ArrayList<>(); public NativeMapView(Context context, int id, Object args) { this.mContext = context; - // 隐私合规接口,必须在创建MapView之前设置 + // 尝试获取Activity引用 + mActivity = getActivityFromContext(context); + MapsInitializer.updatePrivacyShow(context, true, true); MapsInitializer.updatePrivacyAgree(context, true); + container = new FrameLayout(context); + container.setClickable(true); + container.setFocusable(true); + mapView = new MapView(context); - // 在 Flutter PlatformView 中,savedInstanceState 通常为 null - mapView.onCreate(null); + mapView.onCreate(null); aMap = mapView.getMap(); - // 设置地图的 UI 选项 + container.addView(mapView, new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + + initServices(context); + initOverlays(context); setupMapUi(); - // 注册到 MainActivity 以便同步生命周期 + // 通知MainActivity if (context instanceof MainActivity) { ((MainActivity) context).setMapView(this); } + + Log.d(TAG, "NativeMapView初始化完成"); + } + + /** + * 初始化服务 + */ + private void initServices(Context context) { + try { + geocoderSearch = new GeocodeSearch(context); + geocoderSearch.setOnGeocodeSearchListener(this); + routeSearch = new RouteSearch(context); + routeSearch.setRouteSearchListener(this); + } catch (AMapException e) { + Log.e(TAG, "服务初始化失败", e); + } + } + + /** + * 初始化覆盖层UI + */ + private void initOverlays(Context context) { + LinearLayout searchBox = new LinearLayout(context); + searchBox.setOrientation(LinearLayout.VERTICAL); + searchBox.setBackground(getRoundedDrawable(Color.WHITE, 12)); + searchBox.setElevation(dp2px(8)); + int p = dp2px(15); + searchBox.setPadding(p, p, p, p); + searchBox.setClickable(true); + searchBox.setFocusable(true); + + startInput = createInput(context, "起点: 正在定位..."); + searchBox.addView(startInput); + + View vSpace = new View(context); + searchBox.addView(vSpace, new LinearLayout.LayoutParams(1, dp2px(10))); + + LinearLayout endRow = new LinearLayout(context); + endRow.setOrientation(LinearLayout.HORIZONTAL); + endRow.setGravity(Gravity.CENTER_VERTICAL); + + endInput = createInput(context, "终点: 请输入目的地"); + endRow.addView(endInput, new LinearLayout.LayoutParams(0, dp2px(42), 1f)); + + Button routeBtn = new Button(context); + routeBtn.setText("路径规划"); + routeBtn.setTextColor(Color.WHITE); + routeBtn.setAllCaps(false); + routeBtn.setTextSize(14); + routeBtn.setBackground(getRoundedDrawable(Color.parseColor("#017143"), 6)); + routeBtn.setOnClickListener(v -> startRouteSearch()); + endRow.addView(routeBtn, new LinearLayout.LayoutParams(dp2px(90), dp2px(42))); + + searchBox.addView(endRow); + + FrameLayout.LayoutParams searchParams = new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); + searchParams.setMargins(dp2px(15), dp2px(50), dp2px(15), 0); + container.addView(searchBox, searchParams); + + ImageButton locBtn = new ImageButton(context); + locBtn.setImageResource(android.R.drawable.ic_menu_mylocation); + locBtn.setBackground(getRoundedDrawable(Color.WHITE, 30)); + locBtn.setElevation(dp2px(4)); + locBtn.setOnClickListener(v -> { + if (currentLatLng != null) { + aMap.animateCamera(CameraUpdateFactory.newLatLngZoom(currentLatLng, 15f)); + } + }); + FrameLayout.LayoutParams locParams = new FrameLayout.LayoutParams(dp2px(50), dp2px(50)); + locParams.setMargins(0, 0, dp2px(20), dp2px(120)); + locParams.gravity = Gravity.BOTTOM | Gravity.END; + container.addView(locBtn, locParams); + } + + private EditText createInput(Context context, String hint) { + EditText et = new EditText(context); + et.setHint(hint); + et.setTextSize(14f); + et.setTextColor(Color.BLACK); + et.setPadding(dp2px(12), dp2px(10), dp2px(12), dp2px(10)); + et.setBackground(getRoundedDrawable(Color.parseColor("#F5F5F5"), 6)); + et.setSingleLine(true); + et.setImeOptions(EditorInfo.IME_ACTION_DONE); + et.setFocusable(true); + et.setFocusableInTouchMode(true); + return et; + } + + private GradientDrawable getRoundedDrawable(int color, int radiusDp) { + GradientDrawable shape = new GradientDrawable(); + shape.setShape(GradientDrawable.RECTANGLE); + shape.setCornerRadius(dp2px(radiusDp)); + shape.setColor(color); + return shape; + } + + private int dp2px(float dp) { + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, mContext.getResources().getDisplayMetrics()); } private void setupMapUi() { aMap.setLocationSource(this); aMap.setMyLocationEnabled(true); + aMap.setOnMarkerClickListener(this); MyLocationStyle myLocationStyle = new MyLocationStyle(); - myLocationStyle.interval(2000); - // 连续定位并将视角移动到地图中心点,定位蓝点跟随设备移动 - myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATE); + + // --- 放大定位图标 --- + try { + Bitmap carBitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.car); + if (carBitmap != null) { + // 放大到 80dp + int iconSize = dp2px(25); + Bitmap scaledBitmap = Bitmap.createScaledBitmap(carBitmap, iconSize, iconSize, true); + myLocationStyle.myLocationIcon(BitmapDescriptorFactory.fromBitmap(scaledBitmap)); + } + } catch (Exception e) { + Log.e(TAG, "设置大图标失败", e); + } + + myLocationStyle.anchor(0.5f, 0.5f); + myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER); myLocationStyle.showMyLocation(true); myLocationStyle.strokeColor(Color.TRANSPARENT); myLocationStyle.radiusFillColor(Color.TRANSPARENT); aMap.setMyLocationStyle(myLocationStyle); - - // 显示缩放按钮 + aMap.getUiSettings().setZoomControlsEnabled(true); + aMap.getUiSettings().setScaleControlsEnabled(true); + aMap.getUiSettings().setLogoPosition(AMapOptions.LOGO_POSITION_BOTTOM_LEFT); } - @Override - public View getView() { - return mapView; - } - + // ==================== LocationSource 接口实现 ==================== @Override public void activate(OnLocationChangedListener listener) { mListener = listener; @@ -88,56 +291,405 @@ public class NativeMapView implements PlatformView, LocationSource, AMapLocation public void startLocation() { if (mlocationClient == null) { try { - AMapLocationClient.updatePrivacyShow(mContext, true, true); - AMapLocationClient.updatePrivacyAgree(mContext, true); mlocationClient = new AMapLocationClient(mContext); - AMapLocationClientOption mLocationOption = new AMapLocationClientOption(); + AMapLocationClientOption option = new AMapLocationClientOption(); mlocationClient.setLocationListener(this); - mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy); - mlocationClient.setLocationOption(mLocationOption); + option.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy); + mlocationClient.setLocationOption(option); mlocationClient.startLocation(); + Log.d(TAG, "定位启动成功"); } catch (Exception e) { - Log.e(TAG, "startLocation error", e); + Log.e(TAG, "定位启动失败", e); } } } @Override - public void onLocationChanged(AMapLocation amapLocation) { - if (mListener != null && amapLocation != null) { - if (amapLocation.getErrorCode() == 0) { - mListener.onLocationChanged(amapLocation); - // 首次定位成功后缩放地图 - // aMap.moveCamera(CameraUpdateFactory.zoomTo(15)); - } else { - Log.e(TAG, "定位失败," + amapLocation.getErrorCode() + ": " + amapLocation.getErrorInfo()); + public void onLocationChanged(AMapLocation loc) { + if (loc != null) { + if (mListener != null) { + mListener.onLocationChanged(loc); + } + currentLatLng = new LatLng(loc.getLatitude(), loc.getLongitude()); + + if (loc.getErrorCode() == 0) { + if (isFirstLocation) { + isFirstLocation = false; + startPoint = currentLatLng; + aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(currentLatLng, 14f)); + getAddressByLatlng(currentLatLng); + fetchRecommendStation(loc); + fetchNearbyStations(loc); + } } } } - public void onResume() { - if (mapView != null) { - mapView.onResume(); + // ==================== 逆地理编码 ==================== + private void getAddressByLatlng(LatLng latLng) { + LatLonPoint point = new LatLonPoint(latLng.latitude, latLng.longitude); + RegeocodeQuery query = new RegeocodeQuery(point, 200, GeocodeSearch.AMAP); + geocoderSearch.getFromLocationAsyn(query); + } + + @Override + public void onRegeocodeSearched(RegeocodeResult result, int rCode) { + if (rCode == AMapException.CODE_AMAP_SUCCESS && result != null && result.getRegeocodeAddress() != null) { + RegeocodeAddress addr = result.getRegeocodeAddress(); + String fullAddr = addr.getFormatAddress(); + + // 优化地址显示逻辑 + startName = formatAddress(fullAddr,result); + + new Handler(Looper.getMainLooper()).post(() -> { + startInput.setText(startName); + startInput.setSelection(startName.length()); // 光标移到末尾 + }); + + Log.d(TAG, "逆地理编码成功: " + startName); + } else { + Log.e(TAG, "逆地理编码失败: code=" + rCode + ", result=" + (result != null ? "null" : "has data")); } } + /** + * 格式化地址显示,移除重复的前缀并限制长度 + */ + private String formatAddress(String fullAddress,RegeocodeResult result) { + if (fullAddress == null || fullAddress.isEmpty()) { + return "未知地点"; + } + + // 获取各级地址信息 + String province = null; + String city = null; + String district = null; + String township = null; + + try { + if (result.getRegeocodeAddress() != null) { + RegeocodeAddress addr = result.getRegeocodeAddress(); + province = addr.getProvince(); + city = addr.getCity(); + district = addr.getDistrict(); + township = addr.getTownship(); + } + } catch (Exception e) { + Log.e(TAG, "获取地址信息失败", e); + } + + String formattedAddr = fullAddress; + + // 按优先级移除重复前缀(省、市、区、乡) + String[] prefixes = {province, city, district, township}; + for (String prefix : prefixes) { + if (prefix != null && !prefix.isEmpty() && formattedAddr.startsWith(prefix)) { + formattedAddr = formattedAddr.substring(prefix.length()); + Log.d(TAG, "移除前缀: " + prefix + " -> " + formattedAddr); + } + } + + // 限制地址长度并添加省略号 + if (formattedAddr.length() > 25) { + formattedAddr = formattedAddr.substring(0, 25) + "..."; + Log.d(TAG, "地址长度截断: " + formattedAddr); + } + + return formattedAddr; + } + + @Override + public void onGeocodeSearched(GeocodeResult result, int rCode) { + } + + // ==================== API请求 ==================== + + private void fetchRecommendStation(AMapLocation loc) { + try { + JSONObject json = new JSONObject(); + json.put("province", loc.getProvince() != null ? loc.getProvince() : ""); + json.put("city", loc.getCity() != null && !loc.getCity().isEmpty() ? loc.getCity() : ""); + json.put("district", loc.getDistrict() != null ? loc.getDistrict() : ""); + json.put("longitude", String.valueOf(loc.getLongitude())); + json.put("latitude", String.valueOf(loc.getLatitude())); + + RequestBody body = RequestBody.create(json.toString(), MediaType.parse("application/json; charset=utf-8")); + Request request = new Request.Builder() + .url("https://beta-esg.api.lnh2e.com/appointment/station/getStationInfoByArea") + .post(body) + .build(); + + httpClient.newCall(request).enqueue(new Callback() { + @Override + public void onFailure(@NonNull Call call, @NonNull IOException e) { + } + + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { + if (response.isSuccessful() && response.body() != null) { + try { + JSONObject res = new JSONObject(response.body().string()); + if (res.getInt("code") == 0 && !res.isNull("data")) { + JSONObject data = res.getJSONObject("data"); + endPoint = new LatLng(data.getDouble("latitude"), data.getDouble("longitude")); + endName = data.getString("name"); + String addr = data.optString("address", ""); + new Handler(Looper.getMainLooper()).post(() -> { + endInput.setText(addr); + markStation(endPoint, endName, true); + }); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + }); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void fetchNearbyStations(AMapLocation loc) { + try { + JSONObject json = new JSONObject(); + json.put("longitude", String.valueOf(loc.getLongitude())); + json.put("latitude", String.valueOf(loc.getLatitude())); + + RequestBody body = RequestBody.create(json.toString(), MediaType.parse("application/json; charset=utf-8")); + Request request = new Request.Builder() + .url("https://beta-esg.api.lnh2e.com/appointment/station/getNearbyHydrogenStationsByLocation") + .post(body) + .build(); + + httpClient.newCall(request).enqueue(new Callback() { + @Override + public void onFailure(@NonNull Call call, @NonNull IOException e) { + } + + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { + if (response.isSuccessful() && response.body() != null) { + try { + JSONObject res = new JSONObject(response.body().string()); + if (res.getInt("code") == 0 && !res.isNull("data")) { + JSONArray array = res.getJSONArray("data"); + new Handler(Looper.getMainLooper()).post(() -> { + for (int i = 0; i < array.length(); i++) { + try { + JSONObject item = array.getJSONObject(i); + markStation(new LatLng(item.getDouble("latitude"), item.getDouble("longitude")), + item.getString("name"), false); + } catch (Exception ignored) { + } + } + }); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + }); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void markStation(LatLng latLng, String name, boolean isRecommend) { + MarkerOptions opt = new MarkerOptions() + .position(latLng).title(name) + .icon(BitmapDescriptorFactory.defaultMarker(isRecommend ? BitmapDescriptorFactory.HUE_RED : BitmapDescriptorFactory.HUE_GREEN)); + Marker m = aMap.addMarker(opt); + m.setObject(latLng); + stationMarkers.add(m); + } + + @Override + public boolean onMarkerClick(Marker marker) { + if (marker.getObject() instanceof LatLng) { + endPoint = (LatLng) marker.getObject(); + endName = marker.getTitle(); + endInput.setText(endName); + startRouteSearch(); + } + return true; + } + + // ==================== 路径规划 ==================== + + private void startRouteSearch() { + if (startPoint == null || endPoint == null) { + Toast.makeText(mContext, "正在定位中,请稍后...", Toast.LENGTH_SHORT).show(); + return; + } + + Poi start = new Poi(startName, startPoint, ""); + Poi end = new Poi(endName, endPoint, ""); + + AmapNaviParams params = new AmapNaviParams(start, null, end, AmapNaviType.DRIVER, AmapPageType.ROUTE); + + try { + AMapNavi mAMapNavi = AMapNavi.getInstance(mContext); + AMapCarInfo carInfo = new AMapCarInfo(); + carInfo.setCarNumber("沪AGK2267"); + carInfo.setCarType("1"); + carInfo.setVehicleAxis("6"); + carInfo.setVehicleHeight("3.32"); + carInfo.setVehicleLength("6.9"); + carInfo.setVehicleWidth("2.26"); + carInfo.setVehicleSize("2"); + carInfo.setVehicleLoad("4.5"); + carInfo.setVehicleWeight("4.5"); + carInfo.setRestriction(true); + carInfo.setVehicleLoadSwitch(true); + mAMapNavi.setCarInfo(carInfo); + } catch (com.amap.api.maps.AMapException e) { + Log.e(TAG, "设置车辆信息失败", e); + } + + params.setRouteStrategy(PathPlanningStrategy.DRIVING_MULTIPLE_ROUTES_DEFAULT); + + if (mActivity != null) { + AmapNaviPage.getInstance().showRouteActivity(mActivity, params, new INaviInfoCallback() { + @Override + public void onInitNaviFailure() { + Log.e(TAG, "导航初始化失败"); + } + + @Override + public void onGetNavigationText(String s) { + } + + @Override + public void onLocationChange(AMapNaviLocation location) { + } + + @Override + public void onArriveDestination(boolean b) { + } + + @Override + public void onStartNavi(int i) { + } + + @Override + public void onCalculateRouteSuccess(int[] ints) { + } + + @Override + public void onCalculateRouteFailure(int i) { + } + + @Override + public void onStopSpeaking() { + } + + @Override + public void onReCalculateRoute(int i) { + + } + + @Override + public void onArrivedWayPoint(int i) { + } + + @Override + public void onExitPage(int i) { + } + + @Override + public void onStrategyChanged(int i) { + } + + @Override + public void onMapTypeChanged(int i) { + } + + @Override + public void onNaviDirectionChanged(int i) { + } + + @Override + public void onDayAndNightModeChanged(int i) { + } + + @Override + public void onBroadcastModeChanged(int i) { + } + + @Override + public void onScaleAutoChanged(boolean b) { + } + + @Override + public View getCustomNaviBottomView() { + return null; + } + + @Override + public View getCustomNaviView() { + return null; + } + + @Override + public View getCustomMiddleView() { + return null; + } + }); + } + } + + @Override + public void onDriveRouteSearched(DriveRouteResult result, int rCode) { + } + + @Override + public void onBusRouteSearched(BusRouteResult r, int c) { + } + + @Override + public void onWalkRouteSearched(WalkRouteResult r, int c) { + } + + @Override + public void onRideRouteSearched(RideRouteResult r, int c) { + } + + private Activity getActivityFromContext(Context context) { + if (context instanceof Activity) + return (Activity) context; + if (context instanceof android.content.ContextWrapper) { + Context base = ((android.content.ContextWrapper) context).getBaseContext(); + if (base instanceof Activity) + return (Activity) base; + } + return null; + } + + public void onResume() { + mapView.onResume(); + } + public void onPause() { - if (mapView != null) { - mapView.onPause(); - } + mapView.onPause(); } - public void onSaveInstanceState(Bundle outState) { - if (mapView != null) { - mapView.onSaveInstanceState(outState); - } + public void onSaveInstanceState(Bundle out) { + mapView.onSaveInstanceState(out); + } + + @Override + public View getView() { + return container; } @Override public void dispose() { - if (mapView != null) { - mapView.onDestroy(); + if (mlocationClient != null) { + mlocationClient.stopLocation(); + mlocationClient.onDestroy(); } - deactivate(); + mapView.onDestroy(); } } diff --git a/ln_jq_app/android/app/src/main/res/drawable/amap_loc.xml b/ln_jq_app/android/app/src/main/res/drawable/amap_loc.xml deleted file mode 100644 index a58e47e..0000000 --- a/ln_jq_app/android/app/src/main/res/drawable/amap_loc.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - diff --git a/ln_jq_app/android/app/src/main/res/drawable/car.png b/ln_jq_app/android/app/src/main/res/drawable/car.png new file mode 100644 index 0000000000000000000000000000000000000000..5f5ba0a947ed485e890db49386838b4bad502d0c GIT binary patch literal 6754 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 UCptFqe;w2Hv~OuuYS>5o7klGh?EnA( literal 0 HcmV?d00001 diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_end_marker.xml b/ln_jq_app/android/app/src/main/res/drawable/ic_end_marker.xml deleted file mode 100644 index 58bb442..0000000 --- a/ln_jq_app/android/app/src/main/res/drawable/ic_end_marker.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_location.xml b/ln_jq_app/android/app/src/main/res/drawable/ic_location.xml deleted file mode 100644 index 4e99139..0000000 --- a/ln_jq_app/android/app/src/main/res/drawable/ic_location.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_route.xml b/ln_jq_app/android/app/src/main/res/drawable/ic_route.xml deleted file mode 100644 index e16e2fe..0000000 --- a/ln_jq_app/android/app/src/main/res/drawable/ic_route.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_start_marker.xml b/ln_jq_app/android/app/src/main/res/drawable/ic_start_marker.xml deleted file mode 100644 index 0af42cf..0000000 --- a/ln_jq_app/android/app/src/main/res/drawable/ic_start_marker.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_station_marker.xml b/ln_jq_app/android/app/src/main/res/drawable/ic_station_marker.xml deleted file mode 100644 index ef73731..0000000 --- a/ln_jq_app/android/app/src/main/res/drawable/ic_station_marker.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - diff --git a/ln_jq_app/android/app/src/main/res/drawable/ic_tag.png b/ln_jq_app/android/app/src/main/res/drawable/ic_tag.png new file mode 100644 index 0000000000000000000000000000000000000000..dcae650ed00ba1898bc26a07ed2e1943fef0ec8c GIT binary patch literal 3468 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