From 7dc163318f0d37933460263f45e75b4b346761a9 Mon Sep 17 00:00:00 2001 From: Daisy <> Date: Mon, 11 Dec 2023 10:43:41 +0800 Subject: [PATCH 01/33] =?UTF-8?q?=E5=AF=B9=E8=AE=B2=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- star_lock/lib/main.dart | 26 +- .../monitoring/lockMonitoring_page.dart | 187 +- .../monitoring/lockMonitoring_state.dart | 14165 +++++++++++++++- star_lock/lib/talk/call/callTalk.dart | 111 + star_lock/lib/talk/call/g711Decoder.dart | 44 + star_lock/lib/talk/call/iFrameInfo.dart | 22 + star_lock/lib/talk/playAudio.dart | 0 .../flutter/generated_plugin_registrant.cc | 4 + .../linux/flutter/generated_plugins.cmake | 1 + .../Flutter/GeneratedPluginRegistrant.swift | 6 + star_lock/pubspec.yaml | 9 + .../flutter/generated_plugin_registrant.cc | 3 + .../windows/flutter/generated_plugins.cmake | 1 + 13 files changed, 14477 insertions(+), 102 deletions(-) create mode 100644 star_lock/lib/talk/call/callTalk.dart create mode 100644 star_lock/lib/talk/call/g711Decoder.dart create mode 100644 star_lock/lib/talk/call/iFrameInfo.dart delete mode 100644 star_lock/lib/talk/playAudio.dart diff --git a/star_lock/lib/main.dart b/star_lock/lib/main.dart index 1d34717a..24fbff70 100644 --- a/star_lock/lib/main.dart +++ b/star_lock/lib/main.dart @@ -1,10 +1,12 @@ import 'package:aliyun_push/aliyun_push.dart'; +import 'package:audioplayers/audioplayers.dart'; // import 'package:audioplayers/audioplayers.dart'; import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; +import 'package:star_lock/talk/call/callTalk.dart'; import 'package:star_lock/tools/app_manager.dart'; import 'package:star_lock/tools/bindings/app_binding.dart'; import 'package:star_lock/tools/device_info_service.dart'; @@ -124,6 +126,12 @@ class _MyAppState extends State with WidgetsBindingObserver, BaseWidget { WidgetsBinding.instance?.addObserver(this); initAliyunPush(); + + // playLocalAudio(); + + Uint8List uint8List = Uint8List.fromList([]); + CallTalk talkClass = CallTalk(); + talkClass.getAVData(uint8List, 90); } //初始化阿里云推送 @@ -185,16 +193,8 @@ Future _setCommonServices() async { } //播放本地音频 -// void playAudio() async { -// const String audioPath = "assets/ring1.mp3"; -// AudioPlayer audioPlayer = AudioPlayer(); -// // int result = await audioPlayer.play(audioPath, isLocal: true); - -// if (result == 1) { -// // 播放成功 -// print("Audio playback successful!"); -// } else { -// // 播放失败 -// print("Error playing audio"); -// } -// } +void playLocalAudio() async { + final audioPlayer = AudioPlayer(); + audioPlayer.setReleaseMode(ReleaseMode.loop); + await audioPlayer.play(AssetSource('ring1.mp3')); +} diff --git a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart index c4cfd9c6..74128614 100644 --- a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart +++ b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart @@ -1,4 +1,3 @@ - import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; @@ -7,7 +6,6 @@ import '../../../../appRouters.dart'; import '../../../../app_settings/app_colors.dart'; import 'lockMonitoring_logic.dart'; - class LockMonitoringPage extends StatefulWidget { const LockMonitoringPage({Key? key}) : super(key: key); @@ -21,7 +19,7 @@ class _LockMonitoringPageState extends State { @override Widget build(BuildContext context) { - return Container( + return Container( width: 1.sw, height: 1.sh, color: Colors.white, @@ -30,37 +28,44 @@ class _LockMonitoringPageState extends State { Stack( // alignment: Alignment.bottomCenter, children: [ - Image.asset("images/icon_test20231113.png", width: 1.sw, height: 1.sh, fit: BoxFit.cover), + // Image.asset("images/icon_test20231113.png", width: 1.sw, height: 1.sh, fit: BoxFit.cover), + Image.memory( + state.imageData, + width: 1.sw, + height: 1.sh, + fit: BoxFit.cover, + ), Positioned( top: ScreenUtil().statusBarHeight + 30.h, - child: Row( - children: [ - SizedBox(width: 30.w), - GestureDetector( - onTap: () { - Get.back(); - }, - child: Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(30.h) - ), - padding: EdgeInsets.all(10.w), - child: Image(width: 40.w, height: 40.w, image: const AssetImage("images/icon_left_black.png"),), - ), + child: Row(children: [ + SizedBox(width: 30.w), + GestureDetector( + onTap: () { + Get.back(); + }, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(30.h)), + padding: EdgeInsets.all(10.w), + child: Image( + width: 40.w, + height: 40.w, + image: const AssetImage("images/icon_left_black.png"), ), + ), + ), ]), ), Positioned( bottom: 10.w, child: Container( - width: 1.sw - 30.w*2, + width: 1.sw - 30.w * 2, // height: 300.h, margin: EdgeInsets.all(30.w), decoration: BoxDecoration( color: const Color(0xC83C3F41), - borderRadius: BorderRadius.circular(20.h) - ), + borderRadius: BorderRadius.circular(20.h)), child: Column( children: [ SizedBox(height: 20.h), @@ -70,7 +75,7 @@ class _LockMonitoringPageState extends State { SizedBox(height: 20.h), ], ), - )) + )) ], ), ], @@ -78,76 +83,80 @@ class _LockMonitoringPageState extends State { ); } - Widget bottomTopBtnWidget(){ - return Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - // 打开关闭声音 - GestureDetector( - onTap: () { - state.isOpenVoice.value = !state.isOpenVoice.value; - }, - child: Container( - width: 50.w, - height: 50.w, - padding: EdgeInsets.all(5.w), - child: Obx(() => Image( - width: 40.w, - height: 40.w, - image: state.isOpenVoice.value - ? const AssetImage("images/main/icon_lockDetail_monitoringCloseVoice.png") - : const AssetImage("images/main/icon_lockDetail_monitoringOpenVoice.png") - )), - ), - ), - SizedBox(width: 60.w), - // 截图 - GestureDetector( - onTap: () { - // Get.toNamed(Routers.monitoringRealTimeScreenPage); - }, - child: Container( - width: 50.w, - height: 50.w, - padding: EdgeInsets.all(5.w), - child: Image(width: 40.w, height: 40.w, image: const AssetImage("images/main/icon_lockDetail_monitoringScreenshot.png")), - ), - ), - SizedBox(width: 60.w), - // 录制 - GestureDetector( - onTap: () { - // Get.toNamed(Routers.monitoringRealTimeScreenPage); - }, - child: Container( - width: 50.w, - height: 50.w, - padding: EdgeInsets.all(5.w), - child: Image(width: 40.w, height: 40.w, image: const AssetImage("images/main/icon_lockDetail_monitoringScreenRecording.png")), - ), - ), - ]); + Widget bottomTopBtnWidget() { + return Row(mainAxisAlignment: MainAxisAlignment.center, children: [ + // 打开关闭声音 + GestureDetector( + onTap: () { + state.isOpenVoice.value = !state.isOpenVoice.value; + }, + child: Container( + width: 50.w, + height: 50.w, + padding: EdgeInsets.all(5.w), + child: Obx(() => Image( + width: 40.w, + height: 40.w, + image: state.isOpenVoice.value + ? const AssetImage( + "images/main/icon_lockDetail_monitoringCloseVoice.png") + : const AssetImage( + "images/main/icon_lockDetail_monitoringOpenVoice.png"))), + ), + ), + SizedBox(width: 60.w), + // 截图 + GestureDetector( + onTap: () { + // Get.toNamed(Routers.monitoringRealTimeScreenPage); + }, + child: Container( + width: 50.w, + height: 50.w, + padding: EdgeInsets.all(5.w), + child: Image( + width: 40.w, + height: 40.w, + image: const AssetImage( + "images/main/icon_lockDetail_monitoringScreenshot.png")), + ), + ), + SizedBox(width: 60.w), + // 录制 + GestureDetector( + onTap: () { + // Get.toNamed(Routers.monitoringRealTimeScreenPage); + }, + child: Container( + width: 50.w, + height: 50.w, + padding: EdgeInsets.all(5.w), + child: Image( + width: 40.w, + height: 40.w, + image: const AssetImage( + "images/main/icon_lockDetail_monitoringScreenRecording.png")), + ), + ), + ]); } - Widget bottomBottomBtnWidget(){ - return Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - bottomBtnItemWidget("images/main/icon_lockDetail_monitoringTalkback.png", "点击对讲", Colors.white,(){ - - }), - bottomBtnItemWidget("images/main/icon_lockDetail_monitoringUnlock.png", "长按开锁", AppColors.mainColor,(){ - - }) - ]); + Widget bottomBottomBtnWidget() { + return Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ + bottomBtnItemWidget("images/main/icon_lockDetail_monitoringTalkback.png", + "点击对讲", Colors.white, () {}), + bottomBtnItemWidget("images/main/icon_lockDetail_monitoringUnlock.png", + "长按开锁", AppColors.mainColor, () {}) + ]); } - Widget bottomBtnItemWidget(String iconUrl, String name, Color backgroundColor, Function() onClick) { + Widget bottomBtnItemWidget( + String iconUrl, String name, Color backgroundColor, Function() onClick) { var wh = 80.w; return GestureDetector( onTap: onClick, child: SizedBox( - height: 140.h, + height: 140.h, child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ @@ -156,13 +165,15 @@ class _LockMonitoringPageState extends State { height: wh, decoration: BoxDecoration( color: backgroundColor, - borderRadius: BorderRadius.circular((wh+ 10.w*2)/2) - ), + borderRadius: BorderRadius.circular((wh + 10.w * 2) / 2)), padding: EdgeInsets.all(20.w), child: Image.asset(iconUrl, fit: BoxFit.fitWidth), ), SizedBox(height: 20.w), - Expanded(child: Text(name, style: TextStyle(fontSize: 20.sp, color: Colors.white), textAlign: TextAlign.center)) + Expanded( + child: Text(name, + style: TextStyle(fontSize: 20.sp, color: Colors.white), + textAlign: TextAlign.center)) ], )), ); diff --git a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_state.dart b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_state.dart index 991d59bf..a38b76f1 100644 --- a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_state.dart +++ b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_state.dart @@ -1,7 +1,14170 @@ +import 'dart:typed_data'; import 'package:get/get.dart'; class LockMonitoringState { var isOpenVoice = false.obs; -} \ No newline at end of file + Uint8List imageData = Uint8List.fromList([ + 255, + 216, + 255, + 224, + 0, + 17, + 74, + 70, + 73, + 70, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 204, + 255, + 225, + 0, + 166, + 69, + 120, + 105, + 102, + 0, + 0, + 77, + 77, + 0, + 42, + 0, + 0, + 0, + 8, + 0, + 8, + 1, + 15, + 0, + 2, + 0, + 0, + 0, + 7, + 0, + 0, + 0, + 122, + 1, + 16, + 0, + 2, + 0, + 0, + 0, + 8, + 0, + 0, + 0, + 130, + 1, + 18, + 0, + 3, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 26, + 0, + 5, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 38, + 1, + 27, + 0, + 5, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 38, + 1, + 40, + 0, + 3, + 0, + 0, + 0, + 1, + 0, + 2, + 0, + 0, + 2, + 19, + 0, + 3, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 135, + 105, + 0, + 4, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 138, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 4, + 105, + 112, + 112, + 0, + 0, + 0, + 3, + 194, + 74, + 76, + 68, + 86, + 0, + 0, + 0, + 0, + 65, + 67, + 53, + 52, + 0, + 0, + 0, + 0, + 0, + 1, + 144, + 0, + 0, + 7, + 0, + 0, + 0, + 4, + 48, + 50, + 50, + 48, + 0, + 0, + 0, + 0, + 0, + 0, + 255, + 219, + 0, + 67, + 0, + 40, + 28, + 30, + 35, + 30, + 25, + 40, + 35, + 33, + 35, + 45, + 43, + 40, + 48, + 60, + 100, + 65, + 60, + 55, + 55, + 60, + 123, + 88, + 93, + 73, + 100, + 145, + 128, + 153, + 150, + 143, + 128, + 140, + 138, + 160, + 180, + 230, + 195, + 160, + 170, + 218, + 173, + 138, + 140, + 200, + 255, + 203, + 218, + 238, + 245, + 255, + 255, + 255, + 155, + 193, + 255, + 255, + 255, + 250, + 255, + 230, + 253, + 255, + 248, + 255, + 219, + 0, + 67, + 1, + 43, + 45, + 45, + 60, + 53, + 60, + 118, + 65, + 65, + 118, + 248, + 165, + 140, + 165, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 248, + 255, + 192, + 0, + 17, + 8, + 1, + 224, + 2, + 128, + 3, + 1, + 34, + 0, + 2, + 17, + 1, + 3, + 17, + 1, + 255, + 196, + 0, + 31, + 0, + 0, + 1, + 5, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 255, + 196, + 0, + 31, + 1, + 0, + 3, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 255, + 196, + 0, + 181, + 16, + 0, + 2, + 1, + 3, + 3, + 2, + 4, + 3, + 5, + 5, + 4, + 4, + 0, + 0, + 1, + 125, + 1, + 2, + 3, + 0, + 4, + 17, + 5, + 18, + 33, + 49, + 65, + 6, + 19, + 81, + 97, + 7, + 34, + 113, + 20, + 50, + 129, + 145, + 161, + 8, + 35, + 66, + 177, + 193, + 21, + 82, + 209, + 240, + 36, + 51, + 98, + 114, + 130, + 9, + 10, + 22, + 23, + 24, + 25, + 26, + 37, + 38, + 39, + 40, + 41, + 42, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 131, + 132, + 133, + 134, + 135, + 136, + 137, + 138, + 146, + 147, + 148, + 149, + 150, + 151, + 152, + 153, + 154, + 162, + 163, + 164, + 165, + 166, + 167, + 168, + 169, + 170, + 178, + 179, + 180, + 181, + 182, + 183, + 184, + 185, + 186, + 194, + 195, + 196, + 197, + 198, + 199, + 200, + 201, + 202, + 210, + 211, + 212, + 213, + 214, + 215, + 216, + 217, + 218, + 225, + 226, + 227, + 228, + 229, + 230, + 231, + 232, + 233, + 234, + 241, + 242, + 243, + 244, + 245, + 246, + 247, + 248, + 249, + 250, + 255, + 196, + 0, + 181, + 17, + 0, + 2, + 1, + 2, + 4, + 4, + 3, + 4, + 7, + 5, + 4, + 4, + 0, + 1, + 2, + 119, + 0, + 1, + 2, + 3, + 17, + 4, + 5, + 33, + 49, + 6, + 18, + 65, + 81, + 7, + 97, + 113, + 19, + 34, + 50, + 129, + 8, + 20, + 66, + 145, + 161, + 177, + 193, + 9, + 35, + 51, + 82, + 240, + 21, + 98, + 114, + 209, + 10, + 22, + 36, + 52, + 225, + 37, + 241, + 23, + 24, + 25, + 26, + 38, + 39, + 40, + 41, + 42, + 53, + 54, + 55, + 56, + 57, + 58, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 130, + 131, + 132, + 133, + 134, + 135, + 136, + 137, + 138, + 146, + 147, + 148, + 149, + 150, + 151, + 152, + 153, + 154, + 162, + 163, + 164, + 165, + 166, + 167, + 168, + 169, + 170, + 178, + 179, + 180, + 181, + 182, + 183, + 184, + 185, + 186, + 194, + 195, + 196, + 197, + 198, + 199, + 200, + 201, + 202, + 210, + 211, + 212, + 213, + 214, + 215, + 216, + 217, + 218, + 226, + 227, + 228, + 229, + 230, + 231, + 232, + 233, + 234, + 242, + 243, + 244, + 245, + 246, + 247, + 248, + 249, + 250, + 255, + 218, + 0, + 12, + 3, + 1, + 0, + 2, + 17, + 3, + 17, + 0, + 63, + 0, + 207, + 162, + 138, + 41, + 0, + 81, + 69, + 20, + 192, + 40, + 162, + 138, + 0, + 41, + 105, + 41, + 104, + 0, + 162, + 138, + 40, + 0, + 162, + 138, + 40, + 0, + 162, + 138, + 40, + 0, + 162, + 138, + 40, + 0, + 162, + 138, + 40, + 0, + 162, + 138, + 40, + 0, + 162, + 138, + 40, + 0, + 162, + 138, + 40, + 0, + 162, + 138, + 40, + 0, + 162, + 138, + 40, + 0, + 165, + 164, + 165, + 164, + 1, + 69, + 20, + 80, + 48, + 164, + 165, + 162, + 128, + 18, + 150, + 138, + 40, + 16, + 81, + 69, + 20, + 12, + 40, + 162, + 138, + 0, + 40, + 162, + 138, + 4, + 20, + 81, + 69, + 0, + 20, + 148, + 180, + 80, + 48, + 164, + 165, + 164, + 160, + 2, + 138, + 40, + 160, + 66, + 210, + 82, + 209, + 64, + 9, + 69, + 45, + 37, + 3, + 10, + 90, + 74, + 40, + 16, + 81, + 69, + 20, + 0, + 180, + 82, + 82, + 208, + 1, + 69, + 20, + 80, + 1, + 73, + 75, + 69, + 0, + 20, + 81, + 69, + 48, + 10, + 41, + 40, + 160, + 5, + 162, + 146, + 138, + 0, + 40, + 162, + 138, + 0, + 40, + 162, + 146, + 129, + 5, + 45, + 37, + 45, + 0, + 20, + 162, + 146, + 148, + 80, + 3, + 197, + 58, + 154, + 41, + 192, + 80, + 4, + 20, + 81, + 69, + 3, + 10, + 40, + 162, + 128, + 10, + 40, + 162, + 128, + 22, + 138, + 74, + 90, + 0, + 40, + 162, + 138, + 0, + 40, + 162, + 138, + 0, + 40, + 162, + 138, + 0, + 40, + 162, + 138, + 0, + 40, + 162, + 138, + 0, + 40, + 162, + 138, + 0, + 40, + 162, + 138, + 0, + 40, + 162, + 150, + 129, + 137, + 69, + 45, + 37, + 2, + 10, + 41, + 104, + 160, + 98, + 81, + 75, + 69, + 33, + 5, + 20, + 81, + 76, + 2, + 138, + 40, + 160, + 97, + 69, + 20, + 80, + 1, + 69, + 20, + 80, + 1, + 69, + 20, + 82, + 0, + 162, + 138, + 40, + 16, + 81, + 69, + 20, + 192, + 40, + 162, + 138, + 6, + 20, + 81, + 69, + 0, + 20, + 81, + 69, + 2, + 10, + 40, + 162, + 144, + 9, + 75, + 69, + 20, + 0, + 81, + 69, + 20, + 12, + 41, + 41, + 105, + 40, + 16, + 180, + 82, + 81, + 64, + 11, + 69, + 37, + 45, + 0, + 20, + 81, + 73, + 64, + 5, + 20, + 81, + 64, + 5, + 20, + 81, + 76, + 2, + 138, + 92, + 81, + 64, + 9, + 69, + 20, + 80, + 2, + 81, + 75, + 73, + 64, + 130, + 150, + 146, + 150, + 128, + 10, + 81, + 73, + 74, + 40, + 1, + 235, + 82, + 129, + 81, + 173, + 74, + 40, + 2, + 165, + 20, + 81, + 64, + 194, + 138, + 40, + 164, + 1, + 69, + 45, + 20, + 192, + 40, + 162, + 138, + 0, + 40, + 162, + 138, + 0, + 40, + 162, + 138, + 0, + 40, + 165, + 162, + 128, + 18, + 138, + 90, + 40, + 1, + 40, + 165, + 164, + 160, + 2, + 138, + 90, + 49, + 64, + 5, + 20, + 98, + 138, + 0, + 40, + 162, + 138, + 0, + 40, + 165, + 2, + 157, + 182, + 128, + 25, + 70, + 42, + 77, + 180, + 161, + 40, + 2, + 60, + 81, + 138, + 147, + 109, + 24, + 160, + 87, + 35, + 197, + 20, + 242, + 41, + 166, + 129, + 137, + 69, + 20, + 162, + 128, + 19, + 20, + 184, + 167, + 1, + 78, + 2, + 128, + 35, + 219, + 70, + 218, + 151, + 20, + 98, + 128, + 185, + 22, + 218, + 93, + 181, + 38, + 40, + 160, + 87, + 35, + 197, + 38, + 41, + 230, + 154, + 104, + 1, + 180, + 81, + 69, + 3, + 12, + 82, + 237, + 165, + 20, + 240, + 40, + 1, + 155, + 104, + 219, + 82, + 224, + 81, + 138, + 5, + 114, + 29, + 180, + 109, + 169, + 182, + 209, + 138, + 66, + 185, + 14, + 218, + 66, + 42, + 82, + 41, + 132, + 83, + 26, + 99, + 40, + 165, + 197, + 24, + 160, + 98, + 81, + 78, + 219, + 70, + 218, + 0, + 109, + 20, + 165, + 72, + 164, + 164, + 1, + 69, + 20, + 80, + 48, + 164, + 165, + 164, + 160, + 66, + 210, + 81, + 69, + 0, + 20, + 81, + 69, + 0, + 20, + 82, + 82, + 208, + 2, + 209, + 73, + 70, + 105, + 128, + 180, + 98, + 129, + 75, + 64, + 13, + 162, + 148, + 210, + 80, + 33, + 41, + 104, + 162, + 128, + 10, + 81, + 73, + 78, + 2, + 128, + 30, + 181, + 42, + 212, + 74, + 42, + 85, + 226, + 128, + 42, + 209, + 69, + 20, + 12, + 40, + 162, + 138, + 6, + 20, + 81, + 69, + 2, + 10, + 40, + 162, + 128, + 10, + 90, + 40, + 160, + 2, + 138, + 49, + 75, + 138, + 0, + 74, + 41, + 104, + 160, + 2, + 140, + 82, + 129, + 78, + 2, + 128, + 25, + 182, + 151, + 109, + 60, + 10, + 118, + 40, + 2, + 61, + 180, + 109, + 169, + 49, + 72, + 104, + 16, + 204, + 83, + 77, + 60, + 211, + 77, + 0, + 54, + 148, + 81, + 138, + 90, + 6, + 40, + 20, + 225, + 77, + 20, + 241, + 64, + 10, + 41, + 192, + 83, + 105, + 232, + 9, + 25, + 160, + 45, + 112, + 197, + 53, + 170, + 109, + 148, + 141, + 23, + 20, + 13, + 65, + 149, + 141, + 52, + 213, + 143, + 39, + 52, + 162, + 220, + 30, + 180, + 138, + 228, + 101, + 90, + 81, + 87, + 214, + 210, + 16, + 57, + 92, + 159, + 173, + 50, + 72, + 99, + 31, + 117, + 64, + 250, + 83, + 14, + 86, + 85, + 6, + 156, + 13, + 59, + 203, + 197, + 33, + 90, + 87, + 14, + 70, + 25, + 164, + 221, + 72, + 69, + 38, + 40, + 23, + 40, + 237, + 212, + 155, + 169, + 184, + 162, + 130, + 108, + 41, + 52, + 211, + 75, + 138, + 93, + 180, + 192, + 101, + 21, + 38, + 204, + 209, + 229, + 154, + 0, + 104, + 52, + 224, + 104, + 242, + 205, + 27, + 13, + 0, + 46, + 234, + 93, + 212, + 205, + 164, + 81, + 131, + 233, + 64, + 135, + 110, + 163, + 117, + 51, + 6, + 146, + 128, + 176, + 226, + 212, + 220, + 210, + 81, + 64, + 210, + 22, + 148, + 83, + 104, + 205, + 3, + 37, + 81, + 82, + 5, + 6, + 161, + 86, + 169, + 85, + 168, + 37, + 138, + 83, + 138, + 141, + 163, + 169, + 195, + 2, + 41, + 9, + 20, + 137, + 43, + 21, + 197, + 52, + 138, + 153, + 170, + 38, + 160, + 105, + 140, + 163, + 52, + 81, + 138, + 101, + 5, + 20, + 237, + 180, + 133, + 77, + 32, + 27, + 69, + 46, + 41, + 41, + 128, + 81, + 69, + 20, + 0, + 180, + 80, + 41, + 104, + 0, + 165, + 164, + 160, + 80, + 1, + 73, + 78, + 164, + 52, + 0, + 148, + 81, + 69, + 2, + 20, + 84, + 138, + 42, + 49, + 79, + 83, + 64, + 19, + 1, + 197, + 6, + 154, + 166, + 159, + 140, + 208, + 50, + 165, + 20, + 82, + 208, + 2, + 82, + 209, + 75, + 64, + 9, + 69, + 45, + 0, + 80, + 49, + 40, + 2, + 165, + 84, + 169, + 86, + 49, + 233, + 64, + 136, + 2, + 26, + 119, + 150, + 106, + 200, + 64, + 41, + 74, + 208, + 23, + 42, + 109, + 164, + 197, + 74, + 194, + 163, + 52, + 8, + 109, + 37, + 45, + 24, + 160, + 96, + 41, + 194, + 140, + 26, + 80, + 166, + 128, + 20, + 26, + 92, + 208, + 16, + 211, + 196, + 102, + 128, + 35, + 205, + 24, + 38, + 166, + 17, + 84, + 139, + 21, + 0, + 86, + 17, + 19, + 235, + 75, + 246, + 126, + 249, + 53, + 117, + 99, + 160, + 165, + 49, + 20, + 124, + 172, + 83, + 132, + 85, + 107, + 203, + 165, + 9, + 64, + 238, + 87, + 88, + 135, + 165, + 57, + 98, + 201, + 171, + 1, + 105, + 225, + 104, + 17, + 7, + 146, + 41, + 66, + 96, + 99, + 29, + 42, + 198, + 41, + 49, + 65, + 73, + 145, + 5, + 164, + 97, + 206, + 42, + 99, + 128, + 42, + 34, + 50, + 106, + 90, + 54, + 140, + 144, + 220, + 82, + 138, + 93, + 180, + 187, + 105, + 88, + 110, + 104, + 66, + 213, + 11, + 181, + 78, + 87, + 138, + 173, + 50, + 28, + 113, + 79, + 81, + 115, + 161, + 140, + 226, + 155, + 184, + 26, + 174, + 229, + 129, + 193, + 20, + 138, + 228, + 81, + 98, + 92, + 203, + 36, + 83, + 77, + 52, + 62, + 69, + 52, + 181, + 22, + 5, + 49, + 244, + 10, + 64, + 185, + 239, + 74, + 84, + 47, + 66, + 77, + 52, + 153, + 18, + 104, + 92, + 10, + 51, + 81, + 151, + 166, + 150, + 162, + 196, + 19, + 6, + 169, + 20, + 138, + 169, + 184, + 210, + 172, + 132, + 119, + 166, + 5, + 224, + 160, + 211, + 182, + 85, + 120, + 166, + 171, + 11, + 32, + 52, + 132, + 2, + 47, + 106, + 67, + 21, + 74, + 172, + 41, + 220, + 80, + 50, + 185, + 139, + 218, + 155, + 229, + 123, + 85, + 154, + 118, + 40, + 2, + 153, + 134, + 163, + 49, + 85, + 242, + 5, + 70, + 202, + 40, + 11, + 148, + 76, + 102, + 147, + 97, + 171, + 155, + 40, + 49, + 138, + 2, + 229, + 61, + 166, + 128, + 72, + 171, + 6, + 58, + 97, + 74, + 7, + 114, + 61, + 196, + 81, + 190, + 148, + 173, + 33, + 90, + 65, + 97, + 11, + 83, + 9, + 167, + 21, + 164, + 197, + 48, + 18, + 156, + 41, + 180, + 103, + 20, + 1, + 50, + 129, + 78, + 41, + 80, + 135, + 197, + 76, + 175, + 145, + 64, + 152, + 198, + 142, + 152, + 80, + 213, + 140, + 138, + 105, + 197, + 34, + 28, + 138, + 229, + 113, + 77, + 169, + 159, + 165, + 68, + 104, + 26, + 98, + 10, + 80, + 105, + 40, + 166, + 89, + 32, + 165, + 197, + 52, + 26, + 118, + 104, + 1, + 166, + 146, + 156, + 105, + 40, + 1, + 180, + 82, + 209, + 64, + 130, + 156, + 180, + 220, + 83, + 212, + 80, + 50, + 69, + 28, + 212, + 234, + 6, + 42, + 21, + 226, + 165, + 86, + 160, + 10, + 84, + 180, + 184, + 163, + 20, + 0, + 148, + 81, + 69, + 0, + 45, + 57, + 105, + 180, + 229, + 160, + 9, + 148, + 84, + 171, + 80, + 169, + 169, + 3, + 80, + 4, + 162, + 152, + 198, + 144, + 18, + 105, + 226, + 50, + 105, + 138, + 197, + 118, + 4, + 211, + 54, + 19, + 86, + 204, + 84, + 162, + 33, + 233, + 64, + 202, + 130, + 35, + 82, + 44, + 85, + 103, + 203, + 20, + 161, + 61, + 168, + 2, + 1, + 21, + 60, + 69, + 197, + 78, + 20, + 83, + 130, + 208, + 4, + 2, + 58, + 112, + 142, + 166, + 43, + 73, + 138, + 4, + 48, + 32, + 167, + 5, + 2, + 150, + 138, + 0, + 81, + 72, + 122, + 209, + 72, + 104, + 1, + 40, + 162, + 148, + 80, + 2, + 83, + 133, + 54, + 156, + 40, + 1, + 212, + 220, + 210, + 154, + 109, + 0, + 45, + 38, + 41, + 105, + 40, + 1, + 69, + 46, + 40, + 20, + 80, + 2, + 26, + 97, + 64, + 105, + 230, + 129, + 64, + 21, + 38, + 128, + 30, + 213, + 81, + 237, + 202, + 244, + 173, + 98, + 51, + 81, + 180, + 96, + 208, + 51, + 32, + 171, + 14, + 162, + 144, + 31, + 99, + 90, + 166, + 0, + 123, + 83, + 77, + 184, + 244, + 160, + 10, + 8, + 222, + 185, + 167, + 51, + 130, + 56, + 205, + 90, + 54, + 227, + 251, + 181, + 20, + 176, + 145, + 210, + 157, + 198, + 149, + 202, + 189, + 77, + 61, + 98, + 45, + 222, + 151, + 111, + 53, + 60, + 56, + 21, + 55, + 27, + 129, + 92, + 219, + 181, + 70, + 200, + 203, + 214, + 181, + 70, + 210, + 57, + 166, + 73, + 10, + 176, + 166, + 77, + 140, + 176, + 216, + 169, + 82, + 67, + 235, + 73, + 60, + 69, + 14, + 69, + 70, + 185, + 6, + 144, + 172, + 94, + 73, + 13, + 72, + 37, + 245, + 53, + 90, + 35, + 82, + 26, + 5, + 98, + 202, + 56, + 53, + 40, + 35, + 21, + 68, + 54, + 13, + 74, + 178, + 80, + 4, + 228, + 211, + 77, + 51, + 125, + 25, + 160, + 7, + 80, + 104, + 205, + 52, + 154, + 4, + 6, + 152, + 105, + 73, + 166, + 208, + 2, + 98, + 147, + 109, + 62, + 138, + 2, + 228, + 101, + 105, + 133, + 42, + 108, + 81, + 138, + 101, + 92, + 174, + 82, + 154, + 86, + 172, + 145, + 77, + 42, + 13, + 0, + 86, + 193, + 160, + 18, + 166, + 167, + 41, + 77, + 217, + 72, + 6, + 249, + 148, + 134, + 67, + 74, + 99, + 166, + 148, + 52, + 172, + 43, + 33, + 11, + 102, + 155, + 154, + 92, + 26, + 74, + 99, + 176, + 229, + 25, + 171, + 240, + 91, + 43, + 32, + 56, + 172, + 244, + 59, + 79, + 181, + 104, + 89, + 92, + 99, + 228, + 99, + 211, + 165, + 0, + 19, + 89, + 113, + 149, + 224, + 213, + 70, + 70, + 66, + 67, + 14, + 149, + 184, + 10, + 186, + 228, + 84, + 19, + 66, + 27, + 156, + 83, + 11, + 152, + 230, + 146, + 172, + 203, + 6, + 210, + 72, + 226, + 171, + 145, + 138, + 66, + 184, + 218, + 81, + 73, + 74, + 40, + 24, + 224, + 42, + 69, + 20, + 197, + 169, + 86, + 129, + 139, + 70, + 121, + 167, + 129, + 78, + 218, + 61, + 40, + 2, + 2, + 184, + 166, + 17, + 83, + 61, + 68, + 104, + 1, + 134, + 146, + 157, + 183, + 52, + 245, + 140, + 208, + 3, + 0, + 167, + 170, + 154, + 153, + 98, + 169, + 22, + 58, + 0, + 133, + 80, + 212, + 170, + 149, + 32, + 74, + 122, + 173, + 0, + 53, + 35, + 169, + 213, + 40, + 81, + 79, + 20, + 196, + 52, + 168, + 166, + 237, + 167, + 181, + 54, + 128, + 19, + 20, + 134, + 157, + 72, + 104, + 0, + 20, + 240, + 41, + 131, + 173, + 72, + 40, + 0, + 199, + 20, + 211, + 79, + 166, + 181, + 0, + 54, + 138, + 40, + 160, + 4, + 164, + 165, + 162, + 128, + 18, + 138, + 40, + 160, + 4, + 52, + 162, + 131, + 64, + 160, + 7, + 83, + 105, + 105, + 13, + 0, + 45, + 37, + 3, + 165, + 20, + 0, + 225, + 69, + 2, + 138, + 0, + 67, + 74, + 41, + 41, + 104, + 1, + 13, + 37, + 41, + 160, + 80, + 1, + 138, + 41, + 105, + 13, + 0, + 32, + 20, + 199, + 64, + 69, + 74, + 41, + 13, + 1, + 114, + 140, + 144, + 227, + 145, + 76, + 198, + 42, + 241, + 80, + 106, + 39, + 136, + 82, + 177, + 170, + 151, + 114, + 1, + 33, + 20, + 225, + 45, + 35, + 68, + 69, + 70, + 80, + 142, + 162, + 150, + 165, + 89, + 49, + 37, + 195, + 84, + 59, + 42, + 112, + 167, + 210, + 151, + 103, + 181, + 23, + 11, + 34, + 21, + 24, + 167, + 243, + 235, + 65, + 227, + 173, + 52, + 184, + 164, + 14, + 195, + 179, + 64, + 106, + 104, + 96, + 105, + 88, + 99, + 189, + 2, + 208, + 120, + 122, + 112, + 122, + 175, + 186, + 156, + 14, + 105, + 153, + 202, + 37, + 144, + 244, + 22, + 168, + 51, + 138, + 55, + 83, + 51, + 37, + 205, + 45, + 70, + 26, + 141, + 212, + 8, + 150, + 138, + 96, + 106, + 112, + 160, + 7, + 1, + 75, + 73, + 70, + 104, + 1, + 13, + 54, + 156, + 105, + 180, + 202, + 66, + 81, + 138, + 49, + 75, + 64, + 195, + 20, + 210, + 153, + 167, + 210, + 208, + 4, + 70, + 58, + 141, + 163, + 171, + 52, + 220, + 102, + 128, + 42, + 20, + 52, + 131, + 42, + 65, + 29, + 69, + 92, + 216, + 41, + 141, + 22, + 105, + 88, + 9, + 32, + 187, + 32, + 243, + 86, + 126, + 212, + 58, + 26, + 205, + 104, + 200, + 166, + 229, + 128, + 198, + 120, + 160, + 86, + 46, + 205, + 34, + 158, + 65, + 170, + 140, + 115, + 76, + 220, + 125, + 104, + 160, + 74, + 33, + 140, + 154, + 127, + 146, + 253, + 70, + 41, + 189, + 8, + 62, + 245, + 171, + 2, + 171, + 160, + 97, + 206, + 104, + 40, + 205, + 216, + 203, + 247, + 133, + 72, + 166, + 181, + 26, + 221, + 72, + 224, + 85, + 9, + 173, + 138, + 28, + 175, + 79, + 74, + 0, + 23, + 145, + 154, + 112, + 53, + 10, + 57, + 80, + 84, + 211, + 139, + 226, + 129, + 129, + 92, + 209, + 229, + 26, + 156, + 71, + 78, + 242, + 232, + 2, + 5, + 142, + 164, + 84, + 197, + 72, + 22, + 157, + 138, + 0, + 98, + 173, + 72, + 22, + 146, + 156, + 40, + 1, + 49, + 69, + 41, + 164, + 160, + 7, + 169, + 167, + 84, + 64, + 211, + 193, + 166, + 0, + 105, + 40, + 52, + 148, + 0, + 180, + 180, + 218, + 81, + 64, + 130, + 164, + 6, + 153, + 74, + 13, + 0, + 62, + 154, + 105, + 115, + 77, + 52, + 0, + 218, + 90, + 67, + 69, + 0, + 20, + 81, + 69, + 0, + 37, + 20, + 82, + 80, + 2, + 209, + 69, + 37, + 0, + 58, + 144, + 208, + 40, + 52, + 0, + 10, + 40, + 20, + 26, + 0, + 81, + 75, + 72, + 40, + 160, + 5, + 162, + 129, + 65, + 160, + 6, + 154, + 81, + 77, + 61, + 105, + 227, + 165, + 0, + 20, + 148, + 19, + 64, + 160, + 5, + 20, + 134, + 150, + 146, + 128, + 12, + 82, + 26, + 119, + 106, + 109, + 0, + 52, + 168, + 166, + 20, + 6, + 165, + 61, + 41, + 180, + 135, + 113, + 130, + 58, + 82, + 131, + 20, + 252, + 80, + 104, + 11, + 149, + 37, + 135, + 34, + 168, + 200, + 174, + 135, + 145, + 197, + 108, + 227, + 34, + 161, + 146, + 16, + 195, + 165, + 1, + 115, + 36, + 57, + 20, + 227, + 38, + 106, + 121, + 109, + 121, + 202, + 241, + 80, + 52, + 46, + 59, + 102, + 128, + 184, + 221, + 212, + 161, + 241, + 64, + 70, + 238, + 40, + 43, + 237, + 69, + 135, + 113, + 222, + 97, + 52, + 133, + 207, + 189, + 52, + 10, + 93, + 132, + 208, + 72, + 162, + 74, + 145, + 100, + 205, + 66, + 80, + 138, + 104, + 36, + 80, + 43, + 22, + 212, + 212, + 202, + 106, + 172, + 109, + 154, + 152, + 26, + 9, + 177, + 54, + 104, + 205, + 70, + 26, + 141, + 217, + 160, + 7, + 117, + 165, + 2, + 144, + 26, + 118, + 104, + 0, + 197, + 38, + 41, + 212, + 98, + 152, + 13, + 162, + 148, + 241, + 77, + 205, + 5, + 11, + 75, + 138, + 65, + 75, + 64, + 197, + 162, + 138, + 74, + 0, + 66, + 51, + 76, + 104, + 243, + 82, + 82, + 208, + 5, + 70, + 143, + 20, + 208, + 42, + 225, + 80, + 106, + 54, + 142, + 144, + 200, + 113, + 197, + 75, + 107, + 112, + 97, + 125, + 164, + 252, + 167, + 165, + 49, + 144, + 138, + 137, + 135, + 173, + 0, + 205, + 184, + 238, + 20, + 212, + 140, + 21, + 197, + 97, + 44, + 174, + 184, + 193, + 233, + 86, + 224, + 188, + 199, + 90, + 46, + 78, + 168, + 154, + 123, + 117, + 228, + 138, + 162, + 224, + 171, + 98, + 174, + 181, + 192, + 110, + 42, + 9, + 227, + 207, + 43, + 215, + 210, + 129, + 43, + 151, + 194, + 226, + 130, + 41, + 212, + 134, + 153, + 99, + 49, + 69, + 41, + 164, + 164, + 1, + 74, + 40, + 165, + 160, + 2, + 154, + 105, + 198, + 154, + 104, + 1, + 41, + 65, + 164, + 162, + 128, + 29, + 154, + 41, + 185, + 165, + 166, + 2, + 209, + 73, + 75, + 64, + 133, + 20, + 82, + 102, + 150, + 128, + 29, + 154, + 66, + 105, + 185, + 165, + 160, + 0, + 210, + 81, + 73, + 64, + 14, + 162, + 146, + 138, + 0, + 13, + 37, + 6, + 146, + 128, + 22, + 138, + 40, + 160, + 5, + 20, + 26, + 65, + 74, + 104, + 1, + 5, + 41, + 164, + 165, + 160, + 0, + 82, + 211, + 105, + 104, + 1, + 69, + 6, + 138, + 67, + 64, + 9, + 222, + 159, + 218, + 152, + 41, + 212, + 0, + 135, + 173, + 40, + 166, + 247, + 167, + 10, + 0, + 83, + 77, + 165, + 52, + 130, + 128, + 20, + 210, + 80, + 105, + 40, + 0, + 52, + 82, + 210, + 80, + 1, + 64, + 162, + 148, + 10, + 0, + 41, + 166, + 148, + 211, + 77, + 0, + 49, + 134, + 106, + 50, + 128, + 212, + 134, + 144, + 210, + 2, + 22, + 140, + 84, + 47, + 29, + 88, + 106, + 105, + 25, + 160, + 105, + 148, + 202, + 226, + 156, + 132, + 10, + 149, + 210, + 162, + 43, + 138, + 70, + 154, + 50, + 76, + 6, + 21, + 4, + 177, + 227, + 145, + 79, + 12, + 69, + 12, + 217, + 167, + 114, + 92, + 72, + 17, + 182, + 181, + 90, + 67, + 145, + 85, + 138, + 243, + 82, + 33, + 34, + 130, + 92, + 73, + 169, + 69, + 71, + 184, + 210, + 111, + 164, + 46, + 86, + 78, + 41, + 115, + 81, + 7, + 167, + 131, + 154, + 100, + 181, + 98, + 64, + 105, + 217, + 168, + 179, + 138, + 80, + 212, + 18, + 60, + 210, + 98, + 141, + 212, + 103, + 52, + 20, + 152, + 162, + 150, + 144, + 80, + 77, + 49, + 129, + 162, + 146, + 148, + 80, + 49, + 104, + 162, + 138, + 0, + 41, + 40, + 205, + 20, + 0, + 48, + 205, + 68, + 209, + 230, + 165, + 162, + 128, + 42, + 50, + 17, + 77, + 239, + 87, + 25, + 65, + 168, + 26, + 63, + 74, + 67, + 22, + 35, + 205, + 94, + 136, + 2, + 167, + 214, + 179, + 134, + 84, + 212, + 209, + 205, + 182, + 128, + 52, + 168, + 162, + 138, + 96, + 33, + 164, + 165, + 52, + 148, + 0, + 82, + 138, + 74, + 81, + 64, + 5, + 52, + 211, + 169, + 13, + 0, + 51, + 52, + 180, + 134, + 147, + 52, + 128, + 90, + 40, + 162, + 128, + 22, + 150, + 144, + 82, + 211, + 16, + 82, + 211, + 105, + 104, + 0, + 52, + 102, + 138, + 74, + 0, + 90, + 41, + 40, + 160, + 5, + 20, + 180, + 218, + 117, + 0, + 6, + 155, + 75, + 73, + 64, + 5, + 45, + 37, + 20, + 0, + 180, + 166, + 155, + 74, + 40, + 1, + 41, + 212, + 134, + 129, + 64, + 5, + 45, + 37, + 45, + 0, + 20, + 134, + 150, + 131, + 64, + 8, + 41, + 104, + 20, + 26, + 0, + 65, + 214, + 157, + 72, + 41, + 77, + 0, + 38, + 104, + 164, + 165, + 52, + 0, + 148, + 148, + 80, + 41, + 0, + 180, + 148, + 166, + 155, + 64, + 14, + 20, + 164, + 224, + 82, + 10, + 70, + 60, + 208, + 0, + 77, + 48, + 210, + 230, + 154, + 104, + 0, + 205, + 53, + 141, + 6, + 152, + 78, + 77, + 2, + 18, + 138, + 92, + 81, + 76, + 119, + 26, + 121, + 166, + 148, + 205, + 72, + 5, + 46, + 41, + 14, + 246, + 42, + 180, + 120, + 166, + 109, + 53, + 105, + 133, + 33, + 81, + 69, + 138, + 230, + 43, + 109, + 52, + 157, + 42, + 206, + 193, + 81, + 201, + 22, + 69, + 43, + 7, + 49, + 17, + 97, + 73, + 156, + 211, + 29, + 89, + 79, + 52, + 208, + 196, + 81, + 97, + 92, + 144, + 154, + 150, + 39, + 207, + 94, + 181, + 88, + 181, + 10, + 196, + 28, + 138, + 44, + 15, + 82, + 254, + 51, + 205, + 55, + 165, + 64, + 39, + 32, + 82, + 25, + 205, + 51, + 59, + 22, + 5, + 58, + 170, + 172, + 245, + 58, + 48, + 122, + 5, + 97, + 251, + 169, + 65, + 166, + 26, + 1, + 197, + 5, + 34, + 81, + 75, + 81, + 238, + 163, + 125, + 49, + 146, + 82, + 19, + 76, + 221, + 154, + 112, + 160, + 2, + 150, + 147, + 52, + 153, + 205, + 0, + 59, + 52, + 82, + 1, + 78, + 197, + 0, + 38, + 41, + 112, + 41, + 105, + 40, + 2, + 55, + 140, + 30, + 149, + 11, + 41, + 90, + 181, + 138, + 99, + 224, + 210, + 25, + 127, + 52, + 102, + 152, + 13, + 25, + 166, + 33, + 212, + 83, + 115, + 70, + 104, + 24, + 234, + 41, + 51, + 75, + 154, + 0, + 90, + 67, + 70, + 105, + 51, + 64, + 8, + 105, + 180, + 166, + 146, + 144, + 5, + 45, + 54, + 148, + 80, + 2, + 210, + 210, + 10, + 90, + 0, + 40, + 162, + 150, + 152, + 9, + 69, + 20, + 80, + 33, + 41, + 105, + 41, + 69, + 3, + 10, + 81, + 73, + 69, + 2, + 22, + 138, + 5, + 20, + 0, + 148, + 80, + 104, + 160, + 5, + 165, + 20, + 130, + 148, + 117, + 160, + 4, + 52, + 14, + 148, + 166, + 129, + 64, + 9, + 75, + 65, + 162, + 128, + 10, + 67, + 210, + 150, + 144, + 208, + 2, + 138, + 70, + 165, + 20, + 134, + 128, + 20, + 80, + 104, + 20, + 134, + 128, + 20, + 83, + 77, + 40, + 164, + 61, + 104, + 0, + 165, + 20, + 218, + 90, + 64, + 6, + 144, + 10, + 94, + 244, + 80, + 2, + 246, + 166, + 26, + 113, + 52, + 194, + 104, + 0, + 166, + 147, + 65, + 52, + 210, + 104, + 1, + 24, + 211, + 69, + 7, + 154, + 112, + 20, + 0, + 82, + 80, + 77, + 40, + 20, + 8, + 81, + 77, + 38, + 148, + 154, + 105, + 160, + 98, + 19, + 69, + 20, + 184, + 166, + 48, + 20, + 238, + 212, + 152, + 160, + 208, + 34, + 55, + 140, + 53, + 87, + 120, + 57, + 226, + 173, + 209, + 138, + 0, + 207, + 48, + 176, + 247, + 166, + 148, + 35, + 168, + 173, + 45, + 163, + 210, + 152, + 241, + 2, + 40, + 25, + 68, + 10, + 112, + 140, + 183, + 74, + 145, + 227, + 218, + 104, + 70, + 218, + 121, + 165, + 113, + 242, + 144, + 188, + 108, + 189, + 105, + 98, + 147, + 99, + 123, + 85, + 167, + 42, + 233, + 84, + 221, + 112, + 77, + 2, + 177, + 125, + 126, + 97, + 72, + 86, + 162, + 182, + 147, + 229, + 193, + 169, + 201, + 20, + 10, + 196, + 102, + 129, + 79, + 192, + 166, + 154, + 6, + 38, + 113, + 73, + 184, + 210, + 227, + 52, + 108, + 197, + 0, + 56, + 26, + 112, + 168, + 233, + 115, + 64, + 18, + 131, + 75, + 81, + 110, + 167, + 6, + 166, + 33, + 249, + 164, + 205, + 55, + 52, + 229, + 92, + 154, + 6, + 39, + 38, + 148, + 33, + 53, + 42, + 160, + 21, + 32, + 90, + 4, + 68, + 31, + 222, + 157, + 190, + 170, + 134, + 165, + 15, + 64, + 22, + 119, + 82, + 238, + 170, + 251, + 233, + 119, + 208, + 4, + 251, + 169, + 67, + 84, + 27, + 233, + 67, + 251, + 208, + 50, + 124, + 209, + 154, + 132, + 61, + 59, + 117, + 0, + 63, + 52, + 83, + 55, + 81, + 186, + 128, + 29, + 75, + 76, + 13, + 75, + 154, + 64, + 58, + 151, + 52, + 204, + 210, + 230, + 128, + 29, + 154, + 90, + 102, + 105, + 65, + 160, + 7, + 81, + 73, + 154, + 51, + 76, + 5, + 164, + 165, + 164, + 52, + 8, + 90, + 81, + 72, + 41, + 104, + 0, + 165, + 164, + 162, + 128, + 3, + 72, + 41, + 105, + 40, + 24, + 180, + 119, + 162, + 138, + 4, + 58, + 147, + 189, + 3, + 165, + 33, + 160, + 5, + 52, + 148, + 238, + 212, + 134, + 128, + 10, + 67, + 75, + 218, + 147, + 189, + 0, + 40, + 233, + 72, + 122, + 211, + 135, + 74, + 111, + 122, + 0, + 112, + 166, + 181, + 58, + 152, + 122, + 208, + 1, + 69, + 6, + 138, + 64, + 20, + 81, + 69, + 0, + 20, + 82, + 226, + 154, + 78, + 40, + 1, + 24, + 211, + 77, + 41, + 52, + 210, + 104, + 1, + 9, + 166, + 19, + 74, + 77, + 37, + 0, + 20, + 19, + 69, + 24, + 160, + 1, + 69, + 41, + 52, + 180, + 210, + 104, + 0, + 205, + 37, + 2, + 150, + 128, + 0, + 41, + 104, + 20, + 180, + 8, + 67, + 73, + 75, + 138, + 40, + 24, + 152, + 165, + 197, + 20, + 83, + 0, + 165, + 164, + 160, + 154, + 0, + 99, + 160, + 53, + 93, + 163, + 32, + 241, + 86, + 186, + 208, + 84, + 82, + 101, + 41, + 88, + 170, + 20, + 210, + 249, + 89, + 169, + 138, + 138, + 80, + 49, + 83, + 99, + 69, + 36, + 68, + 176, + 227, + 165, + 56, + 198, + 64, + 167, + 25, + 54, + 212, + 77, + 113, + 158, + 49, + 70, + 163, + 109, + 13, + 36, + 138, + 64, + 248, + 60, + 211, + 131, + 3, + 214, + 163, + 124, + 3, + 193, + 166, + 77, + 211, + 44, + 166, + 8, + 167, + 98, + 171, + 195, + 38, + 14, + 13, + 88, + 200, + 245, + 20, + 204, + 216, + 155, + 105, + 8, + 197, + 56, + 178, + 250, + 138, + 122, + 174, + 104, + 2, + 29, + 140, + 123, + 82, + 133, + 34, + 172, + 236, + 20, + 108, + 20, + 1, + 92, + 3, + 82, + 47, + 20, + 242, + 148, + 155, + 40, + 1, + 85, + 170, + 64, + 213, + 14, + 49, + 74, + 51, + 76, + 69, + 32, + 212, + 224, + 106, + 46, + 65, + 165, + 230, + 128, + 37, + 205, + 4, + 212, + 91, + 141, + 46, + 250, + 0, + 126, + 227, + 75, + 186, + 153, + 154, + 76, + 208, + 4, + 161, + 233, + 68, + 149, + 14, + 105, + 51, + 64, + 203, + 30, + 101, + 46, + 250, + 173, + 186, + 141, + 212, + 1, + 104, + 61, + 59, + 125, + 84, + 223, + 74, + 36, + 164, + 5, + 176, + 244, + 187, + 170, + 168, + 146, + 156, + 36, + 160, + 11, + 1, + 169, + 115, + 85, + 252, + 202, + 80, + 244, + 1, + 100, + 53, + 46, + 106, + 184, + 122, + 120, + 122, + 0, + 155, + 52, + 185, + 168, + 67, + 211, + 131, + 83, + 16, + 252, + 211, + 129, + 168, + 243, + 64, + 106, + 6, + 73, + 154, + 51, + 76, + 13, + 75, + 154, + 4, + 62, + 146, + 147, + 52, + 102, + 128, + 22, + 129, + 73, + 154, + 1, + 160, + 99, + 168, + 164, + 205, + 58, + 129, + 0, + 164, + 61, + 105, + 65, + 164, + 99, + 205, + 0, + 56, + 83, + 123, + 211, + 135, + 74, + 105, + 235, + 64, + 14, + 166, + 142, + 180, + 189, + 168, + 29, + 104, + 1, + 79, + 74, + 104, + 20, + 227, + 210, + 146, + 128, + 16, + 210, + 80, + 122, + 208, + 41, + 12, + 40, + 29, + 104, + 52, + 10, + 0, + 92, + 211, + 24, + 211, + 141, + 70, + 79, + 52, + 0, + 134, + 154, + 77, + 41, + 52, + 195, + 64, + 131, + 189, + 7, + 165, + 2, + 142, + 180, + 0, + 10, + 119, + 74, + 49, + 72, + 77, + 0, + 33, + 52, + 222, + 166, + 148, + 210, + 168, + 160, + 2, + 150, + 138, + 90, + 0, + 40, + 163, + 52, + 153, + 160, + 66, + 210, + 81, + 69, + 0, + 45, + 38, + 104, + 164, + 235, + 64, + 192, + 154, + 0, + 245, + 165, + 2, + 130, + 113, + 76, + 5, + 233, + 77, + 38, + 147, + 57, + 162, + 144, + 1, + 164, + 205, + 20, + 1, + 64, + 198, + 178, + 110, + 170, + 237, + 17, + 86, + 207, + 106, + 186, + 5, + 46, + 192, + 221, + 104, + 2, + 159, + 24, + 168, + 159, + 173, + 95, + 54, + 234, + 121, + 168, + 154, + 219, + 39, + 138, + 161, + 20, + 128, + 57, + 205, + 56, + 150, + 245, + 53, + 57, + 183, + 101, + 167, + 165, + 179, + 55, + 53, + 37, + 40, + 54, + 83, + 220, + 222, + 181, + 61, + 181, + 201, + 86, + 10, + 221, + 42, + 211, + 89, + 169, + 82, + 49, + 205, + 103, + 75, + 25, + 141, + 202, + 159, + 194, + 128, + 105, + 163, + 104, + 124, + 192, + 17, + 78, + 11, + 138, + 169, + 97, + 56, + 120, + 182, + 158, + 163, + 138, + 180, + 77, + 2, + 3, + 138, + 76, + 81, + 69, + 48, + 19, + 104, + 164, + 34, + 157, + 73, + 72, + 12, + 236, + 211, + 131, + 0, + 42, + 51, + 72, + 104, + 1, + 204, + 71, + 106, + 101, + 20, + 148, + 192, + 51, + 70, + 234, + 67, + 69, + 0, + 46, + 234, + 55, + 83, + 77, + 33, + 160, + 7, + 238, + 163, + 53, + 29, + 38, + 105, + 1, + 38, + 104, + 205, + 71, + 154, + 93, + 212, + 1, + 38, + 104, + 221, + 81, + 238, + 165, + 205, + 0, + 73, + 190, + 151, + 125, + 69, + 154, + 51, + 64, + 19, + 9, + 41, + 194, + 74, + 175, + 154, + 80, + 104, + 2, + 208, + 146, + 156, + 36, + 170, + 129, + 169, + 193, + 205, + 0, + 92, + 18, + 82, + 239, + 170, + 98, + 74, + 112, + 146, + 128, + 45, + 135, + 167, + 7, + 170, + 98, + 74, + 120, + 150, + 128, + 45, + 134, + 163, + 117, + 86, + 18, + 83, + 132, + 148, + 8, + 177, + 186, + 151, + 53, + 95, + 127, + 189, + 40, + 122, + 6, + 88, + 205, + 56, + 30, + 42, + 184, + 122, + 112, + 122, + 98, + 38, + 205, + 33, + 166, + 110, + 160, + 181, + 32, + 37, + 7, + 138, + 66, + 121, + 166, + 134, + 226, + 147, + 119, + 52, + 192, + 147, + 60, + 80, + 180, + 132, + 241, + 66, + 244, + 160, + 7, + 26, + 15, + 74, + 76, + 243, + 72, + 199, + 138, + 0, + 67, + 75, + 208, + 82, + 82, + 147, + 72, + 97, + 214, + 131, + 66, + 243, + 72, + 79, + 52, + 0, + 140, + 105, + 148, + 164, + 210, + 30, + 148, + 0, + 195, + 73, + 74, + 104, + 160, + 65, + 64, + 20, + 80, + 120, + 20, + 0, + 140, + 123, + 82, + 81, + 69, + 0, + 40, + 162, + 138, + 81, + 64, + 11, + 70, + 105, + 51, + 69, + 0, + 20, + 82, + 81, + 154, + 0, + 92, + 210, + 81, + 74, + 40, + 0, + 162, + 130, + 105, + 40, + 0, + 205, + 37, + 24, + 165, + 197, + 0, + 37, + 20, + 224, + 185, + 167, + 170, + 122, + 208, + 49, + 129, + 105, + 225, + 105, + 248, + 20, + 102, + 128, + 16, + 10, + 56, + 163, + 52, + 98, + 128, + 14, + 180, + 160, + 98, + 140, + 82, + 226, + 128, + 16, + 174, + 69, + 75, + 22, + 7, + 20, + 202, + 51, + 233, + 65, + 81, + 149, + 139, + 91, + 21, + 133, + 85, + 158, + 193, + 101, + 52, + 244, + 144, + 173, + 72, + 38, + 205, + 35, + 68, + 251, + 20, + 225, + 176, + 48, + 190, + 65, + 169, + 153, + 8, + 21, + 41, + 157, + 7, + 83, + 81, + 189, + 196, + 126, + 180, + 21, + 107, + 238, + 136, + 139, + 17, + 66, + 182, + 69, + 13, + 34, + 176, + 227, + 165, + 68, + 14, + 27, + 61, + 168, + 184, + 156, + 19, + 216, + 155, + 147, + 64, + 197, + 38, + 105, + 165, + 169, + 152, + 20, + 240, + 49, + 76, + 35, + 52, + 19, + 64, + 52, + 0, + 155, + 105, + 10, + 210, + 150, + 163, + 52, + 0, + 194, + 40, + 197, + 41, + 164, + 160, + 4, + 197, + 33, + 20, + 236, + 210, + 26, + 0, + 110, + 40, + 197, + 20, + 185, + 160, + 6, + 17, + 73, + 74, + 105, + 40, + 0, + 162, + 151, + 20, + 80, + 2, + 102, + 140, + 209, + 73, + 64, + 11, + 154, + 92, + 211, + 104, + 160, + 7, + 102, + 151, + 52, + 202, + 51, + 64, + 18, + 102, + 140, + 211, + 51, + 70, + 104, + 17, + 38, + 234, + 3, + 83, + 51, + 70, + 104, + 25, + 32, + 122, + 112, + 146, + 161, + 205, + 25, + 160, + 9, + 196, + 180, + 225, + 45, + 86, + 205, + 46, + 104, + 17, + 104, + 75, + 79, + 18, + 85, + 45, + 212, + 224, + 244, + 1, + 120, + 73, + 75, + 191, + 53, + 68, + 72, + 105, + 226, + 90, + 0, + 188, + 175, + 75, + 191, + 154, + 166, + 37, + 167, + 9, + 40, + 2, + 222, + 250, + 120, + 108, + 10, + 168, + 36, + 230, + 159, + 230, + 10, + 0, + 177, + 186, + 130, + 213, + 8, + 146, + 147, + 126, + 104, + 2, + 112, + 105, + 73, + 168, + 85, + 169, + 219, + 168, + 25, + 42, + 156, + 10, + 97, + 106, + 105, + 110, + 41, + 3, + 80, + 3, + 179, + 77, + 38, + 130, + 105, + 185, + 160, + 5, + 160, + 243, + 72, + 79, + 20, + 10, + 4, + 56, + 83, + 73, + 205, + 12, + 123, + 83, + 73, + 197, + 0, + 25, + 165, + 166, + 129, + 78, + 160, + 2, + 151, + 52, + 148, + 80, + 2, + 209, + 154, + 76, + 210, + 103, + 52, + 0, + 185, + 160, + 10, + 5, + 25, + 160, + 5, + 163, + 52, + 128, + 19, + 205, + 56, + 10, + 0, + 74, + 80, + 13, + 56, + 10, + 81, + 64, + 8, + 22, + 156, + 22, + 138, + 92, + 208, + 2, + 241, + 70, + 64, + 164, + 205, + 39, + 214, + 129, + 139, + 146, + 104, + 197, + 25, + 163, + 4, + 208, + 1, + 74, + 5, + 20, + 100, + 10, + 0, + 117, + 55, + 52, + 18, + 77, + 37, + 0, + 47, + 214, + 151, + 52, + 153, + 164, + 205, + 0, + 41, + 57, + 163, + 52, + 153, + 166, + 231, + 52, + 0, + 147, + 13, + 195, + 138, + 130, + 220, + 1, + 57, + 73, + 122, + 30, + 149, + 99, + 32, + 84, + 82, + 168, + 111, + 241, + 161, + 104, + 59, + 182, + 93, + 146, + 202, + 54, + 79, + 221, + 146, + 167, + 235, + 84, + 138, + 188, + 124, + 54, + 13, + 42, + 207, + 112, + 139, + 140, + 238, + 30, + 245, + 28, + 146, + 187, + 117, + 171, + 178, + 96, + 164, + 208, + 166, + 82, + 56, + 197, + 48, + 220, + 98, + 153, + 147, + 233, + 77, + 49, + 150, + 228, + 82, + 208, + 45, + 39, + 168, + 210, + 105, + 51, + 75, + 73, + 80, + 32, + 205, + 37, + 20, + 83, + 0, + 162, + 150, + 146, + 128, + 12, + 82, + 17, + 78, + 164, + 52, + 0, + 218, + 67, + 78, + 160, + 142, + 40, + 2, + 58, + 5, + 46, + 40, + 20, + 0, + 80, + 105, + 113, + 73, + 64, + 9, + 69, + 46, + 40, + 197, + 0, + 54, + 146, + 156, + 69, + 37, + 0, + 38, + 40, + 197, + 45, + 20, + 0, + 148, + 82, + 226, + 140, + 80, + 3, + 105, + 104, + 162, + 128, + 12, + 209, + 154, + 40, + 160, + 3, + 52, + 185, + 166, + 209, + 64, + 14, + 205, + 25, + 166, + 210, + 208, + 2, + 230, + 148, + 26, + 110, + 104, + 205, + 0, + 72, + 13, + 40, + 106, + 143, + 52, + 185, + 160, + 68, + 161, + 141, + 59, + 204, + 53, + 14, + 104, + 205, + 0, + 79, + 230, + 82, + 137, + 42, + 12, + 209, + 154, + 6, + 90, + 18, + 251, + 211, + 132, + 158, + 245, + 83, + 117, + 46, + 234, + 0, + 183, + 190, + 148, + 61, + 84, + 13, + 75, + 190, + 129, + 22, + 183, + 210, + 131, + 85, + 119, + 211, + 188, + 202, + 6, + 88, + 13, + 147, + 75, + 187, + 21, + 2, + 189, + 59, + 125, + 0, + 73, + 158, + 244, + 148, + 205, + 249, + 167, + 3, + 64, + 15, + 20, + 102, + 155, + 186, + 147, + 52, + 8, + 126, + 104, + 206, + 41, + 185, + 164, + 201, + 38, + 128, + 23, + 57, + 167, + 1, + 72, + 56, + 165, + 28, + 208, + 3, + 168, + 3, + 214, + 147, + 112, + 20, + 110, + 160, + 99, + 233, + 105, + 180, + 185, + 160, + 7, + 10, + 90, + 102, + 113, + 73, + 147, + 64, + 15, + 38, + 138, + 109, + 40, + 160, + 7, + 81, + 140, + 209, + 70, + 104, + 1, + 104, + 205, + 38, + 105, + 40, + 1, + 73, + 205, + 2, + 146, + 130, + 212, + 0, + 185, + 163, + 52, + 220, + 209, + 154, + 0, + 113, + 52, + 220, + 210, + 82, + 80, + 3, + 179, + 73, + 187, + 210, + 147, + 25, + 165, + 2, + 128, + 27, + 131, + 78, + 197, + 46, + 40, + 160, + 4, + 197, + 5, + 70, + 58, + 82, + 224, + 154, + 92, + 80, + 2, + 219, + 198, + 164, + 242, + 42, + 219, + 90, + 161, + 31, + 47, + 6, + 170, + 3, + 138, + 179, + 20, + 248, + 24, + 106, + 70, + 188, + 215, + 90, + 24, + 152, + 163, + 20, + 180, + 26, + 102, + 66, + 98, + 147, + 20, + 185, + 164, + 205, + 0, + 24, + 162, + 140, + 209, + 64, + 9, + 69, + 45, + 20, + 0, + 148, + 134, + 150, + 138, + 0, + 105, + 20, + 218, + 147, + 20, + 210, + 40, + 0, + 83, + 65, + 2, + 155, + 74, + 40, + 0, + 197, + 4, + 98, + 156, + 40, + 52, + 0, + 218, + 76, + 83, + 177, + 70, + 40, + 1, + 184, + 164, + 197, + 59, + 20, + 184, + 160, + 6, + 80, + 105, + 77, + 20, + 0, + 218, + 41, + 113, + 69, + 0, + 37, + 37, + 45, + 37, + 0, + 20, + 82, + 226, + 140, + 80, + 2, + 81, + 75, + 69, + 0, + 54, + 138, + 90, + 40, + 1, + 41, + 105, + 113, + 73, + 64, + 6, + 104, + 205, + 20, + 98, + 128, + 12, + 210, + 230, + 146, + 146, + 128, + 31, + 154, + 51, + 76, + 165, + 160, + 7, + 230, + 140, + 211, + 51, + 70, + 104, + 1, + 249, + 165, + 13, + 81, + 230, + 151, + 52, + 1, + 46, + 234, + 55, + 212, + 89, + 163, + 52, + 1, + 48, + 122, + 112, + 144, + 212, + 25, + 165, + 205, + 2, + 44, + 9, + 41, + 67, + 138, + 173, + 186, + 148, + 53, + 0, + 90, + 15, + 154, + 118, + 225, + 85, + 55, + 210, + 239, + 52, + 1, + 103, + 117, + 27, + 170, + 0, + 244, + 224, + 244, + 12, + 155, + 117, + 40, + 53, + 14, + 250, + 55, + 208, + 5, + 141, + 254, + 244, + 190, + 103, + 165, + 86, + 221, + 78, + 221, + 64, + 19, + 230, + 157, + 154, + 128, + 61, + 56, + 61, + 0, + 76, + 41, + 217, + 168, + 60, + 202, + 93, + 244, + 1, + 46, + 105, + 115, + 81, + 110, + 165, + 6, + 128, + 31, + 156, + 209, + 154, + 110, + 105, + 104, + 1, + 104, + 164, + 205, + 25, + 160, + 5, + 205, + 37, + 37, + 40, + 20, + 0, + 180, + 119, + 162, + 140, + 226, + 128, + 23, + 20, + 82, + 82, + 208, + 1, + 74, + 5, + 37, + 45, + 0, + 45, + 20, + 82, + 226, + 128, + 18, + 148, + 113, + 69, + 37, + 0, + 102, + 102, + 140, + 210, + 81, + 64, + 5, + 20, + 81, + 64, + 9, + 69, + 20, + 80, + 1, + 154, + 51, + 69, + 20, + 0, + 81, + 69, + 20, + 0, + 185, + 164, + 52, + 81, + 138, + 0, + 109, + 40, + 163, + 20, + 80, + 2, + 138, + 90, + 74, + 40, + 0, + 162, + 150, + 146, + 128, + 18, + 138, + 13, + 37, + 0, + 20, + 148, + 81, + 64, + 1, + 164, + 165, + 164, + 160, + 4, + 165, + 3, + 52, + 83, + 150, + 128, + 19, + 20, + 148, + 243, + 77, + 197, + 0, + 20, + 152, + 167, + 98, + 140, + 80, + 3, + 49, + 69, + 56, + 138, + 109, + 0, + 20, + 98, + 138, + 90, + 0, + 76, + 81, + 75, + 138, + 40, + 1, + 40, + 197, + 45, + 20, + 0, + 218, + 49, + 78, + 197, + 37, + 0, + 38, + 40, + 197, + 45, + 24, + 160, + 4, + 162, + 151, + 20, + 98, + 128, + 27, + 75, + 75, + 138, + 76, + 80, + 1, + 70, + 104, + 162, + 128, + 12, + 210, + 230, + 155, + 69, + 0, + 59, + 52, + 185, + 166, + 82, + 208, + 3, + 247, + 82, + 238, + 168, + 232, + 205, + 0, + 73, + 154, + 112, + 53, + 14, + 105, + 119, + 80, + 4, + 185, + 167, + 3, + 80, + 238, + 165, + 221, + 64, + 18, + 238, + 167, + 110, + 168, + 119, + 81, + 190, + 129, + 19, + 239, + 165, + 15, + 85, + 247, + 81, + 186, + 129, + 150, + 131, + 138, + 112, + 122, + 167, + 188, + 210, + 135, + 52, + 1, + 112, + 61, + 47, + 152, + 42, + 160, + 115, + 78, + 18, + 80, + 5, + 173, + 212, + 160, + 213, + 97, + 37, + 60, + 73, + 239, + 64, + 22, + 5, + 46, + 106, + 0, + 227, + 214, + 148, + 73, + 233, + 64, + 19, + 102, + 138, + 136, + 62, + 105, + 226, + 128, + 31, + 69, + 38, + 69, + 46, + 234, + 96, + 59, + 20, + 188, + 83, + 55, + 81, + 147, + 64, + 15, + 205, + 38, + 105, + 180, + 102, + 128, + 29, + 146, + 122, + 10, + 79, + 169, + 164, + 205, + 46, + 40, + 3, + 54, + 138, + 90, + 74, + 64, + 20, + 81, + 69, + 0, + 20, + 81, + 74, + 5, + 0, + 38, + 41, + 113, + 78, + 2, + 151, + 20, + 0, + 221, + 185, + 160, + 47, + 173, + 60, + 10, + 13, + 0, + 51, + 20, + 109, + 167, + 98, + 151, + 20, + 1, + 25, + 90, + 77, + 166, + 164, + 163, + 20, + 1, + 17, + 20, + 84, + 165, + 105, + 187, + 115, + 64, + 12, + 162, + 159, + 178, + 154, + 84, + 138, + 0, + 109, + 24, + 162, + 150, + 128, + 19, + 20, + 152, + 167, + 138, + 49, + 64, + 12, + 197, + 38, + 42, + 77, + 180, + 190, + 94, + 122, + 26, + 0, + 139, + 20, + 229, + 20, + 237, + 148, + 109, + 34, + 128, + 19, + 20, + 98, + 164, + 85, + 207, + 74, + 93, + 180, + 1, + 22, + 40, + 197, + 76, + 83, + 142, + 105, + 152, + 197, + 2, + 35, + 52, + 211, + 82, + 17, + 154, + 110, + 218, + 6, + 51, + 20, + 83, + 241, + 73, + 138, + 0, + 5, + 33, + 20, + 184, + 165, + 20, + 128, + 76, + 80, + 69, + 56, + 12, + 210, + 149, + 226, + 152, + 12, + 2, + 140, + 84, + 138, + 51, + 74, + 83, + 61, + 40, + 2, + 44, + 82, + 133, + 6, + 164, + 85, + 193, + 228, + 83, + 138, + 103, + 154, + 4, + 67, + 182, + 147, + 21, + 57, + 92, + 10, + 105, + 90, + 0, + 139, + 109, + 33, + 21, + 54, + 195, + 138, + 97, + 90, + 6, + 69, + 138, + 92, + 83, + 246, + 211, + 130, + 113, + 64, + 16, + 226, + 147, + 21, + 49, + 90, + 54, + 80, + 34, + 26, + 42, + 66, + 148, + 220, + 80, + 49, + 184, + 163, + 20, + 236, + 81, + 138, + 0, + 110, + 40, + 197, + 63, + 20, + 160, + 80, + 4, + 116, + 84, + 187, + 65, + 163, + 101, + 0, + 69, + 69, + 60, + 165, + 38, + 202, + 0, + 110, + 104, + 205, + 46, + 211, + 73, + 180, + 208, + 1, + 154, + 92, + 210, + 96, + 210, + 80, + 3, + 247, + 82, + 238, + 168, + 232, + 160, + 9, + 119, + 81, + 186, + 162, + 165, + 205, + 0, + 74, + 26, + 156, + 31, + 21, + 6, + 104, + 220, + 104, + 2, + 200, + 152, + 138, + 81, + 63, + 174, + 106, + 182, + 234, + 55, + 80, + 5, + 193, + 61, + 40, + 153, + 125, + 106, + 158, + 234, + 3, + 80, + 5, + 241, + 40, + 167, + 9, + 1, + 239, + 89, + 225, + 169, + 194, + 66, + 58, + 26, + 0, + 208, + 7, + 52, + 241, + 129, + 212, + 214, + 112, + 149, + 255, + 0, + 189, + 78, + 23, + 12, + 58, + 80, + 6, + 134, + 71, + 108, + 81, + 154, + 162, + 46, + 143, + 112, + 105, + 226, + 235, + 212, + 145, + 64, + 16, + 209, + 69, + 20, + 0, + 81, + 75, + 138, + 80, + 40, + 0, + 2, + 151, + 20, + 82, + 226, + 128, + 16, + 82, + 226, + 148, + 10, + 90, + 0, + 65, + 70, + 41, + 113, + 78, + 81, + 154, + 0, + 102, + 40, + 197, + 72, + 20, + 131, + 200, + 167, + 4, + 207, + 74, + 4, + 68, + 22, + 156, + 20, + 131, + 210, + 164, + 9, + 159, + 106, + 112, + 66, + 58, + 242, + 40, + 2, + 45, + 185, + 228, + 82, + 21, + 252, + 42, + 113, + 16, + 7, + 57, + 165, + 49, + 43, + 0, + 121, + 205, + 0, + 86, + 35, + 29, + 105, + 54, + 102, + 173, + 42, + 1, + 195, + 12, + 138, + 99, + 197, + 142, + 87, + 183, + 106, + 0, + 172, + 209, + 122, + 84, + 108, + 164, + 28, + 17, + 86, + 192, + 207, + 4, + 98, + 134, + 140, + 227, + 145, + 145, + 64, + 20, + 241, + 74, + 42, + 82, + 189, + 197, + 38, + 40, + 24, + 139, + 205, + 72, + 19, + 34, + 145, + 87, + 154, + 157, + 70, + 70, + 59, + 208, + 34, + 185, + 86, + 7, + 145, + 82, + 44, + 109, + 212, + 98, + 167, + 80, + 113, + 200, + 167, + 4, + 83, + 200, + 52, + 1, + 92, + 41, + 207, + 60, + 26, + 118, + 56, + 228, + 228, + 84, + 254, + 82, + 158, + 185, + 165, + 88, + 130, + 244, + 230, + 152, + 16, + 36, + 106, + 71, + 77, + 194, + 145, + 237, + 129, + 63, + 40, + 252, + 42, + 206, + 0, + 57, + 65, + 131, + 78, + 228, + 143, + 152, + 99, + 222, + 139, + 1, + 156, + 96, + 113, + 198, + 204, + 123, + 210, + 27, + 121, + 113, + 194, + 230, + 180, + 88, + 28, + 122, + 251, + 83, + 20, + 140, + 245, + 160, + 12, + 243, + 19, + 255, + 0, + 118, + 147, + 103, + 168, + 173, + 22, + 68, + 110, + 163, + 6, + 161, + 104, + 121, + 228, + 100, + 122, + 210, + 2, + 145, + 90, + 54, + 85, + 179, + 26, + 142, + 212, + 194, + 128, + 30, + 40, + 25, + 92, + 3, + 82, + 162, + 83, + 246, + 110, + 232, + 106, + 72, + 227, + 35, + 169, + 252, + 168, + 1, + 133, + 9, + 31, + 119, + 241, + 164, + 242, + 88, + 115, + 144, + 69, + 91, + 10, + 0, + 192, + 52, + 129, + 121, + 226, + 152, + 138, + 202, + 138, + 79, + 244, + 167, + 52, + 64, + 253, + 213, + 199, + 210, + 172, + 50, + 17, + 252, + 31, + 136, + 160, + 131, + 140, + 142, + 148, + 1, + 92, + 167, + 24, + 52, + 198, + 32, + 13, + 180, + 242, + 75, + 103, + 28, + 84, + 123, + 79, + 122, + 6, + 48, + 211, + 74, + 212, + 187, + 9, + 233, + 79, + 72, + 115, + 157, + 199, + 240, + 160, + 8, + 22, + 61, + 222, + 212, + 255, + 0, + 40, + 127, + 123, + 53, + 58, + 109, + 7, + 0, + 83, + 138, + 131, + 212, + 98, + 129, + 21, + 76, + 100, + 159, + 148, + 126, + 116, + 155, + 8, + 225, + 134, + 42, + 210, + 198, + 1, + 228, + 230, + 134, + 69, + 206, + 49, + 145, + 239, + 64, + 21, + 74, + 119, + 164, + 242, + 131, + 115, + 147, + 86, + 152, + 42, + 253, + 209, + 138, + 140, + 224, + 115, + 72, + 8, + 76, + 4, + 143, + 148, + 31, + 198, + 154, + 97, + 112, + 50, + 203, + 129, + 235, + 86, + 87, + 6, + 158, + 67, + 145, + 128, + 163, + 31, + 90, + 96, + 81, + 219, + 218, + 141, + 181, + 113, + 226, + 82, + 159, + 195, + 159, + 106, + 132, + 196, + 223, + 195, + 243, + 123, + 82, + 25, + 14, + 49, + 74, + 58, + 243, + 210, + 165, + 242, + 159, + 25, + 101, + 219, + 245, + 166, + 99, + 214, + 128, + 2, + 3, + 30, + 56, + 160, + 197, + 142, + 167, + 63, + 74, + 49, + 74, + 164, + 175, + 67, + 64, + 12, + 242, + 206, + 122, + 99, + 235, + 65, + 136, + 142, + 184, + 252, + 42, + 98, + 225, + 254, + 247, + 90, + 80, + 85, + 184, + 166, + 34, + 182, + 206, + 105, + 193, + 20, + 241, + 142, + 106, + 103, + 141, + 71, + 1, + 178, + 105, + 86, + 54, + 3, + 56, + 11, + 64, + 202, + 230, + 46, + 51, + 180, + 143, + 173, + 55, + 203, + 207, + 74, + 178, + 120, + 61, + 115, + 77, + 145, + 193, + 198, + 209, + 131, + 64, + 21, + 74, + 81, + 229, + 228, + 84, + 164, + 82, + 162, + 130, + 121, + 206, + 61, + 169, + 1, + 1, + 67, + 73, + 138, + 180, + 209, + 131, + 247, + 120, + 250, + 212, + 102, + 50, + 78, + 0, + 160, + 8, + 113, + 70, + 41, + 228, + 96, + 224, + 209, + 182, + 128, + 25, + 73, + 79, + 218, + 71, + 81, + 138, + 49, + 64, + 12, + 165, + 167, + 109, + 163, + 109, + 0, + 55, + 52, + 102, + 151, + 109, + 38, + 40, + 1, + 115, + 70, + 234, + 76, + 81, + 138, + 0, + 178, + 5, + 40, + 90, + 114, + 173, + 72, + 171, + 147, + 64, + 13, + 88, + 201, + 237, + 79, + 242, + 137, + 28, + 26, + 153, + 23, + 21, + 38, + 206, + 244, + 8, + 167, + 179, + 156, + 26, + 81, + 30, + 42, + 217, + 136, + 17, + 158, + 244, + 221, + 184, + 56, + 52, + 236, + 4, + 34, + 60, + 210, + 133, + 245, + 21, + 46, + 220, + 116, + 20, + 161, + 115, + 72, + 8, + 246, + 17, + 200, + 20, + 1, + 147, + 83, + 40, + 35, + 173, + 43, + 71, + 200, + 34, + 152, + 17, + 109, + 207, + 90, + 112, + 140, + 131, + 198, + 13, + 74, + 34, + 207, + 6, + 147, + 105, + 83, + 235, + 64, + 13, + 49, + 231, + 4, + 112, + 104, + 85, + 3, + 131, + 82, + 133, + 200, + 226, + 129, + 131, + 212, + 114, + 40, + 1, + 133, + 48, + 55, + 45, + 3, + 147, + 192, + 169, + 240, + 7, + 65, + 72, + 16, + 246, + 166, + 3, + 0, + 33, + 112, + 86, + 154, + 209, + 19, + 202, + 99, + 233, + 86, + 62, + 180, + 210, + 187, + 79, + 20, + 1, + 88, + 197, + 187, + 131, + 193, + 160, + 38, + 222, + 181, + 100, + 128, + 227, + 220, + 83, + 72, + 219, + 212, + 100, + 82, + 2, + 163, + 219, + 130, + 73, + 67, + 248, + 84, + 5, + 118, + 182, + 8, + 193, + 173, + 32, + 128, + 125, + 209, + 74, + 209, + 164, + 131, + 230, + 94, + 104, + 3, + 61, + 69, + 72, + 160, + 103, + 154, + 115, + 69, + 181, + 182, + 159, + 192, + 210, + 136, + 246, + 251, + 208, + 49, + 203, + 25, + 60, + 245, + 20, + 255, + 0, + 37, + 122, + 130, + 71, + 181, + 73, + 22, + 7, + 227, + 74, + 192, + 30, + 148, + 8, + 132, + 12, + 28, + 48, + 228, + 83, + 182, + 19, + 247, + 106, + 78, + 15, + 222, + 28, + 208, + 85, + 147, + 145, + 200, + 160, + 8, + 204, + 36, + 243, + 158, + 105, + 216, + 227, + 6, + 159, + 156, + 138, + 137, + 139, + 2, + 104, + 1, + 192, + 1, + 77, + 114, + 131, + 156, + 12, + 212, + 126, + 97, + 106, + 105, + 1, + 186, + 154, + 0, + 25, + 134, + 105, + 133, + 179, + 74, + 87, + 3, + 173, + 38, + 5, + 3, + 27, + 130, + 77, + 52, + 173, + 72, + 160, + 83, + 188, + 160, + 123, + 156, + 80, + 4, + 75, + 193, + 167, + 100, + 131, + 197, + 73, + 246, + 96, + 57, + 70, + 39, + 216, + 209, + 229, + 51, + 28, + 99, + 20, + 0, + 198, + 57, + 226, + 145, + 88, + 169, + 20, + 243, + 4, + 138, + 62, + 108, + 99, + 212, + 82, + 152, + 14, + 220, + 238, + 6, + 128, + 20, + 205, + 198, + 48, + 106, + 51, + 33, + 60, + 98, + 155, + 223, + 25, + 231, + 210, + 148, + 174, + 6, + 72, + 34, + 128, + 27, + 182, + 128, + 189, + 169, + 249, + 226, + 152, + 71, + 52, + 128, + 145, + 32, + 92, + 103, + 113, + 250, + 83, + 182, + 237, + 224, + 45, + 68, + 11, + 118, + 98, + 42, + 69, + 155, + 3, + 4, + 26, + 96, + 60, + 163, + 109, + 237, + 138, + 140, + 143, + 194, + 156, + 36, + 220, + 112, + 122, + 83, + 129, + 80, + 221, + 65, + 160, + 67, + 23, + 7, + 168, + 252, + 105, + 78, + 112, + 70, + 120, + 167, + 121, + 101, + 185, + 86, + 3, + 218, + 155, + 142, + 126, + 108, + 208, + 4, + 123, + 65, + 228, + 208, + 0, + 207, + 3, + 20, + 227, + 215, + 138, + 81, + 19, + 147, + 157, + 202, + 40, + 1, + 143, + 31, + 28, + 224, + 125, + 41, + 84, + 46, + 222, + 73, + 167, + 16, + 7, + 4, + 146, + 105, + 60, + 183, + 110, + 49, + 129, + 235, + 64, + 9, + 193, + 29, + 63, + 58, + 69, + 136, + 131, + 184, + 56, + 247, + 24, + 167, + 178, + 149, + 31, + 49, + 7, + 233, + 76, + 235, + 192, + 4, + 226, + 128, + 6, + 59, + 142, + 58, + 147, + 72, + 99, + 11, + 213, + 113, + 82, + 4, + 118, + 25, + 82, + 23, + 235, + 77, + 127, + 66, + 104, + 2, + 35, + 18, + 30, + 115, + 249, + 84, + 126, + 75, + 103, + 10, + 15, + 53, + 97, + 75, + 39, + 240, + 126, + 52, + 52, + 133, + 65, + 201, + 164, + 5, + 115, + 19, + 171, + 109, + 32, + 103, + 218, + 153, + 180, + 231, + 161, + 63, + 74, + 121, + 102, + 39, + 36, + 210, + 198, + 223, + 62, + 115, + 138, + 6, + 69, + 140, + 118, + 197, + 1, + 201, + 24, + 221, + 86, + 153, + 98, + 56, + 222, + 9, + 111, + 106, + 26, + 53, + 101, + 229, + 66, + 251, + 208, + 5, + 77, + 180, + 5, + 45, + 192, + 4, + 212, + 206, + 129, + 23, + 33, + 183, + 10, + 95, + 52, + 21, + 192, + 24, + 62, + 180, + 1, + 8, + 136, + 247, + 227, + 218, + 165, + 216, + 241, + 167, + 32, + 5, + 61, + 233, + 86, + 93, + 189, + 84, + 100, + 119, + 164, + 89, + 20, + 185, + 50, + 130, + 104, + 0, + 27, + 79, + 33, + 73, + 247, + 166, + 237, + 94, + 167, + 39, + 29, + 133, + 56, + 186, + 179, + 99, + 36, + 39, + 181, + 72, + 21, + 148, + 145, + 8, + 3, + 212, + 181, + 0, + 66, + 202, + 28, + 114, + 2, + 168, + 168, + 74, + 16, + 51, + 142, + 42, + 209, + 76, + 54, + 0, + 44, + 253, + 233, + 172, + 14, + 127, + 123, + 249, + 10, + 0, + 175, + 214, + 144, + 174, + 49, + 206, + 106, + 207, + 148, + 178, + 13, + 216, + 84, + 81, + 211, + 21, + 23, + 150, + 78, + 72, + 25, + 3, + 189, + 0, + 68, + 69, + 38, + 42, + 78, + 71, + 61, + 40, + 52, + 1, + 30, + 41, + 164, + 83, + 205, + 24, + 160, + 6, + 98, + 140, + 83, + 177, + 74, + 171, + 154, + 0, + 180, + 22, + 165, + 142, + 51, + 78, + 68, + 201, + 169, + 214, + 50, + 41, + 128, + 44, + 124, + 117, + 169, + 21, + 7, + 122, + 2, + 241, + 214, + 156, + 41, + 136, + 105, + 92, + 30, + 40, + 218, + 24, + 116, + 169, + 0, + 245, + 163, + 110, + 57, + 20, + 1, + 14, + 54, + 156, + 83, + 177, + 232, + 42, + 92, + 6, + 20, + 152, + 218, + 104, + 1, + 138, + 51, + 71, + 151, + 143, + 165, + 61, + 151, + 184, + 160, + 28, + 245, + 226, + 128, + 26, + 23, + 158, + 180, + 237, + 160, + 240, + 105, + 8, + 32, + 245, + 165, + 200, + 34, + 128, + 27, + 179, + 105, + 224, + 241, + 78, + 42, + 15, + 56, + 230, + 148, + 17, + 208, + 211, + 198, + 59, + 82, + 2, + 28, + 149, + 59, + 72, + 167, + 138, + 121, + 195, + 112, + 105, + 188, + 138, + 0, + 5, + 33, + 227, + 173, + 59, + 131, + 222, + 140, + 250, + 208, + 3, + 112, + 185, + 200, + 52, + 225, + 130, + 48, + 105, + 10, + 103, + 165, + 52, + 49, + 7, + 4, + 80, + 2, + 149, + 218, + 114, + 180, + 236, + 2, + 41, + 172, + 91, + 210, + 133, + 203, + 15, + 122, + 0, + 141, + 212, + 129, + 134, + 25, + 30, + 180, + 205, + 190, + 134, + 172, + 158, + 7, + 205, + 80, + 50, + 224, + 252, + 163, + 35, + 218, + 152, + 4, + 106, + 195, + 210, + 166, + 35, + 112, + 207, + 67, + 80, + 161, + 203, + 99, + 161, + 169, + 198, + 113, + 235, + 72, + 6, + 131, + 216, + 138, + 81, + 156, + 83, + 179, + 158, + 13, + 48, + 144, + 58, + 80, + 3, + 25, + 128, + 205, + 51, + 120, + 45, + 232, + 105, + 204, + 65, + 60, + 210, + 50, + 130, + 189, + 63, + 26, + 0, + 107, + 70, + 173, + 200, + 224, + 212, + 91, + 31, + 56, + 219, + 248, + 212, + 225, + 88, + 244, + 25, + 169, + 16, + 99, + 130, + 104, + 2, + 37, + 132, + 227, + 231, + 193, + 20, + 191, + 102, + 67, + 200, + 39, + 233, + 83, + 48, + 3, + 154, + 77, + 195, + 176, + 52, + 1, + 25, + 137, + 7, + 85, + 230, + 149, + 120, + 198, + 41, + 228, + 228, + 114, + 42, + 50, + 141, + 156, + 169, + 160, + 7, + 158, + 123, + 96, + 210, + 5, + 231, + 45, + 64, + 4, + 240, + 212, + 125, + 223, + 113, + 64, + 14, + 36, + 99, + 174, + 106, + 34, + 6, + 120, + 24, + 53, + 38, + 213, + 60, + 175, + 6, + 130, + 72, + 224, + 129, + 249, + 80, + 3, + 54, + 142, + 232, + 51, + 65, + 25, + 92, + 46, + 62, + 148, + 243, + 156, + 117, + 226, + 155, + 176, + 30, + 173, + 131, + 64, + 16, + 125, + 152, + 183, + 42, + 216, + 246, + 197, + 66, + 200, + 200, + 112, + 213, + 112, + 54, + 211, + 200, + 205, + 46, + 65, + 232, + 50, + 40, + 2, + 144, + 247, + 165, + 32, + 118, + 169, + 158, + 220, + 185, + 202, + 28, + 31, + 74, + 134, + 68, + 104, + 200, + 221, + 210, + 144, + 198, + 209, + 154, + 92, + 3, + 72, + 87, + 154, + 0, + 114, + 200, + 203, + 208, + 212, + 139, + 48, + 35, + 7, + 131, + 80, + 80, + 56, + 52, + 1, + 51, + 38, + 91, + 32, + 226, + 164, + 1, + 118, + 243, + 218, + 160, + 220, + 123, + 26, + 124, + 114, + 168, + 63, + 53, + 49, + 11, + 131, + 191, + 129, + 79, + 96, + 196, + 112, + 216, + 164, + 97, + 188, + 102, + 50, + 40, + 85, + 0, + 97, + 207, + 229, + 64, + 13, + 1, + 27, + 140, + 157, + 223, + 90, + 104, + 18, + 198, + 79, + 203, + 242, + 250, + 138, + 113, + 218, + 167, + 228, + 25, + 167, + 229, + 153, + 49, + 145, + 143, + 122, + 0, + 133, + 139, + 55, + 57, + 207, + 176, + 164, + 13, + 216, + 41, + 207, + 189, + 74, + 60, + 180, + 231, + 146, + 212, + 143, + 190, + 78, + 113, + 192, + 160, + 6, + 59, + 184, + 79, + 152, + 243, + 233, + 85, + 219, + 230, + 230, + 159, + 46, + 73, + 35, + 176, + 168, + 199, + 6, + 144, + 198, + 129, + 154, + 149, + 33, + 92, + 101, + 152, + 147, + 237, + 79, + 22, + 234, + 169, + 184, + 185, + 207, + 165, + 57, + 79, + 31, + 42, + 17, + 239, + 64, + 11, + 181, + 143, + 240, + 128, + 61, + 106, + 50, + 170, + 8, + 220, + 219, + 190, + 148, + 246, + 12, + 7, + 206, + 220, + 123, + 82, + 40, + 39, + 148, + 76, + 123, + 154, + 98, + 20, + 161, + 100, + 33, + 84, + 1, + 250, + 213, + 76, + 114, + 71, + 165, + 93, + 216, + 1, + 203, + 49, + 111, + 97, + 73, + 247, + 129, + 1, + 0, + 30, + 167, + 173, + 32, + 41, + 208, + 69, + 78, + 246, + 227, + 105, + 216, + 249, + 111, + 74, + 132, + 130, + 14, + 24, + 96, + 251, + 208, + 49, + 167, + 167, + 53, + 40, + 92, + 40, + 50, + 183, + 30, + 149, + 30, + 42, + 80, + 217, + 69, + 80, + 9, + 110, + 148, + 0, + 226, + 206, + 192, + 5, + 27, + 23, + 212, + 212, + 108, + 155, + 142, + 21, + 137, + 35, + 185, + 169, + 72, + 0, + 15, + 53, + 179, + 254, + 205, + 46, + 9, + 28, + 97, + 19, + 222, + 128, + 42, + 82, + 228, + 129, + 193, + 198, + 122, + 211, + 156, + 46, + 236, + 168, + 33, + 71, + 20, + 210, + 40, + 0, + 221, + 129, + 142, + 212, + 246, + 141, + 54, + 239, + 251, + 163, + 29, + 61, + 106, + 44, + 22, + 59, + 64, + 201, + 171, + 8, + 21, + 122, + 229, + 136, + 233, + 232, + 40, + 2, + 22, + 140, + 99, + 112, + 224, + 30, + 213, + 30, + 218, + 178, + 120, + 147, + 156, + 51, + 118, + 29, + 170, + 41, + 0, + 15, + 199, + 92, + 115, + 64, + 17, + 237, + 193, + 230, + 151, + 56, + 167, + 2, + 51, + 146, + 51, + 67, + 38, + 56, + 7, + 62, + 166, + 128, + 52, + 80, + 84, + 224, + 102, + 161, + 78, + 181, + 97, + 65, + 21, + 66, + 0, + 164, + 123, + 138, + 8, + 167, + 81, + 138, + 0, + 104, + 60, + 210, + 150, + 226, + 148, + 40, + 235, + 138, + 118, + 6, + 48, + 105, + 0, + 204, + 250, + 83, + 179, + 145, + 77, + 35, + 109, + 3, + 52, + 0, + 163, + 32, + 244, + 165, + 49, + 238, + 28, + 80, + 15, + 173, + 60, + 26, + 0, + 104, + 24, + 63, + 53, + 33, + 65, + 156, + 138, + 123, + 115, + 70, + 40, + 1, + 187, + 70, + 58, + 102, + 147, + 238, + 158, + 58, + 83, + 241, + 233, + 70, + 120, + 160, + 4, + 24, + 52, + 26, + 66, + 10, + 156, + 142, + 148, + 236, + 230, + 128, + 26, + 83, + 184, + 160, + 1, + 208, + 210, + 242, + 40, + 192, + 34, + 128, + 20, + 12, + 116, + 165, + 235, + 76, + 201, + 83, + 207, + 74, + 119, + 81, + 197, + 0, + 20, + 155, + 115, + 210, + 150, + 151, + 189, + 0, + 48, + 145, + 222, + 153, + 183, + 186, + 156, + 212, + 216, + 7, + 168, + 164, + 32, + 14, + 69, + 0, + 67, + 128, + 88, + 100, + 115, + 82, + 128, + 71, + 74, + 92, + 231, + 181, + 28, + 131, + 64, + 13, + 96, + 77, + 68, + 192, + 158, + 149, + 59, + 114, + 42, + 50, + 188, + 231, + 173, + 0, + 66, + 65, + 199, + 52, + 228, + 7, + 56, + 235, + 78, + 242, + 137, + 229, + 79, + 224, + 105, + 200, + 172, + 56, + 35, + 20, + 0, + 187, + 50, + 56, + 226, + 141, + 189, + 143, + 90, + 95, + 152, + 82, + 131, + 158, + 15, + 90, + 0, + 136, + 252, + 167, + 173, + 57, + 72, + 110, + 148, + 243, + 142, + 252, + 211, + 72, + 83, + 208, + 98, + 128, + 6, + 56, + 166, + 210, + 225, + 186, + 19, + 70, + 195, + 234, + 49, + 64, + 9, + 156, + 31, + 155, + 243, + 164, + 97, + 198, + 84, + 230, + 159, + 181, + 69, + 48, + 237, + 29, + 51, + 64, + 8, + 9, + 60, + 98, + 148, + 150, + 252, + 40, + 7, + 52, + 29, + 223, + 133, + 0, + 40, + 0, + 142, + 180, + 16, + 160, + 83, + 8, + 25, + 206, + 72, + 160, + 63, + 175, + 52, + 0, + 224, + 222, + 212, + 125, + 48, + 41, + 1, + 61, + 168, + 41, + 187, + 189, + 0, + 33, + 124, + 54, + 15, + 233, + 75, + 149, + 97, + 207, + 205, + 76, + 101, + 10, + 121, + 230, + 148, + 31, + 238, + 228, + 208, + 4, + 18, + 198, + 51, + 149, + 226, + 163, + 53, + 101, + 129, + 144, + 115, + 193, + 237, + 80, + 188, + 50, + 40, + 201, + 193, + 250, + 80, + 3, + 58, + 210, + 98, + 133, + 235, + 205, + 43, + 41, + 28, + 246, + 164, + 49, + 49, + 138, + 76, + 211, + 199, + 78, + 105, + 184, + 20, + 0, + 35, + 21, + 60, + 84, + 233, + 40, + 35, + 230, + 21, + 95, + 161, + 165, + 205, + 1, + 98, + 125, + 165, + 254, + 233, + 20, + 190, + 88, + 3, + 231, + 110, + 125, + 170, + 5, + 145, + 148, + 96, + 84, + 177, + 144, + 195, + 47, + 205, + 49, + 6, + 236, + 125, + 212, + 220, + 62, + 148, + 141, + 159, + 92, + 122, + 138, + 151, + 126, + 56, + 141, + 106, + 38, + 206, + 114, + 253, + 104, + 2, + 6, + 251, + 198, + 152, + 7, + 204, + 1, + 227, + 222, + 156, + 79, + 204, + 113, + 66, + 161, + 119, + 199, + 64, + 58, + 210, + 25, + 96, + 34, + 162, + 142, + 174, + 105, + 126, + 118, + 24, + 24, + 81, + 233, + 72, + 172, + 7, + 202, + 131, + 7, + 214, + 148, + 163, + 30, + 101, + 108, + 125, + 41, + 136, + 104, + 10, + 135, + 131, + 185, + 141, + 12, + 36, + 63, + 120, + 109, + 30, + 212, + 133, + 206, + 112, + 131, + 61, + 179, + 79, + 25, + 85, + 38, + 71, + 200, + 244, + 52, + 1, + 24, + 96, + 56, + 141, + 115, + 239, + 75, + 34, + 182, + 3, + 72, + 195, + 3, + 210, + 140, + 238, + 111, + 220, + 174, + 208, + 41, + 101, + 104, + 193, + 27, + 185, + 97, + 216, + 82, + 1, + 170, + 236, + 231, + 8, + 56, + 245, + 166, + 179, + 41, + 202, + 182, + 29, + 187, + 84, + 152, + 46, + 191, + 63, + 200, + 190, + 162, + 163, + 24, + 13, + 132, + 27, + 135, + 77, + 216, + 160, + 8, + 10, + 178, + 144, + 24, + 99, + 52, + 232, + 207, + 205, + 180, + 16, + 62, + 181, + 44, + 167, + 247, + 100, + 49, + 220, + 199, + 167, + 168, + 170, + 196, + 118, + 60, + 28, + 80, + 50, + 195, + 109, + 13, + 251, + 176, + 88, + 247, + 39, + 165, + 14, + 118, + 242, + 231, + 115, + 31, + 225, + 20, + 136, + 92, + 199, + 132, + 199, + 190, + 105, + 99, + 63, + 43, + 5, + 1, + 155, + 222, + 128, + 26, + 195, + 41, + 150, + 96, + 190, + 139, + 80, + 14, + 149, + 58, + 5, + 25, + 36, + 239, + 99, + 219, + 210, + 160, + 29, + 40, + 1, + 241, + 171, + 16, + 72, + 56, + 7, + 189, + 63, + 36, + 166, + 19, + 229, + 78, + 237, + 64, + 24, + 1, + 164, + 60, + 14, + 138, + 40, + 56, + 206, + 249, + 56, + 95, + 225, + 81, + 222, + 128, + 19, + 39, + 110, + 212, + 59, + 87, + 187, + 30, + 244, + 96, + 5, + 194, + 168, + 219, + 220, + 158, + 244, + 188, + 145, + 190, + 81, + 133, + 236, + 163, + 189, + 35, + 101, + 176, + 207, + 199, + 247, + 80, + 80, + 4, + 76, + 160, + 30, + 58, + 123, + 208, + 14, + 70, + 14, + 6, + 58, + 154, + 145, + 135, + 24, + 97, + 151, + 61, + 20, + 118, + 168, + 200, + 218, + 196, + 100, + 28, + 80, + 6, + 138, + 14, + 213, + 105, + 79, + 2, + 171, + 168, + 230, + 167, + 166, + 33, + 196, + 103, + 165, + 0, + 82, + 102, + 138, + 0, + 112, + 24, + 165, + 164, + 165, + 160, + 6, + 159, + 74, + 48, + 125, + 41, + 72, + 205, + 40, + 160, + 4, + 198, + 105, + 6, + 71, + 90, + 119, + 52, + 14, + 104, + 0, + 57, + 236, + 104, + 205, + 46, + 13, + 27, + 104, + 1, + 164, + 226, + 151, + 173, + 46, + 5, + 46, + 40, + 1, + 51, + 142, + 180, + 148, + 238, + 180, + 152, + 197, + 0, + 24, + 163, + 4, + 26, + 5, + 28, + 208, + 2, + 230, + 154, + 114, + 14, + 69, + 41, + 28, + 230, + 148, + 123, + 208, + 3, + 65, + 205, + 4, + 48, + 52, + 236, + 3, + 69, + 0, + 10, + 217, + 20, + 81, + 176, + 117, + 20, + 116, + 235, + 64, + 6, + 40, + 231, + 165, + 7, + 167, + 20, + 110, + 245, + 160, + 6, + 237, + 207, + 122, + 94, + 157, + 69, + 7, + 218, + 148, + 28, + 245, + 160, + 4, + 60, + 114, + 41, + 51, + 158, + 180, + 236, + 1, + 73, + 128, + 104, + 0, + 230, + 154, + 72, + 61, + 120, + 52, + 165, + 72, + 250, + 83, + 74, + 131, + 200, + 56, + 160, + 5, + 227, + 240, + 160, + 173, + 3, + 142, + 8, + 205, + 3, + 158, + 148, + 0, + 220, + 145, + 215, + 165, + 46, + 15, + 81, + 138, + 11, + 122, + 241, + 70, + 211, + 216, + 138, + 0, + 92, + 122, + 138, + 107, + 47, + 25, + 90, + 9, + 199, + 13, + 249, + 210, + 103, + 142, + 40, + 1, + 171, + 147, + 214, + 156, + 84, + 143, + 122, + 64, + 75, + 122, + 83, + 249, + 29, + 104, + 2, + 63, + 151, + 61, + 77, + 56, + 176, + 199, + 74, + 12, + 106, + 199, + 32, + 144, + 105, + 172, + 74, + 117, + 228, + 122, + 208, + 2, + 0, + 217, + 200, + 20, + 187, + 185, + 230, + 133, + 37, + 134, + 70, + 40, + 42, + 15, + 12, + 40, + 1, + 14, + 59, + 115, + 245, + 164, + 70, + 231, + 128, + 5, + 59, + 229, + 94, + 135, + 34, + 155, + 184, + 30, + 128, + 10, + 0, + 115, + 22, + 61, + 120, + 166, + 152, + 219, + 174, + 65, + 165, + 195, + 30, + 189, + 41, + 192, + 109, + 31, + 122, + 128, + 41, + 202, + 48, + 217, + 198, + 40, + 7, + 214, + 167, + 149, + 193, + 224, + 143, + 210, + 160, + 3, + 210, + 129, + 136, + 125, + 169, + 188, + 131, + 78, + 57, + 205, + 29, + 104, + 1, + 54, + 228, + 83, + 64, + 231, + 6, + 159, + 130, + 13, + 52, + 140, + 154, + 64, + 27, + 127, + 42, + 17, + 252, + 179, + 207, + 74, + 90, + 67, + 215, + 20, + 1, + 54, + 237, + 231, + 229, + 32, + 82, + 144, + 168, + 9, + 124, + 49, + 168, + 71, + 29, + 42, + 85, + 92, + 124, + 196, + 228, + 250, + 83, + 17, + 93, + 128, + 12, + 113, + 78, + 136, + 46, + 236, + 147, + 73, + 39, + 223, + 38, + 132, + 42, + 15, + 205, + 210, + 144, + 201, + 67, + 18, + 112, + 171, + 248, + 226, + 134, + 249, + 78, + 93, + 183, + 122, + 10, + 114, + 187, + 50, + 254, + 237, + 69, + 52, + 5, + 86, + 221, + 38, + 115, + 76, + 64, + 185, + 111, + 245, + 96, + 39, + 214, + 154, + 64, + 86, + 253, + 233, + 201, + 246, + 52, + 247, + 119, + 124, + 97, + 72, + 95, + 92, + 83, + 64, + 69, + 25, + 39, + 123, + 30, + 212, + 128, + 114, + 179, + 184, + 192, + 27, + 87, + 214, + 154, + 140, + 145, + 228, + 70, + 60, + 195, + 222, + 148, + 43, + 57, + 201, + 59, + 87, + 210, + 149, + 153, + 84, + 237, + 136, + 96, + 158, + 244, + 192, + 137, + 216, + 177, + 253, + 225, + 192, + 254, + 237, + 46, + 230, + 113, + 182, + 33, + 180, + 122, + 154, + 10, + 224, + 239, + 148, + 131, + 233, + 205, + 11, + 190, + 94, + 167, + 108, + 116, + 0, + 131, + 17, + 30, + 153, + 126, + 153, + 237, + 76, + 156, + 63, + 14, + 227, + 31, + 74, + 144, + 48, + 7, + 108, + 63, + 55, + 169, + 52, + 174, + 171, + 26, + 146, + 88, + 179, + 159, + 225, + 164, + 5, + 81, + 203, + 1, + 146, + 7, + 122, + 155, + 59, + 134, + 216, + 184, + 29, + 218, + 161, + 32, + 142, + 8, + 193, + 169, + 144, + 121, + 145, + 141, + 164, + 34, + 175, + 95, + 122, + 6, + 11, + 133, + 249, + 87, + 230, + 61, + 218, + 160, + 31, + 46, + 125, + 141, + 78, + 6, + 236, + 249, + 64, + 34, + 142, + 254, + 181, + 95, + 156, + 227, + 223, + 173, + 0, + 77, + 194, + 224, + 147, + 186, + 67, + 208, + 10, + 14, + 85, + 178, + 223, + 52, + 135, + 160, + 20, + 12, + 110, + 11, + 0, + 231, + 185, + 165, + 140, + 17, + 33, + 84, + 249, + 143, + 241, + 19, + 64, + 9, + 146, + 62, + 83, + 243, + 59, + 118, + 236, + 41, + 0, + 108, + 144, + 184, + 103, + 247, + 237, + 78, + 80, + 75, + 21, + 139, + 156, + 253, + 227, + 233, + 76, + 254, + 31, + 151, + 59, + 65, + 193, + 110, + 244, + 192, + 48, + 67, + 225, + 14, + 230, + 238, + 231, + 181, + 53, + 192, + 207, + 28, + 227, + 248, + 189, + 105, + 229, + 178, + 51, + 247, + 19, + 177, + 199, + 90, + 36, + 192, + 10, + 72, + 192, + 236, + 190, + 180, + 128, + 208, + 79, + 189, + 82, + 212, + 0, + 242, + 13, + 76, + 173, + 218, + 152, + 133, + 165, + 218, + 125, + 104, + 167, + 14, + 156, + 208, + 0, + 7, + 20, + 102, + 142, + 148, + 184, + 205, + 0, + 20, + 14, + 105, + 58, + 83, + 133, + 0, + 38, + 105, + 104, + 34, + 129, + 64, + 6, + 104, + 233, + 70, + 40, + 20, + 0, + 30, + 69, + 25, + 199, + 90, + 8, + 193, + 165, + 24, + 52, + 0, + 134, + 140, + 158, + 244, + 99, + 20, + 238, + 40, + 2, + 50, + 15, + 81, + 78, + 235, + 75, + 70, + 56, + 160, + 4, + 165, + 192, + 52, + 99, + 7, + 154, + 62, + 148, + 0, + 152, + 199, + 74, + 92, + 102, + 140, + 250, + 138, + 90, + 0, + 78, + 69, + 28, + 55, + 90, + 40, + 32, + 142, + 69, + 0, + 24, + 199, + 74, + 92, + 3, + 76, + 4, + 154, + 83, + 145, + 212, + 80, + 2, + 226, + 130, + 41, + 55, + 118, + 52, + 160, + 208, + 3, + 119, + 96, + 224, + 209, + 201, + 228, + 83, + 136, + 83, + 214, + 142, + 7, + 74, + 0, + 104, + 111, + 90, + 25, + 7, + 80, + 105, + 73, + 6, + 140, + 80, + 4, + 123, + 187, + 26, + 112, + 245, + 20, + 226, + 138, + 195, + 154, + 97, + 5, + 15, + 6, + 128, + 28, + 72, + 35, + 4, + 83, + 54, + 227, + 233, + 75, + 203, + 12, + 83, + 66, + 48, + 235, + 64, + 14, + 194, + 158, + 13, + 38, + 0, + 232, + 105, + 216, + 226, + 163, + 221, + 131, + 214, + 128, + 29, + 146, + 125, + 41, + 165, + 91, + 189, + 56, + 29, + 221, + 5, + 41, + 86, + 199, + 122, + 0, + 106, + 128, + 59, + 210, + 151, + 29, + 14, + 13, + 55, + 142, + 230, + 151, + 35, + 166, + 1, + 160, + 4, + 199, + 57, + 81, + 75, + 180, + 30, + 9, + 32, + 210, + 16, + 216, + 200, + 31, + 149, + 32, + 60, + 252, + 192, + 138, + 0, + 70, + 93, + 167, + 189, + 46, + 119, + 14, + 0, + 167, + 238, + 3, + 190, + 105, + 187, + 183, + 28, + 40, + 20, + 0, + 221, + 174, + 15, + 56, + 199, + 181, + 59, + 11, + 140, + 247, + 164, + 101, + 113, + 247, + 135, + 30, + 212, + 223, + 148, + 115, + 146, + 40, + 1, + 73, + 227, + 30, + 190, + 213, + 93, + 198, + 211, + 193, + 171, + 27, + 201, + 224, + 12, + 254, + 21, + 28, + 177, + 28, + 103, + 60, + 208, + 4, + 38, + 144, + 210, + 209, + 154, + 6, + 38, + 104, + 197, + 12, + 59, + 210, + 102, + 128, + 16, + 245, + 162, + 148, + 138, + 74, + 64, + 37, + 73, + 27, + 144, + 121, + 168, + 205, + 40, + 160, + 5, + 147, + 239, + 115, + 72, + 172, + 170, + 114, + 70, + 69, + 13, + 210, + 133, + 24, + 96, + 79, + 52, + 1, + 42, + 22, + 147, + 238, + 124, + 163, + 233, + 74, + 192, + 33, + 249, + 240, + 199, + 174, + 105, + 85, + 153, + 254, + 80, + 54, + 138, + 113, + 81, + 16, + 201, + 59, + 137, + 166, + 33, + 138, + 100, + 114, + 56, + 249, + 127, + 42, + 107, + 24, + 195, + 254, + 236, + 18, + 198, + 128, + 90, + 98, + 71, + 221, + 20, + 23, + 88, + 120, + 0, + 22, + 245, + 160, + 5, + 42, + 118, + 230, + 83, + 143, + 161, + 166, + 238, + 99, + 196, + 99, + 143, + 90, + 112, + 4, + 229, + 228, + 32, + 175, + 165, + 55, + 113, + 144, + 149, + 136, + 5, + 2, + 128, + 16, + 132, + 67, + 144, + 75, + 183, + 161, + 165, + 144, + 23, + 140, + 18, + 118, + 123, + 82, + 22, + 72, + 206, + 54, + 130, + 244, + 121, + 100, + 229, + 230, + 60, + 118, + 20, + 128, + 68, + 195, + 169, + 88, + 198, + 204, + 119, + 164, + 192, + 70, + 199, + 223, + 127, + 90, + 112, + 220, + 227, + 8, + 54, + 167, + 122, + 64, + 66, + 29, + 144, + 140, + 183, + 114, + 104, + 2, + 57, + 145, + 131, + 2, + 196, + 18, + 105, + 139, + 142, + 132, + 241, + 79, + 145, + 2, + 41, + 220, + 196, + 201, + 233, + 81, + 175, + 108, + 250, + 208, + 50, + 93, + 219, + 192, + 254, + 24, + 135, + 235, + 80, + 176, + 228, + 254, + 149, + 54, + 210, + 231, + 124, + 167, + 106, + 142, + 131, + 214, + 162, + 144, + 29, + 231, + 182, + 121, + 160, + 9, + 20, + 177, + 140, + 5, + 32, + 39, + 115, + 77, + 85, + 224, + 133, + 108, + 39, + 118, + 161, + 20, + 178, + 252, + 255, + 0, + 44, + 107, + 250, + 210, + 150, + 87, + 60, + 141, + 136, + 58, + 40, + 239, + 64, + 133, + 36, + 96, + 1, + 149, + 140, + 119, + 245, + 166, + 225, + 74, + 130, + 217, + 8, + 15, + 3, + 214, + 156, + 79, + 241, + 200, + 48, + 7, + 221, + 74, + 67, + 156, + 111, + 97, + 243, + 31, + 186, + 148, + 198, + 39, + 250, + 198, + 203, + 2, + 49, + 247, + 82, + 145, + 88, + 231, + 36, + 100, + 250, + 30, + 212, + 230, + 249, + 78, + 7, + 205, + 35, + 127, + 227, + 180, + 155, + 121, + 216, + 167, + 221, + 156, + 210, + 2, + 237, + 75, + 31, + 165, + 69, + 78, + 83, + 138, + 160, + 39, + 165, + 20, + 138, + 114, + 41, + 212, + 8, + 57, + 199, + 52, + 14, + 41, + 105, + 13, + 32, + 23, + 25, + 160, + 113, + 64, + 165, + 60, + 208, + 1, + 239, + 64, + 52, + 131, + 129, + 75, + 138, + 0, + 90, + 74, + 1, + 165, + 197, + 0, + 20, + 152, + 238, + 41, + 104, + 160, + 3, + 52, + 81, + 214, + 147, + 56, + 235, + 64, + 11, + 214, + 140, + 145, + 212, + 82, + 230, + 147, + 61, + 168, + 0, + 235, + 74, + 5, + 52, + 244, + 165, + 6, + 128, + 29, + 138, + 111, + 78, + 148, + 180, + 80, + 1, + 184, + 119, + 163, + 52, + 214, + 233, + 77, + 220, + 7, + 122, + 0, + 115, + 117, + 200, + 165, + 6, + 155, + 156, + 210, + 131, + 138, + 0, + 14, + 15, + 81, + 70, + 7, + 165, + 33, + 60, + 230, + 148, + 48, + 245, + 160, + 3, + 104, + 236, + 105, + 6, + 115, + 79, + 164, + 34, + 128, + 2, + 185, + 28, + 83, + 73, + 35, + 174, + 126, + 180, + 236, + 226, + 151, + 57, + 160, + 6, + 2, + 125, + 104, + 220, + 58, + 26, + 93, + 184, + 233, + 72, + 85, + 79, + 90, + 0, + 48, + 59, + 80, + 73, + 236, + 105, + 54, + 224, + 240, + 77, + 25, + 61, + 141, + 0, + 24, + 39, + 144, + 105, + 216, + 7, + 168, + 20, + 132, + 55, + 108, + 83, + 3, + 115, + 134, + 20, + 0, + 21, + 32, + 252, + 180, + 161, + 137, + 224, + 241, + 71, + 211, + 52, + 187, + 129, + 226, + 128, + 26, + 83, + 156, + 228, + 82, + 49, + 0, + 114, + 41, + 219, + 91, + 61, + 50, + 40, + 33, + 72, + 195, + 12, + 80, + 3, + 1, + 56, + 200, + 6, + 141, + 129, + 186, + 177, + 20, + 191, + 119, + 149, + 205, + 33, + 5, + 135, + 7, + 6, + 128, + 26, + 87, + 103, + 70, + 200, + 247, + 161, + 91, + 158, + 20, + 125, + 105, + 192, + 50, + 253, + 236, + 26, + 9, + 83, + 208, + 115, + 64, + 10, + 114, + 70, + 14, + 113, + 81, + 236, + 92, + 231, + 38, + 148, + 171, + 147, + 192, + 56, + 165, + 242, + 240, + 114, + 92, + 208, + 2, + 135, + 219, + 208, + 83, + 95, + 230, + 83, + 158, + 41, + 75, + 129, + 199, + 90, + 66, + 132, + 130, + 73, + 160, + 10, + 204, + 57, + 52, + 222, + 244, + 231, + 200, + 115, + 73, + 158, + 104, + 24, + 148, + 132, + 0, + 41, + 230, + 152, + 69, + 0, + 47, + 106, + 109, + 45, + 3, + 175, + 52, + 0, + 218, + 41, + 197, + 70, + 105, + 41, + 0, + 210, + 77, + 57, + 78, + 14, + 105, + 27, + 173, + 47, + 27, + 148, + 251, + 208, + 4, + 163, + 205, + 99, + 128, + 8, + 30, + 180, + 226, + 162, + 32, + 14, + 226, + 73, + 236, + 105, + 217, + 148, + 175, + 24, + 2, + 144, + 4, + 207, + 114, + 223, + 90, + 98, + 26, + 21, + 165, + 57, + 108, + 168, + 20, + 214, + 125, + 132, + 170, + 2, + 199, + 215, + 20, + 230, + 18, + 49, + 249, + 242, + 171, + 77, + 221, + 180, + 226, + 32, + 88, + 247, + 160, + 5, + 84, + 219, + 150, + 145, + 176, + 61, + 41, + 9, + 121, + 78, + 20, + 108, + 95, + 92, + 80, + 0, + 206, + 233, + 137, + 221, + 233, + 74, + 198, + 70, + 224, + 169, + 11, + 64, + 3, + 58, + 161, + 10, + 163, + 121, + 246, + 20, + 133, + 8, + 249, + 229, + 111, + 248, + 14, + 40, + 141, + 246, + 41, + 17, + 169, + 99, + 72, + 121, + 249, + 164, + 206, + 238, + 194, + 128, + 26, + 164, + 202, + 216, + 251, + 139, + 233, + 73, + 149, + 221, + 182, + 17, + 131, + 221, + 169, + 78, + 73, + 204, + 131, + 106, + 251, + 82, + 225, + 152, + 109, + 136, + 97, + 123, + 154, + 64, + 53, + 194, + 15, + 151, + 27, + 220, + 247, + 244, + 168, + 15, + 12, + 71, + 165, + 90, + 80, + 35, + 82, + 35, + 249, + 152, + 245, + 38, + 170, + 183, + 82, + 79, + 83, + 64, + 201, + 49, + 136, + 247, + 202, + 114, + 49, + 192, + 205, + 49, + 198, + 2, + 251, + 246, + 167, + 66, + 160, + 225, + 137, + 201, + 236, + 180, + 78, + 122, + 19, + 214, + 128, + 4, + 32, + 69, + 243, + 13, + 222, + 130, + 148, + 141, + 160, + 52, + 131, + 39, + 248, + 86, + 155, + 17, + 11, + 200, + 229, + 207, + 74, + 94, + 67, + 101, + 142, + 100, + 63, + 165, + 48, + 23, + 44, + 24, + 110, + 27, + 156, + 244, + 30, + 148, + 143, + 144, + 121, + 59, + 152, + 247, + 244, + 160, + 112, + 74, + 169, + 203, + 159, + 188, + 222, + 148, + 152, + 249, + 72, + 92, + 0, + 62, + 241, + 245, + 164, + 0, + 62, + 102, + 249, + 120, + 3, + 171, + 122, + 210, + 156, + 2, + 88, + 140, + 15, + 79, + 90, + 0, + 202, + 131, + 140, + 39, + 101, + 245, + 164, + 96, + 88, + 131, + 220, + 244, + 30, + 148, + 192, + 188, + 69, + 37, + 57, + 78, + 69, + 4, + 12, + 211, + 16, + 248, + 219, + 7, + 6, + 166, + 206, + 106, + 184, + 52, + 224, + 230, + 128, + 39, + 162, + 145, + 78, + 105, + 123, + 210, + 1, + 7, + 20, + 238, + 180, + 152, + 165, + 197, + 0, + 2, + 150, + 146, + 138, + 0, + 13, + 25, + 162, + 148, + 80, + 2, + 26, + 81, + 239, + 75, + 73, + 64, + 6, + 49, + 71, + 90, + 78, + 115, + 75, + 64, + 5, + 47, + 90, + 5, + 24, + 244, + 160, + 2, + 146, + 148, + 28, + 209, + 64, + 5, + 55, + 56, + 62, + 212, + 180, + 109, + 244, + 52, + 0, + 157, + 104, + 218, + 58, + 226, + 151, + 111, + 190, + 41, + 57, + 7, + 6, + 128, + 19, + 111, + 167, + 20, + 21, + 108, + 117, + 167, + 80, + 77, + 0, + 70, + 16, + 17, + 212, + 230, + 158, + 20, + 119, + 163, + 56, + 57, + 236, + 105, + 119, + 80, + 2, + 17, + 183, + 233, + 74, + 61, + 65, + 165, + 164, + 28, + 116, + 160, + 5, + 164, + 42, + 59, + 81, + 197, + 29, + 58, + 80, + 3, + 78, + 84, + 250, + 138, + 94, + 13, + 46, + 105, + 8, + 160, + 0, + 113, + 212, + 208, + 77, + 3, + 29, + 13, + 38, + 0, + 233, + 64, + 10, + 121, + 166, + 152, + 243, + 222, + 151, + 119, + 189, + 47, + 94, + 134, + 128, + 25, + 146, + 15, + 90, + 66, + 217, + 237, + 82, + 96, + 119, + 20, + 194, + 6, + 120, + 20, + 0, + 139, + 187, + 184, + 56, + 165, + 33, + 72, + 235, + 65, + 221, + 138, + 64, + 55, + 115, + 186, + 128, + 27, + 187, + 105, + 235, + 78, + 35, + 127, + 66, + 40, + 200, + 29, + 112, + 104, + 251, + 221, + 5, + 0, + 38, + 54, + 245, + 230, + 147, + 229, + 61, + 23, + 154, + 126, + 209, + 252, + 64, + 211, + 112, + 131, + 238, + 231, + 52, + 0, + 208, + 204, + 56, + 228, + 82, + 224, + 30, + 119, + 82, + 150, + 99, + 198, + 8, + 166, + 152, + 243, + 206, + 234, + 0, + 93, + 192, + 116, + 193, + 166, + 177, + 102, + 29, + 64, + 165, + 12, + 171, + 193, + 2, + 154, + 84, + 158, + 69, + 0, + 64, + 192, + 131, + 243, + 117, + 166, + 211, + 156, + 115, + 77, + 160, + 98, + 245, + 20, + 148, + 10, + 13, + 33, + 8, + 71, + 20, + 152, + 52, + 166, + 128, + 104, + 24, + 135, + 154, + 76, + 98, + 134, + 246, + 162, + 128, + 18, + 129, + 74, + 1, + 160, + 241, + 64, + 18, + 39, + 152, + 252, + 14, + 149, + 47, + 238, + 227, + 28, + 0, + 90, + 160, + 135, + 115, + 146, + 162, + 164, + 37, + 99, + 249, + 112, + 25, + 168, + 16, + 184, + 119, + 251, + 220, + 45, + 55, + 32, + 124, + 176, + 142, + 105, + 89, + 100, + 43, + 150, + 96, + 23, + 210, + 145, + 27, + 156, + 32, + 25, + 245, + 166, + 1, + 229, + 42, + 252, + 243, + 242, + 223, + 90, + 8, + 146, + 81, + 129, + 194, + 125, + 105, + 91, + 8, + 115, + 41, + 14, + 105, + 88, + 22, + 94, + 8, + 85, + 244, + 164, + 4, + 97, + 130, + 157, + 144, + 140, + 159, + 90, + 14, + 212, + 59, + 165, + 249, + 155, + 235, + 78, + 5, + 73, + 217, + 24, + 25, + 238, + 113, + 72, + 72, + 135, + 169, + 12, + 199, + 218, + 152, + 8, + 99, + 45, + 251, + 201, + 72, + 10, + 59, + 80, + 3, + 74, + 48, + 132, + 34, + 10, + 82, + 55, + 15, + 50, + 86, + 224, + 116, + 90, + 102, + 76, + 135, + 146, + 99, + 94, + 220, + 82, + 0, + 56, + 13, + 178, + 46, + 189, + 218, + 160, + 144, + 109, + 56, + 206, + 125, + 234, + 198, + 75, + 157, + 145, + 130, + 23, + 185, + 170, + 242, + 112, + 248, + 7, + 32, + 119, + 166, + 49, + 98, + 96, + 132, + 128, + 9, + 115, + 210, + 157, + 42, + 237, + 143, + 107, + 16, + 92, + 156, + 147, + 233, + 77, + 133, + 153, + 88, + 132, + 93, + 196, + 254, + 148, + 167, + 141, + 216, + 201, + 56, + 249, + 137, + 237, + 72, + 67, + 35, + 36, + 31, + 151, + 25, + 60, + 15, + 106, + 123, + 15, + 151, + 106, + 243, + 207, + 204, + 213, + 26, + 240, + 195, + 21, + 55, + 12, + 49, + 157, + 136, + 189, + 125, + 232, + 24, + 132, + 0, + 161, + 87, + 132, + 238, + 221, + 205, + 33, + 33, + 134, + 78, + 118, + 142, + 130, + 128, + 70, + 55, + 21, + 194, + 142, + 21, + 125, + 105, + 64, + 43, + 254, + 241, + 237, + 233, + 76, + 0, + 183, + 115, + 247, + 143, + 79, + 106, + 111, + 183, + 62, + 231, + 214, + 156, + 188, + 130, + 7, + 221, + 31, + 120, + 210, + 96, + 158, + 71, + 115, + 197, + 2, + 47, + 20, + 199, + 214, + 144, + 19, + 222, + 166, + 32, + 48, + 199, + 113, + 77, + 217, + 235, + 76, + 6, + 98, + 138, + 113, + 27, + 126, + 148, + 209, + 64, + 18, + 198, + 120, + 169, + 55, + 14, + 42, + 184, + 200, + 167, + 6, + 160, + 11, + 2, + 138, + 98, + 183, + 62, + 212, + 239, + 113, + 72, + 5, + 34, + 138, + 77, + 212, + 188, + 26, + 0, + 90, + 76, + 210, + 142, + 40, + 32, + 26, + 0, + 1, + 162, + 138, + 51, + 64, + 5, + 29, + 13, + 25, + 160, + 208, + 1, + 205, + 0, + 208, + 13, + 6, + 128, + 3, + 73, + 154, + 50, + 123, + 208, + 13, + 0, + 24, + 30, + 166, + 148, + 28, + 112, + 104, + 205, + 33, + 52, + 0, + 185, + 164, + 220, + 41, + 41, + 195, + 165, + 0, + 37, + 40, + 52, + 187, + 65, + 164, + 42, + 49, + 197, + 0, + 4, + 83, + 74, + 250, + 82, + 227, + 212, + 209, + 183, + 253, + 170, + 0, + 81, + 210, + 151, + 173, + 51, + 37, + 78, + 15, + 231, + 79, + 7, + 34, + 128, + 16, + 169, + 52, + 46, + 123, + 210, + 209, + 248, + 208, + 2, + 26, + 51, + 199, + 52, + 166, + 154, + 15, + 98, + 40, + 0, + 219, + 232, + 105, + 14, + 69, + 41, + 207, + 106, + 76, + 3, + 212, + 80, + 1, + 156, + 246, + 20, + 210, + 24, + 30, + 5, + 60, + 40, + 237, + 77, + 109, + 195, + 166, + 104, + 0, + 250, + 211, + 73, + 11, + 222, + 156, + 57, + 239, + 138, + 82, + 7, + 126, + 104, + 0, + 86, + 220, + 41, + 172, + 132, + 28, + 209, + 184, + 14, + 0, + 165, + 25, + 244, + 160, + 6, + 124, + 189, + 10, + 131, + 73, + 143, + 64, + 71, + 210, + 164, + 40, + 167, + 147, + 197, + 53, + 155, + 104, + 226, + 128, + 26, + 51, + 252, + 89, + 167, + 0, + 163, + 248, + 169, + 23, + 230, + 254, + 42, + 95, + 44, + 142, + 226, + 128, + 17, + 164, + 236, + 40, + 216, + 91, + 161, + 165, + 200, + 61, + 134, + 105, + 54, + 190, + 120, + 198, + 40, + 1, + 62, + 85, + 28, + 168, + 164, + 47, + 199, + 2, + 156, + 85, + 8, + 249, + 133, + 67, + 38, + 209, + 247, + 73, + 160, + 8, + 216, + 243, + 76, + 52, + 226, + 121, + 164, + 52, + 12, + 64, + 113, + 70, + 40, + 227, + 20, + 80, + 3, + 79, + 90, + 80, + 61, + 104, + 60, + 80, + 41, + 0, + 210, + 57, + 163, + 165, + 41, + 164, + 32, + 145, + 197, + 0, + 75, + 22, + 29, + 72, + 197, + 66, + 192, + 134, + 34, + 167, + 135, + 1, + 54, + 168, + 25, + 238, + 106, + 39, + 31, + 53, + 0, + 53, + 88, + 131, + 197, + 79, + 188, + 40, + 206, + 1, + 53, + 94, + 164, + 142, + 86, + 81, + 128, + 50, + 79, + 165, + 0, + 72, + 84, + 177, + 203, + 176, + 3, + 174, + 41, + 55, + 151, + 59, + 99, + 24, + 30, + 184, + 161, + 148, + 99, + 116, + 132, + 250, + 208, + 142, + 207, + 194, + 41, + 3, + 214, + 152, + 133, + 218, + 145, + 13, + 206, + 119, + 55, + 165, + 32, + 67, + 48, + 221, + 35, + 21, + 29, + 133, + 35, + 42, + 198, + 217, + 220, + 75, + 30, + 212, + 187, + 90, + 69, + 253, + 225, + 42, + 191, + 149, + 0, + 2, + 79, + 224, + 136, + 113, + 211, + 118, + 40, + 194, + 68, + 119, + 12, + 187, + 154, + 64, + 95, + 27, + 98, + 82, + 87, + 214, + 154, + 112, + 48, + 20, + 18, + 231, + 222, + 128, + 23, + 3, + 62, + 100, + 199, + 158, + 203, + 65, + 204, + 167, + 50, + 252, + 177, + 138, + 70, + 1, + 57, + 151, + 150, + 236, + 1, + 164, + 101, + 112, + 161, + 164, + 198, + 222, + 195, + 52, + 128, + 93, + 197, + 134, + 212, + 24, + 143, + 161, + 230, + 171, + 190, + 55, + 156, + 116, + 169, + 240, + 206, + 155, + 142, + 17, + 123, + 15, + 90, + 172, + 79, + 38, + 129, + 143, + 136, + 178, + 177, + 217, + 140, + 159, + 90, + 119, + 1, + 74, + 103, + 147, + 247, + 141, + 50, + 48, + 75, + 112, + 113, + 234, + 106, + 64, + 60, + 204, + 246, + 65, + 252, + 84, + 196, + 64, + 69, + 76, + 191, + 188, + 80, + 207, + 247, + 71, + 79, + 122, + 133, + 185, + 39, + 210, + 159, + 27, + 149, + 24, + 235, + 233, + 72, + 100, + 132, + 97, + 242, + 220, + 159, + 225, + 30, + 148, + 206, + 237, + 147, + 207, + 115, + 75, + 158, + 56, + 57, + 99, + 212, + 250, + 82, + 140, + 99, + 0, + 124, + 163, + 245, + 166, + 33, + 9, + 249, + 64, + 3, + 129, + 211, + 222, + 149, + 88, + 134, + 254, + 116, + 133, + 139, + 18, + 113, + 255, + 0, + 214, + 164, + 206, + 6, + 122, + 208, + 6, + 167, + 90, + 81, + 239, + 77, + 35, + 184, + 165, + 28, + 208, + 2, + 145, + 216, + 244, + 166, + 108, + 193, + 226, + 159, + 245, + 165, + 197, + 48, + 27, + 129, + 76, + 35, + 7, + 21, + 45, + 24, + 12, + 57, + 160, + 8, + 195, + 96, + 212, + 129, + 169, + 166, + 58, + 110, + 13, + 0, + 60, + 228, + 210, + 171, + 17, + 193, + 166, + 161, + 206, + 69, + 59, + 25, + 95, + 165, + 0, + 59, + 119, + 165, + 40, + 106, + 137, + 179, + 218, + 144, + 54, + 120, + 52, + 1, + 54, + 239, + 90, + 42, + 29, + 220, + 226, + 156, + 9, + 198, + 40, + 176, + 15, + 39, + 156, + 82, + 110, + 56, + 164, + 60, + 138, + 50, + 8, + 160, + 7, + 6, + 7, + 189, + 40, + 166, + 109, + 230, + 157, + 130, + 5, + 0, + 41, + 165, + 2, + 155, + 78, + 232, + 40, + 1, + 254, + 212, + 220, + 123, + 209, + 187, + 52, + 134, + 144, + 10, + 22, + 151, + 24, + 233, + 64, + 163, + 52, + 0, + 153, + 197, + 46, + 234, + 111, + 227, + 71, + 78, + 180, + 0, + 81, + 206, + 57, + 165, + 29, + 121, + 167, + 99, + 138, + 0, + 143, + 56, + 165, + 20, + 16, + 59, + 138, + 64, + 48, + 120, + 233, + 64, + 18, + 83, + 78, + 105, + 115, + 197, + 55, + 112, + 52, + 0, + 191, + 90, + 66, + 5, + 47, + 214, + 140, + 15, + 90, + 0, + 79, + 166, + 104, + 235, + 214, + 130, + 113, + 212, + 82, + 99, + 61, + 232, + 0, + 233, + 222, + 148, + 62, + 105, + 54, + 99, + 173, + 33, + 218, + 59, + 80, + 2, + 176, + 39, + 167, + 90, + 78, + 71, + 222, + 20, + 12, + 246, + 20, + 191, + 90, + 0, + 105, + 11, + 219, + 52, + 153, + 97, + 235, + 138, + 83, + 242, + 255, + 0, + 21, + 46, + 252, + 244, + 160, + 4, + 224, + 255, + 0, + 21, + 46, + 118, + 142, + 198, + 153, + 181, + 179, + 235, + 79, + 200, + 28, + 17, + 64, + 9, + 184, + 183, + 221, + 2, + 155, + 181, + 191, + 139, + 165, + 7, + 175, + 202, + 166, + 148, + 19, + 223, + 52, + 0, + 223, + 145, + 79, + 124, + 210, + 249, + 135, + 160, + 6, + 149, + 130, + 158, + 123, + 211, + 55, + 145, + 192, + 34, + 128, + 28, + 70, + 71, + 39, + 21, + 89, + 243, + 187, + 25, + 200, + 169, + 25, + 207, + 214, + 163, + 61, + 121, + 160, + 6, + 226, + 145, + 169, + 73, + 244, + 164, + 193, + 52, + 0, + 130, + 142, + 41, + 113, + 77, + 160, + 97, + 72, + 105, + 115, + 197, + 39, + 52, + 0, + 152, + 167, + 70, + 55, + 62, + 59, + 14, + 180, + 132, + 154, + 145, + 98, + 108, + 124, + 220, + 45, + 33, + 14, + 101, + 78, + 21, + 23, + 147, + 214, + 163, + 145, + 10, + 158, + 106, + 80, + 169, + 159, + 144, + 28, + 251, + 154, + 142, + 101, + 101, + 31, + 49, + 20, + 192, + 139, + 20, + 228, + 109, + 141, + 145, + 77, + 160, + 241, + 72, + 100, + 216, + 71, + 230, + 66, + 105, + 203, + 41, + 111, + 146, + 53, + 192, + 245, + 168, + 99, + 218, + 220, + 62, + 113, + 82, + 128, + 231, + 136, + 215, + 11, + 245, + 160, + 66, + 226, + 40, + 206, + 121, + 103, + 247, + 166, + 182, + 231, + 57, + 151, + 33, + 71, + 106, + 113, + 17, + 167, + 65, + 151, + 250, + 211, + 66, + 156, + 150, + 155, + 242, + 205, + 48, + 23, + 204, + 98, + 54, + 196, + 48, + 61, + 105, + 187, + 145, + 14, + 20, + 2, + 254, + 180, + 108, + 105, + 63, + 213, + 168, + 85, + 164, + 98, + 171, + 242, + 42, + 169, + 111, + 90, + 0, + 77, + 222, + 91, + 101, + 128, + 102, + 63, + 141, + 59, + 149, + 59, + 228, + 108, + 183, + 101, + 164, + 255, + 0, + 85, + 208, + 150, + 115, + 218, + 148, + 133, + 140, + 111, + 144, + 146, + 244, + 1, + 28, + 178, + 22, + 28, + 140, + 31, + 74, + 128, + 210, + 187, + 23, + 109, + 198, + 155, + 64, + 199, + 40, + 235, + 233, + 222, + 164, + 99, + 242, + 3, + 209, + 7, + 111, + 90, + 141, + 61, + 250, + 103, + 165, + 76, + 184, + 99, + 185, + 184, + 199, + 69, + 197, + 2, + 43, + 177, + 201, + 205, + 38, + 113, + 79, + 124, + 238, + 36, + 140, + 26, + 142, + 144, + 201, + 84, + 238, + 60, + 113, + 74, + 122, + 250, + 84, + 64, + 224, + 212, + 155, + 242, + 57, + 166, + 33, + 194, + 163, + 144, + 224, + 224, + 80, + 92, + 227, + 142, + 190, + 180, + 206, + 248, + 234, + 104, + 25, + 177, + 210, + 148, + 117, + 166, + 231, + 20, + 28, + 246, + 166, + 34, + 65, + 207, + 20, + 157, + 40, + 7, + 32, + 30, + 244, + 19, + 64, + 1, + 28, + 100, + 82, + 7, + 193, + 164, + 45, + 76, + 205, + 0, + 77, + 188, + 83, + 115, + 233, + 81, + 231, + 138, + 65, + 158, + 212, + 0, + 254, + 141, + 145, + 79, + 6, + 162, + 206, + 105, + 69, + 0, + 73, + 193, + 164, + 49, + 231, + 165, + 55, + 36, + 84, + 138, + 224, + 253, + 104, + 2, + 53, + 82, + 15, + 53, + 40, + 81, + 138, + 24, + 12, + 230, + 149, + 79, + 24, + 160, + 6, + 142, + 188, + 210, + 149, + 29, + 169, + 74, + 130, + 115, + 74, + 56, + 235, + 205, + 0, + 2, + 158, + 41, + 185, + 244, + 165, + 205, + 32, + 17, + 151, + 29, + 40, + 3, + 214, + 151, + 173, + 37, + 0, + 35, + 47, + 165, + 0, + 227, + 173, + 46, + 61, + 233, + 49, + 64, + 15, + 4, + 118, + 163, + 173, + 71, + 208, + 210, + 140, + 250, + 208, + 3, + 240, + 41, + 132, + 226, + 148, + 26, + 48, + 40, + 1, + 1, + 165, + 44, + 64, + 165, + 227, + 218, + 146, + 128, + 16, + 55, + 168, + 167, + 6, + 166, + 237, + 193, + 226, + 148, + 17, + 233, + 64, + 8, + 205, + 131, + 210, + 147, + 118, + 123, + 83, + 138, + 228, + 83, + 72, + 24, + 160, + 5, + 7, + 214, + 157, + 81, + 169, + 29, + 233, + 192, + 250, + 80, + 3, + 179, + 158, + 180, + 194, + 15, + 97, + 79, + 200, + 164, + 39, + 20, + 0, + 131, + 36, + 115, + 70, + 7, + 90, + 51, + 158, + 244, + 184, + 199, + 106, + 0, + 51, + 138, + 67, + 150, + 233, + 70, + 239, + 106, + 105, + 7, + 168, + 20, + 0, + 5, + 199, + 45, + 74, + 72, + 199, + 2, + 128, + 71, + 113, + 77, + 125, + 189, + 69, + 0, + 33, + 207, + 96, + 105, + 64, + 7, + 239, + 102, + 132, + 99, + 211, + 154, + 115, + 12, + 142, + 180, + 0, + 222, + 159, + 116, + 211, + 75, + 147, + 214, + 151, + 36, + 119, + 163, + 37, + 190, + 148, + 0, + 4, + 98, + 115, + 144, + 104, + 108, + 40, + 232, + 41, + 174, + 219, + 71, + 21, + 17, + 144, + 55, + 20, + 0, + 210, + 220, + 159, + 74, + 24, + 241, + 72, + 105, + 9, + 226, + 128, + 17, + 121, + 228, + 208, + 79, + 52, + 40, + 61, + 168, + 97, + 206, + 104, + 0, + 25, + 52, + 16, + 41, + 115, + 73, + 64, + 12, + 39, + 154, + 90, + 24, + 142, + 180, + 42, + 22, + 228, + 130, + 22, + 144, + 0, + 28, + 140, + 12, + 158, + 213, + 40, + 89, + 31, + 151, + 4, + 1, + 78, + 64, + 131, + 238, + 228, + 147, + 74, + 219, + 255, + 0, + 139, + 129, + 76, + 0, + 108, + 78, + 17, + 126, + 106, + 142, + 120, + 206, + 222, + 88, + 28, + 212, + 129, + 129, + 251, + 184, + 30, + 244, + 215, + 140, + 128, + 73, + 108, + 154, + 0, + 172, + 41, + 15, + 52, + 234, + 105, + 164, + 48, + 206, + 41, + 203, + 43, + 1, + 142, + 212, + 218, + 105, + 52, + 1, + 97, + 89, + 113, + 194, + 130, + 105, + 74, + 56, + 249, + 159, + 110, + 61, + 51, + 85, + 178, + 71, + 74, + 145, + 102, + 61, + 232, + 17, + 38, + 246, + 147, + 42, + 8, + 69, + 20, + 155, + 136, + 27, + 83, + 167, + 174, + 41, + 143, + 41, + 106, + 67, + 41, + 198, + 40, + 24, + 230, + 217, + 23, + 59, + 137, + 53, + 11, + 185, + 115, + 150, + 164, + 235, + 214, + 146, + 128, + 3, + 73, + 75, + 73, + 76, + 9, + 16, + 113, + 156, + 243, + 216, + 83, + 200, + 206, + 50, + 126, + 99, + 250, + 83, + 19, + 166, + 59, + 154, + 147, + 27, + 125, + 253, + 232, + 17, + 28, + 170, + 87, + 169, + 207, + 189, + 69, + 82, + 200, + 114, + 189, + 120, + 168, + 141, + 3, + 18, + 140, + 226, + 133, + 86, + 115, + 133, + 31, + 141, + 92, + 130, + 203, + 39, + 47, + 201, + 161, + 33, + 92, + 173, + 28, + 79, + 39, + 65, + 129, + 87, + 173, + 236, + 130, + 224, + 183, + 90, + 181, + 28, + 33, + 71, + 2, + 165, + 11, + 79, + 68, + 0, + 255, + 217 + ]); +} diff --git a/star_lock/lib/talk/call/callTalk.dart b/star_lock/lib/talk/call/callTalk.dart new file mode 100644 index 00000000..cf4985b9 --- /dev/null +++ b/star_lock/lib/talk/call/callTalk.dart @@ -0,0 +1,111 @@ +import 'dart:typed_data'; +import 'package:convert/convert.dart'; +import 'package:flutter_sound/flutter_sound.dart'; +// import 'package:just_audio/just_audio.dart'; +import 'package:star_lock/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart'; +import 'package:star_lock/talk/call/g711Decoder.dart'; +import 'package:star_lock/talk/call/iFrameInfo.dart'; + +class CallTalk { + static int POS_iframe_index = 63; + static int POS_alen = 65; + static int POS_blen = 73; + static int POS_bag_index = 71; + static int POS_bag_num = 69; + static int POS_data = 77; + static int ABUF_NUM = 100; + static int FIRSTINDEX = 1; + + int status = 0; // 假设有这个成员变量 + IframeInfo iframe = IframeInfo(); // 假设有这个成员变量 + LockMonitoringPage callOut = const LockMonitoringPage(); + late FlutterSoundPlayer _player; + + Future getAVData(Uint8List bb, int len) async { + //视频数据 + // String hexData = + // '5858584349449601075439415f396333613730323264346364a5a5a5a5c0a809a3503138363832313530323337000000000000000030303030420e000002000000b33300001f000100b301b301ffd8ffe000114a4649460001010000'; + // Uint8List bb = Uint8List.fromList(hex.decode(hexData)); + //音频数据 + String hexData = + '5858584349449601075439415f396333613730323264346364a5a5a5a5c0a809a3503138363832313530323337000000000000000030303030e02900000100050080020000010001004001b30145444444444444444445454444444444444444444444434343434443434344444444444544454545444444444444454545454545454545454445444545454545454545444444444343434344444443434344444444444343434343434343434443434343434343424343434343434242424242424242424243434343434242424242424343434342424343434242424242434243434343434344454344444444444444444444444444454545454544444444444444444445454545454545454545454545454546454545454545454545454545454545454646464646464645454545464646454545454545454545454545454544444444444444444443434343434343434343434343434343434343434242424242424242424242424242424343434242434343434343434343434343434343434343434444444343434343430000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024001d044000000000001d080001000000001d18c03000000000'; + Uint8List bb = Uint8List.fromList(hex.decode(hexData)); + + // 音频数据 + if (bb[61] == 1) { + // 如果是音频数据且状态符合条件 + _player = FlutterSoundPlayer(); + _initPlayer(); + + // 解码 + Uint8List g711Data = G711Decoder().decodeG711uLaw(bb); + + await _playAudio(g711Data); + } + // 视频数据 + else { + int bagLen = getShortFromByte(bb, POS_blen + 2); + int getIframeIndex = getShortFromByte(bb, POS_iframe_index); + int alen = getShortFromByte(bb, POS_alen); + int blen = getShortFromByte(bb, POS_blen); + int getBagIndex = bb[POS_bag_index] & 0xff; + int getBagNum = bb[POS_bag_num] & 0xff; + + if (getIframeIndex != iframe.iframeIndex) { + iframe = IframeInfo(); + iframe.iframeIndex = getIframeIndex; + iframe.bagNum = getBagNum; + iframe.cur_len = alen; + iframe.bb = Uint8List(alen); + } + + iframe.bagReceive++; + int start = bagLen * (getBagIndex - FIRSTINDEX); + int end = start + blen; + + // 确保 iframe!.bb 不为 null,并且足够长 + if (iframe.bb == null || iframe.bb!.length < end) { + iframe.bb = Uint8List(end); + } + + copyBytes(iframe!.bb!, start, bb, POS_data, blen); + // 打印输出看看字节数组的内容 + print('Copied Bytes: ${iframe.bb}'); + + Uint8List data = iframe.bb!.sublist(0, iframe.cur_len); + + // 打印拷贝后的目标数据 + print(iframe.bb); + } + } + + int getShortFromByte(Uint8List bb, int pos) { + ByteData byteData = ByteData.sublistView(bb, pos, pos + 2); + return byteData.getInt16(0, Endian.little); + } + + void copyBytes(Uint8List destination, int destStart, Uint8List source, + int sourceStart, int length) { + if (destination.length < destStart + length || + source.length < sourceStart + length) { + // 处理越界的情况,这里你可以抛出异常或者进行其他处理 + print('Error: Index out of range'); + return; + } + + for (int i = 0; i < length; i++) { + destination[destStart + i] = source[sourceStart + i]; + } + } + + Future _initPlayer() async { + await _player.openPlayer(); + } + + Future _playAudio(Uint8List audioData) async { + await _player.startPlayer( + fromDataBuffer: audioData, + codec: Codec.pcm16WAV, + ); + } +} diff --git a/star_lock/lib/talk/call/g711Decoder.dart b/star_lock/lib/talk/call/g711Decoder.dart new file mode 100644 index 00000000..94d665a3 --- /dev/null +++ b/star_lock/lib/talk/call/g711Decoder.dart @@ -0,0 +1,44 @@ +import 'dart:typed_data'; + +class G711Decoder { + // G.711 µ-law解码 + Uint8List decodeG711uLaw(Uint8List data) { + List decodedData = []; + + for (int i = 0; i < data.length; i++) { + int sample = _decodeG711uLawSample(data[i]); + decodedData.add(sample); + } + + return Uint8List.fromList(decodedData); + } + + // G.711 µ-law样本解码 + int _decodeG711uLawSample(int uLawByte) { + const int bias = 0x84; + const int mask = 0x7F; + + uLawByte = ~uLawByte; + int sign = uLawByte & 0x80; + int exponent = (uLawByte & 0x70) >> 4; + int mantissa = uLawByte & 0x0F; + + int sample = ((bias << exponent) + mantissa) * (sign == 0 ? 1 : -1); + + return sample & mask; // 防止溢出 + } +} + +void main() { + G711Decoder g711Decoder = G711Decoder(); + + // 假设 g711Data 是G.711 µ-law编码的数据 + Uint8List g711Data = + Uint8List.fromList([/* your G.711 µ-law encoded data */]); + + // 解码 + List decodedData = g711Decoder.decodeG711uLaw(g711Data); + + // 处理解码后的数据,例如播放音频 + print(decodedData); +} diff --git a/star_lock/lib/talk/call/iFrameInfo.dart b/star_lock/lib/talk/call/iFrameInfo.dart new file mode 100644 index 00000000..89e0101b --- /dev/null +++ b/star_lock/lib/talk/call/iFrameInfo.dart @@ -0,0 +1,22 @@ +import 'dart:typed_data'; + +class IframeInfo { + int iframeIndex = -1; + int iframeTime = 0; + int bagNum = 0; + int bagReceive = 0; + bool isFull = false; + int cur_len = 0; + int bb_len = 0; + Uint8List? bb; + int codecMode = 0; + + IframeInfo() { + iframeIndex = -1; + bagNum = 0; + bagReceive = 0; + isFull = false; + cur_len = 0; + bb = Uint8List(512); + } +} diff --git a/star_lock/lib/talk/playAudio.dart b/star_lock/lib/talk/playAudio.dart deleted file mode 100644 index e69de29b..00000000 diff --git a/star_lock/linux/flutter/generated_plugin_registrant.cc b/star_lock/linux/flutter/generated_plugin_registrant.cc index 7111d06f..05d9a9b9 100644 --- a/star_lock/linux/flutter/generated_plugin_registrant.cc +++ b/star_lock/linux/flutter/generated_plugin_registrant.cc @@ -7,6 +7,7 @@ #include "generated_plugin_registrant.h" #include +#include #include #include @@ -14,6 +15,9 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) aj_captcha_flutter_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "AjCaptchaFlutterPlugin"); aj_captcha_flutter_plugin_register_with_registrar(aj_captcha_flutter_registrar); + g_autoptr(FlPluginRegistrar) audioplayers_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "AudioplayersLinuxPlugin"); + audioplayers_linux_plugin_register_with_registrar(audioplayers_linux_registrar); g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); file_selector_plugin_register_with_registrar(file_selector_linux_registrar); diff --git a/star_lock/linux/flutter/generated_plugins.cmake b/star_lock/linux/flutter/generated_plugins.cmake index 7fbf0d0d..b6e600e9 100644 --- a/star_lock/linux/flutter/generated_plugins.cmake +++ b/star_lock/linux/flutter/generated_plugins.cmake @@ -4,6 +4,7 @@ list(APPEND FLUTTER_PLUGIN_LIST aj_captcha_flutter + audioplayers_linux file_selector_linux url_launcher_linux ) diff --git a/star_lock/macos/Flutter/GeneratedPluginRegistrant.swift b/star_lock/macos/Flutter/GeneratedPluginRegistrant.swift index 127e12ed..ff949269 100644 --- a/star_lock/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/star_lock/macos/Flutter/GeneratedPluginRegistrant.swift @@ -6,8 +6,11 @@ import FlutterMacOS import Foundation import aj_captcha_flutter +import audio_session +import audioplayers_darwin import device_info_plus import file_selector_macos +import just_audio import network_info_plus import package_info_plus import path_provider_foundation @@ -17,8 +20,11 @@ import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { AjCaptchaFlutterPlugin.register(with: registry.registrar(forPlugin: "AjCaptchaFlutterPlugin")) + AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin")) + AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) + JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin")) NetworkInfoPlusPlugin.register(with: registry.registrar(forPlugin: "NetworkInfoPlusPlugin")) FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) diff --git a/star_lock/pubspec.yaml b/star_lock/pubspec.yaml index 92daab09..f6749724 100644 --- a/star_lock/pubspec.yaml +++ b/star_lock/pubspec.yaml @@ -117,6 +117,14 @@ dependencies: video_player: ^2.7.2 #控制横竖屏控件 auto_orientation: ^2.3.1 + audioplayers: ^5.2.1 + g711_flutter: ^2.0.0 + ffi: ^2.1.0 + flutter_mjpeg: ^2.0.4 + image_gallery_saver: ^2.0.3 + convert: ^3.1.1 + just_audio: ^0.9.36 + flutter_sound: ^9.2.13 dev_dependencies: flutter_test: @@ -148,6 +156,7 @@ flutter: - images/lan/ - images/mine/ - images/lockType/ + - assets/ # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware diff --git a/star_lock/windows/flutter/generated_plugin_registrant.cc b/star_lock/windows/flutter/generated_plugin_registrant.cc index e2cbdfa4..c3bf33a2 100644 --- a/star_lock/windows/flutter/generated_plugin_registrant.cc +++ b/star_lock/windows/flutter/generated_plugin_registrant.cc @@ -7,6 +7,7 @@ #include "generated_plugin_registrant.h" #include +#include #include #include #include @@ -14,6 +15,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { AjCaptchaFlutterPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("AjCaptchaFlutterPluginCApi")); + AudioplayersWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin")); FileSelectorWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("FileSelectorWindows")); PermissionHandlerWindowsPluginRegisterWithRegistrar( diff --git a/star_lock/windows/flutter/generated_plugins.cmake b/star_lock/windows/flutter/generated_plugins.cmake index fda93fcf..f7d39f56 100644 --- a/star_lock/windows/flutter/generated_plugins.cmake +++ b/star_lock/windows/flutter/generated_plugins.cmake @@ -4,6 +4,7 @@ list(APPEND FLUTTER_PLUGIN_LIST aj_captcha_flutter + audioplayers_windows file_selector_windows permission_handler_windows url_launcher_windows From 4cbcd4a536559091cd87973ea54b7d4da983593e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AD=8F=E5=B0=91=E9=98=B3?= <786612630@qq.com> Date: Mon, 11 Dec 2023 13:44:15 +0800 Subject: [PATCH 02/33] =?UTF-8?q?Flutter=E6=B7=BB=E5=8A=A0UDP=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E4=BC=A0=E8=BE=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ios/Runner.xcodeproj/project.pbxproj | 22 +-- .../XSTalkManager/Utils/UDP/UdpHelper.m | 22 ++- .../blue/io_protocol/io_configuringWifi.dart | 14 ++ star_lock/lib/blue/io_reply.dart | 3 +- star_lock/lib/blue/io_tool/io_manager.dart | 2 +- star_lock/lib/blue/io_tool/io_model.dart | 4 +- star_lock/lib/blue/sender_data.dart | 4 +- star_lock/lib/blue/sender_manage.dart | 4 + .../configuringWifi_logic.dart | 47 ++++- .../lcokSet/lockSet/lockSet_logic.dart | 2 +- .../lcokSet/lockSet/lockSet_page.dart | 16 +- .../lockDetail/lockDetail_logic.dart | 2 + .../lockMian/lockMain/lockMain_logic.dart | 7 +- .../lockMian/lockMain/lockMain_state.dart | 4 + .../mine/addLock/saveLock/saveLock_logic.dart | 4 +- .../lib/mine/mine/starLockMine_state.dart | 2 +- star_lock/lib/network/api.dart | 2 + .../lib/talk/udp/io_protocol/udp_heart.dart | 90 +++++++++ .../udp/io_protocol/udp_mainProtocol.dart | 75 +++++++ .../talk/udp/io_protocol/udp_openDoor.dart | 2 + star_lock/lib/talk/udp/io_udpSender.dart | 40 ++++ star_lock/lib/talk/udp/io_udpType.dart | 50 +++++ star_lock/lib/talk/udp/udp_help.dart | 150 ++++++++++++++ star_lock/lib/talk/udp/udp_manage.dart | 114 +++++++++++ star_lock/lib/talk/udp/udp_reciverData.dart | 187 ++++++++++++++++++ star_lock/lib/talk/udp/udp_reply.dart | 13 ++ star_lock/lib/talk/udp/udp_senderData.dart | 46 +++++ star_lock/lib/talk/udp/udp_senderManage.dart | 41 ++++ star_lock/lib/talk/udp/udp_talkClass.dart | 113 +++++++++++ star_lock/lib/tools/storage.dart | 10 + star_lock/pubspec.yaml | 2 + 31 files changed, 1046 insertions(+), 48 deletions(-) create mode 100644 star_lock/lib/talk/udp/io_protocol/udp_heart.dart create mode 100644 star_lock/lib/talk/udp/io_protocol/udp_mainProtocol.dart create mode 100644 star_lock/lib/talk/udp/io_protocol/udp_openDoor.dart create mode 100644 star_lock/lib/talk/udp/io_udpSender.dart create mode 100644 star_lock/lib/talk/udp/io_udpType.dart create mode 100644 star_lock/lib/talk/udp/udp_help.dart create mode 100644 star_lock/lib/talk/udp/udp_manage.dart create mode 100644 star_lock/lib/talk/udp/udp_reciverData.dart create mode 100644 star_lock/lib/talk/udp/udp_reply.dart create mode 100644 star_lock/lib/talk/udp/udp_senderData.dart create mode 100644 star_lock/lib/talk/udp/udp_senderManage.dart create mode 100644 star_lock/lib/talk/udp/udp_talkClass.dart diff --git a/star_lock/ios/Runner.xcodeproj/project.pbxproj b/star_lock/ios/Runner.xcodeproj/project.pbxproj index ce180cb5..c4056a2b 100644 --- a/star_lock/ios/Runner.xcodeproj/project.pbxproj +++ b/star_lock/ios/Runner.xcodeproj/project.pbxproj @@ -348,18 +348,18 @@ isa = PBXGroup; children = ( 8297E4132AE75BEE00E886FA /* Msg.m */, - 8297E4142AE75BEE00E886FA /* UI.h */, - 8297E4152AE75BEE00E886FA /* HttpManager.h */, - 8297E4162AE75BEE00E886FA /* UDP */, - 8297E41B2AE75BEE00E886FA /* Sformat.m */, - 8297E41C2AE75BEE00E886FA /* Pub.h */, - 8297E41D2AE75BEE00E886FA /* sysInfo.h */, 8297E41E2AE75BEE00E886FA /* Msg.h */, - 8297E41F2AE75BEE00E886FA /* Sformat.h */, - 8297E4202AE75BEE00E886FA /* HttpManager.m */, + 8297E4142AE75BEE00E886FA /* UI.h */, 8297E4212AE75BEE00E886FA /* UI.m */, - 8297E4222AE75BEE00E886FA /* sysInfo.m */, + 8297E41C2AE75BEE00E886FA /* Pub.h */, 8297E4232AE75BEE00E886FA /* Pub.m */, + 8297E41F2AE75BEE00E886FA /* Sformat.h */, + 8297E41B2AE75BEE00E886FA /* Sformat.m */, + 8297E4152AE75BEE00E886FA /* HttpManager.h */, + 8297E4202AE75BEE00E886FA /* HttpManager.m */, + 8297E41D2AE75BEE00E886FA /* sysInfo.h */, + 8297E4222AE75BEE00E886FA /* sysInfo.m */, + 8297E4162AE75BEE00E886FA /* UDP */, 8297E4242AE75BEE00E886FA /* Talk */, ); path = Utils; @@ -428,7 +428,6 @@ 8297E4562AE75D4E00E886FA /* OpenPwd.m */, 8297E4572AE75D4E00E886FA /* P2pTest.h */, 8297E4582AE75D4E00E886FA /* Web.m */, - 8297E4592AE75D4E00E886FA /* Call.h */, 8297E45A2AE75D4E00E886FA /* Setting.m */, 8297E45B2AE75D4E00E886FA /* FaceUpload.m */, 8297E45C2AE75D4E00E886FA /* EquAdd.m */, @@ -439,8 +438,9 @@ 8297E4612AE75D4E00E886FA /* P2pTest.m */, 8297E4622AE75D4E00E886FA /* EquConfig.h */, 8297E4632AE75D4E00E886FA /* Setting.h */, - 8297E4642AE75D4E00E886FA /* Call.m */, 8297E4652AE75D4E00E886FA /* Web.h */, + 8297E4592AE75D4E00E886FA /* Call.h */, + 8297E4642AE75D4E00E886FA /* Call.m */, ); path = NextPage; sourceTree = ""; diff --git a/star_lock/ios/Runner/XSTalkManager/Utils/UDP/UdpHelper.m b/star_lock/ios/Runner/XSTalkManager/Utils/UDP/UdpHelper.m index 81bcd528..c5764edd 100755 --- a/star_lock/ios/Runner/XSTalkManager/Utils/UDP/UdpHelper.m +++ b/star_lock/ios/Runner/XSTalkManager/Utils/UDP/UdpHelper.m @@ -42,15 +42,18 @@ { _udp_datas = [[NSMutableArray alloc] init]; udp_data_class *list; - _udp_list = [[udp_data_class alloc] init]; +// _udp_list = [[udp_data_class alloc] init]; for (int i=0; i-1){ [[Pub getApp] OpenDoorFail:[Pub getEquidFrombb:bb at:9]]; diff --git a/star_lock/lib/blue/io_protocol/io_configuringWifi.dart b/star_lock/lib/blue/io_protocol/io_configuringWifi.dart index d7865623..19500262 100644 --- a/star_lock/lib/blue/io_protocol/io_configuringWifi.dart +++ b/star_lock/lib/blue/io_protocol/io_configuringWifi.dart @@ -17,6 +17,8 @@ class SenderConfiguringWifiCommand extends SenderProtocol { String? password; int? numberOfServers; List? listOfServers; + int? numberOfPhone; + List? listOfPhone; List? token; int? needAuthor; List? publicKey; @@ -29,6 +31,8 @@ class SenderConfiguringWifiCommand extends SenderProtocol { this.password, this.numberOfServers, this.listOfServers, + this.numberOfPhone, + this.listOfPhone, this.token, this.needAuthor, this.publicKey, @@ -78,6 +82,16 @@ class SenderConfiguringWifiCommand extends SenderProtocol { // listOfServers subData.addAll(listOfServers!); + // NumberOfPhone + subData.add(numberOfPhone!); + + // listOfPhone + listOfPhone!.forEach((element) { + int phoneLength = utf8.encode(element).length; + subData.addAll(utf8.encode(element)); + subData = getFixedLengthList(subData, 20 - phoneLength); + }); + // token // subData.addAll(token!); diff --git a/star_lock/lib/blue/io_reply.dart b/star_lock/lib/blue/io_reply.dart index 05e9b7c2..bd63ff10 100644 --- a/star_lock/lib/blue/io_reply.dart +++ b/star_lock/lib/blue/io_reply.dart @@ -1,7 +1,6 @@ + import 'io_type.dart'; - - abstract class Reply{ CommandType? commandType; diff --git a/star_lock/lib/blue/io_tool/io_manager.dart b/star_lock/lib/blue/io_tool/io_manager.dart index 4fa5cdbf..7b8e51e8 100644 --- a/star_lock/lib/blue/io_tool/io_manager.dart +++ b/star_lock/lib/blue/io_tool/io_manager.dart @@ -21,7 +21,7 @@ class IoManager { ///蓝牙传输协议 void bleTransmission() => _dataTransmissionMode = DataTransmissionMode.ble; - ///割草机协议帧序号 + ///协议帧序号 int _commandIndex = 1; configCommandIdx(int idx) => _commandIndex = idx; Future increaseCommandIndex() async { diff --git a/star_lock/lib/blue/io_tool/io_model.dart b/star_lock/lib/blue/io_tool/io_model.dart index 2c8f64cb..9651fff6 100644 --- a/star_lock/lib/blue/io_tool/io_model.dart +++ b/star_lock/lib/blue/io_tool/io_model.dart @@ -3,11 +3,13 @@ import 'package:uuid/uuid.dart'; ///发送数据类 enum DataChannel{ - ble + ble, + udp } extension Extension on DataChannel { bool get isBLE => this == DataChannel.ble; + bool get isUDP => this == DataChannel.udp; } class EventSendModel { diff --git a/star_lock/lib/blue/sender_data.dart b/star_lock/lib/blue/sender_data.dart index 33ad7b73..38ef5ad9 100644 --- a/star_lock/lib/blue/sender_data.dart +++ b/star_lock/lib/blue/sender_data.dart @@ -24,9 +24,7 @@ class CommandSenderManager { bool canSendControlCommand = false; //TODO:发送常规数据 - Future managerSendData ({ - required SenderProtocol command, - CommandSendCallBack? callBack}) async { + Future managerSendData ({required SenderProtocol command, CommandSendCallBack? callBack}) async { if (callBack != null) { // if (!BluetoothManager().connected) { print('❌ 蓝牙断开了'); diff --git a/star_lock/lib/blue/sender_manage.dart b/star_lock/lib/blue/sender_manage.dart index 6f9531ae..2c993a92 100644 --- a/star_lock/lib/blue/sender_manage.dart +++ b/star_lock/lib/blue/sender_manage.dart @@ -519,6 +519,8 @@ class IoSenderManage { required String? password, required int? numberOfServers, required List? listOfServers, + required int? numberOfPhone, + required List? listOfPhone, required List? token, required int? needAuthor, required List? publicKey, @@ -532,6 +534,8 @@ class IoSenderManage { password: password, numberOfServers: numberOfServers, listOfServers: listOfServers, + numberOfPhone: numberOfPhone, + listOfPhone: listOfPhone, token: token, needAuthor: needAuthor, publicKey: publicKey, diff --git a/star_lock/lib/main/lockDetail/lcokSet/configuringWifi/configuringWifi_logic.dart b/star_lock/lib/main/lockDetail/lcokSet/configuringWifi/configuringWifi_logic.dart index a5805f28..c440aeaa 100644 --- a/star_lock/lib/main/lockDetail/lcokSet/configuringWifi/configuringWifi_logic.dart +++ b/star_lock/lib/main/lockDetail/lcokSet/configuringWifi/configuringWifi_logic.dart @@ -1,5 +1,7 @@ import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; import 'package:flutter_reactive_ble/flutter_reactive_ble.dart'; import 'package:network_info_plus/network_info_plus.dart'; @@ -14,12 +16,15 @@ import '../../../../blue/io_tool/io_manager.dart'; import '../../../../blue/io_tool/io_tool.dart'; import '../../../../blue/io_tool/manager_event_bus.dart'; import '../../../../blue/sender_manage.dart'; +import '../../../../login/login/entity/LoginData.dart'; +import '../../../../mine/mine/starLockMine_state.dart'; import '../../../../network/api_repository.dart'; import '../../../../tools/storage.dart'; import 'configuringWifi_state.dart'; class ConfiguringWifiLogic extends BaseGetXController{ final ConfiguringWifiState state = ConfiguringWifiState(); + final StarLockMineState getInfostate = StarLockMineState(); Future getWifiLockServiceIpAndPort() async { var entity = await ApiRepository.to.getWifiLockServiceIpAndPort(); @@ -58,7 +63,7 @@ class ConfiguringWifiLogic extends BaseGetXController{ // WIFI配网结果 Future _replySenderConfiguringWifi(Reply reply) async { - int status = reply.data[6]; + int status = reply.data[5]; print("status:$status"); switch(status){ @@ -97,6 +102,7 @@ class ConfiguringWifiLogic extends BaseGetXController{ serversList.add(type2); } + var phoneList = [getInfostate.mobile()]; IoSenderManage.senderConfiguringWifiCommand( keyID: state.lockSetInfoData.value.lockBasicInfo!.keyId.toString(), userID: await Storage.getUid(), @@ -104,6 +110,8 @@ class ConfiguringWifiLogic extends BaseGetXController{ password: state.wifiPWDController.text, numberOfServers: state.configuringWifiEntity.value.data!.serviceNum, listOfServers: serversList, + numberOfPhone: phoneList.length, + listOfPhone: phoneList, token: tokenData, needAuthor: 1, publicKey: publicKeyDataList, @@ -147,18 +155,35 @@ class ConfiguringWifiLogic extends BaseGetXController{ var serversList = []; for(int i = 0; i addresses = await InternetAddress.lookup(item.serviceIp!); + var itemList = addresses.first.address.split("."); + for (var element in itemList) { + serversList.add(int.parse(element)); + } + print('Resolved google.com to address: ${addresses.first.address} serversList:${serversList}'); - double typeDouble = int.parse(item.port!) / 256; - int type1 = typeDouble.toInt(); - int type2 = int.parse(item.port!) % 256; - serversList.add(type1); - serversList.add(type2); + double typeDouble = int.parse(item.port!) / 256; + int type1 = typeDouble.toInt(); + int type2 = int.parse(item.port!) % 256; + serversList.add(type1); + serversList.add(type2); + } } + String? phone = ''; + final data = await Storage.getString('userLoginData'); + if (data != null && data.isNotEmpty) { + phone = LoginData.fromJson(jsonDecode(data)).mobile; + } + var phoneList = [phone!]; + print("phoneList:$phoneList"); + IoSenderManage.senderConfiguringWifiCommand( keyID: state.lockSetInfoData.value.lockBasicInfo!.keyId.toString(), userID: await Storage.getUid(), @@ -166,6 +191,8 @@ class ConfiguringWifiLogic extends BaseGetXController{ password: state.wifiPWDController.text, numberOfServers: state.configuringWifiEntity.value.data!.serviceNum, listOfServers: serversList, + numberOfPhone: phoneList.length, + listOfPhone: phoneList, token: getTokenList, needAuthor: 1, publicKey: publicKeyDataList, diff --git a/star_lock/lib/main/lockDetail/lcokSet/lockSet/lockSet_logic.dart b/star_lock/lib/main/lockDetail/lcokSet/lockSet/lockSet_logic.dart index c3abf1ad..08ccd6e6 100644 --- a/star_lock/lib/main/lockDetail/lcokSet/lockSet/lockSet_logic.dart +++ b/star_lock/lib/main/lockDetail/lcokSet/lockSet/lockSet_logic.dart @@ -416,7 +416,7 @@ class LockSetLogic extends BaseGetXController { password: state.passwordTF.text, ); if (entity.errorCode!.codeIsSuccessful) { - // deletLockInfoData(); + deletLockInfoData(); blockDeletNumberCheckPasswordCallback(); // if(state.currentDeviceUUid.value.isEmpty){ diff --git a/star_lock/lib/main/lockDetail/lcokSet/lockSet/lockSet_page.dart b/star_lock/lib/main/lockDetail/lcokSet/lockSet/lockSet_page.dart index 92e77479..4c91282e 100644 --- a/star_lock/lib/main/lockDetail/lcokSet/lockSet/lockSet_page.dart +++ b/star_lock/lib/main/lockDetail/lcokSet/lockSet/lockSet_page.dart @@ -423,11 +423,11 @@ class _LockSetPageState extends State with RouteAware { ), SizedBox(height: 10.h), // wifi配网 - Obx( - () => Visibility( - visible: - state.lockFeature.value.wifi == 1 ? true : false, - child: + // Obx( + // () => Visibility( + // visible: + // state.lockFeature.value.wifi == 1 ? true : false, + // child: CommonItem( leftTitel: TranslationLoader.lanKeys!.wifiDistributionNetwork!.tr, rightTitle: "", @@ -439,9 +439,9 @@ class _LockSetPageState extends State with RouteAware { 'lockSetInfoData': state.lockSetInfoData.value }); - }) - ), - ), + }), + // ), + // ), // Obx(() => // 锁时间 Visibility( diff --git a/star_lock/lib/main/lockDetail/lockDetail/lockDetail_logic.dart b/star_lock/lib/main/lockDetail/lockDetail/lockDetail_logic.dart index 92cf3e5a..6f53a39c 100644 --- a/star_lock/lib/main/lockDetail/lockDetail/lockDetail_logic.dart +++ b/star_lock/lib/main/lockDetail/lockDetail/lockDetail_logic.dart @@ -569,6 +569,8 @@ class LockDetailLogic extends BaseGetXController{ super.onInit(); // print("lockDetail_onInit()"); + print("lockDetail_onInit()"); + // 进来获取锁状态 // connectBlue(); // factoryDataResetAction(); diff --git a/star_lock/lib/main/lockMian/lockMain/lockMain_logic.dart b/star_lock/lib/main/lockMian/lockMain/lockMain_logic.dart index 2f84ecf2..3c670828 100644 --- a/star_lock/lib/main/lockMian/lockMain/lockMain_logic.dart +++ b/star_lock/lib/main/lockMian/lockMain/lockMain_logic.dart @@ -2,9 +2,11 @@ import 'dart:async'; import 'package:get/get.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:star_lock/talk/udp/udp_senderManage.dart'; import '../../../blue/io_tool/manager_event_bus.dart'; import '../../../network/api_repository.dart'; +import '../../../talk/udp/udp_help.dart'; import '../../../tools/baseGetXController.dart'; import '../../../tools/eventBusEventManage.dart'; import '../entity/lockListInfo_entity.dart'; @@ -106,7 +108,6 @@ class LockMainLogic extends BaseGetXController { }); } - @override void onReady() { // TODO: implement onReady @@ -114,6 +115,9 @@ class LockMainLogic extends BaseGetXController { print("onReady()"); _initLoadDataAction(); + + // 开启UDP + UdpHelp().openUDP(); } @override @@ -133,6 +137,7 @@ class LockMainLogic extends BaseGetXController { // refreshController.dispose(); _teamEvent.cancel(); + // state.timer.cancel(); } } \ No newline at end of file diff --git a/star_lock/lib/main/lockMian/lockMain/lockMain_state.dart b/star_lock/lib/main/lockMian/lockMain/lockMain_state.dart index fb53a05b..a0d128eb 100644 --- a/star_lock/lib/main/lockMian/lockMain/lockMain_state.dart +++ b/star_lock/lib/main/lockMian/lockMain/lockMain_state.dart @@ -1,4 +1,6 @@ +import 'dart:async'; + import 'package:get/get.dart'; import '../entity/lockListInfo_entity.dart'; @@ -7,4 +9,6 @@ class LockMainState { // 0是无数据 1是有一条数据 2是有很多条数据 var dataLength = 100.obs; var lockListInfoEntity = LockListInfoEntity().obs; + + // late Timer timer; } \ No newline at end of file diff --git a/star_lock/lib/mine/addLock/saveLock/saveLock_logic.dart b/star_lock/lib/mine/addLock/saveLock/saveLock_logic.dart index f6907287..255a9842 100644 --- a/star_lock/lib/mine/addLock/saveLock/saveLock_logic.dart +++ b/star_lock/lib/mine/addLock/saveLock/saveLock_logic.dart @@ -204,7 +204,7 @@ class SaveLockLogic extends BaseGetXController { String featureValueStr = asciiString(featureValue); state.featureValue = featureValueStr; // List allFeatureValueTwoList = charListChangeIntList(featureValue); - // print("featureValueLength:$featureValueLength featureValue:$featureValue \n featureValueStr:$featureValueStr"); + print("featureValueLength:$featureValueLength featureValue:$featureValue \n featureValueStr:$featureValueStr"); index = index + featureValueLength + 1; // 使能特征值字符串长度 @@ -214,7 +214,7 @@ class SaveLockLogic extends BaseGetXController { String featureEnValStr = asciiString(featureValue); state.featureSettingValue = featureEnValStr; // List allFeatureEnValTwoList = charListChangeIntList(featureEnVal); - // print("featureEnValLength:$featureEnValLength featureEnVal:$featureEnVal \n featureEnValStr:$featureEnValStr"); + print("featureEnValLength:$featureEnValLength featureEnVal:$featureEnVal \n featureEnValStr:$featureEnValStr"); index = index + featureEnValLength + 1; // 支持的带参数特征值的总条目数 diff --git a/star_lock/lib/mine/mine/starLockMine_state.dart b/star_lock/lib/mine/mine/starLockMine_state.dart index 1008ae15..6470ce7e 100644 --- a/star_lock/lib/mine/mine/starLockMine_state.dart +++ b/star_lock/lib/mine/mine/starLockMine_state.dart @@ -37,7 +37,7 @@ class StarLockMineState { } String mobile() { - return loginData.value.mobile ?? '-'; + return loginData.value.mobile ?? ''; } String email() { diff --git a/star_lock/lib/network/api.dart b/star_lock/lib/network/api.dart index 73432872..f561dd85 100644 --- a/star_lock/lib/network/api.dart +++ b/star_lock/lib/network/api.dart @@ -1,7 +1,9 @@ abstract class Api { static String baseAddress = "https://pre.lock.star-lock.cn:8093"; //预发布环境 + // static String baseAddress = "http://192.168.56.101:8099"; //联调环境 final String baseUrl = "$baseAddress/api"; + // final String baseUrl = "http://test.lock.star-lock.cn/api"; // 葛工 // final String baseUrl = "https://lock.star-lock.cn/api"; // 测试环境 // final String baseUrl = "http://wenlin.lock.star-lock.cn/api"; //曾工 diff --git a/star_lock/lib/talk/udp/io_protocol/udp_heart.dart b/star_lock/lib/talk/udp/io_protocol/udp_heart.dart new file mode 100644 index 00000000..43b319ae --- /dev/null +++ b/star_lock/lib/talk/udp/io_protocol/udp_heart.dart @@ -0,0 +1,90 @@ + +import 'dart:convert'; + +import 'package:star_lock/tools/toast.dart'; + +import '../../../blue/io_tool/io_tool.dart'; +import 'package:fast_gbk/fast_gbk.dart'; + +import '../io_udpSender.dart'; +import '../io_udpType.dart'; +import '../udp_reply.dart'; + +class UDPSendHeartCommand extends UDPSenderProtocol { + + String? userName; + List? ipList; + String? tokenStr; + + UDPSendHeartCommand({ + this.userName, + this.ipList, + this.tokenStr, + }) : super(CommandUDPType.heart); + + @override + List messageDetail() { + List data = []; + + // 命令 + data.add(4); + + // 命令类型 + data.add(1); + + // 用户名 P18682150237 + // var pStr = "P18682150237"; + data.addAll(utf8.encode(userName!)); + data = getFixedLengthList(data, 20 - utf8.encode(userName!).length); + + // data.add(0); + + // mac地址 + // var macAddress = "02:00:00:00:00:00"; + // data.addAll(utf8.encode(macAddress)); + // data = getFixedLengthList(data, 6 - utf8.encode(macAddress).length); + data.addAll([0, 0, 0, 0, 0, 0]); + + // 预留4个字节 + data.addAll([0, 0, 0, 0]); + + // ip地址 + // var ipStr = "192.168.9.7"; + // data.addAll(utf8.encode(ipStr!)); + // data = getFixedLengthList(data, 12 - utf8.encode(ipStr!).length); + data.addAll(ipList!); + + // 预留8个字节 + data.addAll([0, 0, 0, 0, 0, 0, 0, 0]); + + // token + var token = "token"; + data.addAll(gbk.encode(token)); + data = getFixedLengthList(data, 10 - gbk.encode(token).length); + // print("gbk.encode(token):${gbk.encode(token)}"); + + // tokenStr + // var tokenStr = "b989fa15f75c2ac02718b7c9bb64f80e"; + data.addAll(gbk.encode(tokenStr!)); + // print("gbk.encode(tokenStr):${gbk.encode(tokenStr!)}"); + + var tokenStrLength = gbk.encode(tokenStr!).length; + List tokenStrLengthArr = []; + tokenStrLengthArr.add((tokenStrLength & 0xff)); + tokenStrLengthArr.add((tokenStrLength & 0xff00) >> 8); + tokenStrLengthArr.add((tokenStrLength & 0xff0000) >> 16); + tokenStrLengthArr.add((tokenStrLength & 0xff000000) >> 24); + data.setRange(37, 41, tokenStrLengthArr); + + // print("UDPSendHeartData:$data"); + + return data; + } +} + +class UDPSendHeartReply extends UDPReply { + UDPSendHeartReply.parseData(CommandUDPType commandType, List dataDetail) + : super.parseData(commandType, dataDetail) { + data = dataDetail; + } +} diff --git a/star_lock/lib/talk/udp/io_protocol/udp_mainProtocol.dart b/star_lock/lib/talk/udp/io_protocol/udp_mainProtocol.dart new file mode 100644 index 00000000..8fb2fada --- /dev/null +++ b/star_lock/lib/talk/udp/io_protocol/udp_mainProtocol.dart @@ -0,0 +1,75 @@ + +import 'dart:convert'; + +import '../../../blue/io_tool/io_tool.dart'; + +import '../io_udpSender.dart'; +import '../io_udpType.dart'; +import '../udp_reply.dart'; + +class UDPMainProtocolCommand extends UDPSenderProtocol { + + int? command; + int? commandTypeIsCalling; + int? subCommand; + String? lockID; + String? lockIP; + String? userMobile; + String? userMobileIP; + List? data; + + UDPMainProtocolCommand({ + this.command, + this.commandTypeIsCalling, + this.subCommand, + this.lockID, + this.lockIP, + this.userMobile, + this.userMobileIP, + this.data, + }) : super(CommandUDPType.heart); + + @override + List messageDetail() { + List data = []; + + // 命令 + data.add(command!); + + // 命令类型 + data.add(commandTypeIsCalling!); + + // 子命令 + data.add(subCommand!); + + // lockID + data.addAll(utf8.encode(lockID!)); + data = getFixedLengthList(data, 20 - utf8.encode(lockID!).length); + + // lockIP + var lockIPList = lockIP!.split("."); + lockIPList.forEach((element) { + data.add(int.parse(element)); + }); + + // userMobile + data.addAll(utf8.encode(userMobile!)); + data = getFixedLengthList(data, 20 - utf8.encode(userMobile!).length); + + // userMobileIP + var userMobileIPList = lockIP!.split("."); + userMobileIPList.forEach((element) { + data.add(int.parse(element)); + }); + + // print("datadatadata:$data"); + return data; + } +} + +class UDPMainProtocolReply extends UDPReply { + UDPMainProtocolReply.parseData(CommandUDPType commandType, List dataDetail) + : super.parseData(commandType, dataDetail) { + data = dataDetail; + } +} diff --git a/star_lock/lib/talk/udp/io_protocol/udp_openDoor.dart b/star_lock/lib/talk/udp/io_protocol/udp_openDoor.dart new file mode 100644 index 00000000..139597f9 --- /dev/null +++ b/star_lock/lib/talk/udp/io_protocol/udp_openDoor.dart @@ -0,0 +1,2 @@ + + diff --git a/star_lock/lib/talk/udp/io_udpSender.dart b/star_lock/lib/talk/udp/io_udpSender.dart new file mode 100644 index 00000000..6215271a --- /dev/null +++ b/star_lock/lib/talk/udp/io_udpSender.dart @@ -0,0 +1,40 @@ + +import 'dart:convert'; + +import '../../blue/io_tool/io_tool.dart'; +import 'io_udpType.dart'; + +abstract class IOData { + List messageDetail(); +} + +abstract class UDPSenderProtocol extends IOData { + // var uint8View1 = Uint8List(300); + + CommandUDPType? commandType; //指令类型 + // final List header = [0XEF, 0X01, 0XEE, 0X02]; //帧头 固定取值 0XEF01EE02,长度 4 字节 + // final int ask = 0X01 ; // 包类型:0X01 表示请求包,0X11 表示应答包,长度 1 字节 + + List? commandData = []; //数据块 + + UDPSenderProtocol(this.commandType) { + + } + + //TODO:拼装数据 + List packageData() { + commandData = messageDetail(); + List commandList = []; + + var cID = "XXXCID"; + commandList.addAll(utf8.encode(cID)); + commandList = getFixedLengthList(commandList, 6 - utf8.encode(cID).length); + + // 数据块 + commandList.addAll(commandData!); //数据块 + // print("commandList:$commandList"); + return commandList; + } + + +} \ No newline at end of file diff --git a/star_lock/lib/talk/udp/io_udpType.dart b/star_lock/lib/talk/udp/io_udpType.dart new file mode 100644 index 00000000..af2fa485 --- /dev/null +++ b/star_lock/lib/talk/udp/io_udpType.dart @@ -0,0 +1,50 @@ + +//TODO:发送指令类型 +enum CommandUDPType { + heart, //心跳 = 4 + mainProtocol, // 150 +} + +extension ExtensionCommandType on CommandUDPType { + + static CommandUDPType getCommandType(int value){ + CommandUDPType type = CommandUDPType.heart; + switch(value){ + case 0x04: + { + type = CommandUDPType.heart; + } + break; + } + return type; + } + + int get typeValue { + int type = 0x04; + switch(this){ + case CommandUDPType.heart: + type = 0x04; + break; + case CommandUDPType.mainProtocol: + type = 0x96; + break; + } + // AppLog.log('数组组装指令类型:$name commandIndex:${IoManager + // ().commandIndex}'); + return type; + } + + + String get typeName { + String t = ''; + switch(typeValue){ + case 0x04: + t = '心跳'; + break; + case 0x96: + t = 'UDP主协议'; + break; + } + return t; + } +} \ No newline at end of file diff --git a/star_lock/lib/talk/udp/udp_help.dart b/star_lock/lib/talk/udp/udp_help.dart new file mode 100644 index 00000000..e3ae0ab1 --- /dev/null +++ b/star_lock/lib/talk/udp/udp_help.dart @@ -0,0 +1,150 @@ + + +import 'dart:async'; +import 'dart:io'; + +import 'package:get/get.dart'; + +import '../../network/api_repository.dart'; +import 'udp_manage.dart'; +import 'udp_senderManage.dart'; + +class UdpHelp{ + + openUDP() async { + // 从服务器获取ip跟端口 + var entity = await ApiRepository.to.getWifiLockServiceIpAndPort(); + if(entity.errorCode! == 0){ + UDPManage(); + // UDPManage().initUdp(); + // UDPManage().host = entity.data!.serviceList![0].serviceIp!; + // UDPManage().port = int.parse(entity.data!.serviceList![0].port!); + + var serversList = []; + for(int i = 0; i addresses = await InternetAddress.lookup(item.serviceIp!); + var itemList = addresses.first.address.split("."); + for (var element in itemList) { + serversList.add(int.parse(element)); + } + print('Resolved google.com to address: ${addresses.first.address} serversList:${serversList}'); + } + } + + Timer timer = Timer.periodic(1.seconds, (timer) { + UDPSenderManage.sendHeart( + userName: "15080825640", + ipList: serversList, + tokenStr: "b989fa15f75c2ac02718b7c9bb64f80e", + ); + }); + } + } + + Future getWifiLockServiceIpAndPort() async { + var entity = await ApiRepository.to.getWifiLockServiceIpAndPort(); + if(entity.errorCode! == 0){ + + } + } +} + +class UdpData { + bool isUsed = false; +} + +// class UdpSendThread { +// List udpDatas = []; +// bool udpSendTag = true; +// int udpSendTime = 0; +// +// UdpSendThread() { +// for (int i = 0; i < BUFNUM; i++) { +// udpDatas.add(UdpData()); +// } +// udpSend(); +// } +// +// void udpSend() async { +// while (udpSendTag) { +// while (udpSendTime <= 0) { +// await Future.delayed(Duration(seconds: 1)); +// } +// bool hasDataSend = true; +// while (hasDataSend) { +// hasDataSend = false; +// for (int i = 0; i < BUFNUM; i++) { +// UdpData udpList = udpDatas[i]; +// if (udpList.isUsed) { +// // Do something +// } else { +// // Do something else +// } +// } +// await Future.delayed(Duration(seconds: 1)); +// } +// udpSendTime--; +// } +// } +// } + + + + + + + + +// import 'dart:async'; +// +// class UdpSendCondition { +// bool udpSendTag = true; +// int udpSendTime = 0; +// List udpDatas = []; +// Isolate isolate; +// +// void start() async { +// final receivePort = ReceivePort(); +// isolate = await Isolate.spawn(_isolateEntry, receivePort.sendPort); +// +// receivePort.listen((message) { +// if (message == 'done') { +// udpSendTime--; +// if (udpSendTime <= 0) { +// stop(); +// } +// } +// }); +// } +// +// void stop() { +// if (isolate != null) { +// isolate.kill(priority: Isolate.immediate); +// isolate = null; +// } +// } +// } +// +// void _isolateEntry(SendPort sendPort) async { +// bool hasDataSend = true; +// while (hasDataSend) { +// hasDataSend = false; +// for (int i = 0; i < BUFNUM; i++) { +// var udpList = udpDatas[i]; +// if (udpList.isUsed) { +// // Do something +// } else { +// // Do something else +// } +// } +// await Future.delayed(Duration(seconds: 1)); +// } +// sendPort.send('done'); +// } \ No newline at end of file diff --git a/star_lock/lib/talk/udp/udp_manage.dart b/star_lock/lib/talk/udp/udp_manage.dart new file mode 100644 index 00000000..35922f14 --- /dev/null +++ b/star_lock/lib/talk/udp/udp_manage.dart @@ -0,0 +1,114 @@ + + +import 'dart:async'; +import 'dart:io'; + +import 'package:star_lock/talk/udp/udp_reciverData.dart'; + +import '../../blue/io_tool/io_model.dart'; +import '../../blue/io_tool/manager_event_bus.dart'; + +class UDPManage{ + static UDPManage? _manager; + + UDPManage._init() { + initUdp(); + _streamSubscription = EventBusManager().eventBus!.on().listen((EventSendModel sendModel) { + // print("sendModel.sendChannel:${sendModel.sendChannel}"); + if(sendModel.sendChannel == DataChannel.udp){ + List data = sendModel.data; + sendData(data); + } + }); + } + + static UDPManage _share(){ + _manager ??= UDPManage._init(); + return _manager!; + } + factory UDPManage() => _share(); + UDPManage get manager => _share(); + + StreamSubscription? _streamSubscription; + RawDatagramSocket? _udpSocket; + String host = '47.106.143.213'; + int port = 8056; + // String? _mIp = ''; + // String host = ''; + // int port = 0; + + void initUdp() async { + var listAddress = InternetAddress.lookup(host!); + listAddress.then((list) { + list.forEach((element) { + host = element.address; + }); + }); + await _initUdp(); + } + + Future _initUdp() async { + if(port == 0){ + print('❌ Udp ----> _port == 0'); + return; + } + var addressIListenFrom = InternetAddress.anyIPv4; + int portIListenOn = 62288; + RawDatagramSocket.bind(addressIListenFrom, portIListenOn).then((RawDatagramSocket socket){ + _udpSocket = socket; + ///广播功能 + _udpSocket!.broadcastEnabled = true; + _onReceiveData(socket); + }); + } + + + void _onReceiveData(RawDatagramSocket socket) { + socket.listen((RawSocketEvent event) { + if(event == RawSocketEvent.read){ + Datagram? dg = socket.receive(); + try { + print('Did received data on the stream (length --> ${dg!.data.length}) dg!.data:${dg!.data}'); + // EventBusManager().eventBusFir(EventReceiveModel(data: dg?.data,sendChannel: DataChannel.udp)); + CommandUDPReciverManager.appDataReceive(dg!.data); + } catch (e) { + print('❌ Udp ----> $e'); + } + } + }); + } + + void sendData(List data) { + if(null == _udpSocket || null == data || data.isEmpty || host == ''){ + if(null == _udpSocket ){ + print('❌ Udp ----> null == _udpSocket'); + initUdp(); + } + return; + } + try { + print("sendData:$data"); + var result = _udpSocket?.send(data, InternetAddress(host!), port!); + if(result != data.length) { + print('❌Udp ----> send data $result ${data.length}'); + _udpSocket = null; + } + }catch (e){ + + } + } + + bool exit() { + if(null != _udpSocket) { + print('❌ Udp ----> close'); + _udpSocket?.close(); + } + return true; + } + + + void disposed() { + _streamSubscription?.cancel(); + } + +} \ No newline at end of file diff --git a/star_lock/lib/talk/udp/udp_reciverData.dart b/star_lock/lib/talk/udp/udp_reciverData.dart new file mode 100644 index 00000000..3ff49c54 --- /dev/null +++ b/star_lock/lib/talk/udp/udp_reciverData.dart @@ -0,0 +1,187 @@ + +import 'dart:typed_data'; + +import '../../tools/toast.dart'; +import 'udp_talkClass.dart'; + +class CommandUDPReciverManager { + + static void appDataReceive(List data) async { + ///解析数据 + if(data.isEmpty){ + return; + } + int dataSize = data.length; + if(dataSize < 4){ + return; + } + // print("appDataReceiveData:$data"); + + Uint8List data1 = Uint8List.fromList(data); + if(data1.length==1){ + if(data[0]==0x30 || data[0]==0x31){ + print("p2p打洞"); + + } + } + + if (data[6] == 4) { + if(data[7] == 2){ + print("心跳包反馈 在线状态"); + } else if(data[7]==3) { + [Toast.show(msg: "您已在其他设备登录")]; + } + } else if (data[6] == 150) { + // if( [Pub getApp].isBack){ + // [_udp receiveWithTimeout:-1 tag:0]; + // return YES; + // } + + // 对讲命令 + // var beiCallType = data[8] & 0xff; + var beiCallType = 1 & 0xff; + print("被呼叫2 类型$beiCallType"); + switch (beiCallType) { + case 1:{ + //被叫 + UDPTalkClass().beCallW(data: data); + } + break; + case 6:{ + //接听 + if((data[7] & 0x3) == 2){//被叫 接听反馈 + print("接听反馈"); + + } + } + break; + case 7: + case 8:{//音视频数据 + //print("音视频数据"); + + } + break; + case 9:{ + if((data[7] & 0x3) == 1){//对方保持连接 + //print("对方保持连接"); + data[7] = 2; + + } + else{ + //print("保持连接反馈"); + + } + } + break; + case 10:{ + //开门反馈 + if((data[7] & 0x3) == 2){ + print("开门成功"); + + } + else{ + + } + } + break; + case 30:{ + //开门反馈 + if((data[7] & 0x3) == 1){ + //对方结束对讲 + print("对方结束对讲"); + + } else{ + //结束对讲反馈 + print("结束对讲反馈"); + + } + } + break; + case 140:{ + // p2p测试 + + } + break; + case 141:{ + // p2p测试 + + } + break; + case 142:{ + // p2p测试 + + } + break; + case 143:{ + //p2p测试 NSAsk + print("p2pNSAskNSAsk"); + } + break; + default: + break; + } + } else if (data[6] == 152) { + // 监视命令 + switch (data[8] & 0xff) { + case 2:{ + //被叫 + print("对方忙"); + } + break; + case 4:{ + //监视成功 + print("监视成功"); + + } + break; + case 7: + case 8:{//音视频数据 + //print("音视频数据"); + + } + break; + case 9:{ + //保持连接 + if((data[7] & 0x3) == 1){//对方保持连接 + //print("对方保持连接"); + data[7] = 2; + + } + else{ + //print("保持连接反馈"); + + } + } + break; + case 10:{ + //开门反馈 + if((data[7] & 0x3) == 2){ + print("开门成功"); + + } + else{ + + } + } + break; + case 30:{ + // 监视结束 + if((data[7] & 0x3) == 1){ + // 对方结束监视 + print("对方结束监视"); + + } else{ + //结束对讲反馈 + print("结束监视反馈"); + + } + } + break; + default: + break; + } + } + } + + +} diff --git a/star_lock/lib/talk/udp/udp_reply.dart b/star_lock/lib/talk/udp/udp_reply.dart new file mode 100644 index 00000000..152e2a88 --- /dev/null +++ b/star_lock/lib/talk/udp/udp_reply.dart @@ -0,0 +1,13 @@ + +import 'io_udpType.dart'; + +abstract class UDPReply{ + + CommandUDPType? commandType; + + //command key flag + int status = 0; + List data = []; + UDPReply.parseData(this.commandType, List dataDetail); + +} \ No newline at end of file diff --git a/star_lock/lib/talk/udp/udp_senderData.dart b/star_lock/lib/talk/udp/udp_senderData.dart new file mode 100644 index 00000000..1bf7c90b --- /dev/null +++ b/star_lock/lib/talk/udp/udp_senderData.dart @@ -0,0 +1,46 @@ + +import '../../app_settings/app_settings.dart'; +import '../../blue/io_tool/io_model.dart'; +import '../../blue/io_tool/manager_event_bus.dart'; +import 'io_udpSender.dart'; + +typedef CommandUDPSendCallBack = void Function(ErrorType errorType); + +class CommandUDPSenderManager { + + static final CommandUDPSenderManager _manager = CommandUDPSenderManager._init(); + factory CommandUDPSenderManager()=>_manager; + static CommandUDPSenderManager getInstance()=>_manager; + CommandUDPSenderManager._init(){ + init(); + } + + init(){ + + } + + //TODO:发送常规数据 + Future managerSendData ({required UDPSenderProtocol command, CommandUDPSendCallBack? callBack}) async { + if (callBack != null) { + // if (!BluetoothManager().connected) { + print('❌ 蓝牙断开了'); + if (callBack != null) { + print('managerSendData ❌ callBack'); + // EasyLoading.dismiss(); + callBack(ErrorType.notConnected); + } + return; + } + + List value = command.packageData(); + // print("sendData:${value}"); + _sendNormalData(value); + } + + void _sendNormalData(List data) async { + if (data.isNotEmpty) { + EventBusManager().eventBusFir(EventSendModel(data: data, sendChannel: DataChannel.udp)); + } + } + +} \ No newline at end of file diff --git a/star_lock/lib/talk/udp/udp_senderManage.dart b/star_lock/lib/talk/udp/udp_senderManage.dart new file mode 100644 index 00000000..4b15d39d --- /dev/null +++ b/star_lock/lib/talk/udp/udp_senderManage.dart @@ -0,0 +1,41 @@ + + +import 'io_protocol/udp_heart.dart'; +import 'io_protocol/udp_mainProtocol.dart'; +import 'udp_senderData.dart'; + +class UDPSenderManage { + + //todo:UDP心跳 + static void sendHeart({String? userName, List? ipList, String? tokenStr, CommandUDPSendCallBack? callBack}) { + CommandUDPSenderManager().managerSendData(command: UDPSendHeartCommand( + userName: userName, + ipList: ipList, + tokenStr: tokenStr, + ), callBack: callBack); + } + + //todo:主通讯协议 + static void sendMainProtocol({ + int? command, + int? commandTypeIsCalling, + int? subCommand, + String? lockID, + String? lockIP, + String? userMobile, + String? userMobileIP, + List? data, + CommandUDPSendCallBack? callBack}) { + CommandUDPSenderManager().managerSendData(command: UDPMainProtocolCommand( + command: command, + commandTypeIsCalling: commandTypeIsCalling, + subCommand: subCommand, + lockID: lockID, + lockIP: lockIP, + userMobile: userMobile, + userMobileIP: userMobileIP, + data: data, + ), callBack: callBack); + } + +} \ No newline at end of file diff --git a/star_lock/lib/talk/udp/udp_talkClass.dart b/star_lock/lib/talk/udp/udp_talkClass.dart new file mode 100644 index 00000000..0d5463f7 --- /dev/null +++ b/star_lock/lib/talk/udp/udp_talkClass.dart @@ -0,0 +1,113 @@ + +import 'dart:async'; + +import 'package:fast_gbk/fast_gbk.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import '../../appRouters.dart'; +import '../../main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart'; +import '../../tools/storage.dart'; +import 'udp_manage.dart'; + +class UDPTalkClass{ + static UDPTalkClass? _manager; + static UDPTalkClass _share(){ + _manager ??= UDPTalkClass._init(); + return _manager!; + } + factory UDPTalkClass() => _share(); + UDPTalkClass get manager => _share(); + + UDPTalkClass._init() { + + } + + var status = 0;// 0空闲 + var remoteEquid; + late Timer timer; + // 该字段是为了判断是否跳转到接听界面 挂断或者退出接听界面要记得变更状态 + var isBeCall = false; + + beCallW({List? data, String? ip, int? port}) async { + print("beCall"); + // if (await isCallMe(data)) { + // return; + // } + + if(status == 0){ + // 空闲 + // 响铃 + // [[Pub getApp] ring]; + remoteEquid = getEquidFrombb(data, 9); + status = 6; + + data![7] = 1; + data[8] = 4; + UDPManage().sendData(data); + + data[7] = 1; + data[8] = 5; + UDPManage().sendData(data); + + // Get.to(MaterialPageRoute( + // builder: (context) { + // return const LockMonitoringPage(); + // }, + // fullscreenDialog: true + // )); + + if(UDPTalkClass().isBeCall == false){ + UDPTalkClass().isBeCall = true; + timer = Timer.periodic(1.seconds, (timer) { + data[7] = 1; + data[8] = 9; + UDPManage().sendData(data); + }); + } + + Get.toNamed(Routers.lockMonitoringPage, arguments: { + "lockId": "111" + }); + }else{ + // 忙 + + } + } + + // 判断是否是call的本人 + Future isCallMe(List? data) async { + final loginData = await Storage.getLoginData(); + print("getEquidFrombb(data, 1000):${getEquidFrombb(data, 12)}"); + if(loginData!.mobile == getEquidFrombb(data, 12)){ + return true; + } + return false; + } + + String getEquidFrombb(List? bb, int pos) { + var equid = ""; + int equlen = 8; + + if (bb![pos] == 77) { //M + equlen = 8; + } else if (bb[pos] == 87) { //W + equlen = 5; + } else if (bb[pos] == 72) { //H + equlen = 12; + } else if (bb[pos] == 83) { //S + equlen = 12; + } else if (bb[pos] == 0x50) { //P + equlen = 12; + } else if (bb[pos] == 0x54) { //T + equlen = 16; + } else { + equlen = 12; + } + + List tempbb = bb.sublist(pos, pos + equlen); + equid = gbk.decode(tempbb); + return equid; + } + +} \ No newline at end of file diff --git a/star_lock/lib/tools/storage.dart b/star_lock/lib/tools/storage.dart index dbc50b2c..110da77d 100644 --- a/star_lock/lib/tools/storage.dart +++ b/star_lock/lib/tools/storage.dart @@ -145,5 +145,15 @@ class Storage { return userId; } + static Future getLoginData() async { + LoginData? loginData; + final data = await Storage.getString('userLoginData'); + if (data != null && data.isNotEmpty) { + loginData = LoginData.fromJson(jsonDecode(data)); + } + print("loginData:$loginData"); + return loginData; + } + } diff --git a/star_lock/pubspec.yaml b/star_lock/pubspec.yaml index 92daab09..765801dd 100644 --- a/star_lock/pubspec.yaml +++ b/star_lock/pubspec.yaml @@ -118,6 +118,8 @@ dependencies: #控制横竖屏控件 auto_orientation: ^2.3.1 + fast_gbk: ^1.0.0 + dev_dependencies: flutter_test: sdk: flutter From c2823155b4bb4b14bb5eca963c6453cac1e1d981 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AD=8F=E5=B0=91=E9=98=B3?= <786612630@qq.com> Date: Mon, 18 Dec 2023 16:03:05 +0800 Subject: [PATCH 03/33] =?UTF-8?q?=E8=B0=83=E8=AF=95=E5=AF=B9=E8=AE=B2?= =?UTF-8?q?=E8=A7=86=E9=A2=91=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../XSTalkManager/Utils/Talk/talk_Class.m | 17 +++++++--- star_lock/lib/main.dart | 6 ++-- .../monitoring/lockMonitoring_logic.dart | 34 +++++++++++++++++++ .../monitoring/lockMonitoring_page.dart | 5 +-- .../monitoring/lockMonitoring_state.dart | 4 ++- star_lock/lib/talk/call/callTalk.dart | 25 ++++++++++---- star_lock/lib/talk/udp/udp_manage.dart | 4 +-- star_lock/lib/talk/udp/udp_reciverData.dart | 18 +++++----- star_lock/lib/talk/udp/udp_talkClass.dart | 11 +++--- star_lock/lib/tools/eventBusEventManage.dart | 6 ++++ 10 files changed, 98 insertions(+), 32 deletions(-) diff --git a/star_lock/ios/Runner/XSTalkManager/Utils/Talk/talk_Class.m b/star_lock/ios/Runner/XSTalkManager/Utils/Talk/talk_Class.m index 8d1ee810..5fdbe11e 100755 --- a/star_lock/ios/Runner/XSTalkManager/Utils/Talk/talk_Class.m +++ b/star_lock/ios/Runner/XSTalkManager/Utils/Talk/talk_Class.m @@ -97,6 +97,7 @@ static bool isVedioStop; [arecord AudioEnd]; } +// 保持连接 - (void)connect_ini { _connect_reg_time = [Sformat timestamp]; Byte connect_bb[512]; @@ -642,22 +643,24 @@ static bool isVedioStop; isVedioStop= NO; - + // 呼叫应答,呼叫成功 memcpy(bbsend, bb, 62); bbsend[7] = 1; bbsend[8] = 4; NSLog(@"replay talk ip=%@;port=%d", ip, port); [[Pub getApp].udp sendDataInMain:bbsend length:512 toHost:ip toPort:port]; + // 门锁发送视频 memcpy(bbsend, bb, 62); bbsend[7] = 1; bbsend[8] = 5; NSLog(@"replay talk ip=%@;port=%d", ip, port); [[Pub getApp].udp sendDataInMain:bbsend length:512 toHost:ip toPort:port]; - //定时报告 + // 定时报告 [self connect_ini]; [self connect]; + // 设置定时器,得到连接时间 timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(connect) userInfo:nil repeats:YES]; @@ -855,13 +858,19 @@ static char cnt; } else{//视频数据 NSData *data1 = [[NSData alloc] initWithBytes:bb length:60+32]; + // 音视频数据开始下标 BAGLEN = [Pub getShortFromByte:bb at:POS_blen + 2]; + // 获取帧序号 63 iframe_index = [Pub getShortFromByte:bb at:POS_iframe_index]; + // 获取帧长度 65 alen = [Pub getShortFromByte:bb at:POS_alen]; - blen = [Pub getShortFromByte:bb at:POS_blen]; + // 当前包号 71 bag_index = bb[POS_bag_index]&0xff ; + // 总包数 69 bag_num = bb[POS_bag_num]&0xff; - + // 数据长度 73 + blen = [Pub getShortFromByte:bb at:POS_blen]; + if(iframe_index != iframe.iframe_index){ iframe = [[IframeInfo alloc] init]; iframe.iframe_index = iframe_index; diff --git a/star_lock/lib/main.dart b/star_lock/lib/main.dart index 24fbff70..8ca5a4fb 100644 --- a/star_lock/lib/main.dart +++ b/star_lock/lib/main.dart @@ -129,9 +129,9 @@ class _MyAppState extends State with WidgetsBindingObserver, BaseWidget { // playLocalAudio(); - Uint8List uint8List = Uint8List.fromList([]); - CallTalk talkClass = CallTalk(); - talkClass.getAVData(uint8List, 90); + // Uint8List uint8List = Uint8List.fromList([]); + // CallTalk talkClass = CallTalk(); + // talkClass.getAVData(uint8List, 90); } //初始化阿里云推送 diff --git a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_logic.dart b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_logic.dart index 4ddd39ef..8efa1e76 100644 --- a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_logic.dart +++ b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_logic.dart @@ -1,9 +1,43 @@ +import 'dart:async'; + import '../../../../tools/baseGetXController.dart'; +import '../../../../tools/eventBusEventManage.dart'; import 'lockMonitoring_state.dart'; class LockMonitoringLogic extends BaseGetXController { final LockMonitoringState state = LockMonitoringState(); + /// 收到视频流数据 + StreamSubscription? _getTVDataRefreshUIEvent; + void _getTVDataRefreshUIAction() { + // 蓝牙协议通知传输跟蓝牙之外的数据传输类不一样 eventBus + _getTVDataRefreshUIEvent = eventBus.on().listen((event) { + state.listData.value = event.tvList; + }); + } + + @override + void onReady() { + // TODO: implement onReady + super.onReady(); + print("onReady()"); + + _getTVDataRefreshUIAction(); + } + + @override + void onInit() { + // TODO: implement onInit + super.onInit(); + + } + + @override + void onClose() { + // TODO: implement onClose + print("锁详情界面销毁了"); + _getTVDataRefreshUIEvent!.cancel(); + } } \ No newline at end of file diff --git a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart index 74128614..e2b0b3f5 100644 --- a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart +++ b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; @@ -28,9 +29,9 @@ class _LockMonitoringPageState extends State { Stack( // alignment: Alignment.bottomCenter, children: [ - // Image.asset("images/icon_test20231113.png", width: 1.sw, height: 1.sh, fit: BoxFit.cover), + state.listData.value.isEmpty ? Image.asset("images/icon_test20231113.png", width: 1.sw, height: 1.sh, fit: BoxFit.cover) : Image.memory( - state.imageData, + Uint8List.fromList(state.listData.value), width: 1.sw, height: 1.sh, fit: BoxFit.cover, diff --git a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_state.dart b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_state.dart index a38b76f1..ed1135ca 100644 --- a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_state.dart +++ b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_state.dart @@ -5,7 +5,9 @@ import 'package:get/get.dart'; class LockMonitoringState { var isOpenVoice = false.obs; - Uint8List imageData = Uint8List.fromList([ + var listData = [].obs; + + Uint8List imageData = Uint8List.fromList([ 255, 216, 255, diff --git a/star_lock/lib/talk/call/callTalk.dart b/star_lock/lib/talk/call/callTalk.dart index cf4985b9..6ef84521 100644 --- a/star_lock/lib/talk/call/callTalk.dart +++ b/star_lock/lib/talk/call/callTalk.dart @@ -6,6 +6,8 @@ import 'package:star_lock/main/lockDetail/monitoring/monitoring/lockMonitoring_p import 'package:star_lock/talk/call/g711Decoder.dart'; import 'package:star_lock/talk/call/iFrameInfo.dart'; +import '../../tools/eventBusEventManage.dart'; + class CallTalk { static int POS_iframe_index = 63; static int POS_alen = 65; @@ -27,9 +29,9 @@ class CallTalk { // '5858584349449601075439415f396333613730323264346364a5a5a5a5c0a809a3503138363832313530323337000000000000000030303030420e000002000000b33300001f000100b301b301ffd8ffe000114a4649460001010000'; // Uint8List bb = Uint8List.fromList(hex.decode(hexData)); //音频数据 - String hexData = - '5858584349449601075439415f396333613730323264346364a5a5a5a5c0a809a3503138363832313530323337000000000000000030303030e02900000100050080020000010001004001b30145444444444444444445454444444444444444444444434343434443434344444444444544454545444444444444454545454545454545454445444545454545454545444444444343434344444443434344444444444343434343434343434443434343434343424343434343434242424242424242424243434343434242424242424343434342424343434242424242434243434343434344454344444444444444444444444444454545454544444444444444444445454545454545454545454545454546454545454545454545454545454545454646464646464645454545464646454545454545454545454545454544444444444444444443434343434343434343434343434343434343434242424242424242424242424242424343434242434343434343434343434343434343434343434444444343434343430000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024001d044000000000001d080001000000001d18c03000000000'; - Uint8List bb = Uint8List.fromList(hex.decode(hexData)); + // String hexData = + // '5858584349449601075439415f396333613730323264346364a5a5a5a5c0a809a3503138363832313530323337000000000000000030303030e02900000100050080020000010001004001b30145444444444444444445454444444444444444444444434343434443434344444444444544454545444444444444454545454545454545454445444545454545454545444444444343434344444443434344444444444343434343434343434443434343434343424343434343434242424242424242424243434343434242424242424343434342424343434242424242434243434343434344454344444444444444444444444444454545454544444444444444444445454545454545454545454545454546454545454545454545454545454545454646464646464645454545464646454545454545454545454545454544444444444444444443434343434343434343434343434343434343434242424242424242424242424242424343434242434343434343434343434343434343434343434444444343434343430000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024001d044000000000001d080001000000001d18c03000000000'; + // Uint8List bb = Uint8List.fromList(hex.decode(hexData)); // 音频数据 if (bb[61] == 1) { @@ -68,14 +70,25 @@ class CallTalk { iframe.bb = Uint8List(end); } - copyBytes(iframe!.bb!, start, bb, POS_data, blen); + print('bbbbbb111: ${bb}'); + iframe.bb!.addAll(bb.sublist(76, bb.length)); + + // copyBytes(iframe!.bb!, start, bb, POS_data, blen); // 打印输出看看字节数组的内容 print('Copied Bytes: ${iframe.bb}'); - Uint8List data = iframe.bb!.sublist(0, iframe.cur_len); + if(iframe.bagNum == iframe.bagReceive){ + Uint8List data = iframe.bb!.sublist(0, iframe.cur_len); + print('播放第%d帧:${iframe.iframeIndex} 一帧图片的Data: $data'); + eventBus.fire(GetTVDataRefreshUI(data)); + } + + // Get.toNamed(Routers.lockMonitoringPage, arguments: { + // "lockId": "111" + // }); // 打印拷贝后的目标数据 - print(iframe.bb); + // print(iframe.bb); } } diff --git a/star_lock/lib/talk/udp/udp_manage.dart b/star_lock/lib/talk/udp/udp_manage.dart index 35922f14..573dedfd 100644 --- a/star_lock/lib/talk/udp/udp_manage.dart +++ b/star_lock/lib/talk/udp/udp_manage.dart @@ -68,7 +68,7 @@ class UDPManage{ if(event == RawSocketEvent.read){ Datagram? dg = socket.receive(); try { - print('Did received data on the stream (length --> ${dg!.data.length}) dg!.data:${dg!.data}'); + // print('Did received data on the stream (length --> ${dg!.data.length}) dg!.data:${dg!.data}'); // EventBusManager().eventBusFir(EventReceiveModel(data: dg?.data,sendChannel: DataChannel.udp)); CommandUDPReciverManager.appDataReceive(dg!.data); } catch (e) { @@ -87,7 +87,7 @@ class UDPManage{ return; } try { - print("sendData:$data"); + // print("sendData:$data"); var result = _udpSocket?.send(data, InternetAddress(host!), port!); if(result != data.length) { print('❌Udp ----> send data $result ${data.length}'); diff --git a/star_lock/lib/talk/udp/udp_reciverData.dart b/star_lock/lib/talk/udp/udp_reciverData.dart index 3ff49c54..f01a8137 100644 --- a/star_lock/lib/talk/udp/udp_reciverData.dart +++ b/star_lock/lib/talk/udp/udp_reciverData.dart @@ -2,6 +2,7 @@ import 'dart:typed_data'; import '../../tools/toast.dart'; +import '../call/callTalk.dart'; import 'udp_talkClass.dart'; class CommandUDPReciverManager { @@ -15,7 +16,7 @@ class CommandUDPReciverManager { if(dataSize < 4){ return; } - // print("appDataReceiveData:$data"); + print("appDataReceiveData:$data"); Uint8List data1 = Uint8List.fromList(data); if(data1.length==1){ @@ -27,7 +28,7 @@ class CommandUDPReciverManager { if (data[6] == 4) { if(data[7] == 2){ - print("心跳包反馈 在线状态"); + // print("心跳包反馈 在线状态"); } else if(data[7]==3) { [Toast.show(msg: "您已在其他设备登录")]; } @@ -38,9 +39,8 @@ class CommandUDPReciverManager { // } // 对讲命令 - // var beiCallType = data[8] & 0xff; - var beiCallType = 1 & 0xff; - print("被呼叫2 类型$beiCallType"); + var beiCallType = data[8] & 0xff; + print("被呼叫类型$beiCallType"); switch (beiCallType) { case 1:{ //被叫 @@ -57,8 +57,9 @@ class CommandUDPReciverManager { break; case 7: case 8:{//音视频数据 - //print("音视频数据"); - + print("音视频数据"); + CallTalk cllTalk = CallTalk(); + cllTalk.getAVData(data1, data1.length); } break; case 9:{ @@ -66,8 +67,7 @@ class CommandUDPReciverManager { //print("对方保持连接"); data[7] = 2; - } - else{ + } else{ //print("保持连接反馈"); } diff --git a/star_lock/lib/talk/udp/udp_talkClass.dart b/star_lock/lib/talk/udp/udp_talkClass.dart index 0d5463f7..05d0739b 100644 --- a/star_lock/lib/talk/udp/udp_talkClass.dart +++ b/star_lock/lib/talk/udp/udp_talkClass.dart @@ -19,18 +19,16 @@ class UDPTalkClass{ factory UDPTalkClass() => _share(); UDPTalkClass get manager => _share(); - UDPTalkClass._init() { - - } + UDPTalkClass._init(); var status = 0;// 0空闲 - var remoteEquid; + var remoteEquid;// 手机号 late Timer timer; // 该字段是为了判断是否跳转到接听界面 挂断或者退出接听界面要记得变更状态 var isBeCall = false; beCallW({List? data, String? ip, int? port}) async { - print("beCall"); + // print("beCall"); // if (await isCallMe(data)) { // return; // } @@ -42,10 +40,12 @@ class UDPTalkClass{ remoteEquid = getEquidFrombb(data, 9); status = 6; + // 呼叫应答,呼叫成功 data![7] = 1; data[8] = 4; UDPManage().sendData(data); + // 门锁发送视频 data[7] = 1; data[8] = 5; UDPManage().sendData(data); @@ -59,6 +59,7 @@ class UDPTalkClass{ if(UDPTalkClass().isBeCall == false){ UDPTalkClass().isBeCall = true; + // 保持连接 timer = Timer.periodic(1.seconds, (timer) { data[7] = 1; data[8] = 9; diff --git a/star_lock/lib/tools/eventBusEventManage.dart b/star_lock/lib/tools/eventBusEventManage.dart index 8f1d6546..7958e493 100644 --- a/star_lock/lib/tools/eventBusEventManage.dart +++ b/star_lock/lib/tools/eventBusEventManage.dart @@ -54,4 +54,10 @@ class LockSetChangeSetRefreshLockDetailWithType{ int type;// 0 考勤 1开锁时是否需联网 int setResult; LockSetChangeSetRefreshLockDetailWithType(this.type, this.setResult); +} + +/// 获取到视频流数据然后刷新界面 +class GetTVDataRefreshUI{ + List tvList; + GetTVDataRefreshUI(this.tvList); } \ No newline at end of file From 4f5e95ce00827bc45a94b38bc5da0e67a928c187 Mon Sep 17 00:00:00 2001 From: Daisy <> Date: Mon, 18 Dec 2023 16:03:44 +0800 Subject: [PATCH 04/33] =?UTF-8?q?711=E9=9F=B3=E9=A2=91=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- star_lock/lib/talk/call/callTalk.dart | 31 ++++++++++++++++----------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/star_lock/lib/talk/call/callTalk.dart b/star_lock/lib/talk/call/callTalk.dart index cf4985b9..15e909a4 100644 --- a/star_lock/lib/talk/call/callTalk.dart +++ b/star_lock/lib/talk/call/callTalk.dart @@ -1,6 +1,8 @@ import 'dart:typed_data'; import 'package:convert/convert.dart'; import 'package:flutter_sound/flutter_sound.dart'; +import 'package:get/get.dart'; +import 'package:star_lock/appRouters.dart'; // import 'package:just_audio/just_audio.dart'; import 'package:star_lock/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart'; import 'package:star_lock/talk/call/g711Decoder.dart'; @@ -19,7 +21,7 @@ class CallTalk { int status = 0; // 假设有这个成员变量 IframeInfo iframe = IframeInfo(); // 假设有这个成员变量 LockMonitoringPage callOut = const LockMonitoringPage(); - late FlutterSoundPlayer _player; + FlutterSoundPlayer _audioPlayer = FlutterSoundPlayer(); Future getAVData(Uint8List bb, int len) async { //视频数据 @@ -34,13 +36,12 @@ class CallTalk { // 音频数据 if (bb[61] == 1) { // 如果是音频数据且状态符合条件 - _player = FlutterSoundPlayer(); - _initPlayer(); - // 解码 - Uint8List g711Data = G711Decoder().decodeG711uLaw(bb); + _initializeAudioPlayer(); - await _playAudio(g711Data); + // 用你的711音频数据替换这里的Uint8List + Uint8List rawData = G711Decoder().decodeG711uLaw(bb); + _playRawData(rawData); } // 视频数据 else { @@ -74,6 +75,8 @@ class CallTalk { Uint8List data = iframe.bb!.sublist(0, iframe.cur_len); + Get.toNamed(Routers.lockMonitoringPage, + arguments: {"lockId": widget.lockListInfoItemEntity.lockId}); // 打印拷贝后的目标数据 print(iframe.bb); } @@ -98,14 +101,18 @@ class CallTalk { } } - Future _initPlayer() async { - await _player.openPlayer(); + Future _initializeAudioPlayer() async { + await _audioPlayer.openPlayer(); } - Future _playAudio(Uint8List audioData) async { - await _player.startPlayer( - fromDataBuffer: audioData, - codec: Codec.pcm16WAV, + Future _playRawData(Uint8List rawData) async { + await _audioPlayer.startPlayer( + fromDataBuffer: rawData, + codec: Codec.pcm16, + whenFinished: () { + // 播放完成时的回调 + print("Playback finished"); + }, ); } } From adcb0972054dd89c1dd251b212278be4d84c3d58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AD=8F=E5=B0=91=E9=98=B3?= <786612630@qq.com> Date: Tue, 19 Dec 2023 18:33:02 +0800 Subject: [PATCH 05/33] =?UTF-8?q?=E5=AF=B9=E8=AE=B2=E8=A7=86=E9=A2=91?= =?UTF-8?q?=E5=9B=BE=E7=89=87=E6=95=B0=E6=8D=AE=E6=8E=A5=E6=94=B6=E6=B8=B2?= =?UTF-8?q?=E6=9F=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../monitoring/lockMonitoring_page.dart | 27 ++- .../demoModeLockDetail_logic.dart | 5 - .../demoModeLockDetail_page.dart | 2 +- .../demoModeLockDetail_state.dart | 5 - .../lockMian/lockMain/lockMain_logic.dart | 1 + .../lockAddress/lockAddress_logic.dart | 3 - .../lockAddress/lockAddress_state.dart | 5 - star_lock/lib/nav/navLogic.dart | 3 - star_lock/lib/nav/navState.dart | 5 - star_lock/lib/talk/call/callTalk.dart | 129 ++++++++++--- star_lock/lib/talk/call/iFrameInfo.dart | 2 +- star_lock/lib/talk/udp/udp_reciverData.dart | 175 +++++++++--------- 12 files changed, 203 insertions(+), 159 deletions(-) delete mode 100644 star_lock/lib/main/lockMian/demoMode/demoModeLockDetail/demoModeLockDetail_state.dart delete mode 100644 star_lock/lib/mine/addLock/lockAddress/lockAddress/lockAddress_state.dart delete mode 100644 star_lock/lib/nav/navState.dart diff --git a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart index e2b0b3f5..2a554264 100644 --- a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart +++ b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart @@ -20,22 +20,23 @@ class _LockMonitoringPageState extends State { @override Widget build(BuildContext context) { - return Container( + return SizedBox( width: 1.sw, height: 1.sh, - color: Colors.white, - child: Column( - children: [ - Stack( + // color: Colors.transparent, + child: Stack( // alignment: Alignment.bottomCenter, children: [ - state.listData.value.isEmpty ? Image.asset("images/icon_test20231113.png", width: 1.sw, height: 1.sh, fit: BoxFit.cover) : - Image.memory( - Uint8List.fromList(state.listData.value), - width: 1.sw, - height: 1.sh, - fit: BoxFit.cover, - ), + // state.listData.value.isEmpty ? Image.asset("images/icon_test20231113.png", width: 1.sw, height: 1.sh, fit: BoxFit.cover) : + Obx(() => + state.listData.value.isEmpty + ? Container(color: Colors.red) + :Image.memory( + Uint8List.fromList(state.listData.value), + width: 1.sw, + height: 1.sh, + fit: BoxFit.cover, + )), Positioned( top: ScreenUtil().statusBarHeight + 30.h, child: Row(children: [ @@ -79,8 +80,6 @@ class _LockMonitoringPageState extends State { )) ], ), - ], - ), ); } diff --git a/star_lock/lib/main/lockMian/demoMode/demoModeLockDetail/demoModeLockDetail_logic.dart b/star_lock/lib/main/lockMian/demoMode/demoModeLockDetail/demoModeLockDetail_logic.dart index 11d4b09b..b2cbf02d 100644 --- a/star_lock/lib/main/lockMian/demoMode/demoModeLockDetail/demoModeLockDetail_logic.dart +++ b/star_lock/lib/main/lockMian/demoMode/demoModeLockDetail/demoModeLockDetail_logic.dart @@ -1,13 +1,8 @@ - import '../../../../tools/baseGetXController.dart'; import '../../../../tools/storage.dart'; -import 'demoModeLockDetail_state.dart'; class DemoModeLockDetailLogic extends BaseGetXController { - DemoModeLockDetailState state = DemoModeLockDetailState(); - - @override void onReady() { diff --git a/star_lock/lib/main/lockMian/demoMode/demoModeLockDetail/demoModeLockDetail_page.dart b/star_lock/lib/main/lockMian/demoMode/demoModeLockDetail/demoModeLockDetail_page.dart index 8da69913..50fe2a3e 100644 --- a/star_lock/lib/main/lockMian/demoMode/demoModeLockDetail/demoModeLockDetail_page.dart +++ b/star_lock/lib/main/lockMian/demoMode/demoModeLockDetail/demoModeLockDetail_page.dart @@ -19,7 +19,7 @@ class DemoModeLockDetailPage extends StatefulWidget { class _DemoModeLockDetailPageState extends State { final logic = Get.put(DemoModeLockDetailLogic()); - final state = Get.find().state; + // final state = Get.find().state; @override void initState() { diff --git a/star_lock/lib/main/lockMian/demoMode/demoModeLockDetail/demoModeLockDetail_state.dart b/star_lock/lib/main/lockMian/demoMode/demoModeLockDetail/demoModeLockDetail_state.dart deleted file mode 100644 index 4e3b435f..00000000 --- a/star_lock/lib/main/lockMian/demoMode/demoModeLockDetail/demoModeLockDetail_state.dart +++ /dev/null @@ -1,5 +0,0 @@ - - -class DemoModeLockDetailState { - -} \ No newline at end of file diff --git a/star_lock/lib/main/lockMian/lockMain/lockMain_logic.dart b/star_lock/lib/main/lockMian/lockMain/lockMain_logic.dart index 3c670828..6ee4cff0 100644 --- a/star_lock/lib/main/lockMian/lockMain/lockMain_logic.dart +++ b/star_lock/lib/main/lockMian/lockMain/lockMain_logic.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'dart:typed_data'; import 'package:get/get.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart'; import 'package:star_lock/talk/udp/udp_senderManage.dart'; diff --git a/star_lock/lib/mine/addLock/lockAddress/lockAddress/lockAddress_logic.dart b/star_lock/lib/mine/addLock/lockAddress/lockAddress/lockAddress_logic.dart index b3589a61..d36aa1be 100644 --- a/star_lock/lib/mine/addLock/lockAddress/lockAddress/lockAddress_logic.dart +++ b/star_lock/lib/mine/addLock/lockAddress/lockAddress/lockAddress_logic.dart @@ -1,11 +1,8 @@ import '../../../../tools/baseGetXController.dart'; -import 'lockAddress_state.dart'; class LockAddressLogic extends BaseGetXController { - final LockAddressState state = LockAddressState(); - @override void onReady() { // TODO: implement onReady diff --git a/star_lock/lib/mine/addLock/lockAddress/lockAddress/lockAddress_state.dart b/star_lock/lib/mine/addLock/lockAddress/lockAddress/lockAddress_state.dart deleted file mode 100644 index 3926eed4..00000000 --- a/star_lock/lib/mine/addLock/lockAddress/lockAddress/lockAddress_state.dart +++ /dev/null @@ -1,5 +0,0 @@ - - -class LockAddressState { - -} \ No newline at end of file diff --git a/star_lock/lib/nav/navLogic.dart b/star_lock/lib/nav/navLogic.dart index b74d9453..ed2bd480 100644 --- a/star_lock/lib/nav/navLogic.dart +++ b/star_lock/lib/nav/navLogic.dart @@ -1,9 +1,6 @@ - import '../tools/baseGetXController.dart'; -import 'navState.dart'; class NavLogic extends BaseGetXController { - final NavState state = NavState(); } \ No newline at end of file diff --git a/star_lock/lib/nav/navState.dart b/star_lock/lib/nav/navState.dart deleted file mode 100644 index ec631f3e..00000000 --- a/star_lock/lib/nav/navState.dart +++ /dev/null @@ -1,5 +0,0 @@ - - -class NavState{ - -} \ No newline at end of file diff --git a/star_lock/lib/talk/call/callTalk.dart b/star_lock/lib/talk/call/callTalk.dart index 6ef84521..39af7425 100644 --- a/star_lock/lib/talk/call/callTalk.dart +++ b/star_lock/lib/talk/call/callTalk.dart @@ -1,4 +1,5 @@ import 'dart:typed_data'; +import 'package:flutter/material.dart'; import 'package:convert/convert.dart'; import 'package:flutter_sound/flutter_sound.dart'; // import 'package:just_audio/just_audio.dart'; @@ -9,6 +10,7 @@ import 'package:star_lock/talk/call/iFrameInfo.dart'; import '../../tools/eventBusEventManage.dart'; class CallTalk { + static CallTalk? _manager; static int POS_iframe_index = 63; static int POS_alen = 65; static int POS_blen = 73; @@ -19,10 +21,23 @@ class CallTalk { static int FIRSTINDEX = 1; int status = 0; // 假设有这个成员变量 - IframeInfo iframe = IframeInfo(); // 假设有这个成员变量 + IframeInfo? iframe; // 假设有这个成员变量 + var growableList; LockMonitoringPage callOut = const LockMonitoringPage(); late FlutterSoundPlayer _player; + CallTalk._init() { + iframe = IframeInfo(); + } + + static CallTalk _share() { + _manager ??= CallTalk._init(); + return _manager!; + } + + factory CallTalk() => _share(); + CallTalk get manager => _share(); + Future getAVData(Uint8List bb, int len) async { //视频数据 // String hexData = @@ -46,44 +61,88 @@ class CallTalk { } // 视频数据 else { - int bagLen = getShortFromByte(bb, POS_blen + 2); - int getIframeIndex = getShortFromByte(bb, POS_iframe_index); - int alen = getShortFromByte(bb, POS_alen); - int blen = getShortFromByte(bb, POS_blen); - int getBagIndex = bb[POS_bag_index] & 0xff; - int getBagNum = bb[POS_bag_num] & 0xff; + // 音视频数据开始下标 + var bagLen = bb[POS_blen + 2] + bb[POS_blen + 3] * 256; + // print('音视频数据开始下标 bagLen:$bagLen'); - if (getIframeIndex != iframe.iframeIndex) { + // 获取帧序号 63 + int getIframeIndex = + bb[POS_iframe_index] + bb[POS_iframe_index + 1] * 256; + print('获取帧序号 getIframeIndex:$getIframeIndex'); + // 获取帧长度 65 + // int alen = bb[POS_alen] & 0xff; + // var alenList = bb.sublist(POS_alen, POS_alen + 4); + // int alen = ((0xff & alenList[(0)]) << 24 | + // (0xff & alenList[1]) << 16 | + // (0xff & alenList[2]) << 8 | + // (0xFF & alenList[3])); + // print('获取帧长度 alen:$alen'); + + // 当前包号 71 + int getBagIndex = bb[POS_bag_index] & 0xff; + print('当前包号 getBagIndex:$getBagIndex'); + // 总包数 69 + int getBagNum = bb[POS_bag_num] & 0xff; + print('总包数 getBagNum:$getBagNum'); + // 数据长度 73 + int blen = bb[POS_blen] + bb[POS_blen + 1] * 256; + print('数据长度 blen:$blen'); + + // 这里判断是否是同一帧,如果不是同一帧就重新创建一个 IframeInfo + if (getIframeIndex != iframe!.iframeIndex) { iframe = IframeInfo(); - iframe.iframeIndex = getIframeIndex; - iframe.bagNum = getBagNum; - iframe.cur_len = alen; - iframe.bb = Uint8List(alen); + // print('11111111change getIframeIndex:$getIframeIndex '); + // print('11111111change iframe.iframeIndex: ${iframe!.iframeIndex}'); + iframe!.iframeIndex = getIframeIndex; + iframe!.bagNum = getBagNum; + // iframe!.cur_len = alen; + // iframe!.bb = Uint8List(alen); + growableList = iframe!.bb!.toList(growable: true); } - iframe.bagReceive++; - int start = bagLen * (getBagIndex - FIRSTINDEX); - int end = start + blen; + iframe!.bagReceive++; + // int start = bagLen * (getBagIndex - FIRSTINDEX); + // int end = start + blen; // 确保 iframe!.bb 不为 null,并且足够长 - if (iframe.bb == null || iframe.bb!.length < end) { - iframe.bb = Uint8List(end); + // if (iframe.bb == null || iframe.bb!.length < end) { + // iframe.bb = Uint8List(end); + // } + + // print('22222222change getIframeIndex:$getIframeIndex '); + + // 如果是同一帧就添加起来 + if (getIframeIndex == iframe!.iframeIndex) { + // print('33333333change iframe.iframeIndex: ${iframe!.iframeIndex}'); + var getList = bb.sublist(77, bb.length); + print('getList:${getList}'); + growableList.addAll(getList); + // print('growableList: $growableList'); } - print('bbbbbb111: ${bb}'); - iframe.bb!.addAll(bb.sublist(76, bb.length)); - // copyBytes(iframe!.bb!, start, bb, POS_data, blen); // 打印输出看看字节数组的内容 - print('Copied Bytes: ${iframe.bb}'); - if(iframe.bagNum == iframe.bagReceive){ - Uint8List data = iframe.bb!.sublist(0, iframe.cur_len); - print('播放第%d帧:${iframe.iframeIndex} 一帧图片的Data: $data'); - eventBus.fire(GetTVDataRefreshUI(data)); + print( + 'iframe.bagNum: ${iframe!.bagNum} iframe.bagReceive: ${iframe!.bagReceive}'); + + // 如果收到的包数等于总包数,说明这一帧数据已经接收完毕 + if (iframe!.bagNum == iframe!.bagReceive) { + // List data = iframe!.bb!.sublist(0, iframe!.cur_len); + print('播放第${iframe!.iframeIndex}帧 一帧图片的Data: $growableList'); + String hexString = + uint8ListToHexString(Uint8List.fromList(growableList)); + // print('播放第${iframe!.iframeIndex}帧 hexStringLength:${hexString.length} 一帧图片的hexStringData: $hexString'); // 输出: 0a141e28 + + // if (iframe!.iframeIndex == 1) { + print('下面就是你要的'); + printByteArray('播放第${iframe!.iframeIndex}帧 一帧图片的hexStringData: ', + Uint8List.fromList(growableList)); + eventBus.fire(GetTVDataRefreshUI(growableList)); + // } + // eventBus.fire(GetTVDataRefreshUI(growableList)); } - // Get.toNamed(Routers.lockMonitoringPage, arguments: { // "lockId": "111" // }); @@ -92,6 +151,24 @@ class CallTalk { } } + void printByteArray(String printTitle, Uint8List byteArray) { + final int chunkSize = byteArray.length; // 每行显示的字节数 + int length = byteArray.length; + + for (int i = 0; i < length; i += chunkSize) { + int end = (i + chunkSize < length) ? i + chunkSize : length; + Uint8List chunk = byteArray.sublist(i, end); + + String hexString = + chunk.map((byte) => byte.toRadixString(16).padLeft(2, '0')).join(' '); + debugPrint(hexString); + } + } + + String uint8ListToHexString(Uint8List uint8List) { + return hex.encode(uint8List); + } + int getShortFromByte(Uint8List bb, int pos) { ByteData byteData = ByteData.sublistView(bb, pos, pos + 2); return byteData.getInt16(0, Endian.little); diff --git a/star_lock/lib/talk/call/iFrameInfo.dart b/star_lock/lib/talk/call/iFrameInfo.dart index 89e0101b..f244b1c8 100644 --- a/star_lock/lib/talk/call/iFrameInfo.dart +++ b/star_lock/lib/talk/call/iFrameInfo.dart @@ -17,6 +17,6 @@ class IframeInfo { bagReceive = 0; isFull = false; cur_len = 0; - bb = Uint8List(512); + bb = Uint8List(0); } } diff --git a/star_lock/lib/talk/udp/udp_reciverData.dart b/star_lock/lib/talk/udp/udp_reciverData.dart index f01a8137..ab7b9fcd 100644 --- a/star_lock/lib/talk/udp/udp_reciverData.dart +++ b/star_lock/lib/talk/udp/udp_reciverData.dart @@ -1,4 +1,3 @@ - import 'dart:typed_data'; import '../../tools/toast.dart'; @@ -6,30 +5,28 @@ import '../call/callTalk.dart'; import 'udp_talkClass.dart'; class CommandUDPReciverManager { - static void appDataReceive(List data) async { ///解析数据 - if(data.isEmpty){ + if (data.isEmpty) { return; } int dataSize = data.length; - if(dataSize < 4){ + if (dataSize < 4) { return; } print("appDataReceiveData:$data"); Uint8List data1 = Uint8List.fromList(data); - if(data1.length==1){ - if(data[0]==0x30 || data[0]==0x31){ + if (data1.length == 1) { + if (data[0] == 0x30 || data[0] == 0x31) { print("p2p打洞"); - } } if (data[6] == 4) { - if(data[7] == 2){ + if (data[7] == 2) { // print("心跳包反馈 在线状态"); - } else if(data[7]==3) { + } else if (data[7] == 3) { [Toast.show(msg: "您已在其他设备登录")]; } } else if (data[6] == 150) { @@ -42,77 +39,78 @@ class CommandUDPReciverManager { var beiCallType = data[8] & 0xff; print("被呼叫类型$beiCallType"); switch (beiCallType) { - case 1:{ + case 1: + { //被叫 UDPTalkClass().beCallW(data: data); } break; - case 6:{ + case 6: + { //接听 - if((data[7] & 0x3) == 2){//被叫 接听反馈 + if ((data[7] & 0x3) == 2) { + //被叫 接听反馈 print("接听反馈"); - } } break; - case 7: - case 8:{//音视频数据 - print("音视频数据"); + case 7: + case 8: + { + //音视频数据 + // print("音视频数据"); CallTalk cllTalk = CallTalk(); cllTalk.getAVData(data1, data1.length); } break; - case 9:{ - if((data[7] & 0x3) == 1){//对方保持连接 + case 9: + { + if ((data[7] & 0x3) == 1) { + //对方保持连接 //print("对方保持连接"); data[7] = 2; - - } else{ + } else { //print("保持连接反馈"); - } } break; - case 10:{ + case 10: + { //开门反馈 - if((data[7] & 0x3) == 2){ + if ((data[7] & 0x3) == 2) { print("开门成功"); - - } - else{ - - } + } else {} } break; - case 30:{ + case 30: + { //开门反馈 - if((data[7] & 0x3) == 1){ + if ((data[7] & 0x3) == 1) { //对方结束对讲 print("对方结束对讲"); - - } else{ + } else { //结束对讲反馈 print("结束对讲反馈"); - } } break; - case 140:{ + case 140: + { // p2p测试 - } break; - case 141:{ + case 141: + { // p2p测试 - } break; - case 142:{ + case 142: + { // p2p测试 - } break; - case 143:{ + case 143: + { //p2p测试 NSAsk print("p2pNSAskNSAsk"); } @@ -123,65 +121,60 @@ class CommandUDPReciverManager { } else if (data[6] == 152) { // 监视命令 switch (data[8] & 0xff) { - case 2:{ - //被叫 - print("对方忙"); - } - break; - case 4:{ - //监视成功 - print("监视成功"); - - } - break; + case 2: + { + //被叫 + print("对方忙"); + } + break; + case 4: + { + //监视成功 + print("监视成功"); + } + break; case 7: - case 8:{//音视频数据 - //print("音视频数据"); - - } - break; - case 9:{ - //保持连接 - if((data[7] & 0x3) == 1){//对方保持连接 - //print("对方保持连接"); - data[7] = 2; - + case 8: + { + //音视频数据 + //print("音视频数据"); } - else{ - //print("保持连接反馈"); - + break; + case 9: + { + //保持连接 + if ((data[7] & 0x3) == 1) { + //对方保持连接 + //print("对方保持连接"); + data[7] = 2; + } else { + //print("保持连接反馈"); + } } - } - break; - case 10:{ - //开门反馈 - if((data[7] & 0x3) == 2){ - print("开门成功"); - + break; + case 10: + { + //开门反馈 + if ((data[7] & 0x3) == 2) { + print("开门成功"); + } else {} } - else{ - + break; + case 30: + { + // 监视结束 + if ((data[7] & 0x3) == 1) { + // 对方结束监视 + print("对方结束监视"); + } else { + //结束对讲反馈 + print("结束监视反馈"); + } } - } - break; - case 30:{ - // 监视结束 - if((data[7] & 0x3) == 1){ - // 对方结束监视 - print("对方结束监视"); - - } else{ - //结束对讲反馈 - print("结束监视反馈"); - - } - } - break; + break; default: break; } } } - - } From 158c37a69e9e11d8e5d762dcbca144655b00cac1 Mon Sep 17 00:00:00 2001 From: Daisy <> Date: Tue, 19 Dec 2023 18:41:51 +0800 Subject: [PATCH 06/33] =?UTF-8?q?=E9=9F=B3=E9=A2=91=E6=95=B0=E6=8D=AE=20?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E6=92=AD=E6=94=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- star_lock/lib/talk/call/callTalk.dart | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/star_lock/lib/talk/call/callTalk.dart b/star_lock/lib/talk/call/callTalk.dart index d271855b..faee0db9 100644 --- a/star_lock/lib/talk/call/callTalk.dart +++ b/star_lock/lib/talk/call/callTalk.dart @@ -26,7 +26,7 @@ class CallTalk { IframeInfo? iframe; // 假设有这个成员变量 var growableList; LockMonitoringPage callOut = const LockMonitoringPage(); - late FlutterSoundPlayer _player; + FlutterSoundPlayer _audioPlayer = FlutterSoundPlayer(); CallTalk._init() { iframe = IframeInfo(); @@ -53,13 +53,12 @@ class CallTalk { // 音频数据 if (bb[61] == 1) { // 如果是音频数据且状态符合条件 - _player = FlutterSoundPlayer(); - _initPlayer(); - // 解码 - Uint8List g711Data = G711Decoder().decodeG711uLaw(bb); + _initializeAudioPlayer(); - await _playAudio(g711Data); + // 用你的711音频数据替换这里的Uint8List + Uint8List rawData = G711Decoder().decodeG711uLaw(bb); + _playRawData(rawData); } // 视频数据 else { @@ -190,14 +189,18 @@ class CallTalk { } } - Future _initPlayer() async { - await _player.openPlayer(); + Future _initializeAudioPlayer() async { + await _audioPlayer.openPlayer(); } - Future _playAudio(Uint8List audioData) async { - await _player.startPlayer( - fromDataBuffer: audioData, - codec: Codec.pcm16WAV, + Future _playRawData(Uint8List rawData) async { + await _audioPlayer.startPlayer( + fromDataBuffer: rawData, + codec: Codec.pcm16, + whenFinished: () { + // 播放完成时的回调 + print("Playback finished"); + }, ); } } From e258d9b49caa996a3c4f40f4027afaae65325ee8 Mon Sep 17 00:00:00 2001 From: Daisy <> Date: Wed, 20 Dec 2023 09:36:54 +0800 Subject: [PATCH 07/33] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=9F=B3=E9=A2=91?= =?UTF-8?q?=E6=92=AD=E6=94=BE=E5=99=A8=E5=88=9D=E5=A7=8B=E5=8C=96=E4=BD=8D?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- star_lock/lib/talk/call/callTalk.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/star_lock/lib/talk/call/callTalk.dart b/star_lock/lib/talk/call/callTalk.dart index faee0db9..2801f857 100644 --- a/star_lock/lib/talk/call/callTalk.dart +++ b/star_lock/lib/talk/call/callTalk.dart @@ -30,6 +30,7 @@ class CallTalk { CallTalk._init() { iframe = IframeInfo(); + _initializeAudioPlayer(); } static CallTalk _share() { @@ -53,9 +54,6 @@ class CallTalk { // 音频数据 if (bb[61] == 1) { // 如果是音频数据且状态符合条件 - - _initializeAudioPlayer(); - // 用你的711音频数据替换这里的Uint8List Uint8List rawData = G711Decoder().decodeG711uLaw(bb); _playRawData(rawData); From febbab97daeb01541fde189da277bfa41a8b3c7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AD=8F=E5=B0=91=E9=98=B3?= <786612630@qq.com> Date: Wed, 20 Dec 2023 11:54:54 +0800 Subject: [PATCH 08/33] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=93=9D=E7=89=99?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=95=B0=E6=8D=AE=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- star_lock/lib/blue/blue_manage.dart | 18 +++++++++--------- .../monitoring/lockMonitoring_page.dart | 2 +- .../addLock/nearbyLock/nearbyLock_logic.dart | 1 + 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/star_lock/lib/blue/blue_manage.dart b/star_lock/lib/blue/blue_manage.dart index 43923d2a..416c3bc7 100644 --- a/star_lock/lib/blue/blue_manage.dart +++ b/star_lock/lib/blue/blue_manage.dart @@ -26,7 +26,6 @@ class BlueManage{ Uuid characteristicIdWrite = Uuid.parse("fff2");// 用来写入的特征id String connectDeviceMacAddress = ""; String connectDeviceName = ""; - // final int _limitLen = 20; // 监听发送事件 @@ -302,23 +301,23 @@ class BlueManage{ // 听上报来的数据,参数来自前面扫描到的结果 var allData = []; + int? dataLen; _subScribeToCharacteristic(QualifiedCharacteristic characteristic) { _flutterReactiveBle!.subscribeToCharacteristic(characteristic).listen((data) { // code to handle incoming data print("subscribeToCharacteristic: deviceId = ${characteristic.deviceId} characteristicId =${characteristic.characteristicId}---上报来的数据data = $data"); - var dataLen = 0;// 高16位用来指示后面数据块内容的长度 - if((data[0] == 0xEF)&&(data[1] == 0x01)&&(data[2] == 0xEE)&&(data[3] == 0x02)){ // 当包有头时 // 判断是否需要分包 - dataLen = data[8] * 256 + data[9]; - // print("dataLen1111:$dataLen getDataLength:${data.length}"); - if(dataLen + 12 > data.length){ + dataLen = data[8] * 256 + data[9]; // 高16位用来指示后面数据块内容的长度 + print("dataLen1111:$dataLen getDataLength:${data.length}"); + if(dataLen! + 12 > data.length){ // 当前包的长度小于实际的包时 分包添加 不解析 allData.addAll(data); }else{ // 当前包的长度小于实际的包时 不分包 解析 allData.addAll(data); + print("dataLen2222:$dataLen getDataLength:${data.length}"); CommandReciverManager.appDataReceive(allData); // 发送完解析初始化数组 allData = []; @@ -327,8 +326,9 @@ class BlueManage{ // 当包没有头时 是分包的包 直接添加 allData.addAll(data); // var len = allData[8] * 256 + allData[9]; - // print("dataLen222:$dataLen"); - if(dataLen <= (allData.length - 14)){ + print("dataLen3333:$dataLen"); + if((dataLen! + 14) <= allData.length){ + print("44444数据被解析了"); // 当长度小于等于当前包的数据时 直接解析数据 CommandReciverManager.appDataReceive(allData); // 发送完解析初始化数组 @@ -346,7 +346,7 @@ class BlueManage{ QualifiedCharacteristic characteristic = QualifiedCharacteristic(characteristicId: characteristicIdWrite, serviceId: serviceId, deviceId: connectDeviceMacAddress); print('Write with characteristicId:${characteristic.characteristicId} serviceId:${characteristic.serviceId} deviceId:${characteristic.deviceId} value : $value \nhexStr:${radixHex16String(value)}'); int mtuLength = await _flutterReactiveBle!.requestMtu(deviceId: characteristic.deviceId, mtu: 250); - print("mtuLength:$mtuLength"); + // print("mtuLength:$mtuLength"); try { List valueList = value; List subData = splitList(valueList, mtuLength); diff --git a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart index 2a554264..4bb5d31c 100644 --- a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart +++ b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart @@ -48,7 +48,7 @@ class _LockMonitoringPageState extends State { child: Container( decoration: BoxDecoration( color: Colors.white, - borderRadius: BorderRadius.circular(30.h)), + borderRadius: BorderRadius.circular(25.h)), padding: EdgeInsets.all(10.w), child: Image( width: 40.w, diff --git a/star_lock/lib/mine/addLock/nearbyLock/nearbyLock_logic.dart b/star_lock/lib/mine/addLock/nearbyLock/nearbyLock_logic.dart index 7fe6f5e2..55df7dec 100644 --- a/star_lock/lib/mine/addLock/nearbyLock/nearbyLock_logic.dart +++ b/star_lock/lib/mine/addLock/nearbyLock/nearbyLock_logic.dart @@ -35,6 +35,7 @@ class NearbyLockLogic extends BaseGetXController{ // IoSenderManage.getPublicKey(lockId: deviceName); // } // }, isShowLoading: true); + BlueManage().disconnect(""); BlueManage().connect(lockId, deviceName, isFrist: true, isShowLoading: true); } From 597ff218a964150394460f3d2a2839d549cd8da6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AD=8F=E5=B0=91=E9=98=B3?= <786612630@qq.com> Date: Wed, 20 Dec 2023 13:43:41 +0800 Subject: [PATCH 09/33] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- star_lock/lib/talk/udp/udp_help.dart | 5 +++-- star_lock/lib/talk/udp/udp_reciverData.dart | 2 +- star_lock/lib/tools/storage.dart | 18 ++++++++++++++---- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/star_lock/lib/talk/udp/udp_help.dart b/star_lock/lib/talk/udp/udp_help.dart index e3ae0ab1..c6bea328 100644 --- a/star_lock/lib/talk/udp/udp_help.dart +++ b/star_lock/lib/talk/udp/udp_help.dart @@ -6,6 +6,7 @@ import 'dart:io'; import 'package:get/get.dart'; import '../../network/api_repository.dart'; +import '../../tools/storage.dart'; import 'udp_manage.dart'; import 'udp_senderManage.dart'; @@ -38,9 +39,9 @@ class UdpHelp{ } } - Timer timer = Timer.periodic(1.seconds, (timer) { + Timer timer = Timer.periodic(1.seconds, (timer) async { UDPSenderManage.sendHeart( - userName: "15080825640", + userName: await Storage.getMobile(), ipList: serversList, tokenStr: "b989fa15f75c2ac02718b7c9bb64f80e", ); diff --git a/star_lock/lib/talk/udp/udp_reciverData.dart b/star_lock/lib/talk/udp/udp_reciverData.dart index ab7b9fcd..129cbb48 100644 --- a/star_lock/lib/talk/udp/udp_reciverData.dart +++ b/star_lock/lib/talk/udp/udp_reciverData.dart @@ -14,7 +14,7 @@ class CommandUDPReciverManager { if (dataSize < 4) { return; } - print("appDataReceiveData:$data"); + print("appDataReceiveUDPData:$data"); Uint8List data1 = Uint8List.fromList(data); if (data1.length == 1) { diff --git a/star_lock/lib/tools/storage.dart b/star_lock/lib/tools/storage.dart index 8e98e17e..7a1b0d38 100644 --- a/star_lock/lib/tools/storage.dart +++ b/star_lock/lib/tools/storage.dart @@ -136,13 +136,23 @@ class Storage { } static Future getUid() async { - String? userId = ''; + String? uid = ''; final data = await Storage.getString('userLoginData'); if (data != null && data.isNotEmpty) { - userId = LoginData.fromJson(jsonDecode(data)).uid.toString(); + uid = LoginData.fromJson(jsonDecode(data)).uid.toString(); } - print("pubUserId:$userId"); - return userId; + print("pubUid:$uid"); + return uid; + } + + static Future getMobile() async { + String? mobile = ''; + final data = await Storage.getString('userLoginData'); + if (data != null && data.isNotEmpty) { + mobile = LoginData.fromJson(jsonDecode(data)).mobile.toString(); + } + print("pubUserId:$mobile"); + return mobile; } static Future getLoginData() async { From 5b4a4bb53c4ca851d96af8df5bdb52a2d4142d7d Mon Sep 17 00:00:00 2001 From: Daisy <> Date: Wed, 20 Dec 2023 13:46:05 +0800 Subject: [PATCH 10/33] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=97=A0=E7=94=A8?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- star_lock/ios/Podfile.lock | 50 +++++++++++-- .../ios/Runner.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/xcschemes/Runner.xcscheme | 2 +- star_lock/lib/talk/call/callTalk.dart | 71 ++----------------- 4 files changed, 53 insertions(+), 72 deletions(-) diff --git a/star_lock/ios/Podfile.lock b/star_lock/ios/Podfile.lock index 900a4a92..d9f86221 100644 --- a/star_lock/ios/Podfile.lock +++ b/star_lock/ios/Podfile.lock @@ -27,6 +27,10 @@ PODS: - AMapFoundation (1.8.2) - AMapLocation (2.10.0): - AMapFoundation (>= 1.8.0) + - audio_session (0.0.1): + - Flutter + - audioplayers_darwin (0.0.1): + - Flutter - auto_orientation (0.0.1): - Flutter - camera_avfoundation (0.0.1): @@ -37,12 +41,18 @@ PODS: - Flutter (1.0.0) - flutter_native_contact_picker (0.0.1): - Flutter + - flutter_sound (9.2.13): + - Flutter + - flutter_sound_core (= 9.2.13) + - flutter_sound_core (9.2.13) - fluttertoast (0.0.2): - Flutter - Toast - FMDB (2.7.5): - FMDB/standard (= 2.7.5) - FMDB/standard (2.7.5) + - g711_flutter (0.0.1): + - Flutter - google_maps_flutter_ios (0.0.1): - Flutter - GoogleMaps (< 8.0) @@ -51,8 +61,12 @@ PODS: - GoogleMaps/Base (5.2.0) - GoogleMaps/Maps (5.2.0): - GoogleMaps/Base + - image_gallery_saver (2.0.2): + - Flutter - image_picker_ios (0.0.1): - Flutter + - just_audio (0.0.1): + - Flutter - network_info_plus (0.0.1): - Flutter - package_info_plus (0.4.5): @@ -62,7 +76,7 @@ PODS: - FlutterMacOS - permission_handler_apple (9.1.1): - Flutter - - Protobuf (3.25.1) + - Protobuf (3.25.0) - reactive_ble_mobile (0.0.1): - Flutter - Protobuf (~> 3.5) @@ -88,14 +102,20 @@ DEPENDENCIES: - aliyun_push (from `.symlinks/plugins/aliyun_push/ios`) - amap_flutter_location (from `.symlinks/plugins/amap_flutter_location/ios`) - amap_flutter_map (from `.symlinks/plugins/amap_flutter_map/ios`) + - audio_session (from `.symlinks/plugins/audio_session/ios`) + - audioplayers_darwin (from `.symlinks/plugins/audioplayers_darwin/ios`) - auto_orientation (from `.symlinks/plugins/auto_orientation/ios`) - camera_avfoundation (from `.symlinks/plugins/camera_avfoundation/ios`) - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - Flutter (from `Flutter`) - flutter_native_contact_picker (from `.symlinks/plugins/flutter_native_contact_picker/ios`) + - flutter_sound (from `.symlinks/plugins/flutter_sound/ios`) - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`) + - g711_flutter (from `.symlinks/plugins/g711_flutter/ios`) - google_maps_flutter_ios (from `.symlinks/plugins/google_maps_flutter_ios/ios`) + - image_gallery_saver (from `.symlinks/plugins/image_gallery_saver/ios`) - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) + - just_audio (from `.symlinks/plugins/just_audio/ios`) - network_info_plus (from `.symlinks/plugins/network_info_plus/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) @@ -119,6 +139,7 @@ SPEC REPOS: - AMap3DMap - AMapFoundation - AMapLocation + - flutter_sound_core - FMDB - GoogleMaps - Protobuf @@ -134,6 +155,10 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/amap_flutter_location/ios" amap_flutter_map: :path: ".symlinks/plugins/amap_flutter_map/ios" + audio_session: + :path: ".symlinks/plugins/audio_session/ios" + audioplayers_darwin: + :path: ".symlinks/plugins/audioplayers_darwin/ios" auto_orientation: :path: ".symlinks/plugins/auto_orientation/ios" camera_avfoundation: @@ -144,12 +169,20 @@ EXTERNAL SOURCES: :path: Flutter flutter_native_contact_picker: :path: ".symlinks/plugins/flutter_native_contact_picker/ios" + flutter_sound: + :path: ".symlinks/plugins/flutter_sound/ios" fluttertoast: :path: ".symlinks/plugins/fluttertoast/ios" + g711_flutter: + :path: ".symlinks/plugins/g711_flutter/ios" google_maps_flutter_ios: :path: ".symlinks/plugins/google_maps_flutter_ios/ios" + image_gallery_saver: + :path: ".symlinks/plugins/image_gallery_saver/ios" image_picker_ios: :path: ".symlinks/plugins/image_picker_ios/ios" + just_audio: + :path: ".symlinks/plugins/just_audio/ios" network_info_plus: :path: ".symlinks/plugins/network_info_plus/ios" package_info_plus: @@ -184,31 +217,38 @@ SPEC CHECKSUMS: amap_flutter_map: 979e54d227cedac6c7504a2151bfbf3bcf96760a AMapFoundation: 9885c48fc3a78fdfb84a0299a2293e56ea3c9fec AMapLocation: 5248aec2455ebb5d104b367813c946430a2ee033 + audio_session: 4f3e461722055d21515cf3261b64c973c062f345 + audioplayers_darwin: 877d9a4d06331c5c374595e46e16453ac7eafa40 auto_orientation: 102ed811a5938d52c86520ddd7ecd3a126b5d39d camera_avfoundation: 3125e8cd1a4387f6f31c6c63abb8a55892a9eeeb device_info_plus: e5c5da33f982a436e103237c0c85f9031142abed EMASRest: 8df6f87836767a9415ad5cc4af739bc9d215b475 Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 flutter_native_contact_picker: bd430ba0fbf82768bb50c2c52a69a65759a8f907 - fluttertoast: 31b00dabfa7fb7bacd9e7dbee580d7a2ff4bf265 + flutter_sound: c60effa2a350fb977885f0db2fbc4c1ad5160900 + flutter_sound_core: 26c10e5832e76aaacfae252d8925232281c486ae + fluttertoast: fafc4fa4d01a6a9e4f772ecd190ffa525e9e2d9c FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a + g711_flutter: 8f2769052d2cf3549f83d11e1c42d81d94441123 google_maps_flutter_ios: abdac20d6ce8931f6ebc5f46616df241bfaa2cfd GoogleMaps: 025272d5876d3b32604e5c080dc25eaf68764693 + image_gallery_saver: cb43cc43141711190510e92c460eb1655cd343cb image_picker_ios: 4a8aadfbb6dc30ad5141a2ce3832af9214a705b5 + just_audio: baa7252489dbcf47a4c7cc9ca663e9661c99aafa network_info_plus: 6d0c3eb8367b8164fa3fb0c19875e3f59d49697f package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6 - Protobuf: d94761c33f1239c0a43a0817ca1a5f7f7c900241 + Protobuf: 6a4183ec1d51649eb2be7b86ccc286e5c539219c reactive_ble_mobile: 9ce6723d37ccf701dbffd202d487f23f5de03b4c shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126 sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a SwiftProtobuf: 69f02cd54fb03201c5e6bf8b76f687c5ef7541a3 Toast: 91b396c56ee72a5790816f40d3a94dd357abc196 - url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4 + url_launcher_ios: bf5ce03e0e2088bad9cc378ea97fa0ed5b49673b video_player_avfoundation: 81e49bb3d9fb63dccf9fa0f6d877dc3ddbeac126 webview_flutter_wkwebview: 2e2d318f21a5e036e2c3f26171342e95908bd60a PODFILE CHECKSUM: adf6d8caf5faa9ea4ee2a2ea37f5aea37a6520d7 -COCOAPODS: 1.14.3 +COCOAPODS: 1.12.1 diff --git a/star_lock/ios/Runner.xcodeproj/project.pbxproj b/star_lock/ios/Runner.xcodeproj/project.pbxproj index c4056a2b..382e887c 100644 --- a/star_lock/ios/Runner.xcodeproj/project.pbxproj +++ b/star_lock/ios/Runner.xcodeproj/project.pbxproj @@ -666,7 +666,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1430; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { diff --git a/star_lock/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/star_lock/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 77bd9a21..2820dca7 100644 --- a/star_lock/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/star_lock/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ data = iframe!.bb!.sublist(0, iframe!.cur_len); - print('播放第${iframe!.iframeIndex}帧 一帧图片的Data: $growableList'); - String hexString = - uint8ListToHexString(Uint8List.fromList(growableList)); - // print('播放第${iframe!.iframeIndex}帧 hexStringLength:${hexString.length} 一帧图片的hexStringData: $hexString'); // 输出: 0a141e28 - - // if (iframe!.iframeIndex == 1) { - print('下面就是你要的'); - printByteArray('播放第${iframe!.iframeIndex}帧 一帧图片的hexStringData: ', - Uint8List.fromList(growableList)); + print( + '播放第${iframe!.iframeIndex}帧 一帧图片的hexStringData: ${Uint8List.fromList(growableList)}'); eventBus.fire(GetTVDataRefreshUI(growableList)); - // } - // eventBus.fire(GetTVDataRefreshUI(growableList)); } - - // Get.toNamed(Routers.lockMonitoringPage, arguments: { - // "lockId": "111" - // }); - // 打印拷贝后的目标数据 - // print(iframe.bb); } } +//视频相关处理 void printByteArray(String printTitle, Uint8List byteArray) { final int chunkSize = byteArray.length; // 每行显示的字节数 int length = byteArray.length; @@ -164,29 +127,7 @@ class CallTalk { } } - String uint8ListToHexString(Uint8List uint8List) { - return hex.encode(uint8List); - } - - int getShortFromByte(Uint8List bb, int pos) { - ByteData byteData = ByteData.sublistView(bb, pos, pos + 2); - return byteData.getInt16(0, Endian.little); - } - - void copyBytes(Uint8List destination, int destStart, Uint8List source, - int sourceStart, int length) { - if (destination.length < destStart + length || - source.length < sourceStart + length) { - // 处理越界的情况,这里你可以抛出异常或者进行其他处理 - print('Error: Index out of range'); - return; - } - - for (int i = 0; i < length; i++) { - destination[destStart + i] = source[sourceStart + i]; - } - } - + //音频相关处理 Future _initializeAudioPlayer() async { await _audioPlayer.openPlayer(); } From 962c7cfdedf395362a8685e5fce415008587fb7c Mon Sep 17 00:00:00 2001 From: Daisy <> Date: Wed, 20 Dec 2023 16:52:18 +0800 Subject: [PATCH 11/33] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E6=94=B6=E5=88=B0?= =?UTF-8?q?=E8=A7=86=E9=A2=91=E6=95=B0=E6=8D=AE=E5=90=8E=E5=8A=A0=E8=BD=BD?= =?UTF-8?q?=E5=88=B7=E6=96=B0=E7=99=BD=E5=B1=8F=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../monitoring/lockMonitoring_logic.dart | 17 ++- .../monitoring/lockMonitoring_page.dart | 105 +++++++++--------- .../monitoring/lockMonitoring_state.dart | 4 +- star_lock/lib/talk/call/callTalk.dart | 12 +- star_lock/lib/talk/udp/udp_help.dart | 23 ++-- star_lock/lib/talk/udp/udp_talkClass.dart | 41 ++++--- star_lock/lib/tools/eventBusEventManage.dart | 30 +++-- 7 files changed, 132 insertions(+), 100 deletions(-) diff --git a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_logic.dart b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_logic.dart index 8efa1e76..e02602e2 100644 --- a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_logic.dart +++ b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_logic.dart @@ -1,6 +1,7 @@ - import 'dart:async'; +import 'package:flutter/services.dart'; + import '../../../../tools/baseGetXController.dart'; import '../../../../tools/eventBusEventManage.dart'; import 'lockMonitoring_state.dart'; @@ -12,8 +13,14 @@ class LockMonitoringLogic extends BaseGetXController { StreamSubscription? _getTVDataRefreshUIEvent; void _getTVDataRefreshUIAction() { // 蓝牙协议通知传输跟蓝牙之外的数据传输类不一样 eventBus - _getTVDataRefreshUIEvent = eventBus.on().listen((event) { - state.listData.value = event.tvList; + _getTVDataRefreshUIEvent = + eventBus.on().listen((event) { + if (event.tvList.isNotEmpty) { + // 预加载图片数据 + Uint8List imageData = Uint8List.fromList(event.tvList); + // 更新状态 + state.listData.value = imageData; + } }); } @@ -30,7 +37,6 @@ class LockMonitoringLogic extends BaseGetXController { void onInit() { // TODO: implement onInit super.onInit(); - } @override @@ -39,5 +45,4 @@ class LockMonitoringLogic extends BaseGetXController { print("锁详情界面销毁了"); _getTVDataRefreshUIEvent!.cancel(); } - -} \ No newline at end of file +} diff --git a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart index 4bb5d31c..6bf7186b 100644 --- a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart +++ b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; @@ -23,63 +25,60 @@ class _LockMonitoringPageState extends State { return SizedBox( width: 1.sw, height: 1.sh, - // color: Colors.transparent, child: Stack( - // alignment: Alignment.bottomCenter, - children: [ - // state.listData.value.isEmpty ? Image.asset("images/icon_test20231113.png", width: 1.sw, height: 1.sh, fit: BoxFit.cover) : - Obx(() => - state.listData.value.isEmpty - ? Container(color: Colors.red) - :Image.memory( - Uint8List.fromList(state.listData.value), - width: 1.sw, - height: 1.sh, - fit: BoxFit.cover, - )), - Positioned( - top: ScreenUtil().statusBarHeight + 30.h, - child: Row(children: [ - SizedBox(width: 30.w), - GestureDetector( - onTap: () { - Get.back(); - }, - child: Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(25.h)), - padding: EdgeInsets.all(10.w), - child: Image( - width: 40.w, - height: 40.w, - image: const AssetImage("images/icon_left_black.png"), - ), - ), + children: [ + Obx(() => state.listData.value.isEmpty + ? Container(color: Colors.transparent) + : Image.memory( + state.listData.value, + gaplessPlayback: true, + width: 1.sw, + height: 1.sh, + fit: BoxFit.cover, + )), + Positioned( + top: ScreenUtil().statusBarHeight + 30.h, + child: Row(children: [ + SizedBox(width: 30.w), + GestureDetector( + onTap: () { + Get.back(); + }, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(25.h)), + padding: EdgeInsets.all(10.w), + child: Image( + width: 40.w, + height: 40.w, + image: const AssetImage("images/icon_left_black.png"), ), - ]), + ), ), - Positioned( - bottom: 10.w, - child: Container( - width: 1.sw - 30.w * 2, - // height: 300.h, - margin: EdgeInsets.all(30.w), - decoration: BoxDecoration( - color: const Color(0xC83C3F41), - borderRadius: BorderRadius.circular(20.h)), - child: Column( - children: [ - SizedBox(height: 20.h), - bottomTopBtnWidget(), - SizedBox(height: 20.h), - bottomBottomBtnWidget(), - SizedBox(height: 20.h), - ], - ), - )) - ], + ]), ), + Positioned( + bottom: 10.w, + child: Container( + width: 1.sw - 30.w * 2, + // height: 300.h, + margin: EdgeInsets.all(30.w), + decoration: BoxDecoration( + color: const Color(0xC83C3F41), + borderRadius: BorderRadius.circular(20.h)), + child: Column( + children: [ + SizedBox(height: 20.h), + bottomTopBtnWidget(), + SizedBox(height: 20.h), + bottomBottomBtnWidget(), + SizedBox(height: 20.h), + ], + ), + )) + ], + ), ); } diff --git a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_state.dart b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_state.dart index ed1135ca..977559ef 100644 --- a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_state.dart +++ b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_state.dart @@ -5,9 +5,9 @@ import 'package:get/get.dart'; class LockMonitoringState { var isOpenVoice = false.obs; - var listData = [].obs; + var listData = Uint8List(0).obs; - Uint8List imageData = Uint8List.fromList([ + Uint8List imageData = Uint8List.fromList([ 255, 216, 255, diff --git a/star_lock/lib/talk/call/callTalk.dart b/star_lock/lib/talk/call/callTalk.dart index f09379aa..ceb81f90 100644 --- a/star_lock/lib/talk/call/callTalk.dart +++ b/star_lock/lib/talk/call/callTalk.dart @@ -1,6 +1,9 @@ import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:flutter_sound/flutter_sound.dart'; +import 'package:get/get.dart'; +import 'package:get/get_core/src/get_main.dart'; +import 'package:star_lock/appRouters.dart'; import 'package:star_lock/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart'; import 'package:star_lock/talk/call/g711Decoder.dart'; import 'package:star_lock/talk/call/iFrameInfo.dart'; @@ -21,7 +24,7 @@ class CallTalk { int status = 0; // 假设有这个成员变量 IframeInfo? iframe; // 假设有这个成员变量 var growableList; - LockMonitoringPage callOut = const LockMonitoringPage(); + bool getFirstFrame = false; //是否得到了第一帧 final FlutterSoundPlayer _audioPlayer = FlutterSoundPlayer(); CallTalk._init() { @@ -107,6 +110,13 @@ class CallTalk { if (iframe!.bagNum == iframe!.bagReceive) { print( '播放第${iframe!.iframeIndex}帧 一帧图片的hexStringData: ${Uint8List.fromList(growableList)}'); + + //判断第一帧是否接收到 + if (iframe!.iframeIndex == 0) { + getFirstFrame = true; + eventBus.fire(GetFirstFrameGoPush(getFirstFrame)); + } + eventBus.fire(GetTVDataRefreshUI(growableList)); } } diff --git a/star_lock/lib/talk/udp/udp_help.dart b/star_lock/lib/talk/udp/udp_help.dart index c6bea328..6b47e50b 100644 --- a/star_lock/lib/talk/udp/udp_help.dart +++ b/star_lock/lib/talk/udp/udp_help.dart @@ -1,5 +1,3 @@ - - import 'dart:async'; import 'dart:io'; @@ -10,32 +8,33 @@ import '../../tools/storage.dart'; import 'udp_manage.dart'; import 'udp_senderManage.dart'; -class UdpHelp{ - +class UdpHelp { openUDP() async { // 从服务器获取ip跟端口 var entity = await ApiRepository.to.getWifiLockServiceIpAndPort(); - if(entity.errorCode! == 0){ + if (entity.errorCode! == 0) { UDPManage(); // UDPManage().initUdp(); // UDPManage().host = entity.data!.serviceList![0].serviceIp!; // UDPManage().port = int.parse(entity.data!.serviceList![0].port!); var serversList = []; - for(int i = 0; i addresses = await InternetAddress.lookup(item.serviceIp!); + } else { + List addresses = + await InternetAddress.lookup(item.serviceIp!); var itemList = addresses.first.address.split("."); for (var element in itemList) { serversList.add(int.parse(element)); } - print('Resolved google.com to address: ${addresses.first.address} serversList:${serversList}'); + print( + 'Resolved google.com to address: ${addresses.first.address} serversList:${serversList}'); } } @@ -51,9 +50,7 @@ class UdpHelp{ Future getWifiLockServiceIpAndPort() async { var entity = await ApiRepository.to.getWifiLockServiceIpAndPort(); - if(entity.errorCode! == 0){ - - } + if (entity.errorCode! == 0) {} } } diff --git a/star_lock/lib/talk/udp/udp_talkClass.dart b/star_lock/lib/talk/udp/udp_talkClass.dart index 05d0739b..cf47132b 100644 --- a/star_lock/lib/talk/udp/udp_talkClass.dart +++ b/star_lock/lib/talk/udp/udp_talkClass.dart @@ -1,28 +1,29 @@ - import 'dart:async'; import 'package:fast_gbk/fast_gbk.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:star_lock/tools/eventBusEventManage.dart'; import '../../appRouters.dart'; import '../../main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart'; import '../../tools/storage.dart'; import 'udp_manage.dart'; -class UDPTalkClass{ +class UDPTalkClass { static UDPTalkClass? _manager; - static UDPTalkClass _share(){ + static UDPTalkClass _share() { _manager ??= UDPTalkClass._init(); return _manager!; } + factory UDPTalkClass() => _share(); UDPTalkClass get manager => _share(); UDPTalkClass._init(); - var status = 0;// 0空闲 - var remoteEquid;// 手机号 + var status = 0; // 0空闲 + var remoteEquid; // 手机号 late Timer timer; // 该字段是为了判断是否跳转到接听界面 挂断或者退出接听界面要记得变更状态 var isBeCall = false; @@ -33,7 +34,7 @@ class UDPTalkClass{ // return; // } - if(status == 0){ + if (status == 0) { // 空闲 // 响铃 // [[Pub getApp] ring]; @@ -65,22 +66,36 @@ class UDPTalkClass{ data[8] = 9; UDPManage().sendData(data); }); + + // _getFirstFrameGoPushAction(); + Future.delayed(const Duration(seconds: 1), () { + // 在这里写要延迟执行的代码 + Get.toNamed(Routers.lockMonitoringPage, arguments: {"lockId": "111"}); + }); } - - Get.toNamed(Routers.lockMonitoringPage, arguments: { - "lockId": "111" - }); - }else{ + } else { // 忙 - } } + void _getFirstFrameGoPushAction() { + // 蓝牙协议通知传输跟蓝牙之外的数据传输类不一样 eventBus + StreamSubscription _GetFirstFrameGoPushEvent = + eventBus.on().listen((event) { + if (event.isFirstFrame == true) { + Future.delayed(const Duration(seconds: 1), () { + // 在这里写要延迟执行的代码 + Get.toNamed(Routers.lockMonitoringPage, arguments: {"lockId": "111"}); + }); + } + }); + } + // 判断是否是call的本人 Future isCallMe(List? data) async { final loginData = await Storage.getLoginData(); print("getEquidFrombb(data, 1000):${getEquidFrombb(data, 12)}"); - if(loginData!.mobile == getEquidFrombb(data, 12)){ + if (loginData!.mobile == getEquidFrombb(data, 12)) { return true; } return false; diff --git a/star_lock/lib/tools/eventBusEventManage.dart b/star_lock/lib/tools/eventBusEventManage.dart index 7958e493..84b58165 100644 --- a/star_lock/lib/tools/eventBusEventManage.dart +++ b/star_lock/lib/tools/eventBusEventManage.dart @@ -6,58 +6,64 @@ import '../main/lockDetail/lcokSet/lockSet/lockSetInfo_entity.dart'; EventBus eventBus = EventBus(); /// 刷新锁列表数据 -class RefreshLockListInfoDataEvent{ +class RefreshLockListInfoDataEvent { RefreshLockListInfoDataEvent(); } /// 刷新考勤员工列表 -class RefreshCheckInStaffListDataEvent{ +class RefreshCheckInStaffListDataEvent { RefreshCheckInStaffListDataEvent(); } /// 传递当前锁信息 -class PassCurrentLockInformationEvent{ +class PassCurrentLockInformationEvent { LockSetInfoData lockSetInfoData; PassCurrentLockInformationEvent(this.lockSetInfoData); } /// 卡、密码、指纹修改之后刷新列表 -class OtherTypeRefreshListEvent{ +class OtherTypeRefreshListEvent { OtherTypeRefreshListEvent(); } /// 考情添加员工卡、指纹之后回调卡、指纹number -class ChickInAddStaffCardAndFingerprintBlockNumberEvent{ +class ChickInAddStaffCardAndFingerprintBlockNumberEvent { String number; ChickInAddStaffCardAndFingerprintBlockNumberEvent(this.number); } /// Uuid删除当前锁时 有可能锁被初始化了 但后台没被初始化 当打开APP的时候扫描如果未被连接就传uuid过去 判断直接删除数据 -class ScanAllDeviceFindCurrentDeviceConnectedEvent{ +class ScanAllDeviceFindCurrentDeviceConnectedEvent { String uuid; ScanAllDeviceFindCurrentDeviceConnectedEvent(this.uuid); } /// 多语言 切换之后传值到上一级界面 -class ChangeLanguageBlockLastLanguageEvent{ +class ChangeLanguageBlockLastLanguageEvent { String languageTitle; ChangeLanguageBlockLastLanguageEvent(this.languageTitle); } /// 锁分组添加或者删除锁之后刷新首页数据 -class LockGroupEditGroupLockRefreshEvent{ +class LockGroupEditGroupLockRefreshEvent { LockGroupEditGroupLockRefreshEvent(); } /// 锁设置里面开启关闭刷新锁详情 -class LockSetChangeSetRefreshLockDetailWithType{ - int type;// 0 考勤 1开锁时是否需联网 +class LockSetChangeSetRefreshLockDetailWithType { + int type; // 0 考勤 1开锁时是否需联网 int setResult; LockSetChangeSetRefreshLockDetailWithType(this.type, this.setResult); } /// 获取到视频流数据然后刷新界面 -class GetTVDataRefreshUI{ +class GetTVDataRefreshUI { List tvList; GetTVDataRefreshUI(this.tvList); -} \ No newline at end of file +} + +/// 获取到第一帧图片数据后跳转 +class GetFirstFrameGoPush { + bool isFirstFrame; + GetFirstFrameGoPush(this.isFirstFrame); +} From ca3e9a62c716cc68c8dc91f0f0b1eaf8a4bf8009 Mon Sep 17 00:00:00 2001 From: Daisy <> Date: Thu, 21 Dec 2023 10:18:02 +0800 Subject: [PATCH 12/33] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=BD=95=E9=9F=B3?= =?UTF-8?q?=E6=96=B9=E6=B3=95=EF=BC=88=E5=BE=85=E9=AA=8C=E8=AF=81=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../monitoring/lockMonitoring_page.dart | 49 +- .../monitoring/lockMonitoring_state.dart | 14165 +--------------- 2 files changed, 47 insertions(+), 14167 deletions(-) diff --git a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart index 6bf7186b..797f9c5d 100644 --- a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart +++ b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart @@ -1,11 +1,9 @@ -import 'dart:convert'; - import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:flutter_sound/flutter_sound.dart'; import 'package:get/get.dart'; -import '../../../../appRouters.dart'; import '../../../../app_settings/app_colors.dart'; import 'lockMonitoring_logic.dart'; @@ -20,6 +18,17 @@ class _LockMonitoringPageState extends State { final logic = Get.put(LockMonitoringLogic()); final state = Get.find().state; + late FlutterSoundRecorder recorder; + late FlutterSoundPlayer player; + late String filePath; + + @override + void initState() { + super.initState(); + + _initRecorder(); + } + @override Widget build(BuildContext context) { return SizedBox( @@ -31,6 +40,7 @@ class _LockMonitoringPageState extends State { ? Container(color: Colors.transparent) : Image.memory( state.listData.value, + // key: ValueKey(state.listData.value.hashCode), gaplessPlayback: true, width: 1.sw, height: 1.sh, @@ -177,4 +187,37 @@ class _LockMonitoringPageState extends State { )), ); } + + //录音处理 + _initRecorder() { + recorder = FlutterSoundRecorder(); + } + +//开始录音 + _startRecording() async { + filePath = 'your_output_file.wav'; + await recorder.startRecorder( + toFile: filePath, + codec: Codec.pcm16WAV, + ); + } + +//停止录音 + _stopRecording() async { + await recorder.stopRecorder(); + } + +//播放录音 + _playRecording() async { + player = FlutterSoundPlayer(); + await player.startPlayer( + fromURI: filePath, + codec: Codec.pcm16WAV, + ); + } + +//停止播放 + _stopPlaying() async { + await player.stopPlayer(); + } } diff --git a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_state.dart b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_state.dart index 977559ef..113b1393 100644 --- a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_state.dart +++ b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_state.dart @@ -5,14168 +5,5 @@ import 'package:get/get.dart'; class LockMonitoringState { var isOpenVoice = false.obs; - var listData = Uint8List(0).obs; - - Uint8List imageData = Uint8List.fromList([ - 255, - 216, - 255, - 224, - 0, - 17, - 74, - 70, - 73, - 70, - 0, - 1, - 1, - 0, - 0, - 1, - 0, - 1, - 0, - 0, - 204, - 255, - 225, - 0, - 166, - 69, - 120, - 105, - 102, - 0, - 0, - 77, - 77, - 0, - 42, - 0, - 0, - 0, - 8, - 0, - 8, - 1, - 15, - 0, - 2, - 0, - 0, - 0, - 7, - 0, - 0, - 0, - 122, - 1, - 16, - 0, - 2, - 0, - 0, - 0, - 8, - 0, - 0, - 0, - 130, - 1, - 18, - 0, - 3, - 0, - 0, - 0, - 1, - 0, - 1, - 0, - 0, - 1, - 26, - 0, - 5, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 38, - 1, - 27, - 0, - 5, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 38, - 1, - 40, - 0, - 3, - 0, - 0, - 0, - 1, - 0, - 2, - 0, - 0, - 2, - 19, - 0, - 3, - 0, - 0, - 0, - 1, - 0, - 1, - 0, - 0, - 135, - 105, - 0, - 4, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 138, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 4, - 105, - 112, - 112, - 0, - 0, - 0, - 3, - 194, - 74, - 76, - 68, - 86, - 0, - 0, - 0, - 0, - 65, - 67, - 53, - 52, - 0, - 0, - 0, - 0, - 0, - 1, - 144, - 0, - 0, - 7, - 0, - 0, - 0, - 4, - 48, - 50, - 50, - 48, - 0, - 0, - 0, - 0, - 0, - 0, - 255, - 219, - 0, - 67, - 0, - 40, - 28, - 30, - 35, - 30, - 25, - 40, - 35, - 33, - 35, - 45, - 43, - 40, - 48, - 60, - 100, - 65, - 60, - 55, - 55, - 60, - 123, - 88, - 93, - 73, - 100, - 145, - 128, - 153, - 150, - 143, - 128, - 140, - 138, - 160, - 180, - 230, - 195, - 160, - 170, - 218, - 173, - 138, - 140, - 200, - 255, - 203, - 218, - 238, - 245, - 255, - 255, - 255, - 155, - 193, - 255, - 255, - 255, - 250, - 255, - 230, - 253, - 255, - 248, - 255, - 219, - 0, - 67, - 1, - 43, - 45, - 45, - 60, - 53, - 60, - 118, - 65, - 65, - 118, - 248, - 165, - 140, - 165, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 248, - 255, - 192, - 0, - 17, - 8, - 1, - 224, - 2, - 128, - 3, - 1, - 34, - 0, - 2, - 17, - 1, - 3, - 17, - 1, - 255, - 196, - 0, - 31, - 0, - 0, - 1, - 5, - 1, - 1, - 1, - 1, - 1, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 255, - 196, - 0, - 31, - 1, - 0, - 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 255, - 196, - 0, - 181, - 16, - 0, - 2, - 1, - 3, - 3, - 2, - 4, - 3, - 5, - 5, - 4, - 4, - 0, - 0, - 1, - 125, - 1, - 2, - 3, - 0, - 4, - 17, - 5, - 18, - 33, - 49, - 65, - 6, - 19, - 81, - 97, - 7, - 34, - 113, - 20, - 50, - 129, - 145, - 161, - 8, - 35, - 66, - 177, - 193, - 21, - 82, - 209, - 240, - 36, - 51, - 98, - 114, - 130, - 9, - 10, - 22, - 23, - 24, - 25, - 26, - 37, - 38, - 39, - 40, - 41, - 42, - 52, - 53, - 54, - 55, - 56, - 57, - 58, - 67, - 68, - 69, - 70, - 71, - 72, - 73, - 74, - 83, - 84, - 85, - 86, - 87, - 88, - 89, - 90, - 99, - 100, - 101, - 102, - 103, - 104, - 105, - 106, - 115, - 116, - 117, - 118, - 119, - 120, - 121, - 122, - 131, - 132, - 133, - 134, - 135, - 136, - 137, - 138, - 146, - 147, - 148, - 149, - 150, - 151, - 152, - 153, - 154, - 162, - 163, - 164, - 165, - 166, - 167, - 168, - 169, - 170, - 178, - 179, - 180, - 181, - 182, - 183, - 184, - 185, - 186, - 194, - 195, - 196, - 197, - 198, - 199, - 200, - 201, - 202, - 210, - 211, - 212, - 213, - 214, - 215, - 216, - 217, - 218, - 225, - 226, - 227, - 228, - 229, - 230, - 231, - 232, - 233, - 234, - 241, - 242, - 243, - 244, - 245, - 246, - 247, - 248, - 249, - 250, - 255, - 196, - 0, - 181, - 17, - 0, - 2, - 1, - 2, - 4, - 4, - 3, - 4, - 7, - 5, - 4, - 4, - 0, - 1, - 2, - 119, - 0, - 1, - 2, - 3, - 17, - 4, - 5, - 33, - 49, - 6, - 18, - 65, - 81, - 7, - 97, - 113, - 19, - 34, - 50, - 129, - 8, - 20, - 66, - 145, - 161, - 177, - 193, - 9, - 35, - 51, - 82, - 240, - 21, - 98, - 114, - 209, - 10, - 22, - 36, - 52, - 225, - 37, - 241, - 23, - 24, - 25, - 26, - 38, - 39, - 40, - 41, - 42, - 53, - 54, - 55, - 56, - 57, - 58, - 67, - 68, - 69, - 70, - 71, - 72, - 73, - 74, - 83, - 84, - 85, - 86, - 87, - 88, - 89, - 90, - 99, - 100, - 101, - 102, - 103, - 104, - 105, - 106, - 115, - 116, - 117, - 118, - 119, - 120, - 121, - 122, - 130, - 131, - 132, - 133, - 134, - 135, - 136, - 137, - 138, - 146, - 147, - 148, - 149, - 150, - 151, - 152, - 153, - 154, - 162, - 163, - 164, - 165, - 166, - 167, - 168, - 169, - 170, - 178, - 179, - 180, - 181, - 182, - 183, - 184, - 185, - 186, - 194, - 195, - 196, - 197, - 198, - 199, - 200, - 201, - 202, - 210, - 211, - 212, - 213, - 214, - 215, - 216, - 217, - 218, - 226, - 227, - 228, - 229, - 230, - 231, - 232, - 233, - 234, - 242, - 243, - 244, - 245, - 246, - 247, - 248, - 249, - 250, - 255, - 218, - 0, - 12, - 3, - 1, - 0, - 2, - 17, - 3, - 17, - 0, - 63, - 0, - 207, - 162, - 138, - 41, - 0, - 81, - 69, - 20, - 192, - 40, - 162, - 138, - 0, - 41, - 105, - 41, - 104, - 0, - 162, - 138, - 40, - 0, - 162, - 138, - 40, - 0, - 162, - 138, - 40, - 0, - 162, - 138, - 40, - 0, - 162, - 138, - 40, - 0, - 162, - 138, - 40, - 0, - 162, - 138, - 40, - 0, - 162, - 138, - 40, - 0, - 162, - 138, - 40, - 0, - 162, - 138, - 40, - 0, - 165, - 164, - 165, - 164, - 1, - 69, - 20, - 80, - 48, - 164, - 165, - 162, - 128, - 18, - 150, - 138, - 40, - 16, - 81, - 69, - 20, - 12, - 40, - 162, - 138, - 0, - 40, - 162, - 138, - 4, - 20, - 81, - 69, - 0, - 20, - 148, - 180, - 80, - 48, - 164, - 165, - 164, - 160, - 2, - 138, - 40, - 160, - 66, - 210, - 82, - 209, - 64, - 9, - 69, - 45, - 37, - 3, - 10, - 90, - 74, - 40, - 16, - 81, - 69, - 20, - 0, - 180, - 82, - 82, - 208, - 1, - 69, - 20, - 80, - 1, - 73, - 75, - 69, - 0, - 20, - 81, - 69, - 48, - 10, - 41, - 40, - 160, - 5, - 162, - 146, - 138, - 0, - 40, - 162, - 138, - 0, - 40, - 162, - 146, - 129, - 5, - 45, - 37, - 45, - 0, - 20, - 162, - 146, - 148, - 80, - 3, - 197, - 58, - 154, - 41, - 192, - 80, - 4, - 20, - 81, - 69, - 3, - 10, - 40, - 162, - 128, - 10, - 40, - 162, - 128, - 22, - 138, - 74, - 90, - 0, - 40, - 162, - 138, - 0, - 40, - 162, - 138, - 0, - 40, - 162, - 138, - 0, - 40, - 162, - 138, - 0, - 40, - 162, - 138, - 0, - 40, - 162, - 138, - 0, - 40, - 162, - 138, - 0, - 40, - 162, - 150, - 129, - 137, - 69, - 45, - 37, - 2, - 10, - 41, - 104, - 160, - 98, - 81, - 75, - 69, - 33, - 5, - 20, - 81, - 76, - 2, - 138, - 40, - 160, - 97, - 69, - 20, - 80, - 1, - 69, - 20, - 80, - 1, - 69, - 20, - 82, - 0, - 162, - 138, - 40, - 16, - 81, - 69, - 20, - 192, - 40, - 162, - 138, - 6, - 20, - 81, - 69, - 0, - 20, - 81, - 69, - 2, - 10, - 40, - 162, - 144, - 9, - 75, - 69, - 20, - 0, - 81, - 69, - 20, - 12, - 41, - 41, - 105, - 40, - 16, - 180, - 82, - 81, - 64, - 11, - 69, - 37, - 45, - 0, - 20, - 81, - 73, - 64, - 5, - 20, - 81, - 64, - 5, - 20, - 81, - 76, - 2, - 138, - 92, - 81, - 64, - 9, - 69, - 20, - 80, - 2, - 81, - 75, - 73, - 64, - 130, - 150, - 146, - 150, - 128, - 10, - 81, - 73, - 74, - 40, - 1, - 235, - 82, - 129, - 81, - 173, - 74, - 40, - 2, - 165, - 20, - 81, - 64, - 194, - 138, - 40, - 164, - 1, - 69, - 45, - 20, - 192, - 40, - 162, - 138, - 0, - 40, - 162, - 138, - 0, - 40, - 162, - 138, - 0, - 40, - 165, - 162, - 128, - 18, - 138, - 90, - 40, - 1, - 40, - 165, - 164, - 160, - 2, - 138, - 90, - 49, - 64, - 5, - 20, - 98, - 138, - 0, - 40, - 162, - 138, - 0, - 40, - 165, - 2, - 157, - 182, - 128, - 25, - 70, - 42, - 77, - 180, - 161, - 40, - 2, - 60, - 81, - 138, - 147, - 109, - 24, - 160, - 87, - 35, - 197, - 20, - 242, - 41, - 166, - 129, - 137, - 69, - 20, - 162, - 128, - 19, - 20, - 184, - 167, - 1, - 78, - 2, - 128, - 35, - 219, - 70, - 218, - 151, - 20, - 98, - 128, - 185, - 22, - 218, - 93, - 181, - 38, - 40, - 160, - 87, - 35, - 197, - 38, - 41, - 230, - 154, - 104, - 1, - 180, - 81, - 69, - 3, - 12, - 82, - 237, - 165, - 20, - 240, - 40, - 1, - 155, - 104, - 219, - 82, - 224, - 81, - 138, - 5, - 114, - 29, - 180, - 109, - 169, - 182, - 209, - 138, - 66, - 185, - 14, - 218, - 66, - 42, - 82, - 41, - 132, - 83, - 26, - 99, - 40, - 165, - 197, - 24, - 160, - 98, - 81, - 78, - 219, - 70, - 218, - 0, - 109, - 20, - 165, - 72, - 164, - 164, - 1, - 69, - 20, - 80, - 48, - 164, - 165, - 164, - 160, - 66, - 210, - 81, - 69, - 0, - 20, - 81, - 69, - 0, - 20, - 82, - 82, - 208, - 2, - 209, - 73, - 70, - 105, - 128, - 180, - 98, - 129, - 75, - 64, - 13, - 162, - 148, - 210, - 80, - 33, - 41, - 104, - 162, - 128, - 10, - 81, - 73, - 78, - 2, - 128, - 30, - 181, - 42, - 212, - 74, - 42, - 85, - 226, - 128, - 42, - 209, - 69, - 20, - 12, - 40, - 162, - 138, - 6, - 20, - 81, - 69, - 2, - 10, - 40, - 162, - 128, - 10, - 90, - 40, - 160, - 2, - 138, - 49, - 75, - 138, - 0, - 74, - 41, - 104, - 160, - 2, - 140, - 82, - 129, - 78, - 2, - 128, - 25, - 182, - 151, - 109, - 60, - 10, - 118, - 40, - 2, - 61, - 180, - 109, - 169, - 49, - 72, - 104, - 16, - 204, - 83, - 77, - 60, - 211, - 77, - 0, - 54, - 148, - 81, - 138, - 90, - 6, - 40, - 20, - 225, - 77, - 20, - 241, - 64, - 10, - 41, - 192, - 83, - 105, - 232, - 9, - 25, - 160, - 45, - 112, - 197, - 53, - 170, - 109, - 148, - 141, - 23, - 20, - 13, - 65, - 149, - 141, - 52, - 213, - 143, - 39, - 52, - 162, - 220, - 30, - 180, - 138, - 228, - 101, - 90, - 81, - 87, - 214, - 210, - 16, - 57, - 92, - 159, - 173, - 50, - 72, - 99, - 31, - 117, - 64, - 250, - 83, - 14, - 86, - 85, - 6, - 156, - 13, - 59, - 203, - 197, - 33, - 90, - 87, - 14, - 70, - 25, - 164, - 221, - 72, - 69, - 38, - 40, - 23, - 40, - 237, - 212, - 155, - 169, - 184, - 162, - 130, - 108, - 41, - 52, - 211, - 75, - 138, - 93, - 180, - 192, - 101, - 21, - 38, - 204, - 209, - 229, - 154, - 0, - 104, - 52, - 224, - 104, - 242, - 205, - 27, - 13, - 0, - 46, - 234, - 93, - 212, - 205, - 164, - 81, - 131, - 233, - 64, - 135, - 110, - 163, - 117, - 51, - 6, - 146, - 128, - 176, - 226, - 212, - 220, - 210, - 81, - 64, - 210, - 22, - 148, - 83, - 104, - 205, - 3, - 37, - 81, - 82, - 5, - 6, - 161, - 86, - 169, - 85, - 168, - 37, - 138, - 83, - 138, - 141, - 163, - 169, - 195, - 2, - 41, - 9, - 20, - 137, - 43, - 21, - 197, - 52, - 138, - 153, - 170, - 38, - 160, - 105, - 140, - 163, - 52, - 81, - 138, - 101, - 5, - 20, - 237, - 180, - 133, - 77, - 32, - 27, - 69, - 46, - 41, - 41, - 128, - 81, - 69, - 20, - 0, - 180, - 80, - 41, - 104, - 0, - 165, - 164, - 160, - 80, - 1, - 73, - 78, - 164, - 52, - 0, - 148, - 81, - 69, - 2, - 20, - 84, - 138, - 42, - 49, - 79, - 83, - 64, - 19, - 1, - 197, - 6, - 154, - 166, - 159, - 140, - 208, - 50, - 165, - 20, - 82, - 208, - 2, - 82, - 209, - 75, - 64, - 9, - 69, - 45, - 0, - 80, - 49, - 40, - 2, - 165, - 84, - 169, - 86, - 49, - 233, - 64, - 136, - 2, - 26, - 119, - 150, - 106, - 200, - 64, - 41, - 74, - 208, - 23, - 42, - 109, - 164, - 197, - 74, - 194, - 163, - 52, - 8, - 109, - 37, - 45, - 24, - 160, - 96, - 41, - 194, - 140, - 26, - 80, - 166, - 128, - 20, - 26, - 92, - 208, - 16, - 211, - 196, - 102, - 128, - 35, - 205, - 24, - 38, - 166, - 17, - 84, - 139, - 21, - 0, - 86, - 17, - 19, - 235, - 75, - 246, - 126, - 249, - 53, - 117, - 99, - 160, - 165, - 49, - 20, - 124, - 172, - 83, - 132, - 85, - 107, - 203, - 165, - 9, - 64, - 238, - 87, - 88, - 135, - 165, - 57, - 98, - 201, - 171, - 1, - 105, - 225, - 104, - 17, - 7, - 146, - 41, - 66, - 96, - 99, - 29, - 42, - 198, - 41, - 49, - 65, - 73, - 145, - 5, - 164, - 97, - 206, - 42, - 99, - 128, - 42, - 34, - 50, - 106, - 90, - 54, - 140, - 144, - 220, - 82, - 138, - 93, - 180, - 187, - 105, - 88, - 110, - 104, - 66, - 213, - 11, - 181, - 78, - 87, - 138, - 173, - 50, - 28, - 113, - 79, - 81, - 115, - 161, - 140, - 226, - 155, - 184, - 26, - 174, - 229, - 129, - 193, - 20, - 138, - 228, - 81, - 98, - 92, - 203, - 36, - 83, - 77, - 52, - 62, - 69, - 52, - 181, - 22, - 5, - 49, - 244, - 10, - 64, - 185, - 239, - 74, - 84, - 47, - 66, - 77, - 52, - 153, - 18, - 104, - 92, - 10, - 51, - 81, - 151, - 166, - 150, - 162, - 196, - 19, - 6, - 169, - 20, - 138, - 169, - 184, - 210, - 172, - 132, - 119, - 166, - 5, - 224, - 160, - 211, - 182, - 85, - 120, - 166, - 171, - 11, - 32, - 52, - 132, - 2, - 47, - 106, - 67, - 21, - 74, - 172, - 41, - 220, - 80, - 50, - 185, - 139, - 218, - 155, - 229, - 123, - 85, - 154, - 118, - 40, - 2, - 153, - 134, - 163, - 49, - 85, - 242, - 5, - 70, - 202, - 40, - 11, - 148, - 76, - 102, - 147, - 97, - 171, - 155, - 40, - 49, - 138, - 2, - 229, - 61, - 166, - 128, - 72, - 171, - 6, - 58, - 97, - 74, - 7, - 114, - 61, - 196, - 81, - 190, - 148, - 173, - 33, - 90, - 65, - 97, - 11, - 83, - 9, - 167, - 21, - 164, - 197, - 48, - 18, - 156, - 41, - 180, - 103, - 20, - 1, - 50, - 129, - 78, - 41, - 80, - 135, - 197, - 76, - 175, - 145, - 64, - 152, - 198, - 142, - 152, - 80, - 213, - 140, - 138, - 105, - 197, - 34, - 28, - 138, - 229, - 113, - 77, - 169, - 159, - 165, - 68, - 104, - 26, - 98, - 10, - 80, - 105, - 40, - 166, - 89, - 32, - 165, - 197, - 52, - 26, - 118, - 104, - 1, - 166, - 146, - 156, - 105, - 40, - 1, - 180, - 82, - 209, - 64, - 130, - 156, - 180, - 220, - 83, - 212, - 80, - 50, - 69, - 28, - 212, - 234, - 6, - 42, - 21, - 226, - 165, - 86, - 160, - 10, - 84, - 180, - 184, - 163, - 20, - 0, - 148, - 81, - 69, - 0, - 45, - 57, - 105, - 180, - 229, - 160, - 9, - 148, - 84, - 171, - 80, - 169, - 169, - 3, - 80, - 4, - 162, - 152, - 198, - 144, - 18, - 105, - 226, - 50, - 105, - 138, - 197, - 118, - 4, - 211, - 54, - 19, - 86, - 204, - 84, - 162, - 33, - 233, - 64, - 202, - 130, - 35, - 82, - 44, - 85, - 103, - 203, - 20, - 161, - 61, - 168, - 2, - 1, - 21, - 60, - 69, - 197, - 78, - 20, - 83, - 130, - 208, - 4, - 2, - 58, - 112, - 142, - 166, - 43, - 73, - 138, - 4, - 48, - 32, - 167, - 5, - 2, - 150, - 138, - 0, - 81, - 72, - 122, - 209, - 72, - 104, - 1, - 40, - 162, - 148, - 80, - 2, - 83, - 133, - 54, - 156, - 40, - 1, - 212, - 220, - 210, - 154, - 109, - 0, - 45, - 38, - 41, - 105, - 40, - 1, - 69, - 46, - 40, - 20, - 80, - 2, - 26, - 97, - 64, - 105, - 230, - 129, - 64, - 21, - 38, - 128, - 30, - 213, - 81, - 237, - 202, - 244, - 173, - 98, - 51, - 81, - 180, - 96, - 208, - 51, - 32, - 171, - 14, - 162, - 144, - 31, - 99, - 90, - 166, - 0, - 123, - 83, - 77, - 184, - 244, - 160, - 10, - 8, - 222, - 185, - 167, - 51, - 130, - 56, - 205, - 90, - 54, - 227, - 251, - 181, - 20, - 176, - 145, - 210, - 157, - 198, - 149, - 202, - 189, - 77, - 61, - 98, - 45, - 222, - 151, - 111, - 53, - 60, - 56, - 21, - 55, - 27, - 129, - 92, - 219, - 181, - 70, - 200, - 203, - 214, - 181, - 70, - 210, - 57, - 166, - 73, - 10, - 176, - 166, - 77, - 140, - 176, - 216, - 169, - 82, - 67, - 235, - 73, - 60, - 69, - 14, - 69, - 70, - 185, - 6, - 144, - 172, - 94, - 73, - 13, - 72, - 37, - 245, - 53, - 90, - 35, - 82, - 26, - 5, - 98, - 202, - 56, - 53, - 40, - 35, - 21, - 68, - 54, - 13, - 74, - 178, - 80, - 4, - 228, - 211, - 77, - 51, - 125, - 25, - 160, - 7, - 80, - 104, - 205, - 52, - 154, - 4, - 6, - 152, - 105, - 73, - 166, - 208, - 2, - 98, - 147, - 109, - 62, - 138, - 2, - 228, - 101, - 105, - 133, - 42, - 108, - 81, - 138, - 101, - 92, - 174, - 82, - 154, - 86, - 172, - 145, - 77, - 42, - 13, - 0, - 86, - 193, - 160, - 18, - 166, - 167, - 41, - 77, - 217, - 72, - 6, - 249, - 148, - 134, - 67, - 74, - 99, - 166, - 148, - 52, - 172, - 43, - 33, - 11, - 102, - 155, - 154, - 92, - 26, - 74, - 99, - 176, - 229, - 25, - 171, - 240, - 91, - 43, - 32, - 56, - 172, - 244, - 59, - 79, - 181, - 104, - 89, - 92, - 99, - 228, - 99, - 211, - 165, - 0, - 19, - 89, - 113, - 149, - 224, - 213, - 70, - 70, - 66, - 67, - 14, - 149, - 184, - 10, - 186, - 228, - 84, - 19, - 66, - 27, - 156, - 83, - 11, - 152, - 230, - 146, - 172, - 203, - 6, - 210, - 72, - 226, - 171, - 145, - 138, - 66, - 184, - 218, - 81, - 73, - 74, - 40, - 24, - 224, - 42, - 69, - 20, - 197, - 169, - 86, - 129, - 139, - 70, - 121, - 167, - 129, - 78, - 218, - 61, - 40, - 2, - 2, - 184, - 166, - 17, - 83, - 61, - 68, - 104, - 1, - 134, - 146, - 157, - 183, - 52, - 245, - 140, - 208, - 3, - 0, - 167, - 170, - 154, - 153, - 98, - 169, - 22, - 58, - 0, - 133, - 80, - 212, - 170, - 149, - 32, - 74, - 122, - 173, - 0, - 53, - 35, - 169, - 213, - 40, - 81, - 79, - 20, - 196, - 52, - 168, - 166, - 237, - 167, - 181, - 54, - 128, - 19, - 20, - 134, - 157, - 72, - 104, - 0, - 20, - 240, - 41, - 131, - 173, - 72, - 40, - 0, - 199, - 20, - 211, - 79, - 166, - 181, - 0, - 54, - 138, - 40, - 160, - 4, - 164, - 165, - 162, - 128, - 18, - 138, - 40, - 160, - 4, - 52, - 162, - 131, - 64, - 160, - 7, - 83, - 105, - 105, - 13, - 0, - 45, - 37, - 3, - 165, - 20, - 0, - 225, - 69, - 2, - 138, - 0, - 67, - 74, - 41, - 41, - 104, - 1, - 13, - 37, - 41, - 160, - 80, - 1, - 138, - 41, - 105, - 13, - 0, - 32, - 20, - 199, - 64, - 69, - 74, - 41, - 13, - 1, - 114, - 140, - 144, - 227, - 145, - 76, - 198, - 42, - 241, - 80, - 106, - 39, - 136, - 82, - 177, - 170, - 151, - 114, - 1, - 33, - 20, - 225, - 45, - 35, - 68, - 69, - 70, - 80, - 142, - 162, - 150, - 165, - 89, - 49, - 37, - 195, - 84, - 59, - 42, - 112, - 167, - 210, - 151, - 103, - 181, - 23, - 11, - 34, - 21, - 24, - 167, - 243, - 235, - 65, - 227, - 173, - 52, - 184, - 164, - 14, - 195, - 179, - 64, - 106, - 104, - 96, - 105, - 88, - 99, - 189, - 2, - 208, - 120, - 122, - 112, - 122, - 175, - 186, - 156, - 14, - 105, - 153, - 202, - 37, - 144, - 244, - 22, - 168, - 51, - 138, - 55, - 83, - 51, - 37, - 205, - 45, - 70, - 26, - 141, - 212, - 8, - 150, - 138, - 96, - 106, - 112, - 160, - 7, - 1, - 75, - 73, - 70, - 104, - 1, - 13, - 54, - 156, - 105, - 180, - 202, - 66, - 81, - 138, - 49, - 75, - 64, - 195, - 20, - 210, - 153, - 167, - 210, - 208, - 4, - 70, - 58, - 141, - 163, - 171, - 52, - 220, - 102, - 128, - 42, - 20, - 52, - 131, - 42, - 65, - 29, - 69, - 92, - 216, - 41, - 141, - 22, - 105, - 88, - 9, - 32, - 187, - 32, - 243, - 86, - 126, - 212, - 58, - 26, - 205, - 104, - 200, - 166, - 229, - 128, - 198, - 120, - 160, - 86, - 46, - 205, - 34, - 158, - 65, - 170, - 140, - 115, - 76, - 220, - 125, - 104, - 160, - 74, - 33, - 140, - 154, - 127, - 146, - 253, - 70, - 41, - 189, - 8, - 62, - 245, - 171, - 2, - 171, - 160, - 97, - 206, - 104, - 40, - 205, - 216, - 203, - 247, - 133, - 72, - 166, - 181, - 26, - 221, - 72, - 224, - 85, - 9, - 173, - 138, - 28, - 175, - 79, - 74, - 0, - 23, - 145, - 154, - 112, - 53, - 10, - 57, - 80, - 84, - 211, - 139, - 226, - 129, - 129, - 92, - 209, - 229, - 26, - 156, - 71, - 78, - 242, - 232, - 2, - 5, - 142, - 164, - 84, - 197, - 72, - 22, - 157, - 138, - 0, - 98, - 173, - 72, - 22, - 146, - 156, - 40, - 1, - 49, - 69, - 41, - 164, - 160, - 7, - 169, - 167, - 84, - 64, - 211, - 193, - 166, - 0, - 105, - 40, - 52, - 148, - 0, - 180, - 180, - 218, - 81, - 64, - 130, - 164, - 6, - 153, - 74, - 13, - 0, - 62, - 154, - 105, - 115, - 77, - 52, - 0, - 218, - 90, - 67, - 69, - 0, - 20, - 81, - 69, - 0, - 37, - 20, - 82, - 80, - 2, - 209, - 69, - 37, - 0, - 58, - 144, - 208, - 40, - 52, - 0, - 10, - 40, - 20, - 26, - 0, - 81, - 75, - 72, - 40, - 160, - 5, - 162, - 129, - 65, - 160, - 6, - 154, - 81, - 77, - 61, - 105, - 227, - 165, - 0, - 20, - 148, - 19, - 64, - 160, - 5, - 20, - 134, - 150, - 146, - 128, - 12, - 82, - 26, - 119, - 106, - 109, - 0, - 52, - 168, - 166, - 20, - 6, - 165, - 61, - 41, - 180, - 135, - 113, - 130, - 58, - 82, - 131, - 20, - 252, - 80, - 104, - 11, - 149, - 37, - 135, - 34, - 168, - 200, - 174, - 135, - 145, - 197, - 108, - 227, - 34, - 161, - 146, - 16, - 195, - 165, - 1, - 115, - 36, - 57, - 20, - 227, - 38, - 106, - 121, - 109, - 121, - 202, - 241, - 80, - 52, - 46, - 59, - 102, - 128, - 184, - 221, - 212, - 161, - 241, - 64, - 70, - 238, - 40, - 43, - 237, - 69, - 135, - 113, - 222, - 97, - 52, - 133, - 207, - 189, - 52, - 10, - 93, - 132, - 208, - 72, - 162, - 74, - 145, - 100, - 205, - 66, - 80, - 138, - 104, - 36, - 80, - 43, - 22, - 212, - 212, - 202, - 106, - 172, - 109, - 154, - 152, - 26, - 9, - 177, - 54, - 104, - 205, - 70, - 26, - 141, - 217, - 160, - 7, - 117, - 165, - 2, - 144, - 26, - 118, - 104, - 0, - 197, - 38, - 41, - 212, - 98, - 152, - 13, - 162, - 148, - 241, - 77, - 205, - 5, - 11, - 75, - 138, - 65, - 75, - 64, - 197, - 162, - 138, - 74, - 0, - 66, - 51, - 76, - 104, - 243, - 82, - 82, - 208, - 5, - 70, - 143, - 20, - 208, - 42, - 225, - 80, - 106, - 54, - 142, - 144, - 200, - 113, - 197, - 75, - 107, - 112, - 97, - 125, - 164, - 252, - 167, - 165, - 49, - 144, - 138, - 137, - 135, - 173, - 0, - 205, - 184, - 238, - 20, - 212, - 140, - 21, - 197, - 97, - 44, - 174, - 184, - 193, - 233, - 86, - 224, - 188, - 199, - 90, - 46, - 78, - 168, - 154, - 123, - 117, - 228, - 138, - 162, - 224, - 171, - 98, - 174, - 181, - 192, - 110, - 42, - 9, - 227, - 207, - 43, - 215, - 210, - 129, - 43, - 151, - 194, - 226, - 130, - 41, - 212, - 134, - 153, - 99, - 49, - 69, - 41, - 164, - 164, - 1, - 74, - 40, - 165, - 160, - 2, - 154, - 105, - 198, - 154, - 104, - 1, - 41, - 65, - 164, - 162, - 128, - 29, - 154, - 41, - 185, - 165, - 166, - 2, - 209, - 73, - 75, - 64, - 133, - 20, - 82, - 102, - 150, - 128, - 29, - 154, - 66, - 105, - 185, - 165, - 160, - 0, - 210, - 81, - 73, - 64, - 14, - 162, - 146, - 138, - 0, - 13, - 37, - 6, - 146, - 128, - 22, - 138, - 40, - 160, - 5, - 20, - 26, - 65, - 74, - 104, - 1, - 5, - 41, - 164, - 165, - 160, - 0, - 82, - 211, - 105, - 104, - 1, - 69, - 6, - 138, - 67, - 64, - 9, - 222, - 159, - 218, - 152, - 41, - 212, - 0, - 135, - 173, - 40, - 166, - 247, - 167, - 10, - 0, - 83, - 77, - 165, - 52, - 130, - 128, - 20, - 210, - 80, - 105, - 40, - 0, - 52, - 82, - 210, - 80, - 1, - 64, - 162, - 148, - 10, - 0, - 41, - 166, - 148, - 211, - 77, - 0, - 49, - 134, - 106, - 50, - 128, - 212, - 134, - 144, - 210, - 2, - 22, - 140, - 84, - 47, - 29, - 88, - 106, - 105, - 25, - 160, - 105, - 148, - 202, - 226, - 156, - 132, - 10, - 149, - 210, - 162, - 43, - 138, - 70, - 154, - 50, - 76, - 6, - 21, - 4, - 177, - 227, - 145, - 79, - 12, - 69, - 12, - 217, - 167, - 114, - 92, - 72, - 17, - 182, - 181, - 90, - 67, - 145, - 85, - 138, - 243, - 82, - 33, - 34, - 130, - 92, - 73, - 169, - 69, - 71, - 184, - 210, - 111, - 164, - 46, - 86, - 78, - 41, - 115, - 81, - 7, - 167, - 131, - 154, - 100, - 181, - 98, - 64, - 105, - 217, - 168, - 179, - 138, - 80, - 212, - 18, - 60, - 210, - 98, - 141, - 212, - 103, - 52, - 20, - 152, - 162, - 150, - 144, - 80, - 77, - 49, - 129, - 162, - 146, - 148, - 80, - 49, - 104, - 162, - 138, - 0, - 41, - 40, - 205, - 20, - 0, - 48, - 205, - 68, - 209, - 230, - 165, - 162, - 128, - 42, - 50, - 17, - 77, - 239, - 87, - 25, - 65, - 168, - 26, - 63, - 74, - 67, - 22, - 35, - 205, - 94, - 136, - 2, - 167, - 214, - 179, - 134, - 84, - 212, - 209, - 205, - 182, - 128, - 52, - 168, - 162, - 138, - 96, - 33, - 164, - 165, - 52, - 148, - 0, - 82, - 138, - 74, - 81, - 64, - 5, - 52, - 211, - 169, - 13, - 0, - 51, - 52, - 180, - 134, - 147, - 52, - 128, - 90, - 40, - 162, - 128, - 22, - 150, - 144, - 82, - 211, - 16, - 82, - 211, - 105, - 104, - 0, - 52, - 102, - 138, - 74, - 0, - 90, - 41, - 40, - 160, - 5, - 20, - 180, - 218, - 117, - 0, - 6, - 155, - 75, - 73, - 64, - 5, - 45, - 37, - 20, - 0, - 180, - 166, - 155, - 74, - 40, - 1, - 41, - 212, - 134, - 129, - 64, - 5, - 45, - 37, - 45, - 0, - 20, - 134, - 150, - 131, - 64, - 8, - 41, - 104, - 20, - 26, - 0, - 65, - 214, - 157, - 72, - 41, - 77, - 0, - 38, - 104, - 164, - 165, - 52, - 0, - 148, - 148, - 80, - 41, - 0, - 180, - 148, - 166, - 155, - 64, - 14, - 20, - 164, - 224, - 82, - 10, - 70, - 60, - 208, - 0, - 77, - 48, - 210, - 230, - 154, - 104, - 0, - 205, - 53, - 141, - 6, - 152, - 78, - 77, - 2, - 18, - 138, - 92, - 81, - 76, - 119, - 26, - 121, - 166, - 148, - 205, - 72, - 5, - 46, - 41, - 14, - 246, - 42, - 180, - 120, - 166, - 109, - 53, - 105, - 133, - 33, - 81, - 69, - 138, - 230, - 43, - 109, - 52, - 157, - 42, - 206, - 193, - 81, - 201, - 22, - 69, - 43, - 7, - 49, - 17, - 97, - 73, - 156, - 211, - 29, - 89, - 79, - 52, - 208, - 196, - 81, - 97, - 92, - 144, - 154, - 150, - 39, - 207, - 94, - 181, - 88, - 181, - 10, - 196, - 28, - 138, - 44, - 15, - 82, - 254, - 51, - 205, - 55, - 165, - 64, - 39, - 32, - 82, - 25, - 205, - 51, - 59, - 22, - 5, - 58, - 170, - 172, - 245, - 58, - 48, - 122, - 5, - 97, - 251, - 169, - 65, - 166, - 26, - 1, - 197, - 5, - 34, - 81, - 75, - 81, - 238, - 163, - 125, - 49, - 146, - 82, - 19, - 76, - 221, - 154, - 112, - 160, - 2, - 150, - 147, - 52, - 153, - 205, - 0, - 59, - 52, - 82, - 1, - 78, - 197, - 0, - 38, - 41, - 112, - 41, - 105, - 40, - 2, - 55, - 140, - 30, - 149, - 11, - 41, - 90, - 181, - 138, - 99, - 224, - 210, - 25, - 127, - 52, - 102, - 152, - 13, - 25, - 166, - 33, - 212, - 83, - 115, - 70, - 104, - 24, - 234, - 41, - 51, - 75, - 154, - 0, - 90, - 67, - 70, - 105, - 51, - 64, - 8, - 105, - 180, - 166, - 146, - 144, - 5, - 45, - 54, - 148, - 80, - 2, - 210, - 210, - 10, - 90, - 0, - 40, - 162, - 150, - 152, - 9, - 69, - 20, - 80, - 33, - 41, - 105, - 41, - 69, - 3, - 10, - 81, - 73, - 69, - 2, - 22, - 138, - 5, - 20, - 0, - 148, - 80, - 104, - 160, - 5, - 165, - 20, - 130, - 148, - 117, - 160, - 4, - 52, - 14, - 148, - 166, - 129, - 64, - 9, - 75, - 65, - 162, - 128, - 10, - 67, - 210, - 150, - 144, - 208, - 2, - 138, - 70, - 165, - 20, - 134, - 128, - 20, - 80, - 104, - 20, - 134, - 128, - 20, - 83, - 77, - 40, - 164, - 61, - 104, - 0, - 165, - 20, - 218, - 90, - 64, - 6, - 144, - 10, - 94, - 244, - 80, - 2, - 246, - 166, - 26, - 113, - 52, - 194, - 104, - 0, - 166, - 147, - 65, - 52, - 210, - 104, - 1, - 24, - 211, - 69, - 7, - 154, - 112, - 20, - 0, - 82, - 80, - 77, - 40, - 20, - 8, - 81, - 77, - 38, - 148, - 154, - 105, - 160, - 98, - 19, - 69, - 20, - 184, - 166, - 48, - 20, - 238, - 212, - 152, - 160, - 208, - 34, - 55, - 140, - 53, - 87, - 120, - 57, - 226, - 173, - 209, - 138, - 0, - 207, - 48, - 176, - 247, - 166, - 148, - 35, - 168, - 173, - 45, - 163, - 210, - 152, - 241, - 2, - 40, - 25, - 68, - 10, - 112, - 140, - 183, - 74, - 145, - 227, - 218, - 104, - 70, - 218, - 121, - 165, - 113, - 242, - 144, - 188, - 108, - 189, - 105, - 98, - 147, - 99, - 123, - 85, - 167, - 42, - 233, - 84, - 221, - 112, - 77, - 2, - 177, - 125, - 126, - 97, - 72, - 86, - 162, - 182, - 147, - 229, - 193, - 169, - 201, - 20, - 10, - 196, - 102, - 129, - 79, - 192, - 166, - 154, - 6, - 38, - 113, - 73, - 184, - 210, - 227, - 52, - 108, - 197, - 0, - 56, - 26, - 112, - 168, - 233, - 115, - 64, - 18, - 131, - 75, - 81, - 110, - 167, - 6, - 166, - 33, - 249, - 164, - 205, - 55, - 52, - 229, - 92, - 154, - 6, - 39, - 38, - 148, - 33, - 53, - 42, - 160, - 21, - 32, - 90, - 4, - 68, - 31, - 222, - 157, - 190, - 170, - 134, - 165, - 15, - 64, - 22, - 119, - 82, - 238, - 170, - 251, - 233, - 119, - 208, - 4, - 251, - 169, - 67, - 84, - 27, - 233, - 67, - 251, - 208, - 50, - 124, - 209, - 154, - 132, - 61, - 59, - 117, - 0, - 63, - 52, - 83, - 55, - 81, - 186, - 128, - 29, - 75, - 76, - 13, - 75, - 154, - 64, - 58, - 151, - 52, - 204, - 210, - 230, - 128, - 29, - 154, - 90, - 102, - 105, - 65, - 160, - 7, - 81, - 73, - 154, - 51, - 76, - 5, - 164, - 165, - 164, - 52, - 8, - 90, - 81, - 72, - 41, - 104, - 0, - 165, - 164, - 162, - 128, - 3, - 72, - 41, - 105, - 40, - 24, - 180, - 119, - 162, - 138, - 4, - 58, - 147, - 189, - 3, - 165, - 33, - 160, - 5, - 52, - 148, - 238, - 212, - 134, - 128, - 10, - 67, - 75, - 218, - 147, - 189, - 0, - 40, - 233, - 72, - 122, - 211, - 135, - 74, - 111, - 122, - 0, - 112, - 166, - 181, - 58, - 152, - 122, - 208, - 1, - 69, - 6, - 138, - 64, - 20, - 81, - 69, - 0, - 20, - 82, - 226, - 154, - 78, - 40, - 1, - 24, - 211, - 77, - 41, - 52, - 210, - 104, - 1, - 9, - 166, - 19, - 74, - 77, - 37, - 0, - 20, - 19, - 69, - 24, - 160, - 1, - 69, - 41, - 52, - 180, - 210, - 104, - 0, - 205, - 37, - 2, - 150, - 128, - 0, - 41, - 104, - 20, - 180, - 8, - 67, - 73, - 75, - 138, - 40, - 24, - 152, - 165, - 197, - 20, - 83, - 0, - 165, - 164, - 160, - 154, - 0, - 99, - 160, - 53, - 93, - 163, - 32, - 241, - 86, - 186, - 208, - 84, - 82, - 101, - 41, - 88, - 170, - 20, - 210, - 249, - 89, - 169, - 138, - 138, - 80, - 49, - 83, - 99, - 69, - 36, - 68, - 176, - 227, - 165, - 56, - 198, - 64, - 167, - 25, - 54, - 212, - 77, - 113, - 158, - 49, - 70, - 163, - 109, - 13, - 36, - 138, - 64, - 248, - 60, - 211, - 131, - 3, - 214, - 163, - 124, - 3, - 193, - 166, - 77, - 211, - 44, - 166, - 8, - 167, - 98, - 171, - 195, - 38, - 14, - 13, - 88, - 200, - 245, - 20, - 204, - 216, - 155, - 105, - 8, - 197, - 56, - 178, - 250, - 138, - 122, - 174, - 104, - 2, - 29, - 140, - 123, - 82, - 133, - 34, - 172, - 236, - 20, - 108, - 20, - 1, - 92, - 3, - 82, - 47, - 20, - 242, - 148, - 155, - 40, - 1, - 85, - 170, - 64, - 213, - 14, - 49, - 74, - 51, - 76, - 69, - 32, - 212, - 224, - 106, - 46, - 65, - 165, - 230, - 128, - 37, - 205, - 4, - 212, - 91, - 141, - 46, - 250, - 0, - 126, - 227, - 75, - 186, - 153, - 154, - 76, - 208, - 4, - 161, - 233, - 68, - 149, - 14, - 105, - 51, - 64, - 203, - 30, - 101, - 46, - 250, - 173, - 186, - 141, - 212, - 1, - 104, - 61, - 59, - 125, - 84, - 223, - 74, - 36, - 164, - 5, - 176, - 244, - 187, - 170, - 168, - 146, - 156, - 36, - 160, - 11, - 1, - 169, - 115, - 85, - 252, - 202, - 80, - 244, - 1, - 100, - 53, - 46, - 106, - 184, - 122, - 120, - 122, - 0, - 155, - 52, - 185, - 168, - 67, - 211, - 131, - 83, - 16, - 252, - 211, - 129, - 168, - 243, - 64, - 106, - 6, - 73, - 154, - 51, - 76, - 13, - 75, - 154, - 4, - 62, - 146, - 147, - 52, - 102, - 128, - 22, - 129, - 73, - 154, - 1, - 160, - 99, - 168, - 164, - 205, - 58, - 129, - 0, - 164, - 61, - 105, - 65, - 164, - 99, - 205, - 0, - 56, - 83, - 123, - 211, - 135, - 74, - 105, - 235, - 64, - 14, - 166, - 142, - 180, - 189, - 168, - 29, - 104, - 1, - 79, - 74, - 104, - 20, - 227, - 210, - 146, - 128, - 16, - 210, - 80, - 122, - 208, - 41, - 12, - 40, - 29, - 104, - 52, - 10, - 0, - 92, - 211, - 24, - 211, - 141, - 70, - 79, - 52, - 0, - 134, - 154, - 77, - 41, - 52, - 195, - 64, - 131, - 189, - 7, - 165, - 2, - 142, - 180, - 0, - 10, - 119, - 74, - 49, - 72, - 77, - 0, - 33, - 52, - 222, - 166, - 148, - 210, - 168, - 160, - 2, - 150, - 138, - 90, - 0, - 40, - 163, - 52, - 153, - 160, - 66, - 210, - 81, - 69, - 0, - 45, - 38, - 104, - 164, - 235, - 64, - 192, - 154, - 0, - 245, - 165, - 2, - 130, - 113, - 76, - 5, - 233, - 77, - 38, - 147, - 57, - 162, - 144, - 1, - 164, - 205, - 20, - 1, - 64, - 198, - 178, - 110, - 170, - 237, - 17, - 86, - 207, - 106, - 186, - 5, - 46, - 192, - 221, - 104, - 2, - 159, - 24, - 168, - 159, - 173, - 95, - 54, - 234, - 121, - 168, - 154, - 219, - 39, - 138, - 161, - 20, - 128, - 57, - 205, - 56, - 150, - 245, - 53, - 57, - 183, - 101, - 167, - 165, - 179, - 55, - 53, - 37, - 40, - 54, - 83, - 220, - 222, - 181, - 61, - 181, - 201, - 86, - 10, - 221, - 42, - 211, - 89, - 169, - 82, - 49, - 205, - 103, - 75, - 25, - 141, - 202, - 159, - 194, - 128, - 105, - 163, - 104, - 124, - 192, - 17, - 78, - 11, - 138, - 169, - 97, - 56, - 120, - 182, - 158, - 163, - 138, - 180, - 77, - 2, - 3, - 138, - 76, - 81, - 69, - 48, - 19, - 104, - 164, - 34, - 157, - 73, - 72, - 12, - 236, - 211, - 131, - 0, - 42, - 51, - 72, - 104, - 1, - 204, - 71, - 106, - 101, - 20, - 148, - 192, - 51, - 70, - 234, - 67, - 69, - 0, - 46, - 234, - 55, - 83, - 77, - 33, - 160, - 7, - 238, - 163, - 53, - 29, - 38, - 105, - 1, - 38, - 104, - 205, - 71, - 154, - 93, - 212, - 1, - 38, - 104, - 221, - 81, - 238, - 165, - 205, - 0, - 73, - 190, - 151, - 125, - 69, - 154, - 51, - 64, - 19, - 9, - 41, - 194, - 74, - 175, - 154, - 80, - 104, - 2, - 208, - 146, - 156, - 36, - 170, - 129, - 169, - 193, - 205, - 0, - 92, - 18, - 82, - 239, - 170, - 98, - 74, - 112, - 146, - 128, - 45, - 135, - 167, - 7, - 170, - 98, - 74, - 120, - 150, - 128, - 45, - 134, - 163, - 117, - 86, - 18, - 83, - 132, - 148, - 8, - 177, - 186, - 151, - 53, - 95, - 127, - 189, - 40, - 122, - 6, - 88, - 205, - 56, - 30, - 42, - 184, - 122, - 112, - 122, - 98, - 38, - 205, - 33, - 166, - 110, - 160, - 181, - 32, - 37, - 7, - 138, - 66, - 121, - 166, - 134, - 226, - 147, - 119, - 52, - 192, - 147, - 60, - 80, - 180, - 132, - 241, - 66, - 244, - 160, - 7, - 26, - 15, - 74, - 76, - 243, - 72, - 199, - 138, - 0, - 67, - 75, - 208, - 82, - 82, - 147, - 72, - 97, - 214, - 131, - 66, - 243, - 72, - 79, - 52, - 0, - 140, - 105, - 148, - 164, - 210, - 30, - 148, - 0, - 195, - 73, - 74, - 104, - 160, - 65, - 64, - 20, - 80, - 120, - 20, - 0, - 140, - 123, - 82, - 81, - 69, - 0, - 40, - 162, - 138, - 81, - 64, - 11, - 70, - 105, - 51, - 69, - 0, - 20, - 82, - 81, - 154, - 0, - 92, - 210, - 81, - 74, - 40, - 0, - 162, - 130, - 105, - 40, - 0, - 205, - 37, - 24, - 165, - 197, - 0, - 37, - 20, - 224, - 185, - 167, - 170, - 122, - 208, - 49, - 129, - 105, - 225, - 105, - 248, - 20, - 102, - 128, - 16, - 10, - 56, - 163, - 52, - 98, - 128, - 14, - 180, - 160, - 98, - 140, - 82, - 226, - 128, - 16, - 174, - 69, - 75, - 22, - 7, - 20, - 202, - 51, - 233, - 65, - 81, - 149, - 139, - 91, - 21, - 133, - 85, - 158, - 193, - 101, - 52, - 244, - 144, - 173, - 72, - 38, - 205, - 35, - 68, - 251, - 20, - 225, - 176, - 48, - 190, - 65, - 169, - 153, - 8, - 21, - 41, - 157, - 7, - 83, - 81, - 189, - 196, - 126, - 180, - 21, - 107, - 238, - 136, - 139, - 17, - 66, - 182, - 69, - 13, - 34, - 176, - 227, - 165, - 68, - 14, - 27, - 61, - 168, - 184, - 156, - 19, - 216, - 155, - 147, - 64, - 197, - 38, - 105, - 165, - 169, - 152, - 20, - 240, - 49, - 76, - 35, - 52, - 19, - 64, - 52, - 0, - 155, - 105, - 10, - 210, - 150, - 163, - 52, - 0, - 194, - 40, - 197, - 41, - 164, - 160, - 4, - 197, - 33, - 20, - 236, - 210, - 26, - 0, - 110, - 40, - 197, - 20, - 185, - 160, - 6, - 17, - 73, - 74, - 105, - 40, - 0, - 162, - 151, - 20, - 80, - 2, - 102, - 140, - 209, - 73, - 64, - 11, - 154, - 92, - 211, - 104, - 160, - 7, - 102, - 151, - 52, - 202, - 51, - 64, - 18, - 102, - 140, - 211, - 51, - 70, - 104, - 17, - 38, - 234, - 3, - 83, - 51, - 70, - 104, - 25, - 32, - 122, - 112, - 146, - 161, - 205, - 25, - 160, - 9, - 196, - 180, - 225, - 45, - 86, - 205, - 46, - 104, - 17, - 104, - 75, - 79, - 18, - 85, - 45, - 212, - 224, - 244, - 1, - 120, - 73, - 75, - 191, - 53, - 68, - 72, - 105, - 226, - 90, - 0, - 188, - 175, - 75, - 191, - 154, - 166, - 37, - 167, - 9, - 40, - 2, - 222, - 250, - 120, - 108, - 10, - 168, - 36, - 230, - 159, - 230, - 10, - 0, - 177, - 186, - 130, - 213, - 8, - 146, - 147, - 126, - 104, - 2, - 112, - 105, - 73, - 168, - 85, - 169, - 219, - 168, - 25, - 42, - 156, - 10, - 97, - 106, - 105, - 110, - 41, - 3, - 80, - 3, - 179, - 77, - 38, - 130, - 105, - 185, - 160, - 5, - 160, - 243, - 72, - 79, - 20, - 10, - 4, - 56, - 83, - 73, - 205, - 12, - 123, - 83, - 73, - 197, - 0, - 25, - 165, - 166, - 129, - 78, - 160, - 2, - 151, - 52, - 148, - 80, - 2, - 209, - 154, - 76, - 210, - 103, - 52, - 0, - 185, - 160, - 10, - 5, - 25, - 160, - 5, - 163, - 52, - 128, - 19, - 205, - 56, - 10, - 0, - 74, - 80, - 13, - 56, - 10, - 81, - 64, - 8, - 22, - 156, - 22, - 138, - 92, - 208, - 2, - 241, - 70, - 64, - 164, - 205, - 39, - 214, - 129, - 139, - 146, - 104, - 197, - 25, - 163, - 4, - 208, - 1, - 74, - 5, - 20, - 100, - 10, - 0, - 117, - 55, - 52, - 18, - 77, - 37, - 0, - 47, - 214, - 151, - 52, - 153, - 164, - 205, - 0, - 41, - 57, - 163, - 52, - 153, - 166, - 231, - 52, - 0, - 147, - 13, - 195, - 138, - 130, - 220, - 1, - 57, - 73, - 122, - 30, - 149, - 99, - 32, - 84, - 82, - 168, - 111, - 241, - 161, - 104, - 59, - 182, - 93, - 146, - 202, - 54, - 79, - 221, - 146, - 167, - 235, - 84, - 138, - 188, - 124, - 54, - 13, - 42, - 207, - 112, - 139, - 140, - 238, - 30, - 245, - 28, - 146, - 187, - 117, - 171, - 178, - 96, - 164, - 208, - 166, - 82, - 56, - 197, - 48, - 220, - 98, - 153, - 147, - 233, - 77, - 49, - 150, - 228, - 82, - 208, - 45, - 39, - 168, - 210, - 105, - 51, - 75, - 73, - 80, - 32, - 205, - 37, - 20, - 83, - 0, - 162, - 150, - 146, - 128, - 12, - 82, - 17, - 78, - 164, - 52, - 0, - 218, - 67, - 78, - 160, - 142, - 40, - 2, - 58, - 5, - 46, - 40, - 20, - 0, - 80, - 105, - 113, - 73, - 64, - 9, - 69, - 46, - 40, - 197, - 0, - 54, - 146, - 156, - 69, - 37, - 0, - 38, - 40, - 197, - 45, - 20, - 0, - 148, - 82, - 226, - 140, - 80, - 3, - 105, - 104, - 162, - 128, - 12, - 209, - 154, - 40, - 160, - 3, - 52, - 185, - 166, - 209, - 64, - 14, - 205, - 25, - 166, - 210, - 208, - 2, - 230, - 148, - 26, - 110, - 104, - 205, - 0, - 72, - 13, - 40, - 106, - 143, - 52, - 185, - 160, - 68, - 161, - 141, - 59, - 204, - 53, - 14, - 104, - 205, - 0, - 79, - 230, - 82, - 137, - 42, - 12, - 209, - 154, - 6, - 90, - 18, - 251, - 211, - 132, - 158, - 245, - 83, - 117, - 46, - 234, - 0, - 183, - 190, - 148, - 61, - 84, - 13, - 75, - 190, - 129, - 22, - 183, - 210, - 131, - 85, - 119, - 211, - 188, - 202, - 6, - 88, - 13, - 147, - 75, - 187, - 21, - 2, - 189, - 59, - 125, - 0, - 73, - 158, - 244, - 148, - 205, - 249, - 167, - 3, - 64, - 15, - 20, - 102, - 155, - 186, - 147, - 52, - 8, - 126, - 104, - 206, - 41, - 185, - 164, - 201, - 38, - 128, - 23, - 57, - 167, - 1, - 72, - 56, - 165, - 28, - 208, - 3, - 168, - 3, - 214, - 147, - 112, - 20, - 110, - 160, - 99, - 233, - 105, - 180, - 185, - 160, - 7, - 10, - 90, - 102, - 113, - 73, - 147, - 64, - 15, - 38, - 138, - 109, - 40, - 160, - 7, - 81, - 140, - 209, - 70, - 104, - 1, - 104, - 205, - 38, - 105, - 40, - 1, - 73, - 205, - 2, - 146, - 130, - 212, - 0, - 185, - 163, - 52, - 220, - 209, - 154, - 0, - 113, - 52, - 220, - 210, - 82, - 80, - 3, - 179, - 73, - 187, - 210, - 147, - 25, - 165, - 2, - 128, - 27, - 131, - 78, - 197, - 46, - 40, - 160, - 4, - 197, - 5, - 70, - 58, - 82, - 224, - 154, - 92, - 80, - 2, - 219, - 198, - 164, - 242, - 42, - 219, - 90, - 161, - 31, - 47, - 6, - 170, - 3, - 138, - 179, - 20, - 248, - 24, - 106, - 70, - 188, - 215, - 90, - 24, - 152, - 163, - 20, - 180, - 26, - 102, - 66, - 98, - 147, - 20, - 185, - 164, - 205, - 0, - 24, - 162, - 140, - 209, - 64, - 9, - 69, - 45, - 20, - 0, - 148, - 134, - 150, - 138, - 0, - 105, - 20, - 218, - 147, - 20, - 210, - 40, - 0, - 83, - 65, - 2, - 155, - 74, - 40, - 0, - 197, - 4, - 98, - 156, - 40, - 52, - 0, - 218, - 76, - 83, - 177, - 70, - 40, - 1, - 184, - 164, - 197, - 59, - 20, - 184, - 160, - 6, - 80, - 105, - 77, - 20, - 0, - 218, - 41, - 113, - 69, - 0, - 37, - 37, - 45, - 37, - 0, - 20, - 82, - 226, - 140, - 80, - 2, - 81, - 75, - 69, - 0, - 54, - 138, - 90, - 40, - 1, - 41, - 105, - 113, - 73, - 64, - 6, - 104, - 205, - 20, - 98, - 128, - 12, - 210, - 230, - 146, - 146, - 128, - 31, - 154, - 51, - 76, - 165, - 160, - 7, - 230, - 140, - 211, - 51, - 70, - 104, - 1, - 249, - 165, - 13, - 81, - 230, - 151, - 52, - 1, - 46, - 234, - 55, - 212, - 89, - 163, - 52, - 1, - 48, - 122, - 112, - 144, - 212, - 25, - 165, - 205, - 2, - 44, - 9, - 41, - 67, - 138, - 173, - 186, - 148, - 53, - 0, - 90, - 15, - 154, - 118, - 225, - 85, - 55, - 210, - 239, - 52, - 1, - 103, - 117, - 27, - 170, - 0, - 244, - 224, - 244, - 12, - 155, - 117, - 40, - 53, - 14, - 250, - 55, - 208, - 5, - 141, - 254, - 244, - 190, - 103, - 165, - 86, - 221, - 78, - 221, - 64, - 19, - 230, - 157, - 154, - 128, - 61, - 56, - 61, - 0, - 76, - 41, - 217, - 168, - 60, - 202, - 93, - 244, - 1, - 46, - 105, - 115, - 81, - 110, - 165, - 6, - 128, - 31, - 156, - 209, - 154, - 110, - 105, - 104, - 1, - 104, - 164, - 205, - 25, - 160, - 5, - 205, - 37, - 37, - 40, - 20, - 0, - 180, - 119, - 162, - 140, - 226, - 128, - 23, - 20, - 82, - 82, - 208, - 1, - 74, - 5, - 37, - 45, - 0, - 45, - 20, - 82, - 226, - 128, - 18, - 148, - 113, - 69, - 37, - 0, - 102, - 102, - 140, - 210, - 81, - 64, - 5, - 20, - 81, - 64, - 9, - 69, - 20, - 80, - 1, - 154, - 51, - 69, - 20, - 0, - 81, - 69, - 20, - 0, - 185, - 164, - 52, - 81, - 138, - 0, - 109, - 40, - 163, - 20, - 80, - 2, - 138, - 90, - 74, - 40, - 0, - 162, - 150, - 146, - 128, - 18, - 138, - 13, - 37, - 0, - 20, - 148, - 81, - 64, - 1, - 164, - 165, - 164, - 160, - 4, - 165, - 3, - 52, - 83, - 150, - 128, - 19, - 20, - 148, - 243, - 77, - 197, - 0, - 20, - 152, - 167, - 98, - 140, - 80, - 3, - 49, - 69, - 56, - 138, - 109, - 0, - 20, - 98, - 138, - 90, - 0, - 76, - 81, - 75, - 138, - 40, - 1, - 40, - 197, - 45, - 20, - 0, - 218, - 49, - 78, - 197, - 37, - 0, - 38, - 40, - 197, - 45, - 24, - 160, - 4, - 162, - 151, - 20, - 98, - 128, - 27, - 75, - 75, - 138, - 76, - 80, - 1, - 70, - 104, - 162, - 128, - 12, - 210, - 230, - 155, - 69, - 0, - 59, - 52, - 185, - 166, - 82, - 208, - 3, - 247, - 82, - 238, - 168, - 232, - 205, - 0, - 73, - 154, - 112, - 53, - 14, - 105, - 119, - 80, - 4, - 185, - 167, - 3, - 80, - 238, - 165, - 221, - 64, - 18, - 238, - 167, - 110, - 168, - 119, - 81, - 190, - 129, - 19, - 239, - 165, - 15, - 85, - 247, - 81, - 186, - 129, - 150, - 131, - 138, - 112, - 122, - 167, - 188, - 210, - 135, - 52, - 1, - 112, - 61, - 47, - 152, - 42, - 160, - 115, - 78, - 18, - 80, - 5, - 173, - 212, - 160, - 213, - 97, - 37, - 60, - 73, - 239, - 64, - 22, - 5, - 46, - 106, - 0, - 227, - 214, - 148, - 73, - 233, - 64, - 19, - 102, - 138, - 136, - 62, - 105, - 226, - 128, - 31, - 69, - 38, - 69, - 46, - 234, - 96, - 59, - 20, - 188, - 83, - 55, - 81, - 147, - 64, - 15, - 205, - 38, - 105, - 180, - 102, - 128, - 29, - 146, - 122, - 10, - 79, - 169, - 164, - 205, - 46, - 40, - 3, - 54, - 138, - 90, - 74, - 64, - 20, - 81, - 69, - 0, - 20, - 81, - 74, - 5, - 0, - 38, - 41, - 113, - 78, - 2, - 151, - 20, - 0, - 221, - 185, - 160, - 47, - 173, - 60, - 10, - 13, - 0, - 51, - 20, - 109, - 167, - 98, - 151, - 20, - 1, - 25, - 90, - 77, - 166, - 164, - 163, - 20, - 1, - 17, - 20, - 84, - 165, - 105, - 187, - 115, - 64, - 12, - 162, - 159, - 178, - 154, - 84, - 138, - 0, - 109, - 24, - 162, - 150, - 128, - 19, - 20, - 152, - 167, - 138, - 49, - 64, - 12, - 197, - 38, - 42, - 77, - 180, - 190, - 94, - 122, - 26, - 0, - 139, - 20, - 229, - 20, - 237, - 148, - 109, - 34, - 128, - 19, - 20, - 98, - 164, - 85, - 207, - 74, - 93, - 180, - 1, - 22, - 40, - 197, - 76, - 83, - 142, - 105, - 152, - 197, - 2, - 35, - 52, - 211, - 82, - 17, - 154, - 110, - 218, - 6, - 51, - 20, - 83, - 241, - 73, - 138, - 0, - 5, - 33, - 20, - 184, - 165, - 20, - 128, - 76, - 80, - 69, - 56, - 12, - 210, - 149, - 226, - 152, - 12, - 2, - 140, - 84, - 138, - 51, - 74, - 83, - 61, - 40, - 2, - 44, - 82, - 133, - 6, - 164, - 85, - 193, - 228, - 83, - 138, - 103, - 154, - 4, - 67, - 182, - 147, - 21, - 57, - 92, - 10, - 105, - 90, - 0, - 139, - 109, - 33, - 21, - 54, - 195, - 138, - 97, - 90, - 6, - 69, - 138, - 92, - 83, - 246, - 211, - 130, - 113, - 64, - 16, - 226, - 147, - 21, - 49, - 90, - 54, - 80, - 34, - 26, - 42, - 66, - 148, - 220, - 80, - 49, - 184, - 163, - 20, - 236, - 81, - 138, - 0, - 110, - 40, - 197, - 63, - 20, - 160, - 80, - 4, - 116, - 84, - 187, - 65, - 163, - 101, - 0, - 69, - 69, - 60, - 165, - 38, - 202, - 0, - 110, - 104, - 205, - 46, - 211, - 73, - 180, - 208, - 1, - 154, - 92, - 210, - 96, - 210, - 80, - 3, - 247, - 82, - 238, - 168, - 232, - 160, - 9, - 119, - 81, - 186, - 162, - 165, - 205, - 0, - 74, - 26, - 156, - 31, - 21, - 6, - 104, - 220, - 104, - 2, - 200, - 152, - 138, - 81, - 63, - 174, - 106, - 182, - 234, - 55, - 80, - 5, - 193, - 61, - 40, - 153, - 125, - 106, - 158, - 234, - 3, - 80, - 5, - 241, - 40, - 167, - 9, - 1, - 239, - 89, - 225, - 169, - 194, - 66, - 58, - 26, - 0, - 208, - 7, - 52, - 241, - 129, - 212, - 214, - 112, - 149, - 255, - 0, - 189, - 78, - 23, - 12, - 58, - 80, - 6, - 134, - 71, - 108, - 81, - 154, - 162, - 46, - 143, - 112, - 105, - 226, - 235, - 212, - 145, - 64, - 16, - 209, - 69, - 20, - 0, - 81, - 75, - 138, - 80, - 40, - 0, - 2, - 151, - 20, - 82, - 226, - 128, - 16, - 82, - 226, - 148, - 10, - 90, - 0, - 65, - 70, - 41, - 113, - 78, - 81, - 154, - 0, - 102, - 40, - 197, - 72, - 20, - 131, - 200, - 167, - 4, - 207, - 74, - 4, - 68, - 22, - 156, - 20, - 131, - 210, - 164, - 9, - 159, - 106, - 112, - 66, - 58, - 242, - 40, - 2, - 45, - 185, - 228, - 82, - 21, - 252, - 42, - 113, - 16, - 7, - 57, - 165, - 49, - 43, - 0, - 121, - 205, - 0, - 86, - 35, - 29, - 105, - 54, - 102, - 173, - 42, - 1, - 195, - 12, - 138, - 99, - 197, - 142, - 87, - 183, - 106, - 0, - 172, - 209, - 122, - 84, - 108, - 164, - 28, - 17, - 86, - 192, - 207, - 4, - 98, - 134, - 140, - 227, - 145, - 145, - 64, - 20, - 241, - 74, - 42, - 82, - 189, - 197, - 38, - 40, - 24, - 139, - 205, - 72, - 19, - 34, - 145, - 87, - 154, - 157, - 70, - 70, - 59, - 208, - 34, - 185, - 86, - 7, - 145, - 82, - 44, - 109, - 212, - 98, - 167, - 80, - 113, - 200, - 167, - 4, - 83, - 200, - 52, - 1, - 92, - 41, - 207, - 60, - 26, - 118, - 56, - 228, - 228, - 84, - 254, - 82, - 158, - 185, - 165, - 88, - 130, - 244, - 230, - 152, - 16, - 36, - 106, - 71, - 77, - 194, - 145, - 237, - 129, - 63, - 40, - 252, - 42, - 206, - 0, - 57, - 65, - 131, - 78, - 228, - 143, - 152, - 99, - 222, - 139, - 1, - 156, - 96, - 113, - 198, - 204, - 123, - 210, - 27, - 121, - 113, - 194, - 230, - 180, - 88, - 28, - 122, - 251, - 83, - 20, - 140, - 245, - 160, - 12, - 243, - 19, - 255, - 0, - 118, - 147, - 103, - 168, - 173, - 22, - 68, - 110, - 163, - 6, - 161, - 104, - 121, - 228, - 100, - 122, - 210, - 2, - 145, - 90, - 54, - 85, - 179, - 26, - 142, - 212, - 194, - 128, - 30, - 40, - 25, - 92, - 3, - 82, - 162, - 83, - 246, - 110, - 232, - 106, - 72, - 227, - 35, - 169, - 252, - 168, - 1, - 133, - 9, - 31, - 119, - 241, - 164, - 242, - 88, - 115, - 144, - 69, - 91, - 10, - 0, - 192, - 52, - 129, - 121, - 226, - 152, - 138, - 202, - 138, - 79, - 244, - 167, - 52, - 64, - 253, - 213, - 199, - 210, - 172, - 50, - 17, - 252, - 31, - 136, - 160, - 131, - 140, - 142, - 148, - 1, - 92, - 167, - 24, - 52, - 198, - 32, - 13, - 180, - 242, - 75, - 103, - 28, - 84, - 123, - 79, - 122, - 6, - 48, - 211, - 74, - 212, - 187, - 9, - 233, - 79, - 72, - 115, - 157, - 199, - 240, - 160, - 8, - 22, - 61, - 222, - 212, - 255, - 0, - 40, - 127, - 123, - 53, - 58, - 109, - 7, - 0, - 83, - 138, - 131, - 212, - 98, - 129, - 21, - 76, - 100, - 159, - 148, - 126, - 116, - 155, - 8, - 225, - 134, - 42, - 210, - 198, - 1, - 228, - 230, - 134, - 69, - 206, - 49, - 145, - 239, - 64, - 21, - 74, - 119, - 164, - 242, - 131, - 115, - 147, - 86, - 152, - 42, - 253, - 209, - 138, - 140, - 224, - 115, - 72, - 8, - 76, - 4, - 143, - 148, - 31, - 198, - 154, - 97, - 112, - 50, - 203, - 129, - 235, - 86, - 87, - 6, - 158, - 67, - 145, - 128, - 163, - 31, - 90, - 96, - 81, - 219, - 218, - 141, - 181, - 113, - 226, - 82, - 159, - 195, - 159, - 106, - 132, - 196, - 223, - 195, - 243, - 123, - 82, - 25, - 14, - 49, - 74, - 58, - 243, - 210, - 165, - 242, - 159, - 25, - 101, - 219, - 245, - 166, - 99, - 214, - 128, - 2, - 3, - 30, - 56, - 160, - 197, - 142, - 167, - 63, - 74, - 49, - 74, - 164, - 175, - 67, - 64, - 12, - 242, - 206, - 122, - 99, - 235, - 65, - 136, - 142, - 184, - 252, - 42, - 98, - 225, - 254, - 247, - 90, - 80, - 85, - 184, - 166, - 34, - 182, - 206, - 105, - 193, - 20, - 241, - 142, - 106, - 103, - 141, - 71, - 1, - 178, - 105, - 86, - 54, - 3, - 56, - 11, - 64, - 202, - 230, - 46, - 51, - 180, - 143, - 173, - 55, - 203, - 207, - 74, - 178, - 120, - 61, - 115, - 77, - 145, - 193, - 198, - 209, - 131, - 64, - 21, - 74, - 81, - 229, - 228, - 84, - 164, - 82, - 162, - 130, - 121, - 206, - 61, - 169, - 1, - 1, - 67, - 73, - 138, - 180, - 209, - 131, - 247, - 120, - 250, - 212, - 102, - 50, - 78, - 0, - 160, - 8, - 113, - 70, - 41, - 228, - 96, - 224, - 209, - 182, - 128, - 25, - 73, - 79, - 218, - 71, - 81, - 138, - 49, - 64, - 12, - 165, - 167, - 109, - 163, - 109, - 0, - 55, - 52, - 102, - 151, - 109, - 38, - 40, - 1, - 115, - 70, - 234, - 76, - 81, - 138, - 0, - 178, - 5, - 40, - 90, - 114, - 173, - 72, - 171, - 147, - 64, - 13, - 88, - 201, - 237, - 79, - 242, - 137, - 28, - 26, - 153, - 23, - 21, - 38, - 206, - 244, - 8, - 167, - 179, - 156, - 26, - 81, - 30, - 42, - 217, - 136, - 17, - 158, - 244, - 221, - 184, - 56, - 52, - 236, - 4, - 34, - 60, - 210, - 133, - 245, - 21, - 46, - 220, - 116, - 20, - 161, - 115, - 72, - 8, - 246, - 17, - 200, - 20, - 1, - 147, - 83, - 40, - 35, - 173, - 43, - 71, - 200, - 34, - 152, - 17, - 109, - 207, - 90, - 112, - 140, - 131, - 198, - 13, - 74, - 34, - 207, - 6, - 147, - 105, - 83, - 235, - 64, - 13, - 49, - 231, - 4, - 112, - 104, - 85, - 3, - 131, - 82, - 133, - 200, - 226, - 129, - 131, - 212, - 114, - 40, - 1, - 133, - 48, - 55, - 45, - 3, - 147, - 192, - 169, - 240, - 7, - 65, - 72, - 16, - 246, - 166, - 3, - 0, - 33, - 112, - 86, - 154, - 209, - 19, - 202, - 99, - 233, - 86, - 62, - 180, - 210, - 187, - 79, - 20, - 1, - 88, - 197, - 187, - 131, - 193, - 160, - 38, - 222, - 181, - 100, - 128, - 227, - 220, - 83, - 72, - 219, - 212, - 100, - 82, - 2, - 163, - 219, - 130, - 73, - 67, - 248, - 84, - 5, - 118, - 182, - 8, - 193, - 173, - 32, - 128, - 125, - 209, - 74, - 209, - 164, - 131, - 230, - 94, - 104, - 3, - 61, - 69, - 72, - 160, - 103, - 154, - 115, - 69, - 181, - 182, - 159, - 192, - 210, - 136, - 246, - 251, - 208, - 49, - 203, - 25, - 60, - 245, - 20, - 255, - 0, - 37, - 122, - 130, - 71, - 181, - 73, - 22, - 7, - 227, - 74, - 192, - 30, - 148, - 8, - 132, - 12, - 28, - 48, - 228, - 83, - 182, - 19, - 247, - 106, - 78, - 15, - 222, - 28, - 208, - 85, - 147, - 145, - 200, - 160, - 8, - 204, - 36, - 243, - 158, - 105, - 216, - 227, - 6, - 159, - 156, - 138, - 137, - 139, - 2, - 104, - 1, - 192, - 1, - 77, - 114, - 131, - 156, - 12, - 212, - 126, - 97, - 106, - 105, - 1, - 186, - 154, - 0, - 25, - 134, - 105, - 133, - 179, - 74, - 87, - 3, - 173, - 38, - 5, - 3, - 27, - 130, - 77, - 52, - 173, - 72, - 160, - 83, - 188, - 160, - 123, - 156, - 80, - 4, - 75, - 193, - 167, - 100, - 131, - 197, - 73, - 246, - 96, - 57, - 70, - 39, - 216, - 209, - 229, - 51, - 28, - 99, - 20, - 0, - 198, - 57, - 226, - 145, - 88, - 169, - 20, - 243, - 4, - 138, - 62, - 108, - 99, - 212, - 82, - 152, - 14, - 220, - 238, - 6, - 128, - 20, - 205, - 198, - 48, - 106, - 51, - 33, - 60, - 98, - 155, - 223, - 25, - 231, - 210, - 148, - 174, - 6, - 72, - 34, - 128, - 27, - 182, - 128, - 189, - 169, - 249, - 226, - 152, - 71, - 52, - 128, - 145, - 32, - 92, - 103, - 113, - 250, - 83, - 182, - 237, - 224, - 45, - 68, - 11, - 118, - 98, - 42, - 69, - 155, - 3, - 4, - 26, - 96, - 60, - 163, - 109, - 237, - 138, - 140, - 143, - 194, - 156, - 36, - 220, - 112, - 122, - 83, - 129, - 80, - 221, - 65, - 160, - 67, - 23, - 7, - 168, - 252, - 105, - 78, - 112, - 70, - 120, - 167, - 121, - 101, - 185, - 86, - 3, - 218, - 155, - 142, - 126, - 108, - 208, - 4, - 123, - 65, - 228, - 208, - 0, - 207, - 3, - 20, - 227, - 215, - 138, - 81, - 19, - 147, - 157, - 202, - 40, - 1, - 143, - 31, - 28, - 224, - 125, - 41, - 84, - 46, - 222, - 73, - 167, - 16, - 7, - 4, - 146, - 105, - 60, - 183, - 110, - 49, - 129, - 235, - 64, - 9, - 193, - 29, - 63, - 58, - 69, - 136, - 131, - 184, - 56, - 247, - 24, - 167, - 178, - 149, - 31, - 49, - 7, - 233, - 76, - 235, - 192, - 4, - 226, - 128, - 6, - 59, - 142, - 58, - 147, - 72, - 99, - 11, - 213, - 113, - 82, - 4, - 118, - 25, - 82, - 23, - 235, - 77, - 127, - 66, - 104, - 2, - 35, - 18, - 30, - 115, - 249, - 84, - 126, - 75, - 103, - 10, - 15, - 53, - 97, - 75, - 39, - 240, - 126, - 52, - 52, - 133, - 65, - 201, - 164, - 5, - 115, - 19, - 171, - 109, - 32, - 103, - 218, - 153, - 180, - 231, - 161, - 63, - 74, - 121, - 102, - 39, - 36, - 210, - 198, - 223, - 62, - 115, - 138, - 6, - 69, - 140, - 118, - 197, - 1, - 201, - 24, - 221, - 86, - 153, - 98, - 56, - 222, - 9, - 111, - 106, - 26, - 53, - 101, - 229, - 66, - 251, - 208, - 5, - 77, - 180, - 5, - 45, - 192, - 4, - 212, - 206, - 129, - 23, - 33, - 183, - 10, - 95, - 52, - 21, - 192, - 24, - 62, - 180, - 1, - 8, - 136, - 247, - 227, - 218, - 165, - 216, - 241, - 167, - 32, - 5, - 61, - 233, - 86, - 93, - 189, - 84, - 100, - 119, - 164, - 89, - 20, - 185, - 50, - 130, - 104, - 0, - 27, - 79, - 33, - 73, - 247, - 166, - 237, - 94, - 167, - 39, - 29, - 133, - 56, - 186, - 179, - 99, - 36, - 39, - 181, - 72, - 21, - 148, - 145, - 8, - 3, - 212, - 181, - 0, - 66, - 202, - 28, - 114, - 2, - 168, - 168, - 74, - 16, - 51, - 142, - 42, - 209, - 76, - 54, - 0, - 44, - 253, - 233, - 172, - 14, - 127, - 123, - 249, - 10, - 0, - 175, - 214, - 144, - 174, - 49, - 206, - 106, - 207, - 148, - 178, - 13, - 216, - 84, - 81, - 211, - 21, - 23, - 150, - 78, - 72, - 25, - 3, - 189, - 0, - 68, - 69, - 38, - 42, - 78, - 71, - 61, - 40, - 52, - 1, - 30, - 41, - 164, - 83, - 205, - 24, - 160, - 6, - 98, - 140, - 83, - 177, - 74, - 171, - 154, - 0, - 180, - 22, - 165, - 142, - 51, - 78, - 68, - 201, - 169, - 214, - 50, - 41, - 128, - 44, - 124, - 117, - 169, - 21, - 7, - 122, - 2, - 241, - 214, - 156, - 41, - 136, - 105, - 92, - 30, - 40, - 218, - 24, - 116, - 169, - 0, - 245, - 163, - 110, - 57, - 20, - 1, - 14, - 54, - 156, - 83, - 177, - 232, - 42, - 92, - 6, - 20, - 152, - 218, - 104, - 1, - 138, - 51, - 71, - 151, - 143, - 165, - 61, - 151, - 184, - 160, - 28, - 245, - 226, - 128, - 26, - 23, - 158, - 180, - 237, - 160, - 240, - 105, - 8, - 32, - 245, - 165, - 200, - 34, - 128, - 27, - 179, - 105, - 224, - 241, - 78, - 42, - 15, - 56, - 230, - 148, - 17, - 208, - 211, - 198, - 59, - 82, - 2, - 28, - 149, - 59, - 72, - 167, - 138, - 121, - 195, - 112, - 105, - 188, - 138, - 0, - 5, - 33, - 227, - 173, - 59, - 131, - 222, - 140, - 250, - 208, - 3, - 112, - 185, - 200, - 52, - 225, - 130, - 48, - 105, - 10, - 103, - 165, - 52, - 49, - 7, - 4, - 80, - 2, - 149, - 218, - 114, - 180, - 236, - 2, - 41, - 172, - 91, - 210, - 133, - 203, - 15, - 122, - 0, - 141, - 212, - 129, - 134, - 25, - 30, - 180, - 205, - 190, - 134, - 172, - 158, - 7, - 205, - 80, - 50, - 224, - 252, - 163, - 35, - 218, - 152, - 4, - 106, - 195, - 210, - 166, - 35, - 112, - 207, - 67, - 80, - 161, - 203, - 99, - 161, - 169, - 198, - 113, - 235, - 72, - 6, - 131, - 216, - 138, - 81, - 156, - 83, - 179, - 158, - 13, - 48, - 144, - 58, - 80, - 3, - 25, - 128, - 205, - 51, - 120, - 45, - 232, - 105, - 204, - 65, - 60, - 210, - 50, - 130, - 189, - 63, - 26, - 0, - 107, - 70, - 173, - 200, - 224, - 212, - 91, - 31, - 56, - 219, - 248, - 212, - 225, - 88, - 244, - 25, - 169, - 16, - 99, - 130, - 104, - 2, - 37, - 132, - 227, - 231, - 193, - 20, - 191, - 102, - 67, - 200, - 39, - 233, - 83, - 48, - 3, - 154, - 77, - 195, - 176, - 52, - 1, - 25, - 137, - 7, - 85, - 230, - 149, - 120, - 198, - 41, - 228, - 228, - 114, - 42, - 50, - 141, - 156, - 169, - 160, - 7, - 158, - 123, - 96, - 210, - 5, - 231, - 45, - 64, - 4, - 240, - 212, - 125, - 223, - 113, - 64, - 14, - 36, - 99, - 174, - 106, - 34, - 6, - 120, - 24, - 53, - 38, - 213, - 60, - 175, - 6, - 130, - 72, - 224, - 129, - 249, - 80, - 3, - 54, - 142, - 232, - 51, - 65, - 25, - 92, - 46, - 62, - 148, - 243, - 156, - 117, - 226, - 155, - 176, - 30, - 173, - 131, - 64, - 16, - 125, - 152, - 183, - 42, - 216, - 246, - 197, - 66, - 200, - 200, - 112, - 213, - 112, - 54, - 211, - 200, - 205, - 46, - 65, - 232, - 50, - 40, - 2, - 144, - 247, - 165, - 32, - 118, - 169, - 158, - 220, - 185, - 202, - 28, - 31, - 74, - 134, - 68, - 104, - 200, - 221, - 210, - 144, - 198, - 209, - 154, - 92, - 3, - 72, - 87, - 154, - 0, - 114, - 200, - 203, - 208, - 212, - 139, - 48, - 35, - 7, - 131, - 80, - 80, - 56, - 52, - 1, - 51, - 38, - 91, - 32, - 226, - 164, - 1, - 118, - 243, - 218, - 160, - 220, - 123, - 26, - 124, - 114, - 168, - 63, - 53, - 49, - 11, - 131, - 191, - 129, - 79, - 96, - 196, - 112, - 216, - 164, - 97, - 188, - 102, - 50, - 40, - 85, - 0, - 97, - 207, - 229, - 64, - 13, - 1, - 27, - 140, - 157, - 223, - 90, - 104, - 18, - 198, - 79, - 203, - 242, - 250, - 138, - 113, - 218, - 167, - 228, - 25, - 167, - 229, - 153, - 49, - 145, - 143, - 122, - 0, - 133, - 139, - 55, - 57, - 207, - 176, - 164, - 13, - 216, - 41, - 207, - 189, - 74, - 60, - 180, - 231, - 146, - 212, - 143, - 190, - 78, - 113, - 192, - 160, - 6, - 59, - 184, - 79, - 152, - 243, - 233, - 85, - 219, - 230, - 230, - 159, - 46, - 73, - 35, - 176, - 168, - 199, - 6, - 144, - 198, - 129, - 154, - 149, - 33, - 92, - 101, - 152, - 147, - 237, - 79, - 22, - 234, - 169, - 184, - 185, - 207, - 165, - 57, - 79, - 31, - 42, - 17, - 239, - 64, - 11, - 181, - 143, - 240, - 128, - 61, - 106, - 50, - 170, - 8, - 220, - 219, - 190, - 148, - 246, - 12, - 7, - 206, - 220, - 123, - 82, - 40, - 39, - 148, - 76, - 123, - 154, - 98, - 20, - 161, - 100, - 33, - 84, - 1, - 250, - 213, - 76, - 114, - 71, - 165, - 93, - 216, - 1, - 203, - 49, - 111, - 97, - 73, - 247, - 129, - 1, - 0, - 30, - 167, - 173, - 32, - 41, - 208, - 69, - 78, - 246, - 227, - 105, - 216, - 249, - 111, - 74, - 132, - 130, - 14, - 24, - 96, - 251, - 208, - 49, - 167, - 167, - 53, - 40, - 92, - 40, - 50, - 183, - 30, - 149, - 30, - 42, - 80, - 217, - 69, - 80, - 9, - 110, - 148, - 0, - 226, - 206, - 192, - 5, - 27, - 23, - 212, - 212, - 108, - 155, - 142, - 21, - 137, - 35, - 185, - 169, - 72, - 0, - 15, - 53, - 179, - 254, - 205, - 46, - 9, - 28, - 97, - 19, - 222, - 128, - 42, - 82, - 228, - 129, - 193, - 198, - 122, - 211, - 156, - 46, - 236, - 168, - 33, - 71, - 20, - 210, - 40, - 0, - 221, - 129, - 142, - 212, - 246, - 141, - 54, - 239, - 251, - 163, - 29, - 61, - 106, - 44, - 22, - 59, - 64, - 201, - 171, - 8, - 21, - 122, - 229, - 136, - 233, - 232, - 40, - 2, - 22, - 140, - 99, - 112, - 224, - 30, - 213, - 30, - 218, - 178, - 120, - 147, - 156, - 51, - 118, - 29, - 170, - 41, - 0, - 15, - 199, - 92, - 115, - 64, - 17, - 237, - 193, - 230, - 151, - 56, - 167, - 2, - 51, - 146, - 51, - 67, - 38, - 56, - 7, - 62, - 166, - 128, - 52, - 80, - 84, - 224, - 102, - 161, - 78, - 181, - 97, - 65, - 21, - 66, - 0, - 164, - 123, - 138, - 8, - 167, - 81, - 138, - 0, - 104, - 60, - 210, - 150, - 226, - 148, - 40, - 235, - 138, - 118, - 6, - 48, - 105, - 0, - 204, - 250, - 83, - 179, - 145, - 77, - 35, - 109, - 3, - 52, - 0, - 163, - 32, - 244, - 165, - 49, - 238, - 28, - 80, - 15, - 173, - 60, - 26, - 0, - 104, - 24, - 63, - 53, - 33, - 65, - 156, - 138, - 123, - 115, - 70, - 40, - 1, - 187, - 70, - 58, - 102, - 147, - 238, - 158, - 58, - 83, - 241, - 233, - 70, - 120, - 160, - 4, - 24, - 52, - 26, - 66, - 10, - 156, - 142, - 148, - 236, - 230, - 128, - 26, - 83, - 184, - 160, - 1, - 208, - 210, - 242, - 40, - 192, - 34, - 128, - 20, - 12, - 116, - 165, - 235, - 76, - 201, - 83, - 207, - 74, - 119, - 81, - 197, - 0, - 20, - 155, - 115, - 210, - 150, - 151, - 189, - 0, - 48, - 145, - 222, - 153, - 183, - 186, - 156, - 212, - 216, - 7, - 168, - 164, - 32, - 14, - 69, - 0, - 67, - 128, - 88, - 100, - 115, - 82, - 128, - 71, - 74, - 92, - 231, - 181, - 28, - 131, - 64, - 13, - 96, - 77, - 68, - 192, - 158, - 149, - 59, - 114, - 42, - 50, - 188, - 231, - 173, - 0, - 66, - 65, - 199, - 52, - 228, - 7, - 56, - 235, - 78, - 242, - 137, - 229, - 79, - 224, - 105, - 200, - 172, - 56, - 35, - 20, - 0, - 187, - 50, - 56, - 226, - 141, - 189, - 143, - 90, - 95, - 152, - 82, - 131, - 158, - 15, - 90, - 0, - 136, - 252, - 167, - 173, - 57, - 72, - 110, - 148, - 243, - 142, - 252, - 211, - 72, - 83, - 208, - 98, - 128, - 6, - 56, - 166, - 210, - 225, - 186, - 19, - 70, - 195, - 234, - 49, - 64, - 9, - 156, - 31, - 155, - 243, - 164, - 97, - 198, - 84, - 230, - 159, - 181, - 69, - 48, - 237, - 29, - 51, - 64, - 8, - 9, - 60, - 98, - 148, - 150, - 252, - 40, - 7, - 52, - 29, - 223, - 133, - 0, - 40, - 0, - 142, - 180, - 16, - 160, - 83, - 8, - 25, - 206, - 72, - 160, - 63, - 175, - 52, - 0, - 224, - 222, - 212, - 125, - 48, - 41, - 1, - 61, - 168, - 41, - 187, - 189, - 0, - 33, - 124, - 54, - 15, - 233, - 75, - 149, - 97, - 207, - 205, - 76, - 101, - 10, - 121, - 230, - 148, - 31, - 238, - 228, - 208, - 4, - 18, - 198, - 51, - 149, - 226, - 163, - 53, - 101, - 129, - 144, - 115, - 193, - 237, - 80, - 188, - 50, - 40, - 201, - 193, - 250, - 80, - 3, - 58, - 210, - 98, - 133, - 235, - 205, - 43, - 41, - 28, - 246, - 164, - 49, - 49, - 138, - 76, - 211, - 199, - 78, - 105, - 184, - 20, - 0, - 35, - 21, - 60, - 84, - 233, - 40, - 35, - 230, - 21, - 95, - 161, - 165, - 205, - 1, - 98, - 125, - 165, - 254, - 233, - 20, - 190, - 88, - 3, - 231, - 110, - 125, - 170, - 5, - 145, - 148, - 96, - 84, - 177, - 144, - 195, - 47, - 205, - 49, - 6, - 236, - 125, - 212, - 220, - 62, - 148, - 141, - 159, - 92, - 122, - 138, - 151, - 126, - 56, - 141, - 106, - 38, - 206, - 114, - 253, - 104, - 2, - 6, - 251, - 198, - 152, - 7, - 204, - 1, - 227, - 222, - 156, - 79, - 204, - 113, - 66, - 161, - 119, - 199, - 64, - 58, - 210, - 25, - 96, - 34, - 162, - 142, - 174, - 105, - 126, - 118, - 24, - 24, - 81, - 233, - 72, - 172, - 7, - 202, - 131, - 7, - 214, - 148, - 163, - 30, - 101, - 108, - 125, - 41, - 136, - 104, - 10, - 135, - 131, - 185, - 141, - 12, - 36, - 63, - 120, - 109, - 30, - 212, - 133, - 206, - 112, - 131, - 61, - 179, - 79, - 25, - 85, - 38, - 71, - 200, - 244, - 52, - 1, - 24, - 96, - 56, - 141, - 115, - 239, - 75, - 34, - 182, - 3, - 72, - 195, - 3, - 210, - 140, - 238, - 111, - 220, - 174, - 208, - 41, - 101, - 104, - 193, - 27, - 185, - 97, - 216, - 82, - 1, - 170, - 236, - 231, - 8, - 56, - 245, - 166, - 179, - 41, - 202, - 182, - 29, - 187, - 84, - 152, - 46, - 191, - 63, - 200, - 190, - 162, - 163, - 24, - 13, - 132, - 27, - 135, - 77, - 216, - 160, - 8, - 10, - 178, - 144, - 24, - 99, - 52, - 232, - 207, - 205, - 180, - 16, - 62, - 181, - 44, - 167, - 247, - 100, - 49, - 220, - 199, - 167, - 168, - 170, - 196, - 118, - 60, - 28, - 80, - 50, - 195, - 109, - 13, - 251, - 176, - 88, - 247, - 39, - 165, - 14, - 118, - 242, - 231, - 115, - 31, - 225, - 20, - 136, - 92, - 199, - 132, - 199, - 190, - 105, - 99, - 63, - 43, - 5, - 1, - 155, - 222, - 128, - 26, - 195, - 41, - 150, - 96, - 190, - 139, - 80, - 14, - 149, - 58, - 5, - 25, - 36, - 239, - 99, - 219, - 210, - 160, - 29, - 40, - 1, - 241, - 171, - 16, - 72, - 56, - 7, - 189, - 63, - 36, - 166, - 19, - 229, - 78, - 237, - 64, - 24, - 1, - 164, - 60, - 14, - 138, - 40, - 56, - 206, - 249, - 56, - 95, - 225, - 81, - 222, - 128, - 19, - 39, - 110, - 212, - 59, - 87, - 187, - 30, - 244, - 96, - 5, - 194, - 168, - 219, - 220, - 158, - 244, - 188, - 145, - 190, - 81, - 133, - 236, - 163, - 189, - 35, - 101, - 176, - 207, - 199, - 247, - 80, - 80, - 4, - 76, - 160, - 30, - 58, - 123, - 208, - 14, - 70, - 14, - 6, - 58, - 154, - 145, - 135, - 24, - 97, - 151, - 61, - 20, - 118, - 168, - 200, - 218, - 196, - 100, - 28, - 80, - 6, - 138, - 14, - 213, - 105, - 79, - 2, - 171, - 168, - 230, - 167, - 166, - 33, - 196, - 103, - 165, - 0, - 82, - 102, - 138, - 0, - 112, - 24, - 165, - 164, - 165, - 160, - 6, - 159, - 74, - 48, - 125, - 41, - 72, - 205, - 40, - 160, - 4, - 198, - 105, - 6, - 71, - 90, - 119, - 52, - 14, - 104, - 0, - 57, - 236, - 104, - 205, - 46, - 13, - 27, - 104, - 1, - 164, - 226, - 151, - 173, - 46, - 5, - 46, - 40, - 1, - 51, - 142, - 180, - 148, - 238, - 180, - 152, - 197, - 0, - 24, - 163, - 4, - 26, - 5, - 28, - 208, - 2, - 230, - 154, - 114, - 14, - 69, - 41, - 28, - 230, - 148, - 123, - 208, - 3, - 65, - 205, - 4, - 48, - 52, - 236, - 3, - 69, - 0, - 10, - 217, - 20, - 81, - 176, - 117, - 20, - 116, - 235, - 64, - 6, - 40, - 231, - 165, - 7, - 167, - 20, - 110, - 245, - 160, - 6, - 237, - 207, - 122, - 94, - 157, - 69, - 7, - 218, - 148, - 28, - 245, - 160, - 4, - 60, - 114, - 41, - 51, - 158, - 180, - 236, - 1, - 73, - 128, - 104, - 0, - 230, - 154, - 72, - 61, - 120, - 52, - 165, - 72, - 250, - 83, - 74, - 131, - 200, - 56, - 160, - 5, - 227, - 240, - 160, - 173, - 3, - 142, - 8, - 205, - 3, - 158, - 148, - 0, - 220, - 145, - 215, - 165, - 46, - 15, - 81, - 138, - 11, - 122, - 241, - 70, - 211, - 216, - 138, - 0, - 92, - 122, - 138, - 107, - 47, - 25, - 90, - 9, - 199, - 13, - 249, - 210, - 103, - 142, - 40, - 1, - 171, - 147, - 214, - 156, - 84, - 143, - 122, - 64, - 75, - 122, - 83, - 249, - 29, - 104, - 2, - 63, - 151, - 61, - 77, - 56, - 176, - 199, - 74, - 12, - 106, - 199, - 32, - 144, - 105, - 172, - 74, - 117, - 228, - 122, - 208, - 2, - 0, - 217, - 200, - 20, - 187, - 185, - 230, - 133, - 37, - 134, - 70, - 40, - 42, - 15, - 12, - 40, - 1, - 14, - 59, - 115, - 245, - 164, - 70, - 231, - 128, - 5, - 59, - 229, - 94, - 135, - 34, - 155, - 184, - 30, - 128, - 10, - 0, - 115, - 22, - 61, - 120, - 166, - 152, - 219, - 174, - 65, - 165, - 195, - 30, - 189, - 41, - 192, - 109, - 31, - 122, - 128, - 41, - 202, - 48, - 217, - 198, - 40, - 7, - 214, - 167, - 149, - 193, - 224, - 143, - 210, - 160, - 3, - 210, - 129, - 136, - 125, - 169, - 188, - 131, - 78, - 57, - 205, - 29, - 104, - 1, - 54, - 228, - 83, - 64, - 231, - 6, - 159, - 130, - 13, - 52, - 140, - 154, - 64, - 27, - 127, - 42, - 17, - 252, - 179, - 207, - 74, - 90, - 67, - 215, - 20, - 1, - 54, - 237, - 231, - 229, - 32, - 82, - 144, - 168, - 9, - 124, - 49, - 168, - 71, - 29, - 42, - 85, - 92, - 124, - 196, - 228, - 250, - 83, - 17, - 93, - 128, - 12, - 113, - 78, - 136, - 46, - 236, - 147, - 73, - 39, - 223, - 38, - 132, - 42, - 15, - 205, - 210, - 144, - 201, - 67, - 18, - 112, - 171, - 248, - 226, - 134, - 249, - 78, - 93, - 183, - 122, - 10, - 114, - 187, - 50, - 254, - 237, - 69, - 52, - 5, - 86, - 221, - 38, - 115, - 76, - 64, - 185, - 111, - 245, - 96, - 39, - 214, - 154, - 64, - 86, - 253, - 233, - 201, - 246, - 52, - 247, - 119, - 124, - 97, - 72, - 95, - 92, - 83, - 64, - 69, - 25, - 39, - 123, - 30, - 212, - 128, - 114, - 179, - 184, - 192, - 27, - 87, - 214, - 154, - 140, - 145, - 228, - 70, - 60, - 195, - 222, - 148, - 43, - 57, - 201, - 59, - 87, - 210, - 149, - 153, - 84, - 237, - 136, - 96, - 158, - 244, - 192, - 137, - 216, - 177, - 253, - 225, - 192, - 254, - 237, - 46, - 230, - 113, - 182, - 33, - 180, - 122, - 154, - 10, - 224, - 239, - 148, - 131, - 233, - 205, - 11, - 190, - 94, - 167, - 108, - 116, - 0, - 131, - 17, - 30, - 153, - 126, - 153, - 237, - 76, - 156, - 63, - 14, - 227, - 31, - 74, - 144, - 48, - 7, - 108, - 63, - 55, - 169, - 52, - 174, - 171, - 26, - 146, - 88, - 179, - 159, - 225, - 164, - 5, - 81, - 203, - 1, - 146, - 7, - 122, - 155, - 59, - 134, - 216, - 184, - 29, - 218, - 161, - 32, - 142, - 8, - 193, - 169, - 144, - 121, - 145, - 141, - 164, - 34, - 175, - 95, - 122, - 6, - 11, - 133, - 249, - 87, - 230, - 61, - 218, - 160, - 31, - 46, - 125, - 141, - 78, - 6, - 236, - 249, - 64, - 34, - 142, - 254, - 181, - 95, - 156, - 227, - 223, - 173, - 0, - 77, - 194, - 224, - 147, - 186, - 67, - 208, - 10, - 14, - 85, - 178, - 223, - 52, - 135, - 160, - 20, - 12, - 110, - 11, - 0, - 231, - 185, - 165, - 140, - 17, - 33, - 84, - 249, - 143, - 241, - 19, - 64, - 9, - 146, - 62, - 83, - 243, - 59, - 118, - 236, - 41, - 0, - 108, - 144, - 184, - 103, - 247, - 237, - 78, - 80, - 75, - 21, - 139, - 156, - 253, - 227, - 233, - 76, - 254, - 31, - 151, - 59, - 65, - 193, - 110, - 244, - 192, - 48, - 67, - 225, - 14, - 230, - 238, - 231, - 181, - 53, - 192, - 207, - 28, - 227, - 248, - 189, - 105, - 229, - 178, - 51, - 247, - 19, - 177, - 199, - 90, - 36, - 192, - 10, - 72, - 192, - 236, - 190, - 180, - 128, - 208, - 79, - 189, - 82, - 212, - 0, - 242, - 13, - 76, - 173, - 218, - 152, - 133, - 165, - 218, - 125, - 104, - 167, - 14, - 156, - 208, - 0, - 7, - 20, - 102, - 142, - 148, - 184, - 205, - 0, - 20, - 14, - 105, - 58, - 83, - 133, - 0, - 38, - 105, - 104, - 34, - 129, - 64, - 6, - 104, - 233, - 70, - 40, - 20, - 0, - 30, - 69, - 25, - 199, - 90, - 8, - 193, - 165, - 24, - 52, - 0, - 134, - 140, - 158, - 244, - 99, - 20, - 238, - 40, - 2, - 50, - 15, - 81, - 78, - 235, - 75, - 70, - 56, - 160, - 4, - 165, - 192, - 52, - 99, - 7, - 154, - 62, - 148, - 0, - 152, - 199, - 74, - 92, - 102, - 140, - 250, - 138, - 90, - 0, - 78, - 69, - 28, - 55, - 90, - 40, - 32, - 142, - 69, - 0, - 24, - 199, - 74, - 92, - 3, - 76, - 4, - 154, - 83, - 145, - 212, - 80, - 2, - 226, - 130, - 41, - 55, - 118, - 52, - 160, - 208, - 3, - 119, - 96, - 224, - 209, - 201, - 228, - 83, - 136, - 83, - 214, - 142, - 7, - 74, - 0, - 104, - 111, - 90, - 25, - 7, - 80, - 105, - 73, - 6, - 140, - 80, - 4, - 123, - 187, - 26, - 112, - 245, - 20, - 226, - 138, - 195, - 154, - 97, - 5, - 15, - 6, - 128, - 28, - 72, - 35, - 4, - 83, - 54, - 227, - 233, - 75, - 203, - 12, - 83, - 66, - 48, - 235, - 64, - 14, - 194, - 158, - 13, - 38, - 0, - 232, - 105, - 216, - 226, - 163, - 221, - 131, - 214, - 128, - 29, - 146, - 125, - 41, - 165, - 91, - 189, - 56, - 29, - 221, - 5, - 41, - 86, - 199, - 122, - 0, - 106, - 128, - 59, - 210, - 151, - 29, - 14, - 13, - 55, - 142, - 230, - 151, - 35, - 166, - 1, - 160, - 4, - 199, - 57, - 81, - 75, - 180, - 30, - 9, - 32, - 210, - 16, - 216, - 200, - 31, - 149, - 32, - 60, - 252, - 192, - 138, - 0, - 70, - 93, - 167, - 189, - 46, - 119, - 14, - 0, - 167, - 238, - 3, - 190, - 105, - 187, - 183, - 28, - 40, - 20, - 0, - 221, - 174, - 15, - 56, - 199, - 181, - 59, - 11, - 140, - 247, - 164, - 101, - 113, - 247, - 135, - 30, - 212, - 223, - 148, - 115, - 146, - 40, - 1, - 73, - 227, - 30, - 190, - 213, - 93, - 198, - 211, - 193, - 171, - 27, - 201, - 224, - 12, - 254, - 21, - 28, - 177, - 28, - 103, - 60, - 208, - 4, - 38, - 144, - 210, - 209, - 154, - 6, - 38, - 104, - 197, - 12, - 59, - 210, - 102, - 128, - 16, - 245, - 162, - 148, - 138, - 74, - 64, - 37, - 73, - 27, - 144, - 121, - 168, - 205, - 40, - 160, - 5, - 147, - 239, - 115, - 72, - 172, - 170, - 114, - 70, - 69, - 13, - 210, - 133, - 24, - 96, - 79, - 52, - 1, - 42, - 22, - 147, - 238, - 124, - 163, - 233, - 74, - 192, - 33, - 249, - 240, - 199, - 174, - 105, - 85, - 153, - 254, - 80, - 54, - 138, - 113, - 81, - 16, - 201, - 59, - 137, - 166, - 33, - 138, - 100, - 114, - 56, - 249, - 127, - 42, - 107, - 24, - 195, - 254, - 236, - 18, - 198, - 128, - 90, - 98, - 71, - 221, - 20, - 23, - 88, - 120, - 0, - 22, - 245, - 160, - 5, - 42, - 118, - 230, - 83, - 143, - 161, - 166, - 238, - 99, - 196, - 99, - 143, - 90, - 112, - 4, - 229, - 228, - 32, - 175, - 165, - 55, - 113, - 144, - 149, - 136, - 5, - 2, - 128, - 16, - 132, - 67, - 144, - 75, - 183, - 161, - 165, - 144, - 23, - 140, - 18, - 118, - 123, - 82, - 22, - 72, - 206, - 54, - 130, - 244, - 121, - 100, - 229, - 230, - 60, - 118, - 20, - 128, - 68, - 195, - 169, - 88, - 198, - 204, - 119, - 164, - 192, - 70, - 199, - 223, - 127, - 90, - 112, - 220, - 227, - 8, - 54, - 167, - 122, - 64, - 66, - 29, - 144, - 140, - 183, - 114, - 104, - 2, - 57, - 145, - 131, - 2, - 196, - 18, - 105, - 139, - 142, - 132, - 241, - 79, - 145, - 2, - 41, - 220, - 196, - 201, - 233, - 81, - 175, - 108, - 250, - 208, - 50, - 93, - 219, - 192, - 254, - 24, - 135, - 235, - 80, - 176, - 228, - 254, - 149, - 54, - 210, - 231, - 124, - 167, - 106, - 142, - 131, - 214, - 162, - 144, - 29, - 231, - 182, - 121, - 160, - 9, - 20, - 177, - 140, - 5, - 32, - 39, - 115, - 77, - 85, - 224, - 133, - 108, - 39, - 118, - 161, - 20, - 178, - 252, - 255, - 0, - 44, - 107, - 250, - 210, - 150, - 87, - 60, - 141, - 136, - 58, - 40, - 239, - 64, - 133, - 36, - 96, - 1, - 149, - 140, - 119, - 245, - 166, - 225, - 74, - 130, - 217, - 8, - 15, - 3, - 214, - 156, - 79, - 241, - 200, - 48, - 7, - 221, - 74, - 67, - 156, - 111, - 97, - 243, - 31, - 186, - 148, - 198, - 39, - 250, - 198, - 203, - 2, - 49, - 247, - 82, - 145, - 88, - 231, - 36, - 100, - 250, - 30, - 212, - 230, - 249, - 78, - 7, - 205, - 35, - 127, - 227, - 180, - 155, - 121, - 216, - 167, - 221, - 156, - 210, - 2, - 237, - 75, - 31, - 165, - 69, - 78, - 83, - 138, - 160, - 39, - 165, - 20, - 138, - 114, - 41, - 212, - 8, - 57, - 199, - 52, - 14, - 41, - 105, - 13, - 32, - 23, - 25, - 160, - 113, - 64, - 165, - 60, - 208, - 1, - 239, - 64, - 52, - 131, - 129, - 75, - 138, - 0, - 90, - 74, - 1, - 165, - 197, - 0, - 20, - 152, - 238, - 41, - 104, - 160, - 3, - 52, - 81, - 214, - 147, - 56, - 235, - 64, - 11, - 214, - 140, - 145, - 212, - 82, - 230, - 147, - 61, - 168, - 0, - 235, - 74, - 5, - 52, - 244, - 165, - 6, - 128, - 29, - 138, - 111, - 78, - 148, - 180, - 80, - 1, - 184, - 119, - 163, - 52, - 214, - 233, - 77, - 220, - 7, - 122, - 0, - 115, - 117, - 200, - 165, - 6, - 155, - 156, - 210, - 131, - 138, - 0, - 14, - 15, - 81, - 70, - 7, - 165, - 33, - 60, - 230, - 148, - 48, - 245, - 160, - 3, - 104, - 236, - 105, - 6, - 115, - 79, - 164, - 34, - 128, - 2, - 185, - 28, - 83, - 73, - 35, - 174, - 126, - 180, - 236, - 226, - 151, - 57, - 160, - 6, - 2, - 125, - 104, - 220, - 58, - 26, - 93, - 184, - 233, - 72, - 85, - 79, - 90, - 0, - 48, - 59, - 80, - 73, - 236, - 105, - 54, - 224, - 240, - 77, - 25, - 61, - 141, - 0, - 24, - 39, - 144, - 105, - 216, - 7, - 168, - 20, - 132, - 55, - 108, - 83, - 3, - 115, - 134, - 20, - 0, - 21, - 32, - 252, - 180, - 161, - 137, - 224, - 241, - 71, - 211, - 52, - 187, - 129, - 226, - 128, - 26, - 83, - 156, - 228, - 82, - 49, - 0, - 114, - 41, - 219, - 91, - 61, - 50, - 40, - 33, - 72, - 195, - 12, - 80, - 3, - 1, - 56, - 200, - 6, - 141, - 129, - 186, - 177, - 20, - 191, - 119, - 149, - 205, - 33, - 5, - 135, - 7, - 6, - 128, - 26, - 87, - 103, - 70, - 200, - 247, - 161, - 91, - 158, - 20, - 125, - 105, - 192, - 50, - 253, - 236, - 26, - 9, - 83, - 208, - 115, - 64, - 10, - 114, - 70, - 14, - 113, - 81, - 236, - 92, - 231, - 38, - 148, - 171, - 147, - 192, - 56, - 165, - 242, - 240, - 114, - 92, - 208, - 2, - 135, - 219, - 208, - 83, - 95, - 230, - 83, - 158, - 41, - 75, - 129, - 199, - 90, - 66, - 132, - 130, - 73, - 160, - 10, - 204, - 57, - 52, - 222, - 244, - 231, - 200, - 115, - 73, - 158, - 104, - 24, - 148, - 132, - 0, - 41, - 230, - 152, - 69, - 0, - 47, - 106, - 109, - 45, - 3, - 175, - 52, - 0, - 218, - 41, - 197, - 70, - 105, - 41, - 0, - 210, - 77, - 57, - 78, - 14, - 105, - 27, - 173, - 47, - 27, - 148, - 251, - 208, - 4, - 163, - 205, - 99, - 128, - 8, - 30, - 180, - 226, - 162, - 32, - 14, - 226, - 73, - 236, - 105, - 217, - 148, - 175, - 24, - 2, - 144, - 4, - 207, - 114, - 223, - 90, - 98, - 26, - 21, - 165, - 57, - 108, - 168, - 20, - 214, - 125, - 132, - 170, - 2, - 199, - 215, - 20, - 230, - 18, - 49, - 249, - 242, - 171, - 77, - 221, - 180, - 226, - 32, - 88, - 247, - 160, - 5, - 84, - 219, - 150, - 145, - 176, - 61, - 41, - 9, - 121, - 78, - 20, - 108, - 95, - 92, - 80, - 0, - 206, - 233, - 137, - 221, - 233, - 74, - 198, - 70, - 224, - 169, - 11, - 64, - 3, - 58, - 161, - 10, - 163, - 121, - 246, - 20, - 133, - 8, - 249, - 229, - 111, - 248, - 14, - 40, - 141, - 246, - 41, - 17, - 169, - 99, - 72, - 121, - 249, - 164, - 206, - 238, - 194, - 128, - 26, - 164, - 202, - 216, - 251, - 139, - 233, - 73, - 149, - 221, - 182, - 17, - 131, - 221, - 169, - 78, - 73, - 204, - 131, - 106, - 251, - 82, - 225, - 152, - 109, - 136, - 97, - 123, - 154, - 64, - 53, - 194, - 15, - 151, - 27, - 220, - 247, - 244, - 168, - 15, - 12, - 71, - 165, - 90, - 80, - 35, - 82, - 35, - 249, - 152, - 245, - 38, - 170, - 183, - 82, - 79, - 83, - 64, - 201, - 49, - 136, - 247, - 202, - 114, - 49, - 192, - 205, - 49, - 198, - 2, - 251, - 246, - 167, - 66, - 160, - 225, - 137, - 201, - 236, - 180, - 78, - 122, - 19, - 214, - 128, - 4, - 32, - 69, - 243, - 13, - 222, - 130, - 148, - 141, - 160, - 52, - 131, - 39, - 248, - 86, - 155, - 17, - 11, - 200, - 229, - 207, - 74, - 94, - 67, - 101, - 142, - 100, - 63, - 165, - 48, - 23, - 44, - 24, - 110, - 27, - 156, - 244, - 30, - 148, - 143, - 144, - 121, - 59, - 152, - 247, - 244, - 160, - 112, - 74, - 169, - 203, - 159, - 188, - 222, - 148, - 152, - 249, - 72, - 92, - 0, - 62, - 241, - 245, - 164, - 0, - 62, - 102, - 249, - 120, - 3, - 171, - 122, - 210, - 156, - 2, - 88, - 140, - 15, - 79, - 90, - 0, - 202, - 131, - 140, - 39, - 101, - 245, - 164, - 96, - 88, - 131, - 220, - 244, - 30, - 148, - 192, - 188, - 69, - 37, - 57, - 78, - 69, - 4, - 12, - 211, - 16, - 248, - 219, - 7, - 6, - 166, - 206, - 106, - 184, - 52, - 224, - 230, - 128, - 39, - 162, - 145, - 78, - 105, - 123, - 210, - 1, - 7, - 20, - 238, - 180, - 152, - 165, - 197, - 0, - 2, - 150, - 146, - 138, - 0, - 13, - 25, - 162, - 148, - 80, - 2, - 26, - 81, - 239, - 75, - 73, - 64, - 6, - 49, - 71, - 90, - 78, - 115, - 75, - 64, - 5, - 47, - 90, - 5, - 24, - 244, - 160, - 2, - 146, - 148, - 28, - 209, - 64, - 5, - 55, - 56, - 62, - 212, - 180, - 109, - 244, - 52, - 0, - 157, - 104, - 218, - 58, - 226, - 151, - 111, - 190, - 41, - 57, - 7, - 6, - 128, - 19, - 111, - 167, - 20, - 21, - 108, - 117, - 167, - 80, - 77, - 0, - 70, - 16, - 17, - 212, - 230, - 158, - 20, - 119, - 163, - 56, - 57, - 236, - 105, - 119, - 80, - 2, - 17, - 183, - 233, - 74, - 61, - 65, - 165, - 164, - 28, - 116, - 160, - 5, - 164, - 42, - 59, - 81, - 197, - 29, - 58, - 80, - 3, - 78, - 84, - 250, - 138, - 94, - 13, - 46, - 105, - 8, - 160, - 0, - 113, - 212, - 208, - 77, - 3, - 29, - 13, - 38, - 0, - 233, - 64, - 10, - 121, - 166, - 152, - 243, - 222, - 151, - 119, - 189, - 47, - 94, - 134, - 128, - 25, - 146, - 15, - 90, - 66, - 217, - 237, - 82, - 96, - 119, - 20, - 194, - 6, - 120, - 20, - 0, - 139, - 187, - 184, - 56, - 165, - 33, - 72, - 235, - 65, - 221, - 138, - 64, - 55, - 115, - 186, - 128, - 27, - 187, - 105, - 235, - 78, - 35, - 127, - 66, - 40, - 200, - 29, - 112, - 104, - 251, - 221, - 5, - 0, - 38, - 54, - 245, - 230, - 147, - 229, - 61, - 23, - 154, - 126, - 209, - 252, - 64, - 211, - 112, - 131, - 238, - 231, - 52, - 0, - 208, - 204, - 56, - 228, - 82, - 224, - 30, - 119, - 82, - 150, - 99, - 198, - 8, - 166, - 152, - 243, - 206, - 234, - 0, - 93, - 192, - 116, - 193, - 166, - 177, - 102, - 29, - 64, - 165, - 12, - 171, - 193, - 2, - 154, - 84, - 158, - 69, - 0, - 64, - 192, - 131, - 243, - 117, - 166, - 211, - 156, - 115, - 77, - 160, - 98, - 245, - 20, - 148, - 10, - 13, - 33, - 8, - 71, - 20, - 152, - 52, - 166, - 128, - 104, - 24, - 135, - 154, - 76, - 98, - 134, - 246, - 162, - 128, - 18, - 129, - 74, - 1, - 160, - 241, - 64, - 18, - 39, - 152, - 252, - 14, - 149, - 47, - 238, - 227, - 28, - 0, - 90, - 160, - 135, - 115, - 146, - 162, - 164, - 37, - 99, - 249, - 112, - 25, - 168, - 16, - 184, - 119, - 251, - 220, - 45, - 55, - 32, - 124, - 176, - 142, - 105, - 89, - 100, - 43, - 150, - 96, - 23, - 210, - 145, - 27, - 156, - 32, - 25, - 245, - 166, - 1, - 229, - 42, - 252, - 243, - 242, - 223, - 90, - 8, - 146, - 81, - 129, - 194, - 125, - 105, - 91, - 8, - 115, - 41, - 14, - 105, - 88, - 22, - 94, - 8, - 85, - 244, - 164, - 4, - 97, - 130, - 157, - 144, - 140, - 159, - 90, - 14, - 212, - 59, - 165, - 249, - 155, - 235, - 78, - 5, - 73, - 217, - 24, - 25, - 238, - 113, - 72, - 72, - 135, - 169, - 12, - 199, - 218, - 152, - 8, - 99, - 45, - 251, - 201, - 72, - 10, - 59, - 80, - 3, - 74, - 48, - 132, - 34, - 10, - 82, - 55, - 15, - 50, - 86, - 224, - 116, - 90, - 102, - 76, - 135, - 146, - 99, - 94, - 220, - 82, - 0, - 56, - 13, - 178, - 46, - 189, - 218, - 160, - 144, - 109, - 56, - 206, - 125, - 234, - 198, - 75, - 157, - 145, - 130, - 23, - 185, - 170, - 242, - 112, - 248, - 7, - 32, - 119, - 166, - 49, - 98, - 96, - 132, - 128, - 9, - 115, - 210, - 157, - 42, - 237, - 143, - 107, - 16, - 92, - 156, - 147, - 233, - 77, - 133, - 153, - 88, - 132, - 93, - 196, - 254, - 148, - 167, - 141, - 216, - 201, - 56, - 249, - 137, - 237, - 72, - 67, - 35, - 36, - 31, - 151, - 25, - 60, - 15, - 106, - 123, - 15, - 151, - 106, - 243, - 207, - 204, - 213, - 26, - 240, - 195, - 21, - 55, - 12, - 49, - 157, - 136, - 189, - 125, - 232, - 24, - 132, - 0, - 161, - 87, - 132, - 238, - 221, - 205, - 33, - 33, - 134, - 78, - 118, - 142, - 130, - 128, - 70, - 55, - 21, - 194, - 142, - 21, - 125, - 105, - 64, - 43, - 254, - 241, - 237, - 233, - 76, - 0, - 183, - 115, - 247, - 143, - 79, - 106, - 111, - 183, - 62, - 231, - 214, - 156, - 188, - 130, - 7, - 221, - 31, - 120, - 210, - 96, - 158, - 71, - 115, - 197, - 2, - 47, - 20, - 199, - 214, - 144, - 19, - 222, - 166, - 32, - 48, - 199, - 113, - 77, - 217, - 235, - 76, - 6, - 98, - 138, - 113, - 27, - 126, - 148, - 209, - 64, - 18, - 198, - 120, - 169, - 55, - 14, - 42, - 184, - 200, - 167, - 6, - 160, - 11, - 2, - 138, - 98, - 183, - 62, - 212, - 239, - 113, - 72, - 5, - 34, - 138, - 77, - 212, - 188, - 26, - 0, - 90, - 76, - 210, - 142, - 40, - 32, - 26, - 0, - 1, - 162, - 138, - 51, - 64, - 5, - 29, - 13, - 25, - 160, - 208, - 1, - 205, - 0, - 208, - 13, - 6, - 128, - 3, - 73, - 154, - 50, - 123, - 208, - 13, - 0, - 24, - 30, - 166, - 148, - 28, - 112, - 104, - 205, - 33, - 52, - 0, - 185, - 164, - 220, - 41, - 41, - 195, - 165, - 0, - 37, - 40, - 52, - 187, - 65, - 164, - 42, - 49, - 197, - 0, - 4, - 83, - 74, - 250, - 82, - 227, - 212, - 209, - 183, - 253, - 170, - 0, - 81, - 210, - 151, - 173, - 51, - 37, - 78, - 15, - 231, - 79, - 7, - 34, - 128, - 16, - 169, - 52, - 46, - 123, - 210, - 209, - 248, - 208, - 2, - 26, - 51, - 199, - 52, - 166, - 154, - 15, - 98, - 40, - 0, - 219, - 232, - 105, - 14, - 69, - 41, - 207, - 106, - 76, - 3, - 212, - 80, - 1, - 156, - 246, - 20, - 210, - 24, - 30, - 5, - 60, - 40, - 237, - 77, - 109, - 195, - 166, - 104, - 0, - 250, - 211, - 73, - 11, - 222, - 156, - 57, - 239, - 138, - 82, - 7, - 126, - 104, - 0, - 86, - 220, - 41, - 172, - 132, - 28, - 209, - 184, - 14, - 0, - 165, - 25, - 244, - 160, - 6, - 124, - 189, - 10, - 131, - 73, - 143, - 64, - 71, - 210, - 164, - 40, - 167, - 147, - 197, - 53, - 155, - 104, - 226, - 128, - 26, - 51, - 252, - 89, - 167, - 0, - 163, - 248, - 169, - 23, - 230, - 254, - 42, - 95, - 44, - 142, - 226, - 128, - 17, - 164, - 236, - 40, - 216, - 91, - 161, - 165, - 200, - 61, - 134, - 105, - 54, - 190, - 120, - 198, - 40, - 1, - 62, - 85, - 28, - 168, - 164, - 47, - 199, - 2, - 156, - 85, - 8, - 249, - 133, - 67, - 38, - 209, - 247, - 73, - 160, - 8, - 216, - 243, - 76, - 52, - 226, - 121, - 164, - 52, - 12, - 64, - 113, - 70, - 40, - 227, - 20, - 80, - 3, - 79, - 90, - 80, - 61, - 104, - 60, - 80, - 41, - 0, - 210, - 57, - 163, - 165, - 41, - 164, - 32, - 145, - 197, - 0, - 75, - 22, - 29, - 72, - 197, - 66, - 192, - 134, - 34, - 167, - 135, - 1, - 54, - 168, - 25, - 238, - 106, - 39, - 31, - 53, - 0, - 53, - 88, - 131, - 197, - 79, - 188, - 40, - 206, - 1, - 53, - 94, - 164, - 142, - 86, - 81, - 128, - 50, - 79, - 165, - 0, - 72, - 84, - 177, - 203, - 176, - 3, - 174, - 41, - 55, - 151, - 59, - 99, - 24, - 30, - 184, - 161, - 148, - 99, - 116, - 132, - 250, - 208, - 142, - 207, - 194, - 41, - 3, - 214, - 152, - 133, - 218, - 145, - 13, - 206, - 119, - 55, - 165, - 32, - 67, - 48, - 221, - 35, - 21, - 29, - 133, - 35, - 42, - 198, - 217, - 220, - 75, - 30, - 212, - 187, - 90, - 69, - 253, - 225, - 42, - 191, - 149, - 0, - 2, - 79, - 224, - 136, - 113, - 211, - 118, - 40, - 194, - 68, - 119, - 12, - 187, - 154, - 64, - 95, - 27, - 98, - 82, - 87, - 214, - 154, - 112, - 48, - 20, - 18, - 231, - 222, - 128, - 23, - 3, - 62, - 100, - 199, - 158, - 203, - 65, - 204, - 167, - 50, - 252, - 177, - 138, - 70, - 1, - 57, - 151, - 150, - 236, - 1, - 164, - 101, - 112, - 161, - 164, - 198, - 222, - 195, - 52, - 128, - 93, - 197, - 134, - 212, - 24, - 143, - 161, - 230, - 171, - 190, - 55, - 156, - 116, - 169, - 240, - 206, - 155, - 142, - 17, - 123, - 15, - 90, - 172, - 79, - 38, - 129, - 143, - 136, - 178, - 177, - 217, - 140, - 159, - 90, - 119, - 1, - 74, - 103, - 147, - 247, - 141, - 50, - 48, - 75, - 112, - 113, - 234, - 106, - 64, - 60, - 204, - 246, - 65, - 252, - 84, - 196, - 64, - 69, - 76, - 191, - 188, - 80, - 207, - 247, - 71, - 79, - 122, - 133, - 185, - 39, - 210, - 159, - 27, - 149, - 24, - 235, - 233, - 72, - 100, - 132, - 97, - 242, - 220, - 159, - 225, - 30, - 148, - 206, - 237, - 147, - 207, - 115, - 75, - 158, - 56, - 57, - 99, - 212, - 250, - 82, - 140, - 99, - 0, - 124, - 163, - 245, - 166, - 33, - 9, - 249, - 64, - 3, - 129, - 211, - 222, - 149, - 88, - 134, - 254, - 116, - 133, - 139, - 18, - 113, - 255, - 0, - 214, - 164, - 206, - 6, - 122, - 208, - 6, - 167, - 90, - 81, - 239, - 77, - 35, - 184, - 165, - 28, - 208, - 2, - 145, - 216, - 244, - 166, - 108, - 193, - 226, - 159, - 245, - 165, - 197, - 48, - 27, - 129, - 76, - 35, - 7, - 21, - 45, - 24, - 12, - 57, - 160, - 8, - 195, - 96, - 212, - 129, - 169, - 166, - 58, - 110, - 13, - 0, - 60, - 228, - 210, - 171, - 17, - 193, - 166, - 161, - 206, - 69, - 59, - 25, - 95, - 165, - 0, - 59, - 119, - 165, - 40, - 106, - 137, - 179, - 218, - 144, - 54, - 120, - 52, - 1, - 54, - 239, - 90, - 42, - 29, - 220, - 226, - 156, - 9, - 198, - 40, - 176, - 15, - 39, - 156, - 82, - 110, - 56, - 164, - 60, - 138, - 50, - 8, - 160, - 7, - 6, - 7, - 189, - 40, - 166, - 109, - 230, - 157, - 130, - 5, - 0, - 41, - 165, - 2, - 155, - 78, - 232, - 40, - 1, - 254, - 212, - 220, - 123, - 209, - 187, - 52, - 134, - 144, - 10, - 22, - 151, - 24, - 233, - 64, - 163, - 52, - 0, - 153, - 197, - 46, - 234, - 111, - 227, - 71, - 78, - 180, - 0, - 81, - 206, - 57, - 165, - 29, - 121, - 167, - 99, - 138, - 0, - 143, - 56, - 165, - 20, - 16, - 59, - 138, - 64, - 48, - 120, - 233, - 64, - 18, - 83, - 78, - 105, - 115, - 197, - 55, - 112, - 52, - 0, - 191, - 90, - 66, - 5, - 47, - 214, - 140, - 15, - 90, - 0, - 79, - 166, - 104, - 235, - 214, - 130, - 113, - 212, - 82, - 99, - 61, - 232, - 0, - 233, - 222, - 148, - 62, - 105, - 54, - 99, - 173, - 33, - 218, - 59, - 80, - 2, - 176, - 39, - 167, - 90, - 78, - 71, - 222, - 20, - 12, - 246, - 20, - 191, - 90, - 0, - 105, - 11, - 219, - 52, - 153, - 97, - 235, - 138, - 83, - 242, - 255, - 0, - 21, - 46, - 252, - 244, - 160, - 4, - 224, - 255, - 0, - 21, - 46, - 118, - 142, - 198, - 153, - 181, - 179, - 235, - 79, - 200, - 28, - 17, - 64, - 9, - 184, - 183, - 221, - 2, - 155, - 181, - 191, - 139, - 165, - 7, - 175, - 202, - 166, - 148, - 19, - 223, - 52, - 0, - 223, - 145, - 79, - 124, - 210, - 249, - 135, - 160, - 6, - 149, - 130, - 158, - 123, - 211, - 55, - 145, - 192, - 34, - 128, - 28, - 70, - 71, - 39, - 21, - 89, - 243, - 187, - 25, - 200, - 169, - 25, - 207, - 214, - 163, - 61, - 121, - 160, - 6, - 226, - 145, - 169, - 73, - 244, - 164, - 193, - 52, - 0, - 130, - 142, - 41, - 113, - 77, - 160, - 97, - 72, - 105, - 115, - 197, - 39, - 52, - 0, - 152, - 167, - 70, - 55, - 62, - 59, - 14, - 180, - 132, - 154, - 145, - 98, - 108, - 124, - 220, - 45, - 33, - 14, - 101, - 78, - 21, - 23, - 147, - 214, - 163, - 145, - 10, - 158, - 106, - 80, - 169, - 159, - 144, - 28, - 251, - 154, - 142, - 101, - 101, - 31, - 49, - 20, - 192, - 139, - 20, - 228, - 109, - 141, - 145, - 77, - 160, - 241, - 72, - 100, - 216, - 71, - 230, - 66, - 105, - 203, - 41, - 111, - 146, - 53, - 192, - 245, - 168, - 99, - 218, - 220, - 62, - 113, - 82, - 128, - 231, - 136, - 215, - 11, - 245, - 160, - 66, - 226, - 40, - 206, - 121, - 103, - 247, - 166, - 182, - 231, - 57, - 151, - 33, - 71, - 106, - 113, - 17, - 167, - 65, - 151, - 250, - 211, - 66, - 156, - 150, - 155, - 242, - 205, - 48, - 23, - 204, - 98, - 54, - 196, - 48, - 61, - 105, - 187, - 145, - 14, - 20, - 2, - 254, - 180, - 108, - 105, - 63, - 213, - 168, - 85, - 164, - 98, - 171, - 242, - 42, - 169, - 111, - 90, - 0, - 77, - 222, - 91, - 101, - 128, - 102, - 63, - 141, - 59, - 149, - 59, - 228, - 108, - 183, - 101, - 164, - 255, - 0, - 85, - 208, - 150, - 115, - 218, - 148, - 133, - 140, - 111, - 144, - 146, - 244, - 1, - 28, - 178, - 22, - 28, - 140, - 31, - 74, - 128, - 210, - 187, - 23, - 109, - 198, - 155, - 64, - 199, - 40, - 235, - 233, - 222, - 164, - 99, - 242, - 3, - 209, - 7, - 111, - 90, - 141, - 61, - 250, - 103, - 165, - 76, - 184, - 99, - 185, - 184, - 199, - 69, - 197, - 2, - 43, - 177, - 201, - 205, - 38, - 113, - 79, - 124, - 238, - 36, - 140, - 26, - 142, - 144, - 201, - 84, - 238, - 60, - 113, - 74, - 122, - 250, - 84, - 64, - 224, - 212, - 155, - 242, - 57, - 166, - 33, - 194, - 163, - 144, - 224, - 224, - 80, - 92, - 227, - 142, - 190, - 180, - 206, - 248, - 234, - 104, - 25, - 177, - 210, - 148, - 117, - 166, - 231, - 20, - 28, - 246, - 166, - 34, - 65, - 207, - 20, - 157, - 40, - 7, - 32, - 30, - 244, - 19, - 64, - 1, - 28, - 100, - 82, - 7, - 193, - 164, - 45, - 76, - 205, - 0, - 77, - 188, - 83, - 115, - 233, - 81, - 231, - 138, - 65, - 158, - 212, - 0, - 254, - 141, - 145, - 79, - 6, - 162, - 206, - 105, - 69, - 0, - 73, - 193, - 164, - 49, - 231, - 165, - 55, - 36, - 84, - 138, - 224, - 253, - 104, - 2, - 53, - 82, - 15, - 53, - 40, - 81, - 138, - 24, - 12, - 230, - 149, - 79, - 24, - 160, - 6, - 142, - 188, - 210, - 149, - 29, - 169, - 74, - 130, - 115, - 74, - 56, - 235, - 205, - 0, - 2, - 158, - 41, - 185, - 244, - 165, - 205, - 32, - 17, - 151, - 29, - 40, - 3, - 214, - 151, - 173, - 37, - 0, - 35, - 47, - 165, - 0, - 227, - 173, - 46, - 61, - 233, - 49, - 64, - 15, - 4, - 118, - 163, - 173, - 71, - 208, - 210, - 140, - 250, - 208, - 3, - 240, - 41, - 132, - 226, - 148, - 26, - 48, - 40, - 1, - 1, - 165, - 44, - 64, - 165, - 227, - 218, - 146, - 128, - 16, - 55, - 168, - 167, - 6, - 166, - 237, - 193, - 226, - 148, - 17, - 233, - 64, - 8, - 205, - 131, - 210, - 147, - 118, - 123, - 83, - 138, - 228, - 83, - 72, - 24, - 160, - 5, - 7, - 214, - 157, - 81, - 169, - 29, - 233, - 192, - 250, - 80, - 3, - 179, - 158, - 180, - 194, - 15, - 97, - 79, - 200, - 164, - 39, - 20, - 0, - 131, - 36, - 115, - 70, - 7, - 90, - 51, - 158, - 244, - 184, - 199, - 106, - 0, - 51, - 138, - 67, - 150, - 233, - 70, - 239, - 106, - 105, - 7, - 168, - 20, - 0, - 5, - 199, - 45, - 74, - 72, - 199, - 2, - 128, - 71, - 113, - 77, - 125, - 189, - 69, - 0, - 33, - 207, - 96, - 105, - 64, - 7, - 239, - 102, - 132, - 99, - 211, - 154, - 115, - 12, - 142, - 180, - 0, - 222, - 159, - 116, - 211, - 75, - 147, - 214, - 151, - 36, - 119, - 163, - 37, - 190, - 148, - 0, - 4, - 98, - 115, - 144, - 104, - 108, - 40, - 232, - 41, - 174, - 219, - 71, - 21, - 17, - 144, - 55, - 20, - 0, - 210, - 220, - 159, - 74, - 24, - 241, - 72, - 105, - 9, - 226, - 128, - 17, - 121, - 228, - 208, - 79, - 52, - 40, - 61, - 168, - 97, - 206, - 104, - 0, - 25, - 52, - 16, - 41, - 115, - 73, - 64, - 12, - 39, - 154, - 90, - 24, - 142, - 180, - 42, - 22, - 228, - 130, - 22, - 144, - 0, - 28, - 140, - 12, - 158, - 213, - 40, - 89, - 31, - 151, - 4, - 1, - 78, - 64, - 131, - 238, - 228, - 147, - 74, - 219, - 255, - 0, - 139, - 129, - 76, - 0, - 108, - 78, - 17, - 126, - 106, - 142, - 120, - 206, - 222, - 88, - 28, - 212, - 129, - 129, - 251, - 184, - 30, - 244, - 215, - 140, - 128, - 73, - 108, - 154, - 0, - 172, - 41, - 15, - 52, - 234, - 105, - 164, - 48, - 206, - 41, - 203, - 43, - 1, - 142, - 212, - 218, - 105, - 52, - 1, - 97, - 89, - 113, - 194, - 130, - 105, - 74, - 56, - 249, - 159, - 110, - 61, - 51, - 85, - 178, - 71, - 74, - 145, - 102, - 61, - 232, - 17, - 38, - 246, - 147, - 42, - 8, - 69, - 20, - 155, - 136, - 27, - 83, - 167, - 174, - 41, - 143, - 41, - 106, - 67, - 41, - 198, - 40, - 24, - 230, - 217, - 23, - 59, - 137, - 53, - 11, - 185, - 115, - 150, - 164, - 235, - 214, - 146, - 128, - 3, - 73, - 75, - 73, - 76, - 9, - 16, - 113, - 156, - 243, - 216, - 83, - 200, - 206, - 50, - 126, - 99, - 250, - 83, - 19, - 166, - 59, - 154, - 147, - 27, - 125, - 253, - 232, - 17, - 28, - 170, - 87, - 169, - 207, - 189, - 69, - 82, - 200, - 114, - 189, - 120, - 168, - 141, - 3, - 18, - 140, - 226, - 133, - 86, - 115, - 133, - 31, - 141, - 92, - 130, - 203, - 39, - 47, - 201, - 161, - 33, - 92, - 173, - 28, - 79, - 39, - 65, - 129, - 87, - 173, - 236, - 130, - 224, - 183, - 90, - 181, - 28, - 33, - 71, - 2, - 165, - 11, - 79, - 68, - 0, - 255, - 217 - ]); + var listData = Uint8List(0).obs; //得到的视频流字节数据 } From 62b95c6d88e96c286d5b4f9ca5b3278fba2a3d47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AD=8F=E5=B0=91=E9=98=B3?= <786612630@qq.com> Date: Thu, 21 Dec 2023 10:21:25 +0800 Subject: [PATCH 13/33] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=AF=B9=E8=AE=B2?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../images/main/icon_lockDetail_hangUp.png | Bin 0 -> 2020 bytes .../icon_lockDetail_monitoringAnswerCalls.png | Bin 0 -> 3027 bytes .../icon_lockDetail_monitoringUnTalkback.png | Bin 0 -> 2941 bytes star_lock/lib/main.dart | 8 -- .../monitoring/lockMonitoring_logic.dart | 11 ++ .../monitoring/lockMonitoring_page.dart | 133 +++++++++++++++++- .../monitoring/lockMonitoring_state.dart | 5 +- star_lock/lib/talk/call/callTalk.dart | 1 + .../udp/io_protocol/udp_mainProtocol.dart | 4 +- star_lock/lib/talk/udp/udp_help.dart | 25 ++-- star_lock/lib/talk/udp/udp_manage.dart | 12 +- star_lock/lib/talk/udp/udp_reciverData.dart | 31 +++- star_lock/lib/talk/udp/udp_senderManage.dart | 4 +- star_lock/lib/talk/udp/udp_talkClass.dart | 17 ++- star_lock/lib/tools/eventBusEventManage.dart | 6 + star_lock/lib/tools/storage.dart | 4 +- 16 files changed, 222 insertions(+), 39 deletions(-) create mode 100644 star_lock/images/main/icon_lockDetail_hangUp.png create mode 100644 star_lock/images/main/icon_lockDetail_monitoringAnswerCalls.png create mode 100644 star_lock/images/main/icon_lockDetail_monitoringUnTalkback.png diff --git a/star_lock/images/main/icon_lockDetail_hangUp.png b/star_lock/images/main/icon_lockDetail_hangUp.png new file mode 100644 index 0000000000000000000000000000000000000000..5c3e9a8c5911bd5aae6458272bd2eb751bc6037d GIT binary patch literal 2020 zcmdT_`#%%Q-Ej^0{bNl+C-4Wqem- zDpwEhSe@6{X1J^MOn_85?tS5K<}T7!tLJp>v(Mfr)V+siOOH!9s3@3DtbUA{Rn*}p zYY1Bs`1>>#eJ+(BNcj8Dt>4-wtc44dql`@KQv)_zX-^u0G#7`Wfp`m=$!dba(`ia@ zt28eFL3Tnja$6Ca0E*Mx-u8lsqnQYCjb8n90Qb+J4d7r%kZ}r`^qmZ#nz1nG;UJ~| z`H_B);D`uvPGf?$wsx05AeiECI7^oT_uH$hul~BE*($RV-}Qz?K|WcF=0+jt>>q(@j2XoNRBh(;y_GH z%n806!Bg5O!&-i*!;Eo725F-5o0puNMswvD4O4?CQ0dTqCpQ=8KGdqaQwsm=nA99; zE4~8}$_}Z|LKa<3#eNc_vDxfhJRaYKT=JFgEy3eWb2uTY(|l;ZCT+z10B|bjR;V}4=Ldb;oB0t6UQ<_$0UAC zvk#emr*lo!^fPRU|_U`U{H8<$Z>aJaMRs!<-M+&X`H$xX*>NLsfN+IHFFkl4P+0dCbS`u0)G&b@!Q%DTqqh;R z()F8>2Vd3?F_s7PS;No;k#@kA(}>?kenVUD!|rV5f@C)%fVwR=k{Bl1Am7nlTG5Yn zF@ozuY4fW_OrgqXSP3D3)I@dA(p#z=Wif|%{ zO`HMSY@U}Hg^r!u;n^V6SmVr0g=2c9Fc2m(z5X&FKGY9FPEt;k*nix5QVQIU2eIgm z)EQ@y%>vgX4(6gTKR3o{Mgi1*vUNwx*?yd&UTnG3n~TojW(In)p!htud~JOx;oE~2 zqT*9>>u2}2=O`e(N6}p2F{A>D%wd3eBvCx9XtpS`42+Ao^%Ejr_o#B_?dw4c!CUyT zext&_H=>O~ZT3GW?f(T`NLXsx;zo8bw=+ZNy zKBqPkH}P;tt679qwEVps16;iS_-1cYn`T7N4-7e5!xVo{Y0yDq#vdBD-)5a*P%#w= z!=7hDF^0B-rq?&4n|wWt9>h0zrt_$v)5iv?re}Kj%1oc$Jio2}mioj%U;d=Iqw32? zS=bg|;tMm(T8(ei+`Hxj^T+e%--xf&3c?e`!uE>gW{0AO(vxAC(KR)%r>l0?nKM*? z{wnrs&kX6<^D{Rd?3Lm9^6g^Il?7{y3Os*$3)Mt-cuScKd{lt7-OiXaw%sIZQzA15 z#5z&7c$rtPXkUpk2#(+i%jZ!HHMr~~%Oaon=wcX%H8BMK6O^te&CYK^7X#vXWtHR3 zbK&{25atc*_~Mvuw+$sSX#FrV=63Gu{E!}~_}~I+(Weg@vGyrp!N3c$c(NIRbm^lu zdqLchuUyN>fHR1Ng83`=e#)bT%$rBltWQxadB$ zV+3q0%QJ7e(f=5-at!@CdI*jEAq%VxSWTu4dGg{;I0=;e4hIVYi77rFlE}{CsnxUV ziO~HoxXTtDsJjiBL7d(ZQu5WADdSs6mPbMbiKurmupMR7a(+}$3Pbxt z{#a;%LTS;_)T9%D`Zn^gY{@Pr zvdcO|l3j!>dHv7-+xz8x&Ux?F zXYd&y&$H`bcHcqH0-er)7+y_RDx4Z~k2u}x8DP#K|G?X~|z`(#YGP8DX zc6ZlDd*9e^cZ;&MI@KEY=vfQt;p={{v-fV&Ik-YEqATO~=66qdTc3Zse;3=@+T>gboPs=1 zkh@}l2?mgEx-QfwPx275xQ_>W^;ETFJ`b>+d-hk!e3?Y=?`DG!?HxRSJt>-Fti6f=1DyW)WniFom_2V} zez0g>*!2tqxL$m6@9D6w0Ue4E)Rr>$!;N#*#F%e$TG_3pmqz8DvcA5XrcC{ER!JIs zGI79DL(Bk}dj4Wv2KbUnX+w0r9QSKwn@eL>(suzKG(KtB&B=#=$)8`-s&lI<#(|>N zYcP zF$>D*3~wos5Kb*z^oG>E%lEH(IAdzuE54GRnSX}fP+;`|vD@%TCS`Jhk)$vpTy7+& zVZ-!>Pzn2T#dAfy{@60-d{=^;4>^&&N!*W2V;?5wlM7_nK!@MEwy*ZeDeu+`%(&%6 z6o}_;e)97*X6`xdU~pYw(gJ)SJb4EvX4Aevxv(MYtv|PRhifiQnQcmDc_=X$qlJQE zZOcA6o>N*l@^{cQ5}3%k!ka5Qd~uekEp)LIV>Ix3y=VUK*y0g7XDk&UzPSa>E}anp zxQo`W1WRHpmw9hOI$l&;UkImcG$D&PX8V$qkj`N%%BB9x;~&+hHzrML+k7KGisAuc zK+Svse? zYnuInr;T}8H&lSmt{yn>H}3Yx4`a!-vXiw@=wdKyIi>ps%Z3B);aZro?; zAu2IN{#aAe1MSLSMI?E&LaEa0&zzHPxCHi_wB4e9t6jJ$HJ7J~HXf-A>|6F&4IPJ| zfg6J6U--|u_XKvaIf}U9-C-#aN4(^aTtE@#>B1(}b96VTVCl^fBJWTlhXSnADJMj9 zgb1)Enr|LFDk*Q>rZ?egu-L^0bZ+3u7a=12pb!C4TQgbtGs_R%E_%JKaeV6jSpT_# zp5Efo3*PFfCFhk-QACJJP9_QSmMQr2hALLg#Ae%JsTl_Wi;IOQ%Q_)I#D6a67Y$KM zSiA&_rz20+7E`hD(V?lx>Q#!rD~C}@#HC?L z`Y$P!K{uLCL-ta;UcaZt6_k5+DDxDc@mYPby!s;bZD-Dk_|FM6_&Pk^G~+Y5tgTwwAEcukL$QMhY0Dn@x^_dDG2Wm5&fKz&>sY zN;KCw?Q}8Szw?OC`Y!Tbv^18-l@p_R}Yt0C;%bv7ull_yQ+HD_P?89>msM9! z%0q0wF%Sbt!*^NO)MQbPkhW}UQ7W_vJsW?(!ZHWD!&pyxlO(d5$jsP(TCA!&uN?BFg_ z(3R<>rr8}ec-6X7@+c10Gr09~;lwaM!Gm@y+g(w{NGZf~{xxKso7SgVDlF4LDX0652RCe6yp>#gy zXq#K!?9>}P8Np%m@PPbp<>;NlJsT)B;Q1OW=EUpjZPE^g6Ce@mkM{{v9n6@~Ypa(J zV;XeF96>bTz-nvlpYhpz_ESR8W1&ZE_ox4G)fCi+D0}@td0076+FB zw7<2!SC-A*1I$VjrlpIq4_h(-$ z=>5b`xR1HZ=WR)?XceIUR>z}RyS=M=k$|$`0?1|B*K+|MfT}PDMe(5v0BkMegbYcQ z4z#vtxQ#qO8bwbB_a_J5aW&X6obG{uFG@p|=l6uw6GRO~L+EnMyrv5z1e?-DnX6#WtV8cFpz}j9$%lp>^s=aC~1;9XNelH2ETftx}qDSD5A` z2)Eaxz1)9}erBivaV)@)0NhRwHOcO);;;f_?U<|6-p|^yy5FwFJ?iPyfl;5MU&I7# znY9;N{L#+an?vfbQavUfjrY548>)tjHcgZTc*X{uy=wn~ES^^-zCH4>GL-Dka|6ykdq zzsY6f@O8UeB;ZU~KBU38^2qrD=y{dR?eZ1B88DcdX}eHB^Ez33T3SGaybMeut4 z4E}o@WI{Hiy)i<-DT9;D+K|T#docc$f)BG70-|?bmd->X>F+U4Jjv3WkoCPd~A|?rNs-&K&Vj>(sdPB?(sxZFiaQJZ; rwvH}o-Ug7dDy$A|0HNsq-!gwtj8Pt0e;y)sP}YIoWn)~SHZkx&lGAtg literal 0 HcmV?d00001 diff --git a/star_lock/images/main/icon_lockDetail_monitoringUnTalkback.png b/star_lock/images/main/icon_lockDetail_monitoringUnTalkback.png new file mode 100644 index 0000000000000000000000000000000000000000..e97963ab2623e3f69a45821393f034fede09bd4a GIT binary patch literal 2941 zcmXX|c{J327yiuG3}b8)LWoheEE#)JjIlRmr_e~Ys4S_hFO9ulsZ^Fo8T%47q!=kP zWQnm0m94_alF3pT+dIGaynoz#|9I|s?mg$8bD!rQI~z*@lq3oOAYg4}=D?|>e*?+Q z$t_0by8z%bvokKpj1sf^)!nc^X7hL8=F*qCL7xmgHU$M#c2;J(M0GYlvb9a0jiv_5 z5T9L$l#%#g`nX$kec~=LI8d&aputV!-P|^)T13XoupjFO|5oRVaPg=Mo}4BB%nl2= zK-3$`ULU{f9K5h{8&-dn*>lx|a2tYU2(|7?^-pU&j82czP)+QeGzay=yLl`wlcf9k zE2`D-sye&h^F9YaANv#YWvg`_ra8nr?exA^TP4TtzKh+CGF~U2sgN(>Lx5Gi6o3)N zH$Pfx(WEnb^G4oiVMSr&MQFZLGlABE(v>qv4m}e1`1}_3#x{Gs@+oPL&jEGAxTdIe6}eIKC*nJT zOI*fuKk+TN7s%cFDEf7(3p&D$?45pHNImBCv&LlKsm-;+6>89U`yA>gb7JpJScnU0 z_I`<@0>6@7Fw!$-Zltuuat-&F$Ew~}S3le+r94G9Vn7UMpX4s@082wb0>H`0ZDO=x zh8h(2J>?B5QkL#me~~EG`X@`#nJW!~egJIxit3@G$ltn|z&8p`sI7An`A0Yc#=*|O zP&x|f@k7l+Y;(_ihEJet_#j?=p)^Z$?2E1EA@nJaGL0B6 zspjw+X`V+AR)+vU7@$oGgU}~}Ib2wIWYG>Uk5#4z9Rv6gP@QqymudN43Xnj-DUh-J zXG?LGkRRm!pjLAb{t`GVu#K?k5QuDif6`Ohk@_GQ!9!loBm)ecKY)Fa7X|R(e+32D zND~;27dMGf1`(i735fzv!5ShS!tnt%FoBU305OFOJOM6CP8mqR`kXl($>7?ac!;D4 z7=rjGUztANOIJkf!^QT3^w0O@gL#4R9sv$)R@kY-4a^eAfb8^Kp1KFvb7olSRGjoi z;zBqqCuUAOkm5p%{=XFlkldVA%FkM_-~c?1vul5u)+rod$fZHpQ6l}sxW)t1vNwPG zrJIIh+ZeWF()9=?RO?ngUCVQ`I&95Iy18D_jhM| zv--u!-iwJPfb}i;wz!5-P+~|P^`IPyxHJD#>7M=dT53NJaN2^ancv$^Lmp)9_;|pNtPjG=j|99<0rcxL&hml2 z{-5{tj8{26BBtP!32u+XDNt4L2~8L-U+u~bWq(9>+g0JX!Y(v%akz+x&d z7@%TJ%Lxez0pGdwy;sBbLg||sYm&J=FkHo+qwC=Tb52RV<&q3h{HMyD!b@nY?j|Xp zSe!RIfTUb4*{!1}h7(b<7U{E>${6IGEj_bMjK>Wwxl%K$0Gfvo|Go zI&k`=TpwdQk~gz;?L|ddHiBiJX8YGE@Y4N@LkFMm!ri(`vMmVnJ}8o2ydG-qdgoM9`7Rq77ms8&*te+0`<+vZYwJC4@Rx4@fprv8rHwS= z%ir8NICk@^c0ra7IzTd*Kn7D1S9hb|ZSwV0+@vBxykSe~g&sr`gmlnGQ67!y;#eN9 z@S_o97qRQ~PQ*GcTM-GKy5MFG1iADrk>w%^qW@C_Ig~h>Vir3Yn>(IFT!yAfiL30H z#$==C>&0C*WcQ99{dXh>W|RDBQ%a>2MP_4!ApIU1!k{NBo!@#pyV|@+QwpA!RHC3% zkh!I+wLz)jaz7Ir1vQjG&iLEwDpi=WmFallu_kYxmJZj)_5%DKI&Vj7=f&>-u8zgF z80vfd)C)6;dw8n29t!s|m@(|GMIcDBLpFR>>L%{dPgfy_FAcx8rvU39y1=iPRpfE@ zL&8S1kA1&hUQ3G;WX=TCcwMCJwf%z+ZVj-BB-d`r$4kpB7R&r3>R<8q{3on9<%rFp$DOXC6+s^WHkl+S9krjz zymw*tz0!T%`0G`%T$58hMfYdNwFeYaFo%F3w7kFR!XeuJ{MqVjLGa@&BEFbsPy6^X z{?l4dfAQt~HNWbI_%vz219Kme+1VdT%)|AaV5ka!yGg~Q2h<=+L|XD;FO{gvea*$L z@(CC|APskF)}c4wak9=IREWb!0cB#HN?X7;3;%!%IXA8$Yap`2tyM`ID4aK2%Ts*Y z)Pb%BD|6+td1*!$md{wS%kj^|xC0emYD<1CcX`;~zoDxS40GN1g9>qJ$3e#0`0Rsm zK@v;YcRHuFQgWli8nc?cuUdFQ;a4j4x^ynutL9q0h0bhIeYf?@V@EM6+Gf|*fUv?he3rB=ao$y3)bB|<21XI{%34(g*Ic8yeKmjtvbxJv6f{&G jPpA with WidgetsBindingObserver, BaseWidget { initAliyunPush(); - // playLocalAudio(); - // Uint8List uint8List = Uint8List.fromList([]); // CallTalk talkClass = CallTalk(); // talkClass.getAVData(uint8List, 90); @@ -192,9 +190,3 @@ Future _setCommonServices() async { // Get.log(PlatformInfoService.to.info.version); } -//播放本地音频 -void playLocalAudio() async { - final audioPlayer = AudioPlayer(); - audioPlayer.setReleaseMode(ReleaseMode.loop); - await audioPlayer.play(AssetSource('ring1.mp3')); -} diff --git a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_logic.dart b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_logic.dart index 8efa1e76..208c134e 100644 --- a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_logic.dart +++ b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_logic.dart @@ -17,6 +17,15 @@ class LockMonitoringLogic extends BaseGetXController { }); } + /// 收到接听状态 + StreamSubscription? _getUDPStatusRefreshUIEvent; + void _getUDPStatusRefreshUIAction() { + // 蓝牙协议通知传输跟蓝牙之外的数据传输类不一样 eventBus + _getTVDataRefreshUIEvent = eventBus.on().listen((event) { + state.udpStatus.value = event.udpStatus; + }); + } + @override void onReady() { // TODO: implement onReady @@ -24,6 +33,7 @@ class LockMonitoringLogic extends BaseGetXController { print("onReady()"); _getTVDataRefreshUIAction(); + _getUDPStatusRefreshUIAction(); } @override @@ -38,6 +48,7 @@ class LockMonitoringLogic extends BaseGetXController { // TODO: implement onClose print("锁详情界面销毁了"); _getTVDataRefreshUIEvent!.cancel(); + _getUDPStatusRefreshUIEvent!.cancel(); } } \ No newline at end of file diff --git a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart index 4bb5d31c..e26d8869 100644 --- a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart +++ b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart @@ -2,9 +2,15 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; +import 'package:network_info_plus/network_info_plus.dart'; import '../../../../appRouters.dart'; import '../../../../app_settings/app_colors.dart'; +import '../../../../talk/udp/udp_manage.dart'; +import '../../../../talk/udp/udp_senderManage.dart'; +import '../../../../tools/showTFView.dart'; +import '../../../../tools/storage.dart'; +import '../../../../tools/toast.dart'; import 'lockMonitoring_logic.dart'; class LockMonitoringPage extends StatefulWidget { @@ -142,19 +148,97 @@ class _LockMonitoringPageState extends State { } Widget bottomBottomBtnWidget() { - return Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ - bottomBtnItemWidget("images/main/icon_lockDetail_monitoringTalkback.png", - "点击对讲", Colors.white, () {}), - bottomBtnItemWidget("images/main/icon_lockDetail_monitoringUnlock.png", - "长按开锁", AppColors.mainColor, () {}) + return Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Obx(() => bottomBtnItemWidget(getAnswerBtnImg(), getAnswerBtnName(), Colors.white, () async { + var userMobileIP = await NetworkInfo().getWifiIP(); + var userMobile = await Storage.getMobile(); + + // 刚进来是接听状态,然后改为长按对讲 + UDPSenderManage.sendMainProtocol( + command: 150, + commandTypeIsCalling: 1, + subCommand: 6, + lockID: UDPManage().lockId, + lockIP: UDPManage().host, + userMobile: userMobile, + userMobileIP: userMobileIP, + endData: []); + })), + bottomBtnItemWidget("images/main/icon_lockDetail_hangUp.png", "挂断", Colors.red, () async { + var userMobileIP = await NetworkInfo().getWifiIP(); + var userMobile = await Storage.getMobile(); + + // 挂断 + UDPSenderManage.sendMainProtocol( + command: 150, + commandTypeIsCalling: 1, + subCommand: 30, + lockID: UDPManage().lockId, + lockIP: UDPManage().host, + userMobile: userMobile, + userMobileIP: userMobileIP, + endData: []); + }), + bottomBtnItemWidget("images/main/icon_lockDetail_monitoringUnlock.png", "开锁", AppColors.mainColor, () { + showDeletPasswordAlertDialog(context); + }) + ]); } + String getAnswerBtnImg(){ + switch (state.udpStatus.value) { + case 8: + { + return "images/main/icon_lockDetail_monitoringUnTalkback.png"; + } + case 9: + { + return "images/main/icon_lockDetail_monitoringTalkback.png"; + } + default: + { + return "images/main/icon_lockDetail_monitoringAnswerCalls.png"; + } + } + } + + String getAnswerBtnName(){ + switch (state.udpStatus.value) { + case 8: + { + return "长按说话"; + } + case 9: + { + return "松开发送"; + } + default: + { + return "接听"; + } + } + } + Widget bottomBtnItemWidget( String iconUrl, String name, Color backgroundColor, Function() onClick) { var wh = 80.w; return GestureDetector( onTap: onClick, + onLongPress: (){ + print("onLongPress"); + if(state.udpStatus.value == 8){ + state.udpStatus.value = 9; + } + }, + onLongPressUp: () { + print("onLongPressUp"); + if(state.udpStatus.value == 9){ + state.udpStatus.value = 8; + } + }, child: SizedBox( height: 140.h, child: Column( @@ -178,4 +262,43 @@ class _LockMonitoringPageState extends State { )), ); } + + void showDeletPasswordAlertDialog(BuildContext context) { + showDialog( + barrierDismissible:false, + context: context, + builder: (BuildContext context) { + return ShowTFView( + title: "请输入开锁密码", + tipTitle: "", + controller: state.passwordTF, + sureClick: () async { + //发送删除锁请求 + if (state.passwordTF.text.isEmpty) { + Toast.show(msg: "请输入开锁密码"); + return; + } + + var userMobileIP = await NetworkInfo().getWifiIP(); + var userMobile = await Storage.getMobile(); + + // 开锁 + UDPSenderManage.sendMainProtocol( + command: 150, + commandTypeIsCalling: 1, + subCommand: 10, + lockID: UDPManage().lockId, + lockIP: UDPManage().host, + userMobile: userMobile, + userMobileIP: userMobileIP, + endData: []); + Get.back(); + }, + cancelClick: () { + Get.back(); + }, + ); + }, + ); + } } diff --git a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_state.dart b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_state.dart index ed1135ca..71390d4b 100644 --- a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_state.dart +++ b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_state.dart @@ -1,10 +1,13 @@ import 'dart:typed_data'; +import 'package:flutter/material.dart'; import 'package:get/get.dart'; class LockMonitoringState { - var isOpenVoice = false.obs; + var isOpenVoice = false.obs; + var udpStatus = 0.obs; //0:初始状态 1:等待监视 2: 3:监视中 4:呼叫成功 5:主角通话中 6:被叫通话 8:被叫通话中 9:长按说话 + var passwordTF = TextEditingController(); var listData = [].obs; Uint8List imageData = Uint8List.fromList([ diff --git a/star_lock/lib/talk/call/callTalk.dart b/star_lock/lib/talk/call/callTalk.dart index 2801f857..0453e373 100644 --- a/star_lock/lib/talk/call/callTalk.dart +++ b/star_lock/lib/talk/call/callTalk.dart @@ -57,6 +57,7 @@ class CallTalk { // 用你的711音频数据替换这里的Uint8List Uint8List rawData = G711Decoder().decodeG711uLaw(bb); _playRawData(rawData); + print('收到音频数据了'); } // 视频数据 else { diff --git a/star_lock/lib/talk/udp/io_protocol/udp_mainProtocol.dart b/star_lock/lib/talk/udp/io_protocol/udp_mainProtocol.dart index 8fb2fada..add59504 100644 --- a/star_lock/lib/talk/udp/io_protocol/udp_mainProtocol.dart +++ b/star_lock/lib/talk/udp/io_protocol/udp_mainProtocol.dart @@ -16,7 +16,7 @@ class UDPMainProtocolCommand extends UDPSenderProtocol { String? lockIP; String? userMobile; String? userMobileIP; - List? data; + List? endData; UDPMainProtocolCommand({ this.command, @@ -26,7 +26,7 @@ class UDPMainProtocolCommand extends UDPSenderProtocol { this.lockIP, this.userMobile, this.userMobileIP, - this.data, + this.endData, }) : super(CommandUDPType.heart); @override diff --git a/star_lock/lib/talk/udp/udp_help.dart b/star_lock/lib/talk/udp/udp_help.dart index c6bea328..619c3c21 100644 --- a/star_lock/lib/talk/udp/udp_help.dart +++ b/star_lock/lib/talk/udp/udp_help.dart @@ -12,36 +12,39 @@ import 'udp_senderManage.dart'; class UdpHelp{ + Timer? timer; openUDP() async { // 从服务器获取ip跟端口 var entity = await ApiRepository.to.getWifiLockServiceIpAndPort(); if(entity.errorCode! == 0){ UDPManage(); // UDPManage().initUdp(); - // UDPManage().host = entity.data!.serviceList![0].serviceIp!; - // UDPManage().port = int.parse(entity.data!.serviceList![0].port!); + UDPManage().port = int.parse(entity.data!.serviceList![0].port!); var serversList = []; for(int i = 0; i addresses = await InternetAddress.lookup(item.serviceIp!); + UDPManage().host = addresses.first.address; var itemList = addresses.first.address.split("."); for (var element in itemList) { serversList.add(int.parse(element)); } - print('Resolved google.com to address: ${addresses.first.address} serversList:${serversList}'); + print('Resolved google.com to address: ${addresses.first.address} serversList:$serversList'); } } - Timer timer = Timer.periodic(1.seconds, (timer) async { + var mobile = await Storage.getMobile(); + timer = Timer.periodic(1.seconds, (timer) async { UDPSenderManage.sendHeart( - userName: await Storage.getMobile(), + userName: mobile, ipList: serversList, tokenStr: "b989fa15f75c2ac02718b7c9bb64f80e", ); @@ -49,11 +52,15 @@ class UdpHelp{ } } - Future getWifiLockServiceIpAndPort() async { - var entity = await ApiRepository.to.getWifiLockServiceIpAndPort(); - if(entity.errorCode! == 0){ + // Future getWifiLockServiceIpAndPort() async { + // var entity = await ApiRepository.to.getWifiLockServiceIpAndPort(); + // if(entity.errorCode! == 0){ + // + // } + // } - } + dispose(){ + timer!.cancel(); } } diff --git a/star_lock/lib/talk/udp/udp_manage.dart b/star_lock/lib/talk/udp/udp_manage.dart index 573dedfd..98d27c9f 100644 --- a/star_lock/lib/talk/udp/udp_manage.dart +++ b/star_lock/lib/talk/udp/udp_manage.dart @@ -1,5 +1,4 @@ - import 'dart:async'; import 'dart:io'; @@ -31,16 +30,18 @@ class UDPManage{ StreamSubscription? _streamSubscription; RawDatagramSocket? _udpSocket; - String host = '47.106.143.213'; - int port = 8056; + // String host = '47.106.143.213'; + // int port = 8056; // String? _mIp = ''; - // String host = ''; - // int port = 0; + String host = ''; + int port = 0; + String lockId = '';// 锁id 通过锁id来判断是哪把锁发对讲过来 void initUdp() async { var listAddress = InternetAddress.lookup(host!); listAddress.then((list) { list.forEach((element) { + // print('Udp ----> element.address:${element.address} element.host:${element.host}'); host = element.address; }); }); @@ -52,6 +53,7 @@ class UDPManage{ print('❌ Udp ----> _port == 0'); return; } + print('Udp ----> host:$host port:$port'); var addressIListenFrom = InternetAddress.anyIPv4; int portIListenOn = 62288; RawDatagramSocket.bind(addressIListenFrom, portIListenOn).then((RawDatagramSocket socket){ diff --git a/star_lock/lib/talk/udp/udp_reciverData.dart b/star_lock/lib/talk/udp/udp_reciverData.dart index 129cbb48..4b850c74 100644 --- a/star_lock/lib/talk/udp/udp_reciverData.dart +++ b/star_lock/lib/talk/udp/udp_reciverData.dart @@ -1,5 +1,10 @@ import 'dart:typed_data'; +import 'package:get/get.dart'; +import 'package:star_lock/talk/udp/udp_manage.dart'; + +import '../../blue/io_tool/io_tool.dart'; +import '../../tools/eventBusEventManage.dart'; import '../../tools/toast.dart'; import '../call/callTalk.dart'; import 'udp_talkClass.dart'; @@ -14,7 +19,7 @@ class CommandUDPReciverManager { if (dataSize < 4) { return; } - print("appDataReceiveUDPData:$data"); + // print("appReceiveUDPData:$data"); Uint8List data1 = Uint8List.fromList(data); if (data1.length == 1) { @@ -26,6 +31,7 @@ class CommandUDPReciverManager { if (data[6] == 4) { if (data[7] == 2) { // print("心跳包反馈 在线状态"); + } else if (data[7] == 3) { [Toast.show(msg: "您已在其他设备登录")]; } @@ -42,6 +48,11 @@ class CommandUDPReciverManager { case 1: { //被叫 + // lockId + var lockId = data.sublist(9, 29); + var lockIdStr = utf8String(lockId); + UDPManage().lockId = lockIdStr; + UDPTalkClass().beCallW(data: data); } break; @@ -51,6 +62,10 @@ class CommandUDPReciverManager { if ((data[7] & 0x3) == 2) { //被叫 接听反馈 print("接听反馈"); + UDPTalkClass().status = 8; + // 停止声音 + UDPTalkClass().stopLocalAudio(); + eventBus.fire(GetUDPStatusRefreshUI(UDPTalkClass().status)); } } break; @@ -77,21 +92,29 @@ class CommandUDPReciverManager { case 10: { //开门反馈 + print("appReceiveUDPData:$data"); if ((data[7] & 0x3) == 2) { print("开门成功"); - } else {} + Toast.show(msg: "开门成功"); + } else { + print("开门失败"); + } } break; case 30: { - //开门反馈 + // 挂断 if ((data[7] & 0x3) == 1) { - //对方结束对讲 + // 对方结束对讲 print("对方结束对讲"); } else { //结束对讲反馈 print("结束对讲反馈"); } + UDPTalkClass().status = 0; + Get.back(); + UDPTalkClass().stopLocalAudio(); + eventBus.fire(GetUDPStatusRefreshUI(UDPTalkClass().status)); } break; case 140: diff --git a/star_lock/lib/talk/udp/udp_senderManage.dart b/star_lock/lib/talk/udp/udp_senderManage.dart index 4b15d39d..5899a888 100644 --- a/star_lock/lib/talk/udp/udp_senderManage.dart +++ b/star_lock/lib/talk/udp/udp_senderManage.dart @@ -24,7 +24,7 @@ class UDPSenderManage { String? lockIP, String? userMobile, String? userMobileIP, - List? data, + List? endData, CommandUDPSendCallBack? callBack}) { CommandUDPSenderManager().managerSendData(command: UDPMainProtocolCommand( command: command, @@ -34,7 +34,7 @@ class UDPSenderManage { lockIP: lockIP, userMobile: userMobile, userMobileIP: userMobileIP, - data: data, + endData: endData, ), callBack: callBack); } diff --git a/star_lock/lib/talk/udp/udp_talkClass.dart b/star_lock/lib/talk/udp/udp_talkClass.dart index 05d0739b..737eef48 100644 --- a/star_lock/lib/talk/udp/udp_talkClass.dart +++ b/star_lock/lib/talk/udp/udp_talkClass.dart @@ -1,6 +1,7 @@ import 'dart:async'; +import 'package:audioplayers/audioplayers.dart'; import 'package:fast_gbk/fast_gbk.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; @@ -21,11 +22,12 @@ class UDPTalkClass{ UDPTalkClass._init(); - var status = 0;// 0空闲 + var status = 0; //0:初始状态 1:等待监视 2: 3:监视中 4:呼叫成功 5:主角通话中 6:被叫通话 8:被叫通话中 var remoteEquid;// 手机号 late Timer timer; // 该字段是为了判断是否跳转到接听界面 挂断或者退出接听界面要记得变更状态 var isBeCall = false; + final audioPlayer = AudioPlayer(); beCallW({List? data, String? ip, int? port}) async { // print("beCall"); @@ -70,6 +72,7 @@ class UDPTalkClass{ Get.toNamed(Routers.lockMonitoringPage, arguments: { "lockId": "111" }); + playLocalAudio(); }else{ // 忙 @@ -111,4 +114,16 @@ class UDPTalkClass{ return equid; } + + //播放本地音频 + void playLocalAudio() async { + audioPlayer.setReleaseMode(ReleaseMode.loop); + await audioPlayer.play(AssetSource('ring1.mp3')); + } + + // 停止播放本地音频 + void stopLocalAudio() async { + audioPlayer.setReleaseMode(ReleaseMode.loop); + await audioPlayer.stop(); + } } \ No newline at end of file diff --git a/star_lock/lib/tools/eventBusEventManage.dart b/star_lock/lib/tools/eventBusEventManage.dart index 7958e493..25a8d62e 100644 --- a/star_lock/lib/tools/eventBusEventManage.dart +++ b/star_lock/lib/tools/eventBusEventManage.dart @@ -60,4 +60,10 @@ class LockSetChangeSetRefreshLockDetailWithType{ class GetTVDataRefreshUI{ List tvList; GetTVDataRefreshUI(this.tvList); +} + +/// 获取到UDP接收状态然后刷新界面 +class GetUDPStatusRefreshUI{ + int udpStatus; + GetUDPStatusRefreshUI(this.udpStatus); } \ No newline at end of file diff --git a/star_lock/lib/tools/storage.dart b/star_lock/lib/tools/storage.dart index 7a1b0d38..6de0fe52 100644 --- a/star_lock/lib/tools/storage.dart +++ b/star_lock/lib/tools/storage.dart @@ -141,7 +141,7 @@ class Storage { if (data != null && data.isNotEmpty) { uid = LoginData.fromJson(jsonDecode(data)).uid.toString(); } - print("pubUid:$uid"); + // print("pubUid:$uid"); return uid; } @@ -151,7 +151,7 @@ class Storage { if (data != null && data.isNotEmpty) { mobile = LoginData.fromJson(jsonDecode(data)).mobile.toString(); } - print("pubUserId:$mobile"); + // print("mobile:$mobile"); return mobile; } From 21d7902b7f8f82f9a090e1eabab79d5f49cdc898 Mon Sep 17 00:00:00 2001 From: Daisy <> Date: Thu, 21 Dec 2023 11:59:10 +0800 Subject: [PATCH 14/33] =?UTF-8?q?=E4=BF=AE=E6=94=B9G711=E8=A7=A3=E7=A0=81?= =?UTF-8?q?=E6=96=B9=E5=BC=8F=20=E6=96=B0=E5=A2=9EG711=E7=BC=96=E7=A0=81?= =?UTF-8?q?=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- star_lock/lib/talk/call/callTalk.dart | 23 ++++----- star_lock/lib/talk/call/g711Decoder.dart | 66 +++++++++++------------- star_lock/lib/talk/call/g711Encode.dart | 36 +++++++++++++ 3 files changed, 75 insertions(+), 50 deletions(-) create mode 100644 star_lock/lib/talk/call/g711Encode.dart diff --git a/star_lock/lib/talk/call/callTalk.dart b/star_lock/lib/talk/call/callTalk.dart index 7d62b819..d3418720 100644 --- a/star_lock/lib/talk/call/callTalk.dart +++ b/star_lock/lib/talk/call/callTalk.dart @@ -41,22 +41,19 @@ class CallTalk { CallTalk get manager => _share(); Future getAVData(Uint8List bb, int len) async { - //视频数据 - // String hexData = - // '5858584349449601075439415f396333613730323264346364a5a5a5a5c0a809a3503138363832313530323337000000000000000030303030420e000002000000b33300001f000100b301b301ffd8ffe000114a4649460001010000'; - // Uint8List bb = Uint8List.fromList(hex.decode(hexData)); - //音频数据 - // String hexData = - // '5858584349449601075439415f396333613730323264346364a5a5a5a5c0a809a3503138363832313530323337000000000000000030303030e02900000100050080020000010001004001b30145444444444444444445454444444444444444444444434343434443434344444444444544454545444444444444454545454545454545454445444545454545454545444444444343434344444443434344444444444343434343434343434443434343434343424343434343434242424242424242424243434343434242424242424343434342424343434242424242434243434343434344454344444444444444444444444444454545454544444444444444444445454545454545454545454545454546454545454545454545454545454545454646464646464645454545464646454545454545454545454545454544444444444444444443434343434343434343434343434343434343434242424242424242424242424242424343434242434343434343434343434343434343434343434444444343434343430000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024001d044000000000001d080001000000001d18c03000000000'; - // Uint8List bb = Uint8List.fromList(hex.decode(hexData)); - // 音频数据 if (bb[61] == 1) { - print('dinglingling音频数据来啦啦啦啦啦啦啦啦啦'); + print('dinglingling音频数据来啦啦啦啦啦啦啦啦啦$bb'); // 用你的711音频数据替换这里的Uint8List - Uint8List rawData = G711Decoder().decodeG711uLaw(bb); - _playRawData(rawData); - print('收到音频数据了'); + // Uint8List rawData = G711Decoder().decodeG711uLaw(bb); + // 示例 G711 数据(u-law 或 a-law) + Uint8List g711Data = bb; + // 解码为 PCM 数据 + Uint8List pcmData = G711Decoder().g711Decode(g711Data, G711Type.uLaw); + // 现在你可以使用 pcmData 进行播放或其他处理 + print('得到的pcmData:$pcmData'); + + _playRawData(pcmData); } // 视频数据 else { diff --git a/star_lock/lib/talk/call/g711Decoder.dart b/star_lock/lib/talk/call/g711Decoder.dart index 94d665a3..2b1d5c74 100644 --- a/star_lock/lib/talk/call/g711Decoder.dart +++ b/star_lock/lib/talk/call/g711Decoder.dart @@ -1,44 +1,36 @@ import 'dart:typed_data'; -class G711Decoder { - // G.711 µ-law解码 - Uint8List decodeG711uLaw(Uint8List data) { - List decodedData = []; +enum G711Type { + uLaw, + aLaw, +} - for (int i = 0; i < data.length; i++) { - int sample = _decodeG711uLawSample(data[i]); - decodedData.add(sample); +class G711Decoder { + Uint8List g711Decode(Uint8List g711Data, G711Type g711Type) { + List pcmData = []; + int sign, exponent, mantissa, sample; + + for (int i = 0; i < g711Data.length; i++) { + int value = g711Data[i]; + + if (g711Type == G711Type.uLaw) { + // μ-law decoding + value = ~value & 0xFF; + sign = (value & 0x80) == 0 ? 1 : -1; + exponent = (value & 0x70) >> 4; + mantissa = ((value & 0x0F) << 4) + 0x10; + sample = (mantissa << exponent) * sign; + } else { + // A-law decoding + sign = (value & 0x80) == 0 ? 1 : -1; + exponent = ((value & 0x70) >> 4) + 1; + mantissa = (value & 0x0F) + 0x10; + sample = (mantissa << exponent) * sign; + } + + pcmData.add(sample); } - return Uint8List.fromList(decodedData); - } - - // G.711 µ-law样本解码 - int _decodeG711uLawSample(int uLawByte) { - const int bias = 0x84; - const int mask = 0x7F; - - uLawByte = ~uLawByte; - int sign = uLawByte & 0x80; - int exponent = (uLawByte & 0x70) >> 4; - int mantissa = uLawByte & 0x0F; - - int sample = ((bias << exponent) + mantissa) * (sign == 0 ? 1 : -1); - - return sample & mask; // 防止溢出 + return Uint8List.fromList(pcmData); } } - -void main() { - G711Decoder g711Decoder = G711Decoder(); - - // 假设 g711Data 是G.711 µ-law编码的数据 - Uint8List g711Data = - Uint8List.fromList([/* your G.711 µ-law encoded data */]); - - // 解码 - List decodedData = g711Decoder.decodeG711uLaw(g711Data); - - // 处理解码后的数据,例如播放音频 - print(decodedData); -} diff --git a/star_lock/lib/talk/call/g711Encode.dart b/star_lock/lib/talk/call/g711Encode.dart new file mode 100644 index 00000000..5369a366 --- /dev/null +++ b/star_lock/lib/talk/call/g711Encode.dart @@ -0,0 +1,36 @@ +import 'dart:typed_data'; + +enum G711Type { + uLaw, + aLaw, +} + +class G711Decoder { + Uint8List g711Encode(Uint8List pcmData, G711Type g711Type) { + List g711Data = []; + + for (int sample in pcmData) { + int sign = (sample < 0) ? 0x80 : 0; + int magnitude = (sample < 0) ? -sample : sample; + + int exponent = 7; + while (magnitude < (1 << exponent) && exponent > 0) { + exponent--; + } + + int mantissa = (magnitude >> (exponent - 4)) & 0x0F; + + if (g711Type == G711Type.uLaw) { + // μ-law encoding + int value = ~(sign | ((exponent << 4) & 0x70) | (mantissa >> 4)); + g711Data.add(value & 0xFF); + } else { + // A-law encoding + int value = sign | ((exponent << 4) & 0x70) | (mantissa >> 4); + g711Data.add(value & 0xFF); + } + } + + return Uint8List.fromList(g711Data); + } +} From 81488b599ee0d81649bd77d8dae5b2f0084cc577 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AD=8F=E5=B0=91=E9=98=B3?= <786612630@qq.com> Date: Thu, 21 Dec 2023 13:56:48 +0800 Subject: [PATCH 15/33] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=AF=B9=E8=AE=B2?= =?UTF-8?q?=E6=8E=A5=E6=94=B6=E8=A7=86=E9=A2=91bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../monitoring/lockMonitoring_logic.dart | 2 +- .../monitoring/lockMonitoring_page.dart | 13 +++++++++++++ star_lock/lib/talk/call/callTalk.dart | 15 +++++++-------- star_lock/lib/talk/udp/udp_reciverData.dart | 5 +++-- star_lock/lib/talk/udp/udp_talkClass.dart | 14 ++++++++------ star_lock/lib/tools/showTFView.dart | 4 ++++ 6 files changed, 36 insertions(+), 17 deletions(-) diff --git a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_logic.dart b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_logic.dart index e3fd1723..406bb3bb 100644 --- a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_logic.dart +++ b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_logic.dart @@ -28,7 +28,7 @@ class LockMonitoringLogic extends BaseGetXController { StreamSubscription? _getUDPStatusRefreshUIEvent; void _getUDPStatusRefreshUIAction() { // 蓝牙协议通知传输跟蓝牙之外的数据传输类不一样 eventBus - _getTVDataRefreshUIEvent = eventBus.on().listen((event) { + _getUDPStatusRefreshUIEvent = eventBus.on().listen((event) { state.udpStatus.value = event.udpStatus; }); } diff --git a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart index f9215dd1..16392da6 100644 --- a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart +++ b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart @@ -8,6 +8,7 @@ import 'package:network_info_plus/network_info_plus.dart'; import '../../../../app_settings/app_colors.dart'; import '../../../../talk/udp/udp_manage.dart'; import '../../../../talk/udp/udp_senderManage.dart'; +import '../../../../talk/udp/udp_talkClass.dart'; import '../../../../tools/showTFView.dart'; import '../../../../tools/storage.dart'; import '../../../../tools/toast.dart'; @@ -158,6 +159,7 @@ class _LockMonitoringPageState extends State { Widget bottomBottomBtnWidget() { return Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ + // 接听 Obx(() => bottomBtnItemWidget( getAnswerBtnImg(), getAnswerBtnName(), Colors.white, () async { var userMobileIP = await NetworkInfo().getWifiIP(); @@ -281,6 +283,10 @@ class _LockMonitoringPageState extends State { title: "请输入开锁密码", tipTitle: "", controller: state.passwordTF, + inputFormatters: [ + LengthLimitingTextInputFormatter(6), //限制长度 + FilteringTextInputFormatter.allow(RegExp("[0-9]")), + ], sureClick: () async { //发送删除锁请求 if (state.passwordTF.text.isEmpty) { @@ -311,6 +317,13 @@ class _LockMonitoringPageState extends State { ); } + @override + void dispose() { + super.dispose(); + + // UDPTalkClass().isBeCall = false; + } + //录音处理 _initRecorder() { recorder = FlutterSoundRecorder(); diff --git a/star_lock/lib/talk/call/callTalk.dart b/star_lock/lib/talk/call/callTalk.dart index 7d62b819..26224eee 100644 --- a/star_lock/lib/talk/call/callTalk.dart +++ b/star_lock/lib/talk/call/callTalk.dart @@ -67,7 +67,8 @@ class CallTalk { // 获取帧序号 63 int getIframeIndex = bb[POS_iframe_index] + bb[POS_iframe_index + 1] * 256; - print('获取帧序号 getIframeIndex:$getIframeIndex'); + // print('获取帧序号 getIframeIndex:$getIframeIndex'); + // 获取帧长度 65 // int alen = bb[POS_alen] & 0xff; // var alenList = bb.sublist(POS_alen, POS_alen + 4); @@ -79,13 +80,13 @@ class CallTalk { // 当前包号 71 int getBagIndex = bb[POS_bag_index] & 0xff; - print('当前包号 getBagIndex:$getBagIndex'); + // print('当前包号 getBagIndex:$getBagIndex'); // 总包数 69 int getBagNum = bb[POS_bag_num] & 0xff; - print('总包数 getBagNum:$getBagNum'); + // print('总包数 getBagNum:$getBagNum'); // 数据长度 73 int blen = bb[POS_blen] + bb[POS_blen + 1] * 256; - print('数据长度 blen:$blen'); + // print('数据长度 blen:$blen'); // 这里判断是否是同一帧,如果不是同一帧就重新创建一个 IframeInfo if (getIframeIndex != iframe!.iframeIndex) { @@ -104,13 +105,11 @@ class CallTalk { var getList = bb.sublist(77, bb.length); growableList.addAll(getList); } - print( - 'iframe.bagNum: ${iframe!.bagNum} iframe.bagReceive: ${iframe!.bagReceive}'); + // print('iframe.bagNum: ${iframe!.bagNum} iframe.bagReceive: ${iframe!.bagReceive}'); // 如果收到的包数等于总包数,说明这一帧数据已经接收完毕 if (iframe!.bagNum == iframe!.bagReceive) { - print( - '播放第${iframe!.iframeIndex}帧 一帧图片的hexStringData: ${Uint8List.fromList(growableList)}'); + // print('播放第${iframe!.iframeIndex}帧 一帧图片的hexStringData: ${Uint8List.fromList(growableList)}'); //判断第一帧是否接收到 if (iframe!.iframeIndex == 0) { diff --git a/star_lock/lib/talk/udp/udp_reciverData.dart b/star_lock/lib/talk/udp/udp_reciverData.dart index 4b850c74..3ad96b76 100644 --- a/star_lock/lib/talk/udp/udp_reciverData.dart +++ b/star_lock/lib/talk/udp/udp_reciverData.dart @@ -19,7 +19,7 @@ class CommandUDPReciverManager { if (dataSize < 4) { return; } - // print("appReceiveUDPData:$data"); + print("appReceiveUDPData:$data"); Uint8List data1 = Uint8List.fromList(data); if (data1.length == 1) { @@ -52,7 +52,7 @@ class CommandUDPReciverManager { var lockId = data.sublist(9, 29); var lockIdStr = utf8String(lockId); UDPManage().lockId = lockIdStr; - + UDPTalkClass().status = 0; UDPTalkClass().beCallW(data: data); } break; @@ -112,6 +112,7 @@ class CommandUDPReciverManager { print("结束对讲反馈"); } UDPTalkClass().status = 0; + UDPTalkClass().isBeCall = false; Get.back(); UDPTalkClass().stopLocalAudio(); eventBus.fire(GetUDPStatusRefreshUI(UDPTalkClass().status)); diff --git a/star_lock/lib/talk/udp/udp_talkClass.dart b/star_lock/lib/talk/udp/udp_talkClass.dart index 039a89c3..7cb332e4 100644 --- a/star_lock/lib/talk/udp/udp_talkClass.dart +++ b/star_lock/lib/talk/udp/udp_talkClass.dart @@ -23,7 +23,9 @@ class UDPTalkClass { UDPTalkClass._init(); - var status = 0; //0:初始状态 1:等待监视 2: 3:监视中 4:呼叫成功 5:主角通话中 6:被叫通话 8:被叫通话中 + // var status = 0; //0:初始状态 1:等待监视 2: 3:监视中 4:呼叫成功 5:主角通话中 6:被叫通话 8:被叫通话中 + int status = 0; + var remoteEquid; // 手机号 late Timer timer; // 该字段是为了判断是否跳转到接听界面 挂断或者退出接听界面要记得变更状态 @@ -31,7 +33,7 @@ class UDPTalkClass { final audioPlayer = AudioPlayer(); beCallW({List? data, String? ip, int? port}) async { - // print("beCall"); + print("beCall status:$status"); // if (await isCallMe(data)) { // return; // } @@ -60,8 +62,8 @@ class UDPTalkClass { // fullscreenDialog: true // )); - if (UDPTalkClass().isBeCall == false) { - UDPTalkClass().isBeCall = true; + if (isBeCall == false) { + isBeCall = true; // 保持连接 timer = Timer.periodic(1.seconds, (timer) { data[7] = 1; @@ -70,10 +72,10 @@ class UDPTalkClass { }); // _getFirstFrameGoPushAction(); - Future.delayed(const Duration(seconds: 1), () { + // Future.delayed(const Duration(seconds: 1), () { // 在这里写要延迟执行的代码 Get.toNamed(Routers.lockMonitoringPage, arguments: {"lockId": "111"}); - }); + // }); } playLocalAudio(); diff --git a/star_lock/lib/tools/showTFView.dart b/star_lock/lib/tools/showTFView.dart index c5827ae9..e9dc6ea2 100644 --- a/star_lock/lib/tools/showTFView.dart +++ b/star_lock/lib/tools/showTFView.dart @@ -1,5 +1,6 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; @@ -9,6 +10,7 @@ class ShowTFView extends StatelessWidget { String? title; String? tipTitle; TextEditingController? controller; + List? inputFormatters; Function()? sureClick; Function()? cancelClick; @@ -17,6 +19,7 @@ class ShowTFView extends StatelessWidget { this.title, this.tipTitle, this.controller, + this.inputFormatters, this.sureClick, this.cancelClick}) : super(key: key); @@ -44,6 +47,7 @@ class ShowTFView extends StatelessWidget { maxLines: 1, controller: controller, autofocus: false, + inputFormatters: inputFormatters, decoration: InputDecoration( contentPadding: const EdgeInsets.only(left: 5, top: -8, bottom: 6), From 535d274c6e32ef9280eeee0e2adf303ad4eccc8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AD=8F=E5=B0=91=E9=98=B3?= <786612630@qq.com> Date: Thu, 21 Dec 2023 16:48:07 +0800 Subject: [PATCH 16/33] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=AF=B9=E8=AE=B2?= =?UTF-8?q?=E8=AF=AD=E9=9F=B3=E5=8F=91=E9=80=81=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../android/app/src/main/AndroidManifest.xml | 4 + .../monitoring/lockMonitoring_logic.dart | 25 ++++ .../monitoring/lockMonitoring_page.dart | 135 +++++++++++++----- star_lock/lib/talk/call/callTalk.dart | 5 +- star_lock/lib/talk/udp/udp_reciverData.dart | 4 +- 5 files changed, 135 insertions(+), 38 deletions(-) diff --git a/star_lock/android/app/src/main/AndroidManifest.xml b/star_lock/android/app/src/main/AndroidManifest.xml index 62715a64..946195ed 100644 --- a/star_lock/android/app/src/main/AndroidManifest.xml +++ b/star_lock/android/app/src/main/AndroidManifest.xml @@ -39,6 +39,10 @@ + + + + getPermissionStatus() async { + Permission permission = Permission.microphone; + //granted 通过,denied 被拒绝,permanentlyDenied 拒绝且不在提示 + PermissionStatus status = await permission.status; + if (status.isGranted) { + return true; + } else if (status.isDenied) { + requestPermission(permission); + } else if (status.isPermanentlyDenied) { + openAppSettings(); + } else if (status.isRestricted) { + requestPermission(permission); + } else {} + return false; + } + + ///申请权限 + void requestPermission(Permission permission) async { + PermissionStatus status = await permission.request(); + if (status.isPermanentlyDenied) { + openAppSettings(); + } + } + @override void onReady() { // TODO: implement onReady diff --git a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart index 16392da6..303323ad 100644 --- a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart +++ b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart @@ -1,9 +1,12 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_sound/flutter_sound.dart'; import 'package:get/get.dart'; import 'package:network_info_plus/network_info_plus.dart'; +import 'package:path_provider/path_provider.dart'; import '../../../../app_settings/app_colors.dart'; import '../../../../talk/udp/udp_manage.dart'; @@ -160,22 +163,48 @@ class _LockMonitoringPageState extends State { Widget bottomBottomBtnWidget() { return Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ // 接听 - Obx(() => bottomBtnItemWidget( - getAnswerBtnImg(), getAnswerBtnName(), Colors.white, () async { - var userMobileIP = await NetworkInfo().getWifiIP(); - var userMobile = await Storage.getMobile(); + Obx(() => bottomBtnItemWidget(getAnswerBtnImg(), getAnswerBtnName(), Colors.white, () async { + //获取麦克风权限 + await logic.getPermissionStatus().then((value) async { + if (!value) { + return; + } + var userMobileIP = await NetworkInfo().getWifiIP(); + var userMobile = await Storage.getMobile(); - // 刚进来是接听状态,然后改为长按对讲 - UDPSenderManage.sendMainProtocol( - command: 150, - commandTypeIsCalling: 1, - subCommand: 6, - lockID: UDPManage().lockId, - lockIP: UDPManage().host, - userMobile: userMobile, - userMobileIP: userMobileIP, - endData: []); - })), + // 刚进来是接听状态,然后改为长按对讲 + UDPSenderManage.sendMainProtocol( + command: 150, + commandTypeIsCalling: 1, + subCommand: 6, + lockID: UDPManage().lockId, + lockIP: UDPManage().host, + userMobile: userMobile, + userMobileIP: userMobileIP, + endData: [] + ); + }); + }, + longPress: (){ + // 开始长按 + print("onLongPress"); + if (state.udpStatus.value == 8) { + state.udpStatus.value = 9; + } + _startRecording(); + }, + longPressUp: () async { + // 长按结束 + print("onLongPressUp"); + if (state.udpStatus.value == 9) { + state.udpStatus.value = 8; + } + _stopRecording(); + + _playRecording(); + } + ) + ), bottomBtnItemWidget( "images/main/icon_lockDetail_hangUp.png", "挂断", Colors.red, () async { var userMobileIP = await NetworkInfo().getWifiIP(); @@ -234,22 +263,12 @@ class _LockMonitoringPageState extends State { } Widget bottomBtnItemWidget( - String iconUrl, String name, Color backgroundColor, Function() onClick) { + String iconUrl, String name, Color backgroundColor, Function() onClick, {Function()? longPress, Function()? longPressUp}) { var wh = 80.w; return GestureDetector( onTap: onClick, - onLongPress: () { - print("onLongPress"); - if (state.udpStatus.value == 8) { - state.udpStatus.value = 9; - } - }, - onLongPressUp: () { - print("onLongPressUp"); - if (state.udpStatus.value == 9) { - state.udpStatus.value = 8; - } - }, + onLongPress: longPress, + onLongPressUp: longPressUp, child: SizedBox( height: 140.h, child: Column( @@ -331,29 +350,77 @@ class _LockMonitoringPageState extends State { //开始录音 _startRecording() async { - filePath = 'your_output_file.wav'; + getFilePath().then((value) { + filePath = value; + }); await recorder.startRecorder( toFile: filePath, codec: Codec.pcm16WAV, ); } -//停止录音 + //停止录音 _stopRecording() async { await recorder.stopRecorder(); + + var userMobileIP = await NetworkInfo().getWifiIP(); + var userMobile = await Storage.getMobile(); + + // final file = File(filePath); + File file = File(filePath); // 使用 create 方法创建文件 + + print('filePathfilePath:$filePath file:$file await file.exists():${await file.exists()}'); + if (await file.exists()) { + final List bytes = await file.readAsBytes(); + print('Recorded audio bytes.length:${bytes.length} bytes: $bytes'); + + // 刚进来是接听状态,然后改为长按对讲 + UDPSenderManage.sendMainProtocol( + command: 150, + commandTypeIsCalling: 1, + subCommand: 8, + lockID: UDPManage().lockId, + lockIP: UDPManage().host, + userMobile: userMobile, + userMobileIP: userMobileIP, + endData: bytes + ); + } } -//播放录音 + Future getFilePath() async { + final directory = await getApplicationDocumentsDirectory(); + final filePath = '${directory.path}/recording.wav'; + + // 创建文件 + File file = File(filePath); + await file.create(); // 使用 create 方法创建文件 + + return filePath; + } + + + Future _getRecordedAudioBytes() async { + final file = File(filePath); + if (await file.exists()) { + final List bytes = await file.readAsBytes(); + print('Recorded audio bytes: $bytes'); + } + } + + //播放录音 _playRecording() async { player = FlutterSoundPlayer(); await player.startPlayer( fromURI: filePath, codec: Codec.pcm16WAV, ); + Toast.show(msg: "储存录音播放了"); + print('_playRecording() 储存录音播放了'); } //停止播放 - _stopPlaying() async { - await player.stopPlayer(); - } +// _stopPlaying() async { +// await player.stopPlayer(); +// } } diff --git a/star_lock/lib/talk/call/callTalk.dart b/star_lock/lib/talk/call/callTalk.dart index dcdb6c02..4651ad0a 100644 --- a/star_lock/lib/talk/call/callTalk.dart +++ b/star_lock/lib/talk/call/callTalk.dart @@ -43,11 +43,12 @@ class CallTalk { Future getAVData(Uint8List bb, int len) async { // 音频数据 if (bb[61] == 1) { - print('dinglingling音频数据来啦啦啦啦啦啦啦啦啦$bb'); + print('dinglingling bb.length:${bb.length} 音频数据来:$bb '); // 用你的711音频数据替换这里的Uint8List // Uint8List rawData = G711Decoder().decodeG711uLaw(bb); // 示例 G711 数据(u-law 或 a-law) - Uint8List g711Data = bb; + + Uint8List g711Data = bb.sublist(77, bb.length); // 解码为 PCM 数据 Uint8List pcmData = G711Decoder().g711Decode(g711Data, G711Type.uLaw); // 现在你可以使用 pcmData 进行播放或其他处理 diff --git a/star_lock/lib/talk/udp/udp_reciverData.dart b/star_lock/lib/talk/udp/udp_reciverData.dart index 3ad96b76..52c1e380 100644 --- a/star_lock/lib/talk/udp/udp_reciverData.dart +++ b/star_lock/lib/talk/udp/udp_reciverData.dart @@ -19,7 +19,7 @@ class CommandUDPReciverManager { if (dataSize < 4) { return; } - print("appReceiveUDPData:$data"); + // print("appReceiveUDPData:$data"); Uint8List data1 = Uint8List.fromList(data); if (data1.length == 1) { @@ -43,7 +43,7 @@ class CommandUDPReciverManager { // 对讲命令 var beiCallType = data[8] & 0xff; - print("被呼叫类型$beiCallType"); + // print("被呼叫类型$beiCallType"); switch (beiCallType) { case 1: { From 143ccd69bde4b1269c55d5df9ab2773f88bc8963 Mon Sep 17 00:00:00 2001 From: Daisy <> Date: Thu, 21 Dec 2023 17:41:06 +0800 Subject: [PATCH 17/33] =?UTF-8?q?=E6=96=B0=E5=A2=9Epcm=E8=BD=AC711?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- star_lock/lib/talk/call/g711Encode.dart | 33 +++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/star_lock/lib/talk/call/g711Encode.dart b/star_lock/lib/talk/call/g711Encode.dart index 5369a366..3c004a3c 100644 --- a/star_lock/lib/talk/call/g711Encode.dart +++ b/star_lock/lib/talk/call/g711Encode.dart @@ -33,4 +33,37 @@ class G711Decoder { return Uint8List.fromList(g711Data); } + + List pcm16ToG711u(List pcm16Data) { + List g711uData = []; + + for (int i = 0; i < pcm16Data.length; i += 2) { + int pcmSample = (pcm16Data[i + 1] << 8) | pcm16Data[i]; + int g711Sample = pcmToG711u(pcmSample); + + // 将 G.711 样本拆分成两个字节 + g711uData.add(g711Sample & 0xFF); + g711uData.add((g711Sample >> 8) & 0xFF); + } + + return g711uData; + } + + int pcmToG711u(int pcmSample) { + const int MULAW_BIAS = 0x84; + const int CLIP = 32635; + + // 剪裁 PCM 样本 + if (pcmSample > CLIP) { + pcmSample = CLIP; + } else if (pcmSample < -CLIP) { + pcmSample = -CLIP; + } + + // 增加偏置并取反 + pcmSample += MULAW_BIAS; + pcmSample = ~pcmSample & 0xFF; + + return pcmSample; + } } From 05eb47f1d1fd50a463ebcf97840c67451a07f42c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AD=8F=E5=B0=91=E9=98=B3?= <786612630@qq.com> Date: Thu, 21 Dec 2023 17:52:40 +0800 Subject: [PATCH 18/33] =?UTF-8?q?=E6=B7=BB=E5=8A=A0iOS=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- star_lock/ios/Runner/Info.plist | 2 +- .../monitoring/monitoring/lockMonitoring_page.dart | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/star_lock/ios/Runner/Info.plist b/star_lock/ios/Runner/Info.plist index 0720c34d..2014a808 100644 --- a/star_lock/ios/Runner/Info.plist +++ b/star_lock/ios/Runner/Info.plist @@ -46,7 +46,7 @@ NSLocationWhenInUseUsageDescription 应用在前台的时候可以搜到更新的位置信息 NSMicrophoneUsageDescription - 用于音频插件 + 应用请求麦克风用来通话 NSPhotoLibraryUsageDescription 用于相册 UIApplicationSceneManifest diff --git a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart index 303323ad..8bed2ce1 100644 --- a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart +++ b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart @@ -196,12 +196,12 @@ class _LockMonitoringPageState extends State { longPressUp: () async { // 长按结束 print("onLongPressUp"); + // _playRecording(); + if (state.udpStatus.value == 9) { state.udpStatus.value = 8; } _stopRecording(); - - _playRecording(); } ) ), @@ -223,7 +223,7 @@ class _LockMonitoringPageState extends State { }), bottomBtnItemWidget("images/main/icon_lockDetail_monitoringUnlock.png", "开锁", AppColors.mainColor, () { - showDeletPasswordAlertDialog(context); + showDeletPasswordAlertDialog(context); }) ]); } @@ -353,6 +353,7 @@ class _LockMonitoringPageState extends State { getFilePath().then((value) { filePath = value; }); + await recorder.openRecorder(); await recorder.startRecorder( toFile: filePath, codec: Codec.pcm16WAV, @@ -390,7 +391,7 @@ class _LockMonitoringPageState extends State { Future getFilePath() async { final directory = await getApplicationDocumentsDirectory(); - final filePath = '${directory.path}/recording.wav'; + final filePath = '${directory.path}/recording.mp3'; // 创建文件 File file = File(filePath); @@ -411,11 +412,13 @@ class _LockMonitoringPageState extends State { //播放录音 _playRecording() async { player = FlutterSoundPlayer(); + player.openPlayer(); + await player.startPlayer( fromURI: filePath, codec: Codec.pcm16WAV, ); - Toast.show(msg: "储存录音播放了"); + // Toast.show(msg: "储存录音播放了"); print('_playRecording() 储存录音播放了'); } From ae3b80b7b48d6a93c7c07082030136de638720df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AD=8F=E5=B0=91=E9=98=B3?= <786612630@qq.com> Date: Thu, 21 Dec 2023 18:25:28 +0800 Subject: [PATCH 19/33] =?UTF-8?q?=E4=BF=AE=E6=94=B9iOS=E9=BA=A6=E5=85=8B?= =?UTF-8?q?=E9=A3=8E=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- star_lock/ios/Podfile | 1 + .../lockDetail/monitoring/monitoring/lockMonitoring_page.dart | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/star_lock/ios/Podfile b/star_lock/ios/Podfile index 573ef8f2..b09a90ba 100644 --- a/star_lock/ios/Podfile +++ b/star_lock/ios/Podfile @@ -90,6 +90,7 @@ post_install do |installer| ## dart: PermissionGroup.bluetooth 'PERMISSION_BLUETOOTH=1', + 'PERMISSION_MICROPHONE=1', ## dart: PermissionGroup.appTrackingTransparency # 'PERMISSION_APP_TRACKING_TRANSPARENCY=1', diff --git a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart index 8bed2ce1..0dd7a6d5 100644 --- a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart +++ b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart @@ -262,8 +262,7 @@ class _LockMonitoringPageState extends State { } } - Widget bottomBtnItemWidget( - String iconUrl, String name, Color backgroundColor, Function() onClick, {Function()? longPress, Function()? longPressUp}) { + Widget bottomBtnItemWidget(String iconUrl, String name, Color backgroundColor, Function() onClick, {Function()? longPress, Function()? longPressUp}) { var wh = 80.w; return GestureDetector( onTap: onClick, From a9dfd3f847bbc67e27e58531d638b5eb5a1c61f0 Mon Sep 17 00:00:00 2001 From: Daisy <> Date: Fri, 22 Dec 2023 14:22:34 +0800 Subject: [PATCH 20/33] =?UTF-8?q?g711=E7=BC=96=E8=A7=A3=E7=A0=81=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- star_lock/lib/talk/call/callTalk.dart | 28 ++++---- star_lock/lib/talk/call/g711.dart | 89 ++++++++++++++++++++++++ star_lock/lib/talk/call/g711Decoder.dart | 36 ---------- star_lock/lib/talk/call/g711Encode.dart | 69 ------------------ star_lock/pubspec.yaml | 2 +- 5 files changed, 106 insertions(+), 118 deletions(-) create mode 100644 star_lock/lib/talk/call/g711.dart delete mode 100644 star_lock/lib/talk/call/g711Decoder.dart delete mode 100644 star_lock/lib/talk/call/g711Encode.dart diff --git a/star_lock/lib/talk/call/callTalk.dart b/star_lock/lib/talk/call/callTalk.dart index 4651ad0a..97b6ea57 100644 --- a/star_lock/lib/talk/call/callTalk.dart +++ b/star_lock/lib/talk/call/callTalk.dart @@ -1,11 +1,13 @@ import 'dart:typed_data'; +import 'package:convert/convert.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_ffmpeg/flutter_ffmpeg.dart'; import 'package:flutter_sound/flutter_sound.dart'; import 'package:get/get.dart'; import 'package:get/get_core/src/get_main.dart'; import 'package:star_lock/appRouters.dart'; import 'package:star_lock/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart'; -import 'package:star_lock/talk/call/g711Decoder.dart'; +import 'package:star_lock/talk/call/g711.dart'; import 'package:star_lock/talk/call/iFrameInfo.dart'; import '../../tools/eventBusEventManage.dart'; @@ -29,7 +31,6 @@ class CallTalk { CallTalk._init() { iframe = IframeInfo(); - _initializeAudioPlayer(); } static CallTalk _share() { @@ -43,18 +44,19 @@ class CallTalk { Future getAVData(Uint8List bb, int len) async { // 音频数据 if (bb[61] == 1) { - print('dinglingling bb.length:${bb.length} 音频数据来:$bb '); - // 用你的711音频数据替换这里的Uint8List - // Uint8List rawData = G711Decoder().decodeG711uLaw(bb); - // 示例 G711 数据(u-law 或 a-law) - Uint8List g711Data = bb.sublist(77, bb.length); - // 解码为 PCM 数据 - Uint8List pcmData = G711Decoder().g711Decode(g711Data, G711Type.uLaw); - // 现在你可以使用 pcmData 进行播放或其他处理 - print('得到的pcmData:$pcmData'); + print('dinglingling bb.length:${g711Data.length} 音频数据来:$g711Data '); + Uint8List? pcmBytes = await G711().decodeG711ToPCM(g711Data.toList()); - _playRawData(pcmData); + print('PCM decoded data: $pcmBytes'); + + if (pcmBytes != null) { + _initializeAudioPlayer(); + _playRawData(pcmBytes); + } else { + print('Error decoding G.711 to PCM'); + } + // 在这里处理你的 PCM 数据 } // 视频数据 else { @@ -144,6 +146,8 @@ class CallTalk { await _audioPlayer.startPlayer( fromDataBuffer: rawData, codec: Codec.pcm16, + numChannels: 1, + sampleRate: 8000, whenFinished: () { // 播放完成时的回调 print("Playback finished"); diff --git a/star_lock/lib/talk/call/g711.dart b/star_lock/lib/talk/call/g711.dart new file mode 100644 index 00000000..c3ab0ee7 --- /dev/null +++ b/star_lock/lib/talk/call/g711.dart @@ -0,0 +1,89 @@ +import 'dart:async'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:flutter_ffmpeg/flutter_ffmpeg.dart'; +import 'package:path_provider/path_provider.dart'; + +class G711 { + Future decodeG711ToPCM(List g711Data) async { + try { + FlutterFFmpeg flutterFFmpeg = FlutterFFmpeg(); + + // Save G.711 data to a temporary file + Directory appDocDir = await getApplicationDocumentsDirectory(); + String g711FilePath = '${appDocDir.path}/input.g711'; + await File(g711FilePath).writeAsBytes(g711Data); + + // Replace with the desired output PCM file path + String pcmFilePath = '${appDocDir.path}/output.pcm'; + + // Run FFmpeg command to decode G.711 to PCM + String command = + '-y -f u8 -ar 8000 -ac 1 -i $g711FilePath -f s16le -ar 8000 -ac 1 $pcmFilePath'; + int result = await flutterFFmpeg.execute(command); + + if (result == 0) { + print('G.711 decoding successful! PCM file saved at: $pcmFilePath'); + + // Read PCM data from file + Uint8List pcmBytes = await File(pcmFilePath).readAsBytes(); + + // Delete the temporary G.711 file + await File(g711FilePath).delete(); + + // Delete the temporary PCM file + await File(pcmFilePath).delete(); + + return pcmBytes; + } else { + print('Error during G.711 decoding: $result'); + return null; + } + } catch (e) { + print('Error: $e'); + return null; + } + } + + Future encodePCMToG711(Uint8List pcmData) async { + try { + FlutterFFmpeg flutterFFmpeg = FlutterFFmpeg(); + + // Save PCM data to a temporary file + Directory appDocDir = await getApplicationDocumentsDirectory(); + String pcmFilePath = '${appDocDir.path}/input.pcm'; + await File(pcmFilePath).writeAsBytes(pcmData); + + // Replace with the desired output G.711 file path + String g711FilePath = '${appDocDir.path}/output.g711'; + + // Run FFmpeg command to encode PCM to G.711 + String command = + '-y -f s16le -ar 8000 -ac 1 -i $pcmFilePath -f g711 -ar 8000 -ac 1 $g711FilePath'; + int result = await flutterFFmpeg.execute(command); + + if (result == 0) { + print( + 'PCM encoding to G.711 successful! G.711 file saved at: $g711FilePath'); + + // Read G.711 data from file + Uint8List g711Bytes = await File(g711FilePath).readAsBytes(); + + // Delete the temporary PCM file + await File(pcmFilePath).delete(); + + // Delete the temporary G.711 file + await File(g711FilePath).delete(); + + return g711Bytes; + } else { + print('Error during PCM encoding to G.711: $result'); + return null; + } + } catch (e) { + print('Error: $e'); + return null; + } + } +} diff --git a/star_lock/lib/talk/call/g711Decoder.dart b/star_lock/lib/talk/call/g711Decoder.dart deleted file mode 100644 index 2b1d5c74..00000000 --- a/star_lock/lib/talk/call/g711Decoder.dart +++ /dev/null @@ -1,36 +0,0 @@ -import 'dart:typed_data'; - -enum G711Type { - uLaw, - aLaw, -} - -class G711Decoder { - Uint8List g711Decode(Uint8List g711Data, G711Type g711Type) { - List pcmData = []; - int sign, exponent, mantissa, sample; - - for (int i = 0; i < g711Data.length; i++) { - int value = g711Data[i]; - - if (g711Type == G711Type.uLaw) { - // μ-law decoding - value = ~value & 0xFF; - sign = (value & 0x80) == 0 ? 1 : -1; - exponent = (value & 0x70) >> 4; - mantissa = ((value & 0x0F) << 4) + 0x10; - sample = (mantissa << exponent) * sign; - } else { - // A-law decoding - sign = (value & 0x80) == 0 ? 1 : -1; - exponent = ((value & 0x70) >> 4) + 1; - mantissa = (value & 0x0F) + 0x10; - sample = (mantissa << exponent) * sign; - } - - pcmData.add(sample); - } - - return Uint8List.fromList(pcmData); - } -} diff --git a/star_lock/lib/talk/call/g711Encode.dart b/star_lock/lib/talk/call/g711Encode.dart deleted file mode 100644 index 3c004a3c..00000000 --- a/star_lock/lib/talk/call/g711Encode.dart +++ /dev/null @@ -1,69 +0,0 @@ -import 'dart:typed_data'; - -enum G711Type { - uLaw, - aLaw, -} - -class G711Decoder { - Uint8List g711Encode(Uint8List pcmData, G711Type g711Type) { - List g711Data = []; - - for (int sample in pcmData) { - int sign = (sample < 0) ? 0x80 : 0; - int magnitude = (sample < 0) ? -sample : sample; - - int exponent = 7; - while (magnitude < (1 << exponent) && exponent > 0) { - exponent--; - } - - int mantissa = (magnitude >> (exponent - 4)) & 0x0F; - - if (g711Type == G711Type.uLaw) { - // μ-law encoding - int value = ~(sign | ((exponent << 4) & 0x70) | (mantissa >> 4)); - g711Data.add(value & 0xFF); - } else { - // A-law encoding - int value = sign | ((exponent << 4) & 0x70) | (mantissa >> 4); - g711Data.add(value & 0xFF); - } - } - - return Uint8List.fromList(g711Data); - } - - List pcm16ToG711u(List pcm16Data) { - List g711uData = []; - - for (int i = 0; i < pcm16Data.length; i += 2) { - int pcmSample = (pcm16Data[i + 1] << 8) | pcm16Data[i]; - int g711Sample = pcmToG711u(pcmSample); - - // 将 G.711 样本拆分成两个字节 - g711uData.add(g711Sample & 0xFF); - g711uData.add((g711Sample >> 8) & 0xFF); - } - - return g711uData; - } - - int pcmToG711u(int pcmSample) { - const int MULAW_BIAS = 0x84; - const int CLIP = 32635; - - // 剪裁 PCM 样本 - if (pcmSample > CLIP) { - pcmSample = CLIP; - } else if (pcmSample < -CLIP) { - pcmSample = -CLIP; - } - - // 增加偏置并取反 - pcmSample += MULAW_BIAS; - pcmSample = ~pcmSample & 0xFF; - - return pcmSample; - } -} diff --git a/star_lock/pubspec.yaml b/star_lock/pubspec.yaml index bde1c728..2d1ed9d1 100644 --- a/star_lock/pubspec.yaml +++ b/star_lock/pubspec.yaml @@ -125,7 +125,7 @@ dependencies: convert: ^3.1.1 just_audio: ^0.9.36 flutter_sound: ^9.2.13 - + flutter_ffmpeg: ^0.4.2 fast_gbk: ^1.0.0 dev_dependencies: From a6773da4fd47e11126f3884343cb8fd1c732c10d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AD=8F=E5=B0=91=E9=98=B3?= <786612630@qq.com> Date: Fri, 22 Dec 2023 14:26:58 +0800 Subject: [PATCH 21/33] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../monitoring/lockMonitoring_page.dart | 63 +++++++++++-------- star_lock/lib/talk/call/callTalk.dart | 6 +- .../udp/io_protocol/udp_mainProtocol.dart | 2 + 3 files changed, 42 insertions(+), 29 deletions(-) diff --git a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart index 0dd7a6d5..ad539497 100644 --- a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart +++ b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart @@ -223,6 +223,8 @@ class _LockMonitoringPageState extends State { }), bottomBtnItemWidget("images/main/icon_lockDetail_monitoringUnlock.png", "开锁", AppColors.mainColor, () { + + // _playRecording(); showDeletPasswordAlertDialog(context); }) ]); @@ -231,34 +233,22 @@ class _LockMonitoringPageState extends State { String getAnswerBtnImg() { switch (state.udpStatus.value) { case 8: - { return "images/main/icon_lockDetail_monitoringUnTalkback.png"; - } case 9: - { return "images/main/icon_lockDetail_monitoringTalkback.png"; - } default: - { return "images/main/icon_lockDetail_monitoringAnswerCalls.png"; - } } } String getAnswerBtnName() { switch (state.udpStatus.value) { case 8: - { return "长按说话"; - } case 9: - { return "松开发送"; - } default: - { return "接听"; - } } } @@ -356,6 +346,9 @@ class _LockMonitoringPageState extends State { await recorder.startRecorder( toFile: filePath, codec: Codec.pcm16WAV, + bitRate: 8000, + numChannels: 1, + sampleRate: 8000, ); } @@ -363,9 +356,6 @@ class _LockMonitoringPageState extends State { _stopRecording() async { await recorder.stopRecorder(); - var userMobileIP = await NetworkInfo().getWifiIP(); - var userMobile = await Storage.getMobile(); - // final file = File(filePath); File file = File(filePath); // 使用 create 方法创建文件 @@ -374,23 +364,13 @@ class _LockMonitoringPageState extends State { final List bytes = await file.readAsBytes(); print('Recorded audio bytes.length:${bytes.length} bytes: $bytes'); - // 刚进来是接听状态,然后改为长按对讲 - UDPSenderManage.sendMainProtocol( - command: 150, - commandTypeIsCalling: 1, - subCommand: 8, - lockID: UDPManage().lockId, - lockIP: UDPManage().host, - userMobile: userMobile, - userMobileIP: userMobileIP, - endData: bytes - ); + _sendRecordData(bytes); } } Future getFilePath() async { final directory = await getApplicationDocumentsDirectory(); - final filePath = '${directory.path}/recording.mp3'; + final filePath = '${directory.path}/recording.wav'; // 创建文件 File file = File(filePath); @@ -425,4 +405,33 @@ class _LockMonitoringPageState extends State { // _stopPlaying() async { // await player.stopPlayer(); // } + + _sendRecordData(List bytes) async { + // 刚进来是接听状态,然后改为长按对讲 + var userMobileIP = await NetworkInfo().getWifiIP(); + var userMobile = await Storage.getMobile(); + + // 57 + List topBytes = [ + 1, 1, 1, 1, // 时间戳 + 1, 0, // 音频 + 1, 0, // 帧序号 + 64, 0, 0, 0, // 帧长度 + 1, 0, // 总包数 + 1, 0, // 当前包号 + 64, 1, // 数据长度 + 176, 4, // 保留 + ]; + UDPSenderManage.sendMainProtocol( + command: 150, + commandTypeIsCalling: 1, + subCommand: 8, + lockID: UDPManage().lockId, + lockIP: UDPManage().host, + userMobile: userMobile, + userMobileIP: userMobileIP, + endData: bytes + ); + } + } diff --git a/star_lock/lib/talk/call/callTalk.dart b/star_lock/lib/talk/call/callTalk.dart index 4651ad0a..4dbedae9 100644 --- a/star_lock/lib/talk/call/callTalk.dart +++ b/star_lock/lib/talk/call/callTalk.dart @@ -26,6 +26,7 @@ class CallTalk { var growableList; bool getFirstFrame = false; //是否得到了第一帧 final FlutterSoundPlayer _audioPlayer = FlutterSoundPlayer(); + Uint8List? allPcmData = Uint8List(0); CallTalk._init() { iframe = IframeInfo(); @@ -53,8 +54,9 @@ class CallTalk { Uint8List pcmData = G711Decoder().g711Decode(g711Data, G711Type.uLaw); // 现在你可以使用 pcmData 进行播放或其他处理 print('得到的pcmData:$pcmData'); - - _playRawData(pcmData); + allPcmData!.addAll(pcmData); + await Future.delayed(const Duration(seconds: 3)); + _playRawData(allPcmData!); } // 视频数据 else { diff --git a/star_lock/lib/talk/udp/io_protocol/udp_mainProtocol.dart b/star_lock/lib/talk/udp/io_protocol/udp_mainProtocol.dart index add59504..0fffeb9b 100644 --- a/star_lock/lib/talk/udp/io_protocol/udp_mainProtocol.dart +++ b/star_lock/lib/talk/udp/io_protocol/udp_mainProtocol.dart @@ -62,6 +62,8 @@ class UDPMainProtocolCommand extends UDPSenderProtocol { data.add(int.parse(element)); }); + data.addAll(endData!); + // print("datadatadata:$data"); return data; } From 82b110778d95313412b1d8dcc49fbfbab295a077 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AD=8F=E5=B0=91=E9=98=B3?= <786612630@qq.com> Date: Mon, 25 Dec 2023 10:45:07 +0800 Subject: [PATCH 22/33] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- star_lock/.flutter-plugins-dependencies 2 | 1 + .../main/lockDetail/lockDetail/lockDetail_logic.dart | 3 +-- .../main/lockDetail/lockDetail/lockDetail_page.dart | 1 + star_lock/lib/talk/call/callTalk.dart | 11 +++++++++-- star_lock/lib/talk/udp/udp_reciverData.dart | 2 +- 5 files changed, 13 insertions(+), 5 deletions(-) create mode 100644 star_lock/.flutter-plugins-dependencies 2 diff --git a/star_lock/.flutter-plugins-dependencies 2 b/star_lock/.flutter-plugins-dependencies 2 new file mode 100644 index 00000000..976fa555 --- /dev/null +++ b/star_lock/.flutter-plugins-dependencies 2 @@ -0,0 +1 @@ +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"aj_captcha_flutter","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/aj_captcha_flutter-0.0.1/","native_build":true,"dependencies":[]},{"name":"aliyun_push","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/aliyun_push-0.1.6/","native_build":true,"dependencies":[]},{"name":"amap_flutter_location","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/amap_flutter_location-3.0.0/","native_build":true,"dependencies":[]},{"name":"amap_flutter_map","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/amap_flutter_map-3.0.0/","native_build":true,"dependencies":[]},{"name":"audio_session","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/audio_session-0.1.18/","native_build":true,"dependencies":[]},{"name":"audioplayers_darwin","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/audioplayers_darwin-5.0.2/","native_build":true,"dependencies":[]},{"name":"auto_orientation","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/auto_orientation-2.3.1/","native_build":true,"dependencies":[]},{"name":"camera_avfoundation","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/camera_avfoundation-0.9.13+6/","native_build":true,"dependencies":[]},{"name":"device_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/device_info_plus-8.2.2/","native_build":true,"dependencies":[]},{"name":"flutter_ffmpeg","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/flutter_ffmpeg-0.4.2/","native_build":true,"dependencies":[]},{"name":"flutter_native_contact_picker","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/flutter_native_contact_picker-0.0.4/","native_build":true,"dependencies":[]},{"name":"flutter_sound","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/flutter_sound-9.2.13/","native_build":true,"dependencies":[]},{"name":"fluttertoast","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/fluttertoast-8.2.2/","native_build":true,"dependencies":[]},{"name":"g711_flutter","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/g711_flutter-2.0.0/","native_build":true,"dependencies":[]},{"name":"google_maps_flutter_ios","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/google_maps_flutter_ios-2.3.2/","native_build":true,"dependencies":[]},{"name":"image_gallery_saver","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/image_gallery_saver-2.0.3/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/image_picker_ios-0.8.8+2/","native_build":true,"dependencies":[]},{"name":"just_audio","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/just_audio-0.9.36/","native_build":true,"dependencies":["audio_session"]},{"name":"network_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/network_info_plus-4.1.0/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/package_info_plus-3.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/path_provider_foundation-2.3.1/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/permission_handler_apple-9.1.4/","native_build":true,"dependencies":[]},{"name":"reactive_ble_mobile","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/reactive_ble_mobile-5.2.0/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_foundation-2.3.4/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"sqflite","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/sqflite-2.3.0/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_ios-6.1.5/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/video_player_avfoundation-2.4.11/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/webview_flutter_wkwebview-3.9.1/","native_build":true,"dependencies":[]}],"android":[{"name":"aj_captcha_flutter","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/aj_captcha_flutter-0.0.1/","native_build":true,"dependencies":[]},{"name":"aliyun_push","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/aliyun_push-0.1.6/","native_build":true,"dependencies":[]},{"name":"amap_flutter_location","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/amap_flutter_location-3.0.0/","native_build":true,"dependencies":[]},{"name":"amap_flutter_map","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/amap_flutter_map-3.0.0/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"audio_session","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/audio_session-0.1.18/","native_build":true,"dependencies":[]},{"name":"audioplayers_android","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/audioplayers_android-4.0.3/","native_build":true,"dependencies":[]},{"name":"auto_orientation","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/auto_orientation-2.3.1/","native_build":true,"dependencies":[]},{"name":"camera_android","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/camera_android-0.10.8+12/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"device_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/device_info_plus-8.2.2/","native_build":true,"dependencies":[]},{"name":"flutter_ffmpeg","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/flutter_ffmpeg-0.4.2/","native_build":true,"dependencies":[]},{"name":"flutter_native_contact_picker","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/flutter_native_contact_picker-0.0.4/","native_build":true,"dependencies":[]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/flutter_plugin_android_lifecycle-2.0.16/","native_build":true,"dependencies":[]},{"name":"flutter_sound","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/flutter_sound-9.2.13/","native_build":true,"dependencies":[]},{"name":"fluttertoast","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/fluttertoast-8.2.2/","native_build":true,"dependencies":[]},{"name":"g711_flutter","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/g711_flutter-2.0.0/","native_build":true,"dependencies":[]},{"name":"google_maps_flutter_android","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/google_maps_flutter_android-2.5.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_gallery_saver","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/image_gallery_saver-2.0.3/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/image_picker_android-0.8.8+1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"just_audio","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/just_audio-0.9.36/","native_build":true,"dependencies":["audio_session"]},{"name":"network_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/network_info_plus-4.1.0/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/package_info_plus-3.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/path_provider_android-2.2.0/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/permission_handler_android-10.3.6/","native_build":true,"dependencies":[]},{"name":"reactive_ble_mobile","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/reactive_ble_mobile-5.2.0/","native_build":true,"dependencies":[]},{"name":"shared_preferences_android","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_android-2.2.1/","native_build":true,"dependencies":[]},{"name":"sqflite","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/sqflite-2.3.0/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_android-6.1.0/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/video_player_android-2.4.10/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/webview_flutter_android-3.12.0/","native_build":true,"dependencies":[]}],"macos":[{"name":"aj_captcha_flutter","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/aj_captcha_flutter-0.0.1/","native_build":true,"dependencies":[]},{"name":"audio_session","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/audio_session-0.1.18/","native_build":true,"dependencies":[]},{"name":"audioplayers_darwin","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/audioplayers_darwin-5.0.2/","native_build":true,"dependencies":[]},{"name":"device_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/device_info_plus-8.2.2/","native_build":true,"dependencies":[]},{"name":"file_selector_macos","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/file_selector_macos-0.9.3+3/","native_build":true,"dependencies":[]},{"name":"image_picker_macos","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/image_picker_macos-0.2.1+1/","native_build":false,"dependencies":["file_selector_macos"]},{"name":"just_audio","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/just_audio-0.9.36/","native_build":true,"dependencies":["audio_session"]},{"name":"network_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/network_info_plus-4.1.0/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/package_info_plus-3.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/path_provider_foundation-2.3.1/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_foundation-2.3.4/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"sqflite","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/sqflite-2.3.0/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_macos-3.0.7/","native_build":true,"dependencies":[]}],"linux":[{"name":"aj_captcha_flutter","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/aj_captcha_flutter-0.0.1/","native_build":true,"dependencies":[]},{"name":"audioplayers_linux","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/audioplayers_linux-3.1.0/","native_build":true,"dependencies":[]},{"name":"device_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/device_info_plus-8.2.2/","native_build":false,"dependencies":[]},{"name":"file_selector_linux","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/file_selector_linux-0.9.2+1/","native_build":true,"dependencies":[]},{"name":"image_picker_linux","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/image_picker_linux-0.2.1+1/","native_build":false,"dependencies":["file_selector_linux"]},{"name":"network_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/network_info_plus-4.1.0/","native_build":false,"dependencies":[]},{"name":"package_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/package_info_plus-3.1.2/","native_build":false,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]},{"name":"shared_preferences_linux","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_linux-2.3.2/","native_build":false,"dependencies":["path_provider_linux"]},{"name":"url_launcher_linux","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_linux-3.0.6/","native_build":true,"dependencies":[]}],"windows":[{"name":"aj_captcha_flutter","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/aj_captcha_flutter-0.0.1/","native_build":true,"dependencies":[]},{"name":"audioplayers_windows","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/audioplayers_windows-3.1.0/","native_build":true,"dependencies":[]},{"name":"device_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/device_info_plus-8.2.2/","native_build":false,"dependencies":[]},{"name":"file_selector_windows","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/file_selector_windows-0.9.3+1/","native_build":true,"dependencies":[]},{"name":"image_picker_windows","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/image_picker_windows-0.2.1+1/","native_build":false,"dependencies":["file_selector_windows"]},{"name":"network_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/network_info_plus-4.1.0/","native_build":false,"dependencies":[]},{"name":"package_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/package_info_plus-3.1.2/","native_build":false,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/path_provider_windows-2.2.1/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/permission_handler_windows-0.1.3/","native_build":true,"dependencies":[]},{"name":"shared_preferences_windows","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_windows-2.3.2/","native_build":false,"dependencies":["path_provider_windows"]},{"name":"url_launcher_windows","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_windows-3.0.8/","native_build":true,"dependencies":[]}],"web":[{"name":"aj_captcha_flutter","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/aj_captcha_flutter-0.0.1/","dependencies":[]},{"name":"audio_session","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/audio_session-0.1.18/","dependencies":[]},{"name":"audioplayers_web","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/audioplayers_web-4.1.0/","dependencies":[]},{"name":"camera_web","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/camera_web-0.3.2+2/","dependencies":[]},{"name":"device_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/device_info_plus-8.2.2/","dependencies":[]},{"name":"flutter_sound_web","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/flutter_sound_web-9.2.13/","dependencies":[]},{"name":"fluttertoast","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/fluttertoast-8.2.2/","dependencies":[]},{"name":"google_maps_flutter_web","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/google_maps_flutter_web-0.5.4+1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/image_picker_for_web-3.0.1/","dependencies":[]},{"name":"just_audio_web","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/just_audio_web-0.4.9/","dependencies":[]},{"name":"network_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/network_info_plus-4.1.0/","dependencies":[]},{"name":"package_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/package_info_plus-3.1.2/","dependencies":[]},{"name":"shared_preferences_web","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_web-2.2.1/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_web-2.0.19/","dependencies":[]},{"name":"video_player_web","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/video_player_web-2.0.17/","dependencies":[]}]},"dependencyGraph":[{"name":"aj_captcha_flutter","dependencies":[]},{"name":"aliyun_push","dependencies":[]},{"name":"amap_flutter_location","dependencies":[]},{"name":"amap_flutter_map","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"audio_session","dependencies":[]},{"name":"audioplayers","dependencies":["audioplayers_android","audioplayers_darwin","audioplayers_linux","audioplayers_web","audioplayers_windows","path_provider"]},{"name":"audioplayers_android","dependencies":[]},{"name":"audioplayers_darwin","dependencies":[]},{"name":"audioplayers_linux","dependencies":[]},{"name":"audioplayers_web","dependencies":[]},{"name":"audioplayers_windows","dependencies":[]},{"name":"auto_orientation","dependencies":[]},{"name":"camera","dependencies":["camera_android","camera_avfoundation","camera_web","flutter_plugin_android_lifecycle"]},{"name":"camera_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"camera_avfoundation","dependencies":[]},{"name":"camera_web","dependencies":[]},{"name":"device_info_plus","dependencies":[]},{"name":"file_selector_linux","dependencies":[]},{"name":"file_selector_macos","dependencies":[]},{"name":"file_selector_windows","dependencies":[]},{"name":"flutter_ffmpeg","dependencies":[]},{"name":"flutter_native_contact_picker","dependencies":[]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_reactive_ble","dependencies":["reactive_ble_mobile"]},{"name":"flutter_sound","dependencies":["path_provider","flutter_sound_web"]},{"name":"flutter_sound_web","dependencies":[]},{"name":"fluttertoast","dependencies":[]},{"name":"g711_flutter","dependencies":[]},{"name":"google_maps_flutter","dependencies":["google_maps_flutter_android","google_maps_flutter_ios","google_maps_flutter_web"]},{"name":"google_maps_flutter_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"google_maps_flutter_ios","dependencies":[]},{"name":"google_maps_flutter_web","dependencies":[]},{"name":"image_gallery_saver","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios","image_picker_linux","image_picker_macos","image_picker_windows"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"image_picker_linux","dependencies":["file_selector_linux"]},{"name":"image_picker_macos","dependencies":["file_selector_macos"]},{"name":"image_picker_windows","dependencies":["file_selector_windows"]},{"name":"just_audio","dependencies":["just_audio_web","audio_session","path_provider"]},{"name":"just_audio_web","dependencies":[]},{"name":"network_info_plus","dependencies":[]},{"name":"package_info_plus","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"reactive_ble_mobile","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]},{"name":"sqflite","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2023-12-22 15:43:01.891206","version":"3.10.6"} \ No newline at end of file diff --git a/star_lock/lib/main/lockDetail/lockDetail/lockDetail_logic.dart b/star_lock/lib/main/lockDetail/lockDetail/lockDetail_logic.dart index bc49eb75..607f2c4d 100644 --- a/star_lock/lib/main/lockDetail/lockDetail/lockDetail_logic.dart +++ b/star_lock/lib/main/lockDetail/lockDetail/lockDetail_logic.dart @@ -633,8 +633,7 @@ class LockDetailLogic extends BaseGetXController{ print("有蓝牙权限开始扫描"); startScanAction(); }else{ - getMicrophonePermission() - .then((value) { + getMicrophonePermission().then((value) { if (value) { // 有权限 print("有蓝牙权限开始扫描"); diff --git a/star_lock/lib/main/lockDetail/lockDetail/lockDetail_page.dart b/star_lock/lib/main/lockDetail/lockDetail/lockDetail_page.dart index 02bfbd1f..c7c2e56e 100644 --- a/star_lock/lib/main/lockDetail/lockDetail/lockDetail_page.dart +++ b/star_lock/lib/main/lockDetail/lockDetail/lockDetail_page.dart @@ -65,6 +65,7 @@ class _LockDetailPageState extends State with TickerProviderStat var saveSignKeyList = changeIntListToStringList(signKeyData); Storage.setStringList(saveBlueSignKey, saveSignKeyList); + Storage.setStringList(saveBlueToken, [0, 0, 0, 0]); // logic.startScanAction(); listeningAnimations(); diff --git a/star_lock/lib/talk/call/callTalk.dart b/star_lock/lib/talk/call/callTalk.dart index cbea16c6..bdb03db9 100644 --- a/star_lock/lib/talk/call/callTalk.dart +++ b/star_lock/lib/talk/call/callTalk.dart @@ -28,7 +28,7 @@ class CallTalk { var growableList; bool getFirstFrame = false; //是否得到了第一帧 final FlutterSoundPlayer _audioPlayer = FlutterSoundPlayer(); - Uint8List? allPcmData = Uint8List(0); + List? allPcmData = []; CallTalk._init() { iframe = IframeInfo(); @@ -58,11 +58,14 @@ class CallTalk { print('dinglingling bb.length:${g711Data.length} 音频数据来:$g711Data '); Uint8List? pcmBytes = await G711().decodeG711ToPCM(g711Data.toList()); + allPcmData!.addAll(pcmBytes!); + await Future.delayed(const Duration(seconds: 1)); + print('PCM decoded data: $pcmBytes'); if (pcmBytes != null) { _initializeAudioPlayer(); - _playRawData(pcmBytes); + _playRawData(Uint8List.fromList(allPcmData!)); } else { print('Error decoding G.711 to PCM'); } @@ -163,4 +166,8 @@ class CallTalk { }, ); } + + Future stopLocalAudio() async { + await _audioPlayer.stopPlayer(); + } } diff --git a/star_lock/lib/talk/udp/udp_reciverData.dart b/star_lock/lib/talk/udp/udp_reciverData.dart index 52c1e380..9fea6034 100644 --- a/star_lock/lib/talk/udp/udp_reciverData.dart +++ b/star_lock/lib/talk/udp/udp_reciverData.dart @@ -19,7 +19,7 @@ class CommandUDPReciverManager { if (dataSize < 4) { return; } - // print("appReceiveUDPData:$data"); + print("appReceiveUDPData:$data"); Uint8List data1 = Uint8List.fromList(data); if (data1.length == 1) { From 3d0dc3074f8d589c00597baf83617e0e8296bafc Mon Sep 17 00:00:00 2001 From: Daisy <> Date: Tue, 26 Dec 2023 16:30:06 +0800 Subject: [PATCH 23/33] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E6=B5=8B=E8=AF=95711?= =?UTF-8?q?=E9=9F=B3=E9=A2=91=E6=92=AD=E6=94=BE=E6=88=90=E5=8A=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- star_lock/assets/s10-g711.bin | 1 + star_lock/ios/Podfile.lock | 15 +- .../ios/Runner.xcodeproj/project.pbxproj | 79 ++++++---- star_lock/lib/main.dart | 55 ++++++- star_lock/lib/talk/call/callTalk.dart | 23 ++- star_lock/lib/talk/call/g711.dart | 144 ++++++++++-------- .../Flutter/GeneratedPluginRegistrant.swift | 2 + star_lock/pubspec.yaml | 2 +- 8 files changed, 216 insertions(+), 105 deletions(-) create mode 100644 star_lock/assets/s10-g711.bin diff --git a/star_lock/assets/s10-g711.bin b/star_lock/assets/s10-g711.bin new file mode 100644 index 00000000..9f5085b2 --- /dev/null +++ b/star_lock/assets/s10-g711.bin @@ -0,0 +1 @@ +}~y~zu||}~zruxxvyy|}|zuu}|{}|zztvxyvyyuztpptvyxwsxvvqsqxssssxxvsoouuwsrmoqmjjmnoljjkjjhijllmmljhgecadfegedfifccdfffgfehfcbacddcedacb``cbcbbcccda_^`____^a_^_]]^]]^]^__^^^^____^__]]^]\]]^]]]]][[[[`\\\\[[Z[\\[[[\\\\\\[[\[\]]]]]\[[[[[[[]\\[[\ZZ[[[[[[[[[Z[[[\\]][[\[[[[\]]\\[[[ZZ[[[\\\\ZZZYY[[[[[[[ZYXXXXZ[\]][\ZYYYZZYZZ[[[ZXXXYZYYZYYXWXXZZYXXYXXYXXYYYZZXZYYXXXXWWWWWXXXXWVWXXYVVWTTURTUUTTTUWWVUUUVVVVVVUVVVWWWWVVWWWVUUUWVVVVUTTTUTTTTSTSSSRQRRSSSSSRQRQRSTTTTSUTSTSSTTUUUUTSSSRSSSSSRRRQQQPRRQRQQQQRSRQRPPPOOQPQPPRQQQPPPOOPOPQPPPOOONNOOOOOONOOOOOPPOOOOONNNMNNMMMMMMMMNNNNONNNNNNNNNONNNNNONNNNNNMMNMNNNNMMONMNNOONNNNONMNNOOONNNNMMMMMMNNNNOOPPPRRPONNNNMMNONOOOONOOOOOONNMMMMMNNOOOPOOONMNMMMMNNNNNNOOONNNNMMNNONNMMNMMMMMNNNNNNOOONNNNPNNNNONOONMNNNNNONNOOOONMNMMMMNMMMMMNNNNNMMNNMNNNNNNNMNNMLLLLMLLLLLMLKKKKLKKLLLLKKKKKJIIIIJJJJKKLLKLLLLKJJJJIJJIJJJJJIKJKKJKKKKKKLLLLKKKJJIIJJJKJJKJKKKKLKKKJJJJJJJKKJJJJJLKLLLLLKIJKKKKKKKLLKKKJJJIIIIJJJKKKKKKKJKJJJIJIIIJKKKKKLLLKJJJKKKJJKKJKKJKKIJIHIHHHHIKKKKLLMLKKJJIHIIIJJIJJJKJJIHIHHIIIJJKJJJJIIHHIIJJIIIHIIHJJKLKKKIHIHHIIJJJKJIIIIIIIIIIIHIIJJKKKJJIHHGFHHHJIIJIIIIIJIIIHIIHHIHIIJKKKKJIIHIIIIIIJIIJJIIIIIHIIIIIHJKKLKKKKKJJJJJKKKJIHHGHIIJJJJIJJJJIHHHHIJJJIIHHGHFFFFHHHIHIJIJKJJJHHHGIIHJIIKJIJIIJJJLKJKIHHHIIIJJJJJIIIHHHGGHGGHHHJLIIHIIHIIHHHHIIHIJIIIHHHHHHHIHHIHGHIIJIIJHGGFGGFHIIJKJJJIIIIIIHHHHHHHGHIHHHGGFFGGHHHJIHIIIIIHIIIIIIIHHHGHHHIHHHHHHHGHGHIIJIHHIHGGGGFFFHIIIHHHIIIHHGGGFFFGGHHGHIHHGGGGGIHGIHHIHHIIIHIIHHGFFFFGIHIIIIHHHHGGGFGGGGGFGFGHGHHGGGFGGGGGGIIHHGFFEFFGGGFFFFGGHHHIHHHGGGFFFFGGGHGGGGHHHGGGGGGGGHHHHIHHHGFFGGGGFFFGHIIJJJJIIIGGFGGGGHGGHGGHGHHGGGGHHHHIIHHHGGGGGGHHHHHGGGGHHHHHHHHHGGHHHIHHHGGGGHGGHHGHHHGFGFFFFFGGGFEEEEFFFGGGHHHHGGGGGGFFFFFGGFFGFGGFGIHIIGHIHIHFHHGIHHHHGGGGHGGGFHHHIGGGGFGFFGFGHGHIHHHHHHHHHGGFGGGHIHIIHHHGGFFGHIHHHGHIHHHGHGFFEFFEFFFHJHHGGGGGFFFFFFGGGGGHHGHGFFEFFFFFFFGGHHHGGFFFFFFFFFGGGHHGGGFFEEEEEFFGHHIHHHIHHHGGGFGGGGGGHHHIHGGFFFFFGGGHHHIHHHHHHHHGGGGGGGGGGGGGHHHGGGFFFFGGGGGGGGGFFFFFGGFFFFGGGGGGHGHHGGGGGGGGHHFGFFGFFFFFFFGGGGGHGGGGFFFFGFFFFFGGGHGGHGGHGGHGHHGGGGHHHHGGGGGGGGGHHHHHGHGGGGFGFGGGHHHHHHHHHHHGHHGHIIIHHIIJJJJIIIHHHHHHIIIHHHGHHIHGHGFHHGIHHIGGGGGHGHGGGGGGGFFFEEEEEEEEFFFGGGHHHHHGHGGGGGGGGGGGGHGGGFFGGGHGGGFFFGGHHHHGGGFGGFGGGIIHHHHHHGHHGHHGHHGGFGGHHHHGFFFGHHGHGHHHGGGGGGGGGGFEEEFGGGGHGGGGGGGFGGFGFEFEEFFFFEEFFFFFFFEFFFFFFEEEEEEFFFFFEEFEFFEFFEFEEEEEFFFFGIFFFFEEEFGGGGHGGGGGGGFFFEFFFGGGHHHIHIIHHGGGHHHHHIIIIIIHIHHIHHIGHHHIIIIIIIIIHHHHHIIIJIIHHHGGGGGGGHHHHIIJIIIHHHGHHHIIIIHHIHIHHIIIIHHGGFFGGGHGHGHHGGGGHHHHHHHGGGGGHHGGGGHGGGGGGGGGHGHGHHGGGFGFGFGGGGGHHHHHGGHHHGGHHHHHHGGGGHHHHHHHHIIIHHHIIJJJJIIIIHIIHHHHHIIIIIIHHIHHIHIIHHIHHIHHHGGGGHGGGGGGGFGGGFGGGHHHIHHHGGGGGGFFFFGGGHGGHGHHHHGGGGGHHHHHHHHHHGGGFFGFGGFGGGHHHHHHHHHHHHIIIIIHGGGFHGGHGGHHHHHHHHHGHHHHHHHHHHHHHHHIHHHHHHGGGGGHIIIIIHHHHHHHHHHHIIJJJIIHHHHHGHHHHIIIIIIHHIHHHGGGGGGGHHHHGFFFFFGGGHGHHGGGGGHGGGGGGGHHHHHIIIHHHGFGFGGGGGFFGGHHGGGHGIJIIIIIIIJIIIHHIIJJJJJJJJJJKKKJJJJJJJJIIJIJJJKJIIIIIJJJJJJJJJJJJJJJIJJIJIIIHHHIIIIIIIJJIJJJJJIIHIIIIJJJIIIIIIIIHHHHHIIIIHHHIIJIIIIHHIIJIIIHHHHHHHHHIHHHIIIIIIIHIIIIHHIIIIIIIIHHHHIIHIIIIIIJJJIJIIIIIIIIIIIIHIIIJIHHHHHIHHHHHHHHHHHHHHHIIIIIIIIJJIIHGGGGHGGGGHHHHHGGGGGFGGHHGGGGGHHHGFFGGGGGHHHHHGGGGHHGHHHHHHHHHIIJIIIHIIIIIHIIIIIIIIIIIHHHHIIJJJJJJJJJJJJJJJJJJJJJKKKJJJIJJJKJJJJJKJKKJJJJJJIIIHHHHIJJJIIIJJIIHHHIIIHHHHGHHHHHHHHIIIHHIIIIJJJIIIJJJJIIIJJKKJIIJIJJIIIIIIIIIIJKKKJIIIIJJIJJJJJIJJJKKKKKKKKKKKKLLLKKJKKLLLKKKLLLKKJKLLLKKJJJKJKKKJLLJKKKKKKKKLLLLLKKKKLLLLLKKKKJJKKKKLLKKJJJJJJJJIIIIIIIJJIIIIIIIIJJJIIHIIJJJJIIIIIJIJJKKJIIIIJJJJJJIJJJJJJJJIIIJJJKKKJJKKKLKKJJJJKJKKKKKKKKKKKKLLMMMMLKKKKLLLKKLKKJJJKKLKKKKKKKLLLLLKKKKKJJJJJJKKKKKKKLKLKKKKJIIIIIJKKKKJIJJJJJJJJJJKKKKKJJJJJJJIIIJJKKJJIIJJJJIIIIIJJJJJIIIIJJJIIHHHHHHHHHIIIIIHHHIIIIIIIIJJJJJKKKJJJJJJKKKJJJJJJIIIIIIIHHHIIJIIIIIIJJJJIIIIHHHIJIIHHHIHIIIJJJJKKKKKKKKJJJJJJJJJJJJJJJJKKKKJJJKKKKKJJJKKKKJJKKKKKKKKLLLLLLLLMMMLMMMMLMMMMMMMMMNMMMNNNMNMMLMMNNNMMMMMMMNOOONNNNNNNNNNNNNNNOONNNMMMNOPPOOONNNNNNNNNNNNMNMMNNNMLLLMLNOMMMMLLLLMMLLLLLKLLLMLLKKKLLLLKKJJKKKKKKKKJJJJKKKKJJJJJJJJJJJKKJJIJJJKJIJJKKKKKKKKKKKKKKLKKKJJKKKKKKKKKJJJKKKKJJJKKKKKKKKJJJJKKKKJJJJJJJKKKKJJJKKKKKJJJJKKKKKKKKKKKKKKKKKKLLLKLLLKKKKJKJKKKJJJJJKJKKJKJKJKKKLLLLLLKLLLLLLLMLMLMMNMMMMMNNNNNMMNNNNNNNNNNNNMMMMNNNNNMMLLMMNNNNNMMMNMMMNNNNNNNOONMMMNOOOONNNNNMMMMMNNNMMMMMMMMMMNMMMMMMNMMMMMLLLLKLLMNNMLLMMNMMMLMLMLMLMLLLLLMMMMMNLMLMMMLLKLLLKKKKLLLLLLLLLLLLLLKKKLLLLLLLKLLLLLLLLLLLLLLLLLLKKLKKKKKKJKJKKKKKJIIIJJJKJJJJJJJJJKKKKKKKKKKKKKKKKKKKKKLLKLKKLLLKKKLMMLLKKLLLLLKKKLLLLLKLMMMMMMNNNMMMONNNNNNNNNNNNNOOONNNNOOOONNNNMNNNONNMMMNNNOOPOOOOOOOOONNOOOOOOOOONNNNONOPOPOONOOOOOOPOOOOOOOOOOOOOOQQPPPOOOONNOOOOOOOOOOOOPPOOOOOPQPPOONNNNNNNNOONNNNNNNNNNNMMMMMNNNNNMMMMMMNNNNNNNMNMNNNMMMMMMMMMMMNMMLMMMMMMLLLMMMMMMMMMMMMMMMMMMMMMMNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMMNNMMMNNNNNNNNNNMMMMMMMMNNMMMMMMMMMMMLMMMMMMMMMMMMMMNNNNNNNNNOONNNNNNNNNNNNNOOOOONOOOOOOOOOONNNOOOOOOOOOOOOOOOPPPPPPPPOOOOOOONNNNNNOOONNNNNMMMNNNNNNNNNNNNNNNNNOONNNMNMMMNNNNMMMMMMMMMMMMMMMMMNNNNNNNNNOOONOOONNNNONNNNNNNOOOOONNNNNOOOOOOONOOOOOOOOOOOOOPPOPOONNNOOOOOOOONRPOOOOOOOONONNOOONNNOOPOOONNNOOOONNNNNNNNNNNNNMMNNOOOOOOOOOOOOONNNMNNNNNNNNONNNNOOONNNOONOOOOOOOOOOPOOOOOPQQQQQRRSRQQQQRRRRRRRRQQQQRRQQSTTSRQQQRRSSRSSTTTTSRSSUTUSSSSUUUTTTUUUUUTUTSTQRRRRSRSSSRQQQQQRSRQQQQRRRQQPPOOONOOOOOOOOOOOOOOOOOOPOOOOONNNNNNONNNNNNNNNNNNNNNNNNMNNNNNNNNNNNNNNMMMNNNNNNNNNMMMMNMNMMMNNMMMMMMMMMMLLMMMLLLMMMMMMMMMNNNNNNNNNNNOOOPOOOOOOOOOOOOPOOONOOOOOOOOOOOOOOPOOOOOOOPOOPPPQQRQQQQQQQQQRRRRRRRRRPPPPPPPPPPPPPPPQQQQQRQRRRRSSSSTUUTTUTTSRRRRSSSRQQQQQRQQQRRQQQRSSUTSTTTTSSRRRQRQQPOOOQQQPPOOOPPPPPQQQQQRRRRRQQPPPOOPOPOSQPPPQPPPPQQQQQQQQQQQQQRRQRRRRQQRSSRRRRRSSSSSSTSRRSSTTTTTUUTTTTTUVUVVUVVWWWVWVVWVWVWXXXWWWVVUUVVWVVUUTUTTTTTSTRSSSSSSSSSRSSSRSRRRRRRSRRRRRQQQQQPPOOOPQQQPOPPPQPPPQQQPOOOPPPOPOOOOPOOPOOONOOOOOOOOOOOOOOOOONNNOOOOOOOOOOOOOOOOPOOOOOOOOOOOOOOOOPPPPPPPPQQQQQRRRQQRQQQRSSSSSRRRRRQRQRQQPPPPQQQQQRSSSSRRSSSSRRSSSSSSSRRQQPPOOPPQRRRQQRRRRRRRRRSSRRRRRRRRQQQQQQQQQQQQPPQRRROOOOPQRPOPQSSRSRSSSSRRSSTUTSTTTTSSRSSTTTTSUTTTTSSTTUTTTTSSTTUUVVVUUUUTTTUTSTRRRQQQQQRRRSSSSSTTTSSTTTUUWVVVUUUTTTTUUTTTTTUTUUTTTTTTUUVVWWWWWXXXXXYXXXWWWWWVVVWWXWXWWWXWVUVUZYWXWWWWWWXXXXXWWWXXYYYYXXXXYXWVVWWWVWWWWWVWVVWWWXXXXWWWVVWWWWWWWWWWWWVUUUTTTTUVVUUUUUUUUTTTUTTSTTTTTTSSSSSSTTTTTTSRRQQQRQPPOOPOOOPPPQQQQRQRQQPPPPQQQQQQQRQQQRRRQQPPPOOOOOOOPPPQQRPOQPQQOOPPRQQRRRRRRRSSTTTTTTUUUUVVVUVVVUUUVVVVUVWWWVVUUUTUUUUUVVVVVVWWWWVVVVUUUTTUUUTUUVVVWUVWXWWUVVVVWVVUUTVVUTSQSSSSTTSTSTTSSSSTTTTSSSSSTTTTUUVUUVWVVUUVVUTTTUVUUUUTTUVWVVWWWWVVVVUUUUVUUUVVWWWWVVUUVVWVWVVVUUUUUUUUTTTTVUUVVVVTTUVVVUUUUTUUUTTTTTTTSTTUTUUUUUUUUVUUTTTSTTTSSSSTTTTUUUUUUUTUUUUTUUUUTTTTSSTTUUUVVVWWVWVVVVVWWWWWWWWWXXXXXYXYYXYZZZZZYYXYZ[[[Z`]]]]]]]]\]]]\\]^^]]\[ZZZZZZZZYZYZ[[[ZZYYYYXXXXXXWWWWWXXXYXXXYXXXXYXXXWXVVUVVVVWWWVVUVVWWWWWVUUUUVUTTUVUUTUVVVUUUUUUUTVUUUUUTTTTUUUUUUUUUVVVVVUTTTTUTUUUVUVVWWWWXWWWWWWVWWXXXXWWUVSSUTUUSSSSSSTTTTTTTTTTUUVVVWWWUVVVVVVVVVVVWUTSTVVVUVWWWVVVWWWVVVUVVWWWWWWWVVVVVWXWXWWWWWWWXYYXXXYYYXWXWXYZ[ZZZ[\\\\\\[[Z[\[[[[\\\[[YYXXYYYXYYYZZ[\[\[[\[[[[[[ZYYXXWWWXYXYYYZZZZZYYYYYYYXXXXYYYXWWVXXXXWWXXWWVVVVVVXXXXXXXXYZYYVUUVVWVVWVWWXWVVUVUVWXXWWVVVVVWWWWVVVUUUTTUUVVWWXXWWWWXYYXXXXYXWWWWWVTTUVUTTUVWXXYYYXWXYZYWWWWVUUUUUUVVVVTTUVVVXYZYXWVVVUVVWVUVWW\YZ[[[[[[YYZ[ZYYXXWXXXXYZ[[\[ZYXWWWWWXXXXXXYYYYZZYYZZ[[ZZ[\\[[[ZYZZYYXXYZYYYZZZYYZ[[\\]]\]\\\[YXXYZ[[ZZZYZZZZZZYZ[[\\\\[\\]^\[[\]\[Z[ZZZZ[\\[ZYYYYZYYYZZ[]]]]]\[ZYXWVVVVWYZZYZYYYYWYZXXXWXXWWYZ[ZYZ[\\[ZZZZ[\]^^]\\]]\ZYYYXXXY[\[ZYZ[ZYYYYZYYZ[\]\\[[[\[ZZZZYYYZZZZYYZ[ZYYYZZYYZZZYXXXYYYYZ[[ZYXXYZZYYYYZZYYZZZXXYZ[[[[ZZZYZ[[\[\[Z[ZYYXZ[[[[ZZZYYYYZ[[ZYYYYXWVWWXXXWXXXXXYZZYXXWYYYXYYYYWWWXWWWWXXWWXXXXXXYYYXYYZYWVWXYYYZ[[ZZ[]]][ZZ[\\[Z[ZZ[\\\[[[[ZZZ[\\[[Z[[\\]][ZYZZZZYYXXXXXWVUUUUWWYZ[[ZZYXXYZZXWVUVVVWXXXYXZZYXYZYYXXXXXWWXYZZZZZYYXWXYX]ZZYYYYZZ[[[[ZZZYZZZZZ[[\\\\[\]]]]]]\\]^^]]\]]\[[\]^`aaa`^^^___^_^^__`_^]]^^^]]^^]]]\\\\]]]]]]]\\\\\[\\]^^^_`__^^_^^^]]]\\[[[\]^^^^^]][[[[[[\]]\[[[\\\\]^^^^^^_^^^]\[[[[[ZYXYZ\]]]Z[][\\\]^^^\\\\[[[[[ZYZ\]^^^^__^]\\]]][[\]\\\]]____^]\[Z[\\\]]\\\[ZYXXWXYXWWWXZ\^^__`^^\\[ZYXWWXYYZZYYYYYYYYYZYYYZZZYYZZXWVVVWXYZZYYYZ[[YXXYXXXYYXXWWXYXWXYYZYYZZ\[[Z[[[[[[[ZYWVUVXZ[[ZZZ[\\\\\\\]]\\[ZZYYZ[\\]\[Z[[[[[[\\\[[\\\[[[[[YYZ[\[[Z[[[[[Z[[ZYXYZZZZZZ[[[\]]\\\\\]]\\[[\\\\]]^][[[[[[\]]^\\]]_`_]\\\[Z[\\[[[Z[[[[[ZZYYZZ[\[[[\\\]]]]\\\]^^^]]\[[[\\[[Z`\\\]__^\[[\\]]^^__^^___^__`_^]]\\\\[[\\\\^]^_acbb`_^]]]^__^]]]\\ZXY[]]^^____^^]]\\[[[\]]_aacbaaba_]]]^___`a`^^^_```adeffggjighjigedfgfcabbba__`aa__`cedcbbaabb`_^^__ababbbbbccdcc^_a___]^^^__^__^^]]]]]]]^^^^^^]]\\\]]^^_____```_`__^]]^]\ZYZ[[ZYZ\]]]^^]]\]]]\\\]]^^^]]]]]\[ZZZZZ[[[[[\[[[[\\\\]]]\\[[[[[[[\]]^]]]^^^^^]]]]]]\\]]\\]]]]\\\\]]^]]]]\\[\[\\\[[[\]^^__^_^^^^^\\[ZZZ[\]^^^^]]]]]]]]^^^____^^^]\\\[ZYYYZZ[[]]]]]^__^]\[[[YYZ[\\\]^^]]\\]]]]\[ZZZ[ZYYYZZ[ZZ[[[[\\]]]\[[[]^_^__aaa`_^]]\]\]^__^^^_^^^^^^_^^]]]]^^^^^^]]]]]]]^^^^]\\\[Z_\^^^]]]]]^_`_^^^_^^^]]]]]\\[[\]^_abaabb``_`bca`^^_``adeeda_^^__^]]_abdefgghhecaabbbbbdeffgjkiebbb`___`abcdeghiiigfecbcdeghgffedb_^^___`ceefdefgijkihfeeecaabcddca`_^]]\\]]^^^^_`b^`a^^^]^]]^]^^]]]]]\\\\]]\\]]]]]\\\[\\^^_`abcba__^][[[\]]]^__ab`^]^]]\\]^^^^^_aa`_^^^]]]]_^^^^^^^^]^]]\]^__^]]]^___]\\[\]]]]]^___^^^^^]^^_____`bdeffedb`__^^^^^]^_`accb________a``abbbccccddddffgecba_``aba`_``aabcddeefffeccdeeeffgfghiigfffdb`^]]^____`adedccddcccdefggcb`____`__^]]]]^]]]^___^^^]]]]][[ZXXXXYYZ[\\Z[\[[\\\[[\]]]\\\]]]^^^^]\\\\[[[Z[[[[\]__`h_```_^^^____abcddedc`_____^^^__`bdddbbabbaabcdacdfggdaaaba```aa`aacdfgfeffffffggihgedffdcdeeddfhiiigeb`_^_`bbcccdeeda______`aabcbbcb`_^^^]]]]]]^^^^^__aa`ccdccbbbbccdefeedddbaaab^`_^_^]^_acdcbbaaabceffggfghhggggfghhjjjgffffffeecbbcfijjjjkkmmnoonkjkhgfddddeedddddcbbbabbbcabbbcceeffecbbcca__``ba__^^^]\\]____ab`______^^]^^________`^^^]\\]^^]\]]]^^^`aaa``__^^___^^^^^^__^_`aa``_^^]^__acdeeeeedeeecb`__```__aa___``a`acb`______^_`adghgfeeecb`_____`aba```a__`bccdcabaaa__```bb``____^_____`abbbba``___^^_```__^^^^^_____adedbcddb`_____ahaeeedffgggghjklkiffggffddeghhhhgghgghjkjiijjjkkjijjkkjhgeeecccccbbabceeedcbcdefggeefgihjiggffefeeedeeefdddeedcca``abaa`__^^_aaabbbba`_________^^]]^______^^]]^___`````__`aaa``aceadfdeb__]]]]]]^_````_``__a`_^]]^^^^`aa`bcdffeddcbba_^]^__a`__^^^^^^___`abbbbbccdeddccbaa`aabbbbcba``bcccccdcdeffeeeefhkllkklmlkkklklmlkllkkklmnooonnoomkkjlmlllkigggijjkmmmlkkkjijiggefgikkkihgggfgghgffggfdb`__^^^^^]\]]^^]]^^^__`ababcbaabbbb`bccbbabbba`_`___`bbccddeghijjjkklkkkkklkjjjihiiiihhggfddcdcccceeeefeffgijjjjjiiijkljihgggggedcbb``abaa```abbcafmdhfhghhhijjjigghghhhijklkkjihfffefdcbcabcceeecefgiiihghjiijihhfghhfedcbbccddeeceffhhihhhgghgffffffghkkkklmnmlkjiigfggffgffdccdefgigfgghffgfgfhhiiikigfhiigggefdccefda_]]]]]]]^^^^]acbdc_`_`__^^^^]]]]]^___^_^]^^^^_bccbaba```aabb`____`aacbbdbddcca`___adeggfeddbcdefddcbcccbccbcaacffhijjigegfeeffghgfhhijllmllkkjllmnmmllmnmnnmkjjiiijjjjihghhhhhgggffedccfhhhjkkjkjiifdddeedeffhijjljhgfedddddccaaabcbbdeddccdfffggghggfgfeedbabbbcdfhjjlnmllkkjkjihghgghiihfeccbcbcbbbabaceeeeedeeeedffhhggijjkigfeeddbdffc``__`a`bbccbdfffgdecbccbbbeefccafkcfdhgiggdddccccccccccdcbb`abcdeddceghiiiiiijhhgihiijkkkmmmklkkjjjjlmlklklllloqsrpoorpnoonnmmmlmllihhiihiiihijjklmllljjjiihhhghfddcddefeeedeefeeddccdefeddedfeedccdddffhjmllnossspknliifefcbaba`a`___^^^^_`bddbcdefgghiijjklllmlmoosstuttqpqrrsutqrqqrutsqssvwvpnnlkkklllllkkkkjiigfegggffffddfffhhhijkkkiijjjjijkjjjjjiiiihhhggfgeddcddcccccbccbbbddcfghjhgggfgggggeddedeefgghfghgfeeefeeedffedeedca`abbbcddeefeeffffghijhihhhhiiihgfefefhggijihhgfeeefhiiigghhgffffgfeedddefeghhihiiiiiiiihgeeddddeeeedccedddeeffghghhggfdedcdcbceefededeeggihovkonopssuuz}}~zxvvtqnnnnlkjllnorrrqpqprsux{{{|~~|yxwwwwvvwywwvturooonmmlmlnnnnoqrrqonnoppoptututrrpoqonmmmmnonnnmnnnmllklmmmmmmlkjihghihghfgfffeeefgehhfffhffdddfgegghgffeecba`___^```a`_a_`_````__a```_abccefdddcaaabbcdcdecbabbbba`aaa`_``adefgjjiihhhhikkjjiiiiggedeffhihhhiklkjilkijijkkmllkkkllllmkklllklkjjjkjiihhgefgfffffeefegillllkkijklmlmnmnnnmnmlllmlmlkkllmoomnnopposppppopuuwyxxxwvuonnoopoooorrrqoonnnmmlmllljjjjikllnnnmlllkklkjjjkkkjjhgfddcccccdfffgddeccbbbdeefggfffdba_`abccedfeeggggfdefefgijjiijkljjkkkkjkllmmjijhigfegeiekngihjknlmnnopnnmmmlmkkjjkkijjkmllmmmmlmmmnnoqssqonmllklkkjkkkmnnooqoooooppqpprqqpnllmmmjijjklllnnnlnnptuvvvspoponpqqspronpoortwwutsqqwwxyy|{~~}{|}~~|}|{vvtponmkmljjijlllkijjdeaaedbfegggfffffeefffeddb`___````____`b`adbcdbabccbccccffgeffghghhhihfhgefegghggggjlllkjigikklllonnopnmomnklnooprrortqqrqrqproqrpqqopopqonopomljkkkklmllkggihiigegehgghgfeddccefgfghhedeeffeeehijkhikhfeeghefiiikhiiffilkkkhghijlmnnnonkljlllnpoookmnnousrtssrtv{{xxtortsxsttrtrpssrwuorsnoomonnnomqppopqmkkjiijlnomnnnnonnkklikkjjijjjkkihkmonknuqrttvxrtssoz{qwrrqvuspqooqoppnnmlmmmmmlmmonnooonnmonmmmnnmmlkkmoqsqnmkihihgjjmnnmjiikmijkikmmnnlljihgggfgfgifhfgfggffgfhifigegffgiffhhjgfhfefgkieggeihikkkklkjklonorqqlmpmmppooororuwvrquruqtmlrmmomlpnnnomnmnquswx{}xxvqqqpponorrtvvuvuy}{{y~|{}|~~zy{z{|{{wswtu{zz|yxy~{yyvtrutwxzwxxvuwwvvsuuvstrtrptqoropnkknmmmmkkjhjjjjjhikkkigggefedbab_`b_`adcececbdbdefcfdcbbbbccdaaa_```abaaaba________`__bbccb`ddfgfeddddcdbccbdbcddeeeffffhjmmmmjijjikmlmmmllklnmlllnqoqotrpuwtyvuxxxx}xz}|}y|~~{}||z|{{}}{}}}}|}|{yzvuvrorpoqpsyvzxvurosutsvwxrsqtnuwsssvxzxxx}xx|}|ywwvuuwvvvooqrqturtwtoqrpstsurpopmmonmpnmnllkkljijihikiijgfdeefeefgedeggdeefjkmnkjkhiijknlkmihhefhgghdeecdefgfdfcehggiggggikjkkjjjijkllkjjijkklllnllliiiljjklkmihmifihhiikhihklllonomnmkljlllmlnnlnnpmopqsyxvtqmlklmmmlnnmmmllkllmmjkkjkkkmmllmkkkjgijiknomnqonprrsupsoooppoqqsooqpqqpsqpsrrrppsrooopuwtuwztuoqwyuyuvwuvuprrorvsssundwhqommqnnmolmmlklopoosq|lzhunolnlkjnnmmonnoolpnnmlmnmoommpqropqqomllolporoomoqosooookmnntsvsrnoknnnnnmmsjpnmmlmnoonssrrqppntwprrotormvnuonpvrvuxvwwuwz{{vuprnrowt|ry~ytvyopkpjlinnpkwzotnoylptpvzxz{qtrproost{ypolmvruouotpoqqtrtsropqrwv|{}twppvuyrxsvqoopoorsvpspqppyuxoqnlkmkjimjklklommklihjuinifgedebf`eed`edhhejkijgkkkjnimkkhkintlqookmmnlnknnomqytswr|{}nqlxieliiqjjmmkjkmkjililljmiknnrplppouvvionmiejnnjkm{mpmnnjhjkkiijkgkgmojiljljikljjekmjfhhljiknrmnmnykvlmommokpnpmjipjlhmjpeniqgxhomomlimlnollqmporx}pt|twu}xswv|rvuuuyvxrwusnwqvwo~zuu|oqwkzzmyykrkxmujvuptlzvroz{{vy{tvyw{sv}uxytuwovprprott{uwwywnqlsvqmnlllgkklllnsronnqomlnlnjkoomklkpknmxnsimnoltr}tspwmtmwmuirkonnrqrquktlomkjjmglgljkhilmmjqntmkjmwvmxtvv{wx{vuslpomnlsromqrtlmkjnjiglkolkljmmkillwpqlstxsoqnnkkgqonlmsqqltmyqnmromhgjhgab`jfdblllhflnomnozxlldbcc```_babfgggddjlsokeb]ZYXUUSUSSSVX[[msg`YOMKIGFEIJNZj_cj|aTLGB?>>>AFKRiug[SOPkgNFB??=<>DKRXle]XUOORh~gSFDACCABIO[jg]WWUUXetj[MEDBFDEGOVdvk_[VVTY^ujbXMFECFFFFMO]cwhj[]Y^^`_VLHFFHGFIMPZdulc_]bhyeaVNIHFHHGHJMR[jtic_lkomfZRLKJKIHHJLOU_f}hc]^`gn^TMJIIGFDGILM\ck\YTY[hhYMJFGDDCEHJMVf|oaZWW\_zm[PLIGGGGHILNQYgxlcZXZ\d}m_VOKHGHHIIIKMOX_lsf^\\_f}ueZTNLIIIKJKKLOS[gszgb^_^fsoe[VQOONNOOPNOPZ`im|lgceeeyneYTRPOPOPRPOOQ[afm{michjtld[WTTTSPPQQQOOVagoqqovz~shZUSUUSQTY]\]Zb__\igydji|yr}jd_^^]^aglklunmrfe^][XURSY[a_mzz{|y}|rxoohead_b]_^d_hi||~q{lwiljpmxtw~yrwjoeqeshjjqu~{}wq|kl`g]jZj[o\_dlnq~nokjjnnpktozn{m~n~mli~htiolnnmnnooiwg|dydtescuj}m|sy}vvxqlqjoitlxpzu{xsvsqogiejhedhfjglnqrumrkpl~s{jomtknmvuyv{rws}ltjndifjcjeijmnv|upolrr|oxo}}|wnoniigjhojspwxxunoomlknlmijotx}zzyyvrry}}n}nvkmdlfkeccgjotn|w}}r~ojjvfi]h_c__^a_cani|isv|{|yqpr|{kmbd`_^^_a_a_heujymrotzwywtu|hjef`c^f_c^bdmmqnz|}st|~znpkiiad_a\`]h`ykmvzpj~k~jnuwhudmdfadeiiqo|}{uqi~n~vt}vy}mtjnhmhpdnnz|wwpztzomwlwnxp|qpjjinhkglfnkrwx}uoxvo~mxsx{zuuktktkulnijfghhiiigfhilur~xrzy~rtommoqsvpllmlllmnmlknltoyoxmwn{{torv{yznylsmqhpgsfre}d{dvfu_sgpklnoys|x{yz{tomwilhmllokyjimjn{nvqwuwrqrvs~}t{pvovnqrturyswpy{zvtxuspzp|y{~zwwz}}trnxnxtxtyy{|z{xxvyrsnnoy{~tznsjkgmhfdai_l^j\l^k_ffhjimnvw|~yullfa_^\_W_V^T[VYWY\^bfjoy{|}}umiba^e[Z[WYSWP\Y``gmyxupzx~{stjc^]ZWUSSRRQWVa_xr}mg`ZZVUPPNOOXXadnxyw{hi^\VUSTRQQQ[\hg|}uwhc[\VWQROROQWZhh|umofo~ic`ZXROMNKMLMRTY]e}{xlohdcip|{jbaZWTQONLLLLSX[aiuwogfllwgd]WTOMNLLMMX\gjynlmzype^VUQOOMMNS]bn|{nihjuvnaaUXPQNMLNO\^hn|noko|umb^VUOONLKLMVY_l{syfecgmoosuhb^]VRVOOMLMOS\Zmwj}ou{|upkg\]XVONMNMSZ[koyuuxzznf^[VPOONOWW^ltssrwy}fd]WOONMMSTW_dvhjgccnuwj^[UQNMKLMQNV[cw{jfg_a`hnwze_ZTNMKKIJNMNZXlohn\^^]bcnuli[WPOLLJJJMLNVTccnma_^Ygfif`YUPNLLKKNKTR\dpkt_nklqf]UUNMLJKNLOXRla|okxhu~me[WTOMLKKMNMVO_]mnzdsnu}vif\YVQPNMLNNLVM^Xjm{ikmhxnswlh_\WUSOOPSOZPc]runtvo{yj`]USONMNNMWNaXnvldnkjws|yjd]XVRPNOPNXP`^piqcgeilo|wwhaZVQONNOPNYRd`}saj]bbgovpd^XSOMLLONNXRh_gm]gYj^mnuc^XTNNKLKNMOTRd]}zogbf^gatm~{c_VSONLKLOLVP[_ojl\aZ^^ehuj_ZROMKKKNLNVSheif][][_droi_XROMLMMQN]Wntof`Z^_^jx|c^TSMNKMNSN\Zmvwiccqi|j_UTMNLMLRNX\hn]^\_`ftoaZROLLJLJQOU^cxia\[\_`jwwe^XUOMLKLJMMOUYes|nc_[ZY]_fmwune`\YXXVVUTXWZ]chm~orilfjgmkomptzzx{nnfd`a[][Z[\^_ejjlzw~~xnokjmffhehjjsssz~~}vzuryovrronmijjigiiljkknmoux}z}zxtqponolmmllnknlmnmmlsqwwy~z}~{|~vyxropnmknlkiknlnopuuoqsrqnvxqouutqrsv{}wvnpnjifefddgehjlontnqrsvqvnmjkjmjmnlny|zoljhicddfgjns}{uonpswz~zxnmmmmosz~}qpnonww}|spnpoorsz~xjtxujtzswxt|w{pnqrssjpuz~ysw~{zv|v|zokmotqklhdabbgjn{{vzr~mvoloqvu}zrrhgcegcdefjnot}~womlgc__][\Z[YZ[^djw{{uu}z~{phghd][Z[YY[\\^_edlnnxzxuuy{~ojcadbcda`^\YY\^cjv|w|urrtrpmjhg`]\\]_ehnyu~vonpofb]]\ZVTWX[gpz~||he`ZURPPSV`nzwqv}}j_[ZXXWY]`d|uoyw{|x{}mkb`_]XXVXZZ\myxzs{y|vnzoec\^\\Y[\]eqmy~xrumc][X\\\]p{}{{wysne^XWXXY]iowt{|uu}{yw{ykkgc\YTQQQS\kvuyxmnp~x}xwomjle]YZWTTUV[jowzzqoxqnilgrvroji]VTYYXXinwqopkkekzynsx{xu{so{~zyule]XUUUUYgjolns~nim}vvqll}~{z}wxssli_[XXWWT]kklguyoahn{vovw|tqfab_\\ZYXYkfhdmqoeit|qoyzymjc_[XUTRW\]ehq~xpkhia^ZWVTS]_entynrx|ngf_[XZY\Y^^\`_pwq{}~yxrllih`]XWVURV][`cknjj|{~|toj`^YVSPRRWYZ]`cfhop~}{urkc`\WUQPORUU[]_bcmu|}|~~{le^[XWTTRTXV[Z\cfnzwput~|~~ynqid_[VTPNMMONSW[deowtzmec][VTTSWVY_\abj|vh^\XUSOQPTZXbep|||ng_ZWROONNOPUY_kq|ng_YVPNNNNOVW\^iw}~wzqqhd^ZWQOMMLNOQWZdiz|uqqid^\YUQNMMMPOTXZemzv{vqogj^]XVQONNOSPWY]gv{snjhca\YTROPNSSY]gnx}uuqif]\XUSONOLONSV\it{wkj__[YTRNMMMKNNRUZag|}|ynmkea\\XWSQNNMMLOPU[_pwvojjeda`[[XUSPNOMQPTY]kp~vnlg_^YWSQRQPVV^cn|zoib[YVSUVV]]fk|xxqkeb\YXTQOOPOQXV^cvxwyqoilfb__ZYUROMNOMSUU_bx|wtpihgba^ZYUSOOPPPWX]fpz|tuojjc_][XTQONNOOTZ\dm{zvxpomgd_\YWRQOOPRZ_gr|rtwwutmgc\XVRPPRQSZ^doxwrni`]XUQOOOPQU[`gr~~{{trnhc_[YTQOOPPSVZ]bk|vokf_]YYVPONOOOOSX\bnvojea]YVTRQQQRSTY]aht{sqmjg`]ZXWURQQPPQRUX]dp~rnlfa`]ZWUSQQSUW[`ju|uolhf^\YVUSQRSSTW[_gw}ypljhd`]ZXVTSPPPQSUY^enz|wtqkfa]XUSRPPRRTW[_enzookga^[XUSRQQQQRUX[_hs~{wqnmklfd^[WTRPOOOPRUY\`jpwpkfb][YWUTTSSTX[^fo~xsnleb_\ZWVUUUVX[]bho~}sskffa]]ZZZXVVVWXZ^cho{~|ttpllhgc`]\ZZZ[\]]^_dhot~ztpjifdb`_`__begknrzvtokhejhfhifhjklmooppoorptw||tojhhehfgdefghjlmnonponooqqsutvyyy{}|}}{||zyxywomkljigebbcccfhjkkmnnussuuvwtyyuywxvtxx{~~z|~ysuppnlmkhjhhjggijmmnprqovrszz{~~~}{wupmmjkihiijjklloqy}{~||xzxxvwyy|~|}xrtpnllonmkntortzv}zvx~~y}}}}z}t{ontmyppxvmpq{z~~}}vv{r|o~{{v}{|~||vwpp}moxiluei~hixnrxuz|}|xumonpupjklngjrkhjslmrkyoiqkzmpvv{ng}l|w{mulxqtttn}m{|ws}|w||~y|xu|~tz|{{t|wsvmnvlnsn}wuwy~|w~}t}utupovttzz}z{|wvwstl}onmnihjghijnmtowlqvm{nvyzyuvoroosorpunsuslsrmwpurqvpokkmjjknmkjgkmnptswvtussmmsovtswtpwusuopoopsosnqjkolnpquuprvu{s~~~}}ux}t|tqxvxxw{{wuvysvwwxssv{x|}}{~{{}z~~xwusstopomjkmorrvuwrsusvvtvuyvzy~{yqnlifc___]]\\[ZZZZ[\^admu|tnmjifba^]ZWTRQPQQTWX_al~|ohb^[WTQONNNORUY^bku~rle_\ZXVTSTTWZY_eh~~xqmjjmosysle_]ZXWWVVWZZ^cdoz{znkjfghinmsy}vrlgg_][XVUSUWX[__gr~z{uuzzyonh_^[XXUVVXXZ^]iku|~xv{s{|usnd`]ZZXXY\Z_`frxxrjca^\[YYZ[]a_jty|t{zznkd]]ZVUSQRRTVY[ben}}ysmlmilllrsywqrmlga_]YXVTUVWXY\^djz{omjedbbeeiont||~uunmjd_\ZXUUVWX\]_hjwvmjjjjoqu{slhca_^]^^^cemv{wt|znia][WXXXYZ[^_clvpldha]YXWVXZ[\aioq}yrjgc_\YYXWYZ[^cms}}{pwxxvw{olifa][YXYZ^^abilmy|~{skgc`]][\]\\\admu~{|{{||{tnlea^\[[ZZZ\^_fiox~~}{wujdb^\ZYZZXZ\]^ddklrytohc`][YXXXWYY\acfmo{yoid_^]\[Z[[[]_djru~uolheb_]\[ZZZ[^_cins}}sonkic__]\]]^^`fioxwy|ururxvxvtolggbha_a_`deklv|~}}|{|}|pmkfdceegfhmux~}wunkjiffgjgijmtz{~}}~ywtnkjhebdceefehilro{zsvnmkiifdcc__cfehjnrw|{||~~|upqqmljjhhhhjjknosw~~|wxuomnkjlkhmmnt{~{~|{||vsuuqpqvottxrwwxyuz~}|~~|yysqomnmlnkmmkilkklnnortvrtqoosvvyw}zuruqoosopqttpoqooorpnrukqqononnnoonptw{x|{|{yy}|~}{}z|z~}|}~|~{ywuwtppssuxxxy{z~{vyyx{yxzyvz{xx~~zzytwwxvsvuxz}}}~~|~zw{ruomrurvw|}~xwv{}~~}|xvroklkljjjhgghhhklnqtvx|}}|tuponkmmnmnjjhhgjijlnnrsw{|}~|{y}wrtrnmmmklmljlkkkmmosruy{~yvvrqoponmmmmnpsvw{|}}wxurnnnmlmmlnonouz{{zztwuuvssvooolmkjjjiiiirklmnnorqvvtuusvy|yy~~~|xuoonmlonmmllllpnmonoppprtuswyw{}|{zzvwyqrpommmnmrrvtzyz}~~~~~}{}zz}~{|{|ywy{x}~~yyttqrtvpponloklmnnooooqonmnnnosquvvuwtwvy{wwyvuwvstvsrqonnooooopqprrsstvyutvxsqtrprqsoqssqtttsuxxuwwxxw|xtsrrprqqtrnqooqnooqnnorqqtvusuyuvxzy}~|~z}~~{zz||~{}zywxuwwxvruuosustvtuzuwz}z~{z{{sz{wy~~~zz}zx}~{|{|||}~}||~}~~zz}{}~}}}}}}|xwwvvvvvwyvwvvtvuvtswvttzvvxztx|yz{|}}|~~~}xy|y{}yzyzw{|vwxttxwvuwsuqpqqprooqurqspmmmlnopoonlmmmnrrwxxwvvz|{y{~~~x|}|{~~wvzvy}{|~~}}~~}~~~~~~}|~|||{xyzzzwwtrprpopqonnmkmmlklmlmnmmooprtrqsqoqqopossrsutstrruvsz{}}}}}}|~{zyzy|{xyzxxzyz}~~~||{xy|||{|{zz~}xx~~}|~|~zz}{y|~xxxvrtvttsssnpqopqrrttstrprpptquzrosknpnoonsqoomnnnnnooonmomlmnllmlmmlmmonnoqqpooqropoopopopposrrusssrqtttwwuwwstttsvvv||y{zx~}w~}~}}zvzzw{}{}|}z{z}{}~}|~~{|zz{{{yxz{z~~||{{|}|z{ysuwutwxy}|}|z}~}~|~|}z}|||~wxyzxvvvswvuttrqoonnpqooqpnqrnoqonqpuvyx{z{ywxwqtvqruqoonnoprtux|}{{|x{zy|~|{{xyvrrwxvwzyxvvwuvzyyxyy{z{zxx{yy}{yz{xyy{zzzyyzzzxz{{}|~|~|z{}{y{{~|yyzyzyy}~z}}}zzwxvrxurvqsrqqqponpppppqqopsqpqqoqrotspstrtwttwwvxwy{zzyvtuustttuvtvuuttutvtvxvxy|yzurtvtsstuvvxxyyxxyy}~~}}~~~|}}~~}}|~|~~~~}~~}|z~|y~|w|zzsspmnmlmmnonnopoomklmnqponmkjlkkkklkkigihghijkkljiiijjlmmooprsonmorpqusrqpnqqrtwyzuuzwzyz|z~}{{xy{~}{}vwyvtttuvuswx{~zx|{}{|{}|~~}|}z{||~|}{|{}|}~~~|{{x}~}{zxsruwxvxyuwvqrrsoqrptqoqtuttuusrsstxxwusropvuwuwz||{{zz{yz{xrxwrxutwzwuuuvzxwwyz{zx}zy|{}|~~}|~}|z{}zzy|zuzxw|~~}~}}zxwssvyzwww{vsnnjm}nurvt|~~yvyxyz|~|zvx|zvwy{~{vy{|~xusssppqwwxwjokjnooosroupqmlllnmnmlllsprtornqqwssww|x}zywuqommopvpouq}{otmxszwrwxswxy}xx{~y{|vv~zuw~sux}{~xz}zzyr~z{}v|w~s||z||}s{|{vn|oruoyx{vpvtlxioqj|lvtjylvtkqhiognlirdifdrhqljsfifbk`heamemocvckm`wcmoc|bnoo|i|tjinn~iuplorlpoyrzxv}t|sx|ow}qqtmvyttom~wniwhjrvfatxcco~_cnu^~cn~bgibsgaxc`y}d`ua_dcc_~~_^|\^|]`p\bp]go^ek^fk]gmalfd}q{kwkrkqjddmomliz{oxlsnsmjimruno|yoqkylvot}nm|ixxixqdvji|lfuhasf_ne`mg_tjc`sheq_ngmyi}nkrdlfjlkmigjcfcfiilhijekfllhmihidkilmiolkmfmejkinhnlfrevomcgtit{ilucktmqhgoxzu~ty}~~}~}{~zt}|{}y{}|~{}~x|||v{}~~|xwmsxuqq}pqx|vtswzpp{l~gqoh|gptfkvdi}ga}lg^`iu^_rmb_nnepnmvovuzhymovmzqnllsooqvw{pvqs}}vslhjlhngkgidfgieielhldnmktj}uskn}~jlwrh}f~mjxhskkvl~y{vvvx{}~uyzk~ou{rn|xtrvqy}uyzyzu~~{u}t~~~zxw}zvzz}p{ws}svvouourmquvxwwyq|qzyy{x|{qtwuqoxxz}{s}}~|~w}|~~zvzysszznv~~}~zuysnnmmkklmnnpmonstx}}zysvnklfgedfegffefjip|ztpkjieeba^]^\\[[\^`ddiq{qvnvqox~pjhdc^\\[ZYWWWUVRUTTZY_biw{~{nmffffll{rmjec_]^]\[[XXWWYZZ^baox}|wsx{p~~pjf_^^_]]]\^[Y[\]ejoxnnkxzzlhghgeaa`^^[\`^hloz~~rkjec`^_]`_^^__clm}|ojhhjjm~pjdb`]^\]^\\[\\\bejtofgfjihm~pli_^^\[[YWXVTVVX^_dqxvjhbijlkqtokc]ZZZYVUXYZZ]dluviegknqpphc_\[ZYXY[ZZ[_l{phhbhkmtziga`][XXXWWWUUWYbfmoomlnowmc]YXWVUUUVVUW[_grwnmnnmn|ohb_][XXXYYY\_gn|yomoyxtnif__][\Z[YWWX\\aahu|}|xqikjmmjlgffhifecbcehlt{tqoqmmnnihgibdaecfknrz}|x~zx{zwqwmjlkphljltv{nq}|||}wpllmfebf_faghk{r}qluhsmkkfeddjjpwk~qxpr{uwkmeldibae^fdgkeubxfytolmodkbgc^e[`d_j_lmu|~rmpvw}mvjjwby_eoauidzixx|oxq~~}osw}~tyx{{{zrqwmzmf{npzkyqosqm~lkvjvmt{t~}w~}{s|sn|mlviomjpkoly~u|~qzoepiekgdnmzp}t{~xxrpuwv{lylpmluhvorojmy}w|~y|whyljgdceebfkltvwykxr{owz|uk}}kp}~w{n~yq}z}wz{qowyo}utpy|nphsqimjfm|m}|y|u|yov}vwp~oourllyml}my|}y~xws}|y|}}xyv{yqnvqkuvrt{oq{}~x}nzozqnylmpgmpjomuqtzszz|sw|smonlpmo{xux||uuxlqmjkjomorpqw~}{ywpppyxv{}~~}~z{wyvx}x|{otksojnqpsuu|yvuvurlmupyuu~uy|z~~xy}uyyt~|y{{y~v~vsrpqzwu}|z{tnqqoonklmowt{}}pkida^\\\[ZZ[^`gq~jk\[WOONNNORX\]i}rkf_corrf\UQNMLLMNQ[]hnlc^bcsxbZSNLMKLMTYZesnhadeu}oc[QOLKLLNW[cld^Z[^bhe]UOMJIIJKOVYjvo][YSQTW[]v^WQKMKIJIIKO[[t|l\XYTTVZcjw^XONMKKKMOT^kum^Y\]\\asw_WUSQOOTY[aoprmzlfetoaZXZWVTWZ]`mzylfnhfdn|lf^YVTPRUV[\]_ddxxtpgf_dlwxogb\[]\[\VWSRSXZ\hx~l_^^YZUW^enxvocYUPRPQSUVXY^Z_psf_[Z\^golhab^[\ZUVYYchwsfkkeiwyvjab^ZXXXYX\gen~t_`dholoocb_]][]Z[\\\Z\hjz~x~}vmmkfp~xqkdhb]ihde`e^^`^e^]__]^\cdinhnmnnyx~{qvjnkgtmltootqxttoil`jegkntw}}{n}kqrxzzx}}|}tw~l|wr{wupk{z{pznkmoqm{~~u|||rxlqoimepqgphttip}v|wx~vsow|l}oor{o{xoqozlwjqnnsnynoviuolwkkmh|yeh|nnniwek~flyufpfimikpllzru|sy}y}jmmgjjmnoo|kmmgr|mflofvhel`lccmgtsgqsutpqjzoqnwzvzprvfkiikkoltilnmijgnhzm{wvsr{s{|~||~sz|sz{x|otsm|whzllw|xu|zuorskxsoyjc|nhydqlgkcpfpirpj{vgk}zomizyqwnsoomosqjp~s{t{t}w}upvk}km|m~{xy}uqzokypczbvpkwk|zou}xun~kvvypznzxvv}xty|z}tz{v|wz|y~yzousyu~}pmrxnwumrvtxt~{o}lomuwqzt~limpmunpuvmwz}pommtmkxot~hzsh|lmvlqxmxonvn}wmzrtzilvdrivv}wnrx}zwqtvwplzuplnosnnoukyvwx}uuxu||w~xxzn|~~}zs|w~yx}zz}uzyytwmkthnolynrsk}umtvgmehqow}zxxojginjnhhjcc^__addfkhwv{~p{tqlhpjde]bd^bZ^kgox|usv|zy{{hibdg`]^_b^]]fn}}yml|~xpjeebfa__^__]Z\\[^deuuqqp{||xtrnjhhd_\ZWWXYbbjy|{z|xxpjfbdda]ZZXWV[af|w~ussq~yofc^[[WVXVZ^]l~{|y{yptrmnnqqikc__ZUROQRTZ]eszlkkiklosyytsslf`\ZVUSUVY_dm~}qkc_]ZY[^aejs~nhb]ZXWVWWY[^dmz}zyqid`^[XXVVVVY]bl~{|yoornpjec^[XTTTSTVWY\`emuwnjfd_\[YXXXXY[^`jnsz}||{zyrunhd_\[YWWWXY\_fn|{xwnic^\YXVVVWZ]ckq{ymh_\ZVTSUVWZ\ajvzrlhe`][XVTRRUXY[`gp}}zohc^[XVTRSTTVW\_fo|tlgb_[ZXVWXWY[ajp~wnf_]ZZXXX[\]]`gnxumgd_]ZZYXZ`dcov{nqhx~prloiac^\YSUQRYZ]klrqrvum}|vkmih^[[ZVTW\h_h~|mfwontx~|mec_[XUVUT_`dzokcihljtxtttzxxwnjf]YTTUSZhbuv{vi\^_gji}{uyzxohb\WRTTR\ecrh|xkikyuyld^\_elns}~|~xkc\XSUSUZljovvv|x}sigo}~mf^[ZZZ[]mjwkor~usr}~tkg]YZWZ\inuvo}|{}ojlk|md`\XSQPRSV_ilwk~qigcbefoxoi_[VVTSPRSV\imtlw~wnmno|{}s~mhfe`^]\[\]]_cv~zsv~{}s}zsvpulic`bcdi~pwz~~~mg_\ZZ[]hzzyqwrmf`dgimkm|z|oqwupnlc^[WVUUWZ_kqxoojmpuvpgjfdijmtsuoijhc_[VTRQRTW_jz|wottznleegilry{}yxzsng_[[XYZZ^lwvx}nrmpv~zkjghd_[XXWX\_dvvuu{{xupld_]\]^^^bjtzuqx}wpoos~ypha_^_`a`ckv}z{}{okikpzrmib^ZVUUUVWXZ^ix}slkmv}xuuuoic_][YWVWY]`ku|umlmos}wkkikv~{qlfdbeijhed_^\YXXX[_fm{wqroz}}z{}|xvuttomkjggfddggkmt~ytomkihhijiikmoovx~|y~}|}x{vomjfdbaabchkms{ytolkjjkklponpqqrruxz}{zz|utqookigdba__abchjouy|zwuqnmklkjhdddefffhjimnpusw{~}}|zzyvzwwxwtwtqqrvxyxyy{{y|~~zxxutrostruusxwvy{z~~}~{{xvvpopopommkkk{}jrqrwkknjkhjiejheikjmnlromsonppqvurxrv|rvsnqoqvx}}z}zt{svzo{|}x}svwwwzuyvtrrrpzzy|||}~yzwxutwoonmnmlnkkllimllnmopouvx|yroljjigggfgfegeeggkqr{}slkfghfhcaa_`aabiosujolmsuxtoijhfjhkkhgeeaabaiov~tjlhglms~xnkhecaacccda^]\\\\adm{~mib_^_eht}nida_^^^^^^^]\ZXXXYZ_ep|roggdeikx|sjg`][YWUWXZ_mz}~smfea_^^^`em}~zplhfba^][\Z]^gsw|wmifca_^][[Z[\dkxxojmszzxqoliggda_\[WVUWX^ep}|}~}|umgehmu|wyupliec_\ZWVSTV[dm|lfdio|wxzttsuomkgb]ZVTSTV[amyv{rqtt}mheemw}vzx|~snf_[YVWY\fpxrlp|xle^[YY[^husnjnyqld^ZXUUWZ_goyv|u}trkow~{voga\ZXWWZ_gotpwq{vsknt}~}tnfc][YWXZ_hty{~x}{smnmt|xxutmic^][ZZ]dlu|xppoz{sljd_]ZZZ[ahpt~~~zsljiglo{y{{qled^]YXWVWZ^dglonrr}|sliggehjruzyxrtrw}ynjc`^]YZXWXZ]bglst{||smkijgjlpv{xzttvx|zplfb^]\[ZZ[]afknu{upjgd`_aaekotz{uoljijggehmpquxsomihhgfgiknpvw||{y{}|ytnljjijjklosy|}||~~zwyxwvsromjhfedccddfejjvzs~}{|}zupnlkiiijjlnrx~|{xvvtxx|}~~{zz{||~~wvsomlmllmnoquxz~zyxsonnlkjiiijkllnnnmmlmlooqtv{}~{tomkjhfecdefhjlnqw{}zupmlkkjhhghhhghijlnpuz{}|}{vomkhhedddcddehklnopuw}~wuqmkihfeccdeffhhkmnrsvx{||xsnlkhgfdeeffgikooty|}ywysqmnlkiiikjlmmoorrtuuyy{~~|yyvuwttqooommmnnplyt{xyy{{}~}{vvvwuvwvvyzy{}~~}|{{yzyywxxxwwz}~|v~wwyuuxvvtututtqqonnprtwy}~yvqonmlljjhhihjkmmoquwyyy||~{|{xwvutrsuuxvxxxvusstvxzyxvvxxwuurrqssvyyzywyxzzxxxzz{xywuuvvvuuxyz}~~~|zzxwyyy{{||{|~~~~|}}~~~~}||~~~}}~~}}|z{zwyyy~}~~~}{xxxxx|}|y{|{|~||~~|zztuwwustqsrrstutpsoqm|zrvrtrwttuuwwxvxz|||}~}|z}z}~}~}}{{zyyxzz{|}|}}{{{yyyywxxvvxxvwy{}~~~}{|vu|{|~}}|yyyxywx{zzyyvtqsrpqqsroonoqpqrorqstuttuqrppprtqqrrponnnnnnnnnnnnnmooppoorqprsrrstvuttstwuuvuvwxxyyyz{z{z|}{||{}{y{zzyvwvtxxxyxyvxwwwx{}}}~~~}}~~~|{{|yxxxzy{~~~~~|z{{yx{yxwwwyxwxvvstrrrqqqpppqnonoooosprq{~}|~}|}~|z{z{zyy||{}}}}~~~~}}|~~~}z|{||{|{wwwvtussvz{|{v|wy|sxuuxuuutrooonoonnooooonnonnnmmmmnlmlllklmnmnnnoooopooonnnnmnnnoooqrppttsstsqroqqpqsqrrpooponnmmmnnnmnmnnqttz{z||{}}~~}{}~}}~~~~~|{y{xvwwusutqsrtutttvurtsrrtowvuuuuvyz}~{}|yz|{zyzyxzxxwwzwyz{|~|}|yvwwvvvstssqqrrwuuvxx}~~}}{xz|}{|{{ywwx{z{{z{|~}~~}|z|}~~}||yy|ywwvwxx|}~~~|}~~}~~~~~{|~}}|{{y|~~~}~}|zzzzywyyyxtqrpopttvxzwwxuvttvvwuvuvsrpqtuvtttrsoqopprrssrqqqqpoqstqopqpqpsuvwyxz|z|}{{}~||y{zvvyxw{z}}}~}~}}}~~}}}}~}~||}{}~~|||}{}~~~||||~|~{zzxzxxvvwwyx{{{zz}}|zz|z{yzywwwwtvwxzzwuwwwvusprpqqopqrrrsprpooopqrtsrqpvrwnovrusqtustrrsqsqorptrtttuyuurrsrsrprqrttstvstx{~}~|||}z{|~}}~{{{z}~~}zywxxtutssstwvtvtqqtsssttrqpooqqstvvwwvvuxyz{{zyxwwstsqrrsrusrqponooonorqsuuspnmnnnmnoptrrrsqprrstwvxyzy|}|~}}~~~~}~~}{z}~}~}{~|{{yxvvxwzz}~~ztronnlkkjklmmnqqrtuy{{uqmjhhaaa^^^]^__`acefjmnut}ywpokkhfdc`__^^]]^__`egls{~x|~{twkjg`a^^]\]^^ddls|{yyv|}sohe`]]\[[[]^ahkxvutquw~ymic_][YXWWYZ\adpwxrikfhjkuzolea]ZXWUUTUWV\\blp{mlfbc`cdfkoyyrjd_\ZXWWVXZZadn~zylilglnsohb][XWXXZ]]eiqz{nlljnqunic^\\[[X\^^lk{nohggejlu}rid_][ZYYY^]dmoofccbbhgox{ne`\YWTSRSTXY]dgmgdaa`dgkstkc]ZUSPPOOOTUY`bz~vrhb_^]__egm~xmb^ZWURQPQRVW\diqnhehfmp}ukb^ZXVUSVU[[ckstnhdeihvuxkf^ZYUVTVWZ\ckxolgbcbeknxib\XURPOOOQTU]^lwynec^]^__ii{|ic]XWSRQQQUVY_bv|mfb^^__cinzlc_[WUQPOPQVT]]jvsnhddcfltrha[XUTQRPUU[_d{yvlomo}}~skc_\YXWWZZbfl|pmlipr|qjb]ZWVUWUX]^imzmnhkkmr{}}snhb^[XUSQQRQVV\^gooofidffeillwx~zzpoic_\ZXVUVUWX\`eq}}~tytvxzvpjhb_^^]]a`jl|{unlkkgnly|~yzxvpommhhehdhlltu~|}{zzltjhjegcdccfccbdcfhkmsx|}}}vuolkffa`a_a_`_^^]^^^_acdhkow|}}z~~wvnokjhfedbbbbddehjmux~ywspnkiigidhljrquyurklggcbdcbccehjos|tmkjhgghikloptyz{zsqnkhfeddffjmoy}{utpoononyux~}pwkjicea`_]^]]]]^`bginuw}~xvsopnooqvu|{yqnlifdca____`abdfjkosz~{xutrsrrx~xsnnklkkmmmoqz|ytpmmnnqrw{~}}xzyvursrstw}~}|}|{z~{}yyvrpnnmmmopqtx{}~}{zzzzuutqrrsruw{zz{~{}tuonlmmlkkllnoonmmnopsrqoonmlkjjihhgghjkmsw{~~}zvrnliggeffhgiknsw|}}}~}~~}{{vvuuwz}{tuolnklkllmmqsx~|zwvuttrrw|~}|{{zz{}~}zxwxyz{~{y||||}}}|xxssrqstvzyzy|wtspsswyx||}{yvsutttuutuwy|{~~~~}zxurqprrqstw{~~~|}|zxwwtutstuvvxyyxwzzz}}}~}}|}~~~yxsqoooojnonoonstwzz{{xyxwvvwwwwvvvtuuvwx{}~}~}~}}{zz{y||{|}}}~|zxuuqssppqprprrqsrqxxy{}{{{zzxxwuuvvwxyzy{|}}}zyyyz|~~~~~~~}|}}zzxyy||~}{xvsqoprppooomnnopqpooopnnmnknzmporqqsqprrtwwvwxzzxwvttqpnnmlklmnoortuuwwtvwwwxyxyzyyzz{{~}}~}~~}|zzwwwuussrstuuutttuvvyxwxuuuvtuvwxy|~}|zz{zyyxxyyy{~}~~~~~{zyz|zywyxzzy{zzxyzwvvvuwsqponnnmklkiiiiiiiijklmmooooqtstststuuwyyz{{~||}}}}|{yy{z|y|||~~~||zwyzzzzxxxyxy{{|{||{{{{{}~~}z|~}~}~}}|zyxwxxyyxvuuvuuttxwwuvuwwxxwy|~~~}{xtrqqqpqqpqsruuvy{{zzwuvwvy{{yxxxxxxwvvvwxz|~}}{yxywxvvxyxyzz||}}~}{{|}~~{yxwxx{z}}}|{z{||{xxusrponmmmllllmmmmquvwwvvuttxwuvwwuutsqqrqrtuvwvwsqpoppppppnnmlkkklllmoppooooopoqrroopppoppqoqqqrrsuwwyzzyyxusqporuuttqpponotvy}{|}~~{{yxvrqpquyy|}}zzxxxzxz{yxz||~}|~~}{{{{|z|~}}~}zwurtuvxyzzy~~~~}{}}}}}}}|yxvxvuvuu}~~}~~|zxxyyyvuuwvvtuttsqqtplqnnonknmmmnnopqssstrprrqooonlmkkkllkjlkkllllnnnmlmlmnoqsqsrqqopnnnnopqsrrqrw{|~|{zxyyywuutvw|}~~|{y|~|zyvv{{|}}|z}}|}}~|||}~}~{~yzyx{y|~~}{|||~~|{zzxyzuvyyzyyxuvuttstwvxy{~|}xu}|ssx|xunotzzytvyz{wxz}~|}}~yxxy||}yz~}~~}~}}|}|}~|}}|zututsuuuuvvwvvvwrtussutuuvtrqsruumvtrollnmnmmllkllkkljklmnmmnmooooruuuutpsroppsrrtroppnooonmquvutrrruv{{{yz{wvwvz{zywvpqsuwyyyxyxywusruuxzxwzyxvwwyy||}~|wz{}}{usu}~ypnoonpt{|{vvw{}|}xuytpqw|}zuou}rnopokgeeda^_dgjq}zupmjifd`___`fm~{y{z||{sounpleeedfq~{uohdeffeacjyqmjhea^\YWWZ\_hngegjnr{~unonjc]\[Z\^afsvlnry{uuqpkhb_\\]_bhm~xyoomf^ZW[]_]\^konu}zznnsoe^\\\ZZ]cjqrp||~w|qrpof_\[\]^]ajoowvvtwwml|{uzzmhjig_ZWUVUX[\_k|vcdeor{zx}{xru|sx~~sstne_\Z[Z]`dklmrukefeflnvyylkrnkb\[Z]`cfk|~xzx|zj_]`adegpy{qmrrf`XVYYY[]gptiinruvyv}yutxstzvigffc]XUVXYZ]akwmknuwz||z{w}~xtvwj`\Z[Z[\^ekovstx{~|}zyywqlc^]^^ZY]dms{~qlmo~|y|{|trmkhga][[^`dhksqtx|~}{yxst||yvmotume`^]^^_agmxxsz{wzzuv~ynhb`acabcjlxw|}|wqppkf`_beecchou|{}zsmjkifb^_dkp{}uvz}ysspookg`^\\^bgzorljhfgw|zsoljmqy{rmnomjknz}~voorsnkiijha^[ZYY[_hypkgikvxwuw|ssu~~~zyysnga^]`iq{v{}y}|{omnnljf`][ZY[^fk}|uxvlkn~|zuqqqqmhd`a_`emzunlikozyvtw~yxy}yrnjgba`dbck{wljjjkls|zwwvuu{}zw||vxljedbcdda``is{~{yrmkljfdaaca__`abdkv{z~{~~zurorpnmliihhiiijklnopssxzvpsqqysstllmouxzz|{~zxywvqnlllmmnoqrx|}~z}~|zuooorsuqnlllklklooollklmoqponnnnlklnnopsqty{{ywy|{|~}xx|}ywwz}|wwsoprtuuusrooopqtvvvxx{}}}~~}}{zyy|~}}~}}~|~|{wuvw{~|yuy{~~zwusruuvyyusrpopsvvvwvutsqqrqstuvupnmlmprruvsutrtx||zxvvsopomllklnnnoonmjijmpqqonnommorstpnnnnpssuy|}xsoqtuwzzxsnllmnrrqppsvxz{{z|z~{zz}~~yursvy~|yvrnnotxzzxvsttuvutsqoommoorrqpooooomlllkllkkkiffeefddeffeccba`abehkjihhiiiknommlllllkklnoqomkklnqrponooorvy{yvrqqquusqnmllmov}yuvz}~~|~~~~}}}}~zy|~{txzy|yxxxwvy{zxxwwxxvwwwvvtuvwywtrpqqrstuwx{|{|{xwxzz|{xvuvvuusurrvvvvuuy{yzzy{z{}~~yxz|}|||~{vtsvzzzxxwvwz~|yyzx{|{z{~}~~}~~|{||zz{~yxuruuttuutroonnnqqrtwwxwwz{zy}zwwvvyyxwxxwxwuttwyxyzxxyzywutsuvwvvvutsvvxz{z{~}}zz{xxwuturqpoonooptqqqrp}~~{xwssuvyz||}~|{~}~{|x|}}}}~|zwtqponmnoomoqsuwwxwxvxxz~|~~}{xyvvsqonlklmonnooruux|~}zy}~~{vspooooqqtuqssruvxz}||{wvutropppsrrprruxwwvzyxywx|~~~~|yzyxvvy|~yxz}}zzywvuuuvtvtvwyzx{}~}}~{yxwx{}}}~~}}~~~~~zyx}||ywx}~}~~~~|wvxyxxx|}yvwwxx{}|yy{zyyy|~|{{{{~}}||~|}~|{{wyz~|z}~~}~~w{z{|twvxxz{{|zxvxuvy{}~~|{{{}~}|xxvutww{wzuywvuuwz{zy{zzzzxzzwyvtvuwvtwtvuvstuwxxwwvxxwxvwwz}|~}y|}}}~|{zzrursrsorpoomplnmqrutqrpoopqsttwwvturspqqtuttqpooruuxyyzvuttxx|xyxvvrtrvv}|~{|zz|~}~|~~~~||z{z{|}~}|z}}}|{~}~}~{}}y{yy}{zwxxyv{}~~~~~{yyvttuwxsqonmllorvwz|||x{w~|}~z}wwppnpoqpoonmmmmotzrz|wyvotxxwvsqoljihiikklmnnomorqvy||{|{{yvvxttsroonnooptvwwxy{~|{zxvyswvxy~|zyyz{{~~~{xxxz||~~}}|{zzyxy}}{yxrrpponnoqqqssrtrvwz}xwstprnqoonmlkjkmnrquqvqtorrxvzwzpqmnmnmmlmlnmonnnortwx|~{z~}xzzwuuutvvz|{z~z~|{~~}{xvuswz{~~}{}}||{|}~}}}~~}~}|yxz{~~|~}~~~}xxxwuwwwwwvwupnmlihhijjhghjlllnqtuy}wnlhea_^^^^^]\\]]^_dinr{znhc_][YZ[\^`gnyssoiea^][\_cinyx~sopme^\XXVW[`ewfmz}~}rzvlmnja\WWTSUZ^gzmhs{uxs}{{}wslf^YXTUX[`dzzkwx~wzxwlmhc[YWUWWZ_gyk}y}}qed]]XWX[]_aw{kzp~rjcb[Z\_chenzr}~yyif^^YWW[]`_q{ium|~y~r{|sko}vhb^^YVUY\]^wmilxjil{t~zxvvzjbd_ZWW\``e}llnl~{~t{xrysnlylj`a[ZXZ[]^mvvgbhrjhn|zw}ul{xv{ye][\XXUZ_bex}lin{mxtuwq~oi`a]XVY_cfwqq{~uz|zthgm^\Y_fgiyqpt}~rjia^\^efesx}rmf_\ZZ^badsqovu|}~ymi`]ZZWY[]]fnrimyz{kp~{wmnrz|umlif^[YYXXWY]jnvfiltgih}s|wywz}yllda^\ZZXZ[\^gw{nw}|x{}xtnic_]]]_`ehu|xz}xspkg_\\[Z\]`iqv~une_\[Y[\`bjoypmr}}wu}yusxwyow{~xrprnjd^\ZXXZ]_clu{pr|{}~{}}~wjea]\^^eenwmif_`agmp}}}znie_]]^bdkq}xxyy||x}}y{}oomookikjhb^]^\^^^_ejpnju}{wqy{}{{z}|tpookga`__\\]`eijlnz|{|wtrutonmmmjiijljhecaa`dgr}|~}}yustrrvurolkigefjnwyzzz}zqlkjjihgdb_^_bglt{~||tmhfggeccdecbbcdehjmptvxustvx}zzwojfcb_^]]]^^_chlv}}xtslmulroppw}|wrsqqnmmmkiiiknr}~}}ywwttqqtutvyzz||}}}|}{{{|{}zvsqruttvvsonmmnnnttsz||vmokhhfeghhiikkkijmps{}yxvuuqnmmllkjjlmosw|~}yvtropoqsurpoononmow|yuqrrtwxxvoljijlou|}}wurtvywvvtuv{{{{}tonnnpruy|}|{}{yspopsutxyzvurtxz||~}}|||}}~|yxtssttsrssutqonnpqvwywvrpnnntwzy||{}~yxsqpqsssrrqoooptxzz{xwpmkkjjknoonmkihhjlouy~~~~{xvwxzvtsqnnnprtrponmoqwy}}|}}zywvvv{}}w|zy|yx|zyxxzvtqqrtrrww{}}~}~|{zz{{~~~~}~yurportponnmmnostuxyyxwuplkklmnnmlllkmnpnopoopquxwwtqnmmllmmnlllkkkjjjkmottspommllmmnoporuyzxuqrstrtx{}{{~|{}~}~z{|}|{|~}|zy{~|wvuvw{{wrnlkklnnpomlmmnoptvywxywuusstvwxvvuqopsuyzyupnmnrvxwtsrrutstusroorsrqopoqsvz{{wwvvz|u}zxzww~}|xxussuvy{}~~|vuuuuvuuvx|{|ywz}{wwy}}ywrrpqqssuwuuutttvwwy}~|xy|}}}zxvtsrpuvvxussrtwtuqnnoooouvxxz|~~}~~~|}~~}zzz{~|{zyz{|~~~zwvwx~}{{|}{wuwz}~}|}}|}~}~~}}{yxyyz|~||~~~}xurv|}{|}~{~xyz}~}~|z}}~}zyyxvyz{|ywvuxy||~|uqqrvyzsqnmoru{|zwwvrrsttrrqnkjlnpttpnmljjlnorqnmmllmortsssroonllmmnoqqqqpooopruvwx{}~~~{xxy|||}|z}}|}}}{{~|||}~}{}rwpyw|{y|w}z~~ywwxxyyxyy{yt|q{tvpspsrww}}{}{}{{}|y{szqxquryvyvwxwvwvzw{z|{|||y~yyxwututzy{wzu{yz|~}}}{}}~{~{~~wux~tx}~}}~}zv|wyy||xurqqpsqqsnponspwuyx|~{yv|vv}q|pzrvsvuzxx{y~wuysxwyw{z}{|wzw||~~||{~txsxovtzw{svs{|}xwzzxuwtsxvx|z|}}yuuy}rtsy}|z}ruw{|z}zyx}tzsvx|}}uvrsquqqswtwstour|wu{tvotrrqsrrpoqqusvuuvywyy|yxwq}x}uxtzx}{~vstttpssyxzqsoorqyqxosqssw{y{zxuvz{{z~y~}{{vpmmpu~w{{puztwxusljjln~ottvxtwu~qwwusv~ztqljjhg}efhfh}iklmottx}yunijhgd~dcgfhjkm{nwo{w}{|runyswpxpymvkwkxjskumyn~v}wyxyu|wxxroqvw~|||y~wy}vpnpoqwxz}}}w}~}yywzzyyssvwwsyy}y~w~v~uxx|wxzxvqnzuopopoqywz~y||~}y~w}svo{t{s}uu|uzryy|z{vsxsuut{v|uuw|{{{~z}z{x|~~||v|xzs}pwnsmqnqotvvyy}x{{|y}w}z|w}|~~}}|~zz}~~|~|ux{{|}{~z}}~}}{{{v}ussww}vxuuvw{y~||~{ywxwwxuwsvpssurwsuuvrwsvqxq|tvxs{r|tvt}p{nzoyq|sysxqwswvx{{~|~yuz|~~}~xxyyz|~|}z}x~twouotovnuptp{xys{mofibgagchekionz{|tkjefcb_a^^^]]achmq|zrnjifb^_^^]\\^aeimwvyqpmhfbcba_`afimtv}|zolgfa`_abcaabehmoxyvzomggbb^^^^]\_chouyxlolsznjg`_^^\[YYWWUXZ_elsrsjjflmz~pjda^][ZXXWWWX\^fis~|soqq{umhfca_]][\Z[Y]_gkuxskmjtv}umhc__^\\ZZ[ZZZ_bnnyvonlpxymjfc_a_^]]\[[Z[_aim{~}tsmnnt}wpljiihgdba`^]]ahs|wumqpyuokghgiefbc_`]^]dhquyzzz{sqmkjkjhiecb`_^^dhqs|yosmonxqsmlhgfhigfba^]\\[_cnu{|tuq{{}|~~wuqrongd`a^^\^cku~{~svy|w|s|xxuyurjf_]\[Y[^eq|pumywujb^[YY\^joz|t~{pic_][ZZ^bjo{~twr|~zuic^\[ZYXZ^aikvz|xzw|zwmgc_\\\[\^dgor}|vokhc_^]]]]]ahnty~xpnmligdcdab_khlouzztpnnnnnnmmmjifgiloqv~~~z{|~~}xwtpmmkjjhfecfkmor~{urqvwz~}~yusqplkhhffgjmus||}xyupoonrty~yywwuuoqqrpliihfeceglqw~zzwz{|xvrmkffghjmu}yyx|~}}{{ywsutrpoommljhkow~}{vvtx~~yuvsopoooqpsuw{{{}~yvomkighfghjkmmoqswy}{uqonolljmlnoqvwxyz~~}}}~{zywtsqxuutwvvtsppoonqrvy}~{|{xvuttqsruuvvxwuwwy{~}{}}~~|z|zzurqonpqstyz{|}}}~~xzztwwuttrstvz~|xwurpsuwyy|}~~}xtrqnnnnnoostuw|}zwtqnmmnmnoqqvy|~{zwwwvvwwyy{|~}}}|xutrpqprprqqqrtuvx{~~|yuqpqrsrrqonnptyz}~}{~|{|zxxvvuuututuxz}|{xvutuutsuuvxxy||}||}~}{xyzyz}|}~~~~}{zzzzyy}}}|zyzzyzywwvvxwwwvsqpoooooppqsuvyy}|{}}}}}|{|{zzyxwutssrqssrttttqsrqrrqqsrttsttuuvuvwwvyxzzzzzy{|z{zwyvwyz{}|~{{z{z{{{{zyy{{{||z~}}|}{zz{xxwuusuuxz|}}|||}|}~{xtponoppqpopqpoooooorsuvvurrrrqrqstyy{{|}~}~~}|{xusrrroopqpoonoooppstvwvvxzyyxxxzyyxxwxwvwwwwvttuvsuttrttstuvwxzxxxzz{{~}~~~~~|{|}}}}}}~~~}|{|~}||}~|y{zyzwvvwvvyz~~||zyzyyxz}|~|zyzzzyy}|~|zyyxvvuvxzzxxwxwwwyy{{z{|~uz}y{zsvrqrsutuuuvuwwy{~~|{zyxxwxzxz{|}||||{|z{{{z{{{|ywxvussrtuwvvxxzzyzzzz{|}~~~~~}}~|||~~||||zxywwuvvvvuux{{||~~~||||{|}}{|}{{~||{xurpponnmnnmmmmnopppqrrsttqttuwuuursrrrsstvvxzz{~}~~~}}}~}}~zyyxwvvxxyzxzz{{{|~}}~|{zzyyxzy|{{|}~}||}{yxxzyz{||}~|}||}|}}|{yyz||~}~}~~}~}}{ywwxy}}x~z~|y|{~~~}{{|{{{xyyxyz}~~~}~}~~~~}~~}|{{xvuttttuxz{||}}~~~~}||{zxvtsqrrsuuwxy{|{zyvtttutsrqppqrqrsttvxyzzxyyyzzzxvutrppqsttvwyz{||~~||{z|}~~}{{{{ywvuuuuvtrqqqrutvwwzy{|}|{}}{|{yxwwxz}}{|}}}{}}{{yywuusstvwyz{{~~~}}}}|{xxvsrpqppnnmot{{}~{yzyz{|~}|~~{{zz{|}}}|{||~~~~~~~}}}}~||zxyyxwvy|~|}|zz{yzzzzxwxxwvvttuvuvvwvyzzz{|~{|zywvwwvwyyx{}}{{{{zywvwwvurqpnmlmmmnooqtwy{}|{{|{z{}}}|z{}|xvvvuwz|||}}~~~~|zxyz{zy{|{{zyxwyyzz|||}~}~}~}}|z}~{wuustswxz}~~|{zxuutuuutvutvxwx{}~}zwwvtsttsssvvvvvuxzy{||||~}|ywtrqpooqqooooopqpqpqrstuuwxvxvtsrtvvvxyz{zz|}~~u|}y}|y|||}|}}{}~~~}~~~|}|{|}}}~~}~||~~}}~~~}|}~~|{|{{yz{{yyxwxyzzz|zwvtrsrqqqrpoonnnnooonnnnmmnnnnmmnnmllnnoomlljhhiihjjjjiiiijjjlmmmnnqvzz{zyxvwvvwyzyxwx{~|{zvtrrrqonnmmllllkllmnoruwwvvvwz||~~~~|}}}}||~}~}~}~{xwvwxxyz}{urngjjikifheddcdccdfhiknqtxzy|}~|wsokjigfdcccdefggffddcdefimpv|}||zyz{xwpnljhfb`_^^^^`ekt}zz}~}wpmigd`_^]]]^_cgn{~~}~xqmjgb_]\[[\]ago|}~zuqnjec`^]\\]_fmyyustv{zxuwy{wyrznqkifc_^]]^agm|zyxz}}zwtnjfa_]]^_em~wqnmmot|}}|zxtonmljiec`_]\]_dkw{spoqsu}~wsojljfgecgfea_]\[\^cmx{qliggims~|vromkghggeddc`^\ZYXXZ\airyqliilqztnjgecaa``_`aaa_^\ZZYZ\_gn||tmhfddflq~sljhhghghijjjjhfb_]\]^bju|qljijlr|vommmmnmmllmmljiea^]]_ckxzrnmnqxxqnlkjjhhhgfffeb_^\\\]_foxqnllos}|unmlkjjihhiiiigc`^]]^agn|yqljijls}yoljijkkkjjkkkjgd`^^^_cjryrlkjkmtvomlkkkkkjjkloooligeegksunmnqwxvnjihhhiihhhhiiifd`___cgm}umhfegjovxnjfddefeedddfghfd`^\[[\^bjs}pkgcbbeiozsmjiijiihikmnopoljfca`bhnyypkjknt}~wwvxyxxyxyz}yslieccfinv~rljklovwqooonmlmmmnnoomjfb___bfnyyoljlot{{wvuvutqpoooooonie`][[[]^jwwxolkkmpy|wttttqnkjijjkkjgc_^]]]^`ejnuuomnqv{~{yxy||{|yz{|}}|xqmieb_`cglpy|wwy~}yrihdab__dflq~}yz{~}~ysnjgdb`adgkowzwqmieb____bcdek]PFFM\y`WTOQOP`yqývt`_glpOJQah`cqxk|iVJEGKOUXRMJHHIKQdw}jUKHKNVlqaXUUTPMJHHLMORUOGA>=>?EIMU_~xmu~l]UZZSSSPNMKJKKLOUY`ly~soxphd^]]ZYZZVRPRUTROMLNSVYbsf[Z^hnjjovknu}md\ZY[]_ekjja^\\^bn}unjrf^\\[Z]aggin}kdimligcccehnytoonou{y{}qia`^_dntzvja_^^dmz~xrnty}uiedaadlv}{v}}xmic]\\][WVWYXZ]^_bejkloss|z~~ykaZXXZ^_cfeeitzssomotr{}qox~~{qoja]\`kzwrmily}vpmlgdcdjo~{tmha__^_aded`][\]^^`fjjjfjixy|~qmrwrtronmlhfgmzqlknw|trqrppw}sjihhhlnje_^ahn}wnnlkpwxvtvukmhdc^_ejnv}zsppoptqqtqsry{womnot~vlifba`bbceilp~|vtwxtqqqomszuljmnige_^^adiv|wononmr}|vvz}}nhfhjligggjmpvx|vqsz}nihggknw}umechknu|~}xvx}{of^\\_bdehjlmqxz|zwtxyxy{~~zwsoruv|}oklmlhddegghknsqoonnv~{~~zy|xvtrsvuqomklmosv{}||~}vnjijkmqy|yxurqonmlmnotyxmhfgijjkkmp|zxwzzvtqoruvtx{}{wvsrqsty~zuokkox~~~~z{{|zyvrlhgfffhhhlu}}~|yvutpnnmkjjlnqwyvtv|}vtsw~tspnnp|{xwx{{ywsqponnlkjgghjmrw|vqnkfcdffehlnptxvxzywvvssvuv|}~}|~}xwwurouxxy~}{}~|y{z{}~~{zutm|uososz~xvyzuor~wvwz{|~||vnmpnnouy~{xyuqouwuw{~~~~wwvz|zwttrty~}xsrqtz{z{~~}~~}z~|zvuz|{zyzyyx}}|~}wvuwtrpnnouvw~|wtqnlkihknnoqsry}yy}}}}}~~{xxtpqvvqpomklmpsvxvsqqrrrspopooqqsrpsuy|{x|{xqmjjjnqrrsrrsqqqppoooqqqussttutrpoooosvyz{}~~}{|{{y~~zuuwzyttsww|}|y{}|~~}{zzzz{y{}~}zxx}|}}xz{~~zwvsoooopsvyyuuvuw}~ywvvuuwtsrvxz}~}xxytvuuprqptrtsuy}}ytuornlnlnomnsuwtuz{}}~~~zuspqpprorx||~|{x{}|zxtqqooooppopprqrqquwz{{}|wpnljiijkkmptwvtvz|yyz{zxxxzy{~{tonlllkmonnmmkjjjkjklllmotz|}|}|~}{{|ywsommlkjiijklmpsy{||}ytolkklkkklmonoqx|||zrmjhijmorw}zwvrqtwyw{~zy{zywtqlheccefjlmtvolljjhhfedb_^]_]]__eihn{}yvxz|unjhd__`_^]]^^^^]_bcglwwsrvwuu|xmhd`][[[[ZYYYZZZZ]_bekwxnmlnoos~uoomgb`b_^]]^^]]^ddhisz~}ojifea__^^\[]_dknystrty{okhda]\Z[[Z[`ipzxoh`][ZXXXZ[^bhosib]a\YXWYZ^bjwxurnnormd^YWTSQQQSUZ\blvmkfdcioxqjb[WTRQOPPRTY]bjtnihhnxqf]YUSQQRTX]co|xmlmn~tc\WSPOOPSX^fyohejlx~sh^[YYYXXYXYZY\`ejp|zoox}wnjhigdc`^ZWVURRT^ksngaa]^dvymkhhfhlnmkd_\YWTTZcguymggbci|ymkifegknpqoi_ZUTPNOZ`l{jeba^cq~ummjklv}xkb[YVSS\juqicefj|}vuxzpe\VTQPQ^jy_][^`i}yquu~k_YSQOPTf}y_]Z]_h{qtw}re\UOLLLMNWluiZRSU]bq~z{|yh[VOMMNOVfj`VTSY_oxgfejjpwg\UPMKLMOX`sd`YXX^lxu||ob]TPMMMORYbmfa\]]ktd_[VRPQRX]ennfgdhfzq`]ZYWSRRY]cezee_gbju~qmh`]ZYWVTVY_emxggbkir|ojea^\\YXUVX\_eyifahhq|~xwqlf`^]\XVTTW\_erqkcfhrwqou{pngc__][XXY[^fkmjejm{qmhihiecaekqyxtwzxsrokhfhhmr~wmoo{}xrmlhda\]^]^cfs}njefeko~yqmljlpx{tokjfdba__^__dfmwsmkkknt|}~umljkhgecb`_^]\^`fr}tnnsxzqnmkijjigdbacdgp{toos|wmjhghijhgddcbacfkstpnmps~{{zwrmkgfeghkmnnmkihgggjmu}zvusx|~ytrvz}|unmkklkmmorwvtqnonlkklnq|yv||rljhhghjnx{wqsz~|sonkhhjmou|{||{{svspw{|wrmkjkkmgjpr}wqoqpstw|~|~yzvtspomkheeghhjlpx~~|~~}}}}|wuuuutuy|~yyzzyzzyusppnjiijkoy~}|{|~||ywvuusvx|{yzzwrqnmmmnoswz~ytnmmkjiijklnqux{||ywursusv{~~}ytqnlkjlmnptxz{|{wuromnopoootrronljiihhgjmoswzyyxxvsrpqrqtwxzy{~~}|zyyvvw{}}wurqnortwuuvvtqpqropqqrqpsuvx|~~~||~yy{}}~{||xutppux{zw}~|zxyx{}{{zz}~zwyzyyyyywwuqqooqsuxy{zz}|yyx{zzwwywtolkiiijjllmooooppooopoprtvy|~{xvuuutvyyxx|~{vwxxvw}~{yuw|~~}|~|vxrwv{|{zxtstvxxzz{|yyz{{|}}~~|z||zyvronnmlmmnnqw|}}xxxz{}zvwxvvvxyyz}}{zzz||}}{|wutooopsstvvtroonnopsrstuuustrtvwyywutrrrsttuwy{{{xvzxwyyw|{{}|zxy~~}~~||}|oy||}}zvx}~~~}{{}||zxwxsuyxvuuxwwxxyvtsstrstw{~~ywyy{zz}|xy{yvuuxxusrsqqtttstusqmlllmnnopooonnmonmopsuwzywwwxvtutqooonmmmmnnnoopponmmmmnpuzyz|{{|~~zyz}z{~~~|{z||}~~~|xwvtuxvxxxy{{|wuwxz{}}~yx}{|}|xwwvuvz|~zy{}|~}{znsqnomlppqqstvutrstsuy~}{zwvuuvsroopommnmmllkklmotvuvzzy}~zy{xuy|~}||zzwwxzxxyywx{}|}}~ztuxwrsvyxww{}}wssuwww{}||~~|~}}{z}}~zutuvsusvx{{|||zyz|yw|}|x|||{xz{{zyyyvw{||~||{zxwwwvvzzz{}~~~}{~}z|{yzz{||zxx}|y{}zwy|zvuxyyz{~|}||~|~yyyyvx~}}{zwvsrvutwyxwy|{|}{{{{xx|}}~}}{{|x}|y}y~|}~{xxyww{|xtutonsvsrsuyxx{|{~|{yvsw|vxv|}zwzx{w~|yyttprusuw{zyxz|~|}}}}~~|~{xsqvwwtx|zwwxxzx{}}}~}}~{{yyyxzvursrqtty}}~~}{~~}{yxvwwxz{}|~~||s|uvrrvrorrwpstutvvzz~}|xxs{x|~}z}}}yyywywyw{yzwwssmrqssvyzy{|xx}~}~~{y||z|z|zqwotntu~|~{||}{||z{~|zxy{|~zup{s~p~rystvw{~~}}ywr{s|u~yvtyuoqoqsrsvr|m|orxojilvupoy|||o|kqutvpopmwn|rvtrpw|qysumvo|l}nzqsxwtunpmlitgfmrsknuzspo||ur~x}{xxz{~~}~z{z~{}wx{xsuu~{tuv{x||xwssll~luqutr{stqpqrqzx~~toxootkolnmmkmjojtlnmiohljtl|tz|{|{y}|yut~{x}|{uwnunqrsyqvyzv}uzwvqo}nmlsyx~{|y{}{zyx}uwv}wz~{y~~~z}xzzsr}u{t|oo|p}s~xzvv{~}wy|~xupnpmmmlklinoqrys}oyruortszs}||{~~}yytu||~~{|}z|~}{|z{uyt~|}{|zyyxwx{xxtyvyw{zzzxzuysytz||z}{ysoomnlpprtv{wyv{|ywuzrwr|{}|~~}{}z{xwuvtvyu{uzwwsvrtoutxwy{z{v|}y|z{|~zy||{usoqnplpm{{osonmlnpu{{rokhdc_^]]^]_`bdgjn{|vwz}of^\ZXXVWXXY[\^gnwujfcefkt{ic\YWUUUUUWY[^enowj``^_bgtme^ZVTSSRSUVX[]gjn{mb]]\\_eoym`\YWUUSUUUVY[derwl`^]]\bj~ri_\YWUTSTTUVX\ecwsj^^\\\`jwre]YVUTSQSRTVW\bbwvi_][[\_gosj_[VTPONNNNOPRY\bnvk_\ZXXY]fl}k`\XUSQPOOPRTW]^kw}ma^][\^emzni_b^ZYWWVWZ[`jmtgca_ablvxkd_]Z[YYXYY_fhqgfc`dgtxkf^^[[ZYZ\[ahjzjgfacfluwkf^^[[YYXZ[]hiz{fc_]\_`imuh_]XVTTSSRUVW]^eown`]\ZY[\`fn{j`]YWTRRPPQSSW\^imxme\[ZYZ\afqld][XVSTSTUWXZ_blxync^]]]^emtxmd`]\YZYYYYZ\bel{}pf___`cjsqid`^[ZZYYZ[\_fiywod^]]^_dowvld^]ZZWXXXY[\_jo}oj`^^_`dkvqjc`^]ZZZZY\]^_knzokcbdegky|nf_]ZZXZYZ[]^ciwzyokfgjiln}uqnlhdb__^^_chvwy||wplkfad___\[\\]celw}|srvst|{ytoomjheeb`_a``fmo|wwwzuzxvspqmonnmjhgdbdegksx}{uuvwx{zttmlkihieec_`__beknsy{tqnlhjjijijjjlnr~||yyz|}~zxxsnmmlljihdddegkouz}}}}}~vppmkjikiijjjlmmonqprtxz|}|~z{z||zspnmnou{|wqoosuwzz|}wwtqorvy~~}zyywuqomkiihfijlqz~vzonnkjjjiighiijlnquw{~~|{xupmlkjjkkllllmnmllonortwttxwsstsnnonnpvvw||wttsruttuvyyz{}{~}~~~}||zvvrrqrsw|}~{z{yy~zzxyxyzy{yz}~~}}|~~}}}ztpollklos{}|||{|{{xxyyustrooqtwz~~}zyvttstsrsssqqwttxvzz{|~~{vrnnkiihiknqx}{vrnnjiihggilnrv~|{yzxyzz~xtrpot|{upmljlmoovyzyyzxvwustrpqquxy{}|xqllkllklmsx}xvsvwvwtvoozrqvqx~~~}y{~z~|{{z|}ytokmntxx|{}}}}~~yronoonnnopoqqopvy~~vtronmmosuwz|~|ysrtv~wurnmlnlnnt~{womjnsy~{yx|~|zyvvroponlljjijmowyz|xutspomlijjjmosw||wsmlhigihghfihiklpqrutptz{}}z}|~}zvwxvsnlkkknmmmrz|~~}zvvqnjklmsrv~|}~zyzw}{uportxxz}yqnomkjnt~}~}}~|z~xvvzww~}xpnmlnnrru}~uu{~}{|~zwutwuyvyqoloronmqosuvyzwv{|wrqswzzonquzx}~{onoppuw|||somorswz|upooptx}}xsqoqrssv{z{~xrtrxqxy}vrox}xomklknqvy~{utsuwtytyy|{z|~~}~|ynigc`_`dgggmt{tnnkihkmmnmuz~|wvvurommmrv|yssu{z{vxwszxz~{{zxv|zrmljiikovz|}}unjfemhfjmsy{}|y|}vtomihinpotw}~}~zyxzxsu|~{|}~}ww{~zz|{{}~~|xtportwttrv|{}ysttsrqswz{|~}rpmnu|vpmklntz}xpoonrsy|}x|}}}zsonkjknqx~~|{vonlgihikmmowyuzwrmmnmmnsty~~|wvoou||tljkmqqtuy~~zttwvtuw{zx||{y|z}}~}}|~}~z{}{uvyvu}{uuvtzx~~~~~|{urwwztmllntwy{}wzwupoosxxyysnlmqonoyz|}~|{~xwpqnnlommotw{y|xzywxvvu|{tqoss{|vvx{swvwuqqnmnpy~wrposoonrwuyy|yzrmoqvv{wvwvxz}{z|ytmmlllotzuqqonkovz}uomllnqqsu~vvvrommonnnoonouxzxvvursov}yywwz{~~}y{w~}z~}}z{{}}~wzxz{y{{|{xtnlklt|}zvqpqqrrz}}|}~||xvwyz{|{~}zztomkklmmnmmmmklnstyz}{ttw|sooooryyxxy{xwvxwvttstqonmknpoqtqmmnoooqspponoqutsspqnroqpotvwx~zywxxvw|}prmkkigmnpsosw}|zookkkllllfchmr{womotnjeab__agq~|tzoqvyw~yzzownfb_^]^^fxzvvijjnox}~{pkq|mib`^[Z\cmqmjojurpmtv{~{x}ywqtt|nc`_^]Z[]fh}rovlvrqmigb`a^__hvuxwrznx}tlflhf`][\agynlmkxoxx|pmzlzou}tgd__^]]ZXY^cljemgvovgdrxpzmx}}~~zlhdea_[Y\`k}sjum}w{~~zoifehhjgeflo|sl}q}vsxqleab^^\]^ck~wmz|qmmkgdkgga`^bf~hfhsjvpsz}vsx~spjb^]\]\VWVZZ|b_^elkyvcosu{iugtrvz|upr{{uuebceda\\[ZZ[_lmiboo~j}{|us~~zzsrohea__]\[[^ctvjkvxzyyk|w{ywric__h`ecgkzrpqs|xvstqnee_^\_e~vrljfeadgim}wpnvo~}y{xmld`c```ei~{mkq|}|}wwwvsnnnle_]\]`fdiuynv~}y}nv~~rnlnqha]][XXXY_uzsuxtz}~soospg_]\\]\Z\`ntmm{|{|myxu|{~sokfa]\]_drop}u|}xoopsliefc_]Z\_iojinopozu~vwtohc^_]^ZXZ_ivopuyx{wnhiiig`]]f}{zwysru|{~|sjijie_\^bci~|~u|zuomkkgdcabahrwprxs{y}~}wyyzxtnqvpxmlhjkljxzotz}vy{|xwvtvvnkgfgge``cjxzxzv|zuplnnqvwxwvwvqnkfghksw}}|ypnmsyskilkmmnnnrry~}{tuy~polmpoolposrsst}yvrstysv~uuqnwzwpjkjjjios{tliikklmmnqsy~}}vw{{ursz{tstopnovz}|xwnkjkmlsyy~{||~x{}|{~zvw{~~zxw~y|y{}{s~~tqorusonssuvvuwuwnnlmmlkhkjlknsstx}}zzxuuvzuzqljjjhkmmpuytuuprqsoonnlmihjollow~~|yy|}}}zuxuuquzy||}}|t}~{vrtry{z{y{}~}wtv{|wvtzv~|{zuouvyy|~}~}}{}~xuxuyx|~|{}~|}|tspmnppopponqt{z}}{~~~~wzyy{xsqmjlntqotx}zwvx{|zyquoqkkihkknlortvrw{{~yutttwporwxzyzvyz}~ytv{y}{{|vwv|}}~|v}qwqoooootvwyywx}y|{}{}~~{~||~}|~~{xuuxy|z~}|||w{}|yvrtu}||}}y{xytrooqnpmqnoomooys||vzusokmkmkijlomonrtpqpqturupkjjmkmlvywyy}~~z{wwvx|zxvvxw|{~{ytswzzvusssrsy~{}~}|~~|}}z~}xvyvxty~~z|y}z~~~~~{zvrptvsrty{zz|uonomjljmlklntuxtzz{}yqomlkjkknssyxp{yzz~xrtvvspsvz~|||yx{~~{x~}|{ywz|{~}|{ywuvy|{~{yvqropnqqvx||{}|~yuvuwuxxzxwssy}{zz|wxwttrqsqrqwwpopttopqupoonpnnorqnqrstrpqy{yxwtuttrvtuzzyprsyssqssnmlooqppooopvw|xzzswuvxwxwvuxzxxwwvwy{}{|zxvvwtxv||z}xzurpquw|yzz~{xxsvruty{x|y{y~yx{{}||{|}}{~~~}}|x|{z}|}~}~{|||}}z{{}}}~~~{y{~~~|{|y{|zxzx{vvrrspvu~wvqsrvuwyv|xxzvvtwz{}z~}~wyywxww}}ztoononsvx|yyttsswtyy~uvywwuurvqqstwxxww|zxvuuuvvvxtupnoooquuvqqsolknprpnpoqprswzzyxyywzw||wz|}xywy{z~~{{uxtsrnspuoqoqposu|}}~{|zy}y~~~}|}{~|}{~~}zspooopqu}wvosqtpprqstxy~}~}xyuuyz}xtqomkiiikmoty}z~~z||{z{tyxz~~~zwvrqswx|}~~z{|~x{uvzvt||~}}{x}}{zx|wsoorqpooponnuwxyy~}{y}{vtppsnpvz{|~}{{~}~~xxtwstxuwvzz~zux{vrvwvstvvz||||z{yttuvvyz}~|}|ywvuy|}}~~xx}}~~~}|~}~xvuuy}|}z||{{}~z}~vtyyx|zuvpnpnwuux{||wwzvtvxsuutryzvxzzzx|~vxxzw{~||zywsrqqtxwtwzwx{}~yxvuuvwuxwxuxxy}|}|{{}~~}uzxxvx~~}|}yxwyyw}{}~~yspoopnqtw}}z{ywvtrnmnopoqoqqooorononnnooqrqqusqstw|wtw{|y}xxyytssopoopuzzy}zvuvtpvqsvutrxpouvwuxzz~}{y~~|{zwtwytw{~~~{z}}wz|y{z||~~~~}{~~~~}~~}|}~|~~~{|zyuwu{s~}{|~||~|y{~~}}wyyxx}~uttvs{w~~|x|yyw}|~{}|{}y|}|}|z}x}xz{vr}{y}v|vztxw~z|w{uzn}rvwo}nxm{rzuxvzryq{uvv{{tupqooozq}uwsvqps|x|{|~w~uzwvswovlvloooqwvyqnlosot{~|yx|x{|{{|~y{v{~~}zw{{}vvxr{xzx~v~wzy~~|z~}}{~yw~q}x|ooov}{yu|}{~r}u~}~|uvqonmpsootouovwwzxxxoqnmoltvwuqoxrxpu{{zrwyw|{}|x|}y{tz}v|xtz~{~|x~|}{~}yy{|zxvrlkjigfiggefffgilnu{zw}ojjc^__b^_a_`_`caabkvnqloibhlvv~wonjhijllmonlie_\ZXXWVW_gcxh_[_]]_i~sififilrvy{z~rje`^ZUUVVU\jkyjd[]_`em}zqnw}xld\XWTQOPTY\ejd^Z[Z]gtvonjoqvsic\XTQQSSRW\bi{ia^\\]am}{z~}jb]YYVWVVY\^fgmyojfflpvxmifcaccaa_____ciokghlr{mmmptld_^_^___a`_^^]]_`o|vmginz}omttyna^]^[]]^^`_^\\[\]et}}tokjqxtmiilnrga\]\^_efjjiea^[ZYZZfnsjfb_`emvfdfm|oicbdglmvqyrng_\WXVXZdwld`__fmwj`]]_jz~meb_bfny~pc[VSRSW\jla^]_iusga`exshbaacfnwzmb\VTSUX^ssc\Z[^hw~md_^`ltf_]^`fmv~pe]XRPOPTYa}wf][\_ijb]^_jzwh`]]_dm}l_ZVSSUX^lqf_^_fvleacjyqjcbdioqg^YTSSW\iwjeehnvlhhmxwokmnzxxle^[YXXZ^h|xjc_`donideirwlfdbdhmszxle_[YWXY]dozka]\]`hqtib^adkysleb`behmossqlhc][YXXY]cm}yja]Z[\cj}vjd^`^dkuxliabaegjosxvwomea]\YZ[_fuvljkms{spv}}vonmmorwx}yvslieca_djs}}otstwokjhikmvy}ztqjrkiknsopq{zuonmllmnopqqspoonlllnq}~zsmkklnsx~yuonmllmmnllknnspsnollmoqz~{troppsw|~wzllnjkljjklnovvxuutrstvwvsnst}~{usqtw|~}{vrropoonnnosqsssrtonllllnntst}{xxwx}~~ywuqmjmmllmoqvz~{wwwsnnmmmnoosrvwrupronmnnlmllmmqu~~z~||wytrxvxz{zzvxxwwyzy|~~~}~{yyvxuruonmlmlnlklkkjlmlmnostz{~}~~~|trpmoootsuxy~{|}xzzyxz|~v~~}}|}y~{~}{yz}|{{||ppty{wsrotxxwvspttnnoosw{}|wyy}y}~~~~~zy}u}|~xuvvrrtpytxwstqrpnlkjkkmqv|yuxqvyywz{wtonmmnqpopopvtzyz}}zwtoolmnklllmmnmkmnrvt|yx~yrnnllhhiiiikkmopopqpqqootuz{{{}~{|z~||~}{z|~~|z{}{}yx{~|~~~~z}{}~~~~|}~~~ywww|}{wuxz{yzz{{{zxvtsuvuuuvz{~~z|{{zxz}}}|{~~{zzz}~~~}}{z{{~|}~}||}}zytrnmmlmooppstutv{{|zywzywxuuuuttsrpnnmnnopuyxxxzyz|{uqooooprwwtuvwvtsvuvyzzz|}|zzvuronnmmjlmmmnnnnnpoprpooporrooqrppqprtwz~|{~}~~|~~~~~~~~~~~~~~~zxxwyywvyxz~{zyxvw}|{}~|yw{{|~~~}~~{wy|}|~~}~}{|~}}~{zzz||{xzyz{~}{||~|ywuvvvvttrqpqstuy{~~~~}~}|}{}}}~{|zzz}~~{zxzywxxww{~}{{|{}|~|}~}|~~|}{zz}~|xtstuwxy{zy{}~}~}~|zz{z{||}~}}~~}yxz}~~}}|{}|~~||z|||{yvtssrpoquxwwz{yxyzyxy{{vqrspoooqstuvwwy||}|{zyxvwxwyxspopopqqstyyyxxxy{{|{ywtrponmmmnoqrtwwyzxyxxyzz{|{z|{{zwwwvwxz}yyxx{z~}|{{zyzzz{|~||{zz}~|yyxuxou{x~}x~}|xvssuwxxz|~}{vuponmnprux|}{wsrqqooooqsttuwy}~}}}~yy{vrtrqpprtttrrsutsuvxyzzzyzyxvxxyyyy{||}}|}~}{|{x|~~}|}|}~|||}~~}|yxy{~~~}{zzy{}~}{zzxy{~~}~~~~}|z{zyx{zwwwxxz||~|yzxxvx{zx{xy{{{}{~~|~|}zxusnusutwvy{}}yzxvvwxwwz}~~}|{|}|zzz{{|}|~}}~{||zy||z|~~}~|}|y|{zxyzypw{x}}~~|xvvutx{{yvwvuwuuruwx{}~~~~~yvvvxuwyxywwusqpoortvw{~~zxwutvwuusruwxtswyy{~{{zwtporpnpuusprzyuvz}{{}~}yvzzwruzzxwy{{yzzzwx|{vsvxwtu{||{y{vuz|{|~~|y{~|vyzxsu|{y{~{wwx|ywy}~||y}~~z~vyoylq~pvxzy~|vprromylwztvropirshwmso}oykhlubnvf|qouzoomzlz{s|nssqp~ippg}tt}yws|o{uljokz|lvm~ikmbgltiusjkzpopozn|prqkvgtlfudxhmqkjxwjojm~~hm~llwy{x}{{vywwtz~wz|wo}|t||y~{yw|xyxztx{z|wzs}spyzzymrt}yw|{yx||||z}{|v{upvwnynuspwo~x}}{|{vmywywspzzsvy|u}|q}v{s}n|wx~w}rzt|nsyw{{yx~o|}psruz}wu~ss|ssvmunoum{mrvxv~tw~snk{kot||ov}}{z{|{|~|ro}|}|u|q}~vxy~z{{{z{v~zqnstporsoornwuuuyz|mzytvszm|n|ou}sy|}ztvmov{nvpl|o~yr{}}su~lnnryt}q~w{}y}ovx~mluftuy|x~}~~ry~o~spqqmuux~}yxzqmxkrqovzpw~ttyxwtjwqzvmtmm}nmvvtklytll~jtupmg~qwvmmo|uurmhrudzn_bttjso|no}s{muzwjlmjt|iw{it}~|o}ulsa}gpttx|m{v{}z}otr~~y||~zrtuw~}urr}w}xy}|z{y~zr~z}tzotyxwu}w~||s{zx|znyqnzpytzv~{wzxousrntsq{uqz|~~w}zxrusmrqjmpkvutuyunonoontopyp{}}}~~~zz{}}~wxvtnomkmkjiggkikmnvxvommiba_b^]]\\\YYZ[]_ggtsolhijkou||zuypr~tnmggd]]][\[[]bklqoicghhilv{ztuoqvsplkhb`]Z[YYZZ^hkrojjjklnxzwtrwvqqnljhba_\ZZ[\cikzzmkoosy}ztrv|}yssvpljheb^]^_cjny}tjimmv~rnnknsonpmnjc`^\\YW[[^dckwojdb__fimt|rkkkkjhlnmmlkkf`^ZYXWVX\`bgstnhd^^chnt~}mnqpmilrrnlnnic][[XWWY_dguwmha]_dkqvrmkjjfeikollnkga]\[Z[Y^ehvthgd\]ahswlonkjeihdedcb_[ZXWX[aiquje__chprqnkkjmtonljjd^^]]^^cosxkec\\_blxxvrtnnjuyjhcaa^\\]^^euukgbbgkv~zusrljg`]ZYYZ[^io~pgd_]agpzsruyzxwxphe`]\ZYY[]hs{kc_\Y\_fswolgegjmmlotrkb^ZWURRU[afv|j`^\Y\_gs}xrjeaafjjknnmif`][YYWY`hrrmldadhn|ywsnmqtyusz|umecc_]^fnvtomjikq~ummnswv}|wnid`__]bjpznkq|}uppsu|~|tme`_^\[[\__`eltwuv{}yrooqx|z|zvsnlsytjdcaa____^beeejr{}x|xxwxy{|rnjjmiikptrr~yponmlkkljkns}zvqtwzzwsomjgggfedgiknou{~}}{u{xz|~~}{}~yyvyxplkkmlmnt}{{{~{}vvrqwvqqqsztrqttonmrwx{{xxxwty}ywsqvx{}}|}xwuptposupqrxxvuspqooux{}zyxuxwwx{~}z{y|}{{}xzxtvsz~{|uvywvomosz|~~|}zz}~ytwspnmnprtvryy{~~{|{|||{}{rqpnnjkkkiggihgfgkntyz~}{zxvwxy}{{rvzwzxxvwxzyyxxwxwxttsuuxz{|~}{vsommlnoqsvwxz|~~}xwusrqqsvx||}}||||~~|yuywwqozwvyuy|wuqtqnnlkkkjjkkmmmnrw{}~~~|}{yuurrtssrqpprrssvvwxx}~}ywy||||z~~zxvuusuvz}~~~~~~|{}}}}|{{~~~}ywxwxxyzz{|}}~{xyzyyuwzz|zwtqqomlkkllmnnnnnoopqrrstvxwuutrrrsqommnmmllmmlllmnnnmnnqrwx{vzux|y{x{{}|zzxyz|~~{yyxxyz{|~}~~}zxxxxxx{{~zxz{yssvvwvyx|}|}~~}|zzzwuvtsttwvtspoonnlllkklnooopsvx{}~}|ywtrppoqtuwx{yyyvurqqppruuvuuxy{}~|zzwwyyzy{}|}~}}{z{yxz}~~~~~||{{|~~~{{zzwvuwwwvxyyyxvtrrursrwx|{yy{wwxwwxyxyvvuvuusqrrqonnnmmmnopqttuuxy|z}}||y{{}{{zxvtssrrssttutwwxyy|~~}}zyvwr|~|}{{yzz|||~~~}}~}}~}}}}zyz{~}{|~}z{xttqonnnoqvwyzyvtsttsrpqpponmmllkllmnnooonoooopsvwywqoonnnnnmkklnmmlmnmmnoqqrpopooprssvyz{{{zyz{|{zzzz{{~~|||}~~~~~|{~~~}|~~~}{yxz|||||~}~~}}z{|~~~}zxvtvvwwwwzyyyz|zywwyz}||}|zyzzy{{|}}|}}||xx{}|{zzzyyzz{z{zxxvwwx|~~||{z}}u}vxy}|~}|||~~~{zzz|~}rtz{~z||yvutwyttvxvuvuvuttttsu|{xwyz{z|{{xpponnnnnnmnqrpnnmmmostvtuwwuuuwvtuuwvxyxwvvwwxx{~~|zzxxxuvxz|}}}||}~~~~~}}}~|}}}}}}~~}{{|{|}}~~~~}|}~}}}}}|z{|~}~}{~~}}zywtvvrppqrsrrrrswz~~|ytsrqrprqpnonxu|~|z{zz|}~}}}}~}}}|{y}}}}}~|{}}{|~~}|~}~~z{qs}{z|}{}zxyyz|~~|ywvyy{zvyywvxx{~~ywwxxtpoprqqrsuvxwwxz|~|~|xwvwvwuuttrppqnnnoqswxyy{yxwxxvrpopqponmlijjlnootuvvxyywyxxwxz{|vuvxyywwuuwz||{{z{~zz{|{{|}zxwywvrsy}}~}zwttustrstvuquwxwy{}}{{z{yvwuuvyx~~~}}~~}|}~}}~~}|{zywvssrvy{~~|yxy|~}~|zxvtuyxwy{{}|zuokjkmorvyz|}{soononrwz}|xyou{wx{x}~yussstvxw}}~{w{|}{wvwtvuuy{}}zxwwxzxy|}}}||}}yzz{||}}}zyxxxvwuwz}|~}||||{zyvvwtstvwz|{z}}~|yxwxxy{|}~~{}z{z||~|}~~~}|z{zzyzyx{{{zy{z{z|}}~|xvxyxwy}~}~zxvrqqttuy|~|zzyvutommmmnqswz{yz~{zzzysrqprtvvvwz~~}|zzyyxwvvx}|~|{yyx{}{xturpnnorttsutvuvy{zxxwvsomojjkjlnkotvwvvyzwvuwwvspoonlljijlnooprsx{}{xuusrqqqomlmommnpty}}~}~|zvsrqqorrurqpoorv|~}~{zxwvvxz}~~}||{|~}yuuxz}}~~}|yuqoopqruxz}|}}}{yyxz|~|}||||{xwwzx{|xuurqqrrqoopqstwv{|{}}zyzzzwusrrsqpoonmprrx}}ztrsqssuxwwvsqoopqssuvyzzzxssrrqqrqtuutttvyyz||||}|~}}|}~|yxoturxzy}}||}}zxspmlkkkjkmnoooppqtx{~zzzzwxxvvvxzyyz|yvw{|{}||{wxwwttywwxzxupoonoty~~~{|}|~}}zz}}~{wvuwxxzxyyvrtz}|wyzy}}~}xxtqqoosux{}}}{|||z{yzxy|||{y{|~}{yxvsrtxzzz{zy~~~y}|~~~}{yxxzyz|~zxvw{~{yvsosuuxvvxtqonptwy{||z{ywvxy|~~~~ysrqpqnoomlnrx{}zxxyyywutuvvttwuxy{z}}{~}zyvz|}~~~}}}|ywwuqooppruvwtrqommmlkjjjkkklmnooooooqomlllkklmnmnnooopoppsuuusrrsonnnonlkkllkllmmmllmmooprqqqrrqoosqtsstwxxz~~z{|zzxx{}~~~}zz}~|wxv}|zuwuuttwxzz}~||}~zwvsmknoqoosuusy~{{}~}{ywzzwssy{xx{}{xz}{{{~}{}}ytuvtsvy|xz~}||t{|wz{v|~{|uuxonosywuxx{yyz~~|{~zw|}}~~{xwwxwzz~~|}z}}}~~~}xtrpqonosqnnrusswyuqruwtuxz}{{yywsqnomnropqtusqqpoqqqrttvtu{zwvzywwxzwuvxxtrutrpppqooppqstzxxvwzuww{yy|}}~||zww|}wy|||yz~zwv{|}~|~~||~|{|}}~}|}~}{yxtvz}xz|~{z|~}|}|}{tooonooqqrutstsssqrtttvzzvxy|}xvxs|ztvupurotsurrssrtuupoppronmoqonnrsqsqqqqqoopvxqswyuonqqtssxxwx|{wuz}{y{||{wrtxy|{~~~{zzy~|xxtwvxuqvy}{vvz{~{~}~{z{yutsvyuqosvz}}~|{||~{z|~~~}}{yz||x||xwz}~}zzxyyw{{{xvtsuvvz{}}{x{{yx{~||~ywvuwtstwywyz}}}~}{vwxw{x{zz|zuwwrrrusw}~}~}{{~}}|{zz{~|z|~}|{~}z||~~}}|w{vtrvywstv|}~~zy{~~ysoonoononmkknqrtuwzyz|zyxxwz{||zxtroooopprssu}~~|}|wx{|~}{{{yww}~~}~}|~}xx|}|w{~}yy{z{{~~~{yywwxzzuqtsrpqsqqpooprsspruuwuutqoonmlloooosxzz|~|zuqppoooorw||}{~~~~|{}}~}{}~{{{|}}}~~}|}{||~~|~{xxyzxvwuxy{}|z~}~~{yyyz}}~||~y~{~zyy{{}|~}{ywx}|zxvvtqpquzwxyzzy~~z|~}xyz{||~}}~{|}~||}{|~~|}~~}}zxy{{~}}{yz|xuxtusnmmmmmonmllopoqtusopquvz|||~{xvutuwwuvsuqoqonnorqruuuwtux|}}}~{yxxyxz{}}|z|~~}|zyz{yz{{|}}yzzzzzxwx{~}|xvwwxwvxx{|{~~~}~~}|~}zyz{{yw|~}zyvwvvvx}|}~~}}|}|~{z|}~~}|~}~~}}~~~z{|z{z{|ywvxvwuuzyxwxwwvusrqtsponnnnooopsststxz}{ \ No newline at end of file diff --git a/star_lock/ios/Podfile.lock b/star_lock/ios/Podfile.lock index d9f86221..962d06af 100644 --- a/star_lock/ios/Podfile.lock +++ b/star_lock/ios/Podfile.lock @@ -38,6 +38,13 @@ PODS: - device_info_plus (0.0.1): - Flutter - EMASRest (11.1.1.2) + - ffmpeg-kit-ios-https (5.1.LTS) + - ffmpeg_kit_flutter (5.1.0.LTS): + - ffmpeg_kit_flutter/https-lts (= 5.1.0.LTS) + - Flutter + - ffmpeg_kit_flutter/https-lts (5.1.0.LTS): + - ffmpeg-kit-ios-https (= 5.1.LTS) + - Flutter - Flutter (1.0.0) - flutter_native_contact_picker (0.0.1): - Flutter @@ -107,6 +114,7 @@ DEPENDENCIES: - auto_orientation (from `.symlinks/plugins/auto_orientation/ios`) - camera_avfoundation (from `.symlinks/plugins/camera_avfoundation/ios`) - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) + - ffmpeg_kit_flutter (from `.symlinks/plugins/ffmpeg_kit_flutter/ios`) - Flutter (from `Flutter`) - flutter_native_contact_picker (from `.symlinks/plugins/flutter_native_contact_picker/ios`) - flutter_sound (from `.symlinks/plugins/flutter_sound/ios`) @@ -139,6 +147,7 @@ SPEC REPOS: - AMap3DMap - AMapFoundation - AMapLocation + - ffmpeg-kit-ios-https - flutter_sound_core - FMDB - GoogleMaps @@ -165,6 +174,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/camera_avfoundation/ios" device_info_plus: :path: ".symlinks/plugins/device_info_plus/ios" + ffmpeg_kit_flutter: + :path: ".symlinks/plugins/ffmpeg_kit_flutter/ios" Flutter: :path: Flutter flutter_native_contact_picker: @@ -223,6 +234,8 @@ SPEC CHECKSUMS: camera_avfoundation: 3125e8cd1a4387f6f31c6c63abb8a55892a9eeeb device_info_plus: e5c5da33f982a436e103237c0c85f9031142abed EMASRest: 8df6f87836767a9415ad5cc4af739bc9d215b475 + ffmpeg-kit-ios-https: 9e50ffa7eaa6272a0021829e054ef241f2ecffb2 + ffmpeg_kit_flutter: fb5bee3a6038231463ee99e30f97a5763e0ae40f Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 flutter_native_contact_picker: bd430ba0fbf82768bb50c2c52a69a65759a8f907 flutter_sound: c60effa2a350fb977885f0db2fbc4c1ad5160900 @@ -249,6 +262,6 @@ SPEC CHECKSUMS: video_player_avfoundation: 81e49bb3d9fb63dccf9fa0f6d877dc3ddbeac126 webview_flutter_wkwebview: 2e2d318f21a5e036e2c3f26171342e95908bd60a -PODFILE CHECKSUM: adf6d8caf5faa9ea4ee2a2ea37f5aea37a6520d7 +PODFILE CHECKSUM: 42aa7ffc6134b996f93caa6a9b6a2b5b580ff28a COCOAPODS: 1.12.1 diff --git a/star_lock/ios/Runner.xcodeproj/project.pbxproj b/star_lock/ios/Runner.xcodeproj/project.pbxproj index 382e887c..a756cc4c 100644 --- a/star_lock/ios/Runner.xcodeproj/project.pbxproj +++ b/star_lock/ios/Runner.xcodeproj/project.pbxproj @@ -10,7 +10,6 @@ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 3364C3F42B0C902100AA5ABC /* lcokStarMain.png in Resources */ = {isa = PBXBuildFile; fileRef = 3364C3F32B0C902100AA5ABC /* lcokStarMain.png */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3EF1E85D6F1EE0C0DCF8449F /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09D8B2FA2B26BA5BFF31AB2A /* Pods_Runner.framework */; }; 8297E4102AE75AC500E886FA /* XSFlutterManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8297E40E2AE75AC500E886FA /* XSFlutterManager.m */; }; 8297E43A2AE75BEE00E886FA /* Msg.m in Sources */ = {isa = PBXBuildFile; fileRef = 8297E4132AE75BEE00E886FA /* Msg.m */; }; 8297E43B2AE75BEE00E886FA /* udp_data_class.m in Sources */ = {isa = PBXBuildFile; fileRef = 8297E4172AE75BEE00E886FA /* udp_data_class.m */; }; @@ -125,6 +124,7 @@ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + CD1142BE3A076363977FB03C /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ED1F1A04428235FB1B6FD471 /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -141,9 +141,10 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 09D8B2FA2B26BA5BFF31AB2A /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 0BEB3ADCCEC961E2916B9004 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 265F8968B3CDB02494B21491 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 3364C3F32B0C902100AA5ABC /* lcokStarMain.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = lcokStarMain.png; sourceTree = ""; }; 33BF41252A96174D009D92E2 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; @@ -303,9 +304,8 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 99F6494C6B1A24363CCC6D32 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - BDB5B400176768766E85D5EB /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; - DC20461C9C4624BEB2DCD779 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + DAD8EE71BE7C05B99667C256 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + ED1F1A04428235FB1B6FD471 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -313,7 +313,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 3EF1E85D6F1EE0C0DCF8449F /* Pods_Runner.framework in Frameworks */, + CD1142BE3A076363977FB03C /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -323,9 +323,9 @@ 780FAA17A040B9755AD6154A /* Pods */ = { isa = PBXGroup; children = ( - DC20461C9C4624BEB2DCD779 /* Pods-Runner.debug.xcconfig */, - 99F6494C6B1A24363CCC6D32 /* Pods-Runner.release.xcconfig */, - BDB5B400176768766E85D5EB /* Pods-Runner.profile.xcconfig */, + 0BEB3ADCCEC961E2916B9004 /* Pods-Runner.debug.xcconfig */, + 265F8968B3CDB02494B21491 /* Pods-Runner.release.xcconfig */, + DAD8EE71BE7C05B99667C256 /* Pods-Runner.profile.xcconfig */, ); path = Pods; sourceTree = ""; @@ -565,14 +565,6 @@ path = img; sourceTree = ""; }; - 9304F75C378DB3447BB2408C /* Frameworks */ = { - isa = PBXGroup; - children = ( - 09D8B2FA2B26BA5BFF31AB2A /* Pods_Runner.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( @@ -591,7 +583,7 @@ 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, 780FAA17A040B9755AD6154A /* Pods */, - 9304F75C378DB3447BB2408C /* Frameworks */, + B8F749EDCB3FB55CC9253F00 /* Frameworks */, ); sourceTree = ""; }; @@ -635,6 +627,14 @@ name = "Supporting Files"; sourceTree = ""; }; + B8F749EDCB3FB55CC9253F00 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ED1F1A04428235FB1B6FD471 /* Pods_Runner.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -642,14 +642,15 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - 03BC065FC3064C0B6EE97546 /* [CP] Check Pods Manifest.lock */, + 818C8F3353996877C27F8ACC /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - D9B107A6B141D5F15BC356F2 /* [CP] Copy Pods Resources */, + 8AC988DFB36B18C3A52624A8 /* [CP] Embed Pods Frameworks */, + C87CD71185302EE14BA1323E /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -783,7 +784,23 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 03BC065FC3064C0B6EE97546 /* [CP] Check Pods Manifest.lock */ = { + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin\n"; + }; + 818C8F3353996877C27F8ACC /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -805,21 +822,22 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + 8AC988DFB36B18C3A52624A8 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); - inputPaths = ( - "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - name = "Thin Binary"; - outputPaths = ( + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; @@ -836,7 +854,7 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n"; }; - D9B107A6B141D5F15BC356F2 /* [CP] Copy Pods Resources */ = { + C87CD71185302EE14BA1323E /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -1106,6 +1124,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "cn.star-lock.starLock"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; + STRIP_INSTALLED_PRODUCT = NO; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; @@ -1355,6 +1374,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "cn.star-lock.starLock"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; + STRIP_INSTALLED_PRODUCT = NO; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; @@ -1498,6 +1518,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "cn.star-lock.starLock"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; + STRIP_INSTALLED_PRODUCT = NO; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; diff --git a/star_lock/lib/main.dart b/star_lock/lib/main.dart index f8a8dc1f..0912cfb7 100644 --- a/star_lock/lib/main.dart +++ b/star_lock/lib/main.dart @@ -5,8 +5,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:flutter_sound/flutter_sound.dart'; import 'package:get/get.dart'; import 'package:star_lock/talk/call/callTalk.dart'; +import 'package:star_lock/talk/call/g711.dart'; import 'package:star_lock/tools/app_manager.dart'; import 'package:star_lock/tools/bindings/app_binding.dart'; import 'package:star_lock/tools/device_info_service.dart'; @@ -52,6 +54,8 @@ final RouteObserver routeObserver = RouteObserver(); class _MyAppState extends State with WidgetsBindingObserver, BaseWidget { final _aliyunPush = AliyunPush(); var _deviceId = ""; + // final audioPlayer = AudioPlayer(); + final FlutterSoundPlayer _audioPlayer = FlutterSoundPlayer(); @override Widget build(BuildContext context) { @@ -130,6 +134,8 @@ class _MyAppState extends State with WidgetsBindingObserver, BaseWidget { // Uint8List uint8List = Uint8List.fromList([]); // CallTalk talkClass = CallTalk(); // talkClass.getAVData(uint8List, 90); + + _initializeAudioPlayer(); } //初始化阿里云推送 @@ -158,6 +164,54 @@ class _MyAppState extends State with WidgetsBindingObserver, BaseWidget { // }); } + Uint8List convertToInt8ListLittleEndian(List intList) { + List int8List = []; + + for (int intValue in intList) { + intValue = intValue * 2; + // 将 int 拆分为两个字节,采用小端序 + int8List.add(intValue & 0xFF); // 低 8 位 + int8List.add((intValue & 0xFF00) >> 8); // 高 8 位 + } + + return Uint8List.fromList(int8List); + } + + //音频相关处理 + Future _initializeAudioPlayer() async { + await _audioPlayer.closePlayer(); + await _audioPlayer.openPlayer(); + await _audioPlayer.setSubscriptionDuration(Duration(milliseconds: 10)); + + List pcmBytes; + + String filePath = 'assets/s10-g711.bin'; + + List audioData = await G711().readAssetFile(filePath); + // print('读取711文件数据长度为:${audioData.length} 数据为:$audioData'); + if (audioData.isNotEmpty) { + // 在这里处理你的音频数据 + pcmBytes = G711().convertList(audioData); + print('转换pcmBytes数据长度为:${pcmBytes.length}'); + _playRawData(pcmBytes); + } else { + print('Failed to read audio data.'); + } + } + + Future _playRawData(List rawData) async { + print( + '啊啦啦啦啦啦数据长度为:${convertToInt8ListLittleEndian(rawData).length}, 数据为 ${convertToInt8ListLittleEndian(rawData)}'); + + await _audioPlayer.startPlayer( + fromURI: null, + fromDataBuffer: convertToInt8ListLittleEndian(rawData), + codec: Codec.pcm16, //_codec, + sampleRate: 8000, //tSAMPLERATE, + numChannels: 1, + ); + } + @override void dispose() { WidgetsBinding.instance?.removeObserver(this); @@ -189,4 +243,3 @@ Future _setCommonServices() async { await Get.putAsync(() => DeviceInfoService().init()); // Get.log(PlatformInfoService.to.info.version); } - diff --git a/star_lock/lib/talk/call/callTalk.dart b/star_lock/lib/talk/call/callTalk.dart index 97b6ea57..381391e4 100644 --- a/star_lock/lib/talk/call/callTalk.dart +++ b/star_lock/lib/talk/call/callTalk.dart @@ -1,12 +1,6 @@ import 'dart:typed_data'; -import 'package:convert/convert.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_ffmpeg/flutter_ffmpeg.dart'; import 'package:flutter_sound/flutter_sound.dart'; -import 'package:get/get.dart'; -import 'package:get/get_core/src/get_main.dart'; -import 'package:star_lock/appRouters.dart'; -import 'package:star_lock/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart'; import 'package:star_lock/talk/call/g711.dart'; import 'package:star_lock/talk/call/iFrameInfo.dart'; @@ -46,7 +40,14 @@ class CallTalk { if (bb[61] == 1) { Uint8List g711Data = bb.sublist(77, bb.length); print('dinglingling bb.length:${g711Data.length} 音频数据来:$g711Data '); - Uint8List? pcmBytes = await G711().decodeG711ToPCM(g711Data.toList()); + + List pcmBytes = Uint8List.fromList([]); + try { + // 将 ALaw 转为 Linear + pcmBytes = G711().convertList(g711Data); + } catch (e) { + print('Error decoding G.711 to PCM: $e'); + } print('PCM decoded data: $pcmBytes'); @@ -56,7 +57,6 @@ class CallTalk { } else { print('Error decoding G.711 to PCM'); } - // 在这里处理你的 PCM 数据 } // 视频数据 else { @@ -142,15 +142,14 @@ class CallTalk { await _audioPlayer.openPlayer(); } - Future _playRawData(Uint8List rawData) async { + Future _playRawData(List rawData) async { await _audioPlayer.startPlayer( - fromDataBuffer: rawData, + fromDataBuffer: Uint8List.fromList(rawData), codec: Codec.pcm16, numChannels: 1, sampleRate: 8000, whenFinished: () { - // 播放完成时的回调 - print("Playback finished"); + print('Finished playing'); }, ); } diff --git a/star_lock/lib/talk/call/g711.dart b/star_lock/lib/talk/call/g711.dart index c3ab0ee7..0d9aca8f 100644 --- a/star_lock/lib/talk/call/g711.dart +++ b/star_lock/lib/talk/call/g711.dart @@ -1,89 +1,111 @@ import 'dart:async'; +import 'dart:ffi' as ffi; import 'dart:io'; import 'dart:typed_data'; -import 'package:flutter_ffmpeg/flutter_ffmpeg.dart'; +import 'package:ffmpeg_kit_flutter/ffmpeg_kit.dart'; +import 'package:ffmpeg_kit_flutter/return_code.dart'; +import 'package:flutter/services.dart'; import 'package:path_provider/path_provider.dart'; class G711 { + Future> readAssetFile(String assetPath) async { + ByteData data = await rootBundle.load(assetPath); + List bytes = data.buffer.asUint8List(); + return bytes; + } + + int ALawToLinear(int aVal) { + // 取反 + aVal = ~aVal; + + // 计算偏移 + int t = ((aVal & 0x0F) << 3) + 0x84; + t <<= (aVal & 0x70) >> 4; + + // 根据符号位决定返回值的正负 + return (aVal & 0x80) != 0 ? 0x84 - t : t - 0x84; + } + + List convertList(List aLawList) { + // 将 ALawToLinear 函数应用于 List + List linearList = aLawList.map(ALawToLinear).toList(); + return linearList; + } + Future decodeG711ToPCM(List g711Data) async { + // FlutterFFmpeg flutterFFmpeg = FlutterFFmpeg(); + + // Save G.711 data to a temporary file + Directory appDocDir = await getApplicationDocumentsDirectory(); + String g711FilePath = '${appDocDir.path}/input.g711'; + await File(g711FilePath).writeAsBytes(g711Data); + + // Replace with the desired output PCM file path + String pcmFilePath = '${appDocDir.path}/output.pcm'; + + // Run FFmpeg command to decode G.711 to PCM + // String command = + // '-y -f u8 -ar 8000 -ac 1 -i $g711FilePath -f s16le -ar 8000 -ac 1 $pcmFilePath'; try { - FlutterFFmpeg flutterFFmpeg = FlutterFFmpeg(); + final session = await FFmpegKit.execute( + '-y -f u8 -ar 8000 -ac 1 -i $g711FilePath -f s16le -ar 8000 -ac 1 $pcmFilePath', + ); - // Save G.711 data to a temporary file - Directory appDocDir = await getApplicationDocumentsDirectory(); - String g711FilePath = '${appDocDir.path}/input.g711'; - await File(g711FilePath).writeAsBytes(g711Data); + final returnCode = await session.getReturnCode(); - // Replace with the desired output PCM file path - String pcmFilePath = '${appDocDir.path}/output.pcm'; - - // Run FFmpeg command to decode G.711 to PCM - String command = - '-y -f u8 -ar 8000 -ac 1 -i $g711FilePath -f s16le -ar 8000 -ac 1 $pcmFilePath'; - int result = await flutterFFmpeg.execute(command); - - if (result == 0) { - print('G.711 decoding successful! PCM file saved at: $pcmFilePath'); - - // Read PCM data from file + if (ReturnCode.isSuccess(returnCode)) { Uint8List pcmBytes = await File(pcmFilePath).readAsBytes(); - - // Delete the temporary G.711 file - await File(g711FilePath).delete(); - - // Delete the temporary PCM file - await File(pcmFilePath).delete(); - return pcmBytes; } else { - print('Error during G.711 decoding: $result'); - return null; + print('FFmpeg execution failed with rc=$returnCode'); + // 处理执行失败的情况 } } catch (e) { - print('Error: $e'); - return null; + print('Error executing FFmpeg command: $e'); + // 处理异常情况 } + return null; } - Future encodePCMToG711(Uint8List pcmData) async { - try { - FlutterFFmpeg flutterFFmpeg = FlutterFFmpeg(); + // Future encodePCMToG711(Uint8List pcmData) async { + // try { + // // FlutterFFmpeg flutterFFmpeg = FlutterFFmpeg(); - // Save PCM data to a temporary file - Directory appDocDir = await getApplicationDocumentsDirectory(); - String pcmFilePath = '${appDocDir.path}/input.pcm'; - await File(pcmFilePath).writeAsBytes(pcmData); + // // Save PCM data to a temporary file + // Directory appDocDir = await getApplicationDocumentsDirectory(); + // String pcmFilePath = '${appDocDir.path}/input.pcm'; + // await File(pcmFilePath).writeAsBytes(pcmData); - // Replace with the desired output G.711 file path - String g711FilePath = '${appDocDir.path}/output.g711'; + // // Replace with the desired output G.711 file path + // String g711FilePath = '${appDocDir.path}/output.g711'; - // Run FFmpeg command to encode PCM to G.711 - String command = - '-y -f s16le -ar 8000 -ac 1 -i $pcmFilePath -f g711 -ar 8000 -ac 1 $g711FilePath'; - int result = await flutterFFmpeg.execute(command); + // // Run FFmpeg command to encode PCM to G.711 + // String command = + // '-y -f s16le -ar 8000 -ac 1 -i $pcmFilePath -f g711 -ar 8000 -ac 1 $g711FilePath'; + // int result = await flutterFFmpeg.execute(command); - if (result == 0) { - print( - 'PCM encoding to G.711 successful! G.711 file saved at: $g711FilePath'); + // if (result == 0) { + // print( + // 'PCM encoding to G.711 successful! G.711 file saved at: $g711FilePath'); - // Read G.711 data from file - Uint8List g711Bytes = await File(g711FilePath).readAsBytes(); + // // Read G.711 data from file + // Uint8List g711Bytes = await File(g711FilePath).readAsBytes(); - // Delete the temporary PCM file - await File(pcmFilePath).delete(); + // // Delete the temporary PCM file + // await File(pcmFilePath).delete(); - // Delete the temporary G.711 file - await File(g711FilePath).delete(); + // // Delete the temporary G.711 file + // await File(g711FilePath).delete(); - return g711Bytes; - } else { - print('Error during PCM encoding to G.711: $result'); - return null; - } - } catch (e) { - print('Error: $e'); - return null; - } - } + // return g711Bytes; + // } else { + // print('Error during PCM encoding to G.711: $result'); + // return null; + // } + // } catch (e) { + // print('Error: $e'); + // return null; + // } + // } } diff --git a/star_lock/macos/Flutter/GeneratedPluginRegistrant.swift b/star_lock/macos/Flutter/GeneratedPluginRegistrant.swift index ff949269..ed8af5a9 100644 --- a/star_lock/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/star_lock/macos/Flutter/GeneratedPluginRegistrant.swift @@ -9,6 +9,7 @@ import aj_captcha_flutter import audio_session import audioplayers_darwin import device_info_plus +import ffmpeg_kit_flutter import file_selector_macos import just_audio import network_info_plus @@ -23,6 +24,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin")) AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) + FFmpegKitFlutterPlugin.register(with: registry.registrar(forPlugin: "FFmpegKitFlutterPlugin")) FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin")) NetworkInfoPlusPlugin.register(with: registry.registrar(forPlugin: "NetworkInfoPlusPlugin")) diff --git a/star_lock/pubspec.yaml b/star_lock/pubspec.yaml index 2d1ed9d1..2ecfba90 100644 --- a/star_lock/pubspec.yaml +++ b/star_lock/pubspec.yaml @@ -125,7 +125,7 @@ dependencies: convert: ^3.1.1 just_audio: ^0.9.36 flutter_sound: ^9.2.13 - flutter_ffmpeg: ^0.4.2 + ffmpeg_kit_flutter: 5.1.0-LTS fast_gbk: ^1.0.0 dev_dependencies: From 1806c15c2f4b98ffc3b2647dce6cf84326fd23cc Mon Sep 17 00:00:00 2001 From: Daisy <> Date: Tue, 26 Dec 2023 16:34:30 +0800 Subject: [PATCH 24/33] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=97=A0=E7=94=A8?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=EF=BC=8Cmain=E5=87=BD=E6=95=B0=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E6=92=AD=E6=94=BE711=E9=9F=B3=E9=A2=91=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=88=90=E5=8A=9F=E6=9A=82=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- star_lock/lib/main.dart | 20 ++----- star_lock/lib/talk/call/g711.dart | 90 ++++--------------------------- 2 files changed, 15 insertions(+), 95 deletions(-) diff --git a/star_lock/lib/main.dart b/star_lock/lib/main.dart index 0912cfb7..5dc9a493 100644 --- a/star_lock/lib/main.dart +++ b/star_lock/lib/main.dart @@ -135,7 +135,8 @@ class _MyAppState extends State with WidgetsBindingObserver, BaseWidget { // CallTalk talkClass = CallTalk(); // talkClass.getAVData(uint8List, 90); - _initializeAudioPlayer(); + //测试播放711音频数据 + // _initializeAudioPlayer(); } //初始化阿里云推送 @@ -164,19 +165,6 @@ class _MyAppState extends State with WidgetsBindingObserver, BaseWidget { // }); } - Uint8List convertToInt8ListLittleEndian(List intList) { - List int8List = []; - - for (int intValue in intList) { - intValue = intValue * 2; - // 将 int 拆分为两个字节,采用小端序 - int8List.add(intValue & 0xFF); // 低 8 位 - int8List.add((intValue & 0xFF00) >> 8); // 高 8 位 - } - - return Uint8List.fromList(int8List); - } - //音频相关处理 Future _initializeAudioPlayer() async { await _audioPlayer.closePlayer(); @@ -201,11 +189,11 @@ class _MyAppState extends State with WidgetsBindingObserver, BaseWidget { Future _playRawData(List rawData) async { print( - '啊啦啦啦啦啦数据长度为:${convertToInt8ListLittleEndian(rawData).length}, 数据为 ${convertToInt8ListLittleEndian(rawData)}'); + '啊啦啦啦啦啦数据长度为:${G711().convertToInt8ListLittleEndian(rawData).length}, 数据为 ${G711().convertToInt8ListLittleEndian(rawData)}'); await _audioPlayer.startPlayer( fromURI: null, - fromDataBuffer: convertToInt8ListLittleEndian(rawData), + fromDataBuffer: G711().convertToInt8ListLittleEndian(rawData), codec: Codec.pcm16, //_codec, sampleRate: 8000, //tSAMPLERATE, numChannels: 1, diff --git a/star_lock/lib/talk/call/g711.dart b/star_lock/lib/talk/call/g711.dart index 0d9aca8f..aaf3afcc 100644 --- a/star_lock/lib/talk/call/g711.dart +++ b/star_lock/lib/talk/call/g711.dart @@ -1,12 +1,5 @@ import 'dart:async'; -import 'dart:ffi' as ffi; -import 'dart:io'; -import 'dart:typed_data'; - -import 'package:ffmpeg_kit_flutter/ffmpeg_kit.dart'; -import 'package:ffmpeg_kit_flutter/return_code.dart'; import 'package:flutter/services.dart'; -import 'package:path_provider/path_provider.dart'; class G711 { Future> readAssetFile(String assetPath) async { @@ -27,85 +20,24 @@ class G711 { return (aVal & 0x80) != 0 ? 0x84 - t : t - 0x84; } +//711解码为pcm数据 List convertList(List aLawList) { // 将 ALawToLinear 函数应用于 List List linearList = aLawList.map(ALawToLinear).toList(); return linearList; } - Future decodeG711ToPCM(List g711Data) async { - // FlutterFFmpeg flutterFFmpeg = FlutterFFmpeg(); +//List转为Uint8List + Uint8List convertToInt8ListLittleEndian(List intList) { + List int8List = []; - // Save G.711 data to a temporary file - Directory appDocDir = await getApplicationDocumentsDirectory(); - String g711FilePath = '${appDocDir.path}/input.g711'; - await File(g711FilePath).writeAsBytes(g711Data); - - // Replace with the desired output PCM file path - String pcmFilePath = '${appDocDir.path}/output.pcm'; - - // Run FFmpeg command to decode G.711 to PCM - // String command = - // '-y -f u8 -ar 8000 -ac 1 -i $g711FilePath -f s16le -ar 8000 -ac 1 $pcmFilePath'; - try { - final session = await FFmpegKit.execute( - '-y -f u8 -ar 8000 -ac 1 -i $g711FilePath -f s16le -ar 8000 -ac 1 $pcmFilePath', - ); - - final returnCode = await session.getReturnCode(); - - if (ReturnCode.isSuccess(returnCode)) { - Uint8List pcmBytes = await File(pcmFilePath).readAsBytes(); - return pcmBytes; - } else { - print('FFmpeg execution failed with rc=$returnCode'); - // 处理执行失败的情况 - } - } catch (e) { - print('Error executing FFmpeg command: $e'); - // 处理异常情况 + for (int intValue in intList) { + intValue = intValue * 2; + // 将 int 拆分为两个字节,采用小端序 + int8List.add(intValue & 0xFF); // 低 8 位 + int8List.add((intValue & 0xFF00) >> 8); // 高 8 位 } - return null; + + return Uint8List.fromList(int8List); } - - // Future encodePCMToG711(Uint8List pcmData) async { - // try { - // // FlutterFFmpeg flutterFFmpeg = FlutterFFmpeg(); - - // // Save PCM data to a temporary file - // Directory appDocDir = await getApplicationDocumentsDirectory(); - // String pcmFilePath = '${appDocDir.path}/input.pcm'; - // await File(pcmFilePath).writeAsBytes(pcmData); - - // // Replace with the desired output G.711 file path - // String g711FilePath = '${appDocDir.path}/output.g711'; - - // // Run FFmpeg command to encode PCM to G.711 - // String command = - // '-y -f s16le -ar 8000 -ac 1 -i $pcmFilePath -f g711 -ar 8000 -ac 1 $g711FilePath'; - // int result = await flutterFFmpeg.execute(command); - - // if (result == 0) { - // print( - // 'PCM encoding to G.711 successful! G.711 file saved at: $g711FilePath'); - - // // Read G.711 data from file - // Uint8List g711Bytes = await File(g711FilePath).readAsBytes(); - - // // Delete the temporary PCM file - // await File(pcmFilePath).delete(); - - // // Delete the temporary G.711 file - // await File(g711FilePath).delete(); - - // return g711Bytes; - // } else { - // print('Error during PCM encoding to G.711: $result'); - // return null; - // } - // } catch (e) { - // print('Error: $e'); - // return null; - // } - // } } From 9848852f9f546cb0315e8ad9b13af2d32b34fbd9 Mon Sep 17 00:00:00 2001 From: Daisy <> Date: Wed, 27 Dec 2023 13:59:11 +0800 Subject: [PATCH 25/33] =?UTF-8?q?=E6=92=AD=E6=94=BE=E6=9A=82=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- star_lock/lib/talk/call/callTalk.dart | 85 +++++++++++++++++---------- 1 file changed, 53 insertions(+), 32 deletions(-) diff --git a/star_lock/lib/talk/call/callTalk.dart b/star_lock/lib/talk/call/callTalk.dart index ab040e77..93455b70 100644 --- a/star_lock/lib/talk/call/callTalk.dart +++ b/star_lock/lib/talk/call/callTalk.dart @@ -1,8 +1,10 @@ import 'dart:typed_data'; +import 'package:audioplayers/audioplayers.dart'; import 'package:flutter/material.dart'; import 'package:flutter_sound/flutter_sound.dart'; import 'package:star_lock/talk/call/g711.dart'; import 'package:star_lock/talk/call/iFrameInfo.dart'; +import 'package:star_lock/talk/udp/udp_talkClass.dart'; import '../../tools/eventBusEventManage.dart'; class CallTalk { @@ -21,7 +23,8 @@ class CallTalk { var growableList; bool getFirstFrame = false; //是否得到了第一帧 final FlutterSoundPlayer _audioPlayer = FlutterSoundPlayer(); - List? allPcmData = []; + List allPcmData = []; + int _bufferSize = 400; // 设置缓冲区大小,根据需求调整 CallTalk._init() { iframe = IframeInfo(); @@ -40,35 +43,16 @@ class CallTalk { if (bb[61] == 1) { Uint8List g711Data = bb.sublist(77, bb.length); - // // 解码为 PCM 数据 - // Uint8List pcmData = G711Decoder().g711Decode(g711Data, G711Type.uLaw); - // // 现在你可以使用 pcmData 进行播放或其他处理 - // print('得到的pcmData:$pcmData'); - // allPcmData!.addAll(pcmData); - // await Future.delayed(const Duration(seconds: 3)); - // _playRawData(allPcmData!); - - print('dinglingling bb.length:${g711Data.length} 音频数据来:$g711Data '); - - List pcmBytes = Uint8List.fromList([]); + List pcmBytes; try { // 将 ALaw 转为 Linear pcmBytes = G711().convertList(g711Data); + allPcmData.addAll(pcmBytes); + // await Future.delayed(const Duration(seconds: 1)); + _initializeAudioPlayer(allPcmData); } catch (e) { print('Error decoding G.711 to PCM: $e'); } - - allPcmData!.addAll(pcmBytes!); - await Future.delayed(const Duration(seconds: 1)); - - print('PCM decoded data: $pcmBytes'); - - if (pcmBytes != null) { - _initializeAudioPlayer(); - _playRawData(Uint8List.fromList(allPcmData!)); - } else { - print('Error decoding G.711 to PCM'); - } } // 视频数据 else { @@ -150,23 +134,60 @@ class CallTalk { } //音频相关处理 - Future _initializeAudioPlayer() async { - await _audioPlayer.openPlayer(); + Future _initializeAudioPlayer(List audioData) async { + // _audioPlayer.closePlayer(); + _audioPlayer.openPlayer(); + + // await _audioPlayer + // .setSubscriptionDuration(const Duration(milliseconds: 10)); + if (audioData.isNotEmpty) { + // 在这里处理你的音频数据 + print('转换pcmBytes数据长度为:${audioData.length}'); + _playRawData(audioData); + // _playAudioStream(audioData); + } else { + print('Failed to read audio data.'); + } } Future _playRawData(List rawData) async { + print( + '啊啦啦啦啦啦数据长度为:${G711().convertToInt8ListLittleEndian(rawData).length}, 数据为 ${G711().convertToInt8ListLittleEndian(rawData)}'); + await _audioPlayer.startPlayer( - fromDataBuffer: Uint8List.fromList(rawData), + fromDataBuffer: G711().convertToInt8ListLittleEndian(rawData), codec: Codec.pcm16, - numChannels: 1, sampleRate: 8000, - whenFinished: () { - print('Finished playing'); - }, + numChannels: 1, ); } - Future stopLocalAudio() async { + Future _playAudioStream(List audioData) async { + await _audioPlayer.startPlayer( + codec: Codec.pcm16, + sampleRate: 8000, + numChannels: 1, + ); + + int totalLength = audioData.length; + int offset = 0; + + while (offset < totalLength) { + int chunkSize = _bufferSize; + if (offset + chunkSize > totalLength) { + chunkSize = totalLength - offset; + } + + List chunk = audioData.sublist(offset, offset + chunkSize); + await _audioPlayer.feedFromStream(Uint8List.fromList(chunk)); + + offset += chunkSize; + } + + await _audioPlayer.stopPlayer(); + } + + Future stopAudioPlayer() async { await _audioPlayer.stopPlayer(); } } From d8301654023e821ec7d40bc1b964560bdf295424 Mon Sep 17 00:00:00 2001 From: Daisy <> Date: Wed, 27 Dec 2023 17:16:58 +0800 Subject: [PATCH 26/33] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E6=B5=81=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E6=92=AD=E6=94=BE=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- star_lock/lib/talk/call/callTalk.dart | 34 +++++++++++++-------------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/star_lock/lib/talk/call/callTalk.dart b/star_lock/lib/talk/call/callTalk.dart index 93455b70..403376c6 100644 --- a/star_lock/lib/talk/call/callTalk.dart +++ b/star_lock/lib/talk/call/callTalk.dart @@ -143,8 +143,8 @@ class CallTalk { if (audioData.isNotEmpty) { // 在这里处理你的音频数据 print('转换pcmBytes数据长度为:${audioData.length}'); - _playRawData(audioData); - // _playAudioStream(audioData); + // _playRawData(audioData); + playAudioStream(audioData); } else { print('Failed to read audio data.'); } @@ -162,32 +162,30 @@ class CallTalk { ); } - Future _playAudioStream(List audioData) async { + Future playAudioStream(List audioData) async { + await _audioPlayer + .setSubscriptionDuration(const Duration(milliseconds: 10)); + + // 启动播放器 await _audioPlayer.startPlayer( codec: Codec.pcm16, sampleRate: 8000, numChannels: 1, ); - int totalLength = audioData.length; - int offset = 0; - - while (offset < totalLength) { - int chunkSize = _bufferSize; - if (offset + chunkSize > totalLength) { - chunkSize = totalLength - offset; + // 将音频数据逐步添加到缓冲区 + for (int i = 0; i < audioData.length; i += 320) { + int chunkSize = 320; + if (i + chunkSize > audioData.length) { + chunkSize = audioData.length - i; } - List chunk = audioData.sublist(offset, offset + chunkSize); - await _audioPlayer.feedFromStream(Uint8List.fromList(chunk)); - - offset += chunkSize; + List chunk = audioData.sublist(i, i + chunkSize); + await _audioPlayer + .feedFromStream(G711().convertToInt8ListLittleEndian(chunk)); } - await _audioPlayer.stopPlayer(); - } - - Future stopAudioPlayer() async { + // 停止播放器 await _audioPlayer.stopPlayer(); } } From 4492e75a40017a3e132948035a66d48be8b4fa14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AD=8F=E5=B0=91=E9=98=B3?= <786612630@qq.com> Date: Wed, 27 Dec 2023 17:18:20 +0800 Subject: [PATCH 27/33] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=AF=B9=E8=AE=B2?= =?UTF-8?q?=E5=8F=91=E9=80=81=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../monitoring/lockMonitoring_logic.dart | 1 + .../monitoring/lockMonitoring_page.dart | 391 ++++++++++++++---- .../monitoring/lockMonitoring_state.dart | 1 + star_lock/lib/talk/udp/udp_reciverData.dart | 2 +- .../flutter/generated_plugin_registrant.cc | 4 + .../linux/flutter/generated_plugins.cmake | 1 + star_lock/pubspec.yaml | 1 + 7 files changed, 318 insertions(+), 83 deletions(-) diff --git a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_logic.dart b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_logic.dart index c437be87..ad32bc41 100644 --- a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_logic.dart +++ b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_logic.dart @@ -1,3 +1,4 @@ + import 'dart:async'; import 'package:flutter/services.dart'; diff --git a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart index ad539497..69e908b0 100644 --- a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart +++ b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart @@ -1,5 +1,10 @@ +import 'dart:async'; +import 'dart:convert'; import 'dart:io'; +import 'dart:isolate'; +import 'dart:typed_data'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; @@ -7,8 +12,10 @@ import 'package:flutter_sound/flutter_sound.dart'; import 'package:get/get.dart'; import 'package:network_info_plus/network_info_plus.dart'; import 'package:path_provider/path_provider.dart'; +import 'package:flutter_audio_capture/flutter_audio_capture.dart'; import '../../../../app_settings/app_colors.dart'; +import '../../../../blue/io_tool/io_tool.dart'; import '../../../../talk/udp/udp_manage.dart'; import '../../../../talk/udp/udp_senderManage.dart'; import '../../../../talk/udp/udp_talkClass.dart'; @@ -28,9 +35,10 @@ class _LockMonitoringPageState extends State { final logic = Get.put(LockMonitoringLogic()); final state = Get.find().state; - late FlutterSoundRecorder recorder; - late FlutterSoundPlayer player; - late String filePath; + late FlutterAudioCapture audioCapture; + // late FlutterSoundRecorder recorder; + // late FlutterSoundPlayer player; + // late String filePath; @override void initState() { @@ -198,10 +206,10 @@ class _LockMonitoringPageState extends State { print("onLongPressUp"); // _playRecording(); + // _stopCapture(); if (state.udpStatus.value == 9) { state.udpStatus.value = 8; } - _stopRecording(); } ) ), @@ -334,104 +342,323 @@ class _LockMonitoringPageState extends State { //录音处理 _initRecorder() { - recorder = FlutterSoundRecorder(); + // recorder = FlutterSoundRecorder(); + audioCapture = FlutterAudioCapture(); } + // Future _startRecording(List dataList) async { + // try { + // await recorder.openAudioSession(); + // /// 监听录音 + // recorder.onProgress!.listen((e) { + // print("onProgress:$e"); + // }); + // + // await recorder.startRecorder( + // onProgress: (StreamController progress) { + // progress.stream.listen((FooderData fooData) { + // // 在这里处理 PCM 数据(fooData.buffer) + // print('Received PCM data: ${fooData.buffer.length} bytes'); + // }); + // }, + // ); + // setState(() { + // _isRecording = true; + // }); + // } catch (e) { + // print('Error starting recording: $e'); + // } + // } + + // Future _stopRecording() async { + // try { + // await recorder.stopRecorder(); + // await _recorder.closeAudioSession(); + // setState(() { + // _isRecording = false; + // }); + // } catch (e) { + // print('Error stopping recording: $e'); + // } + // } + + //开始录音 _startRecording() async { - getFilePath().then((value) { - filePath = value; - }); - await recorder.openRecorder(); - await recorder.startRecorder( - toFile: filePath, - codec: Codec.pcm16WAV, - bitRate: 8000, - numChannels: 1, - sampleRate: 8000, + try { + // _getFilePath().then((value) { + // filePath = value; + // }); + // await recorder.openRecorder(); + // // 监听录音 + // recorder.onProgress!.listen((e) { + // print("onProgress:$e"); + // }); + // await recorder.startRecorder( + // toFile: filePath, + // codec: Codec.pcm16WAV, + // bitRate: 8000, + // numChannels: 1, + // sampleRate: 8000, + // ); + + _startCapture(); + } catch (e) { + print('Error starting recording: $e'); + } + + // getFilePath().then((value) { + // filePath = value; + // }); + // await recorder.openRecorder(); + // await recorder.startRecorder( + // toFile: filePath, + // codec: Codec.pcm16WAV, + // bitRate: 8000, + // numChannels: 1, + // sampleRate: 8000, + // ); + } + + Future _startCapture() async { + await audioCapture.start( + _listener, + onError, + sampleRate: 8000, + bufferSize: 3000 ); } + Future _stopCapture() async { + await audioCapture.stop(); + } + + Future _listener(dynamic obj) async { + print('data.length:${obj.length} Received data:$obj'); + var buffer = Float64List.fromList(obj.cast()); + Int16List list = float64ListToInt16List(buffer); + print('Get data.length:${list.length} Received data:$list'); + for (int i = 0; i < list.length; i++) { + list[i] = linearToULaw(list[i]); + } + print('change Get data.length:${list.length} change Received data:$list'); + List sendList = list.toList(); + + Isolate isolate = await Isolate.spawn(_sendRecordData, { + "bytes": sendList, + "udpSendDataFrameNumber": 0, + "lockID": UDPManage().lockId, + "lockIP": UDPManage().host, + "userMobile": await Storage.getMobile(), + "userMobileIP": await NetworkInfo().getWifiIP(), + }); + + // 在主线程中监听子线程发送的数据 + // receivePort.listen((data) { + // print('Received data: $data'); + // }); + } + + void onError(Object e) { + print(e); + } + + int linearToULaw(int pcmVal) { + int mask; + int seg; + int uval; + + if (pcmVal < 0) { + pcmVal = 0x84 - pcmVal; + mask = 0x7F; + } else { + pcmVal += 0x84; + mask = 0xFF; + } + + seg = search(pcmVal); + if (seg >= 8) { + return 0x7F ^ mask; + } else { + uval = (seg << 4); + uval |= ((pcmVal >> (seg + 3)) & 0xF); + return uval ^ mask; + } + } + + int search(int val) { + List table = [0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF]; + int size = 8; + for (int i = 0; i < size; i++) { + if (val <= table[i]) { + return i; + } + } + return size; + } + + Int16List float64ListToInt16List(Float64List float64List) { + Int16List int16List = Int16List(float64List.length); + for (int i = 0; i < float64List.length; i++) { + double sample = float64List[i]; + // Make sure the sample value is within the int16 range + if (sample > 1.0) { + sample = 1.0; + } else if (sample < -1.0) { + sample = -1.0; + } + // Convert the sample to int16 by scaling it to the full int16 range + int16List[i] = (sample * 32767).toInt(); + } + return int16List; + } + //停止录音 - _stopRecording() async { - await recorder.stopRecorder(); + // _stopRecording() async { + // try { + // await recorder.stopRecorder(); + // } catch (e) { + // print('Error stopping recording: $e'); + // } + // await recorder.stopRecorder(); + // + // // final file = File(filePath); + // File file = File(filePath); // 使用 create 方法创建文件 + // + // print('filePathfilePath:$filePath file:$file await file.exists():${await file.exists()}'); + // if (await file.exists()) { + // final List bytes = await file.readAsBytes(); + // print('Recorded audio bytes.length:${bytes.length} bytes: $bytes'); + // + // _sendRecordData(bytes); + // } + // } + + // Future _getFilePath() async { + // final directory = await getApplicationDocumentsDirectory(); + // final filePath = '${directory.path}/recording.wav'; + // + // // 创建文件 + // File file = File(filePath); + // await file.create(); // 使用 create 方法创建文件 + // + // return filePath; + // } + + + // Future _getRecordedAudioBytes() async { // final file = File(filePath); - File file = File(filePath); // 使用 create 方法创建文件 - - print('filePathfilePath:$filePath file:$file await file.exists():${await file.exists()}'); - if (await file.exists()) { - final List bytes = await file.readAsBytes(); - print('Recorded audio bytes.length:${bytes.length} bytes: $bytes'); - - _sendRecordData(bytes); - } - } - - Future getFilePath() async { - final directory = await getApplicationDocumentsDirectory(); - final filePath = '${directory.path}/recording.wav'; - - // 创建文件 - File file = File(filePath); - await file.create(); // 使用 create 方法创建文件 - - return filePath; - } - - - Future _getRecordedAudioBytes() async { - final file = File(filePath); - if (await file.exists()) { - final List bytes = await file.readAsBytes(); - print('Recorded audio bytes: $bytes'); - } - } + // if (await file.exists()) { + // final List bytes = await file.readAsBytes(); + // print('Recorded audio bytes: $bytes'); + // } + // } //播放录音 - _playRecording() async { - player = FlutterSoundPlayer(); - player.openPlayer(); - - await player.startPlayer( - fromURI: filePath, - codec: Codec.pcm16WAV, - ); + // _playRecording() async { + // player = FlutterSoundPlayer(); + // player.openPlayer(); + // + // await player.startPlayer( + // fromURI: filePath, + // codec: Codec.pcm16WAV, + // ); // Toast.show(msg: "储存录音播放了"); - print('_playRecording() 储存录音播放了'); - } + // print('_playRecording() 储存录音播放了'); + // } //停止播放 // _stopPlaying() async { // await player.stopPlayer(); // } - _sendRecordData(List bytes) async { - // 刚进来是接听状态,然后改为长按对讲 - var userMobileIP = await NetworkInfo().getWifiIP(); - var userMobile = await Storage.getMobile(); + // var udpSendDataFrameNumber = 0; + _sendRecordData(Map args) async { - // 57 - List topBytes = [ - 1, 1, 1, 1, // 时间戳 - 1, 0, // 音频 - 1, 0, // 帧序号 - 64, 0, 0, 0, // 帧长度 - 1, 0, // 总包数 - 1, 0, // 当前包号 - 64, 1, // 数据长度 - 176, 4, // 保留 - ]; - UDPSenderManage.sendMainProtocol( - command: 150, - commandTypeIsCalling: 1, - subCommand: 8, - lockID: UDPManage().lockId, - lockIP: UDPManage().host, - userMobile: userMobile, - userMobileIP: userMobileIP, - endData: bytes - ); + List bytes = args["bytes"]; + int udpSendDataFrameNumber = args["udpSendDataFrameNumber"]; + String? lockID = args["lockID"]; + String? lockIP = args["lockIP"]; + String? userMobile = args["userMobile"]; + String? userMobileIP = args["userMobileIP"]; + + int length = 320; // 每个子List的长度 + for (int i = 0; i < bytes.length; i += length) { + int end = (i + length < bytes.length) ? i + length : bytes.length; + bytes.sublist(i, end); + // _sendRecordData(bytes.sublist(i, end)); + // // 刚进来是接听状态,然后改为长按对讲 + // var userMobileIP = await NetworkInfo().getWifiIP(); + // var userMobile = await Storage.getMobile(); + + while(true) { + udpSendDataFrameNumber++; + if (udpSendDataFrameNumber >= 65536) udpSendDataFrameNumber=1; + // 57 + List topBytes = [ + 1, 1, 1, 1, // 时间戳 + 1, 0, // 音频 + 1, 0, // 帧序号 + 64, 0, 0, 0, // 帧长度 + 1, 0, // 总包数 + 1, 0, // 当前包号 + 64, 1, // 数据长度 + 176, 4, // 保留 + ]; + + ByteData byteData = ByteData(2); + byteData.setUint16(0, udpSendDataFrameNumber, Endian.little); + topBytes[6] = byteData.getUint8(0); + topBytes[7] = byteData.getUint8(1); + + topBytes.addAll(bytes); + // print("topBytes:$topBytes"); + // UDPSenderManage.sendMainProtocol( + // command: 150, + // commandTypeIsCalling: 1, + // subCommand: 8, + // lockID: lockID, + // lockIP: lockIP, + // userMobile: userMobile, + // userMobileIP: userMobileIP, + // endData: topBytes + // ); + + // 命令 + topBytes.add(150); + + // 命令类型 + topBytes.add(1); + + // 子命令 + topBytes.add(8); + + // lockID + List lockIDData = utf8.encode(lockID!); + topBytes.addAll(lockIDData); + topBytes = getFixedLengthList(lockIDData, 20 - lockIDData.length); + + // lockIP + var lockIPList = lockIP!.split("."); + lockIPList.forEach((element) { + topBytes.add(int.parse(element)); + }); + + // userMobile + List userMobileData = utf8.encode(userMobile!); + topBytes.addAll(userMobileData); + topBytes = getFixedLengthList(topBytes, 20 - userMobileData.length); + + // userMobileIP + var userMobileIPList = lockIP!.split("."); + userMobileIPList.forEach((element) { + topBytes.add(int.parse(element)); + }); + + UDPManage().sendData(topBytes); + } + } } } diff --git a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_state.dart b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_state.dart index 67cce56e..3e70b79c 100644 --- a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_state.dart +++ b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_state.dart @@ -5,6 +5,7 @@ import 'package:get/get.dart'; class LockMonitoringState { var isOpenVoice = false.obs; + var udpSendDataFrameNumber = 0;// 帧序号 var udpStatus = 0.obs; //0:初始状态 1:等待监视 2: 3:监视中 4:呼叫成功 5:主角通话中 6:被叫通话 8:被叫通话中 9:长按说话 var passwordTF = TextEditingController(); diff --git a/star_lock/lib/talk/udp/udp_reciverData.dart b/star_lock/lib/talk/udp/udp_reciverData.dart index 9fea6034..52c1e380 100644 --- a/star_lock/lib/talk/udp/udp_reciverData.dart +++ b/star_lock/lib/talk/udp/udp_reciverData.dart @@ -19,7 +19,7 @@ class CommandUDPReciverManager { if (dataSize < 4) { return; } - print("appReceiveUDPData:$data"); + // print("appReceiveUDPData:$data"); Uint8List data1 = Uint8List.fromList(data); if (data1.length == 1) { diff --git a/star_lock/linux/flutter/generated_plugin_registrant.cc b/star_lock/linux/flutter/generated_plugin_registrant.cc index 05d9a9b9..f03aaf40 100644 --- a/star_lock/linux/flutter/generated_plugin_registrant.cc +++ b/star_lock/linux/flutter/generated_plugin_registrant.cc @@ -9,6 +9,7 @@ #include #include #include +#include #include void fl_register_plugins(FlPluginRegistry* registry) { @@ -21,6 +22,9 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); file_selector_plugin_register_with_registrar(file_selector_linux_registrar); + g_autoptr(FlPluginRegistrar) flutter_audio_capture_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterAudioCapturePlugin"); + flutter_audio_capture_plugin_register_with_registrar(flutter_audio_capture_registrar); g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); diff --git a/star_lock/linux/flutter/generated_plugins.cmake b/star_lock/linux/flutter/generated_plugins.cmake index b6e600e9..01b1e1e7 100644 --- a/star_lock/linux/flutter/generated_plugins.cmake +++ b/star_lock/linux/flutter/generated_plugins.cmake @@ -6,6 +6,7 @@ list(APPEND FLUTTER_PLUGIN_LIST aj_captcha_flutter audioplayers_linux file_selector_linux + flutter_audio_capture url_launcher_linux ) diff --git a/star_lock/pubspec.yaml b/star_lock/pubspec.yaml index 2ecfba90..fcd0b488 100644 --- a/star_lock/pubspec.yaml +++ b/star_lock/pubspec.yaml @@ -127,6 +127,7 @@ dependencies: flutter_sound: ^9.2.13 ffmpeg_kit_flutter: 5.1.0-LTS fast_gbk: ^1.0.0 + flutter_audio_capture: ^1.1.6 dev_dependencies: flutter_test: From 541a19d1a4e6ea9fb7a82e036d97d57df0d63a7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AD=8F=E5=B0=91=E9=98=B3?= <786612630@qq.com> Date: Fri, 29 Dec 2023 14:28:47 +0800 Subject: [PATCH 28/33] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=AF=B9=E8=AE=B2?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=8F=91=E9=80=81=E9=9F=B3=E9=A2=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- star_lock/ios/Podfile.lock | 47 +-- .../ios/Runner.xcodeproj/project.pbxproj | 23 +- .../xcshareddata/xcschemes/Runner.xcscheme | 2 +- .../monitoring/lockMonitoring_logic.dart | 253 +++++++++++- .../monitoring/lockMonitoring_page.dart | 389 +----------------- .../monitoring/lockMonitoring_state.dart | 23 +- .../udp/io_protocol/udp_mainProtocol.dart | 16 +- .../flutter/generated_plugin_registrant.cc | 4 - .../linux/flutter/generated_plugins.cmake | 1 - .../Flutter/GeneratedPluginRegistrant.swift | 2 - star_lock/pubspec.yaml | 7 +- 11 files changed, 330 insertions(+), 437 deletions(-) diff --git a/star_lock/ios/Podfile.lock b/star_lock/ios/Podfile.lock index 962d06af..b338036f 100644 --- a/star_lock/ios/Podfile.lock +++ b/star_lock/ios/Podfile.lock @@ -38,16 +38,11 @@ PODS: - device_info_plus (0.0.1): - Flutter - EMASRest (11.1.1.2) - - ffmpeg-kit-ios-https (5.1.LTS) - - ffmpeg_kit_flutter (5.1.0.LTS): - - ffmpeg_kit_flutter/https-lts (= 5.1.0.LTS) - - Flutter - - ffmpeg_kit_flutter/https-lts (5.1.0.LTS): - - ffmpeg-kit-ios-https (= 5.1.LTS) - - Flutter - Flutter (1.0.0) - flutter_native_contact_picker (0.0.1): - Flutter + - flutter_pcm_sound (0.0.1): + - Flutter - flutter_sound (9.2.13): - Flutter - flutter_sound_core (= 9.2.13) @@ -62,11 +57,11 @@ PODS: - Flutter - google_maps_flutter_ios (0.0.1): - Flutter - - GoogleMaps (< 8.0) - - GoogleMaps (5.2.0): - - GoogleMaps/Maps (= 5.2.0) - - GoogleMaps/Base (5.2.0) - - GoogleMaps/Maps (5.2.0): + - GoogleMaps (< 9.0) + - GoogleMaps (7.4.0): + - GoogleMaps/Maps (= 7.4.0) + - GoogleMaps/Base (7.4.0) + - GoogleMaps/Maps (7.4.0): - GoogleMaps/Base - image_gallery_saver (2.0.2): - Flutter @@ -83,7 +78,7 @@ PODS: - FlutterMacOS - permission_handler_apple (9.1.1): - Flutter - - Protobuf (3.25.0) + - Protobuf (3.25.1) - reactive_ble_mobile (0.0.1): - Flutter - Protobuf (~> 3.5) @@ -94,7 +89,7 @@ PODS: - sqflite (0.0.3): - Flutter - FMDB (>= 2.7.5) - - SwiftProtobuf (1.25.1) + - SwiftProtobuf (1.25.2) - Toast (4.0.0) - url_launcher_ios (0.0.1): - Flutter @@ -114,9 +109,9 @@ DEPENDENCIES: - auto_orientation (from `.symlinks/plugins/auto_orientation/ios`) - camera_avfoundation (from `.symlinks/plugins/camera_avfoundation/ios`) - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - - ffmpeg_kit_flutter (from `.symlinks/plugins/ffmpeg_kit_flutter/ios`) - Flutter (from `Flutter`) - flutter_native_contact_picker (from `.symlinks/plugins/flutter_native_contact_picker/ios`) + - flutter_pcm_sound (from `.symlinks/plugins/flutter_pcm_sound/ios`) - flutter_sound (from `.symlinks/plugins/flutter_sound/ios`) - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`) - g711_flutter (from `.symlinks/plugins/g711_flutter/ios`) @@ -147,7 +142,6 @@ SPEC REPOS: - AMap3DMap - AMapFoundation - AMapLocation - - ffmpeg-kit-ios-https - flutter_sound_core - FMDB - GoogleMaps @@ -174,12 +168,12 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/camera_avfoundation/ios" device_info_plus: :path: ".symlinks/plugins/device_info_plus/ios" - ffmpeg_kit_flutter: - :path: ".symlinks/plugins/ffmpeg_kit_flutter/ios" Flutter: :path: Flutter flutter_native_contact_picker: :path: ".symlinks/plugins/flutter_native_contact_picker/ios" + flutter_pcm_sound: + :path: ".symlinks/plugins/flutter_pcm_sound/ios" flutter_sound: :path: ".symlinks/plugins/flutter_sound/ios" fluttertoast: @@ -234,17 +228,16 @@ SPEC CHECKSUMS: camera_avfoundation: 3125e8cd1a4387f6f31c6c63abb8a55892a9eeeb device_info_plus: e5c5da33f982a436e103237c0c85f9031142abed EMASRest: 8df6f87836767a9415ad5cc4af739bc9d215b475 - ffmpeg-kit-ios-https: 9e50ffa7eaa6272a0021829e054ef241f2ecffb2 - ffmpeg_kit_flutter: fb5bee3a6038231463ee99e30f97a5763e0ae40f Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 flutter_native_contact_picker: bd430ba0fbf82768bb50c2c52a69a65759a8f907 + flutter_pcm_sound: de0572ca4f99091cc2abfcc31601b8a4ddd33c0e flutter_sound: c60effa2a350fb977885f0db2fbc4c1ad5160900 flutter_sound_core: 26c10e5832e76aaacfae252d8925232281c486ae - fluttertoast: fafc4fa4d01a6a9e4f772ecd190ffa525e9e2d9c + fluttertoast: 31b00dabfa7fb7bacd9e7dbee580d7a2ff4bf265 FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a g711_flutter: 8f2769052d2cf3549f83d11e1c42d81d94441123 - google_maps_flutter_ios: abdac20d6ce8931f6ebc5f46616df241bfaa2cfd - GoogleMaps: 025272d5876d3b32604e5c080dc25eaf68764693 + google_maps_flutter_ios: 590249c67f34f422122c232f2a626192adbc78ee + GoogleMaps: 032f676450ba0779bd8ce16840690915f84e57ac image_gallery_saver: cb43cc43141711190510e92c460eb1655cd343cb image_picker_ios: 4a8aadfbb6dc30ad5141a2ce3832af9214a705b5 just_audio: baa7252489dbcf47a4c7cc9ca663e9661c99aafa @@ -252,16 +245,16 @@ SPEC CHECKSUMS: package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6 - Protobuf: 6a4183ec1d51649eb2be7b86ccc286e5c539219c + Protobuf: d94761c33f1239c0a43a0817ca1a5f7f7c900241 reactive_ble_mobile: 9ce6723d37ccf701dbffd202d487f23f5de03b4c shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126 sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a - SwiftProtobuf: 69f02cd54fb03201c5e6bf8b76f687c5ef7541a3 + SwiftProtobuf: 407a385e97fd206c4fbe880cc84123989167e0d1 Toast: 91b396c56ee72a5790816f40d3a94dd357abc196 url_launcher_ios: bf5ce03e0e2088bad9cc378ea97fa0ed5b49673b video_player_avfoundation: 81e49bb3d9fb63dccf9fa0f6d877dc3ddbeac126 webview_flutter_wkwebview: 2e2d318f21a5e036e2c3f26171342e95908bd60a -PODFILE CHECKSUM: 42aa7ffc6134b996f93caa6a9b6a2b5b580ff28a +PODFILE CHECKSUM: 85f69c27139c5112fdd69e85b95c1cc6de403d3e -COCOAPODS: 1.12.1 +COCOAPODS: 1.14.3 diff --git a/star_lock/ios/Runner.xcodeproj/project.pbxproj b/star_lock/ios/Runner.xcodeproj/project.pbxproj index a756cc4c..1a0ea32a 100644 --- a/star_lock/ios/Runner.xcodeproj/project.pbxproj +++ b/star_lock/ios/Runner.xcodeproj/project.pbxproj @@ -649,7 +649,6 @@ 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 8AC988DFB36B18C3A52624A8 /* [CP] Embed Pods Frameworks */, C87CD71185302EE14BA1323E /* [CP] Copy Pods Resources */, ); buildRules = ( @@ -667,7 +666,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1430; + LastUpgradeCheck = 1300; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { @@ -822,23 +821,6 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - 8AC988DFB36B18C3A52624A8 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -1007,6 +989,7 @@ ENABLE_BITCODE = NO; GCC_NO_COMMON_BLOCKS = NO; INFOPLIST_FILE = Runner/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1257,6 +1240,7 @@ ENABLE_BITCODE = NO; GCC_NO_COMMON_BLOCKS = NO; INFOPLIST_FILE = Runner/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1401,6 +1385,7 @@ ENABLE_BITCODE = NO; GCC_NO_COMMON_BLOCKS = NO; INFOPLIST_FILE = Runner/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/star_lock/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/star_lock/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 2820dca7..77bd9a21 100644 --- a/star_lock/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/star_lock/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ ().listen((event) { state.udpStatus.value = event.udpStatus; }); } + Future _readG711Data() async { + String filePath = 'assets/s10-g711.bin'; + List audioData = await G711().readAssetFile(filePath); + // Get.log('发送读取711文件数据为:$audioData');// 数据为:$audioData + // return; + // print('发送读取711文件数据长度为:${audioData.length}');// 数据为:$audioData + if (audioData.isNotEmpty) { + // 在这里处理你的音频数据 + // pcmBytes = G711().convertList(audioData); + // print('发送转换pcmBytes数据长度为:${pcmBytes.length}'); + + int start = 0; + int length = 320; + while (start < audioData.length) { + // await Future.delayed(const Duration(milliseconds: 50)); + + int end = (start + length > audioData.length) ? audioData.length : start + length; + List sublist = audioData.sublist(start, end); + sendRecordData({ + "bytes": sublist, + // "udpSendDataFrameNumber": 0, + "lockID": UDPManage().lockId, + "lockIP": UDPManage().host, + "userMobile": await state.userMobile, + "userMobileIP": await state.userMobileIP, + }); + print(sublist); + start += length; + } + print('G711数据发送完成'); + } else { + print('Failed to read audio data.'); + } + } + + Future startProcessing() async { + frameListener(List frame) async { + Get.log('Get data.length:${frame.length} Received data:$frame'); + for (int i = 0; i < frame.length; i++) { + frame[i] = linearToULaw(frame[i]); + } + Get.log('change Get data.length:${frame.length} change Received data:$frame'); + await Future.delayed(const Duration(milliseconds: 50)); + sendRecordData({ + "bytes": frame, + // "udpSendDataFrameNumber": 0, + "lockID": UDPManage().lockId, + "lockIP": UDPManage().host, + "userMobile": await state.userMobile, + "userMobileIP": await state.userMobileIP, + }); + } + + errorListener(VoiceProcessorException error) { + print("VoiceProcessorException: $error"); + }; + state.voiceProcessor?.addFrameListener(frameListener); + state.voiceProcessor?.addErrorListener(errorListener); + + try { + if (await state.voiceProcessor?.hasRecordAudioPermission() ?? false) { + await state.voiceProcessor?.start(320, 8000); + bool? isRecording = await state.voiceProcessor?.isRecording(); + + } else { + + } + } on PlatformException catch (ex) { + Get.log("PlatformException: $ex"); + } finally { + + } + } + + Future stopProcessing() async { + try { + await state.voiceProcessor?.stop(); + } on PlatformException catch (ex) { + Get.log("PlatformException: $ex"); + } finally { + + } + } + + void onError(Object e) { + print(e); + } + + sendRecordData(Map args) async { + + List bytes = args["bytes"]; + // int udpSendDataFrameNumber = args["udpSendDataFrameNumber"]; + String? lockID = args["lockID"]; + String? lockIP = args["lockIP"]; + String? userMobile = args["userMobile"]; + String? userMobileIP = args["userMobileIP"]; + + // int length = 320; // 每个子List的长度 + // List list = state.listAudioData.value.sublist(0, 320); + // for (int i = 0; i < bytes.length; i += length) { + // int end = (i + length < bytes.length) ? i + length : bytes.length; + // bytes.sublist(i, end); + // // _sendRecordData(bytes.sublist(i, end)); + // // // 刚进来是接听状态,然后改为长按对讲 + // } + + // while(list.isNotEmpty) { + state.udpSendDataFrameNumber++; + if (state.udpSendDataFrameNumber >= 65536) state.udpSendDataFrameNumber=1; + // 57 + List topBytes = []; + + // var cID = "XXXCID"; + // List cIDData = utf8.encode(cID!); + // topBytes.addAll(cIDData); + // // topBytes = getFixedLengthList(cIDData, 20 - cIDData.length); + // for (int i = 0; i < 6 - cIDData.length; i++) { + // topBytes.add(0); + // } + // + // // 命令 + // topBytes.add(150); + // + // // 命令类型 + // topBytes.add(1); + // + // // 子命令 + // topBytes.add(8); + // + // // lockID + // List lockIDData = utf8.encode(lockID!); + // topBytes.addAll(lockIDData); + // // topBytes = getFixedLengthList(lockIDData, 20 - lockIDData.length); + // for (int i = 0; i < 20 - lockIDData.length; i++) { + // topBytes.add(0); + // } + // + // // lockIP + // var lockIPList = lockIP!.split("."); + // lockIPList.forEach((element) { + // topBytes.add(int.parse(element)); + // }); + // + // // userMobile + // List userMobileData = utf8.encode(userMobile!); + // topBytes.addAll(userMobileData); + // // topBytes = getFixedLengthList(topBytes, 20 - userMobileData.length); + // for (int i = 0; i < 20 - userMobileData.length; i++) { + // topBytes.add(0); + // } + // + // // userMobileIP + // var userMobileIPList = userMobileIP!.split("."); + // userMobileIPList.forEach((element) { + // topBytes.add(int.parse(element)); + // }); + + topBytes.addAll([ + 1, 1, 1, 1, // 时间戳 + 1, 0, // 音频 + 1, 0, // 帧序号 + 64, 0, 0, 0, // 帧长度 + 1, 0, // 总包数 + 1, 0, // 当前包号 + 64, 1, // 数据长度 + 176, 4, // 保留 + ]); + + topBytes[6] = (state.udpSendDataFrameNumber & 0x000000FF); + topBytes[7] = ((state.udpSendDataFrameNumber & 0x0000FF00) >> 8); + + print("udpSendDataFrameNumber:${state.udpSendDataFrameNumber} topBytes[63]:${topBytes[6]} topBytes[64]:${topBytes[7]}"); + topBytes.addAll(bytes); + Get.log("setVoiceBytes:$topBytes"); + + UDPSenderManage.sendMainProtocol( + command: 150, + commandTypeIsCalling: 1, + subCommand: 8, + lockID: lockID, + lockIP: lockIP, + userMobile: userMobile, + userMobileIP: userMobileIP, + endData: topBytes + ); + + // UDPManage().sendData(topBytes); + } + + // 拿到的音频转化成pcm + int linearToULaw(int pcmVal) { + int mask; + int seg; + int uval; + + if (pcmVal < 0) { + pcmVal = 0x84 - pcmVal; + mask = 0x7F; + } else { + pcmVal += 0x84; + mask = 0xFF; + } + + seg = search(pcmVal); + if (seg >= 8) { + return 0x7F ^ mask; + } else { + uval = (seg << 4); + uval |= ((pcmVal >> (seg + 3)) & 0xF); + return uval ^ mask; + } + } + + int search(int val) { + List table = [0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF]; + int size = 8; + for (int i = 0; i < size; i++) { + if (val <= table[i]) { + return i; + } + } + return size; + } + + double _calculateVolumeLevel(List frame) { + double rms = 0.0; + for (int sample in frame) { + rms += pow(sample, 2); + } + rms = sqrt(rms / frame.length); + + double dbfs = 20 * log(rms / 32767.0) / log(10); + double normalizedValue = (dbfs + 50) / 50; + return normalizedValue.clamp(0.0, 1.0); + } + Future getPermissionStatus() async { Permission permission = Permission.microphone; //granted 通过,denied 被拒绝,permanentlyDenied 拒绝且不在提示 @@ -67,6 +314,8 @@ class LockMonitoringLogic extends BaseGetXController { _getTVDataRefreshUIAction(); _getUDPStatusRefreshUIAction(); + + initRecorder(); } @override @@ -81,5 +330,7 @@ class LockMonitoringLogic extends BaseGetXController { print("锁详情界面销毁了"); _getTVDataRefreshUIEvent!.cancel(); _getUDPStatusRefreshUIEvent!.cancel(); + + stopProcessing(); } } diff --git a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart index 69e908b0..78d24564 100644 --- a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart +++ b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart @@ -1,26 +1,13 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; -import 'dart:isolate'; -import 'dart:typed_data'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:flutter_sound/flutter_sound.dart'; import 'package:get/get.dart'; -import 'package:network_info_plus/network_info_plus.dart'; -import 'package:path_provider/path_provider.dart'; -import 'package:flutter_audio_capture/flutter_audio_capture.dart'; import '../../../../app_settings/app_colors.dart'; -import '../../../../blue/io_tool/io_tool.dart'; import '../../../../talk/udp/udp_manage.dart'; import '../../../../talk/udp/udp_senderManage.dart'; -import '../../../../talk/udp/udp_talkClass.dart'; import '../../../../tools/showTFView.dart'; -import '../../../../tools/storage.dart'; import '../../../../tools/toast.dart'; import 'lockMonitoring_logic.dart'; @@ -35,18 +22,6 @@ class _LockMonitoringPageState extends State { final logic = Get.put(LockMonitoringLogic()); final state = Get.find().state; - late FlutterAudioCapture audioCapture; - // late FlutterSoundRecorder recorder; - // late FlutterSoundPlayer player; - // late String filePath; - - @override - void initState() { - super.initState(); - - _initRecorder(); - } - @override Widget build(BuildContext context) { return SizedBox( @@ -177,9 +152,9 @@ class _LockMonitoringPageState extends State { if (!value) { return; } - var userMobileIP = await NetworkInfo().getWifiIP(); - var userMobile = await Storage.getMobile(); + // state.isSenderAudioData.value = false; + print("发送接听了"); // 刚进来是接听状态,然后改为长按对讲 UDPSenderManage.sendMainProtocol( command: 150, @@ -187,8 +162,8 @@ class _LockMonitoringPageState extends State { subCommand: 6, lockID: UDPManage().lockId, lockIP: UDPManage().host, - userMobile: userMobile, - userMobileIP: userMobileIP, + userMobile: await state.userMobile, + userMobileIP: await state.userMobileIP, endData: [] ); }); @@ -196,27 +171,24 @@ class _LockMonitoringPageState extends State { longPress: (){ // 开始长按 print("onLongPress"); + state.listAudioData.value = []; if (state.udpStatus.value == 8) { state.udpStatus.value = 9; } - _startRecording(); + // logic.readG711Data(); + logic.startProcessing(); }, longPressUp: () async { // 长按结束 print("onLongPressUp"); - // _playRecording(); - - // _stopCapture(); if (state.udpStatus.value == 9) { state.udpStatus.value = 8; } } ) ), - bottomBtnItemWidget( - "images/main/icon_lockDetail_hangUp.png", "挂断", Colors.red, () async { - var userMobileIP = await NetworkInfo().getWifiIP(); - var userMobile = await Storage.getMobile(); + bottomBtnItemWidget("images/main/icon_lockDetail_hangUp.png", "挂断", Colors.red, () async { + logic.stopProcessing(); // 挂断 UDPSenderManage.sendMainProtocol( @@ -225,15 +197,12 @@ class _LockMonitoringPageState extends State { subCommand: 30, lockID: UDPManage().lockId, lockIP: UDPManage().host, - userMobile: userMobile, - userMobileIP: userMobileIP, + userMobile: await state.userMobile, + userMobileIP: await state.userMobileIP, endData: []); }), - bottomBtnItemWidget("images/main/icon_lockDetail_monitoringUnlock.png", - "开锁", AppColors.mainColor, () { - - // _playRecording(); - showDeletPasswordAlertDialog(context); + bottomBtnItemWidget("images/main/icon_lockDetail_monitoringUnlock.png", "开锁", AppColors.mainColor, () { + showDeletPasswordAlertDialog(context); }) ]); } @@ -296,7 +265,7 @@ class _LockMonitoringPageState extends State { context: context, builder: (BuildContext context) { return ShowTFView( - title: "请输入开锁密码", + title: "请输入六位数字开锁密码", tipTitle: "", controller: state.passwordTF, inputFormatters: [ @@ -310,9 +279,6 @@ class _LockMonitoringPageState extends State { return; } - var userMobileIP = await NetworkInfo().getWifiIP(); - var userMobile = await Storage.getMobile(); - // 开锁 UDPSenderManage.sendMainProtocol( command: 150, @@ -320,8 +286,8 @@ class _LockMonitoringPageState extends State { subCommand: 10, lockID: UDPManage().lockId, lockIP: UDPManage().host, - userMobile: userMobile, - userMobileIP: userMobileIP, + userMobile: await state.userMobile, + userMobileIP: await state.userMobileIP, endData: []); Get.back(); }, @@ -337,328 +303,5 @@ class _LockMonitoringPageState extends State { void dispose() { super.dispose(); - // UDPTalkClass().isBeCall = false; } - - //录音处理 - _initRecorder() { - // recorder = FlutterSoundRecorder(); - audioCapture = FlutterAudioCapture(); - } - - // Future _startRecording(List dataList) async { - // try { - // await recorder.openAudioSession(); - // /// 监听录音 - // recorder.onProgress!.listen((e) { - // print("onProgress:$e"); - // }); - // - // await recorder.startRecorder( - // onProgress: (StreamController progress) { - // progress.stream.listen((FooderData fooData) { - // // 在这里处理 PCM 数据(fooData.buffer) - // print('Received PCM data: ${fooData.buffer.length} bytes'); - // }); - // }, - // ); - // setState(() { - // _isRecording = true; - // }); - // } catch (e) { - // print('Error starting recording: $e'); - // } - // } - - // Future _stopRecording() async { - // try { - // await recorder.stopRecorder(); - // await _recorder.closeAudioSession(); - // setState(() { - // _isRecording = false; - // }); - // } catch (e) { - // print('Error stopping recording: $e'); - // } - // } - - -//开始录音 - _startRecording() async { - try { - // _getFilePath().then((value) { - // filePath = value; - // }); - // await recorder.openRecorder(); - // // 监听录音 - // recorder.onProgress!.listen((e) { - // print("onProgress:$e"); - // }); - // await recorder.startRecorder( - // toFile: filePath, - // codec: Codec.pcm16WAV, - // bitRate: 8000, - // numChannels: 1, - // sampleRate: 8000, - // ); - - _startCapture(); - } catch (e) { - print('Error starting recording: $e'); - } - - // getFilePath().then((value) { - // filePath = value; - // }); - // await recorder.openRecorder(); - // await recorder.startRecorder( - // toFile: filePath, - // codec: Codec.pcm16WAV, - // bitRate: 8000, - // numChannels: 1, - // sampleRate: 8000, - // ); - } - - Future _startCapture() async { - await audioCapture.start( - _listener, - onError, - sampleRate: 8000, - bufferSize: 3000 - ); - } - - Future _stopCapture() async { - await audioCapture.stop(); - } - - Future _listener(dynamic obj) async { - print('data.length:${obj.length} Received data:$obj'); - var buffer = Float64List.fromList(obj.cast()); - Int16List list = float64ListToInt16List(buffer); - print('Get data.length:${list.length} Received data:$list'); - for (int i = 0; i < list.length; i++) { - list[i] = linearToULaw(list[i]); - } - print('change Get data.length:${list.length} change Received data:$list'); - List sendList = list.toList(); - - Isolate isolate = await Isolate.spawn(_sendRecordData, { - "bytes": sendList, - "udpSendDataFrameNumber": 0, - "lockID": UDPManage().lockId, - "lockIP": UDPManage().host, - "userMobile": await Storage.getMobile(), - "userMobileIP": await NetworkInfo().getWifiIP(), - }); - - // 在主线程中监听子线程发送的数据 - // receivePort.listen((data) { - // print('Received data: $data'); - // }); - } - - void onError(Object e) { - print(e); - } - - int linearToULaw(int pcmVal) { - int mask; - int seg; - int uval; - - if (pcmVal < 0) { - pcmVal = 0x84 - pcmVal; - mask = 0x7F; - } else { - pcmVal += 0x84; - mask = 0xFF; - } - - seg = search(pcmVal); - if (seg >= 8) { - return 0x7F ^ mask; - } else { - uval = (seg << 4); - uval |= ((pcmVal >> (seg + 3)) & 0xF); - return uval ^ mask; - } - } - - int search(int val) { - List table = [0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF]; - int size = 8; - for (int i = 0; i < size; i++) { - if (val <= table[i]) { - return i; - } - } - return size; - } - - Int16List float64ListToInt16List(Float64List float64List) { - Int16List int16List = Int16List(float64List.length); - for (int i = 0; i < float64List.length; i++) { - double sample = float64List[i]; - // Make sure the sample value is within the int16 range - if (sample > 1.0) { - sample = 1.0; - } else if (sample < -1.0) { - sample = -1.0; - } - // Convert the sample to int16 by scaling it to the full int16 range - int16List[i] = (sample * 32767).toInt(); - } - return int16List; - } - - //停止录音 - // _stopRecording() async { - // try { - // await recorder.stopRecorder(); - // } catch (e) { - // print('Error stopping recording: $e'); - // } - - // await recorder.stopRecorder(); - // - // // final file = File(filePath); - // File file = File(filePath); // 使用 create 方法创建文件 - // - // print('filePathfilePath:$filePath file:$file await file.exists():${await file.exists()}'); - // if (await file.exists()) { - // final List bytes = await file.readAsBytes(); - // print('Recorded audio bytes.length:${bytes.length} bytes: $bytes'); - // - // _sendRecordData(bytes); - // } - // } - - // Future _getFilePath() async { - // final directory = await getApplicationDocumentsDirectory(); - // final filePath = '${directory.path}/recording.wav'; - // - // // 创建文件 - // File file = File(filePath); - // await file.create(); // 使用 create 方法创建文件 - // - // return filePath; - // } - - - // Future _getRecordedAudioBytes() async { - // final file = File(filePath); - // if (await file.exists()) { - // final List bytes = await file.readAsBytes(); - // print('Recorded audio bytes: $bytes'); - // } - // } - - //播放录音 - // _playRecording() async { - // player = FlutterSoundPlayer(); - // player.openPlayer(); - // - // await player.startPlayer( - // fromURI: filePath, - // codec: Codec.pcm16WAV, - // ); - // Toast.show(msg: "储存录音播放了"); - // print('_playRecording() 储存录音播放了'); - // } - -//停止播放 -// _stopPlaying() async { -// await player.stopPlayer(); -// } - - // var udpSendDataFrameNumber = 0; - _sendRecordData(Map args) async { - - List bytes = args["bytes"]; - int udpSendDataFrameNumber = args["udpSendDataFrameNumber"]; - String? lockID = args["lockID"]; - String? lockIP = args["lockIP"]; - String? userMobile = args["userMobile"]; - String? userMobileIP = args["userMobileIP"]; - - int length = 320; // 每个子List的长度 - for (int i = 0; i < bytes.length; i += length) { - int end = (i + length < bytes.length) ? i + length : bytes.length; - bytes.sublist(i, end); - // _sendRecordData(bytes.sublist(i, end)); - // // 刚进来是接听状态,然后改为长按对讲 - // var userMobileIP = await NetworkInfo().getWifiIP(); - // var userMobile = await Storage.getMobile(); - - while(true) { - udpSendDataFrameNumber++; - if (udpSendDataFrameNumber >= 65536) udpSendDataFrameNumber=1; - // 57 - List topBytes = [ - 1, 1, 1, 1, // 时间戳 - 1, 0, // 音频 - 1, 0, // 帧序号 - 64, 0, 0, 0, // 帧长度 - 1, 0, // 总包数 - 1, 0, // 当前包号 - 64, 1, // 数据长度 - 176, 4, // 保留 - ]; - - ByteData byteData = ByteData(2); - byteData.setUint16(0, udpSendDataFrameNumber, Endian.little); - topBytes[6] = byteData.getUint8(0); - topBytes[7] = byteData.getUint8(1); - - topBytes.addAll(bytes); - // print("topBytes:$topBytes"); - // UDPSenderManage.sendMainProtocol( - // command: 150, - // commandTypeIsCalling: 1, - // subCommand: 8, - // lockID: lockID, - // lockIP: lockIP, - // userMobile: userMobile, - // userMobileIP: userMobileIP, - // endData: topBytes - // ); - - // 命令 - topBytes.add(150); - - // 命令类型 - topBytes.add(1); - - // 子命令 - topBytes.add(8); - - // lockID - List lockIDData = utf8.encode(lockID!); - topBytes.addAll(lockIDData); - topBytes = getFixedLengthList(lockIDData, 20 - lockIDData.length); - - // lockIP - var lockIPList = lockIP!.split("."); - lockIPList.forEach((element) { - topBytes.add(int.parse(element)); - }); - - // userMobile - List userMobileData = utf8.encode(userMobile!); - topBytes.addAll(userMobileData); - topBytes = getFixedLengthList(topBytes, 20 - userMobileData.length); - - // userMobileIP - var userMobileIPList = lockIP!.split("."); - userMobileIPList.forEach((element) { - topBytes.add(int.parse(element)); - }); - - UDPManage().sendData(topBytes); - } - } - } - } diff --git a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_state.dart b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_state.dart index 3e70b79c..fe3391cf 100644 --- a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_state.dart +++ b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_state.dart @@ -1,14 +1,33 @@ +import 'dart:async'; import 'dart:typed_data'; import 'package:flutter/material.dart'; +import 'package:flutter_voice_processor/flutter_voice_processor.dart'; import 'package:get/get.dart'; +import 'package:network_info_plus/network_info_plus.dart'; + +import '../../../../tools/storage.dart'; class LockMonitoringState { var isOpenVoice = false.obs; var udpSendDataFrameNumber = 0;// 帧序号 - var udpStatus = - 0.obs; //0:初始状态 1:等待监视 2: 3:监视中 4:呼叫成功 5:主角通话中 6:被叫通话 8:被叫通话中 9:长按说话 + // var isSenderAudioData = false.obs;// 是否要发送音频数据 + + var userMobileIP = NetworkInfo().getWifiIP(); + var userMobile = Storage.getMobile(); + + var udpStatus = 0.obs; //0:初始状态 1:等待监视 2: 3:监视中 4:呼叫成功 5:主角通话中 6:被叫通话 8:被叫通话中 9:长按说话 var passwordTF = TextEditingController(); var listData = Uint8List(0).obs; //得到的视频流字节数据 + var listAudioData = [].obs; //得到的音频流字节数据 + + late final VoiceProcessor? voiceProcessor; + + // 定时器超过60秒关闭当前界面 + late Timer oneMinuteTimeTimer; + // 定时器如果发送了接听的命令 而没收到回复就每秒重复发送10次 + late Timer answerTimer; + late Timer hangUpTimer; + late Timer openDoorTimer; } diff --git a/star_lock/lib/talk/udp/io_protocol/udp_mainProtocol.dart b/star_lock/lib/talk/udp/io_protocol/udp_mainProtocol.dart index 0fffeb9b..478e4e55 100644 --- a/star_lock/lib/talk/udp/io_protocol/udp_mainProtocol.dart +++ b/star_lock/lib/talk/udp/io_protocol/udp_mainProtocol.dart @@ -43,8 +43,12 @@ class UDPMainProtocolCommand extends UDPSenderProtocol { data.add(subCommand!); // lockID - data.addAll(utf8.encode(lockID!)); - data = getFixedLengthList(data, 20 - utf8.encode(lockID!).length); + List lockIDData = utf8.encode(lockID!); + data.addAll(lockIDData); + // topBytes = getFixedLengthList(lockIDData, 20 - lockIDData.length); + for (int i = 0; i < 20 - lockIDData.length; i++) { + data.add(0); + } // lockIP var lockIPList = lockIP!.split("."); @@ -53,8 +57,12 @@ class UDPMainProtocolCommand extends UDPSenderProtocol { }); // userMobile - data.addAll(utf8.encode(userMobile!)); - data = getFixedLengthList(data, 20 - utf8.encode(userMobile!).length); + List userMobileData = utf8.encode(userMobile!); + data.addAll(userMobileData); + // topBytes = getFixedLengthList(topBytes, 20 - userMobileData.length); + for (int i = 0; i < 20 - userMobileData.length; i++) { + data.add(0); + } // userMobileIP var userMobileIPList = lockIP!.split("."); diff --git a/star_lock/linux/flutter/generated_plugin_registrant.cc b/star_lock/linux/flutter/generated_plugin_registrant.cc index f03aaf40..05d9a9b9 100644 --- a/star_lock/linux/flutter/generated_plugin_registrant.cc +++ b/star_lock/linux/flutter/generated_plugin_registrant.cc @@ -9,7 +9,6 @@ #include #include #include -#include #include void fl_register_plugins(FlPluginRegistry* registry) { @@ -22,9 +21,6 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); file_selector_plugin_register_with_registrar(file_selector_linux_registrar); - g_autoptr(FlPluginRegistrar) flutter_audio_capture_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterAudioCapturePlugin"); - flutter_audio_capture_plugin_register_with_registrar(flutter_audio_capture_registrar); g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); diff --git a/star_lock/linux/flutter/generated_plugins.cmake b/star_lock/linux/flutter/generated_plugins.cmake index 01b1e1e7..b6e600e9 100644 --- a/star_lock/linux/flutter/generated_plugins.cmake +++ b/star_lock/linux/flutter/generated_plugins.cmake @@ -6,7 +6,6 @@ list(APPEND FLUTTER_PLUGIN_LIST aj_captcha_flutter audioplayers_linux file_selector_linux - flutter_audio_capture url_launcher_linux ) diff --git a/star_lock/macos/Flutter/GeneratedPluginRegistrant.swift b/star_lock/macos/Flutter/GeneratedPluginRegistrant.swift index ed8af5a9..ff949269 100644 --- a/star_lock/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/star_lock/macos/Flutter/GeneratedPluginRegistrant.swift @@ -9,7 +9,6 @@ import aj_captcha_flutter import audio_session import audioplayers_darwin import device_info_plus -import ffmpeg_kit_flutter import file_selector_macos import just_audio import network_info_plus @@ -24,7 +23,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin")) AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) - FFmpegKitFlutterPlugin.register(with: registry.registrar(forPlugin: "FFmpegKitFlutterPlugin")) FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin")) NetworkInfoPlusPlugin.register(with: registry.registrar(forPlugin: "NetworkInfoPlusPlugin")) diff --git a/star_lock/pubspec.yaml b/star_lock/pubspec.yaml index fcd0b488..2536969e 100644 --- a/star_lock/pubspec.yaml +++ b/star_lock/pubspec.yaml @@ -125,16 +125,17 @@ dependencies: convert: ^3.1.1 just_audio: ^0.9.36 flutter_sound: ^9.2.13 - ffmpeg_kit_flutter: 5.1.0-LTS +# ffmpeg_kit_flutter: 5.1.0-LTS fast_gbk: ^1.0.0 - flutter_audio_capture: ^1.1.6 +# flutter_audio_capture: <1.1.5 + flutter_voice_processor: ^1.1.0 dev_dependencies: flutter_test: sdk: flutter # The "flutter_lints" package below contains a set of recommended lints to - # encourage good coding practices. The lint set provided by the package is + # encourage good coding practices. The lint fset provided by the package is # activated in the `analysis_options.yaml` file located at the root of your # package. See that file for information about deactivating specific lint # rules and activating additional ones. From 286fce3c096b0176814f2f257bd70c17c912afca Mon Sep 17 00:00:00 2001 From: Daisy <> Date: Fri, 29 Dec 2023 14:31:25 +0800 Subject: [PATCH 29/33] =?UTF-8?q?pcm=E9=9F=B3=E9=A2=91=E6=92=AD=E6=94=BE?= =?UTF-8?q?=E6=8F=92=E4=BB=B6=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- star_lock/ios/Podfile.lock | 6 + star_lock/lib/talk/call/callTalk.dart | 108 ++++++------------ .../Flutter/GeneratedPluginRegistrant.swift | 2 + star_lock/pubspec.yaml | 1 + 4 files changed, 45 insertions(+), 72 deletions(-) diff --git a/star_lock/ios/Podfile.lock b/star_lock/ios/Podfile.lock index 962d06af..93ff623d 100644 --- a/star_lock/ios/Podfile.lock +++ b/star_lock/ios/Podfile.lock @@ -48,6 +48,8 @@ PODS: - Flutter (1.0.0) - flutter_native_contact_picker (0.0.1): - Flutter + - flutter_pcm_sound (0.0.1): + - Flutter - flutter_sound (9.2.13): - Flutter - flutter_sound_core (= 9.2.13) @@ -117,6 +119,7 @@ DEPENDENCIES: - ffmpeg_kit_flutter (from `.symlinks/plugins/ffmpeg_kit_flutter/ios`) - Flutter (from `Flutter`) - flutter_native_contact_picker (from `.symlinks/plugins/flutter_native_contact_picker/ios`) + - flutter_pcm_sound (from `.symlinks/plugins/flutter_pcm_sound/ios`) - flutter_sound (from `.symlinks/plugins/flutter_sound/ios`) - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`) - g711_flutter (from `.symlinks/plugins/g711_flutter/ios`) @@ -180,6 +183,8 @@ EXTERNAL SOURCES: :path: Flutter flutter_native_contact_picker: :path: ".symlinks/plugins/flutter_native_contact_picker/ios" + flutter_pcm_sound: + :path: ".symlinks/plugins/flutter_pcm_sound/ios" flutter_sound: :path: ".symlinks/plugins/flutter_sound/ios" fluttertoast: @@ -238,6 +243,7 @@ SPEC CHECKSUMS: ffmpeg_kit_flutter: fb5bee3a6038231463ee99e30f97a5763e0ae40f Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 flutter_native_contact_picker: bd430ba0fbf82768bb50c2c52a69a65759a8f907 + flutter_pcm_sound: de0572ca4f99091cc2abfcc31601b8a4ddd33c0e flutter_sound: c60effa2a350fb977885f0db2fbc4c1ad5160900 flutter_sound_core: 26c10e5832e76aaacfae252d8925232281c486ae fluttertoast: fafc4fa4d01a6a9e4f772ecd190ffa525e9e2d9c diff --git a/star_lock/lib/talk/call/callTalk.dart b/star_lock/lib/talk/call/callTalk.dart index 403376c6..0d65f2c5 100644 --- a/star_lock/lib/talk/call/callTalk.dart +++ b/star_lock/lib/talk/call/callTalk.dart @@ -1,11 +1,11 @@ +import 'dart:convert'; import 'dart:typed_data'; -import 'package:audioplayers/audioplayers.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_sound/flutter_sound.dart'; +import 'package:flutter/foundation.dart'; import 'package:star_lock/talk/call/g711.dart'; import 'package:star_lock/talk/call/iFrameInfo.dart'; -import 'package:star_lock/talk/udp/udp_talkClass.dart'; import '../../tools/eventBusEventManage.dart'; +import 'package:flutter_pcm_sound/flutter_pcm_sound.dart'; +import 'package:flutter_sound/flutter_sound.dart'; class CallTalk { static CallTalk? _manager; @@ -22,9 +22,9 @@ class CallTalk { IframeInfo? iframe; // 假设有这个成员变量 var growableList; bool getFirstFrame = false; //是否得到了第一帧 - final FlutterSoundPlayer _audioPlayer = FlutterSoundPlayer(); List allPcmData = []; - int _bufferSize = 400; // 设置缓冲区大小,根据需求调整 + int _remainingFrames = 0; + bool getAudio = false; CallTalk._init() { iframe = IframeInfo(); @@ -48,8 +48,14 @@ class CallTalk { // 将 ALaw 转为 Linear pcmBytes = G711().convertList(g711Data); allPcmData.addAll(pcmBytes); - // await Future.delayed(const Duration(seconds: 1)); - _initializeAudioPlayer(allPcmData); + // if (_remainingFrames == 0) { + // _remainingFrames = 1; + // print('延迟了么1'); + + // await Future.delayed(const Duration(milliseconds: 50)); + // } + + _initializeAudioPlayer(pcmBytes); } catch (e) { print('Error decoding G.711 to PCM: $e'); } @@ -118,74 +124,32 @@ class CallTalk { } } -//视频相关处理 - void printByteArray(String printTitle, Uint8List byteArray) { - final int chunkSize = byteArray.length; // 每行显示的字节数 - int length = byteArray.length; - - for (int i = 0; i < length; i += chunkSize) { - int end = (i + chunkSize < length) ? i + chunkSize : length; - Uint8List chunk = byteArray.sublist(i, end); - - String hexString = - chunk.map((byte) => byte.toRadixString(16).padLeft(2, '0')).join(' '); - debugPrint(hexString); - } - } - //音频相关处理 Future _initializeAudioPlayer(List audioData) async { - // _audioPlayer.closePlayer(); - _audioPlayer.openPlayer(); + FlutterPcmSound.setLogLevel(LogLevel.error); + FlutterPcmSound.setup(sampleRate: 8000, channelCount: 1); + FlutterPcmSound.setFeedThreshold(8000 * 10); + // FlutterPcmSound.setFeedCallback(onFeed); + PcmArrayInt16 fromList = PcmArrayInt16.fromList(audioData); + await FlutterPcmSound.feed(fromList); - // await _audioPlayer - // .setSubscriptionDuration(const Duration(milliseconds: 10)); - if (audioData.isNotEmpty) { - // 在这里处理你的音频数据 - print('转换pcmBytes数据长度为:${audioData.length}'); - // _playRawData(audioData); - playAudioStream(audioData); + FlutterPcmSound.play(); + } + + void onFeed(int remainingFrames) async { + int framesToFeed = 320; + + if (allPcmData.length >= framesToFeed) { + List frames = allPcmData.sublist(0, framesToFeed); + allPcmData.removeRange(0, framesToFeed); + + // 将数据传递给 FlutterPcmSound + PcmArrayInt16 fromList = PcmArrayInt16.fromList(frames); + await FlutterPcmSound.feed(fromList); + FlutterPcmSound.play(); } else { - print('Failed to read audio data.'); + // 处理长度不足的情况,可以等待更多数据或者采取其他措施 + print("Not enough data in allPcmData."); } } - - Future _playRawData(List rawData) async { - print( - '啊啦啦啦啦啦数据长度为:${G711().convertToInt8ListLittleEndian(rawData).length}, 数据为 ${G711().convertToInt8ListLittleEndian(rawData)}'); - - await _audioPlayer.startPlayer( - fromDataBuffer: G711().convertToInt8ListLittleEndian(rawData), - codec: Codec.pcm16, - sampleRate: 8000, - numChannels: 1, - ); - } - - Future playAudioStream(List audioData) async { - await _audioPlayer - .setSubscriptionDuration(const Duration(milliseconds: 10)); - - // 启动播放器 - await _audioPlayer.startPlayer( - codec: Codec.pcm16, - sampleRate: 8000, - numChannels: 1, - ); - - // 将音频数据逐步添加到缓冲区 - for (int i = 0; i < audioData.length; i += 320) { - int chunkSize = 320; - if (i + chunkSize > audioData.length) { - chunkSize = audioData.length - i; - } - - List chunk = audioData.sublist(i, i + chunkSize); - await _audioPlayer - .feedFromStream(G711().convertToInt8ListLittleEndian(chunk)); - } - - // 停止播放器 - await _audioPlayer.stopPlayer(); - } } diff --git a/star_lock/macos/Flutter/GeneratedPluginRegistrant.swift b/star_lock/macos/Flutter/GeneratedPluginRegistrant.swift index ed8af5a9..2d44de26 100644 --- a/star_lock/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/star_lock/macos/Flutter/GeneratedPluginRegistrant.swift @@ -11,6 +11,7 @@ import audioplayers_darwin import device_info_plus import ffmpeg_kit_flutter import file_selector_macos +import flutter_pcm_sound import just_audio import network_info_plus import package_info_plus @@ -26,6 +27,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) FFmpegKitFlutterPlugin.register(with: registry.registrar(forPlugin: "FFmpegKitFlutterPlugin")) FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) + FlutterPcmSoundPlugin.register(with: registry.registrar(forPlugin: "FlutterPcmSoundPlugin")) JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin")) NetworkInfoPlusPlugin.register(with: registry.registrar(forPlugin: "NetworkInfoPlusPlugin")) FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin")) diff --git a/star_lock/pubspec.yaml b/star_lock/pubspec.yaml index fcd0b488..0ea60ff9 100644 --- a/star_lock/pubspec.yaml +++ b/star_lock/pubspec.yaml @@ -128,6 +128,7 @@ dependencies: ffmpeg_kit_flutter: 5.1.0-LTS fast_gbk: ^1.0.0 flutter_audio_capture: ^1.1.6 + flutter_pcm_sound: ^1.1.0 dev_dependencies: flutter_test: From 0c5e71f231c07d0a66d86010e4c36a53a74e38c0 Mon Sep 17 00:00:00 2001 From: Daisy <> Date: Fri, 29 Dec 2023 18:10:22 +0800 Subject: [PATCH 30/33] =?UTF-8?q?=E9=9F=B3=E9=A2=91=E6=92=AD=E6=94=BE?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E9=80=9A=E8=BF=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- star_lock/lib/main.dart | 51 ++++++++++++++++++++------- star_lock/lib/talk/call/callTalk.dart | 35 ++---------------- 2 files changed, 42 insertions(+), 44 deletions(-) diff --git a/star_lock/lib/main.dart b/star_lock/lib/main.dart index 5dc9a493..ec2431f8 100644 --- a/star_lock/lib/main.dart +++ b/star_lock/lib/main.dart @@ -4,6 +4,7 @@ import 'package:audioplayers/audioplayers.dart'; import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:flutter_pcm_sound/flutter_pcm_sound.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_sound/flutter_sound.dart'; import 'package:get/get.dart'; @@ -56,6 +57,7 @@ class _MyAppState extends State with WidgetsBindingObserver, BaseWidget { var _deviceId = ""; // final audioPlayer = AudioPlayer(); final FlutterSoundPlayer _audioPlayer = FlutterSoundPlayer(); + late List allDataBytes; @override Widget build(BuildContext context) { @@ -167,9 +169,9 @@ class _MyAppState extends State with WidgetsBindingObserver, BaseWidget { //音频相关处理 Future _initializeAudioPlayer() async { - await _audioPlayer.closePlayer(); - await _audioPlayer.openPlayer(); - await _audioPlayer.setSubscriptionDuration(Duration(milliseconds: 10)); + // await _audioPlayer.closePlayer(); + // await _audioPlayer.openPlayer(); + // await _audioPlayer.setSubscriptionDuration(Duration(milliseconds: 10)); List pcmBytes; @@ -180,6 +182,8 @@ class _MyAppState extends State with WidgetsBindingObserver, BaseWidget { if (audioData.isNotEmpty) { // 在这里处理你的音频数据 pcmBytes = G711().convertList(audioData); + allDataBytes = pcmBytes; + // allDataBytes = pcmBytes.sublist(0, 640); print('转换pcmBytes数据长度为:${pcmBytes.length}'); _playRawData(pcmBytes); } else { @@ -188,16 +192,39 @@ class _MyAppState extends State with WidgetsBindingObserver, BaseWidget { } Future _playRawData(List rawData) async { - print( - '啊啦啦啦啦啦数据长度为:${G711().convertToInt8ListLittleEndian(rawData).length}, 数据为 ${G711().convertToInt8ListLittleEndian(rawData)}'); + // print( + // '啊啦啦啦啦啦数据长度为:${G711().convertToInt8ListLittleEndian(rawData).length}, 数据为 ${G711().convertToInt8ListLittleEndian(rawData)}'); - await _audioPlayer.startPlayer( - fromURI: null, - fromDataBuffer: G711().convertToInt8ListLittleEndian(rawData), - codec: Codec.pcm16, //_codec, - sampleRate: 8000, //tSAMPLERATE, - numChannels: 1, - ); + // await _audioPlayer.startPlayer( + // fromURI: null, + // fromDataBuffer: G711().convertToInt8ListLittleEndian(rawData), + // codec: Codec.pcm16, //_codec, + // sampleRate: 8000, //tSAMPLERATE, + // numChannels: 1, + // ); + + FlutterPcmSound.setLogLevel(LogLevel.error); + FlutterPcmSound.setup(sampleRate: 8000, channelCount: 1); + FlutterPcmSound.setFeedThreshold(8000 ~/ 2); + FlutterPcmSound.setFeedCallback(onFeed); + FlutterPcmSound.play(); + } + + void onFeed(int remainingFrames) async { + int framesToFeed = 320; + + if (allDataBytes.length >= framesToFeed) { + List frames = allDataBytes.sublist(0, framesToFeed); + allDataBytes.removeRange(0, framesToFeed); + + // 将数据传递给 FlutterPcmSound + PcmArrayInt16 fromList = PcmArrayInt16.fromList(frames); + await FlutterPcmSound.feed(fromList); + FlutterPcmSound.play(); + } else { + // 处理长度不足的情况,可以等待更多数据或者采取其他措施 + print("Not enough data in allPcmData."); + } } @override diff --git a/star_lock/lib/talk/call/callTalk.dart b/star_lock/lib/talk/call/callTalk.dart index 0d65f2c5..cd6ae460 100644 --- a/star_lock/lib/talk/call/callTalk.dart +++ b/star_lock/lib/talk/call/callTalk.dart @@ -22,12 +22,12 @@ class CallTalk { IframeInfo? iframe; // 假设有这个成员变量 var growableList; bool getFirstFrame = false; //是否得到了第一帧 - List allPcmData = []; - int _remainingFrames = 0; - bool getAudio = false; CallTalk._init() { iframe = IframeInfo(); + FlutterPcmSound.setLogLevel(LogLevel.error); + FlutterPcmSound.setup(sampleRate: 8000, channelCount: 1); + FlutterPcmSound.setFeedThreshold(8000 ~/ 2); } static CallTalk _share() { @@ -47,14 +47,6 @@ class CallTalk { try { // 将 ALaw 转为 Linear pcmBytes = G711().convertList(g711Data); - allPcmData.addAll(pcmBytes); - // if (_remainingFrames == 0) { - // _remainingFrames = 1; - // print('延迟了么1'); - - // await Future.delayed(const Duration(milliseconds: 50)); - // } - _initializeAudioPlayer(pcmBytes); } catch (e) { print('Error decoding G.711 to PCM: $e'); @@ -126,30 +118,9 @@ class CallTalk { //音频相关处理 Future _initializeAudioPlayer(List audioData) async { - FlutterPcmSound.setLogLevel(LogLevel.error); - FlutterPcmSound.setup(sampleRate: 8000, channelCount: 1); - FlutterPcmSound.setFeedThreshold(8000 * 10); - // FlutterPcmSound.setFeedCallback(onFeed); PcmArrayInt16 fromList = PcmArrayInt16.fromList(audioData); await FlutterPcmSound.feed(fromList); FlutterPcmSound.play(); } - - void onFeed(int remainingFrames) async { - int framesToFeed = 320; - - if (allPcmData.length >= framesToFeed) { - List frames = allPcmData.sublist(0, framesToFeed); - allPcmData.removeRange(0, framesToFeed); - - // 将数据传递给 FlutterPcmSound - PcmArrayInt16 fromList = PcmArrayInt16.fromList(frames); - await FlutterPcmSound.feed(fromList); - FlutterPcmSound.play(); - } else { - // 处理长度不足的情况,可以等待更多数据或者采取其他措施 - print("Not enough data in allPcmData."); - } - } } From fda85f95a50426ca446eef0dbc03acd8b90976af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AD=8F=E5=B0=91=E9=98=B3?= <786612630@qq.com> Date: Fri, 29 Dec 2023 18:11:36 +0800 Subject: [PATCH 31/33] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=AF=B9=E8=AE=B2?= =?UTF-8?q?=E5=8F=91=E9=80=81=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- star_lock/.flutter-plugins-dependencies 2 | 1 - star_lock/ios/Podfile.lock | 22 ++++-- .../monitoring/lockMonitoring_logic.dart | 74 ++++++++++++++++- .../monitoring/lockMonitoring_page.dart | 79 ++++++++----------- .../monitoring/lockMonitoring_state.dart | 6 +- star_lock/lib/talk/udp/udp_reciverData.dart | 2 + 6 files changed, 123 insertions(+), 61 deletions(-) delete mode 100644 star_lock/.flutter-plugins-dependencies 2 diff --git a/star_lock/.flutter-plugins-dependencies 2 b/star_lock/.flutter-plugins-dependencies 2 deleted file mode 100644 index 976fa555..00000000 --- a/star_lock/.flutter-plugins-dependencies 2 +++ /dev/null @@ -1 +0,0 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"aj_captcha_flutter","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/aj_captcha_flutter-0.0.1/","native_build":true,"dependencies":[]},{"name":"aliyun_push","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/aliyun_push-0.1.6/","native_build":true,"dependencies":[]},{"name":"amap_flutter_location","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/amap_flutter_location-3.0.0/","native_build":true,"dependencies":[]},{"name":"amap_flutter_map","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/amap_flutter_map-3.0.0/","native_build":true,"dependencies":[]},{"name":"audio_session","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/audio_session-0.1.18/","native_build":true,"dependencies":[]},{"name":"audioplayers_darwin","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/audioplayers_darwin-5.0.2/","native_build":true,"dependencies":[]},{"name":"auto_orientation","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/auto_orientation-2.3.1/","native_build":true,"dependencies":[]},{"name":"camera_avfoundation","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/camera_avfoundation-0.9.13+6/","native_build":true,"dependencies":[]},{"name":"device_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/device_info_plus-8.2.2/","native_build":true,"dependencies":[]},{"name":"flutter_ffmpeg","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/flutter_ffmpeg-0.4.2/","native_build":true,"dependencies":[]},{"name":"flutter_native_contact_picker","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/flutter_native_contact_picker-0.0.4/","native_build":true,"dependencies":[]},{"name":"flutter_sound","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/flutter_sound-9.2.13/","native_build":true,"dependencies":[]},{"name":"fluttertoast","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/fluttertoast-8.2.2/","native_build":true,"dependencies":[]},{"name":"g711_flutter","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/g711_flutter-2.0.0/","native_build":true,"dependencies":[]},{"name":"google_maps_flutter_ios","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/google_maps_flutter_ios-2.3.2/","native_build":true,"dependencies":[]},{"name":"image_gallery_saver","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/image_gallery_saver-2.0.3/","native_build":true,"dependencies":[]},{"name":"image_picker_ios","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/image_picker_ios-0.8.8+2/","native_build":true,"dependencies":[]},{"name":"just_audio","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/just_audio-0.9.36/","native_build":true,"dependencies":["audio_session"]},{"name":"network_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/network_info_plus-4.1.0/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/package_info_plus-3.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/path_provider_foundation-2.3.1/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"permission_handler_apple","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/permission_handler_apple-9.1.4/","native_build":true,"dependencies":[]},{"name":"reactive_ble_mobile","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/reactive_ble_mobile-5.2.0/","native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_foundation-2.3.4/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"sqflite","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/sqflite-2.3.0/","native_build":true,"dependencies":[]},{"name":"url_launcher_ios","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_ios-6.1.5/","native_build":true,"dependencies":[]},{"name":"video_player_avfoundation","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/video_player_avfoundation-2.4.11/","native_build":true,"dependencies":[]},{"name":"webview_flutter_wkwebview","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/webview_flutter_wkwebview-3.9.1/","native_build":true,"dependencies":[]}],"android":[{"name":"aj_captcha_flutter","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/aj_captcha_flutter-0.0.1/","native_build":true,"dependencies":[]},{"name":"aliyun_push","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/aliyun_push-0.1.6/","native_build":true,"dependencies":[]},{"name":"amap_flutter_location","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/amap_flutter_location-3.0.0/","native_build":true,"dependencies":[]},{"name":"amap_flutter_map","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/amap_flutter_map-3.0.0/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"audio_session","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/audio_session-0.1.18/","native_build":true,"dependencies":[]},{"name":"audioplayers_android","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/audioplayers_android-4.0.3/","native_build":true,"dependencies":[]},{"name":"auto_orientation","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/auto_orientation-2.3.1/","native_build":true,"dependencies":[]},{"name":"camera_android","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/camera_android-0.10.8+12/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"device_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/device_info_plus-8.2.2/","native_build":true,"dependencies":[]},{"name":"flutter_ffmpeg","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/flutter_ffmpeg-0.4.2/","native_build":true,"dependencies":[]},{"name":"flutter_native_contact_picker","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/flutter_native_contact_picker-0.0.4/","native_build":true,"dependencies":[]},{"name":"flutter_plugin_android_lifecycle","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/flutter_plugin_android_lifecycle-2.0.16/","native_build":true,"dependencies":[]},{"name":"flutter_sound","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/flutter_sound-9.2.13/","native_build":true,"dependencies":[]},{"name":"fluttertoast","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/fluttertoast-8.2.2/","native_build":true,"dependencies":[]},{"name":"g711_flutter","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/g711_flutter-2.0.0/","native_build":true,"dependencies":[]},{"name":"google_maps_flutter_android","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/google_maps_flutter_android-2.5.1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_gallery_saver","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/image_gallery_saver-2.0.3/","native_build":true,"dependencies":[]},{"name":"image_picker_android","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/image_picker_android-0.8.8+1/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"]},{"name":"just_audio","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/just_audio-0.9.36/","native_build":true,"dependencies":["audio_session"]},{"name":"network_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/network_info_plus-4.1.0/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/package_info_plus-3.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/path_provider_android-2.2.0/","native_build":true,"dependencies":[]},{"name":"permission_handler_android","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/permission_handler_android-10.3.6/","native_build":true,"dependencies":[]},{"name":"reactive_ble_mobile","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/reactive_ble_mobile-5.2.0/","native_build":true,"dependencies":[]},{"name":"shared_preferences_android","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_android-2.2.1/","native_build":true,"dependencies":[]},{"name":"sqflite","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/sqflite-2.3.0/","native_build":true,"dependencies":[]},{"name":"url_launcher_android","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_android-6.1.0/","native_build":true,"dependencies":[]},{"name":"video_player_android","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/video_player_android-2.4.10/","native_build":true,"dependencies":[]},{"name":"webview_flutter_android","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/webview_flutter_android-3.12.0/","native_build":true,"dependencies":[]}],"macos":[{"name":"aj_captcha_flutter","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/aj_captcha_flutter-0.0.1/","native_build":true,"dependencies":[]},{"name":"audio_session","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/audio_session-0.1.18/","native_build":true,"dependencies":[]},{"name":"audioplayers_darwin","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/audioplayers_darwin-5.0.2/","native_build":true,"dependencies":[]},{"name":"device_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/device_info_plus-8.2.2/","native_build":true,"dependencies":[]},{"name":"file_selector_macos","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/file_selector_macos-0.9.3+3/","native_build":true,"dependencies":[]},{"name":"image_picker_macos","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/image_picker_macos-0.2.1+1/","native_build":false,"dependencies":["file_selector_macos"]},{"name":"just_audio","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/just_audio-0.9.36/","native_build":true,"dependencies":["audio_session"]},{"name":"network_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/network_info_plus-4.1.0/","native_build":true,"dependencies":[]},{"name":"package_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/package_info_plus-3.1.2/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/path_provider_foundation-2.3.1/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"shared_preferences_foundation","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_foundation-2.3.4/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"sqflite","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/sqflite-2.3.0/","native_build":true,"dependencies":[]},{"name":"url_launcher_macos","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_macos-3.0.7/","native_build":true,"dependencies":[]}],"linux":[{"name":"aj_captcha_flutter","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/aj_captcha_flutter-0.0.1/","native_build":true,"dependencies":[]},{"name":"audioplayers_linux","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/audioplayers_linux-3.1.0/","native_build":true,"dependencies":[]},{"name":"device_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/device_info_plus-8.2.2/","native_build":false,"dependencies":[]},{"name":"file_selector_linux","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/file_selector_linux-0.9.2+1/","native_build":true,"dependencies":[]},{"name":"image_picker_linux","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/image_picker_linux-0.2.1+1/","native_build":false,"dependencies":["file_selector_linux"]},{"name":"network_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/network_info_plus-4.1.0/","native_build":false,"dependencies":[]},{"name":"package_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/package_info_plus-3.1.2/","native_build":false,"dependencies":[]},{"name":"path_provider_linux","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]},{"name":"shared_preferences_linux","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_linux-2.3.2/","native_build":false,"dependencies":["path_provider_linux"]},{"name":"url_launcher_linux","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_linux-3.0.6/","native_build":true,"dependencies":[]}],"windows":[{"name":"aj_captcha_flutter","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/aj_captcha_flutter-0.0.1/","native_build":true,"dependencies":[]},{"name":"audioplayers_windows","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/audioplayers_windows-3.1.0/","native_build":true,"dependencies":[]},{"name":"device_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/device_info_plus-8.2.2/","native_build":false,"dependencies":[]},{"name":"file_selector_windows","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/file_selector_windows-0.9.3+1/","native_build":true,"dependencies":[]},{"name":"image_picker_windows","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/image_picker_windows-0.2.1+1/","native_build":false,"dependencies":["file_selector_windows"]},{"name":"network_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/network_info_plus-4.1.0/","native_build":false,"dependencies":[]},{"name":"package_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/package_info_plus-3.1.2/","native_build":false,"dependencies":[]},{"name":"path_provider_windows","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/path_provider_windows-2.2.1/","native_build":false,"dependencies":[]},{"name":"permission_handler_windows","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/permission_handler_windows-0.1.3/","native_build":true,"dependencies":[]},{"name":"shared_preferences_windows","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_windows-2.3.2/","native_build":false,"dependencies":["path_provider_windows"]},{"name":"url_launcher_windows","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_windows-3.0.8/","native_build":true,"dependencies":[]}],"web":[{"name":"aj_captcha_flutter","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/aj_captcha_flutter-0.0.1/","dependencies":[]},{"name":"audio_session","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/audio_session-0.1.18/","dependencies":[]},{"name":"audioplayers_web","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/audioplayers_web-4.1.0/","dependencies":[]},{"name":"camera_web","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/camera_web-0.3.2+2/","dependencies":[]},{"name":"device_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/device_info_plus-8.2.2/","dependencies":[]},{"name":"flutter_sound_web","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/flutter_sound_web-9.2.13/","dependencies":[]},{"name":"fluttertoast","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/fluttertoast-8.2.2/","dependencies":[]},{"name":"google_maps_flutter_web","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/google_maps_flutter_web-0.5.4+1/","dependencies":[]},{"name":"image_picker_for_web","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/image_picker_for_web-3.0.1/","dependencies":[]},{"name":"just_audio_web","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/just_audio_web-0.4.9/","dependencies":[]},{"name":"network_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/network_info_plus-4.1.0/","dependencies":[]},{"name":"package_info_plus","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/package_info_plus-3.1.2/","dependencies":[]},{"name":"shared_preferences_web","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/shared_preferences_web-2.2.1/","dependencies":[]},{"name":"url_launcher_web","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/url_launcher_web-2.0.19/","dependencies":[]},{"name":"video_player_web","path":"/Users/sky/.pub-cache/hosted/pub.flutter-io.cn/video_player_web-2.0.17/","dependencies":[]}]},"dependencyGraph":[{"name":"aj_captcha_flutter","dependencies":[]},{"name":"aliyun_push","dependencies":[]},{"name":"amap_flutter_location","dependencies":[]},{"name":"amap_flutter_map","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"audio_session","dependencies":[]},{"name":"audioplayers","dependencies":["audioplayers_android","audioplayers_darwin","audioplayers_linux","audioplayers_web","audioplayers_windows","path_provider"]},{"name":"audioplayers_android","dependencies":[]},{"name":"audioplayers_darwin","dependencies":[]},{"name":"audioplayers_linux","dependencies":[]},{"name":"audioplayers_web","dependencies":[]},{"name":"audioplayers_windows","dependencies":[]},{"name":"auto_orientation","dependencies":[]},{"name":"camera","dependencies":["camera_android","camera_avfoundation","camera_web","flutter_plugin_android_lifecycle"]},{"name":"camera_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"camera_avfoundation","dependencies":[]},{"name":"camera_web","dependencies":[]},{"name":"device_info_plus","dependencies":[]},{"name":"file_selector_linux","dependencies":[]},{"name":"file_selector_macos","dependencies":[]},{"name":"file_selector_windows","dependencies":[]},{"name":"flutter_ffmpeg","dependencies":[]},{"name":"flutter_native_contact_picker","dependencies":[]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"flutter_reactive_ble","dependencies":["reactive_ble_mobile"]},{"name":"flutter_sound","dependencies":["path_provider","flutter_sound_web"]},{"name":"flutter_sound_web","dependencies":[]},{"name":"fluttertoast","dependencies":[]},{"name":"g711_flutter","dependencies":[]},{"name":"google_maps_flutter","dependencies":["google_maps_flutter_android","google_maps_flutter_ios","google_maps_flutter_web"]},{"name":"google_maps_flutter_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"google_maps_flutter_ios","dependencies":[]},{"name":"google_maps_flutter_web","dependencies":[]},{"name":"image_gallery_saver","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios","image_picker_linux","image_picker_macos","image_picker_windows"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"image_picker_linux","dependencies":["file_selector_linux"]},{"name":"image_picker_macos","dependencies":["file_selector_macos"]},{"name":"image_picker_windows","dependencies":["file_selector_windows"]},{"name":"just_audio","dependencies":["just_audio_web","audio_session","path_provider"]},{"name":"just_audio_web","dependencies":[]},{"name":"network_info_plus","dependencies":[]},{"name":"package_info_plus","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":["permission_handler_android","permission_handler_apple","permission_handler_windows"]},{"name":"permission_handler_android","dependencies":[]},{"name":"permission_handler_apple","dependencies":[]},{"name":"permission_handler_windows","dependencies":[]},{"name":"reactive_ble_mobile","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_android","shared_preferences_foundation","shared_preferences_linux","shared_preferences_web","shared_preferences_windows"]},{"name":"shared_preferences_android","dependencies":[]},{"name":"shared_preferences_foundation","dependencies":[]},{"name":"shared_preferences_linux","dependencies":["path_provider_linux"]},{"name":"shared_preferences_web","dependencies":[]},{"name":"shared_preferences_windows","dependencies":["path_provider_windows"]},{"name":"sqflite","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_android","url_launcher_ios","url_launcher_linux","url_launcher_macos","url_launcher_web","url_launcher_windows"]},{"name":"url_launcher_android","dependencies":[]},{"name":"url_launcher_ios","dependencies":[]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_web","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]},{"name":"webview_flutter","dependencies":["webview_flutter_android","webview_flutter_wkwebview"]},{"name":"webview_flutter_android","dependencies":[]},{"name":"webview_flutter_wkwebview","dependencies":[]}],"date_created":"2023-12-22 15:43:01.891206","version":"3.10.6"} \ No newline at end of file diff --git a/star_lock/ios/Podfile.lock b/star_lock/ios/Podfile.lock index b338036f..eb3ce1b3 100644 --- a/star_lock/ios/Podfile.lock +++ b/star_lock/ios/Podfile.lock @@ -47,6 +47,9 @@ PODS: - Flutter - flutter_sound_core (= 9.2.13) - flutter_sound_core (9.2.13) + - flutter_voice_processor (1.1.0): + - Flutter + - ios-voice-processor (~> 1.1.0) - fluttertoast (0.0.2): - Flutter - Toast @@ -58,15 +61,16 @@ PODS: - google_maps_flutter_ios (0.0.1): - Flutter - GoogleMaps (< 9.0) - - GoogleMaps (7.4.0): - - GoogleMaps/Maps (= 7.4.0) - - GoogleMaps/Base (7.4.0) - - GoogleMaps/Maps (7.4.0): + - GoogleMaps (6.2.1): + - GoogleMaps/Maps (= 6.2.1) + - GoogleMaps/Base (6.2.1) + - GoogleMaps/Maps (6.2.1): - GoogleMaps/Base - image_gallery_saver (2.0.2): - Flutter - image_picker_ios (0.0.1): - Flutter + - ios-voice-processor (1.1.0) - just_audio (0.0.1): - Flutter - network_info_plus (0.0.1): @@ -113,6 +117,7 @@ DEPENDENCIES: - flutter_native_contact_picker (from `.symlinks/plugins/flutter_native_contact_picker/ios`) - flutter_pcm_sound (from `.symlinks/plugins/flutter_pcm_sound/ios`) - flutter_sound (from `.symlinks/plugins/flutter_sound/ios`) + - flutter_voice_processor (from `.symlinks/plugins/flutter_voice_processor/ios`) - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`) - g711_flutter (from `.symlinks/plugins/g711_flutter/ios`) - google_maps_flutter_ios (from `.symlinks/plugins/google_maps_flutter_ios/ios`) @@ -145,6 +150,7 @@ SPEC REPOS: - flutter_sound_core - FMDB - GoogleMaps + - ios-voice-processor - Protobuf - SwiftProtobuf - Toast @@ -176,6 +182,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/flutter_pcm_sound/ios" flutter_sound: :path: ".symlinks/plugins/flutter_sound/ios" + flutter_voice_processor: + :path: ".symlinks/plugins/flutter_voice_processor/ios" fluttertoast: :path: ".symlinks/plugins/fluttertoast/ios" g711_flutter: @@ -233,13 +241,15 @@ SPEC CHECKSUMS: flutter_pcm_sound: de0572ca4f99091cc2abfcc31601b8a4ddd33c0e flutter_sound: c60effa2a350fb977885f0db2fbc4c1ad5160900 flutter_sound_core: 26c10e5832e76aaacfae252d8925232281c486ae + flutter_voice_processor: 53afbf59ad3feb82f4a379fea9ed8dc98495210f fluttertoast: 31b00dabfa7fb7bacd9e7dbee580d7a2ff4bf265 FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a g711_flutter: 8f2769052d2cf3549f83d11e1c42d81d94441123 google_maps_flutter_ios: 590249c67f34f422122c232f2a626192adbc78ee - GoogleMaps: 032f676450ba0779bd8ce16840690915f84e57ac + GoogleMaps: 20d7b12be49a14287f797e88e0e31bc4156aaeb4 image_gallery_saver: cb43cc43141711190510e92c460eb1655cd343cb image_picker_ios: 4a8aadfbb6dc30ad5141a2ce3832af9214a705b5 + ios-voice-processor: 8e32d7f980a06d392d128ef1cd19cf6ddcaca3c1 just_audio: baa7252489dbcf47a4c7cc9ca663e9661c99aafa network_info_plus: 6d0c3eb8367b8164fa3fb0c19875e3f59d49697f package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e @@ -255,6 +265,6 @@ SPEC CHECKSUMS: video_player_avfoundation: 81e49bb3d9fb63dccf9fa0f6d877dc3ddbeac126 webview_flutter_wkwebview: 2e2d318f21a5e036e2c3f26171342e95908bd60a -PODFILE CHECKSUM: 85f69c27139c5112fdd69e85b95c1cc6de403d3e +PODFILE CHECKSUM: 42aa7ffc6134b996f93caa6a9b6a2b5b580ff28a COCOAPODS: 1.14.3 diff --git a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_logic.dart b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_logic.dart index 3b45b818..dcbe7fbe 100644 --- a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_logic.dart +++ b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_logic.dart @@ -38,14 +38,80 @@ class LockMonitoringLogic extends BaseGetXController { }); } - /// 收到接听状态 + /// 收到UDP发送的状态 StreamSubscription? _getUDPStatusRefreshUIEvent; void _getUDPStatusRefreshUIAction() { _getUDPStatusRefreshUIEvent = eventBus.on().listen((event) { state.udpStatus.value = event.udpStatus; + if(state.udpStatus.value == 8){ + // 接听成功了,然后刷新界面的时间 60秒以后自动挂断 + state.oneMinuteTimeTimer = Timer.periodic(const Duration(seconds:1), (Timer t) async { + state.oneMinuteTime.value++; + Get.log('state.oneMinuteTime.value:${state.oneMinuteTime.value}'); + if(state.oneMinuteTime.value >= 60){ + // 超过60秒了 + state.oneMinuteTimeTimer.cancel(); + state.oneMinuteTime.value = 0; + // 挂断 + UDPSenderManage.sendMainProtocol( + command: 150, + commandTypeIsCalling: 1, + subCommand: 30, + lockID: UDPManage().lockId, + lockIP: UDPManage().host, + userMobile: await state.userMobile, + userMobileIP: await state.userMobileIP, + endData: []); + + // 关闭当前界面 + Get.back(); + } + }); + } }); } + /// 接听 + udpAnswerAction() async { + UDPSenderManage.sendMainProtocol( + command: 150, + commandTypeIsCalling: 1, + subCommand: 6, + lockID: UDPManage().lockId, + lockIP: UDPManage().host, + userMobile: await state.userMobile, + userMobileIP: await state.userMobileIP, + endData: [] + ); + } + + /// 挂断 + udpHangUpAction() async { + UDPSenderManage.sendMainProtocol( + command: 150, + commandTypeIsCalling: 1, + subCommand: 30, + lockID: UDPManage().lockId, + lockIP: UDPManage().host, + userMobile: await state.userMobile, + userMobileIP: await state.userMobileIP, + endData: []); + } + + /// 开门 + udpOpenDoorAction() async { + UDPSenderManage.sendMainProtocol( + command: 150, + commandTypeIsCalling: 1, + subCommand: 10, + lockID: UDPManage().lockId, + lockIP: UDPManage().host, + userMobile: await state.userMobile, + userMobileIP: await state.userMobileIP, + endData: []); + Get.back(); + } + Future _readG711Data() async { String filePath = 'assets/s10-g711.bin'; List audioData = await G711().readAssetFile(filePath); @@ -83,11 +149,11 @@ class LockMonitoringLogic extends BaseGetXController { Future startProcessing() async { frameListener(List frame) async { - Get.log('Get data.length:${frame.length} Received data:$frame'); + // Get.log('Get data.length:${frame.length} Received data:$frame'); for (int i = 0; i < frame.length; i++) { frame[i] = linearToULaw(frame[i]); } - Get.log('change Get data.length:${frame.length} change Received data:$frame'); + // Get.log('change Get data.length:${frame.length} change Received data:$frame'); await Future.delayed(const Duration(milliseconds: 50)); sendRecordData({ "bytes": frame, @@ -330,7 +396,7 @@ class LockMonitoringLogic extends BaseGetXController { print("锁详情界面销毁了"); _getTVDataRefreshUIEvent!.cancel(); _getUDPStatusRefreshUIEvent!.cancel(); - + state.oneMinuteTimeTimer.cancel(); stopProcessing(); } } diff --git a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart index 78d24564..1bfca06f 100644 --- a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart +++ b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_page.dart @@ -41,25 +41,34 @@ class _LockMonitoringPageState extends State { )), Positioned( top: ScreenUtil().statusBarHeight + 30.h, - child: Row(children: [ - SizedBox(width: 30.w), - GestureDetector( - onTap: () { - Get.back(); - }, - child: Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(25.h)), - padding: EdgeInsets.all(10.w), - child: Image( - width: 40.w, - height: 40.w, - image: const AssetImage("images/icon_left_black.png"), - ), - ), - ), - ]), + width: 1.sw, + child: Obx(() { + var sec = (state.oneMinuteTime.value % 60).toString().padLeft(2,'0'); + var min = (state.oneMinuteTime.value ~/ 60).toString().padLeft(2,'0'); + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text("$min:$sec", style: TextStyle(fontSize: 26.sp, color: Colors.white)), + // SizedBox(width: 30.w), + // GestureDetector( + // onTap: () { + // Get.back(); + // }, + // child: Container( + // decoration: BoxDecoration( + // color: Colors.white, + // borderRadius: BorderRadius.circular(25.h)), + // padding: EdgeInsets.all(10.w), + // child: Image( + // width: 40.w, + // height: 40.w, + // image: const AssetImage("images/icon_left_black.png"), + // ), + // ), + // ), + ] + ); + }), ), Positioned( bottom: 10.w, @@ -156,16 +165,7 @@ class _LockMonitoringPageState extends State { // state.isSenderAudioData.value = false; print("发送接听了"); // 刚进来是接听状态,然后改为长按对讲 - UDPSenderManage.sendMainProtocol( - command: 150, - commandTypeIsCalling: 1, - subCommand: 6, - lockID: UDPManage().lockId, - lockIP: UDPManage().host, - userMobile: await state.userMobile, - userMobileIP: await state.userMobileIP, - endData: [] - ); + logic.udpAnswerAction(); }); }, longPress: (){ @@ -191,15 +191,7 @@ class _LockMonitoringPageState extends State { logic.stopProcessing(); // 挂断 - UDPSenderManage.sendMainProtocol( - command: 150, - commandTypeIsCalling: 1, - subCommand: 30, - lockID: UDPManage().lockId, - lockIP: UDPManage().host, - userMobile: await state.userMobile, - userMobileIP: await state.userMobileIP, - endData: []); + logic.udpHangUpAction(); }), bottomBtnItemWidget("images/main/icon_lockDetail_monitoringUnlock.png", "开锁", AppColors.mainColor, () { showDeletPasswordAlertDialog(context); @@ -280,16 +272,7 @@ class _LockMonitoringPageState extends State { } // 开锁 - UDPSenderManage.sendMainProtocol( - command: 150, - commandTypeIsCalling: 1, - subCommand: 10, - lockID: UDPManage().lockId, - lockIP: UDPManage().host, - userMobile: await state.userMobile, - userMobileIP: await state.userMobileIP, - endData: []); - Get.back(); + logic.udpOpenDoorAction(); }, cancelClick: () { Get.back(); diff --git a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_state.dart b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_state.dart index fe3391cf..1e3bec11 100644 --- a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_state.dart +++ b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_state.dart @@ -24,8 +24,10 @@ class LockMonitoringState { late final VoiceProcessor? voiceProcessor; - // 定时器超过60秒关闭当前界面 - late Timer oneMinuteTimeTimer; + + late Timer oneMinuteTimeTimer;// 定时器超过60秒关闭当前界面 + var oneMinuteTime = 0.obs;// 定时器秒数 + // 定时器如果发送了接听的命令 而没收到回复就每秒重复发送10次 late Timer answerTimer; late Timer hangUpTimer; diff --git a/star_lock/lib/talk/udp/udp_reciverData.dart b/star_lock/lib/talk/udp/udp_reciverData.dart index 52c1e380..aafcc339 100644 --- a/star_lock/lib/talk/udp/udp_reciverData.dart +++ b/star_lock/lib/talk/udp/udp_reciverData.dart @@ -10,6 +10,8 @@ import '../call/callTalk.dart'; import 'udp_talkClass.dart'; class CommandUDPReciverManager { + + static void appDataReceive(List data) async { ///解析数据 if (data.isEmpty) { From 2723c0b058a03479efd958fb4a4b2e93cda6af15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AD=8F=E5=B0=91=E9=98=B3?= <786612630@qq.com> Date: Fri, 29 Dec 2023 18:40:02 +0800 Subject: [PATCH 32/33] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=AF=B9=E8=AE=B2?= =?UTF-8?q?=E6=8E=A5=E6=94=B6=E9=9F=B3=E9=A2=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../monitoring/lockMonitoring_logic.dart | 2 +- star_lock/lib/talk/call/callTalk.dart | 35 +++++++++++++++++-- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_logic.dart b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_logic.dart index dcbe7fbe..09c52a9f 100644 --- a/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_logic.dart +++ b/star_lock/lib/main/lockDetail/monitoring/monitoring/lockMonitoring_logic.dart @@ -47,7 +47,7 @@ class LockMonitoringLogic extends BaseGetXController { // 接听成功了,然后刷新界面的时间 60秒以后自动挂断 state.oneMinuteTimeTimer = Timer.periodic(const Duration(seconds:1), (Timer t) async { state.oneMinuteTime.value++; - Get.log('state.oneMinuteTime.value:${state.oneMinuteTime.value}'); + // Get.log('state.oneMinuteTime.value:${state.oneMinuteTime.value}'); if(state.oneMinuteTime.value >= 60){ // 超过60秒了 state.oneMinuteTimeTimer.cancel(); diff --git a/star_lock/lib/talk/call/callTalk.dart b/star_lock/lib/talk/call/callTalk.dart index cd6ae460..33b12d26 100644 --- a/star_lock/lib/talk/call/callTalk.dart +++ b/star_lock/lib/talk/call/callTalk.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'dart:typed_data'; import 'package:flutter/foundation.dart'; +import 'package:get/get.dart'; import 'package:star_lock/talk/call/g711.dart'; import 'package:star_lock/talk/call/iFrameInfo.dart'; import '../../tools/eventBusEventManage.dart'; @@ -22,6 +23,7 @@ class CallTalk { IframeInfo? iframe; // 假设有这个成员变量 var growableList; bool getFirstFrame = false; //是否得到了第一帧 + List allDataBytes = []; //音频数据 CallTalk._init() { iframe = IframeInfo(); @@ -47,6 +49,14 @@ class CallTalk { try { // 将 ALaw 转为 Linear pcmBytes = G711().convertList(g711Data); + allDataBytes.addAll(pcmBytes); + + // String filePath = 'assets/s10-g711.bin'; + // + // List audioData = await G711().readAssetFile(filePath); + // pcmBytes = G711().convertList(audioData); + // allDataBytes = pcmBytes.sublist(0, 640); + _initializeAudioPlayer(pcmBytes); } catch (e) { print('Error decoding G.711 to PCM: $e'); @@ -118,9 +128,28 @@ class CallTalk { //音频相关处理 Future _initializeAudioPlayer(List audioData) async { - PcmArrayInt16 fromList = PcmArrayInt16.fromList(audioData); - await FlutterPcmSound.feed(fromList); + Get.log('_initializeAudioPlayer audioData:$audioData'); + PcmArrayInt16 fromList = PcmArrayInt16.fromList(audioData); + // FlutterPcmSound.setFeedCallback(onFeed); + await FlutterPcmSound.feed(fromList); FlutterPcmSound.play(); } -} + + void onFeed(int remainingFrames) async { + int framesToFeed = 320; + + if (allDataBytes.length >= framesToFeed) { + List frames = allDataBytes.sublist(0, framesToFeed); + allDataBytes.removeRange(0, framesToFeed); + + // 将数据传递给 FlutterPcmSound + PcmArrayInt16 fromList = PcmArrayInt16.fromList(frames); + await FlutterPcmSound.feed(fromList); + FlutterPcmSound.play(); + } else { + // 处理长度不足的情况,可以等待更多数据或者采取其他措施 + print("Not enough data in allPcmData."); + } + } + } From 4297e25b22aa6d293f8c1449d90688a2c646850d Mon Sep 17 00:00:00 2001 From: Daisy <> Date: Tue, 2 Jan 2024 15:32:56 +0800 Subject: [PATCH 33/33] =?UTF-8?q?1=EF=BC=8C=E4=BF=AE=E5=A4=8DBug-1000665?= =?UTF-8?q?=20=E5=BC=80=E9=94=81=E9=A1=B5-=E5=AF=86=E7=A0=81-=E5=8D=95?= =?UTF-8?q?=E6=AC=A1=20=E5=8D=95=E6=AC=A1=E5=AF=86=E7=A0=81=E4=B8=8D?= =?UTF-8?q?=E8=83=BD=E6=94=B9=EF=BC=8C=E6=98=9F=E9=94=81=E7=82=B9=E5=87=BB?= =?UTF-8?q?=E6=9C=89=E5=BC=B9=E5=87=BA=E4=BF=AE=E6=94=B9=E5=AF=86=E7=A0=81?= =?UTF-8?q?=202=EF=BC=8C=E4=BF=AE=E5=A4=8DBug-1000660=20=E5=BC=80=E9=94=81?= =?UTF-8?q?=E9=A1=B5-=E5=AF=86=E7=A0=81-=E9=99=90=E6=97=B6=20=E9=80=89?= =?UTF-8?q?=E6=8B=A9=E7=9A=84=E5=BC=80=E5=A7=8B=E6=97=B6=E9=97=B4=E6=98=AF?= =?UTF-8?q?=E6=95=B4=E7=82=B9=EF=BC=8C=E6=98=BE=E7=A4=BA=E5=8D=B4=E6=9C=89?= =?UTF-8?q?=E5=88=86=E9=92=9F=E6=95=B0=203=EF=BC=8C=E4=BF=AE=E5=A4=8DBug-?= =?UTF-8?q?=201000658=20=E5=BC=80=E9=94=81=E9=A1=B5-=E5=AF=86=E7=A0=81-?= =?UTF-8?q?=E6=B8=85=E7=A9=BA=E7=A0=81=20=E4=B8=8D=E5=8F=AF=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=EF=BC=8C=E6=98=9F=E9=94=81=E7=82=B9=E5=87=BB=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E6=A1=86=E5=BC=B9=E5=87=BA=204=EF=BC=8C=E4=BF=AE?= =?UTF-8?q?=E5=A4=8DBug-=201000649=20=E5=BC=80=E9=94=81=E9=A1=B5-=E5=AF=86?= =?UTF-8?q?=E7=A0=81-=E5=8D=95=E6=AC=A1-=E5=AF=86=E7=A0=81=E8=AF=A6?= =?UTF-8?q?=E6=83=85=E6=98=BE=E7=A4=BA=E6=97=B6=E9=97=B4=E9=94=99=E8=AF=AF?= =?UTF-8?q?=205=EF=BC=8C=E4=BF=AE=E5=A4=8DBug-=201000648=20=E5=BC=80?= =?UTF-8?q?=E9=94=81=E9=A1=B5-=E5=AF=86=E7=A0=81-=E6=B8=85=E7=A9=BA?= =?UTF-8?q?=E5=AF=86=E7=A0=81-=E5=AF=86=E7=A0=81=E8=AF=A6=E6=83=85?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E6=97=B6=E9=97=B4=E9=94=99=E8=AF=AF=206?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=E6=94=B9=E6=97=A5=E6=9C=9F=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E9=87=8D=E6=9E=84=E5=8F=8A=E5=8F=82=E6=95=B0=E6=A3=80=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../checkingInAddStaff_logic.dart | 47 +++++--- .../electronicKeyDetailChangeDate_logic.dart | 48 ++++++++ .../electronicKeyDetailChangeDate_page.dart | 112 ++++-------------- .../electronicKeyDetailChangeDate_state.dart | 43 +++++++ .../passwordKeyDetail_logic.dart | 17 +-- .../passwordKeyDetail_page.dart | 13 +- .../passwordKeyDetail_state.dart | 7 ++ .../passwordKeyList_logic.dart | 10 +- .../passwordKey_perpetual_logic.dart | 24 ++-- star_lock/lib/network/api_provider.dart | 31 +++-- star_lock/lib/network/api_repository.dart | 78 ++++++------ 11 files changed, 246 insertions(+), 184 deletions(-) create mode 100644 star_lock/lib/main/lockDetail/electronicKey/electronicKeyDetail/electronicKeyDetailChangeDate/electronicKeyDetailChangeDate_logic.dart create mode 100644 star_lock/lib/main/lockDetail/electronicKey/electronicKeyDetail/electronicKeyDetailChangeDate/electronicKeyDetailChangeDate_state.dart diff --git a/star_lock/lib/main/lockDetail/checkingIn/checkingInStaff/checkingInSetAddStaff/checkingInAddStaff_logic.dart b/star_lock/lib/main/lockDetail/checkingIn/checkingInStaff/checkingInSetAddStaff/checkingInAddStaff_logic.dart index f1432dcf..a3eb457f 100644 --- a/star_lock/lib/main/lockDetail/checkingIn/checkingInStaff/checkingInSetAddStaff/checkingInAddStaff_logic.dart +++ b/star_lock/lib/main/lockDetail/checkingIn/checkingInStaff/checkingInSetAddStaff/checkingInAddStaff_logic.dart @@ -1,4 +1,3 @@ - import 'dart:async'; import 'package:get/get.dart'; @@ -138,35 +137,49 @@ class CheckingInAddStaffLogic extends BaseGetXController{ have: state.appUnHaveAccount.value ? "2" : "1", staffName: state.staffNameController.text, countryCode: state.countryCode.value, - usernameType:usernameType, + usernameType: usernameType, ); - if(entity.errorCode!.codeIsSuccessful){ + if (entity.errorCode!.codeIsSuccessful) { eventBus.fire(RefreshCheckInStaffListDataEvent()); Get.close(2); - }else if(entity.errorCode! == 425){ + } else if (entity.errorCode! == 425) { Toast.show(msg: entity.errorMsg!); } } //获取密码请求 void getKeyboardPwdRequest() async { - if(state.staffNameController.text.isEmpty){ + if (state.staffNameController.text.isEmpty) { Toast.show(msg: "请输入姓名"); return; } + // var entity = await ApiRepository.to.getPasswordKey( + // "0", + // '0', + // state.staffNameController.text, + // 2.toString(), + // '0', + // state.getKeyInfosData.value.lockId.toString(), + // '0', + // "0", + // '0', + // 0, + // 0, + // 1); var entity = await ApiRepository.to.getPasswordKey( - "0", - '0', - state.staffNameController.text, - 2.toString(), - '0', - state.getKeyInfosData.value.lockId.toString(), - '0', - "0", - '0', - 0, - 0, - 1); + endDate: "0", + isExclusive: '0', + keyboardPwdName: state.staffNameController.text, + keyboardPwdType: 2.toString(), + keyboardPwdVersion: '0', + lockId: state.getKeyInfosData.value.lockId.toString(), + operatorUid: '0', + startDate: '0', + timezoneRawOffSet: '0', + startHours: 0, + endHours: 0, + isCoerced: 1); + if (entity.errorCode!.codeIsSuccessful) { print('获取密码成功'); if (entity.data != null) { diff --git a/star_lock/lib/main/lockDetail/electronicKey/electronicKeyDetail/electronicKeyDetailChangeDate/electronicKeyDetailChangeDate_logic.dart b/star_lock/lib/main/lockDetail/electronicKey/electronicKeyDetail/electronicKeyDetailChangeDate/electronicKeyDetailChangeDate_logic.dart new file mode 100644 index 00000000..0ef8c6dc --- /dev/null +++ b/star_lock/lib/main/lockDetail/electronicKey/electronicKeyDetail/electronicKeyDetailChangeDate/electronicKeyDetailChangeDate_logic.dart @@ -0,0 +1,48 @@ +import 'package:get/get.dart'; +import 'package:star_lock/main/lockDetail/electronicKey/electronicKeyDetail/electronicKeyDetailChangeDate/electronicKeyDetailChangeDate_state.dart'; +import 'package:star_lock/main/lockDetail/electronicKey/electronicKeyDetail/keyOperationRecordEntity.dart'; +import 'package:star_lock/main/lockDetail/passwordKey/passwordKey_perpetual/passwordKeyEntity.dart'; +import 'package:star_lock/network/api_repository.dart'; +import 'package:star_lock/tools/baseGetXController.dart'; +import 'package:star_lock/tools/toast.dart'; + +class ElectronicKeyDetailChangeDateLogic extends BaseGetXController { + final ElectronicKeyDetailChangeDateState state = + ElectronicKeyDetailChangeDateState(); + + //更新密码请求 + Future updatePwdRequest() async { + PasswordKeyEntity entity = await ApiRepository.to.updatePasswordKey( + lockId: state.itemData.value.lockId!, + keyboardPwdId: state.pwdId.value.toString(), + keyboardPwdName: state.inputNameController.text, + newKeyboardPwd: state.inputPwdController.text, + startDate: state.startDate.value, + endDate: state.endDate.value, + changeType: state.changeType.value, + hoursStart: state.hoursStart.value, + hoursEnd: state.hoursEnd.value, + isCoerced: state.isCoerced.value); + if (entity.errorCode!.codeIsSuccessful) { + Toast.show(msg: "修改成功"); + Get.back(); + } + } + + //修改钥匙名称请求 + Future updateKeyDateRequest() async { + KeyOperationRecordEntity entity = await ApiRepository.to.updateKeyDate( + state.itemData.value.keyId.toString(), + state.itemData.value.lockId.toString(), + state.failureDateTime.millisecondsSinceEpoch.toString(), + state.endDay.value, + '', + state.effectiveDateTime.millisecondsSinceEpoch.toString(), + state.startDay.value, + state.weekDays.value); + if (entity.errorCode!.codeIsSuccessful) { + Toast.show(msg: "修改成功"); + Get.back(); + } + } +} diff --git a/star_lock/lib/main/lockDetail/electronicKey/electronicKeyDetail/electronicKeyDetailChangeDate/electronicKeyDetailChangeDate_page.dart b/star_lock/lib/main/lockDetail/electronicKey/electronicKeyDetail/electronicKeyDetailChangeDate/electronicKeyDetailChangeDate_page.dart index 125126cf..52239b04 100644 --- a/star_lock/lib/main/lockDetail/electronicKey/electronicKeyDetail/electronicKeyDetailChangeDate/electronicKeyDetailChangeDate_page.dart +++ b/star_lock/lib/main/lockDetail/electronicKey/electronicKeyDetail/electronicKeyDetailChangeDate/electronicKeyDetailChangeDate_page.dart @@ -1,16 +1,9 @@ import 'package:flutter/material.dart'; -// import 'package:flutter_pickers/pickers.dart'; -// import 'package:flutter_pickers/time_picker/model/date_mode.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; -import 'package:star_lock/main/lockDetail/electronicKey/electronicKeyDetail/keyOperationRecordEntity.dart'; -import 'package:star_lock/main/lockDetail/electronicKey/electronicKeyList/entity/ElectronicKeyListEntity.dart'; -import 'package:star_lock/main/lockDetail/passwordKey/passwordKey_perpetual/passwordKeyEntity.dart'; -import 'package:star_lock/network/api_repository.dart'; -import 'package:star_lock/tools/baseGetXController.dart'; +import 'package:star_lock/main/lockDetail/electronicKey/electronicKeyDetail/electronicKeyDetailChangeDate/electronicKeyDetailChangeDate_logic.dart'; import 'package:star_lock/tools/pickers/pickers.dart'; import 'package:star_lock/tools/pickers/time_picker/model/date_mode.dart'; -import 'package:star_lock/tools/toast.dart'; import '../../../../../app_settings/app_colors.dart'; import '../../../../../tools/commonItem.dart'; @@ -27,34 +20,11 @@ class ElectronicKeyDetailChangeDate extends StatefulWidget { class _ElectronicKeyDetailChangeDateState extends State { - ElectronicKeyListItem itemData = ElectronicKeyListItem(); - - String _selectEffectiveDate = ''; //生效时间 - String _selectFailureDate = ''; //失效时间 - late DateTime _effectiveDateTime; - late DateTime _failureDateTime; - late String endDay = ''; - late String startDay = ''; - late List weekDays = []; - late String pwdId = ''; - late String lockId = ''; - late String fromType = ''; // 1 从指纹详情进入 + final logic = Get.put(ElectronicKeyDetailChangeDateLogic()); + final state = Get.find().state; @override Widget build(BuildContext context) { - dynamic obj = ModalRoute.of(context)?.settings.arguments; - if (obj != null && (obj["itemData"] != null)) { - itemData = obj["itemData"]; - } - if (obj != null && (obj["pwdId"] != null)) { - pwdId = obj["pwdId"]; - } - if (obj != null && (obj["lockId"] != null)) { - lockId = obj["lockId"]; - } - if (obj != null && (obj["fromType"] != null)) { - fromType = obj["fromType"]; - } return Scaffold( backgroundColor: AppColors.mainBackgroundColor, appBar: TitleAppBar( @@ -69,12 +39,12 @@ class _ElectronicKeyDetailChangeDateState style: TextStyle(color: Colors.white, fontSize: 24.sp), ), onPressed: () { - if (fromType == "1") { + if (state.fromType.value == "1") { } else { - if (lockId.isNotEmpty && pwdId.isNotEmpty) { - updatePwdRequest(); + if (state.lockId.value != 0 && state.pwdId.value.isNotEmpty) { + logic.updatePwdRequest(); } else { - updateKeyDateRequest(); + logic.updateKeyDateRequest(); } } }, @@ -88,77 +58,37 @@ class _ElectronicKeyDetailChangeDateState Widget buildMainUI() { return Column( children: [ - CommonItem( + Obx(() => CommonItem( leftTitel: TranslationLoader.lanKeys!.effectiveTime!.tr, - rightTitle: _selectEffectiveDate, + rightTitle: state.selectEffectiveDate.value, isHaveLine: true, isHaveDirection: true, action: () { Pickers.showDatePicker(context, mode: DateMode.YMDHM, onConfirm: (p) { - setState(() { - _selectEffectiveDate = - '${p.year}-${intToStr(p.month!)}-${intToStr(p.day!)} ${intToStr(p.hour!)}:${intToStr(p.minute!)}'; - _effectiveDateTime = DateTime.parse(_selectEffectiveDate); - }); + state.selectEffectiveDate.value = + '${p.year}-${intToStr(p.month!)}-${intToStr(p.day!)} ${intToStr(p.hour!)}:${intToStr(p.minute!)}'; + state.effectiveDateTime = + DateTime.parse(state.selectEffectiveDate.value); }); - }), - CommonItem( + })), + Obx(() => CommonItem( leftTitel: TranslationLoader.lanKeys!.failureTime!.tr, - rightTitle: _selectFailureDate, + rightTitle: state.selectFailureDate.value, isHaveDirection: true, action: () { Pickers.showDatePicker(context, mode: DateMode.YMDHM, onConfirm: (p) { - setState(() { - _selectFailureDate = - '${p.year}-${intToStr(p.month!)}-${intToStr(p.day!)} ${intToStr(p.hour!)}:${intToStr(p.minute!)}'; - _failureDateTime = DateTime.parse(_selectFailureDate); - }); + state.selectFailureDate.value = + '${p.year}-${intToStr(p.month!)}-${intToStr(p.day!)} ${intToStr(p.hour!)}:${intToStr(p.minute!)}'; + state.failureDateTime = + DateTime.parse(state.selectFailureDate.value); }); - }), + })), ], ); } - //修改钥匙名称请求 - Future updateKeyDateRequest() async { - KeyOperationRecordEntity entity = await ApiRepository.to.updateKeyDate( - itemData.keyId.toString(), - itemData.lockId.toString(), - _failureDateTime.millisecondsSinceEpoch.toString(), - endDay, - '', - _effectiveDateTime.millisecondsSinceEpoch.toString(), - startDay, - weekDays); - if (entity.errorCode!.codeIsSuccessful) { - print("修改要是名称成功啦啦啦啦啦"); - Toast.show(msg: "修改成功"); - setState(() { - Navigator.pop(context); - }); - } - } - - //更新密码请求 - Future updatePwdRequest() async { - PasswordKeyEntity entity = await ApiRepository.to.updatePasswordKey( - lockId, - pwdId, - '', - '', - _effectiveDateTime.millisecondsSinceEpoch.toString(), - _failureDateTime.millisecondsSinceEpoch.toString(), - ''); - if (entity.errorCode!.codeIsSuccessful) { - Toast.show(msg: "修改成功"); - setState(() { - Navigator.pop(context); - }); - } - } - String intToStr(int v) { return (v < 10) ? "0$v" : "$v"; } diff --git a/star_lock/lib/main/lockDetail/electronicKey/electronicKeyDetail/electronicKeyDetailChangeDate/electronicKeyDetailChangeDate_state.dart b/star_lock/lib/main/lockDetail/electronicKey/electronicKeyDetail/electronicKeyDetailChangeDate/electronicKeyDetailChangeDate_state.dart new file mode 100644 index 00000000..cac37195 --- /dev/null +++ b/star_lock/lib/main/lockDetail/electronicKey/electronicKeyDetail/electronicKeyDetailChangeDate/electronicKeyDetailChangeDate_state.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:star_lock/main/lockDetail/electronicKey/electronicKeyList/entity/ElectronicKeyListEntity.dart'; + +class ElectronicKeyDetailChangeDateState { + final itemData = ElectronicKeyListItem().obs; + final TextEditingController inputPwdController = TextEditingController(); + final TextEditingController inputNameController = TextEditingController(); + final changeType = '1' + .obs; //1-通过APP走蓝牙修改,不传默认1,必需先通过APP SDK蓝牙修改后调用该接口 2-通过网关或WiFi锁修改,如果是WiFi锁或有连接网关,则可以传2,直接调用该接口修改生效 + final isCoerced = '1'.obs; //胁迫指纹:1;非胁迫指纹:2(胁迫指纹开锁触发报警) + final hoursStart = 0.obs; + final hoursEnd = 0.obs; + final startDate = 0.obs; + final endDate = 0.obs; + final pwdId = ''.obs; + final lockId = 0.obs; + final fromType = ''.obs; + final selectEffectiveDate = ''.obs; //生效时间 + final selectFailureDate = ''.obs; //失效时间 + DateTime effectiveDateTime = DateTime.now(); + DateTime failureDateTime = DateTime.now(); + final endDay = ''.obs; + final startDay = ''.obs; + final weekDays = [].obs; + + ElectronicKeyDetailChangeDateState() { + Map map = Get.arguments; + // itemData.value = map["itemData"]; + if ((map["itemData"] != null)) { + itemData.value = map["itemData"]; + } + if ((map["pwdId"] != null)) { + pwdId.value = map["pwdId"]; + } + if ((map["lockId"] != null)) { + lockId.value = map["lockId"]; + } + if ((map["fromType"] != null)) { + fromType.value = map["fromType"]; + } + } +} diff --git a/star_lock/lib/main/lockDetail/passwordKey/passwordKeyDetail/passwordKeyDetail_logic.dart b/star_lock/lib/main/lockDetail/passwordKey/passwordKeyDetail/passwordKeyDetail_logic.dart index 04a6c0d3..9bb42161 100644 --- a/star_lock/lib/main/lockDetail/passwordKey/passwordKeyDetail/passwordKeyDetail_logic.dart +++ b/star_lock/lib/main/lockDetail/passwordKey/passwordKeyDetail/passwordKeyDetail_logic.dart @@ -23,13 +23,16 @@ class PasswordKeyDetailLogic extends BaseGetXController { //更新密码请求 Future updatePwdRequest() async { PasswordKeyEntity entity = await ApiRepository.to.updatePasswordKey( - state.itemData.value.lockId.toString(), - state.itemData.value.keyboardPwdId.toString(), - state.inputNameController.text, - state.inputPwdController.text, - '', - '', - ''); + lockId: state.itemData.value.lockId!, + keyboardPwdId: state.itemData.value.keyboardPwdId.toString(), + keyboardPwdName: state.inputNameController.text, + newKeyboardPwd: state.inputPwdController.text, + startDate: state.startDate.value, + endDate: state.endDate.value, + changeType: state.changeType.value, + hoursStart: state.hoursStart.value, + hoursEnd: state.hoursEnd.value, + isCoerced: state.isCoerced.value); if (entity.errorCode!.codeIsSuccessful) { Toast.show(msg: "修改成功"); Get.back(); diff --git a/star_lock/lib/main/lockDetail/passwordKey/passwordKeyDetail/passwordKeyDetail_page.dart b/star_lock/lib/main/lockDetail/passwordKey/passwordKeyDetail/passwordKeyDetail_page.dart index a175268a..1b89d35d 100644 --- a/star_lock/lib/main/lockDetail/passwordKey/passwordKeyDetail/passwordKeyDetail_page.dart +++ b/star_lock/lib/main/lockDetail/passwordKey/passwordKeyDetail/passwordKeyDetail_page.dart @@ -55,10 +55,19 @@ class _PasswordKeyDetailPageState extends State { rightTitle: state.inputPwdController.text.isNotEmpty ? state.inputPwdController.text : state.itemData.value.keyboardPwd, - isHaveDirection: true, + isHaveDirection: (state.itemData.value.keyboardPwdType == 1 || + state.itemData.value.keyboardPwdType == 4) + ? false + : true, isHaveLine: true, action: () { - showCupertinoAlertDialog(context, state.inputPwdController); + if (state.itemData.value.keyboardPwdType == 1 || + state.itemData.value.keyboardPwdType == 4) { + return; + } else { + showCupertinoAlertDialog( + context, state.inputPwdController); + } }), CommonItem( leftTitel: TranslationLoader.lanKeys!.name!.tr, diff --git a/star_lock/lib/main/lockDetail/passwordKey/passwordKeyDetail/passwordKeyDetail_state.dart b/star_lock/lib/main/lockDetail/passwordKey/passwordKeyDetail/passwordKeyDetail_state.dart index b838e3c0..5745bef6 100644 --- a/star_lock/lib/main/lockDetail/passwordKey/passwordKeyDetail/passwordKeyDetail_state.dart +++ b/star_lock/lib/main/lockDetail/passwordKey/passwordKeyDetail/passwordKeyDetail_state.dart @@ -6,6 +6,13 @@ class PasswordKeyDetailState { final itemData = PasswordKeyListItem().obs; final TextEditingController inputPwdController = TextEditingController(); final TextEditingController inputNameController = TextEditingController(); + final changeType = '1' + .obs; //1-通过APP走蓝牙修改,不传默认1,必需先通过APP SDK蓝牙修改后调用该接口 2-通过网关或WiFi锁修改,如果是WiFi锁或有连接网关,则可以传2,直接调用该接口修改生效 + final isCoerced = '1'.obs; //胁迫指纹:1;非胁迫指纹:2(胁迫指纹开锁触发报警) + final hoursStart = 0.obs; + final hoursEnd = 0.obs; + final startDate = 0.obs; + final endDate = 0.obs; PasswordKeyDetailState() { Map map = Get.arguments; diff --git a/star_lock/lib/main/lockDetail/passwordKey/passwordKeyList/passwordKeyList_logic.dart b/star_lock/lib/main/lockDetail/passwordKey/passwordKeyList/passwordKeyList_logic.dart index 4b920eb8..82b30cde 100644 --- a/star_lock/lib/main/lockDetail/passwordKey/passwordKeyList/passwordKeyList_logic.dart +++ b/star_lock/lib/main/lockDetail/passwordKey/passwordKeyList/passwordKeyList_logic.dart @@ -12,9 +12,8 @@ class PasswordKeyListLogic extends BaseGetXController { //请求密码钥匙列表 void mockNetworkDataRequest() async { PasswordKeyListEntity entity = await ApiRepository.to.passwordKeyList( - '0', + state.keyInfo.value.keyStatus.toString(), state.keyInfo.value.lockId.toString(), - '0', state.pageNum.toString(), state.pageSize.toString(), state.searchController.text); @@ -35,9 +34,10 @@ class PasswordKeyListLogic extends BaseGetXController { } //删除密码请求 deleteType:1-蓝牙 2-网关 - Future deletePwdRequest(String lockId, String keyboardPwdId, int deleteType) async { - PasswordKeyEntity entity = await ApiRepository.to.deleteKeyboardPwd( - lockId, keyboardPwdId, deleteType); + Future deletePwdRequest( + String lockId, String keyboardPwdId, int deleteType) async { + PasswordKeyEntity entity = await ApiRepository.to + .deleteKeyboardPwd(lockId, keyboardPwdId, deleteType); if (entity.errorCode!.codeIsSuccessful) { Toast.show(msg: "删除成功"); mockNetworkDataRequest(); diff --git a/star_lock/lib/main/lockDetail/passwordKey/passwordKey_perpetual/passwordKey_perpetual_logic.dart b/star_lock/lib/main/lockDetail/passwordKey/passwordKey_perpetual/passwordKey_perpetual_logic.dart index 9ae822f0..dcdfca78 100644 --- a/star_lock/lib/main/lockDetail/passwordKey/passwordKey_perpetual/passwordKey_perpetual_logic.dart +++ b/star_lock/lib/main/lockDetail/passwordKey/passwordKey_perpetual/passwordKey_perpetual_logic.dart @@ -90,18 +90,18 @@ class PasswordKeyPerpetualLogic extends BaseGetXController { state.effectiveDateTime.value.millisecondsSinceEpoch.toString(); } var entity = await ApiRepository.to.getPasswordKey( - getFailureDateTime, - '0', - state.nameController.text, - getKeyType, - '0', - lockId, - '0', - getEffectiveDateTime, - '0', - state.loopStartHours.value, - state.loopEndHours.value, - 1); + endDate: getFailureDateTime, + isExclusive: '0', + keyboardPwdName: state.nameController.text, + keyboardPwdType: getKeyType, + keyboardPwdVersion: '0', + lockId: lockId, + operatorUid: '0', + startDate: getEffectiveDateTime, + timezoneRawOffSet: '0', + startHours: state.loopStartHours.value, + endHours: state.loopEndHours.value, + isCoerced: 1); if (entity.errorCode!.codeIsSuccessful) { print('获取密码成功'); state.isSendSuccess.value = true; diff --git a/star_lock/lib/network/api_provider.dart b/star_lock/lib/network/api_provider.dart index af5e9971..8985e9ee 100644 --- a/star_lock/lib/network/api_provider.dart +++ b/star_lock/lib/network/api_provider.dart @@ -362,19 +362,13 @@ class ApiProvider extends BaseProvider { Future getWifiLockServiceIpAndPort() => post(getWifiServiceIpURL.toUrl, jsonEncode({})); - Future passwordKeyList( - String keyStatus, - String lockId, - String operatorUid, - String pageNo, - String pageSize, - String searchStr) => + Future passwordKeyList(String keyStatus, String lockId, + String pageNo, String pageSize, String searchStr) => post( passwordKeyListURL.toUrl, jsonEncode({ 'keyStatus': keyStatus, 'lockId': lockId, - 'operatorUid': operatorUid, 'pageNo': pageNo, 'pageSize': pageSize, 'searchStr': searchStr @@ -436,14 +430,16 @@ class ApiProvider extends BaseProvider { })); Future updateKeyboardPwd( - String lockId, - String keyboardPwdId, - String keyboardPwdName, - String newKeyboardPwd, - String startDate, - String endDate, - String changeType, - ) => + int lockId, + String keyboardPwdId, + String keyboardPwdName, + String newKeyboardPwd, + int startDate, + int endDate, + String changeType, + String isCoerced, + int hoursStart, + int hoursEnd) => post( updatePasswordKeyURL.toUrl, jsonEncode({ @@ -454,6 +450,9 @@ class ApiProvider extends BaseProvider { 'startDate': startDate, 'endDate': endDate, 'changeType': changeType, + 'isCoerced': isCoerced, + 'hoursStart': hoursStart, + 'hoursEnd': hoursEnd })); Future clearOperationRecord(String lockId) => diff --git a/star_lock/lib/network/api_repository.dart b/star_lock/lib/network/api_repository.dart index ee55448d..6276ef48 100644 --- a/star_lock/lib/network/api_repository.dart +++ b/star_lock/lib/network/api_repository.dart @@ -323,15 +323,10 @@ class ApiRepository { } //密码列表 - Future passwordKeyList( - String keyStatus, - String lockId, - String operatorUid, - String pageNo, - String pageSize, - String searchStr) async { + Future passwordKeyList(String keyStatus, String lockId, + String pageNo, String pageSize, String searchStr) async { final res = await apiProvider.passwordKeyList( - keyStatus, lockId, operatorUid, pageNo, pageSize, searchStr); + keyStatus, lockId, pageNo, pageSize, searchStr); return PasswordKeyListEntity.fromJson(res.body); } @@ -357,43 +352,47 @@ class ApiRepository { } // 获取所有锁设置信息 - Future getLockSettingInfoData({required String lockId}) async { + Future getLockSettingInfoData( + {required String lockId}) async { final res = await apiProvider.getLockSettingInfoData(lockId); return LockSetInfoEntity.fromJson(res.body); } // 删除锁 - Future deletOwnerLockData({required String lockId}) async { + Future deletOwnerLockData( + {required String lockId}) async { final res = await apiProvider.deletLockInfo(lockId); return LockListInfoEntity.fromJson(res.body); } // 删除钥匙 - Future deletOwnerKeyData({required String lockId, required String keyId}) async { + Future deletOwnerKeyData( + {required String lockId, required String keyId}) async { final res = await apiProvider.deletOwnerKeyInfo(lockId, keyId); return LockListInfoEntity.fromJson(res.body); } // 检查账户密码 - Future checkLoginPassword({required String password}) async { + Future checkLoginPassword( + {required String password}) async { final res = await apiProvider.checkLoginPassword(password); return LockListInfoEntity.fromJson(res.body); } //获取密码 Future getPasswordKey( - String endDate, - String isExclusive, - String keyboardPwdName, - String keyboardPwdType, - String keyboardPwdVersion, - String lockId, - String operatorUid, - String startDate, - String timezoneRawOffSet, - int startHours, - int endHours, - int isCoerced) async { + {required String endDate, + required String isExclusive, + required String keyboardPwdName, + required String keyboardPwdType, + required String keyboardPwdVersion, + required String lockId, + required String operatorUid, + required String startDate, + required String timezoneRawOffSet, + required int startHours, + required int endHours, + required int isCoerced}) async { final res = await apiProvider.getKeyboardPwd( endDate, isExclusive, @@ -427,16 +426,27 @@ class ApiRepository { //修改密码 Future updatePasswordKey( - String lockId, - String keyboardPwdId, - String keyboardPwdName, - String newKeyboardPwd, - String startDate, - String endDate, - String changeType, - ) async { - final res = await apiProvider.updateKeyboardPwd(lockId, keyboardPwdId, - keyboardPwdName, newKeyboardPwd, startDate, endDate, changeType); + {required int lockId, + required String keyboardPwdId, + required String keyboardPwdName, + required String newKeyboardPwd, + required int startDate, + required int endDate, + required String changeType, + required String isCoerced, + required int hoursStart, + required int hoursEnd}) async { + final res = await apiProvider.updateKeyboardPwd( + lockId, + keyboardPwdId, + keyboardPwdName, + newKeyboardPwd, + startDate, + endDate, + changeType, + isCoerced, + hoursStart, + hoursEnd); return PasswordKeyEntity.fromJson(res.body); }