Merge branch 'master' of ssh://git.swordlost.top:222/SikongJueluo/FPGA_WebLab into dpp
This commit is contained in:
		
							
								
								
									
										3
									
								
								components.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								components.d.ts
									
									
									
									
										vendored
									
									
								
							@@ -13,6 +13,7 @@ declare module 'vue' {
 | 
			
		||||
    BaseBoard: typeof import('./src/components/equipments/BaseBoard.vue')['default']
 | 
			
		||||
    BaseInputField: typeof import('./src/components/InputField/BaseInputField.vue')['default']
 | 
			
		||||
    Canvas: typeof import('./src/components/Canvas.vue')['default']
 | 
			
		||||
    ChannelConfig: typeof import('./src/components/LogicAnalyzer/ChannelConfig.vue')['default']
 | 
			
		||||
    CollapsibleSection: typeof import('./src/components/CollapsibleSection.vue')['default']
 | 
			
		||||
    ComponentSelector: typeof import('./src/components/LabCanvas/ComponentSelector.vue')['default']
 | 
			
		||||
    DDR: typeof import('./src/components/equipments/DDR.vue')['default']
 | 
			
		||||
@@ -29,6 +30,7 @@ declare module 'vue' {
 | 
			
		||||
    LabCanvasNew: typeof import('./src/components/LabCanvas/LabCanvasNew.vue')['default']
 | 
			
		||||
    LabComponentsDrawer: typeof import('./src/components/LabCanvasNew/LabComponentsDrawer.vue')['default']
 | 
			
		||||
    LabComponentsDrawerNew: typeof import('./src/components/LabCanvas/LabComponentsDrawerNew.vue')['default']
 | 
			
		||||
    LogicalWaveFormDisplay: typeof import('./src/components/LogicAnalyzer/LogicalWaveFormDisplay.vue')['default']
 | 
			
		||||
    LoginCard: typeof import('./src/components/LoginCard.vue')['default']
 | 
			
		||||
    MarkdownRenderer: typeof import('./src/components/MarkdownRenderer.vue')['default']
 | 
			
		||||
    MechanicalButton: typeof import('./src/components/equipments/MechanicalButton.vue')['default']
 | 
			
		||||
@@ -66,6 +68,7 @@ declare module 'vue' {
 | 
			
		||||
    TabsTrigger: typeof import('reka-ui')['TabsTrigger']
 | 
			
		||||
    ThemeControlButton: typeof import('./src/components/ThemeControlButton.vue')['default']
 | 
			
		||||
    ThemeControlToggle: typeof import('./src/components/ThemeControlToggle.vue')['default']
 | 
			
		||||
    TriggerSettings: typeof import('./src/components/LogicAnalyzer/TriggerSettings.vue')['default']
 | 
			
		||||
    TutorialCarousel: typeof import('./src/components/TutorialCarousel.vue')['default']
 | 
			
		||||
    UploadCard: typeof import('./src/components/UploadCard.vue')['default']
 | 
			
		||||
    WaveformDisplay: typeof import('./src/components/Oscilloscope/WaveformDisplay.vue')['default']
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@
 | 
			
		||||
/// </summary>
 | 
			
		||||
public static class MsgBus
 | 
			
		||||
{
 | 
			
		||||
    private static readonly UDPServer udpServer = new UDPServer(1234);
 | 
			
		||||
    private static readonly UDPServer udpServer = new UDPServer(1234, 12);
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 获取UDP服务器
 | 
			
		||||
    /// </summary>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
using System.Net;
 | 
			
		||||
using DotNext;
 | 
			
		||||
using Peripherals.PowerClient;
 | 
			
		||||
 | 
			
		||||
namespace Peripherals.CameraClient;
 | 
			
		||||
 | 
			
		||||
@@ -27,7 +28,7 @@ class Camera
 | 
			
		||||
 | 
			
		||||
    const uint CAM_I2C_ADDR = 0x3C;
 | 
			
		||||
    const Peripherals.I2cClient.I2cProtocol CAM_PROTO = Peripherals.I2cClient.I2cProtocol.SCCB;
 | 
			
		||||
    const byte PLL_MUX = 60;
 | 
			
		||||
    const byte PLL_MUX = 105;
 | 
			
		||||
    const UInt32 FrameAddr = 0x00;
 | 
			
		||||
 | 
			
		||||
    // 动态分辨率参数
 | 
			
		||||
@@ -54,6 +55,8 @@ class Camera
 | 
			
		||||
 | 
			
		||||
    public async ValueTask<Result<bool>> Init()
 | 
			
		||||
    {
 | 
			
		||||
        await PowerHardwareCamera(true);
 | 
			
		||||
        await SleepHardwareCamera(false);
 | 
			
		||||
        // 步骤1: 复位
 | 
			
		||||
        var resetResult = await Reset();
 | 
			
		||||
        if (!resetResult.IsSuccessful) return resetResult;
 | 
			
		||||
@@ -139,14 +142,16 @@ class Camera
 | 
			
		||||
        var resolutionResult = await ConfigureResolution1280x720();
 | 
			
		||||
        if (!resolutionResult.IsSuccessful) return resolutionResult;
 | 
			
		||||
 | 
			
		||||
        // 步骤22: 开始流
 | 
			
		||||
        // // 步骤22: 开始流
 | 
			
		||||
        var startResult = await StartStreaming();
 | 
			
		||||
        if (!startResult.IsSuccessful) return startResult;
 | 
			
		||||
        // var resetResult2 = await Reset();
 | 
			
		||||
        // if (!resetResult2.IsSuccessful) return resetResult2;
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async ValueTask<Result<bool>> EnableCamera(bool isEnable)
 | 
			
		||||
    public async ValueTask<Result<bool>> EnableHardwareTrans(bool isEnable)
 | 
			
		||||
    {
 | 
			
		||||
        var ret = await UDPClientPool.WriteAddr(this.ep, this.taskID, CameraAddr.CAPTURE_ON, Convert.ToUInt32(isEnable));
 | 
			
		||||
        if (!ret.IsSuccessful)
 | 
			
		||||
@@ -162,7 +167,7 @@ class Camera
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async ValueTask<Result<bool>> EnableCameraHardware(bool isEnable)
 | 
			
		||||
    public async ValueTask<Result<bool>> PowerHardwareCamera(bool isEnable)
 | 
			
		||||
    {
 | 
			
		||||
        {
 | 
			
		||||
            var ret = await UDPClientPool.WriteAddr(this.ep, this.taskID, CameraAddr.CAMERA_POWER, (isEnable ? 0x00000001u : 0x00000000u));
 | 
			
		||||
@@ -180,7 +185,7 @@ class Camera
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async ValueTask<Result<bool>> SleepCameraHardware(bool isEnable)
 | 
			
		||||
    public async ValueTask<Result<bool>> SleepHardwareCamera(bool isEnable)
 | 
			
		||||
    {
 | 
			
		||||
        {
 | 
			
		||||
            var ret = await UDPClientPool.WriteAddr(this.ep, this.taskID, CameraAddr.CAMERA_POWER, (isEnable ? 0x00000101u : 0x00000001u));
 | 
			
		||||
@@ -224,7 +229,7 @@ class Camera
 | 
			
		||||
            // 读取失败时清除缓冲区,为下次读取做准备
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                await MsgBus.UDPServer.ClearUDPData(this.address, this.taskID);
 | 
			
		||||
                MsgBus.UDPServer.ClearUDPData(this.address, this.taskID);
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
@@ -237,6 +242,33 @@ class Camera
 | 
			
		||||
        return result.Value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 读取摄像头寄存器
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="registerAddr">寄存器地址</param>
 | 
			
		||||
    /// <returns>读取到的寄存器值</returns>
 | 
			
		||||
    private async ValueTask<Result<byte>> ReadRegister(UInt16 registerAddr)
 | 
			
		||||
    {
 | 
			
		||||
        var i2c = new Peripherals.I2cClient.I2c(this.address, this.port, this.taskID, this.timeout);
 | 
			
		||||
        
 | 
			
		||||
        // 地址高低字节
 | 
			
		||||
        var addrBytes = new byte[2];
 | 
			
		||||
        addrBytes[0] = (byte)(registerAddr >> 8);
 | 
			
		||||
        addrBytes[1] = (byte)(registerAddr & 0xFF);
 | 
			
		||||
 | 
			
		||||
        // 先写寄存器地址
 | 
			
		||||
        var writeResult = await i2c.WriteData(CAM_I2C_ADDR, addrBytes, CAM_PROTO);
 | 
			
		||||
        if (!writeResult.IsSuccessful)
 | 
			
		||||
            return new(writeResult.Error);
 | 
			
		||||
 | 
			
		||||
        // 再读一个字节
 | 
			
		||||
        var readResult = await i2c.ReadData(CAM_I2C_ADDR, 1, CAM_PROTO);
 | 
			
		||||
        if (!readResult.IsSuccessful)
 | 
			
		||||
            return new(readResult.Error);
 | 
			
		||||
 | 
			
		||||
        return readResult.Value[0];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// 批量配置I2C寄存器
 | 
			
		||||
    /// </summary>
 | 
			
		||||
@@ -260,7 +292,7 @@ class Camera
 | 
			
		||||
            var address = cmd[0];
 | 
			
		||||
            i2cData[0] = (byte)(address >> 8);    // 地址高位
 | 
			
		||||
            i2cData[1] = (byte)(address & 0xFF);  // 地址低位
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            // 复制数据部分
 | 
			
		||||
            for (int i = 1; i < cmd.Length; i++)
 | 
			
		||||
            {
 | 
			
		||||
@@ -296,7 +328,7 @@ class Camera
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    await Task.Delay(3); // 其他命令延时3ms
 | 
			
		||||
                    await Task.Delay(5); // 其他命令延时3ms
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -391,11 +423,6 @@ class Camera
 | 
			
		||||
        // 2. 配置I2C寄存器
 | 
			
		||||
        var resolutionRegisters = new UInt16[][]
 | 
			
		||||
        {
 | 
			
		||||
            // H_OFFSET/V_OFFSET
 | 
			
		||||
            [0x3810, unchecked((byte)((hOffset >> 8) & 0xFF))],
 | 
			
		||||
            [0x3811, unchecked((byte)(hOffset & 0xFF))],
 | 
			
		||||
            [0x3812, unchecked((byte)((vOffset >> 8) & 0xFF))],
 | 
			
		||||
            
 | 
			
		||||
            // H_START/V_START
 | 
			
		||||
            [0x3800, unchecked((byte)((hStart >> 8) & 0xFF))],
 | 
			
		||||
            [0x3801, unchecked((byte)(hStart & 0xFF))],
 | 
			
		||||
@@ -420,6 +447,10 @@ class Camera
 | 
			
		||||
            [0x380E, unchecked((byte)((vts >> 8) & 0xFF))],
 | 
			
		||||
            [0x380F, unchecked((byte)(vts & 0xFF))],
 | 
			
		||||
            
 | 
			
		||||
            // H_OFFSET/V_OFFSET
 | 
			
		||||
            [0x3810, unchecked((byte)((hOffset >> 8) & 0xFF))],
 | 
			
		||||
            [0x3811, unchecked((byte)(hOffset & 0xFF))],
 | 
			
		||||
            [0x3812, unchecked((byte)((vOffset >> 8) & 0xFF))],
 | 
			
		||||
            // Timing Voffset
 | 
			
		||||
            [0x3813, unchecked((byte)(vOffset & 0xFF))]
 | 
			
		||||
        };
 | 
			
		||||
@@ -548,10 +579,11 @@ class Camera
 | 
			
		||||
    {
 | 
			
		||||
        var resetRegisters = new UInt16[][]
 | 
			
		||||
        {
 | 
			
		||||
            [0x30, 0x08, 0x82] // 复位命令
 | 
			
		||||
            [0x3103, 0x11],// system clock from pad, bit[1]
 | 
			
		||||
            [0x3008, 0x82] // 复位命令
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return await ConfigureRegisters(resetRegisters, customDelayMs: 5); // 复位后等待5ms
 | 
			
		||||
        return await ConfigureRegisters(resetRegisters, customDelayMs: 50); // 复位后等待5ms
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
@@ -576,7 +608,7 @@ class Camera
 | 
			
		||||
    {
 | 
			
		||||
        var basicRegisters = new UInt16[][]
 | 
			
		||||
        {
 | 
			
		||||
            [0x3103, 0x02],
 | 
			
		||||
            [0x3103, 0x02], // system clock from pad, bit[1]
 | 
			
		||||
            [0x3017, 0xff],
 | 
			
		||||
            [0x3018, 0xff],
 | 
			
		||||
            [0x3037, 0x13],
 | 
			
		||||
@@ -633,9 +665,7 @@ class Camera
 | 
			
		||||
        {
 | 
			
		||||
            [0x3905, 0x02],
 | 
			
		||||
            [0x3906, 0x10],
 | 
			
		||||
            [0x3901, 0x0a],
 | 
			
		||||
            [0x3035, 0x11], // 30fps
 | 
			
		||||
            [0x3036, PLL_MUX] // PLL倍频
 | 
			
		||||
            [0x3901, 0x0a]
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return await ConfigureRegisters(clockRegisters);
 | 
			
		||||
@@ -693,7 +723,6 @@ class Camera
 | 
			
		||||
            [0x3c04, 0x28],
 | 
			
		||||
            [0x3c05, 0x98],
 | 
			
		||||
            [0x3c06, 0x00],
 | 
			
		||||
            [0x3c07, 0x08],
 | 
			
		||||
            [0x3c08, 0x00],
 | 
			
		||||
            [0x3c09, 0x1c],
 | 
			
		||||
            [0x3c0a, 0x9c],
 | 
			
		||||
@@ -753,10 +782,6 @@ class Camera
 | 
			
		||||
            [0x3a1e, 0x26], // AEC控制;stable range out low
 | 
			
		||||
            [0x3a11, 0x60], // AEC控制; fast zone high
 | 
			
		||||
            [0x3a1f, 0x14], // AEC控制; fast zone low
 | 
			
		||||
            [0x3a02, 0x17], // 60Hz max exposure
 | 
			
		||||
            [0x3a03, 0x10], // 60Hz max exposure
 | 
			
		||||
            [0x3a14, 0x17], // 50Hz max exposure
 | 
			
		||||
            [0x3a15, 0x10], // 50Hz max exposure
 | 
			
		||||
            [0x3b07, 0x0a]  // 帧曝光模式
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
@@ -900,14 +925,13 @@ class Camera
 | 
			
		||||
    {
 | 
			
		||||
        var timingRegisters = new UInt16[][]
 | 
			
		||||
        {
 | 
			
		||||
            [0x3820, 0x46], // vflip
 | 
			
		||||
            [0x3821, 0x01], // mirror
 | 
			
		||||
            [0x3814, 0x31], // timing X inc
 | 
			
		||||
            [0x3815, 0x31], // timing Y inc
 | 
			
		||||
            [0x3618, 0x00],
 | 
			
		||||
            [0x3612, 0x29],
 | 
			
		||||
            [0x3709, 0x52],
 | 
			
		||||
            [0x370c, 0x03]
 | 
			
		||||
            [0x3035, 0x11], // 60fps
 | 
			
		||||
            [0x3036, PLL_MUX],// PLL倍频
 | 
			
		||||
            [0x3c07, 0x08],
 | 
			
		||||
            [0x3820, 0x41], // vflip
 | 
			
		||||
            [0x3821, 0x00], // mirror
 | 
			
		||||
            [0x3814, 0x11], // timing X inc
 | 
			
		||||
            [0x3815, 0x11]  // timing Y inc
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return await ConfigureRegisters(timingRegisters);
 | 
			
		||||
@@ -921,14 +945,22 @@ class Camera
 | 
			
		||||
    {
 | 
			
		||||
        var testRegisters = new UInt16[][]
 | 
			
		||||
        {
 | 
			
		||||
            [0x3618, 0x00],
 | 
			
		||||
            [0x3612, 0x29],
 | 
			
		||||
            [0x3709, 0x52],
 | 
			
		||||
            [0x370c, 0x03],
 | 
			
		||||
            [0x4004, 0x02], // BLC(背光) 2 lines
 | 
			
		||||
            [0x4713, 0x03], // JPEG mode 3
 | 
			
		||||
            [0x4407, 0x04], // 量化标度
 | 
			
		||||
            [0x460c, 0x20],
 | 
			
		||||
            [0x3a02, 0x17], // 60Hz max exposure
 | 
			
		||||
            [0x3a03, 0x10], // 60Hz max exposure
 | 
			
		||||
            [0x3a14, 0x17], // 50Hz max exposure
 | 
			
		||||
            [0x3a15, 0x10], // 50Hz max exposure
 | 
			
		||||
            [0x4837, 0x22], // DVP CLK divider
 | 
			
		||||
            [0x3824, 0x02], // DVP CLK divider
 | 
			
		||||
            // 彩条测试禁用
 | 
			
		||||
            [0x503d, 0x00],
 | 
			
		||||
            [0x503d, 0x80],
 | 
			
		||||
            [0x4741, 0x00],
 | 
			
		||||
            // 闪光灯配置
 | 
			
		||||
            [0x3016, 0x02],
 | 
			
		||||
@@ -962,250 +994,250 @@ class Camera
 | 
			
		||||
    private static readonly UInt16[] OV5640_AF_FIRMWARE =
 | 
			
		||||
    [
 | 
			
		||||
        0x02, 0x0d, 0xf3, 0x02, 0x0a, 0x5f, 0xc2, 0x01, 0x22, 0x22, 0x00, 0x02, 0x0f, 0x31, 0x30, 0x01,
 | 
			
		||||
        0x03, 0x02, 0x03, 0x09, 0x30, 0x02, 0x03, 0x02, 0x03, 0x09, 0x90, 0x51, 0xa5, 0xe0, 0x78, 0xbb, 
 | 
			
		||||
        0xf6, 0xa3, 0xe0, 0x08, 0xf6, 0xa3, 0xe0, 0x08, 0xf6, 0xe5, 0x1f, 0x70, 0x45, 0x75, 0x1e, 0x20, 
 | 
			
		||||
        0xd2, 0x34, 0x12, 0x0c, 0x0c, 0x78, 0x9c, 0x12, 0x0b, 0xd2, 0x78, 0xa8, 0xa6, 0x14, 0x08, 0xa6, 
 | 
			
		||||
        0x15, 0x78, 0xb3, 0xa6, 0x09, 0x18, 0x76, 0x01, 0x78, 0x4c, 0xa6, 0x0a, 0x08, 0xa6, 0x0b, 0x78, 
 | 
			
		||||
        0x6c, 0xa6, 0x14, 0x08, 0xa6, 0x15, 0x78, 0xb3, 0xe6, 0x78, 0x8c, 0xf6, 0x75, 0x1f, 0x01, 0x78, 
 | 
			
		||||
        0xbb, 0xe6, 0x78, 0xb8, 0xf6, 0x78, 0xbc, 0xe6, 0x78, 0xb9, 0xf6, 0x78, 0xbd, 0xe6, 0x78, 0xba, 
 | 
			
		||||
        0xf6, 0x22, 0x79, 0xb8, 0xe7, 0xd3, 0x78, 0xbb, 0x96, 0x40, 0x05, 0xe7, 0x96, 0xff, 0x80, 0x08, 
 | 
			
		||||
        0xc3, 0x79, 0xbb, 0xe7, 0x78, 0xb8, 0x96, 0xff, 0x78, 0xa6, 0x76, 0x00, 0x08, 0xa6, 0x07, 0x79, 
 | 
			
		||||
        0xb9, 0xe7, 0xd3, 0x78, 0xbc, 0x96, 0x40, 0x05, 0xe7, 0x96, 0xff, 0x80, 0x08, 0xc3, 0x79, 0xbc, 
 | 
			
		||||
        0xe7, 0x78, 0xb9, 0x96, 0xff, 0x12, 0x0c, 0x13, 0x79, 0xba, 0xe7, 0xd3, 0x78, 0xbd, 0x96, 0x40, 
 | 
			
		||||
        0x05, 0xe7, 0x96, 0xff, 0x80, 0x08, 0xc3, 0x79, 0xbd, 0xe7, 0x78, 0xba, 0x96, 0xff, 0x12, 0x0c, 
 | 
			
		||||
        0x13, 0x78, 0xb2, 0xe6, 0x25, 0xe0, 0x24, 0x4c, 0xf8, 0xa6, 0x0a, 0x08, 0xa6, 0x0b, 0x78, 0xb2, 
 | 
			
		||||
        0xe6, 0x25, 0xe0, 0x24, 0x6c, 0xf8, 0xa6, 0x14, 0x08, 0xa6, 0x15, 0x78, 0xb2, 0xe6, 0x24, 0x8c, 
 | 
			
		||||
        0xf8, 0xa6, 0x09, 0x78, 0xb2, 0xe6, 0x24, 0x01, 0xff, 0xe4, 0x33, 0xfe, 0xd3, 0xef, 0x94, 0x0f, 
 | 
			
		||||
        0xee, 0x64, 0x80, 0x94, 0x80, 0x40, 0x04, 0x7f, 0x00, 0x80, 0x05, 0x78, 0xb2, 0xe6, 0x04, 0xff, 
 | 
			
		||||
        0x78, 0xb2, 0xa6, 0x07, 0xe5, 0x1f, 0xb4, 0x01, 0x0a, 0xe6, 0x60, 0x03, 0x02, 0x03, 0x09, 0x75, 
 | 
			
		||||
        0x1f, 0x02, 0x22, 0x12, 0x0c, 0x0c, 0x78, 0x9e, 0x12, 0x0b, 0xd2, 0x12, 0x0c, 0x0c, 0x78, 0xa0, 
 | 
			
		||||
        0x12, 0x0b, 0xff, 0x78, 0xaa, 0x12, 0x0b, 0xff, 0xff, 0x78, 0xac, 0xa6, 0x06, 0x08, 0xa6, 0x07, 
 | 
			
		||||
        0x78, 0x8c, 0xe6, 0x78, 0xb4, 0xf6, 0x78, 0x8c, 0xe6, 0x78, 0xb5, 0xf6, 0x7f, 0x01, 0xef, 0x25, 
 | 
			
		||||
        0xe0, 0x24, 0x4d, 0x78, 0x9f, 0x12, 0x0b, 0xc9, 0x50, 0x0a, 0x12, 0x0b, 0xab, 0x78, 0x9e, 0xa6, 
 | 
			
		||||
        0x04, 0x08, 0xa6, 0x05, 0xef, 0x25, 0xe0, 0x24, 0x6d, 0x78, 0xab, 0x12, 0x0b, 0xc9, 0x50, 0x0f, 
 | 
			
		||||
        0xef, 0x25, 0xe0, 0x24, 0x6c, 0x12, 0x0b, 0xb0, 0x78, 0xaa, 0xa6, 0x04, 0x08, 0xa6, 0x05, 0x74, 
 | 
			
		||||
        0x8c, 0x2f, 0xf9, 0x78, 0xb4, 0xe6, 0xc3, 0x97, 0x50, 0x08, 0x74, 0x8c, 0x2f, 0xf8, 0xe6, 0x78, 
 | 
			
		||||
        0xb4, 0xf6, 0xef, 0x25, 0xe0, 0x24, 0x4d, 0xf9, 0xd3, 0x78, 0xa1, 0x12, 0x0b, 0xcb, 0x40, 0x0a, 
 | 
			
		||||
        0x12, 0x0b, 0xab, 0x78, 0xa0, 0xa6, 0x04, 0x08, 0xa6, 0x05, 0xef, 0x25, 0xe0, 0x24, 0x6d, 0xf9, 
 | 
			
		||||
        0xd3, 0x78, 0xad, 0x12, 0x0b, 0xcb, 0x40, 0x0f, 0xef, 0x25, 0xe0, 0x24, 0x6c, 0x12, 0x0b, 0xb0, 
 | 
			
		||||
        0x78, 0xac, 0xa6, 0x04, 0x08, 0xa6, 0x05, 0x74, 0x8c, 0x2f, 0xf9, 0x78, 0xb5, 0xe6, 0xd3, 0x97, 
 | 
			
		||||
        0x40, 0x08, 0x74, 0x8c, 0x2f, 0xf8, 0xe6, 0x78, 0xb5, 0xf6, 0x0f, 0xef, 0x64, 0x10, 0x60, 0x03, 
 | 
			
		||||
        0x02, 0x01, 0x3e, 0xc3, 0x79, 0x9f, 0x78, 0xa1, 0x12, 0x0b, 0xf7, 0x78, 0xa2, 0xf6, 0x08, 0xa6, 
 | 
			
		||||
        0x07, 0xc3, 0x79, 0xab, 0x78, 0xad, 0x12, 0x0b, 0xf7, 0x78, 0xae, 0xf6, 0x08, 0xa6, 0x07, 0xc3, 
 | 
			
		||||
        0x79, 0xb4, 0xe7, 0x78, 0xb5, 0x96, 0x08, 0xf6, 0xd3, 0x79, 0x9f, 0xe7, 0x78, 0x9d, 0x96, 0x19, 
 | 
			
		||||
        0xe7, 0x18, 0x96, 0x40, 0x05, 0x09, 0xe7, 0x08, 0x80, 0x06, 0xc3, 0x79, 0x9d, 0xe7, 0x78, 0x9f, 
 | 
			
		||||
        0x12, 0x0b, 0xf8, 0xfe, 0x78, 0xa4, 0xa6, 0x06, 0x08, 0xa6, 0x07, 0xd3, 0x79, 0xab, 0xe7, 0x78, 
 | 
			
		||||
        0xa9, 0x96, 0x19, 0xe7, 0x18, 0x96, 0x40, 0x05, 0x09, 0xe7, 0x08, 0x80, 0x06, 0xc3, 0x79, 0xa9, 
 | 
			
		||||
        0xe7, 0x78, 0xab, 0x12, 0x0b, 0xf8, 0xfe, 0x78, 0xb0, 0xa6, 0x06, 0x08, 0xa6, 0x07, 0x79, 0xb4, 
 | 
			
		||||
        0xe7, 0xd3, 0x78, 0xb3, 0x96, 0x40, 0x05, 0xe7, 0x96, 0xff, 0x80, 0x08, 0xc3, 0x79, 0xb3, 0xe7, 
 | 
			
		||||
        0x78, 0xb4, 0x96, 0xff, 0x78, 0xb7, 0xa6, 0x07, 0xe5, 0x1f, 0x64, 0x02, 0x60, 0x03, 0x02, 0x02, 
 | 
			
		||||
        0xef, 0x90, 0x30, 0x24, 0x74, 0x0f, 0xf0, 0x90, 0x0e, 0x8a, 0xe4, 0x93, 0xff, 0x18, 0xe6, 0xc3, 
 | 
			
		||||
        0x9f, 0x40, 0x03, 0x02, 0x03, 0x09, 0x90, 0x30, 0x24, 0x74, 0x0e, 0xf0, 0x78, 0xa2, 0x12, 0x0b, 
 | 
			
		||||
        0xd9, 0x12, 0x0b, 0xa2, 0x90, 0x0e, 0x87, 0x12, 0x0b, 0xb7, 0x78, 0x9e, 0x12, 0x0b, 0xe8, 0x7b, 
 | 
			
		||||
        0x04, 0x12, 0x0b, 0x90, 0xc3, 0x12, 0x07, 0x0e, 0x50, 0x6f, 0x90, 0x0e, 0x8b, 0xe4, 0x93, 0xff, 
 | 
			
		||||
        0x78, 0xb7, 0xe6, 0x9f, 0x40, 0x07, 0x90, 0x30, 0x24, 0x74, 0x0a, 0x80, 0x16, 0x90, 0x0e, 0x89, 
 | 
			
		||||
        0xe4, 0x93, 0xff, 0xd3, 0x78, 0xa7, 0xe6, 0x9f, 0x18, 0xe6, 0x94, 0x00, 0x40, 0x09, 0x90, 0x30, 
 | 
			
		||||
        0x24, 0x74, 0x0b, 0xf0, 0x75, 0x1f, 0x05, 0x78, 0xae, 0x12, 0x0b, 0xd9, 0x12, 0x0b, 0xa2, 0x90, 
 | 
			
		||||
        0x0e, 0x88, 0x12, 0x0b, 0xb7, 0x78, 0xa8, 0x12, 0x0b, 0xe8, 0x7b, 0x40, 0x12, 0x0b, 0x90, 0xd3, 
 | 
			
		||||
        0x12, 0x07, 0x0e, 0x40, 0x24, 0x90, 0x30, 0x24, 0x74, 0x0c, 0xf0, 0x75, 0x1f, 0x05, 0x22, 0x90, 
 | 
			
		||||
        0x30, 0x24, 0x74, 0x01, 0xf0, 0xe5, 0x1f, 0xb4, 0x05, 0x0f, 0xd2, 0x01, 0xc2, 0x02, 0xe4, 0xf5, 
 | 
			
		||||
        0x1f, 0xf5, 0x1e, 0xd2, 0x34, 0xd2, 0x32, 0xd2, 0x35, 0x22, 0xe5, 0x1f, 0x60, 0x03, 0x02, 0x03, 
 | 
			
		||||
        0x93, 0xf5, 0x1e, 0xd2, 0x34, 0x75, 0x34, 0xff, 0x75, 0x35, 0x0e, 0x75, 0x36, 0x55, 0x75, 0x37, 
 | 
			
		||||
        0x01, 0x12, 0x0d, 0x85, 0xe4, 0xff, 0xef, 0x25, 0xe0, 0x24, 0x4c, 0xf8, 0xe4, 0xf6, 0x08, 0xf6, 
 | 
			
		||||
        0x0f, 0xbf, 0x34, 0xf2, 0x90, 0x0e, 0x8c, 0xe4, 0x93, 0xff, 0xe5, 0x49, 0xc3, 0x9f, 0x50, 0x04, 
 | 
			
		||||
        0x7f, 0x05, 0x80, 0x02, 0x7f, 0xfb, 0x78, 0xbb, 0xa6, 0x07, 0x12, 0x0e, 0xbc, 0x40, 0x04, 0x7f, 
 | 
			
		||||
        0x03, 0x80, 0x02, 0x7f, 0x30, 0x78, 0xba, 0xa6, 0x07, 0xe6, 0x18, 0xf6, 0x08, 0xe6, 0x78, 0xb7, 
 | 
			
		||||
        0xf6, 0x78, 0xba, 0xe6, 0x78, 0xb8, 0xf6, 0x78, 0xbd, 0x76, 0x33, 0xe4, 0x08, 0xf6, 0x78, 0xb6, 
 | 
			
		||||
        0x76, 0x01, 0x75, 0x48, 0x02, 0x78, 0xb4, 0xf6, 0x08, 0xf6, 0x74, 0xff, 0x78, 0xbf, 0xf6, 0x08, 
 | 
			
		||||
        0xf6, 0x75, 0x1f, 0x01, 0x78, 0xba, 0xe6, 0x75, 0xf0, 0x05, 0xa4, 0xf5, 0x49, 0x12, 0x0a, 0xfd, 
 | 
			
		||||
        0xc2, 0x36, 0x22, 0x78, 0xb6, 0xe6, 0xd3, 0x94, 0x00, 0x40, 0x02, 0x16, 0x22, 0xe5, 0x1f, 0xb4, 
 | 
			
		||||
        0x05, 0x23, 0xe4, 0xf5, 0x1f, 0xc2, 0x01, 0x78, 0xb4, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x78, 0x4c, 
 | 
			
		||||
        0xa6, 0x06, 0x08, 0xa6, 0x07, 0xa2, 0x36, 0xe4, 0x33, 0xf5, 0x3c, 0x90, 0x30, 0x28, 0xf0, 0x75, 
 | 
			
		||||
        0x1e, 0x10, 0xd2, 0x34, 0x22, 0xe5, 0x49, 0x75, 0xf0, 0x05, 0x84, 0x78, 0xba, 0xf6, 0x90, 0x0e, 
 | 
			
		||||
        0x85, 0xe4, 0x93, 0xff, 0x25, 0xe0, 0x24, 0x0a, 0xf8, 0xe6, 0xfc, 0x08, 0xe6, 0xfd, 0x78, 0xba, 
 | 
			
		||||
        0xe6, 0x25, 0xe0, 0x24, 0x4c, 0xf8, 0xa6, 0x04, 0x08, 0xa6, 0x05, 0xef, 0x12, 0x0e, 0xc3, 0xd3, 
 | 
			
		||||
        0x78, 0xb5, 0x96, 0xee, 0x18, 0x96, 0x40, 0x0d, 0x78, 0xba, 0xe6, 0x78, 0xb7, 0xf6, 0x78, 0xb4, 
 | 
			
		||||
        0xa6, 0x06, 0x08, 0xa6, 0x07, 0x90, 0x0e, 0x85, 0xe4, 0x93, 0x12, 0x0e, 0xc3, 0xc3, 0x78, 0xc0, 
 | 
			
		||||
        0x96, 0xee, 0x18, 0x96, 0x50, 0x0d, 0x78, 0xba, 0xe6, 0x78, 0xb8, 0xf6, 0x78, 0xbf, 0xa6, 0x06, 
 | 
			
		||||
        0x08, 0xa6, 0x07, 0x78, 0xb4, 0xe6, 0xfe, 0x08, 0xe6, 0xc3, 0x78, 0xc0, 0x96, 0xff, 0xee, 0x18, 
 | 
			
		||||
        0x96, 0x78, 0xc1, 0xf6, 0x08, 0xa6, 0x07, 0x90, 0x0e, 0x8e, 0xe4, 0x18, 0x12, 0x0e, 0xa1, 0x40, 
 | 
			
		||||
        0x02, 0xd2, 0x36, 0x78, 0xba, 0xe6, 0x08, 0x26, 0x08, 0xf6, 0xe5, 0x1f, 0x64, 0x01, 0x70, 0x4a, 
 | 
			
		||||
        0xe6, 0xc3, 0x78, 0xbe, 0x12, 0x0e, 0x97, 0x40, 0x05, 0x12, 0x0e, 0x92, 0x40, 0x39, 0x12, 0x0e, 
 | 
			
		||||
        0xba, 0x40, 0x04, 0x7f, 0xfe, 0x80, 0x02, 0x7f, 0x02, 0x78, 0xbb, 0xa6, 0x07, 0x78, 0xb7, 0xe6, 
 | 
			
		||||
        0x24, 0x03, 0x78, 0xbd, 0xf6, 0x78, 0xb7, 0xe6, 0x24, 0xfd, 0x78, 0xbe, 0xf6, 0x12, 0x0e, 0xba, 
 | 
			
		||||
        0x40, 0x06, 0x78, 0xbe, 0xe6, 0xff, 0x80, 0x04, 0x78, 0xbd, 0xe6, 0xff, 0x78, 0xbc, 0xa6, 0x07, 
 | 
			
		||||
        0x75, 0x1f, 0x02, 0x78, 0xb6, 0x76, 0x01, 0x02, 0x05, 0x59, 0xe5, 0x1f, 0x64, 0x02, 0x60, 0x03, 
 | 
			
		||||
        0x02, 0x05, 0x39, 0x78, 0xbc, 0xe6, 0xff, 0xc3, 0x78, 0xbe, 0x12, 0x0e, 0x98, 0x40, 0x08, 0x12, 
 | 
			
		||||
        0x0e, 0x92, 0x50, 0x03, 0x02, 0x05, 0x37, 0x12, 0x0e, 0xba, 0x40, 0x04, 0x7f, 0xff, 0x80, 0x02, 
 | 
			
		||||
        0x7f, 0x01, 0x78, 0xbb, 0xa6, 0x07, 0x78, 0xb7, 0xe6, 0x04, 0x78, 0xbd, 0xf6, 0x78, 0xb7, 0xe6, 
 | 
			
		||||
        0x14, 0x78, 0xbe, 0xf6, 0x18, 0x12, 0x0e, 0xbc, 0x40, 0x04, 0xe6, 0xff, 0x80, 0x02, 0x7f, 0x00, 
 | 
			
		||||
        0x78, 0xbd, 0xa6, 0x07, 0xd3, 0x08, 0xe6, 0x64, 0x80, 0x94, 0x80, 0x40, 0x04, 0xe6, 0xff, 0x80, 
 | 
			
		||||
        0x02, 0x7f, 0x00, 0x78, 0xbe, 0xa6, 0x07, 0xc3, 0x18, 0xe6, 0x64, 0x80, 0x94, 0xb3, 0x50, 0x04, 
 | 
			
		||||
        0xe6, 0xff, 0x80, 0x02, 0x7f, 0x33, 0x78, 0xbd, 0xa6, 0x07, 0xc3, 0x08, 0xe6, 0x64, 0x80, 0x94, 
 | 
			
		||||
        0xb3, 0x50, 0x04, 0xe6, 0xff, 0x80, 0x02, 0x7f, 0x33, 0x78, 0xbe, 0xa6, 0x07, 0x12, 0x0e, 0xba, 
 | 
			
		||||
        0x40, 0x06, 0x78, 0xbe, 0xe6, 0xff, 0x80, 0x04, 0x78, 0xbd, 0xe6, 0xff, 0x78, 0xbc, 0xa6, 0x07, 
 | 
			
		||||
        0x75, 0x1f, 0x03, 0x78, 0xb6, 0x76, 0x01, 0x80, 0x20, 0xe5, 0x1f, 0x64, 0x03, 0x70, 0x26, 0x78, 
 | 
			
		||||
        0xbc, 0xe6, 0xff, 0xc3, 0x78, 0xbe, 0x12, 0x0e, 0x98, 0x40, 0x05, 0x12, 0x0e, 0x92, 0x40, 0x09, 
 | 
			
		||||
        0x78, 0xb7, 0xe6, 0x78, 0xbc, 0xf6, 0x75, 0x1f, 0x04, 0x78, 0xbc, 0xe6, 0x75, 0xf0, 0x05, 0xa4, 
 | 
			
		||||
        0xf5, 0x49, 0x02, 0x0a, 0xfd, 0xe5, 0x1f, 0xb4, 0x04, 0x1f, 0x90, 0x0e, 0x8d, 0xe4, 0x78, 0xc1, 
 | 
			
		||||
        0x12, 0x0e, 0xa1, 0x40, 0x02, 0xd2, 0x36, 0x75, 0x1f, 0x05, 0x75, 0x34, 0xff, 0x75, 0x35, 0x0e, 
 | 
			
		||||
        0x75, 0x36, 0x59, 0x75, 0x37, 0x01, 0x12, 0x0d, 0x85, 0x22, 0xef, 0x8d, 0xf0, 0xa4, 0xa8, 0xf0, 
 | 
			
		||||
        0xcf, 0x8c, 0xf0, 0xa4, 0x28, 0xce, 0x8d, 0xf0, 0xa4, 0x2e, 0xfe, 0x22, 0xbc, 0x00, 0x0b, 0xbe, 
 | 
			
		||||
        0x00, 0x29, 0xef, 0x8d, 0xf0, 0x84, 0xff, 0xad, 0xf0, 0x22, 0xe4, 0xcc, 0xf8, 0x75, 0xf0, 0x08, 
 | 
			
		||||
        0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xec, 0x33, 0xfc, 0xee, 0x9d, 0xec, 0x98, 0x40, 0x05, 0xfc, 
 | 
			
		||||
        0xee, 0x9d, 0xfe, 0x0f, 0xd5, 0xf0, 0xe9, 0xe4, 0xce, 0xfd, 0x22, 0xed, 0xf8, 0xf5, 0xf0, 0xee, 
 | 
			
		||||
        0x84, 0x20, 0xd2, 0x1c, 0xfe, 0xad, 0xf0, 0x75, 0xf0, 0x08, 0xef, 0x2f, 0xff, 0xed, 0x33, 0xfd, 
 | 
			
		||||
        0x40, 0x07, 0x98, 0x50, 0x06, 0xd5, 0xf0, 0xf2, 0x22, 0xc3, 0x98, 0xfd, 0x0f, 0xd5, 0xf0, 0xea, 
 | 
			
		||||
        0x22, 0xe8, 0x8f, 0xf0, 0xa4, 0xcc, 0x8b, 0xf0, 0xa4, 0x2c, 0xfc, 0xe9, 0x8e, 0xf0, 0xa4, 0x2c, 
 | 
			
		||||
        0xfc, 0x8a, 0xf0, 0xed, 0xa4, 0x2c, 0xfc, 0xea, 0x8e, 0xf0, 0xa4, 0xcd, 0xa8, 0xf0, 0x8b, 0xf0, 
 | 
			
		||||
        0xa4, 0x2d, 0xcc, 0x38, 0x25, 0xf0, 0xfd, 0xe9, 0x8f, 0xf0, 0xa4, 0x2c, 0xcd, 0x35, 0xf0, 0xfc, 
 | 
			
		||||
        0xeb, 0x8e, 0xf0, 0xa4, 0xfe, 0xa9, 0xf0, 0xeb, 0x8f, 0xf0, 0xa4, 0xcf, 0xc5, 0xf0, 0x2e, 0xcd, 
 | 
			
		||||
        0x39, 0xfe, 0xe4, 0x3c, 0xfc, 0xea, 0xa4, 0x2d, 0xce, 0x35, 0xf0, 0xfd, 0xe4, 0x3c, 0xfc, 0x22, 
 | 
			
		||||
        0x75, 0xf0, 0x08, 0x75, 0x82, 0x00, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xcd, 0x33, 0xcd, 0xcc, 
 | 
			
		||||
        0x33, 0xcc, 0xc5, 0x82, 0x33, 0xc5, 0x82, 0x9b, 0xed, 0x9a, 0xec, 0x99, 0xe5, 0x82, 0x98, 0x40, 
 | 
			
		||||
        0x0c, 0xf5, 0x82, 0xee, 0x9b, 0xfe, 0xed, 0x9a, 0xfd, 0xec, 0x99, 0xfc, 0x0f, 0xd5, 0xf0, 0xd6, 
 | 
			
		||||
        0xe4, 0xce, 0xfb, 0xe4, 0xcd, 0xfa, 0xe4, 0xcc, 0xf9, 0xa8, 0x82, 0x22, 0xb8, 0x00, 0xc1, 0xb9, 
 | 
			
		||||
        0x00, 0x59, 0xba, 0x00, 0x2d, 0xec, 0x8b, 0xf0, 0x84, 0xcf, 0xce, 0xcd, 0xfc, 0xe5, 0xf0, 0xcb, 
 | 
			
		||||
        0xf9, 0x78, 0x18, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xec, 0x33, 0xfc, 0xeb, 
 | 
			
		||||
        0x33, 0xfb, 0x10, 0xd7, 0x03, 0x99, 0x40, 0x04, 0xeb, 0x99, 0xfb, 0x0f, 0xd8, 0xe5, 0xe4, 0xf9, 
 | 
			
		||||
        0xfa, 0x22, 0x78, 0x18, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xec, 0x33, 0xfc, 
 | 
			
		||||
        0xc9, 0x33, 0xc9, 0x10, 0xd7, 0x05, 0x9b, 0xe9, 0x9a, 0x40, 0x07, 0xec, 0x9b, 0xfc, 0xe9, 0x9a, 
 | 
			
		||||
        0xf9, 0x0f, 0xd8, 0xe0, 0xe4, 0xc9, 0xfa, 0xe4, 0xcc, 0xfb, 0x22, 0x75, 0xf0, 0x10, 0xef, 0x2f, 
 | 
			
		||||
        0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xcc, 0x33, 0xcc, 0xc8, 0x33, 0xc8, 0x10, 0xd7, 0x07, 
 | 
			
		||||
        0x9b, 0xec, 0x9a, 0xe8, 0x99, 0x40, 0x0a, 0xed, 0x9b, 0xfd, 0xec, 0x9a, 0xfc, 0xe8, 0x99, 0xf8, 
 | 
			
		||||
        0x0f, 0xd5, 0xf0, 0xda, 0xe4, 0xcd, 0xfb, 0xe4, 0xcc, 0xfa, 0xe4, 0xc8, 0xf9, 0x22, 0xeb, 0x9f, 
 | 
			
		||||
        0xf5, 0xf0, 0xea, 0x9e, 0x42, 0xf0, 0xe9, 0x9d, 0x42, 0xf0, 0xe8, 0x9c, 0x45, 0xf0, 0x22, 0xe8, 
 | 
			
		||||
        0x60, 0x0f, 0xef, 0xc3, 0x33, 0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xec, 0x33, 0xfc, 0xd8, 
 | 
			
		||||
        0xf1, 0x22, 0xe4, 0x93, 0xfc, 0x74, 0x01, 0x93, 0xfd, 0x74, 0x02, 0x93, 0xfe, 0x74, 0x03, 0x93, 
 | 
			
		||||
        0xff, 0x22, 0xe6, 0xfb, 0x08, 0xe6, 0xf9, 0x08, 0xe6, 0xfa, 0x08, 0xe6, 0xcb, 0xf8, 0x22, 0xec, 
 | 
			
		||||
        0xf6, 0x08, 0xed, 0xf6, 0x08, 0xee, 0xf6, 0x08, 0xef, 0xf6, 0x22, 0xa4, 0x25, 0x82, 0xf5, 0x82, 
 | 
			
		||||
        0xe5, 0xf0, 0x35, 0x83, 0xf5, 0x83, 0x22, 0xd0, 0x83, 0xd0, 0x82, 0xf8, 0xe4, 0x93, 0x70, 0x12, 
 | 
			
		||||
        0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3, 0x93, 0xf8, 0x74, 0x01, 0x93, 0xf5, 0x82, 0x88, 0x83, 
 | 
			
		||||
        0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, 0xef, 0xa3, 0xa3, 0xa3, 0x80, 0xdf, 0x90, 0x38, 0x04, 
 | 
			
		||||
        0x78, 0x50, 0x12, 0x0c, 0x7f, 0x90, 0x38, 0x00, 0xe0, 0xfe, 0xa3, 0xe0, 0xfd, 0xed, 0xff, 0xc3, 
 | 
			
		||||
        0x12, 0x0c, 0x38, 0x90, 0x38, 0x10, 0x12, 0x0c, 0x2c, 0x90, 0x38, 0x06, 0x78, 0x52, 0x12, 0x0c, 
 | 
			
		||||
        0x7f, 0x90, 0x38, 0x02, 0xe0, 0xfe, 0xa3, 0xe0, 0xfd, 0xed, 0xff, 0xc3, 0x12, 0x0c, 0x38, 0x90, 
 | 
			
		||||
        0x38, 0x12, 0x12, 0x0c, 0x2c, 0xa3, 0xe0, 0xb4, 0x31, 0x07, 0x78, 0x50, 0x79, 0x50, 0x12, 0x0c, 
 | 
			
		||||
        0x95, 0x90, 0x38, 0x14, 0xe0, 0xb4, 0x71, 0x15, 0x78, 0x50, 0xe6, 0xfe, 0x08, 0xe6, 0x78, 0x02, 
 | 
			
		||||
        0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0x79, 0x51, 0xf7, 0xee, 0x19, 0xf7, 0x90, 0x38, 0x15, 
 | 
			
		||||
        0xe0, 0xb4, 0x31, 0x07, 0x78, 0x52, 0x79, 0x52, 0x12, 0x0c, 0x95, 0x90, 0x38, 0x15, 0xe0, 0xb4, 
 | 
			
		||||
        0x71, 0x15, 0x78, 0x52, 0xe6, 0xfe, 0x08, 0xe6, 0x78, 0x02, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 
 | 
			
		||||
        0xf9, 0x79, 0x53, 0xf7, 0xee, 0x19, 0xf7, 0x79, 0x50, 0x12, 0x0c, 0x67, 0x09, 0x12, 0x0c, 0x67, 
 | 
			
		||||
        0xaf, 0x45, 0x12, 0x0c, 0x1d, 0x7d, 0x50, 0x12, 0x05, 0x9c, 0x78, 0x58, 0xa6, 0x06, 0x08, 0xa6, 
 | 
			
		||||
        0x07, 0xaf, 0x43, 0x12, 0x0c, 0x1d, 0x7d, 0x50, 0x12, 0x05, 0x9c, 0x78, 0x54, 0xa6, 0x06, 0x08, 
 | 
			
		||||
        0xa6, 0x07, 0xaf, 0x46, 0x78, 0x52, 0x12, 0x0c, 0x1f, 0x7d, 0x3c, 0x12, 0x05, 0x9c, 0x78, 0x5a, 
 | 
			
		||||
        0xa6, 0x06, 0x08, 0xa6, 0x07, 0xaf, 0x44, 0x7e, 0x00, 0x78, 0x52, 0x12, 0x0c, 0x21, 0x7d, 0x3c, 
 | 
			
		||||
        0x12, 0x05, 0x9c, 0x78, 0x56, 0xa6, 0x06, 0x08, 0xa6, 0x07, 0xc3, 0x78, 0x59, 0xe6, 0x94, 0x08, 
 | 
			
		||||
        0x18, 0xe6, 0x94, 0x00, 0x50, 0x05, 0x76, 0x00, 0x08, 0x76, 0x08, 0xc3, 0x78, 0x5b, 0xe6, 0x94, 
 | 
			
		||||
        0x08, 0x18, 0xe6, 0x94, 0x00, 0x50, 0x05, 0x76, 0x00, 0x08, 0x76, 0x08, 0x78, 0x58, 0x12, 0x0c, 
 | 
			
		||||
        0x54, 0xff, 0xd3, 0x78, 0x55, 0xe6, 0x9f, 0x18, 0xe6, 0x9e, 0x40, 0x0e, 0x78, 0x58, 0xe6, 0x13, 
 | 
			
		||||
        0xfe, 0x08, 0xe6, 0x78, 0x55, 0x12, 0x0c, 0x8a, 0x80, 0x04, 0x7e, 0x00, 0x7f, 0x00, 0x78, 0x5c, 
 | 
			
		||||
        0x12, 0x0c, 0x4c, 0xff, 0xd3, 0x78, 0x57, 0xe6, 0x9f, 0x18, 0xe6, 0x9e, 0x40, 0x0e, 0x78, 0x5a, 
 | 
			
		||||
        0xe6, 0x13, 0xfe, 0x08, 0xe6, 0x78, 0x57, 0x12, 0x0c, 0x8a, 0x80, 0x04, 0x7e, 0x00, 0x7f, 0x00, 
 | 
			
		||||
        0xe4, 0xfc, 0xfd, 0x78, 0x60, 0x12, 0x07, 0x4f, 0x78, 0x58, 0x12, 0x0c, 0x54, 0x78, 0x55, 0x26, 
 | 
			
		||||
        0xff, 0xee, 0x18, 0x36, 0xfe, 0x78, 0x64, 0x12, 0x0c, 0x4c, 0x78, 0x57, 0x26, 0xff, 0xee, 0x18, 
 | 
			
		||||
        0x36, 0xfe, 0xe4, 0xfc, 0xfd, 0x78, 0x68, 0x12, 0x07, 0x4f, 0x12, 0x0c, 0x5c, 0x78, 0x64, 0x12, 
 | 
			
		||||
        0x07, 0x42, 0xd3, 0x12, 0x07, 0x0e, 0x40, 0x08, 0x12, 0x0c, 0x5c, 0x78, 0x64, 0x12, 0x07, 0x4f, 
 | 
			
		||||
        0x78, 0x52, 0x12, 0x0c, 0x5e, 0x78, 0x68, 0x12, 0x07, 0x42, 0xd3, 0x12, 0x07, 0x0e, 0x40, 0x0a, 
 | 
			
		||||
        0x78, 0x52, 0x12, 0x0c, 0x5e, 0x78, 0x68, 0x12, 0x07, 0x4f, 0xe4, 0xfd, 0x78, 0x5f, 0x12, 0x0c, 
 | 
			
		||||
        0x77, 0x24, 0x01, 0x12, 0x0c, 0x40, 0x78, 0x63, 0x12, 0x0c, 0x77, 0x24, 0x02, 0x12, 0x0c, 0x40, 
 | 
			
		||||
        0x78, 0x67, 0x12, 0x0c, 0x77, 0x24, 0x03, 0x12, 0x0c, 0x40, 0x78, 0x6b, 0x12, 0x0c, 0x77, 0x24, 
 | 
			
		||||
        0x04, 0x12, 0x0c, 0x40, 0x0d, 0xbd, 0x05, 0xd4, 0xc2, 0x0e, 0xc2, 0x06, 0x22, 0x85, 0x08, 0x41, 
 | 
			
		||||
        0x90, 0x30, 0x24, 0xe0, 0xf5, 0x3d, 0xa3, 0xe0, 0xf5, 0x3e, 0xa3, 0xe0, 0xf5, 0x3f, 0xa3, 0xe0, 
 | 
			
		||||
        0xf5, 0x40, 0xa3, 0xe0, 0xf5, 0x3c, 0xd2, 0x33, 0xe5, 0x41, 0x12, 0x07, 0x67, 0x09, 0xb4, 0x03, 
 | 
			
		||||
        0x09, 0xb8, 0x04, 0x09, 0xbe, 0x05, 0x09, 0xc1, 0x06, 0x09, 0xc4, 0x07, 0x09, 0xcd, 0x08, 0x09, 
 | 
			
		||||
        0xde, 0x12, 0x09, 0xe0, 0x80, 0x09, 0xe5, 0x81, 0x0a, 0x43, 0x8f, 0x0a, 0x32, 0x90, 0x0a, 0x43, 
 | 
			
		||||
        0x91, 0x0a, 0x43, 0x92, 0x0a, 0x43, 0x93, 0x0a, 0x43, 0x94, 0x0a, 0x43, 0x98, 0x0a, 0x40, 0x9f, 
 | 
			
		||||
        0x00, 0x00, 0x0a, 0x5e, 0x12, 0x0e, 0xce, 0x22, 0x12, 0x0e, 0xce, 0xd2, 0x03, 0x22, 0xd2, 0x03, 
 | 
			
		||||
        0x22, 0xc2, 0x03, 0x22, 0xa2, 0x36, 0xe4, 0x33, 0xf5, 0x3c, 0x02, 0x0a, 0x43, 0xc2, 0x01, 0xc2, 
 | 
			
		||||
        0x02, 0xc2, 0x03, 0x12, 0x0d, 0x14, 0x75, 0x1e, 0x70, 0xd2, 0x34, 0x02, 0x0a, 0x43, 0x80, 0x4d, 
 | 
			
		||||
        0x12, 0x0f, 0x17, 0x80, 0x5e, 0x85, 0x3d, 0x43, 0x85, 0x3e, 0x44, 0xe5, 0x45, 0xc3, 0x13, 0xff, 
 | 
			
		||||
        0xe5, 0x43, 0xc3, 0x9f, 0x50, 0x02, 0x8f, 0x43, 0xe5, 0x46, 0xc3, 0x13, 0xff, 0xe5, 0x44, 0xc3, 
 | 
			
		||||
        0x9f, 0x50, 0x02, 0x8f, 0x44, 0xe5, 0x45, 0xc3, 0x13, 0xff, 0xfd, 0xe5, 0x43, 0x90, 0x0e, 0x7f, 
 | 
			
		||||
        0x12, 0x0e, 0xea, 0x40, 0x04, 0xee, 0x9f, 0xf5, 0x43, 0xe5, 0x46, 0xc3, 0x13, 0xff, 0xfd, 0xe5, 
 | 
			
		||||
        0x44, 0x90, 0x0e, 0x80, 0x12, 0x0e, 0xea, 0x40, 0x04, 0xee, 0x9f, 0xf5, 0x44, 0x12, 0x07, 0x8d, 
 | 
			
		||||
        0x80, 0x11, 0x85, 0x40, 0x46, 0x85, 0x3f, 0x45, 0x85, 0x3e, 0x44, 0x85, 0x3d, 0x43, 0x80, 0x03, 
 | 
			
		||||
        0x02, 0x07, 0x8d, 0x90, 0x30, 0x24, 0xe5, 0x3d, 0xf0, 0xa3, 0xe5, 0x3e, 0xf0, 0xa3, 0xe5, 0x3f, 
 | 
			
		||||
        0xf0, 0xa3, 0xe5, 0x40, 0xf0, 0xa3, 0xe5, 0x3c, 0xf0, 0x90, 0x30, 0x23, 0xe4, 0xf0, 0x22, 0xc0, 
 | 
			
		||||
        0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x90, 0x3f, 0x0c, 0xe0, 0xf5, 0x32, 0xe5, 0x32, 0x30, 
 | 
			
		||||
        0xe3, 0x4c, 0x30, 0x35, 0x3e, 0x90, 0x60, 0x19, 0xe0, 0xf5, 0x0a, 0xa3, 0xe0, 0xf5, 0x0b, 0x90, 
 | 
			
		||||
        0x60, 0x1d, 0xe0, 0xf5, 0x14, 0xa3, 0xe0, 0xf5, 0x15, 0x30, 0x01, 0x06, 0x30, 0x32, 0x03, 0xd3, 
 | 
			
		||||
        0x80, 0x01, 0xc3, 0x92, 0x09, 0x30, 0x02, 0x06, 0x30, 0x32, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 
 | 
			
		||||
        0x0a, 0x30, 0x32, 0x0c, 0x30, 0x03, 0x09, 0x20, 0x02, 0x06, 0x20, 0x01, 0x03, 0xd3, 0x80, 0x01, 
 | 
			
		||||
        0xc3, 0x92, 0x0b, 0x90, 0x30, 0x01, 0xe0, 0x44, 0x40, 0xf0, 0xe0, 0x54, 0xbf, 0xf0, 0xe5, 0x32, 
 | 
			
		||||
        0x30, 0xe1, 0x14, 0x30, 0x33, 0x11, 0x90, 0x30, 0x22, 0xe0, 0xf5, 0x08, 0xe4, 0xf0, 0x30, 0x00, 
 | 
			
		||||
        0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x08, 0xe5, 0x32, 0x30, 0xe5, 0x12, 0x90, 0x56, 0xa1, 0xe0, 
 | 
			
		||||
        0xf5, 0x09, 0x30, 0x30, 0x09, 0x30, 0x05, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x0d, 0x90, 0x3f, 
 | 
			
		||||
        0x0c, 0xe5, 0x32, 0xf0, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0x90, 0x0e, 0x7d, 
 | 
			
		||||
        0xe4, 0x93, 0xfe, 0x74, 0x01, 0x93, 0xff, 0xc3, 0x90, 0x0e, 0x7b, 0x74, 0x01, 0x93, 0x9f, 0xff, 
 | 
			
		||||
        0xe4, 0x93, 0x9e, 0xfe, 0xe4, 0x8f, 0x3b, 0x8e, 0x3a, 0xf5, 0x39, 0xf5, 0x38, 0xab, 0x3b, 0xaa, 
 | 
			
		||||
        0x3a, 0xa9, 0x39, 0xa8, 0x38, 0xaf, 0x49, 0xfc, 0xfd, 0xfe, 0x12, 0x05, 0xf1, 0x12, 0x0e, 0xfc, 
 | 
			
		||||
        0xe4, 0x7b, 0xff, 0xfa, 0xf9, 0xf8, 0x12, 0x06, 0x7c, 0x12, 0x0e, 0xfc, 0x90, 0x0e, 0x69, 0xe4, 
 | 
			
		||||
        0x12, 0x0f, 0x11, 0x12, 0x0e, 0xfc, 0xe4, 0x85, 0x48, 0x37, 0xf5, 0x36, 0xf5, 0x35, 0xf5, 0x34, 
 | 
			
		||||
        0xaf, 0x37, 0xae, 0x36, 0xad, 0x35, 0xac, 0x34, 0xa3, 0x12, 0x0f, 0x11, 0x8f, 0x37, 0x8e, 0x36, 
 | 
			
		||||
        0x8d, 0x35, 0x8c, 0x34, 0xe5, 0x3b, 0x45, 0x37, 0xf5, 0x3b, 0xe5, 0x3a, 0x45, 0x36, 0xf5, 0x3a, 
 | 
			
		||||
        0xe5, 0x39, 0x45, 0x35, 0xf5, 0x39, 0xe5, 0x38, 0x45, 0x34, 0xf5, 0x38, 0xe4, 0xf5, 0x22, 0xf5, 
 | 
			
		||||
        0x23, 0x85, 0x3b, 0x31, 0x85, 0x3a, 0x30, 0x85, 0x39, 0x2f, 0x85, 0x38, 0x2e, 0x02, 0x0d, 0xc5, 
 | 
			
		||||
        0xad, 0x39, 0xac, 0x38, 0xfa, 0xf9, 0xf8, 0x12, 0x05, 0xf1, 0x8f, 0x3b, 0x8e, 0x3a, 0x8d, 0x39, 
 | 
			
		||||
        0x8c, 0x38, 0xab, 0x37, 0xaa, 0x36, 0xa9, 0x35, 0xa8, 0x34, 0x22, 0xef, 0x25, 0xe0, 0x24, 0x4c, 
 | 
			
		||||
        0xf8, 0xe6, 0xfc, 0x08, 0xe6, 0xfd, 0x22, 0x93, 0xff, 0xe4, 0xfc, 0xfd, 0xfe, 0x12, 0x05, 0xf1, 
 | 
			
		||||
        0x8f, 0x37, 0x8e, 0x36, 0x8d, 0x35, 0x8c, 0x34, 0x22, 0xf9, 0xc3, 0xe6, 0x97, 0x18, 0xe6, 0x19, 
 | 
			
		||||
        0x97, 0x22, 0xff, 0xa6, 0x06, 0x08, 0xa6, 0x07, 0x22, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0xe4, 0x8f, 
 | 
			
		||||
        0x37, 0x8e, 0x36, 0xf5, 0x35, 0xf5, 0x34, 0x22, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0xe4, 0x8f, 0x3b, 
 | 
			
		||||
        0x8e, 0x3a, 0xf5, 0x39, 0xf5, 0x38, 0x22, 0xe7, 0x96, 0xff, 0x19, 0xe7, 0x18, 0x96, 0x22, 0xff, 
 | 
			
		||||
        0xa6, 0x06, 0x08, 0xa6, 0x07, 0x78, 0x6c, 0xe6, 0xfe, 0x08, 0xe6, 0x22, 0x78, 0x4c, 0xe6, 0xfe, 
 | 
			
		||||
        0x08, 0xe6, 0x22, 0x78, 0xa7, 0xef, 0x26, 0xf6, 0x18, 0xe4, 0x36, 0xf6, 0x22, 0x78, 0x50, 0x7e, 
 | 
			
		||||
        0x00, 0xe6, 0xfc, 0x08, 0xe6, 0xfd, 0x12, 0x05, 0x8a, 0x7c, 0x00, 0x22, 0xe0, 0xa3, 0xe0, 0x75, 
 | 
			
		||||
        0xf0, 0x02, 0xa4, 0xff, 0xae, 0xf0, 0xc3, 0x08, 0xe6, 0x9f, 0xf6, 0x18, 0xe6, 0x9e, 0xf6, 0x22, 
 | 
			
		||||
        0xff, 0xe5, 0xf0, 0x34, 0x60, 0x8f, 0x82, 0xf5, 0x83, 0xec, 0xf0, 0x22, 0xe4, 0xfc, 0xfd, 0x12, 
 | 
			
		||||
        0x07, 0x4f, 0x78, 0x5a, 0xe6, 0xc3, 0x13, 0xfe, 0x08, 0xe6, 0x13, 0x22, 0x78, 0x50, 0xe6, 0xfe, 
 | 
			
		||||
        0x08, 0xe6, 0xff, 0xe4, 0xfc, 0xfd, 0x22, 0xe7, 0xc4, 0xf8, 0x54, 0xf0, 0xc8, 0x68, 0xf7, 0x09, 
 | 
			
		||||
        0xe7, 0xc4, 0x54, 0x0f, 0x48, 0xf7, 0x22, 0xe6, 0xfc, 0xed, 0x75, 0xf0, 0x04, 0xa4, 0x22, 0xe0, 
 | 
			
		||||
        0xfe, 0xa3, 0xe0, 0xfd, 0xee, 0xf6, 0xed, 0x08, 0xf6, 0x22, 0x13, 0xff, 0xc3, 0xe6, 0x9f, 0xff, 
 | 
			
		||||
        0x18, 0xe6, 0x9e, 0xfe, 0x22, 0xe6, 0xc3, 0x13, 0xf7, 0x08, 0xe6, 0x13, 0x09, 0xf7, 0x22, 0x75, 
 | 
			
		||||
        0x89, 0x03, 0x75, 0xa8, 0x01, 0x75, 0xb8, 0x04, 0x75, 0x34, 0xff, 0x75, 0x35, 0x0e, 0x75, 0x36, 
 | 
			
		||||
        0x15, 0x75, 0x37, 0x0d, 0x12, 0x0d, 0x85, 0x12, 0x00, 0x09, 0x12, 0x0f, 0x17, 0x12, 0x00, 0x06, 
 | 
			
		||||
        0xd2, 0x00, 0xd2, 0x33, 0xd2, 0xaf, 0x75, 0x34, 0xff, 0x75, 0x35, 0x0e, 0x75, 0x36, 0x49, 0x75, 
 | 
			
		||||
        0x37, 0x03, 0x12, 0x0d, 0x85, 0x30, 0x08, 0x09, 0xc2, 0x33, 0x12, 0x09, 0x5d, 0xc2, 0x08, 0xd2, 
 | 
			
		||||
        0x33, 0x30, 0x0b, 0x09, 0xc2, 0x35, 0x12, 0x00, 0x0e, 0xc2, 0x0b, 0xd2, 0x35, 0x30, 0x09, 0x09, 
 | 
			
		||||
        0xc2, 0x35, 0x12, 0x03, 0x0a, 0xc2, 0x09, 0xd2, 0x35, 0x30, 0x0e, 0x03, 0x12, 0x07, 0x8d, 0x30, 
 | 
			
		||||
        0x34, 0xd3, 0x90, 0x30, 0x29, 0xe5, 0x1e, 0xf0, 0xb4, 0x10, 0x05, 0x90, 0x30, 0x23, 0xe4, 0xf0, 
 | 
			
		||||
        0xc2, 0x34, 0x80, 0xc1, 0xe4, 0xf5, 0x49, 0x90, 0x0e, 0x77, 0x93, 0xff, 0xe4, 0x8f, 0x37, 0xf5, 
 | 
			
		||||
        0x36, 0xf5, 0x35, 0xf5, 0x34, 0xaf, 0x37, 0xae, 0x36, 0xad, 0x35, 0xac, 0x34, 0x90, 0x0e, 0x6a, 
 | 
			
		||||
        0x12, 0x0f, 0x11, 0x8f, 0x37, 0x8e, 0x36, 0x8d, 0x35, 0x8c, 0x34, 0x90, 0x0e, 0x72, 0x12, 0x07, 
 | 
			
		||||
        0x32, 0xef, 0x45, 0x37, 0xf5, 0x37, 0xee, 0x45, 0x36, 0xf5, 0x36, 0xed, 0x45, 0x35, 0xf5, 0x35, 
 | 
			
		||||
        0xec, 0x45, 0x34, 0xf5, 0x34, 0xe4, 0xf5, 0x22, 0xf5, 0x23, 0x85, 0x37, 0x31, 0x85, 0x36, 0x30, 
 | 
			
		||||
        0x85, 0x35, 0x2f, 0x85, 0x34, 0x2e, 0x12, 0x0d, 0xc5, 0xe4, 0xf5, 0x22, 0xf5, 0x23, 0x90, 0x0e, 
 | 
			
		||||
        0x72, 0x12, 0x0f, 0x05, 0x12, 0x0d, 0xc5, 0xe4, 0xf5, 0x22, 0xf5, 0x23, 0x90, 0x0e, 0x6e, 0x12, 
 | 
			
		||||
        0x0f, 0x05, 0x02, 0x0d, 0xc5, 0xae, 0x35, 0xaf, 0x36, 0xe4, 0xfd, 0xed, 0xc3, 0x95, 0x37, 0x50, 
 | 
			
		||||
        0x33, 0x12, 0x0f, 0x52, 0xe4, 0x93, 0xf5, 0x38, 0x74, 0x01, 0x93, 0xf5, 0x39, 0x45, 0x38, 0x60, 
 | 
			
		||||
        0x23, 0x85, 0x39, 0x82, 0x85, 0x38, 0x83, 0xe0, 0xfc, 0x12, 0x0f, 0x52, 0x74, 0x03, 0x93, 0x52, 
 | 
			
		||||
        0x04, 0x12, 0x0f, 0x52, 0x74, 0x02, 0x93, 0x42, 0x04, 0x85, 0x39, 0x82, 0x85, 0x38, 0x83, 0xec, 
 | 
			
		||||
        0xf0, 0x0d, 0x80, 0xc7, 0x22, 0xa2, 0xaf, 0x92, 0x31, 0xc2, 0xaf, 0xe5, 0x23, 0x45, 0x22, 0x90, 
 | 
			
		||||
        0x0e, 0x5d, 0x60, 0x0b, 0x12, 0x0f, 0x47, 0xe0, 0xf5, 0x2c, 0xe0, 0xf5, 0x2d, 0x80, 0x0f, 0x12, 
 | 
			
		||||
        0x0f, 0x47, 0xe5, 0x30, 0xf0, 0x90, 0x0e, 0x5f, 0x12, 0x0f, 0x47, 0xe5, 0x31, 0xf0, 0xa2, 0x31, 
 | 
			
		||||
        0x92, 0xaf, 0x22, 0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0xcb, 0x02, 0x0c, 0x9f, 0x00, 
 | 
			
		||||
        0x11, 0x05, 0x25, 0x16, 0x33, 0x02, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x74, 0x20, 0x20, 0x14, 0x00, 
 | 
			
		||||
        0x10, 0x00, 0x56, 0x40, 0x1a, 0x30, 0x29, 0x7e, 0x00, 0x30, 0x04, 0x20, 0xdf, 0x30, 0x05, 0x40, 
 | 
			
		||||
        0xbf, 0x50, 0x03, 0x00, 0xfd, 0x50, 0x27, 0x01, 0xfe, 0x60, 0x00, 0x11, 0x00, 0x3f, 0x05, 0x30, 
 | 
			
		||||
        0x00, 0x3f, 0x06, 0x22, 0x00, 0x3f, 0x01, 0x2a, 0x00, 0x3f, 0x02, 0x00, 0x00, 0x36, 0x06, 0x07, 
 | 
			
		||||
        0x00, 0x3f, 0x0b, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x30, 0x01, 0x40, 0xbf, 0x30, 0x01, 0x00, 
 | 
			
		||||
        0xbf, 0x30, 0x29, 0x70, 0x00, 0x3a, 0x00, 0x00, 0xff, 0x3a, 0x00, 0x00, 0xff, 0x36, 0x03, 0x36, 
 | 
			
		||||
        0x02, 0x41, 0x44, 0x58, 0x20, 0x18, 0x10, 0x0a, 0x04, 0x04, 0x00, 0x03, 0xff, 0x64, 0x00, 0x00, 
 | 
			
		||||
        0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x06, 0x00, 0x03, 0x98, 0x00, 0xcc, 0x50, 
 | 
			
		||||
        0x3c, 0x28, 0x1e, 0x0c, 0x0c, 0x00, 0x00, 0x10, 0x0c, 0x10, 0x04, 0x0c, 0x6e, 0x06, 0x05, 0x00, 
 | 
			
		||||
        0xa5, 0x5a, 0x78, 0xbc, 0xe6, 0xd3, 0x08, 0xff, 0xe6, 0x64, 0x80, 0xf8, 0xef, 0x64, 0x80, 0x98, 
 | 
			
		||||
        0x22, 0x93, 0xff, 0x7e, 0x00, 0xe6, 0xfc, 0x08, 0xe6, 0xfd, 0x12, 0x05, 0x8a, 0x78, 0xbf, 0xe6, 
 | 
			
		||||
        0xfc, 0x08, 0xe6, 0xfd, 0xd3, 0xef, 0x9d, 0xee, 0x9c, 0x22, 0x78, 0xbb, 0xd3, 0xe6, 0x64, 0x80, 
 | 
			
		||||
        0x94, 0x80, 0x22, 0x25, 0xe0, 0x24, 0x0a, 0xf8, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x22, 0xd2, 0x01, 
 | 
			
		||||
        0xc2, 0x02, 0xe4, 0xf5, 0x1f, 0xf5, 0x1e, 0xd2, 0x34, 0xd2, 0x32, 0xd2, 0x35, 0xd2, 0x01, 0xc2, 
 | 
			
		||||
        0x02, 0xf5, 0x1f, 0xf5, 0x1e, 0xd2, 0x34, 0xd2, 0x32, 0x22, 0x2d, 0xfd, 0xe4, 0x33, 0xfc, 0xe4, 
 | 
			
		||||
        0x93, 0xfe, 0xfb, 0xd3, 0xed, 0x9b, 0x74, 0x80, 0xf8, 0x6c, 0x98, 0x22, 0x8f, 0x3b, 0x8e, 0x3a, 
 | 
			
		||||
        0x8d, 0x39, 0x8c, 0x38, 0x22, 0x12, 0x07, 0x32, 0x8f, 0x31, 0x8e, 0x30, 0x8d, 0x2f, 0x8c, 0x2e, 
 | 
			
		||||
        0x22, 0x93, 0xf9, 0xf8, 0x02, 0x07, 0x1f, 0x90, 0x0e, 0x81, 0x12, 0x07, 0x32, 0x8f, 0x46, 0x8e, 
 | 
			
		||||
        0x45, 0x8d, 0x44, 0x8c, 0x43, 0xd2, 0x06, 0x30, 0x06, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x0e, 
 | 
			
		||||
        0x22, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x90, 0x3f, 0x0d, 0xe0, 0xf5, 0x33, 0xe5, 0x33, 0xf0, 
 | 
			
		||||
        0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0xe4, 0x93, 0xfe, 0x74, 0x01, 0x93, 0xf5, 0x82, 0x8e, 
 | 
			
		||||
        0x03, 0x02, 0x03, 0x09, 0x30, 0x02, 0x03, 0x02, 0x03, 0x09, 0x90, 0x51, 0xa5, 0xe0, 0x78, 0xbb,
 | 
			
		||||
        0xf6, 0xa3, 0xe0, 0x08, 0xf6, 0xa3, 0xe0, 0x08, 0xf6, 0xe5, 0x1f, 0x70, 0x45, 0x75, 0x1e, 0x20,
 | 
			
		||||
        0xd2, 0x34, 0x12, 0x0c, 0x0c, 0x78, 0x9c, 0x12, 0x0b, 0xd2, 0x78, 0xa8, 0xa6, 0x14, 0x08, 0xa6,
 | 
			
		||||
        0x15, 0x78, 0xb3, 0xa6, 0x09, 0x18, 0x76, 0x01, 0x78, 0x4c, 0xa6, 0x0a, 0x08, 0xa6, 0x0b, 0x78,
 | 
			
		||||
        0x6c, 0xa6, 0x14, 0x08, 0xa6, 0x15, 0x78, 0xb3, 0xe6, 0x78, 0x8c, 0xf6, 0x75, 0x1f, 0x01, 0x78,
 | 
			
		||||
        0xbb, 0xe6, 0x78, 0xb8, 0xf6, 0x78, 0xbc, 0xe6, 0x78, 0xb9, 0xf6, 0x78, 0xbd, 0xe6, 0x78, 0xba,
 | 
			
		||||
        0xf6, 0x22, 0x79, 0xb8, 0xe7, 0xd3, 0x78, 0xbb, 0x96, 0x40, 0x05, 0xe7, 0x96, 0xff, 0x80, 0x08,
 | 
			
		||||
        0xc3, 0x79, 0xbb, 0xe7, 0x78, 0xb8, 0x96, 0xff, 0x78, 0xa6, 0x76, 0x00, 0x08, 0xa6, 0x07, 0x79,
 | 
			
		||||
        0xb9, 0xe7, 0xd3, 0x78, 0xbc, 0x96, 0x40, 0x05, 0xe7, 0x96, 0xff, 0x80, 0x08, 0xc3, 0x79, 0xbc,
 | 
			
		||||
        0xe7, 0x78, 0xb9, 0x96, 0xff, 0x12, 0x0c, 0x13, 0x79, 0xba, 0xe7, 0xd3, 0x78, 0xbd, 0x96, 0x40,
 | 
			
		||||
        0x05, 0xe7, 0x96, 0xff, 0x80, 0x08, 0xc3, 0x79, 0xbd, 0xe7, 0x78, 0xba, 0x96, 0xff, 0x12, 0x0c,
 | 
			
		||||
        0x13, 0x78, 0xb2, 0xe6, 0x25, 0xe0, 0x24, 0x4c, 0xf8, 0xa6, 0x0a, 0x08, 0xa6, 0x0b, 0x78, 0xb2,
 | 
			
		||||
        0xe6, 0x25, 0xe0, 0x24, 0x6c, 0xf8, 0xa6, 0x14, 0x08, 0xa6, 0x15, 0x78, 0xb2, 0xe6, 0x24, 0x8c,
 | 
			
		||||
        0xf8, 0xa6, 0x09, 0x78, 0xb2, 0xe6, 0x24, 0x01, 0xff, 0xe4, 0x33, 0xfe, 0xd3, 0xef, 0x94, 0x0f,
 | 
			
		||||
        0xee, 0x64, 0x80, 0x94, 0x80, 0x40, 0x04, 0x7f, 0x00, 0x80, 0x05, 0x78, 0xb2, 0xe6, 0x04, 0xff,
 | 
			
		||||
        0x78, 0xb2, 0xa6, 0x07, 0xe5, 0x1f, 0xb4, 0x01, 0x0a, 0xe6, 0x60, 0x03, 0x02, 0x03, 0x09, 0x75,
 | 
			
		||||
        0x1f, 0x02, 0x22, 0x12, 0x0c, 0x0c, 0x78, 0x9e, 0x12, 0x0b, 0xd2, 0x12, 0x0c, 0x0c, 0x78, 0xa0,
 | 
			
		||||
        0x12, 0x0b, 0xff, 0x78, 0xaa, 0x12, 0x0b, 0xff, 0xff, 0x78, 0xac, 0xa6, 0x06, 0x08, 0xa6, 0x07,
 | 
			
		||||
        0x78, 0x8c, 0xe6, 0x78, 0xb4, 0xf6, 0x78, 0x8c, 0xe6, 0x78, 0xb5, 0xf6, 0x7f, 0x01, 0xef, 0x25,
 | 
			
		||||
        0xe0, 0x24, 0x4d, 0x78, 0x9f, 0x12, 0x0b, 0xc9, 0x50, 0x0a, 0x12, 0x0b, 0xab, 0x78, 0x9e, 0xa6,
 | 
			
		||||
        0x04, 0x08, 0xa6, 0x05, 0xef, 0x25, 0xe0, 0x24, 0x6d, 0x78, 0xab, 0x12, 0x0b, 0xc9, 0x50, 0x0f,
 | 
			
		||||
        0xef, 0x25, 0xe0, 0x24, 0x6c, 0x12, 0x0b, 0xb0, 0x78, 0xaa, 0xa6, 0x04, 0x08, 0xa6, 0x05, 0x74,
 | 
			
		||||
        0x8c, 0x2f, 0xf9, 0x78, 0xb4, 0xe6, 0xc3, 0x97, 0x50, 0x08, 0x74, 0x8c, 0x2f, 0xf8, 0xe6, 0x78,
 | 
			
		||||
        0xb4, 0xf6, 0xef, 0x25, 0xe0, 0x24, 0x4d, 0xf9, 0xd3, 0x78, 0xa1, 0x12, 0x0b, 0xcb, 0x40, 0x0a,
 | 
			
		||||
        0x12, 0x0b, 0xab, 0x78, 0xa0, 0xa6, 0x04, 0x08, 0xa6, 0x05, 0xef, 0x25, 0xe0, 0x24, 0x6d, 0xf9,
 | 
			
		||||
        0xd3, 0x78, 0xad, 0x12, 0x0b, 0xcb, 0x40, 0x0f, 0xef, 0x25, 0xe0, 0x24, 0x6c, 0x12, 0x0b, 0xb0,
 | 
			
		||||
        0x78, 0xac, 0xa6, 0x04, 0x08, 0xa6, 0x05, 0x74, 0x8c, 0x2f, 0xf9, 0x78, 0xb5, 0xe6, 0xd3, 0x97,
 | 
			
		||||
        0x40, 0x08, 0x74, 0x8c, 0x2f, 0xf8, 0xe6, 0x78, 0xb5, 0xf6, 0x0f, 0xef, 0x64, 0x10, 0x60, 0x03,
 | 
			
		||||
        0x02, 0x01, 0x3e, 0xc3, 0x79, 0x9f, 0x78, 0xa1, 0x12, 0x0b, 0xf7, 0x78, 0xa2, 0xf6, 0x08, 0xa6,
 | 
			
		||||
        0x07, 0xc3, 0x79, 0xab, 0x78, 0xad, 0x12, 0x0b, 0xf7, 0x78, 0xae, 0xf6, 0x08, 0xa6, 0x07, 0xc3,
 | 
			
		||||
        0x79, 0xb4, 0xe7, 0x78, 0xb5, 0x96, 0x08, 0xf6, 0xd3, 0x79, 0x9f, 0xe7, 0x78, 0x9d, 0x96, 0x19,
 | 
			
		||||
        0xe7, 0x18, 0x96, 0x40, 0x05, 0x09, 0xe7, 0x08, 0x80, 0x06, 0xc3, 0x79, 0x9d, 0xe7, 0x78, 0x9f,
 | 
			
		||||
        0x12, 0x0b, 0xf8, 0xfe, 0x78, 0xa4, 0xa6, 0x06, 0x08, 0xa6, 0x07, 0xd3, 0x79, 0xab, 0xe7, 0x78,
 | 
			
		||||
        0xa9, 0x96, 0x19, 0xe7, 0x18, 0x96, 0x40, 0x05, 0x09, 0xe7, 0x08, 0x80, 0x06, 0xc3, 0x79, 0xa9,
 | 
			
		||||
        0xe7, 0x78, 0xab, 0x12, 0x0b, 0xf8, 0xfe, 0x78, 0xb0, 0xa6, 0x06, 0x08, 0xa6, 0x07, 0x79, 0xb4,
 | 
			
		||||
        0xe7, 0xd3, 0x78, 0xb3, 0x96, 0x40, 0x05, 0xe7, 0x96, 0xff, 0x80, 0x08, 0xc3, 0x79, 0xb3, 0xe7,
 | 
			
		||||
        0x78, 0xb4, 0x96, 0xff, 0x78, 0xb7, 0xa6, 0x07, 0xe5, 0x1f, 0x64, 0x02, 0x60, 0x03, 0x02, 0x02,
 | 
			
		||||
        0xef, 0x90, 0x30, 0x24, 0x74, 0x0f, 0xf0, 0x90, 0x0e, 0x8a, 0xe4, 0x93, 0xff, 0x18, 0xe6, 0xc3,
 | 
			
		||||
        0x9f, 0x40, 0x03, 0x02, 0x03, 0x09, 0x90, 0x30, 0x24, 0x74, 0x0e, 0xf0, 0x78, 0xa2, 0x12, 0x0b,
 | 
			
		||||
        0xd9, 0x12, 0x0b, 0xa2, 0x90, 0x0e, 0x87, 0x12, 0x0b, 0xb7, 0x78, 0x9e, 0x12, 0x0b, 0xe8, 0x7b,
 | 
			
		||||
        0x04, 0x12, 0x0b, 0x90, 0xc3, 0x12, 0x07, 0x0e, 0x50, 0x6f, 0x90, 0x0e, 0x8b, 0xe4, 0x93, 0xff,
 | 
			
		||||
        0x78, 0xb7, 0xe6, 0x9f, 0x40, 0x07, 0x90, 0x30, 0x24, 0x74, 0x0a, 0x80, 0x16, 0x90, 0x0e, 0x89,
 | 
			
		||||
        0xe4, 0x93, 0xff, 0xd3, 0x78, 0xa7, 0xe6, 0x9f, 0x18, 0xe6, 0x94, 0x00, 0x40, 0x09, 0x90, 0x30,
 | 
			
		||||
        0x24, 0x74, 0x0b, 0xf0, 0x75, 0x1f, 0x05, 0x78, 0xae, 0x12, 0x0b, 0xd9, 0x12, 0x0b, 0xa2, 0x90,
 | 
			
		||||
        0x0e, 0x88, 0x12, 0x0b, 0xb7, 0x78, 0xa8, 0x12, 0x0b, 0xe8, 0x7b, 0x40, 0x12, 0x0b, 0x90, 0xd3,
 | 
			
		||||
        0x12, 0x07, 0x0e, 0x40, 0x24, 0x90, 0x30, 0x24, 0x74, 0x0c, 0xf0, 0x75, 0x1f, 0x05, 0x22, 0x90,
 | 
			
		||||
        0x30, 0x24, 0x74, 0x01, 0xf0, 0xe5, 0x1f, 0xb4, 0x05, 0x0f, 0xd2, 0x01, 0xc2, 0x02, 0xe4, 0xf5,
 | 
			
		||||
        0x1f, 0xf5, 0x1e, 0xd2, 0x34, 0xd2, 0x32, 0xd2, 0x35, 0x22, 0xe5, 0x1f, 0x60, 0x03, 0x02, 0x03,
 | 
			
		||||
        0x93, 0xf5, 0x1e, 0xd2, 0x34, 0x75, 0x34, 0xff, 0x75, 0x35, 0x0e, 0x75, 0x36, 0x55, 0x75, 0x37,
 | 
			
		||||
        0x01, 0x12, 0x0d, 0x85, 0xe4, 0xff, 0xef, 0x25, 0xe0, 0x24, 0x4c, 0xf8, 0xe4, 0xf6, 0x08, 0xf6,
 | 
			
		||||
        0x0f, 0xbf, 0x34, 0xf2, 0x90, 0x0e, 0x8c, 0xe4, 0x93, 0xff, 0xe5, 0x49, 0xc3, 0x9f, 0x50, 0x04,
 | 
			
		||||
        0x7f, 0x05, 0x80, 0x02, 0x7f, 0xfb, 0x78, 0xbb, 0xa6, 0x07, 0x12, 0x0e, 0xbc, 0x40, 0x04, 0x7f,
 | 
			
		||||
        0x03, 0x80, 0x02, 0x7f, 0x30, 0x78, 0xba, 0xa6, 0x07, 0xe6, 0x18, 0xf6, 0x08, 0xe6, 0x78, 0xb7,
 | 
			
		||||
        0xf6, 0x78, 0xba, 0xe6, 0x78, 0xb8, 0xf6, 0x78, 0xbd, 0x76, 0x33, 0xe4, 0x08, 0xf6, 0x78, 0xb6,
 | 
			
		||||
        0x76, 0x01, 0x75, 0x48, 0x02, 0x78, 0xb4, 0xf6, 0x08, 0xf6, 0x74, 0xff, 0x78, 0xbf, 0xf6, 0x08,
 | 
			
		||||
        0xf6, 0x75, 0x1f, 0x01, 0x78, 0xba, 0xe6, 0x75, 0xf0, 0x05, 0xa4, 0xf5, 0x49, 0x12, 0x0a, 0xfd,
 | 
			
		||||
        0xc2, 0x36, 0x22, 0x78, 0xb6, 0xe6, 0xd3, 0x94, 0x00, 0x40, 0x02, 0x16, 0x22, 0xe5, 0x1f, 0xb4,
 | 
			
		||||
        0x05, 0x23, 0xe4, 0xf5, 0x1f, 0xc2, 0x01, 0x78, 0xb4, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x78, 0x4c,
 | 
			
		||||
        0xa6, 0x06, 0x08, 0xa6, 0x07, 0xa2, 0x36, 0xe4, 0x33, 0xf5, 0x3c, 0x90, 0x30, 0x28, 0xf0, 0x75,
 | 
			
		||||
        0x1e, 0x10, 0xd2, 0x34, 0x22, 0xe5, 0x49, 0x75, 0xf0, 0x05, 0x84, 0x78, 0xba, 0xf6, 0x90, 0x0e,
 | 
			
		||||
        0x85, 0xe4, 0x93, 0xff, 0x25, 0xe0, 0x24, 0x0a, 0xf8, 0xe6, 0xfc, 0x08, 0xe6, 0xfd, 0x78, 0xba,
 | 
			
		||||
        0xe6, 0x25, 0xe0, 0x24, 0x4c, 0xf8, 0xa6, 0x04, 0x08, 0xa6, 0x05, 0xef, 0x12, 0x0e, 0xc3, 0xd3,
 | 
			
		||||
        0x78, 0xb5, 0x96, 0xee, 0x18, 0x96, 0x40, 0x0d, 0x78, 0xba, 0xe6, 0x78, 0xb7, 0xf6, 0x78, 0xb4,
 | 
			
		||||
        0xa6, 0x06, 0x08, 0xa6, 0x07, 0x90, 0x0e, 0x85, 0xe4, 0x93, 0x12, 0x0e, 0xc3, 0xc3, 0x78, 0xc0,
 | 
			
		||||
        0x96, 0xee, 0x18, 0x96, 0x50, 0x0d, 0x78, 0xba, 0xe6, 0x78, 0xb8, 0xf6, 0x78, 0xbf, 0xa6, 0x06,
 | 
			
		||||
        0x08, 0xa6, 0x07, 0x78, 0xb4, 0xe6, 0xfe, 0x08, 0xe6, 0xc3, 0x78, 0xc0, 0x96, 0xff, 0xee, 0x18,
 | 
			
		||||
        0x96, 0x78, 0xc1, 0xf6, 0x08, 0xa6, 0x07, 0x90, 0x0e, 0x8e, 0xe4, 0x18, 0x12, 0x0e, 0xa1, 0x40,
 | 
			
		||||
        0x02, 0xd2, 0x36, 0x78, 0xba, 0xe6, 0x08, 0x26, 0x08, 0xf6, 0xe5, 0x1f, 0x64, 0x01, 0x70, 0x4a,
 | 
			
		||||
        0xe6, 0xc3, 0x78, 0xbe, 0x12, 0x0e, 0x97, 0x40, 0x05, 0x12, 0x0e, 0x92, 0x40, 0x39, 0x12, 0x0e,
 | 
			
		||||
        0xba, 0x40, 0x04, 0x7f, 0xfe, 0x80, 0x02, 0x7f, 0x02, 0x78, 0xbb, 0xa6, 0x07, 0x78, 0xb7, 0xe6,
 | 
			
		||||
        0x24, 0x03, 0x78, 0xbd, 0xf6, 0x78, 0xb7, 0xe6, 0x24, 0xfd, 0x78, 0xbe, 0xf6, 0x12, 0x0e, 0xba,
 | 
			
		||||
        0x40, 0x06, 0x78, 0xbe, 0xe6, 0xff, 0x80, 0x04, 0x78, 0xbd, 0xe6, 0xff, 0x78, 0xbc, 0xa6, 0x07,
 | 
			
		||||
        0x75, 0x1f, 0x02, 0x78, 0xb6, 0x76, 0x01, 0x02, 0x05, 0x59, 0xe5, 0x1f, 0x64, 0x02, 0x60, 0x03,
 | 
			
		||||
        0x02, 0x05, 0x39, 0x78, 0xbc, 0xe6, 0xff, 0xc3, 0x78, 0xbe, 0x12, 0x0e, 0x98, 0x40, 0x08, 0x12,
 | 
			
		||||
        0x0e, 0x92, 0x50, 0x03, 0x02, 0x05, 0x37, 0x12, 0x0e, 0xba, 0x40, 0x04, 0x7f, 0xff, 0x80, 0x02,
 | 
			
		||||
        0x7f, 0x01, 0x78, 0xbb, 0xa6, 0x07, 0x78, 0xb7, 0xe6, 0x04, 0x78, 0xbd, 0xf6, 0x78, 0xb7, 0xe6,
 | 
			
		||||
        0x14, 0x78, 0xbe, 0xf6, 0x18, 0x12, 0x0e, 0xbc, 0x40, 0x04, 0xe6, 0xff, 0x80, 0x02, 0x7f, 0x00,
 | 
			
		||||
        0x78, 0xbd, 0xa6, 0x07, 0xd3, 0x08, 0xe6, 0x64, 0x80, 0x94, 0x80, 0x40, 0x04, 0xe6, 0xff, 0x80,
 | 
			
		||||
        0x02, 0x7f, 0x00, 0x78, 0xbe, 0xa6, 0x07, 0xc3, 0x18, 0xe6, 0x64, 0x80, 0x94, 0xb3, 0x50, 0x04,
 | 
			
		||||
        0xe6, 0xff, 0x80, 0x02, 0x7f, 0x33, 0x78, 0xbd, 0xa6, 0x07, 0xc3, 0x08, 0xe6, 0x64, 0x80, 0x94,
 | 
			
		||||
        0xb3, 0x50, 0x04, 0xe6, 0xff, 0x80, 0x02, 0x7f, 0x33, 0x78, 0xbe, 0xa6, 0x07, 0x12, 0x0e, 0xba,
 | 
			
		||||
        0x40, 0x06, 0x78, 0xbe, 0xe6, 0xff, 0x80, 0x04, 0x78, 0xbd, 0xe6, 0xff, 0x78, 0xbc, 0xa6, 0x07,
 | 
			
		||||
        0x75, 0x1f, 0x03, 0x78, 0xb6, 0x76, 0x01, 0x80, 0x20, 0xe5, 0x1f, 0x64, 0x03, 0x70, 0x26, 0x78,
 | 
			
		||||
        0xbc, 0xe6, 0xff, 0xc3, 0x78, 0xbe, 0x12, 0x0e, 0x98, 0x40, 0x05, 0x12, 0x0e, 0x92, 0x40, 0x09,
 | 
			
		||||
        0x78, 0xb7, 0xe6, 0x78, 0xbc, 0xf6, 0x75, 0x1f, 0x04, 0x78, 0xbc, 0xe6, 0x75, 0xf0, 0x05, 0xa4,
 | 
			
		||||
        0xf5, 0x49, 0x02, 0x0a, 0xfd, 0xe5, 0x1f, 0xb4, 0x04, 0x1f, 0x90, 0x0e, 0x8d, 0xe4, 0x78, 0xc1,
 | 
			
		||||
        0x12, 0x0e, 0xa1, 0x40, 0x02, 0xd2, 0x36, 0x75, 0x1f, 0x05, 0x75, 0x34, 0xff, 0x75, 0x35, 0x0e,
 | 
			
		||||
        0x75, 0x36, 0x59, 0x75, 0x37, 0x01, 0x12, 0x0d, 0x85, 0x22, 0xef, 0x8d, 0xf0, 0xa4, 0xa8, 0xf0,
 | 
			
		||||
        0xcf, 0x8c, 0xf0, 0xa4, 0x28, 0xce, 0x8d, 0xf0, 0xa4, 0x2e, 0xfe, 0x22, 0xbc, 0x00, 0x0b, 0xbe,
 | 
			
		||||
        0x00, 0x29, 0xef, 0x8d, 0xf0, 0x84, 0xff, 0xad, 0xf0, 0x22, 0xe4, 0xcc, 0xf8, 0x75, 0xf0, 0x08,
 | 
			
		||||
        0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xec, 0x33, 0xfc, 0xee, 0x9d, 0xec, 0x98, 0x40, 0x05, 0xfc,
 | 
			
		||||
        0xee, 0x9d, 0xfe, 0x0f, 0xd5, 0xf0, 0xe9, 0xe4, 0xce, 0xfd, 0x22, 0xed, 0xf8, 0xf5, 0xf0, 0xee,
 | 
			
		||||
        0x84, 0x20, 0xd2, 0x1c, 0xfe, 0xad, 0xf0, 0x75, 0xf0, 0x08, 0xef, 0x2f, 0xff, 0xed, 0x33, 0xfd,
 | 
			
		||||
        0x40, 0x07, 0x98, 0x50, 0x06, 0xd5, 0xf0, 0xf2, 0x22, 0xc3, 0x98, 0xfd, 0x0f, 0xd5, 0xf0, 0xea,
 | 
			
		||||
        0x22, 0xe8, 0x8f, 0xf0, 0xa4, 0xcc, 0x8b, 0xf0, 0xa4, 0x2c, 0xfc, 0xe9, 0x8e, 0xf0, 0xa4, 0x2c,
 | 
			
		||||
        0xfc, 0x8a, 0xf0, 0xed, 0xa4, 0x2c, 0xfc, 0xea, 0x8e, 0xf0, 0xa4, 0xcd, 0xa8, 0xf0, 0x8b, 0xf0,
 | 
			
		||||
        0xa4, 0x2d, 0xcc, 0x38, 0x25, 0xf0, 0xfd, 0xe9, 0x8f, 0xf0, 0xa4, 0x2c, 0xcd, 0x35, 0xf0, 0xfc,
 | 
			
		||||
        0xeb, 0x8e, 0xf0, 0xa4, 0xfe, 0xa9, 0xf0, 0xeb, 0x8f, 0xf0, 0xa4, 0xcf, 0xc5, 0xf0, 0x2e, 0xcd,
 | 
			
		||||
        0x39, 0xfe, 0xe4, 0x3c, 0xfc, 0xea, 0xa4, 0x2d, 0xce, 0x35, 0xf0, 0xfd, 0xe4, 0x3c, 0xfc, 0x22,
 | 
			
		||||
        0x75, 0xf0, 0x08, 0x75, 0x82, 0x00, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xcd, 0x33, 0xcd, 0xcc,
 | 
			
		||||
        0x33, 0xcc, 0xc5, 0x82, 0x33, 0xc5, 0x82, 0x9b, 0xed, 0x9a, 0xec, 0x99, 0xe5, 0x82, 0x98, 0x40,
 | 
			
		||||
        0x0c, 0xf5, 0x82, 0xee, 0x9b, 0xfe, 0xed, 0x9a, 0xfd, 0xec, 0x99, 0xfc, 0x0f, 0xd5, 0xf0, 0xd6,
 | 
			
		||||
        0xe4, 0xce, 0xfb, 0xe4, 0xcd, 0xfa, 0xe4, 0xcc, 0xf9, 0xa8, 0x82, 0x22, 0xb8, 0x00, 0xc1, 0xb9,
 | 
			
		||||
        0x00, 0x59, 0xba, 0x00, 0x2d, 0xec, 0x8b, 0xf0, 0x84, 0xcf, 0xce, 0xcd, 0xfc, 0xe5, 0xf0, 0xcb,
 | 
			
		||||
        0xf9, 0x78, 0x18, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xec, 0x33, 0xfc, 0xeb,
 | 
			
		||||
        0x33, 0xfb, 0x10, 0xd7, 0x03, 0x99, 0x40, 0x04, 0xeb, 0x99, 0xfb, 0x0f, 0xd8, 0xe5, 0xe4, 0xf9,
 | 
			
		||||
        0xfa, 0x22, 0x78, 0x18, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xec, 0x33, 0xfc,
 | 
			
		||||
        0xc9, 0x33, 0xc9, 0x10, 0xd7, 0x05, 0x9b, 0xe9, 0x9a, 0x40, 0x07, 0xec, 0x9b, 0xfc, 0xe9, 0x9a,
 | 
			
		||||
        0xf9, 0x0f, 0xd8, 0xe0, 0xe4, 0xc9, 0xfa, 0xe4, 0xcc, 0xfb, 0x22, 0x75, 0xf0, 0x10, 0xef, 0x2f,
 | 
			
		||||
        0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xcc, 0x33, 0xcc, 0xc8, 0x33, 0xc8, 0x10, 0xd7, 0x07,
 | 
			
		||||
        0x9b, 0xec, 0x9a, 0xe8, 0x99, 0x40, 0x0a, 0xed, 0x9b, 0xfd, 0xec, 0x9a, 0xfc, 0xe8, 0x99, 0xf8,
 | 
			
		||||
        0x0f, 0xd5, 0xf0, 0xda, 0xe4, 0xcd, 0xfb, 0xe4, 0xcc, 0xfa, 0xe4, 0xc8, 0xf9, 0x22, 0xeb, 0x9f,
 | 
			
		||||
        0xf5, 0xf0, 0xea, 0x9e, 0x42, 0xf0, 0xe9, 0x9d, 0x42, 0xf0, 0xe8, 0x9c, 0x45, 0xf0, 0x22, 0xe8,
 | 
			
		||||
        0x60, 0x0f, 0xef, 0xc3, 0x33, 0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xec, 0x33, 0xfc, 0xd8,
 | 
			
		||||
        0xf1, 0x22, 0xe4, 0x93, 0xfc, 0x74, 0x01, 0x93, 0xfd, 0x74, 0x02, 0x93, 0xfe, 0x74, 0x03, 0x93,
 | 
			
		||||
        0xff, 0x22, 0xe6, 0xfb, 0x08, 0xe6, 0xf9, 0x08, 0xe6, 0xfa, 0x08, 0xe6, 0xcb, 0xf8, 0x22, 0xec,
 | 
			
		||||
        0xf6, 0x08, 0xed, 0xf6, 0x08, 0xee, 0xf6, 0x08, 0xef, 0xf6, 0x22, 0xa4, 0x25, 0x82, 0xf5, 0x82,
 | 
			
		||||
        0xe5, 0xf0, 0x35, 0x83, 0xf5, 0x83, 0x22, 0xd0, 0x83, 0xd0, 0x82, 0xf8, 0xe4, 0x93, 0x70, 0x12,
 | 
			
		||||
        0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3, 0x93, 0xf8, 0x74, 0x01, 0x93, 0xf5, 0x82, 0x88, 0x83,
 | 
			
		||||
        0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, 0xef, 0xa3, 0xa3, 0xa3, 0x80, 0xdf, 0x90, 0x38, 0x04,
 | 
			
		||||
        0x78, 0x50, 0x12, 0x0c, 0x7f, 0x90, 0x38, 0x00, 0xe0, 0xfe, 0xa3, 0xe0, 0xfd, 0xed, 0xff, 0xc3,
 | 
			
		||||
        0x12, 0x0c, 0x38, 0x90, 0x38, 0x10, 0x12, 0x0c, 0x2c, 0x90, 0x38, 0x06, 0x78, 0x52, 0x12, 0x0c,
 | 
			
		||||
        0x7f, 0x90, 0x38, 0x02, 0xe0, 0xfe, 0xa3, 0xe0, 0xfd, 0xed, 0xff, 0xc3, 0x12, 0x0c, 0x38, 0x90,
 | 
			
		||||
        0x38, 0x12, 0x12, 0x0c, 0x2c, 0xa3, 0xe0, 0xb4, 0x31, 0x07, 0x78, 0x50, 0x79, 0x50, 0x12, 0x0c,
 | 
			
		||||
        0x95, 0x90, 0x38, 0x14, 0xe0, 0xb4, 0x71, 0x15, 0x78, 0x50, 0xe6, 0xfe, 0x08, 0xe6, 0x78, 0x02,
 | 
			
		||||
        0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0x79, 0x51, 0xf7, 0xee, 0x19, 0xf7, 0x90, 0x38, 0x15,
 | 
			
		||||
        0xe0, 0xb4, 0x31, 0x07, 0x78, 0x52, 0x79, 0x52, 0x12, 0x0c, 0x95, 0x90, 0x38, 0x15, 0xe0, 0xb4,
 | 
			
		||||
        0x71, 0x15, 0x78, 0x52, 0xe6, 0xfe, 0x08, 0xe6, 0x78, 0x02, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8,
 | 
			
		||||
        0xf9, 0x79, 0x53, 0xf7, 0xee, 0x19, 0xf7, 0x79, 0x50, 0x12, 0x0c, 0x67, 0x09, 0x12, 0x0c, 0x67,
 | 
			
		||||
        0xaf, 0x45, 0x12, 0x0c, 0x1d, 0x7d, 0x50, 0x12, 0x05, 0x9c, 0x78, 0x58, 0xa6, 0x06, 0x08, 0xa6,
 | 
			
		||||
        0x07, 0xaf, 0x43, 0x12, 0x0c, 0x1d, 0x7d, 0x50, 0x12, 0x05, 0x9c, 0x78, 0x54, 0xa6, 0x06, 0x08,
 | 
			
		||||
        0xa6, 0x07, 0xaf, 0x46, 0x78, 0x52, 0x12, 0x0c, 0x1f, 0x7d, 0x3c, 0x12, 0x05, 0x9c, 0x78, 0x5a,
 | 
			
		||||
        0xa6, 0x06, 0x08, 0xa6, 0x07, 0xaf, 0x44, 0x7e, 0x00, 0x78, 0x52, 0x12, 0x0c, 0x21, 0x7d, 0x3c,
 | 
			
		||||
        0x12, 0x05, 0x9c, 0x78, 0x56, 0xa6, 0x06, 0x08, 0xa6, 0x07, 0xc3, 0x78, 0x59, 0xe6, 0x94, 0x08,
 | 
			
		||||
        0x18, 0xe6, 0x94, 0x00, 0x50, 0x05, 0x76, 0x00, 0x08, 0x76, 0x08, 0xc3, 0x78, 0x5b, 0xe6, 0x94,
 | 
			
		||||
        0x08, 0x18, 0xe6, 0x94, 0x00, 0x50, 0x05, 0x76, 0x00, 0x08, 0x76, 0x08, 0x78, 0x58, 0x12, 0x0c,
 | 
			
		||||
        0x54, 0xff, 0xd3, 0x78, 0x55, 0xe6, 0x9f, 0x18, 0xe6, 0x9e, 0x40, 0x0e, 0x78, 0x58, 0xe6, 0x13,
 | 
			
		||||
        0xfe, 0x08, 0xe6, 0x78, 0x55, 0x12, 0x0c, 0x8a, 0x80, 0x04, 0x7e, 0x00, 0x7f, 0x00, 0x78, 0x5c,
 | 
			
		||||
        0x12, 0x0c, 0x4c, 0xff, 0xd3, 0x78, 0x57, 0xe6, 0x9f, 0x18, 0xe6, 0x9e, 0x40, 0x0e, 0x78, 0x5a,
 | 
			
		||||
        0xe6, 0x13, 0xfe, 0x08, 0xe6, 0x78, 0x57, 0x12, 0x0c, 0x8a, 0x80, 0x04, 0x7e, 0x00, 0x7f, 0x00,
 | 
			
		||||
        0xe4, 0xfc, 0xfd, 0x78, 0x60, 0x12, 0x07, 0x4f, 0x78, 0x58, 0x12, 0x0c, 0x54, 0x78, 0x55, 0x26,
 | 
			
		||||
        0xff, 0xee, 0x18, 0x36, 0xfe, 0x78, 0x64, 0x12, 0x0c, 0x4c, 0x78, 0x57, 0x26, 0xff, 0xee, 0x18,
 | 
			
		||||
        0x36, 0xfe, 0xe4, 0xfc, 0xfd, 0x78, 0x68, 0x12, 0x07, 0x4f, 0x12, 0x0c, 0x5c, 0x78, 0x64, 0x12,
 | 
			
		||||
        0x07, 0x42, 0xd3, 0x12, 0x07, 0x0e, 0x40, 0x08, 0x12, 0x0c, 0x5c, 0x78, 0x64, 0x12, 0x07, 0x4f,
 | 
			
		||||
        0x78, 0x52, 0x12, 0x0c, 0x5e, 0x78, 0x68, 0x12, 0x07, 0x42, 0xd3, 0x12, 0x07, 0x0e, 0x40, 0x0a,
 | 
			
		||||
        0x78, 0x52, 0x12, 0x0c, 0x5e, 0x78, 0x68, 0x12, 0x07, 0x4f, 0xe4, 0xfd, 0x78, 0x5f, 0x12, 0x0c,
 | 
			
		||||
        0x77, 0x24, 0x01, 0x12, 0x0c, 0x40, 0x78, 0x63, 0x12, 0x0c, 0x77, 0x24, 0x02, 0x12, 0x0c, 0x40,
 | 
			
		||||
        0x78, 0x67, 0x12, 0x0c, 0x77, 0x24, 0x03, 0x12, 0x0c, 0x40, 0x78, 0x6b, 0x12, 0x0c, 0x77, 0x24,
 | 
			
		||||
        0x04, 0x12, 0x0c, 0x40, 0x0d, 0xbd, 0x05, 0xd4, 0xc2, 0x0e, 0xc2, 0x06, 0x22, 0x85, 0x08, 0x41,
 | 
			
		||||
        0x90, 0x30, 0x24, 0xe0, 0xf5, 0x3d, 0xa3, 0xe0, 0xf5, 0x3e, 0xa3, 0xe0, 0xf5, 0x3f, 0xa3, 0xe0,
 | 
			
		||||
        0xf5, 0x40, 0xa3, 0xe0, 0xf5, 0x3c, 0xd2, 0x33, 0xe5, 0x41, 0x12, 0x07, 0x67, 0x09, 0xb4, 0x03,
 | 
			
		||||
        0x09, 0xb8, 0x04, 0x09, 0xbe, 0x05, 0x09, 0xc1, 0x06, 0x09, 0xc4, 0x07, 0x09, 0xcd, 0x08, 0x09,
 | 
			
		||||
        0xde, 0x12, 0x09, 0xe0, 0x80, 0x09, 0xe5, 0x81, 0x0a, 0x43, 0x8f, 0x0a, 0x32, 0x90, 0x0a, 0x43,
 | 
			
		||||
        0x91, 0x0a, 0x43, 0x92, 0x0a, 0x43, 0x93, 0x0a, 0x43, 0x94, 0x0a, 0x43, 0x98, 0x0a, 0x40, 0x9f,
 | 
			
		||||
        0x00, 0x00, 0x0a, 0x5e, 0x12, 0x0e, 0xce, 0x22, 0x12, 0x0e, 0xce, 0xd2, 0x03, 0x22, 0xd2, 0x03,
 | 
			
		||||
        0x22, 0xc2, 0x03, 0x22, 0xa2, 0x36, 0xe4, 0x33, 0xf5, 0x3c, 0x02, 0x0a, 0x43, 0xc2, 0x01, 0xc2,
 | 
			
		||||
        0x02, 0xc2, 0x03, 0x12, 0x0d, 0x14, 0x75, 0x1e, 0x70, 0xd2, 0x34, 0x02, 0x0a, 0x43, 0x80, 0x4d,
 | 
			
		||||
        0x12, 0x0f, 0x17, 0x80, 0x5e, 0x85, 0x3d, 0x43, 0x85, 0x3e, 0x44, 0xe5, 0x45, 0xc3, 0x13, 0xff,
 | 
			
		||||
        0xe5, 0x43, 0xc3, 0x9f, 0x50, 0x02, 0x8f, 0x43, 0xe5, 0x46, 0xc3, 0x13, 0xff, 0xe5, 0x44, 0xc3,
 | 
			
		||||
        0x9f, 0x50, 0x02, 0x8f, 0x44, 0xe5, 0x45, 0xc3, 0x13, 0xff, 0xfd, 0xe5, 0x43, 0x90, 0x0e, 0x7f,
 | 
			
		||||
        0x12, 0x0e, 0xea, 0x40, 0x04, 0xee, 0x9f, 0xf5, 0x43, 0xe5, 0x46, 0xc3, 0x13, 0xff, 0xfd, 0xe5,
 | 
			
		||||
        0x44, 0x90, 0x0e, 0x80, 0x12, 0x0e, 0xea, 0x40, 0x04, 0xee, 0x9f, 0xf5, 0x44, 0x12, 0x07, 0x8d,
 | 
			
		||||
        0x80, 0x11, 0x85, 0x40, 0x46, 0x85, 0x3f, 0x45, 0x85, 0x3e, 0x44, 0x85, 0x3d, 0x43, 0x80, 0x03,
 | 
			
		||||
        0x02, 0x07, 0x8d, 0x90, 0x30, 0x24, 0xe5, 0x3d, 0xf0, 0xa3, 0xe5, 0x3e, 0xf0, 0xa3, 0xe5, 0x3f,
 | 
			
		||||
        0xf0, 0xa3, 0xe5, 0x40, 0xf0, 0xa3, 0xe5, 0x3c, 0xf0, 0x90, 0x30, 0x23, 0xe4, 0xf0, 0x22, 0xc0,
 | 
			
		||||
        0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x90, 0x3f, 0x0c, 0xe0, 0xf5, 0x32, 0xe5, 0x32, 0x30,
 | 
			
		||||
        0xe3, 0x4c, 0x30, 0x35, 0x3e, 0x90, 0x60, 0x19, 0xe0, 0xf5, 0x0a, 0xa3, 0xe0, 0xf5, 0x0b, 0x90,
 | 
			
		||||
        0x60, 0x1d, 0xe0, 0xf5, 0x14, 0xa3, 0xe0, 0xf5, 0x15, 0x30, 0x01, 0x06, 0x30, 0x32, 0x03, 0xd3,
 | 
			
		||||
        0x80, 0x01, 0xc3, 0x92, 0x09, 0x30, 0x02, 0x06, 0x30, 0x32, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92,
 | 
			
		||||
        0x0a, 0x30, 0x32, 0x0c, 0x30, 0x03, 0x09, 0x20, 0x02, 0x06, 0x20, 0x01, 0x03, 0xd3, 0x80, 0x01,
 | 
			
		||||
        0xc3, 0x92, 0x0b, 0x90, 0x30, 0x01, 0xe0, 0x44, 0x40, 0xf0, 0xe0, 0x54, 0xbf, 0xf0, 0xe5, 0x32,
 | 
			
		||||
        0x30, 0xe1, 0x14, 0x30, 0x33, 0x11, 0x90, 0x30, 0x22, 0xe0, 0xf5, 0x08, 0xe4, 0xf0, 0x30, 0x00,
 | 
			
		||||
        0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x08, 0xe5, 0x32, 0x30, 0xe5, 0x12, 0x90, 0x56, 0xa1, 0xe0,
 | 
			
		||||
        0xf5, 0x09, 0x30, 0x30, 0x09, 0x30, 0x05, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x0d, 0x90, 0x3f,
 | 
			
		||||
        0x0c, 0xe5, 0x32, 0xf0, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0x90, 0x0e, 0x7d,
 | 
			
		||||
        0xe4, 0x93, 0xfe, 0x74, 0x01, 0x93, 0xff, 0xc3, 0x90, 0x0e, 0x7b, 0x74, 0x01, 0x93, 0x9f, 0xff,
 | 
			
		||||
        0xe4, 0x93, 0x9e, 0xfe, 0xe4, 0x8f, 0x3b, 0x8e, 0x3a, 0xf5, 0x39, 0xf5, 0x38, 0xab, 0x3b, 0xaa,
 | 
			
		||||
        0x3a, 0xa9, 0x39, 0xa8, 0x38, 0xaf, 0x49, 0xfc, 0xfd, 0xfe, 0x12, 0x05, 0xf1, 0x12, 0x0e, 0xfc,
 | 
			
		||||
        0xe4, 0x7b, 0xff, 0xfa, 0xf9, 0xf8, 0x12, 0x06, 0x7c, 0x12, 0x0e, 0xfc, 0x90, 0x0e, 0x69, 0xe4,
 | 
			
		||||
        0x12, 0x0f, 0x11, 0x12, 0x0e, 0xfc, 0xe4, 0x85, 0x48, 0x37, 0xf5, 0x36, 0xf5, 0x35, 0xf5, 0x34,
 | 
			
		||||
        0xaf, 0x37, 0xae, 0x36, 0xad, 0x35, 0xac, 0x34, 0xa3, 0x12, 0x0f, 0x11, 0x8f, 0x37, 0x8e, 0x36,
 | 
			
		||||
        0x8d, 0x35, 0x8c, 0x34, 0xe5, 0x3b, 0x45, 0x37, 0xf5, 0x3b, 0xe5, 0x3a, 0x45, 0x36, 0xf5, 0x3a,
 | 
			
		||||
        0xe5, 0x39, 0x45, 0x35, 0xf5, 0x39, 0xe5, 0x38, 0x45, 0x34, 0xf5, 0x38, 0xe4, 0xf5, 0x22, 0xf5,
 | 
			
		||||
        0x23, 0x85, 0x3b, 0x31, 0x85, 0x3a, 0x30, 0x85, 0x39, 0x2f, 0x85, 0x38, 0x2e, 0x02, 0x0d, 0xc5,
 | 
			
		||||
        0xad, 0x39, 0xac, 0x38, 0xfa, 0xf9, 0xf8, 0x12, 0x05, 0xf1, 0x8f, 0x3b, 0x8e, 0x3a, 0x8d, 0x39,
 | 
			
		||||
        0x8c, 0x38, 0xab, 0x37, 0xaa, 0x36, 0xa9, 0x35, 0xa8, 0x34, 0x22, 0xef, 0x25, 0xe0, 0x24, 0x4c,
 | 
			
		||||
        0xf8, 0xe6, 0xfc, 0x08, 0xe6, 0xfd, 0x22, 0x93, 0xff, 0xe4, 0xfc, 0xfd, 0xfe, 0x12, 0x05, 0xf1,
 | 
			
		||||
        0x8f, 0x37, 0x8e, 0x36, 0x8d, 0x35, 0x8c, 0x34, 0x22, 0xf9, 0xc3, 0xe6, 0x97, 0x18, 0xe6, 0x19,
 | 
			
		||||
        0x97, 0x22, 0xff, 0xa6, 0x06, 0x08, 0xa6, 0x07, 0x22, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0xe4, 0x8f,
 | 
			
		||||
        0x37, 0x8e, 0x36, 0xf5, 0x35, 0xf5, 0x34, 0x22, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0xe4, 0x8f, 0x3b,
 | 
			
		||||
        0x8e, 0x3a, 0xf5, 0x39, 0xf5, 0x38, 0x22, 0xe7, 0x96, 0xff, 0x19, 0xe7, 0x18, 0x96, 0x22, 0xff,
 | 
			
		||||
        0xa6, 0x06, 0x08, 0xa6, 0x07, 0x78, 0x6c, 0xe6, 0xfe, 0x08, 0xe6, 0x22, 0x78, 0x4c, 0xe6, 0xfe,
 | 
			
		||||
        0x08, 0xe6, 0x22, 0x78, 0xa7, 0xef, 0x26, 0xf6, 0x18, 0xe4, 0x36, 0xf6, 0x22, 0x78, 0x50, 0x7e,
 | 
			
		||||
        0x00, 0xe6, 0xfc, 0x08, 0xe6, 0xfd, 0x12, 0x05, 0x8a, 0x7c, 0x00, 0x22, 0xe0, 0xa3, 0xe0, 0x75,
 | 
			
		||||
        0xf0, 0x02, 0xa4, 0xff, 0xae, 0xf0, 0xc3, 0x08, 0xe6, 0x9f, 0xf6, 0x18, 0xe6, 0x9e, 0xf6, 0x22,
 | 
			
		||||
        0xff, 0xe5, 0xf0, 0x34, 0x60, 0x8f, 0x82, 0xf5, 0x83, 0xec, 0xf0, 0x22, 0xe4, 0xfc, 0xfd, 0x12,
 | 
			
		||||
        0x07, 0x4f, 0x78, 0x5a, 0xe6, 0xc3, 0x13, 0xfe, 0x08, 0xe6, 0x13, 0x22, 0x78, 0x50, 0xe6, 0xfe,
 | 
			
		||||
        0x08, 0xe6, 0xff, 0xe4, 0xfc, 0xfd, 0x22, 0xe7, 0xc4, 0xf8, 0x54, 0xf0, 0xc8, 0x68, 0xf7, 0x09,
 | 
			
		||||
        0xe7, 0xc4, 0x54, 0x0f, 0x48, 0xf7, 0x22, 0xe6, 0xfc, 0xed, 0x75, 0xf0, 0x04, 0xa4, 0x22, 0xe0,
 | 
			
		||||
        0xfe, 0xa3, 0xe0, 0xfd, 0xee, 0xf6, 0xed, 0x08, 0xf6, 0x22, 0x13, 0xff, 0xc3, 0xe6, 0x9f, 0xff,
 | 
			
		||||
        0x18, 0xe6, 0x9e, 0xfe, 0x22, 0xe6, 0xc3, 0x13, 0xf7, 0x08, 0xe6, 0x13, 0x09, 0xf7, 0x22, 0x75,
 | 
			
		||||
        0x89, 0x03, 0x75, 0xa8, 0x01, 0x75, 0xb8, 0x04, 0x75, 0x34, 0xff, 0x75, 0x35, 0x0e, 0x75, 0x36,
 | 
			
		||||
        0x15, 0x75, 0x37, 0x0d, 0x12, 0x0d, 0x85, 0x12, 0x00, 0x09, 0x12, 0x0f, 0x17, 0x12, 0x00, 0x06,
 | 
			
		||||
        0xd2, 0x00, 0xd2, 0x33, 0xd2, 0xaf, 0x75, 0x34, 0xff, 0x75, 0x35, 0x0e, 0x75, 0x36, 0x49, 0x75,
 | 
			
		||||
        0x37, 0x03, 0x12, 0x0d, 0x85, 0x30, 0x08, 0x09, 0xc2, 0x33, 0x12, 0x09, 0x5d, 0xc2, 0x08, 0xd2,
 | 
			
		||||
        0x33, 0x30, 0x0b, 0x09, 0xc2, 0x35, 0x12, 0x00, 0x0e, 0xc2, 0x0b, 0xd2, 0x35, 0x30, 0x09, 0x09,
 | 
			
		||||
        0xc2, 0x35, 0x12, 0x03, 0x0a, 0xc2, 0x09, 0xd2, 0x35, 0x30, 0x0e, 0x03, 0x12, 0x07, 0x8d, 0x30,
 | 
			
		||||
        0x34, 0xd3, 0x90, 0x30, 0x29, 0xe5, 0x1e, 0xf0, 0xb4, 0x10, 0x05, 0x90, 0x30, 0x23, 0xe4, 0xf0,
 | 
			
		||||
        0xc2, 0x34, 0x80, 0xc1, 0xe4, 0xf5, 0x49, 0x90, 0x0e, 0x77, 0x93, 0xff, 0xe4, 0x8f, 0x37, 0xf5,
 | 
			
		||||
        0x36, 0xf5, 0x35, 0xf5, 0x34, 0xaf, 0x37, 0xae, 0x36, 0xad, 0x35, 0xac, 0x34, 0x90, 0x0e, 0x6a,
 | 
			
		||||
        0x12, 0x0f, 0x11, 0x8f, 0x37, 0x8e, 0x36, 0x8d, 0x35, 0x8c, 0x34, 0x90, 0x0e, 0x72, 0x12, 0x07,
 | 
			
		||||
        0x32, 0xef, 0x45, 0x37, 0xf5, 0x37, 0xee, 0x45, 0x36, 0xf5, 0x36, 0xed, 0x45, 0x35, 0xf5, 0x35,
 | 
			
		||||
        0xec, 0x45, 0x34, 0xf5, 0x34, 0xe4, 0xf5, 0x22, 0xf5, 0x23, 0x85, 0x37, 0x31, 0x85, 0x36, 0x30,
 | 
			
		||||
        0x85, 0x35, 0x2f, 0x85, 0x34, 0x2e, 0x12, 0x0d, 0xc5, 0xe4, 0xf5, 0x22, 0xf5, 0x23, 0x90, 0x0e,
 | 
			
		||||
        0x72, 0x12, 0x0f, 0x05, 0x12, 0x0d, 0xc5, 0xe4, 0xf5, 0x22, 0xf5, 0x23, 0x90, 0x0e, 0x6e, 0x12,
 | 
			
		||||
        0x0f, 0x05, 0x02, 0x0d, 0xc5, 0xae, 0x35, 0xaf, 0x36, 0xe4, 0xfd, 0xed, 0xc3, 0x95, 0x37, 0x50,
 | 
			
		||||
        0x33, 0x12, 0x0f, 0x52, 0xe4, 0x93, 0xf5, 0x38, 0x74, 0x01, 0x93, 0xf5, 0x39, 0x45, 0x38, 0x60,
 | 
			
		||||
        0x23, 0x85, 0x39, 0x82, 0x85, 0x38, 0x83, 0xe0, 0xfc, 0x12, 0x0f, 0x52, 0x74, 0x03, 0x93, 0x52,
 | 
			
		||||
        0x04, 0x12, 0x0f, 0x52, 0x74, 0x02, 0x93, 0x42, 0x04, 0x85, 0x39, 0x82, 0x85, 0x38, 0x83, 0xec,
 | 
			
		||||
        0xf0, 0x0d, 0x80, 0xc7, 0x22, 0xa2, 0xaf, 0x92, 0x31, 0xc2, 0xaf, 0xe5, 0x23, 0x45, 0x22, 0x90,
 | 
			
		||||
        0x0e, 0x5d, 0x60, 0x0b, 0x12, 0x0f, 0x47, 0xe0, 0xf5, 0x2c, 0xe0, 0xf5, 0x2d, 0x80, 0x0f, 0x12,
 | 
			
		||||
        0x0f, 0x47, 0xe5, 0x30, 0xf0, 0x90, 0x0e, 0x5f, 0x12, 0x0f, 0x47, 0xe5, 0x31, 0xf0, 0xa2, 0x31,
 | 
			
		||||
        0x92, 0xaf, 0x22, 0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0xcb, 0x02, 0x0c, 0x9f, 0x00,
 | 
			
		||||
        0x11, 0x05, 0x25, 0x16, 0x33, 0x02, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x74, 0x20, 0x20, 0x14, 0x00,
 | 
			
		||||
        0x10, 0x00, 0x56, 0x40, 0x1a, 0x30, 0x29, 0x7e, 0x00, 0x30, 0x04, 0x20, 0xdf, 0x30, 0x05, 0x40,
 | 
			
		||||
        0xbf, 0x50, 0x03, 0x00, 0xfd, 0x50, 0x27, 0x01, 0xfe, 0x60, 0x00, 0x11, 0x00, 0x3f, 0x05, 0x30,
 | 
			
		||||
        0x00, 0x3f, 0x06, 0x22, 0x00, 0x3f, 0x01, 0x2a, 0x00, 0x3f, 0x02, 0x00, 0x00, 0x36, 0x06, 0x07,
 | 
			
		||||
        0x00, 0x3f, 0x0b, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x30, 0x01, 0x40, 0xbf, 0x30, 0x01, 0x00,
 | 
			
		||||
        0xbf, 0x30, 0x29, 0x70, 0x00, 0x3a, 0x00, 0x00, 0xff, 0x3a, 0x00, 0x00, 0xff, 0x36, 0x03, 0x36,
 | 
			
		||||
        0x02, 0x41, 0x44, 0x58, 0x20, 0x18, 0x10, 0x0a, 0x04, 0x04, 0x00, 0x03, 0xff, 0x64, 0x00, 0x00,
 | 
			
		||||
        0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x06, 0x00, 0x03, 0x98, 0x00, 0xcc, 0x50,
 | 
			
		||||
        0x3c, 0x28, 0x1e, 0x0c, 0x0c, 0x00, 0x00, 0x10, 0x0c, 0x10, 0x04, 0x0c, 0x6e, 0x06, 0x05, 0x00,
 | 
			
		||||
        0xa5, 0x5a, 0x78, 0xbc, 0xe6, 0xd3, 0x08, 0xff, 0xe6, 0x64, 0x80, 0xf8, 0xef, 0x64, 0x80, 0x98,
 | 
			
		||||
        0x22, 0x93, 0xff, 0x7e, 0x00, 0xe6, 0xfc, 0x08, 0xe6, 0xfd, 0x12, 0x05, 0x8a, 0x78, 0xbf, 0xe6,
 | 
			
		||||
        0xfc, 0x08, 0xe6, 0xfd, 0xd3, 0xef, 0x9d, 0xee, 0x9c, 0x22, 0x78, 0xbb, 0xd3, 0xe6, 0x64, 0x80,
 | 
			
		||||
        0x94, 0x80, 0x22, 0x25, 0xe0, 0x24, 0x0a, 0xf8, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x22, 0xd2, 0x01,
 | 
			
		||||
        0xc2, 0x02, 0xe4, 0xf5, 0x1f, 0xf5, 0x1e, 0xd2, 0x34, 0xd2, 0x32, 0xd2, 0x35, 0xd2, 0x01, 0xc2,
 | 
			
		||||
        0x02, 0xf5, 0x1f, 0xf5, 0x1e, 0xd2, 0x34, 0xd2, 0x32, 0x22, 0x2d, 0xfd, 0xe4, 0x33, 0xfc, 0xe4,
 | 
			
		||||
        0x93, 0xfe, 0xfb, 0xd3, 0xed, 0x9b, 0x74, 0x80, 0xf8, 0x6c, 0x98, 0x22, 0x8f, 0x3b, 0x8e, 0x3a,
 | 
			
		||||
        0x8d, 0x39, 0x8c, 0x38, 0x22, 0x12, 0x07, 0x32, 0x8f, 0x31, 0x8e, 0x30, 0x8d, 0x2f, 0x8c, 0x2e,
 | 
			
		||||
        0x22, 0x93, 0xf9, 0xf8, 0x02, 0x07, 0x1f, 0x90, 0x0e, 0x81, 0x12, 0x07, 0x32, 0x8f, 0x46, 0x8e,
 | 
			
		||||
        0x45, 0x8d, 0x44, 0x8c, 0x43, 0xd2, 0x06, 0x30, 0x06, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x0e,
 | 
			
		||||
        0x22, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x90, 0x3f, 0x0d, 0xe0, 0xf5, 0x33, 0xe5, 0x33, 0xf0,
 | 
			
		||||
        0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0xe4, 0x93, 0xfe, 0x74, 0x01, 0x93, 0xf5, 0x82, 0x8e,
 | 
			
		||||
        0x83, 0x22, 0x8f, 0x82, 0x8e, 0x83, 0x75, 0xf0, 0x04, 0xed, 0x02, 0x07, 0x5b
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
@@ -1227,7 +1259,7 @@ class Camera
 | 
			
		||||
            UInt16 addr = (UInt16)(firmwareAddr + i);
 | 
			
		||||
            firmwareCommands.Add([addr, OV5640_AF_FIRMWARE[i]]);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        var result = await ConfigureRegisters(firmwareCommands.ToArray());
 | 
			
		||||
        if (!result.IsSuccessful)
 | 
			
		||||
        {
 | 
			
		||||
@@ -1306,15 +1338,15 @@ class Camera
 | 
			
		||||
                logger.Error($"读取对焦状态寄存器(0x3029)失败: {readResult.Error}");
 | 
			
		||||
                return new(readResult.Error);
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            focusStatus = readResult.Value;
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            if (focusStatus == 0x10)
 | 
			
		||||
            {
 | 
			
		||||
                logger.Info("对焦已完成 (0x3029 = 0x10)");
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            if (iteration-- == 0)
 | 
			
		||||
            {
 | 
			
		||||
                logger.Error($"自动对焦超时,状态: 0x{focusStatus:X2}");
 | 
			
		||||
 
 | 
			
		||||
@@ -108,7 +108,7 @@ public class DDS
 | 
			
		||||
        if (waveNum < 0 || waveNum > 3) return new(new ArgumentException(
 | 
			
		||||
            $"Wave number should be 0 ~ 3 instead of {waveNum}", nameof(waveNum)));
 | 
			
		||||
 | 
			
		||||
        await MsgBus.UDPServer.ClearUDPData(this.address, 1);
 | 
			
		||||
        MsgBus.UDPServer.ClearUDPData(this.address, 1);
 | 
			
		||||
        logger.Trace("Clear udp data finished");
 | 
			
		||||
 | 
			
		||||
        var ret = await UDPClientPool.WriteAddr(
 | 
			
		||||
@@ -132,7 +132,7 @@ public class DDS
 | 
			
		||||
        if (waveNum < 0 || waveNum > 3) return new(new ArgumentException(
 | 
			
		||||
            $"Wave number should be 0 ~ 3 instead of {waveNum}", nameof(waveNum)));
 | 
			
		||||
 | 
			
		||||
        await MsgBus.UDPServer.ClearUDPData(this.address, 1);
 | 
			
		||||
        MsgBus.UDPServer.ClearUDPData(this.address, 1);
 | 
			
		||||
        logger.Trace("Clear udp data finished");
 | 
			
		||||
 | 
			
		||||
        var ret = await UDPClientPool.WriteAddr(
 | 
			
		||||
@@ -158,7 +158,7 @@ public class DDS
 | 
			
		||||
        if (phase < 0 || phase > 4096) return new(new ArgumentException(
 | 
			
		||||
            $"Phase should be 0 ~ 4096 instead of {phase}", nameof(phase)));
 | 
			
		||||
 | 
			
		||||
        await MsgBus.UDPServer.ClearUDPData(this.address, 1);
 | 
			
		||||
        MsgBus.UDPServer.ClearUDPData(this.address, 1);
 | 
			
		||||
        logger.Trace("Clear udp data finished");
 | 
			
		||||
 | 
			
		||||
        var ret = await UDPClientPool.WriteAddr(
 | 
			
		||||
 
 | 
			
		||||
@@ -82,7 +82,7 @@ public class I2c
 | 
			
		||||
    /// <param name="taskID">[TODO:parameter]</param>
 | 
			
		||||
    /// <param name="timeout">[TODO:parameter]</param>
 | 
			
		||||
    /// <returns>[TODO:return]</returns>
 | 
			
		||||
    public I2c(string address, int port, int taskID,int timeout = 2000)
 | 
			
		||||
    public I2c(string address, int port, int taskID, int timeout = 2000)
 | 
			
		||||
    {
 | 
			
		||||
        if (timeout < 0)
 | 
			
		||||
            throw new ArgumentException("Timeout couldn't be negative", nameof(timeout));
 | 
			
		||||
@@ -109,7 +109,7 @@ public class I2c
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 清除UDP服务器接收缓冲区
 | 
			
		||||
        await MsgBus.UDPServer.ClearUDPData(this.address, this.taskID);
 | 
			
		||||
        MsgBus.UDPServer.ClearUDPData(this.address, this.taskID);
 | 
			
		||||
 | 
			
		||||
        logger.Trace($"Clear up udp server {this.address} receive data");
 | 
			
		||||
 | 
			
		||||
@@ -214,7 +214,7 @@ public class I2c
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 清除UDP服务器接收缓冲区
 | 
			
		||||
        await MsgBus.UDPServer.ClearUDPData(this.address, this.taskID);
 | 
			
		||||
        MsgBus.UDPServer.ClearUDPData(this.address, this.taskID);
 | 
			
		||||
 | 
			
		||||
        logger.Trace($"Clear up udp server {this.address} receive data");
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -627,7 +627,7 @@ public class Jtag
 | 
			
		||||
    public async ValueTask<Result<uint>> ReadIDCode()
 | 
			
		||||
    {
 | 
			
		||||
        // Clear Data
 | 
			
		||||
        await MsgBus.UDPServer.ClearUDPData(this.address, 0);
 | 
			
		||||
        MsgBus.UDPServer.ClearUDPData(this.address, 0);
 | 
			
		||||
 | 
			
		||||
        logger.Trace($"Clear up udp server {this.address,0} receive data");
 | 
			
		||||
 | 
			
		||||
@@ -665,7 +665,7 @@ public class Jtag
 | 
			
		||||
    public async ValueTask<Result<uint>> ReadStatusReg()
 | 
			
		||||
    {
 | 
			
		||||
        // Clear Data
 | 
			
		||||
        await MsgBus.UDPServer.ClearUDPData(this.address, 0);
 | 
			
		||||
        MsgBus.UDPServer.ClearUDPData(this.address, 0);
 | 
			
		||||
 | 
			
		||||
        logger.Trace($"Clear up udp server {this.address,0} receive data");
 | 
			
		||||
 | 
			
		||||
@@ -702,7 +702,7 @@ public class Jtag
 | 
			
		||||
    public async ValueTask<Result<bool>> DownloadBitstream(byte[] bitstream)
 | 
			
		||||
    {
 | 
			
		||||
        // Clear Data
 | 
			
		||||
        await MsgBus.UDPServer.ClearUDPData(this.address, 0);
 | 
			
		||||
        MsgBus.UDPServer.ClearUDPData(this.address, 0);
 | 
			
		||||
 | 
			
		||||
        logger.Trace($"Clear up udp server {this.address,0} receive data");
 | 
			
		||||
 | 
			
		||||
@@ -786,7 +786,7 @@ public class Jtag
 | 
			
		||||
        logger.Debug($"Get boundar scan registers number: {portNum}");
 | 
			
		||||
 | 
			
		||||
        // Clear Data
 | 
			
		||||
        await MsgBus.UDPServer.ClearUDPData(this.address, 0);
 | 
			
		||||
        MsgBus.UDPServer.ClearUDPData(this.address, 0);
 | 
			
		||||
 | 
			
		||||
        logger.Trace($"Clear up udp server {this.address,0} receive data");
 | 
			
		||||
 | 
			
		||||
@@ -853,7 +853,7 @@ public class Jtag
 | 
			
		||||
    public async ValueTask<Result<bool>> SetSpeed(UInt32 speed)
 | 
			
		||||
    {
 | 
			
		||||
        // Clear Data
 | 
			
		||||
        await MsgBus.UDPServer.ClearUDPData(this.address, 0);
 | 
			
		||||
        MsgBus.UDPServer.ClearUDPData(this.address, 0);
 | 
			
		||||
 | 
			
		||||
        logger.Trace($"Clear up udp server {this.address,0} receive data");
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -44,7 +44,7 @@ public class MatrixKey
 | 
			
		||||
    public async ValueTask<Result<bool>> EnableControl()
 | 
			
		||||
    {
 | 
			
		||||
        if (MsgBus.IsRunning)
 | 
			
		||||
            await MsgBus.UDPServer.ClearUDPData(this.address, 1);
 | 
			
		||||
            MsgBus.UDPServer.ClearUDPData(this.address, 1);
 | 
			
		||||
        else return new(new Exception("Message Bus not work!"));
 | 
			
		||||
 | 
			
		||||
        var ret = await UDPClientPool.WriteAddr(this.ep, 1, MatrixKeyAddr.KEY_ENABLE, 1, this.timeout);
 | 
			
		||||
@@ -59,7 +59,7 @@ public class MatrixKey
 | 
			
		||||
    public async ValueTask<Result<bool>> DisableControl()
 | 
			
		||||
    {
 | 
			
		||||
        if (MsgBus.IsRunning)
 | 
			
		||||
            await MsgBus.UDPServer.ClearUDPData(this.address, 1);
 | 
			
		||||
            MsgBus.UDPServer.ClearUDPData(this.address, 1);
 | 
			
		||||
        else return new(new Exception("Message Bus not work!"));
 | 
			
		||||
 | 
			
		||||
        var ret = await UDPClientPool.WriteAddr(this.ep, 1, MatrixKeyAddr.KEY_ENABLE, 0, this.timeout);
 | 
			
		||||
@@ -75,7 +75,7 @@ public class MatrixKey
 | 
			
		||||
    public async ValueTask<Result<bool>> ControlKey(BitArray keyStates)
 | 
			
		||||
    {
 | 
			
		||||
        if (MsgBus.IsRunning)
 | 
			
		||||
            await MsgBus.UDPServer.ClearUDPData(this.address, 1);
 | 
			
		||||
            MsgBus.UDPServer.ClearUDPData(this.address, 1);
 | 
			
		||||
        else return new(new Exception("Message Bus not work!"));
 | 
			
		||||
 | 
			
		||||
        if (keyStates.Length != 16) return new(new ArgumentException(
 | 
			
		||||
 
 | 
			
		||||
@@ -45,7 +45,7 @@ public class Power
 | 
			
		||||
    public async ValueTask<Result<bool>> SetPowerOnOff(bool enable)
 | 
			
		||||
    {
 | 
			
		||||
        if (MsgBus.IsRunning)
 | 
			
		||||
            await MsgBus.UDPServer.ClearUDPData(this.address, 1);
 | 
			
		||||
            MsgBus.UDPServer.ClearUDPData(this.address, 1);
 | 
			
		||||
        else return new(new Exception("Message Bus not work!"));
 | 
			
		||||
 | 
			
		||||
        var ret = await UDPClientPool.WriteAddr(this.ep, 1, PowerAddr.PowerCtrl, Convert.ToUInt32(enable), this.timeout);
 | 
			
		||||
 
 | 
			
		||||
@@ -382,7 +382,7 @@ public class RemoteUpdater
 | 
			
		||||
    /// <returns>[TODO:return]</returns>
 | 
			
		||||
    public async ValueTask<Result<bool>> HotResetBitstream(int bitstreamNum)
 | 
			
		||||
    {
 | 
			
		||||
        await MsgBus.UDPServer.ClearUDPData(this.address, 0);
 | 
			
		||||
        MsgBus.UDPServer.ClearUDPData(this.address, 0);
 | 
			
		||||
        logger.Trace("Clear udp data finished");
 | 
			
		||||
 | 
			
		||||
        {
 | 
			
		||||
@@ -412,7 +412,7 @@ public class RemoteUpdater
 | 
			
		||||
        byte[]? bitstream2,
 | 
			
		||||
        byte[]? bitstream3)
 | 
			
		||||
    {
 | 
			
		||||
        await MsgBus.UDPServer.ClearUDPData(this.address, 0);
 | 
			
		||||
        MsgBus.UDPServer.ClearUDPData(this.address, 0);
 | 
			
		||||
        logger.Trace("Clear udp data finished");
 | 
			
		||||
 | 
			
		||||
        for (int bitstreamNum = 0; bitstreamNum < 4; bitstreamNum++)
 | 
			
		||||
@@ -463,7 +463,7 @@ public class RemoteUpdater
 | 
			
		||||
                $"The length of data should be divided by 4096, bug given {bytesData.Length}", nameof(bytesData)));
 | 
			
		||||
        var bitstreamBlockNum = bytesData.Length / (4 * 1024);
 | 
			
		||||
 | 
			
		||||
        await MsgBus.UDPServer.ClearUDPData(this.address, 0);
 | 
			
		||||
        MsgBus.UDPServer.ClearUDPData(this.address, 0);
 | 
			
		||||
        logger.Trace("Clear udp data finished");
 | 
			
		||||
 | 
			
		||||
        {
 | 
			
		||||
@@ -539,7 +539,7 @@ public class RemoteUpdater
 | 
			
		||||
    /// <returns>[TODO:return]</returns>
 | 
			
		||||
    public async ValueTask<Result<UInt32>> GetVersion()
 | 
			
		||||
    {
 | 
			
		||||
        await MsgBus.UDPServer.ClearUDPData(this.address, 0);
 | 
			
		||||
        MsgBus.UDPServer.ClearUDPData(this.address, 0);
 | 
			
		||||
        logger.Trace("Clear udp data finished");
 | 
			
		||||
 | 
			
		||||
        {
 | 
			
		||||
 
 | 
			
		||||
@@ -156,8 +156,7 @@ public class HttpVideoStreamService : BackgroundService
 | 
			
		||||
            throw new Exception("Please config camera first");
 | 
			
		||||
        }
 | 
			
		||||
        _cameraEnable = isEnabled;
 | 
			
		||||
        await _camera.EnableCamera(_cameraEnable);
 | 
			
		||||
        await _camera.SleepCameraHardware(!_cameraEnable);
 | 
			
		||||
        await _camera.EnableHardwareTrans(_cameraEnable);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
 
 | 
			
		||||
@@ -477,7 +477,7 @@ public class UDPClientPool
 | 
			
		||||
            int outstanding = sentCount - (found.HasValue ? found.Value : 0);
 | 
			
		||||
 | 
			
		||||
            // If outstanding >= 512 - batchSize, wait for some data to be received
 | 
			
		||||
            if (outstanding >= 512 - batchSize)
 | 
			
		||||
            if (outstanding >= 256 - batchSize)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
using System.Net;
 | 
			
		||||
using System.Net.Sockets;
 | 
			
		||||
using System.Runtime.CompilerServices;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using DotNext;
 | 
			
		||||
using DotNext.Threading;
 | 
			
		||||
using Newtonsoft.Json;
 | 
			
		||||
using WebProtocol;
 | 
			
		||||
 | 
			
		||||
@@ -72,12 +72,10 @@ public class UDPServer
 | 
			
		||||
{
 | 
			
		||||
    private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
 | 
			
		||||
 | 
			
		||||
    private Dictionary<string, Queue<UDPData>> udpData = new Dictionary<string, Queue<UDPData>>();
 | 
			
		||||
 | 
			
		||||
    private Semaphore taskPool = new Semaphore(3, 3);
 | 
			
		||||
    private ConcurrentDictionary<string, ConcurrentQueue<UDPData>> udpData = new ConcurrentDictionary<string, ConcurrentQueue<UDPData>>();
 | 
			
		||||
 | 
			
		||||
    private int listenPort;
 | 
			
		||||
    private UdpClient listener;
 | 
			
		||||
    private List<UdpClient> listeners = new List<UdpClient>();
 | 
			
		||||
    private IPEndPoint groupEP;
 | 
			
		||||
 | 
			
		||||
    private bool isRunning = false;
 | 
			
		||||
@@ -103,15 +101,19 @@ public class UDPServer
 | 
			
		||||
    /// Construct a udp server with fixed port
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="port"> Device UDP Port </param>
 | 
			
		||||
    /// <param name="num"> UDP Client Num </param>
 | 
			
		||||
    /// <returns> UDPServer class </returns>
 | 
			
		||||
    public UDPServer(int port)
 | 
			
		||||
    public UDPServer(int port, int num)
 | 
			
		||||
    {
 | 
			
		||||
        // Construction
 | 
			
		||||
        listenPort = port;
 | 
			
		||||
        this.listenPort = port;
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            listener = new UdpClient(listenPort);
 | 
			
		||||
            groupEP = new IPEndPoint(IPAddress.Any, listenPort);
 | 
			
		||||
            for (int i = 0; i < num; i++)
 | 
			
		||||
            {
 | 
			
		||||
                listeners.Add(new UdpClient(this.listenPort + i));
 | 
			
		||||
            }
 | 
			
		||||
            this.groupEP = new IPEndPoint(IPAddress.Any, listenPort);
 | 
			
		||||
        }
 | 
			
		||||
        catch (Exception e)
 | 
			
		||||
        {
 | 
			
		||||
@@ -145,25 +147,19 @@ public class UDPServer
 | 
			
		||||
    {
 | 
			
		||||
        UDPData? data = null;
 | 
			
		||||
 | 
			
		||||
        // logger.Debug($"Caller \"{callerName}|{callerLineNum}\": Try to find {ipAddr}-{taskID} UDP Data");
 | 
			
		||||
 | 
			
		||||
        var startTime = DateTime.Now;
 | 
			
		||||
        var isTimeout = false;
 | 
			
		||||
        var timeleft = TimeSpan.FromMilliseconds(timeout);
 | 
			
		||||
        while (!isTimeout)
 | 
			
		||||
        {
 | 
			
		||||
            var elapsed = DateTime.Now - startTime;
 | 
			
		||||
            isTimeout = elapsed >= TimeSpan.FromMilliseconds(timeout);
 | 
			
		||||
            if (isTimeout) break;
 | 
			
		||||
 | 
			
		||||
            timeleft = TimeSpan.FromMilliseconds(timeout) - elapsed;
 | 
			
		||||
            using (await udpData.AcquireWriteLockAsync(timeleft))
 | 
			
		||||
            lock (udpData)
 | 
			
		||||
            {
 | 
			
		||||
                if (udpData.ContainsKey($"{ipAddr}-{taskID}") &&
 | 
			
		||||
                    udpData.TryGetValue($"{ipAddr}-{taskID}", out var dataQueue) &&
 | 
			
		||||
                    dataQueue.Count > 0)
 | 
			
		||||
                if (udpData.TryGetValue($"{ipAddr}-{taskID}", out var dataQueue) &&
 | 
			
		||||
                    dataQueue.TryDequeue(out data))
 | 
			
		||||
                {
 | 
			
		||||
                    data = dataQueue.Dequeue();
 | 
			
		||||
                    // logger.Debug($"Find UDP Data: {data.ToString()}");
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
@@ -196,22 +192,22 @@ public class UDPServer
 | 
			
		||||
 | 
			
		||||
        var startTime = DateTime.Now;
 | 
			
		||||
        var isTimeout = false;
 | 
			
		||||
        var timeleft = TimeSpan.FromMilliseconds(timeout);
 | 
			
		||||
        while (!isTimeout)
 | 
			
		||||
        {
 | 
			
		||||
            var elapsed = DateTime.Now - startTime;
 | 
			
		||||
            isTimeout = elapsed >= TimeSpan.FromMilliseconds(timeout);
 | 
			
		||||
            if (isTimeout) break;
 | 
			
		||||
 | 
			
		||||
            timeleft = TimeSpan.FromMilliseconds(timeout) - elapsed;
 | 
			
		||||
            using (await udpData.AcquireWriteLockAsync(timeleft))
 | 
			
		||||
            lock (udpData)
 | 
			
		||||
            {
 | 
			
		||||
                if (udpData.ContainsKey($"{ipAddr}-{taskID}") &&
 | 
			
		||||
                    udpData.TryGetValue($"{ipAddr}-{taskID}", out var dataQueue) &&
 | 
			
		||||
                    dataQueue.Count > 0)
 | 
			
		||||
                if (udpData.TryGetValue($"{ipAddr}-{taskID}", out var dataQueue) &&
 | 
			
		||||
                    !dataQueue.IsEmpty)
 | 
			
		||||
                {
 | 
			
		||||
                    data = dataQueue.ToList();
 | 
			
		||||
                    dataQueue.Clear();
 | 
			
		||||
                    data = new List<UDPData>();
 | 
			
		||||
                    while (dataQueue.TryDequeue(out var item))
 | 
			
		||||
                    {
 | 
			
		||||
                        data.Add(item);
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@@ -241,24 +237,18 @@ public class UDPServer
 | 
			
		||||
 | 
			
		||||
        var startTime = DateTime.Now;
 | 
			
		||||
        var isTimeout = false;
 | 
			
		||||
        var timeleft = TimeSpan.FromMilliseconds(timeout);
 | 
			
		||||
        while (!isTimeout)
 | 
			
		||||
        {
 | 
			
		||||
            var elapsed = DateTime.Now - startTime;
 | 
			
		||||
            isTimeout = elapsed >= TimeSpan.FromMilliseconds(timeout);
 | 
			
		||||
            if (isTimeout) break;
 | 
			
		||||
 | 
			
		||||
            timeleft = TimeSpan.FromMilliseconds(timeout) - elapsed;
 | 
			
		||||
            using (await udpData.AcquireReadLockAsync(timeleft))
 | 
			
		||||
            if (udpData.TryGetValue($"{ipAddr}-{taskID}", out var dataQueue) &&
 | 
			
		||||
                !dataQueue.IsEmpty)
 | 
			
		||||
            {
 | 
			
		||||
                if (udpData.ContainsKey($"{ipAddr}-{taskID}") &&
 | 
			
		||||
                    udpData.TryGetValue($"{ipAddr}-{taskID}", out var dataQueue) &&
 | 
			
		||||
                    dataQueue.Count > 0)
 | 
			
		||||
                {
 | 
			
		||||
                    data = dataQueue.ToList();
 | 
			
		||||
                    // logger.Debug($"Find UDP Data Array: {JsonConvert.SerializeObject(data)}");
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                data = dataQueue.ToArray().ToList();
 | 
			
		||||
                // logger.Debug($"Find UDP Data Array: {JsonConvert.SerializeObject(data)}");
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -286,22 +276,16 @@ public class UDPServer
 | 
			
		||||
 | 
			
		||||
        var startTime = DateTime.Now;
 | 
			
		||||
        var isTimeout = false;
 | 
			
		||||
        var timeleft = TimeSpan.FromMilliseconds(timeout);
 | 
			
		||||
        while (!isTimeout)
 | 
			
		||||
        {
 | 
			
		||||
            var elapsed = DateTime.Now - startTime;
 | 
			
		||||
            isTimeout = elapsed >= TimeSpan.FromMilliseconds(timeout);
 | 
			
		||||
            if (isTimeout) break;
 | 
			
		||||
 | 
			
		||||
            timeleft = TimeSpan.FromMilliseconds(timeout) - elapsed;
 | 
			
		||||
            using (await udpData.AcquireReadLockAsync(timeleft))
 | 
			
		||||
            if (udpData.TryGetValue($"{ipAddr}-{taskID}", out var dataQueue))
 | 
			
		||||
            {
 | 
			
		||||
                if (udpData.ContainsKey($"{ipAddr}-{taskID}") &&
 | 
			
		||||
                    udpData.TryGetValue($"{ipAddr}-{taskID}", out var dataQueue))
 | 
			
		||||
                {
 | 
			
		||||
                    count = dataQueue.Count;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                count = dataQueue.Count;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -367,52 +351,26 @@ public class UDPServer
 | 
			
		||||
 | 
			
		||||
        return retPack.Value;
 | 
			
		||||
    }
 | 
			
		||||
    static int ReceiveHandleCcount = 0;
 | 
			
		||||
 | 
			
		||||
    private void ReceiveHandler(IAsyncResult res)
 | 
			
		||||
    private async Task ReceiveHandler(byte[] data, IPEndPoint endPoint, DateTime time)
 | 
			
		||||
    {
 | 
			
		||||
        var remoteEP = new IPEndPoint(IPAddress.Any, listenPort);
 | 
			
		||||
        byte[] bytes = listener.EndReceive(res, ref remoteEP);
 | 
			
		||||
 | 
			
		||||
        // 提前开始接收下一个包
 | 
			
		||||
        listener.BeginReceive(new AsyncCallback(ReceiveHandler), null);
 | 
			
		||||
        logger.Debug($"Test ReceiveHandler Count = {ReceiveHandleCcount}");
 | 
			
		||||
        ReceiveHandleCcount++;
 | 
			
		||||
 | 
			
		||||
        // Handle RemoteEP
 | 
			
		||||
        if (remoteEP is null)
 | 
			
		||||
        // 异步锁保护 udpData
 | 
			
		||||
        await Task.Run(() =>
 | 
			
		||||
        {
 | 
			
		||||
            logger.Debug($"Receive Data from Unknown at {DateTime.Now.ToString()}:");
 | 
			
		||||
            logger.Debug($"  Original Data : {BitConverter.ToString(bytes).Replace("-", " ")}");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
            // Handle RemoteEP
 | 
			
		||||
            if (endPoint is null)
 | 
			
		||||
            {
 | 
			
		||||
                logger.Debug($"Receive Data from Unknown at {DateTime.Now.ToString()}:");
 | 
			
		||||
                logger.Debug($"  Original Data : {BitConverter.ToString(data).Replace("-", " ")}");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        // 异步处理数据包
 | 
			
		||||
        Task.Run(() =>
 | 
			
		||||
        {
 | 
			
		||||
            var udpData = RecordUDPData(bytes, remoteEP, Convert.ToInt32(bytes[1]));
 | 
			
		||||
            PrintData(udpData);
 | 
			
		||||
            var udpDataObj = RecordUDPData(data, endPoint, time, Convert.ToInt32(data[1]));
 | 
			
		||||
            // PrintData(udpDataObj);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private bool SendBytes(IPEndPoint endPoint, byte[] buf)
 | 
			
		||||
    {
 | 
			
		||||
        var sendLen = listener.Send(buf, endPoint);
 | 
			
		||||
 | 
			
		||||
        if (sendLen == buf.Length) { return true; }
 | 
			
		||||
        else { return false; }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private bool SendString(IPEndPoint endPoint, string text)
 | 
			
		||||
    {
 | 
			
		||||
        byte[] buf = Encoding.ASCII.GetBytes(text);
 | 
			
		||||
        var sendLen = listener.Send(buf, endPoint);
 | 
			
		||||
 | 
			
		||||
        if (sendLen == buf.Length) { return true; }
 | 
			
		||||
        else { return false; }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private UDPData RecordUDPData(byte[] bytes, IPEndPoint remoteEP, int taskID)
 | 
			
		||||
    private UDPData RecordUDPData(byte[] bytes, IPEndPoint remoteEP, DateTime time, int taskID)
 | 
			
		||||
    {
 | 
			
		||||
        var remoteAddress = remoteEP.Address.ToString();
 | 
			
		||||
        var remotePort = remoteEP.Port;
 | 
			
		||||
@@ -422,26 +380,25 @@ public class UDPServer
 | 
			
		||||
            Port = remotePort,
 | 
			
		||||
            TaskID = taskID,
 | 
			
		||||
            Data = bytes,
 | 
			
		||||
            DateTime = DateTime.Now,
 | 
			
		||||
            DateTime = time,
 | 
			
		||||
            HasRead = false,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        using (udpData.AcquireWriteLock())
 | 
			
		||||
 | 
			
		||||
        lock (udpData)
 | 
			
		||||
        {
 | 
			
		||||
            // Record UDP Receive Data
 | 
			
		||||
            if (udpData.ContainsKey($"{remoteAddress}-{taskID}") &&
 | 
			
		||||
                udpData.TryGetValue($"{remoteAddress}-{taskID}", out var dataQueue))
 | 
			
		||||
            var key = $"{remoteAddress}-{taskID}";
 | 
			
		||||
            var dataQueue = udpData.GetOrAdd(key, _ => new ConcurrentQueue<UDPData>());
 | 
			
		||||
            dataQueue.Enqueue(data);
 | 
			
		||||
 | 
			
		||||
            // 对队列进行一次按时间排序
 | 
			
		||||
            if (dataQueue.Count > 0)
 | 
			
		||||
            {
 | 
			
		||||
                dataQueue.Enqueue(data);
 | 
			
		||||
                logger.Debug($"Test Lock dataQueue.Count = {dataQueue.Count}");
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                var queue = new Queue<UDPData>();
 | 
			
		||||
                queue.Enqueue(data);
 | 
			
		||||
                udpData.Add($"{remoteAddress}-{taskID}", queue);
 | 
			
		||||
                logger.Trace("Receive data from new client");
 | 
			
		||||
                var sorted = dataQueue.OrderBy(d => d.DateTime).ToList();
 | 
			
		||||
                udpData.TryUpdate(key, new ConcurrentQueue<UDPData>(sorted), dataQueue);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            PrintAllData();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return data;
 | 
			
		||||
@@ -451,7 +408,7 @@ public class UDPServer
 | 
			
		||||
    /// 输出UDP Data到log中
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="data">UDP数据</param>
 | 
			
		||||
    public void PrintData(UDPData data)
 | 
			
		||||
    public string PrintData(UDPData data)
 | 
			
		||||
    {
 | 
			
		||||
        var bytes = data.Data;
 | 
			
		||||
        var sign = bytes[0];
 | 
			
		||||
@@ -489,6 +446,11 @@ public class UDPServer
 | 
			
		||||
        // logger.Debug($"Receive Data from {data.Address}:{data.Port} at {data.DateTime.ToString()}:");
 | 
			
		||||
        // logger.Debug($"  Original Data : {BitConverter.ToString(bytes).Replace("-", " ")}");
 | 
			
		||||
        // if (recvData.Length != 0) logger.Debug($"  Decoded Data  : {recvData}");
 | 
			
		||||
        return $@"
 | 
			
		||||
        Receive Data from {data.Address}:{data.Port} at {data.DateTime.ToString()}:
 | 
			
		||||
            Original Data : {BitConverter.ToString(bytes).Replace("-", " ")}
 | 
			
		||||
            Decoded Data  : {recvData} 
 | 
			
		||||
        ";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
@@ -497,16 +459,13 @@ public class UDPServer
 | 
			
		||||
    /// <returns> void </returns>
 | 
			
		||||
    public void PrintAllData()
 | 
			
		||||
    {
 | 
			
		||||
        using (udpData.AcquireReadLock())
 | 
			
		||||
        {
 | 
			
		||||
            // logger.Debug("Ready Data:");
 | 
			
		||||
        logger.Debug("Ready Data:");
 | 
			
		||||
 | 
			
		||||
            foreach (var ip in udpData)
 | 
			
		||||
        foreach (var kvp in udpData)
 | 
			
		||||
        {
 | 
			
		||||
            foreach (var data in kvp.Value)
 | 
			
		||||
            {
 | 
			
		||||
                foreach (var data in ip.Value)
 | 
			
		||||
                {
 | 
			
		||||
                    // logger.Debug(data.ToString());
 | 
			
		||||
                }
 | 
			
		||||
                logger.Debug(PrintData(data));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -517,37 +476,48 @@ public class UDPServer
 | 
			
		||||
    /// <param name="ipAddr">IP地址</param>
 | 
			
		||||
    /// <param name="taskID">[TODO:parameter]</param>
 | 
			
		||||
    /// <returns>无</returns>
 | 
			
		||||
    public async Task ClearUDPData(string ipAddr, int taskID)
 | 
			
		||||
    public void ClearUDPData(string ipAddr, int taskID)
 | 
			
		||||
    {
 | 
			
		||||
        using (await udpData.AcquireWriteLockAsync())
 | 
			
		||||
        var key = $"{ipAddr}-{taskID}";
 | 
			
		||||
        if (udpData.TryGetValue(key, out var dataQueue))
 | 
			
		||||
        {
 | 
			
		||||
            if (udpData.ContainsKey($"{ipAddr}-{taskID}") &&
 | 
			
		||||
                udpData.TryGetValue($"{ipAddr}-{taskID}", out var dataQueue) &&
 | 
			
		||||
                dataQueue.Count > 0)
 | 
			
		||||
            {
 | 
			
		||||
                dataQueue.Clear();
 | 
			
		||||
            }
 | 
			
		||||
            // 清空队列的最有效方式是替换为新的队列
 | 
			
		||||
            udpData.TryUpdate(key, new ConcurrentQueue<UDPData>(), dataQueue);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Start UDP Server
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <returns>None</returns>
 | 
			
		||||
    public void Start()
 | 
			
		||||
    {
 | 
			
		||||
        this.isRunning = true;
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            this.listener.BeginReceive(new AsyncCallback(ReceiveHandler), null);
 | 
			
		||||
            foreach (var client in listeners)
 | 
			
		||||
            {
 | 
			
		||||
                Task.Run(async () =>
 | 
			
		||||
                {
 | 
			
		||||
                    while (this.isRunning)
 | 
			
		||||
                    {
 | 
			
		||||
                        try
 | 
			
		||||
                        {
 | 
			
		||||
                            UdpReceiveResult result = await client.ReceiveAsync();
 | 
			
		||||
                            ReceiveHandler(result.Buffer, result.RemoteEndPoint, DateTime.Now);
 | 
			
		||||
                        }
 | 
			
		||||
                        catch (Exception ex)
 | 
			
		||||
                        {
 | 
			
		||||
                            Console.WriteLine($"Error: {ex.Message}");
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        catch (Exception e)
 | 
			
		||||
        {
 | 
			
		||||
            Console.WriteLine(e.ToString());
 | 
			
		||||
        }
 | 
			
		||||
        finally
 | 
			
		||||
        {
 | 
			
		||||
            this.isRunning = true;
 | 
			
		||||
            this.isRunning = false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -557,8 +527,12 @@ public class UDPServer
 | 
			
		||||
    /// <returns>None</returns>
 | 
			
		||||
    public void Stop()
 | 
			
		||||
    {
 | 
			
		||||
        this.listener.Close();
 | 
			
		||||
        foreach (var item in listeners)
 | 
			
		||||
        {
 | 
			
		||||
            item.Close();
 | 
			
		||||
        }
 | 
			
		||||
        this.isRunning = false;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										7615
									
								
								src/APIClient.ts
									
									
									
									
									
								
							
							
						
						
									
										7615
									
								
								src/APIClient.ts
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -48,14 +48,15 @@
 | 
			
		||||
import { computed } from "vue";
 | 
			
		||||
import { CheckCircle, XCircle, AlertTriangle, Info, X } from "lucide-vue-next";
 | 
			
		||||
import { useAlertStore } from ".";
 | 
			
		||||
import { useRequiredInjection } from "@/utils/Common";
 | 
			
		||||
 | 
			
		||||
const alertStore = useAlertStore();
 | 
			
		||||
const alertStore = useRequiredInjection(useAlertStore);
 | 
			
		||||
 | 
			
		||||
// Computed classes for different alert types
 | 
			
		||||
const alertClasses = computed(() => {
 | 
			
		||||
  const baseClasses = "shadow-lg max-w-sm";
 | 
			
		||||
 | 
			
		||||
  switch (alertStore?.alertState.value.type) {
 | 
			
		||||
  switch (alertStore.alertState.value.type) {
 | 
			
		||||
    case "success":
 | 
			
		||||
      return `${baseClasses} alert-success`;
 | 
			
		||||
    case "error":
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										174
									
								
								src/components/LogicAnalyzer/ChannelConfig.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								src/components/LogicAnalyzer/ChannelConfig.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,174 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="space-y-4">
 | 
			
		||||
    <!-- 通道状态概览 -->
 | 
			
		||||
    <div class="stats stats-horizontal bg-base-100 shadow flex justify-between">
 | 
			
		||||
      <div class="stat">
 | 
			
		||||
        <div class="stat-title">总通道数</div>
 | 
			
		||||
        <div class="stat-value text-primary">8</div>
 | 
			
		||||
        <div class="stat-desc">逻辑分析仪通道</div>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <div class="stat">
 | 
			
		||||
        <div class="stat-title">启用通道</div>
 | 
			
		||||
        <div class="stat-value text-success">{{ enabledChannelCount }}</div>
 | 
			
		||||
        <div class="stat-desc">当前激活通道</div>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <div class="stat">
 | 
			
		||||
        <div class="stat-title">采样率</div>
 | 
			
		||||
        <div class="stat-value text-info">100MHz</div>
 | 
			
		||||
        <div class="stat-desc">最大采样频率</div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <!-- 通道配置列表 -->
 | 
			
		||||
    <div class="space-y-2">
 | 
			
		||||
      <div class="flex items-center justify-between p-2 bg-base-300 rounded-lg">
 | 
			
		||||
        <span class="font-medium">通道</span>
 | 
			
		||||
        <span class="font-medium">启用</span>
 | 
			
		||||
        <span class="font-medium">标签</span>
 | 
			
		||||
        <span class="font-medium">颜色</span>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <div
 | 
			
		||||
        v-for="(channel, index) in channels"
 | 
			
		||||
        :key="index"
 | 
			
		||||
        class="flex items-center justify-between p-3 bg-base-200 rounded-lg hover:bg-base-300 transition-colors"
 | 
			
		||||
      >
 | 
			
		||||
        <!-- 通道编号 -->
 | 
			
		||||
        <div class="flex items-center gap-2">
 | 
			
		||||
          <span class="font-mono font-medium w-12">CH{{ index }}</span>
 | 
			
		||||
          <div
 | 
			
		||||
            class="w-3 h-3 rounded-full border-2 border-white shadow-sm"
 | 
			
		||||
            :style="{ backgroundColor: channel.color }"
 | 
			
		||||
          ></div>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <!-- 启用开关 -->
 | 
			
		||||
        <div class="form-control">
 | 
			
		||||
          <input
 | 
			
		||||
            type="checkbox"
 | 
			
		||||
            v-model="channel.enabled"
 | 
			
		||||
            class="toggle toggle-sm toggle-primary"
 | 
			
		||||
            @change="updateChannelStatus(index)"
 | 
			
		||||
          />
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <!-- 通道标签 -->
 | 
			
		||||
        <div class="form-control w-32">
 | 
			
		||||
          <input
 | 
			
		||||
            type="text"
 | 
			
		||||
            v-model="channel.label"
 | 
			
		||||
            :placeholder="`通道 ${index}`"
 | 
			
		||||
            class="input input-sm input-bordered w-full"
 | 
			
		||||
            :disabled="!channel.enabled"
 | 
			
		||||
          />
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <!-- 颜色选择 -->
 | 
			
		||||
        <div class="form-control">
 | 
			
		||||
          <input
 | 
			
		||||
            type="color"
 | 
			
		||||
            v-model="channel.color"
 | 
			
		||||
            class="w-8 h-8 rounded border-2 border-base-300 cursor-pointer"
 | 
			
		||||
            :disabled="!channel.enabled"
 | 
			
		||||
          />
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <!-- 批量操作 -->
 | 
			
		||||
    <div class="flex gap-2 pt-4">
 | 
			
		||||
      <button @click="enableAllChannels" class="btn btn-primary btn-sm">
 | 
			
		||||
        全部启用
 | 
			
		||||
      </button>
 | 
			
		||||
 | 
			
		||||
      <button @click="disableAllChannels" class="btn btn-outline btn-sm">
 | 
			
		||||
        全部禁用
 | 
			
		||||
      </button>
 | 
			
		||||
 | 
			
		||||
      <button @click="resetChannelLabels" class="btn btn-outline btn-sm">
 | 
			
		||||
        重置标签
 | 
			
		||||
      </button>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { ref, computed, reactive } from "vue";
 | 
			
		||||
 | 
			
		||||
// 通道接口定义
 | 
			
		||||
interface Channel {
 | 
			
		||||
  enabled: boolean;
 | 
			
		||||
  label: string;
 | 
			
		||||
  color: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 预设配置接口
 | 
			
		||||
interface Preset {
 | 
			
		||||
  name: string;
 | 
			
		||||
  description: string;
 | 
			
		||||
  channels: Partial<Channel>[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 默认颜色数组
 | 
			
		||||
const defaultColors = [
 | 
			
		||||
  "#FF5733",
 | 
			
		||||
  "#33FF57",
 | 
			
		||||
  "#3357FF",
 | 
			
		||||
  "#FF33F5",
 | 
			
		||||
  "#F5FF33",
 | 
			
		||||
  "#33FFF5",
 | 
			
		||||
  "#FF8C33",
 | 
			
		||||
  "#8C33FF",
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
// 通道配置
 | 
			
		||||
const channels = reactive<Channel[]>(
 | 
			
		||||
  Array.from({ length: 8 }, (_, index) => ({
 | 
			
		||||
    enabled: false,
 | 
			
		||||
    label: `CH${index}`,
 | 
			
		||||
    color: defaultColors[index],
 | 
			
		||||
  })),
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
// 计算启用的通道数量
 | 
			
		||||
const enabledChannelCount = computed(
 | 
			
		||||
  () => channels.filter((channel) => channel.enabled).length,
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
// 更新通道状态
 | 
			
		||||
const updateChannelStatus = (index: number) => {
 | 
			
		||||
  console.log(`通道 ${index} 状态更新:`, channels[index].enabled);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 启用所有通道
 | 
			
		||||
const enableAllChannels = () => {
 | 
			
		||||
  channels.forEach((channel) => {
 | 
			
		||||
    channel.enabled = true;
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 禁用所有通道
 | 
			
		||||
const disableAllChannels = () => {
 | 
			
		||||
  channels.forEach((channel) => {
 | 
			
		||||
    channel.enabled = false;
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 重置通道标签
 | 
			
		||||
const resetChannelLabels = () => {
 | 
			
		||||
  channels.forEach((channel, index) => {
 | 
			
		||||
    channel.label = `CH${index}`;
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 应用预设配置
 | 
			
		||||
const applyPreset = (preset: Preset) => {
 | 
			
		||||
  preset.channels.forEach((presetChannel, index) => {
 | 
			
		||||
    if (index < channels.length && presetChannel) {
 | 
			
		||||
      Object.assign(channels[index], presetChannel);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										210
									
								
								src/components/LogicAnalyzer/LogicalWaveFormDisplay.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										210
									
								
								src/components/LogicAnalyzer/LogicalWaveFormDisplay.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,210 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="w-full h-150">
 | 
			
		||||
    <v-chart 
 | 
			
		||||
      v-if="data" 
 | 
			
		||||
      class="w-full h-full" 
 | 
			
		||||
      :option="option" 
 | 
			
		||||
      autoresize 
 | 
			
		||||
      :update-options="updateOptions"
 | 
			
		||||
    />
 | 
			
		||||
    <div
 | 
			
		||||
      v-else
 | 
			
		||||
      class="w-full h-full flex items-center justify-center text-gray-500"
 | 
			
		||||
    >
 | 
			
		||||
      暂无数据
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { computed, shallowRef } from "vue";
 | 
			
		||||
import VChart from "vue-echarts";
 | 
			
		||||
import type { LogicDataType } from "./index";
 | 
			
		||||
 | 
			
		||||
// Echarts
 | 
			
		||||
import { use } from "echarts/core";
 | 
			
		||||
import { LineChart } from "echarts/charts";
 | 
			
		||||
import {
 | 
			
		||||
  TooltipComponent,
 | 
			
		||||
  GridComponent,
 | 
			
		||||
  DataZoomComponent,
 | 
			
		||||
  AxisPointerComponent,
 | 
			
		||||
  ToolboxComponent,
 | 
			
		||||
} from "echarts/components";
 | 
			
		||||
import { CanvasRenderer } from "echarts/renderers";
 | 
			
		||||
import type { ComposeOption } from "echarts/core";
 | 
			
		||||
import type { LineSeriesOption } from "echarts/charts";
 | 
			
		||||
import type {
 | 
			
		||||
  AxisPointerComponentOption,
 | 
			
		||||
  TooltipComponentOption,
 | 
			
		||||
  GridComponentOption,
 | 
			
		||||
  DataZoomComponentOption,
 | 
			
		||||
} from "echarts/components";
 | 
			
		||||
import type {
 | 
			
		||||
  ToolboxComponentOption,
 | 
			
		||||
  XAXisOption,
 | 
			
		||||
  YAXisOption,
 | 
			
		||||
} from "echarts/types/dist/shared";
 | 
			
		||||
 | 
			
		||||
use([
 | 
			
		||||
  TooltipComponent,
 | 
			
		||||
  ToolboxComponent,
 | 
			
		||||
  GridComponent,
 | 
			
		||||
  AxisPointerComponent,
 | 
			
		||||
  DataZoomComponent,
 | 
			
		||||
  LineChart,
 | 
			
		||||
  CanvasRenderer,
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
type EChartsOption = ComposeOption<
 | 
			
		||||
  | AxisPointerComponentOption
 | 
			
		||||
  | TooltipComponentOption
 | 
			
		||||
  | ToolboxComponentOption
 | 
			
		||||
  | GridComponentOption
 | 
			
		||||
  | DataZoomComponentOption
 | 
			
		||||
  | LineSeriesOption
 | 
			
		||||
>;
 | 
			
		||||
 | 
			
		||||
// Define props
 | 
			
		||||
interface Props {
 | 
			
		||||
  data?: LogicDataType;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const props = defineProps<Props>();
 | 
			
		||||
 | 
			
		||||
// 添加更新选项来减少重绘
 | 
			
		||||
const updateOptions = shallowRef({
 | 
			
		||||
  notMerge: false,
 | 
			
		||||
  lazyUpdate: true,
 | 
			
		||||
  silent: false
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const option = computed((): EChartsOption => {
 | 
			
		||||
  if (!props.data) return {};
 | 
			
		||||
 | 
			
		||||
  const channelCount = props.data.y.length;
 | 
			
		||||
  const channelSpacing = 2; // 每个通道之间的间距
 | 
			
		||||
 | 
			
		||||
  // 使用单个网格
 | 
			
		||||
  const grids: GridComponentOption[] = [
 | 
			
		||||
    {
 | 
			
		||||
      left: "5%",
 | 
			
		||||
      right: "5%",
 | 
			
		||||
      top: "5%",
 | 
			
		||||
      bottom: "15%",
 | 
			
		||||
    },
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  // 单个X轴
 | 
			
		||||
  const xAxis: XAXisOption[] = [
 | 
			
		||||
    {
 | 
			
		||||
      type: "category",
 | 
			
		||||
      boundaryGap: false,
 | 
			
		||||
      data: props.data!.x.map((x) => x.toFixed(3)),
 | 
			
		||||
      axisLabel: {
 | 
			
		||||
        formatter: (value: string) => `${value}${props.data!.xUnit}`,
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  // 单个Y轴,范围根据通道数量调整
 | 
			
		||||
  const yAxis: YAXisOption[] = [
 | 
			
		||||
    {
 | 
			
		||||
      type: "value",
 | 
			
		||||
      min: -0.5,
 | 
			
		||||
      max: channelCount * channelSpacing - 0.5,
 | 
			
		||||
      interval: channelSpacing,
 | 
			
		||||
      axisLabel: {
 | 
			
		||||
        formatter: (value: number) => {
 | 
			
		||||
          const channelIndex = Math.round(value / channelSpacing);
 | 
			
		||||
          return channelIndex < channelCount
 | 
			
		||||
            ? props.data!.channelNames[channelIndex]
 | 
			
		||||
            : "";
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      splitLine: { show: false },
 | 
			
		||||
    },
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  // 创建系列数据,每个通道有不同的Y偏移
 | 
			
		||||
  const series: LineSeriesOption[] = props.data.y.map((channelData, index) => ({
 | 
			
		||||
    name: props.data!.channelNames[index],
 | 
			
		||||
    type: "line",
 | 
			
		||||
    data: channelData.map((value) => value + index * channelSpacing + 0.2),
 | 
			
		||||
    step: "end",
 | 
			
		||||
    lineStyle: {
 | 
			
		||||
      width: 2,
 | 
			
		||||
    },
 | 
			
		||||
    areaStyle: {
 | 
			
		||||
      opacity: 0.3,
 | 
			
		||||
      origin: index * channelSpacing,
 | 
			
		||||
    },
 | 
			
		||||
    symbol: "none",
 | 
			
		||||
    // 优化性能配置
 | 
			
		||||
    sampling: "lttb",
 | 
			
		||||
    // large: true,
 | 
			
		||||
    // largeThreshold: 2000,
 | 
			
		||||
    // progressive: 2000,
 | 
			
		||||
    // 减少动画以避免闪烁
 | 
			
		||||
    animation: false,
 | 
			
		||||
  }));
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    // 全局动画配置
 | 
			
		||||
    animation: false,
 | 
			
		||||
    tooltip: {
 | 
			
		||||
      trigger: "axis",
 | 
			
		||||
      axisPointer: {
 | 
			
		||||
        type: "line",
 | 
			
		||||
        label: {
 | 
			
		||||
          backgroundColor: "#6a7985",
 | 
			
		||||
        },
 | 
			
		||||
        // 减少axisPointer的动画
 | 
			
		||||
        animation: false,
 | 
			
		||||
      },
 | 
			
		||||
      formatter: (params: any) => {
 | 
			
		||||
        if (Array.isArray(params) && params.length > 0) {
 | 
			
		||||
          const timeValue = props.data!.x[params[0].dataIndex];
 | 
			
		||||
          const dataIndex = params[0].dataIndex;
 | 
			
		||||
 | 
			
		||||
          let tooltip = `Time: ${timeValue.toFixed(3)}${props.data!.xUnit}<br/>`;
 | 
			
		||||
 | 
			
		||||
          // 显示所有通道在当前时间点的原始数值(0或1)
 | 
			
		||||
          props.data!.channelNames.forEach((channelName, index) => {
 | 
			
		||||
            const originalValue = props.data!.y[index][dataIndex];
 | 
			
		||||
            tooltip += `${channelName}: ${originalValue}<br/>`;
 | 
			
		||||
          });
 | 
			
		||||
 | 
			
		||||
          return tooltip;
 | 
			
		||||
        }
 | 
			
		||||
        return "";
 | 
			
		||||
      },
 | 
			
		||||
      // 优化tooltip性能
 | 
			
		||||
      hideDelay: 100,
 | 
			
		||||
    },
 | 
			
		||||
    toolbox: {
 | 
			
		||||
      feature: {
 | 
			
		||||
        restore: {},
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    grid: grids,
 | 
			
		||||
    xAxis: xAxis,
 | 
			
		||||
    yAxis: yAxis,
 | 
			
		||||
    dataZoom: [
 | 
			
		||||
      {
 | 
			
		||||
        show: true,
 | 
			
		||||
        realtime: true,
 | 
			
		||||
        start: 0,
 | 
			
		||||
        end: 100,
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "inside",
 | 
			
		||||
        realtime: true,
 | 
			
		||||
        start: 0,
 | 
			
		||||
        end: 100,
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
    series: series,
 | 
			
		||||
  };
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										266
									
								
								src/components/LogicAnalyzer/TriggerSettings.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										266
									
								
								src/components/LogicAnalyzer/TriggerSettings.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,266 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="space-y-4">
 | 
			
		||||
    <!-- 全局触发模式配置 -->
 | 
			
		||||
    <div class="form-control">
 | 
			
		||||
      <label class="label">
 | 
			
		||||
        <span class="label-text font-medium">全局触发模式</span>
 | 
			
		||||
      </label>
 | 
			
		||||
      <div class="grid grid-cols-2 md:grid-cols-4 gap-2">
 | 
			
		||||
        <button
 | 
			
		||||
          v-for="mode in globalModes"
 | 
			
		||||
          :key="mode.value"
 | 
			
		||||
          @click="setGlobalMode(mode.value)"
 | 
			
		||||
          :class="[
 | 
			
		||||
            'btn btn-sm',
 | 
			
		||||
            currentGlobalMode === mode.value ? 'btn-primary' : 'btn-outline',
 | 
			
		||||
          ]"
 | 
			
		||||
        >
 | 
			
		||||
          {{ mode.label }}
 | 
			
		||||
        </button>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="label">
 | 
			
		||||
        <span class="label-text-alt text-gray-500">
 | 
			
		||||
          选择多路信号触发条件的逻辑组合方式
 | 
			
		||||
        </span>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <!-- 信号触发配置 -->
 | 
			
		||||
    <div class="form-control">
 | 
			
		||||
      <label class="label">
 | 
			
		||||
        <span class="label-text font-medium">信号触发配置</span>
 | 
			
		||||
      </label>
 | 
			
		||||
      <div class="space-y-2">
 | 
			
		||||
        <div
 | 
			
		||||
          v-for="(signal, index) in signalConfigs"
 | 
			
		||||
          :key="index"
 | 
			
		||||
          class="flex items-center gap-2 p-3 bg-base-200 rounded-lg"
 | 
			
		||||
        >
 | 
			
		||||
          <span class="text-sm font-medium w-16">CH{{ index }}</span>
 | 
			
		||||
 | 
			
		||||
          <!-- 操作符选择 -->
 | 
			
		||||
          <select
 | 
			
		||||
            v-model="signal.operator"
 | 
			
		||||
            class="select select-sm select-bordered w-32"
 | 
			
		||||
          >
 | 
			
		||||
            <option v-for="op in operators" :key="op.value" :value="op.value">
 | 
			
		||||
              {{ op.label }}
 | 
			
		||||
            </option>
 | 
			
		||||
          </select>
 | 
			
		||||
 | 
			
		||||
          <!-- 信号值选择 -->
 | 
			
		||||
          <select
 | 
			
		||||
            v-model="signal.value"
 | 
			
		||||
            class="select select-sm select-bordered w-32"
 | 
			
		||||
          >
 | 
			
		||||
            <option
 | 
			
		||||
              v-for="val in signalValues"
 | 
			
		||||
              :key="val.value"
 | 
			
		||||
              :value="val.value"
 | 
			
		||||
            >
 | 
			
		||||
              {{ val.label }}
 | 
			
		||||
            </option>
 | 
			
		||||
          </select>
 | 
			
		||||
 | 
			
		||||
          <!-- 启用/禁用开关 -->
 | 
			
		||||
          <div class="form-control">
 | 
			
		||||
            <label class="label cursor-pointer gap-2">
 | 
			
		||||
              <span class="label-text text-sm">启用</span>
 | 
			
		||||
              <input
 | 
			
		||||
                type="checkbox"
 | 
			
		||||
                v-model="signal.enabled"
 | 
			
		||||
                class="toggle toggle-sm toggle-primary"
 | 
			
		||||
              />
 | 
			
		||||
            </label>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <!-- 操作按钮 -->
 | 
			
		||||
    <div class="flex gap-2 pt-4">
 | 
			
		||||
      <button
 | 
			
		||||
        @click="applyConfiguration"
 | 
			
		||||
        :disabled="isApplying"
 | 
			
		||||
        class="btn btn-primary btn-sm"
 | 
			
		||||
      >
 | 
			
		||||
        <span
 | 
			
		||||
          v-if="isApplying"
 | 
			
		||||
          class="loading loading-spinner loading-sm"
 | 
			
		||||
        ></span>
 | 
			
		||||
        应用配置
 | 
			
		||||
      </button>
 | 
			
		||||
 | 
			
		||||
      <button @click="resetConfiguration" class="btn btn-outline btn-sm">
 | 
			
		||||
        重置
 | 
			
		||||
      </button>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <!-- 状态指示 -->
 | 
			
		||||
    <div
 | 
			
		||||
      v-if="lastApplyResult"
 | 
			
		||||
      class="alert alert-sm"
 | 
			
		||||
      :class="lastApplyResult.success ? 'alert-success' : 'alert-error'"
 | 
			
		||||
    >
 | 
			
		||||
      <span>{{ lastApplyResult.message }}</span>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { ref, reactive, computed } from "vue";
 | 
			
		||||
import { useEquipments } from "@/stores/equipments";
 | 
			
		||||
import {
 | 
			
		||||
  CaptureConfig,
 | 
			
		||||
  LogicAnalyzerClient,
 | 
			
		||||
  GlobalCaptureMode,
 | 
			
		||||
  SignalOperator,
 | 
			
		||||
  SignalValue,
 | 
			
		||||
  type SignalTriggerConfig,
 | 
			
		||||
} from "@/APIClient";
 | 
			
		||||
import { AuthManager } from "@/utils/AuthManager";
 | 
			
		||||
 | 
			
		||||
// 使用设备配置
 | 
			
		||||
const equipments = useEquipments();
 | 
			
		||||
 | 
			
		||||
// 当前全局模式
 | 
			
		||||
const currentGlobalMode = ref<GlobalCaptureMode>(GlobalCaptureMode.AND);
 | 
			
		||||
 | 
			
		||||
// 加载状态
 | 
			
		||||
const isApplying = ref(false);
 | 
			
		||||
const lastApplyResult = ref<{ success: boolean; message: string } | null>(null);
 | 
			
		||||
 | 
			
		||||
// 全局模式选项
 | 
			
		||||
const globalModes = [
 | 
			
		||||
  {
 | 
			
		||||
    value: GlobalCaptureMode.AND,
 | 
			
		||||
    label: "AND",
 | 
			
		||||
    description: "所有条件都满足时触发",
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    value: GlobalCaptureMode.OR,
 | 
			
		||||
    label: "OR",
 | 
			
		||||
    description: "任一条件满足时触发",
 | 
			
		||||
  },
 | 
			
		||||
  { value: GlobalCaptureMode.NAND, label: "NAND", description: "AND的非" },
 | 
			
		||||
  { value: GlobalCaptureMode.NOR, label: "NOR", description: "OR的非" },
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
// 操作符选项
 | 
			
		||||
const operators = [
 | 
			
		||||
  { value: SignalOperator.Equal, label: "=" },
 | 
			
		||||
  { value: SignalOperator.NotEqual, label: "≠" },
 | 
			
		||||
  { value: SignalOperator.LessThan, label: "<" },
 | 
			
		||||
  { value: SignalOperator.LessThanOrEqual, label: "≤" },
 | 
			
		||||
  { value: SignalOperator.GreaterThan, label: ">" },
 | 
			
		||||
  { value: SignalOperator.GreaterThanOrEqual, label: "≥" },
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
// 信号值选项
 | 
			
		||||
const signalValues = [
 | 
			
		||||
  { value: SignalValue.Logic0, label: "0" },
 | 
			
		||||
  { value: SignalValue.Logic1, label: "1" },
 | 
			
		||||
  { value: SignalValue.NotCare, label: "X" },
 | 
			
		||||
  { value: SignalValue.Rise, label: "↑" },
 | 
			
		||||
  { value: SignalValue.Fall, label: "↓" },
 | 
			
		||||
  { value: SignalValue.RiseOrFall, label: "↕" },
 | 
			
		||||
  { value: SignalValue.NoChange, label: "—" },
 | 
			
		||||
  { value: SignalValue.SomeNumber, label: "#" },
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
// 8个信号通道的配置
 | 
			
		||||
const signalConfigs = reactive(
 | 
			
		||||
  Array.from({ length: 8 }, (_, index) => ({
 | 
			
		||||
    signalIndex: index,
 | 
			
		||||
    operator: SignalOperator.Equal,
 | 
			
		||||
    value: SignalValue.Logic1,
 | 
			
		||||
    enabled: false,
 | 
			
		||||
  })),
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
// 设置全局触发模式
 | 
			
		||||
const setGlobalMode = async (mode: GlobalCaptureMode) => {
 | 
			
		||||
  try {
 | 
			
		||||
    const client = AuthManager.createAuthenticatedLogicAnalyzerClient();
 | 
			
		||||
    const success = await client.setGlobalTrigMode(mode);
 | 
			
		||||
 | 
			
		||||
    if (success) {
 | 
			
		||||
      currentGlobalMode.value = mode;
 | 
			
		||||
      lastApplyResult.value = {
 | 
			
		||||
        success: true,
 | 
			
		||||
        message: `全局触发模式已设置为 ${globalModes.find((m) => m.value === mode)?.label}`,
 | 
			
		||||
      };
 | 
			
		||||
    } else {
 | 
			
		||||
      throw new Error("设置失败");
 | 
			
		||||
    }
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.error("设置全局触发模式失败:", error);
 | 
			
		||||
    lastApplyResult.value = {
 | 
			
		||||
      success: false,
 | 
			
		||||
      message: "设置全局触发模式失败",
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 应用完整配置
 | 
			
		||||
const applyConfiguration = async () => {
 | 
			
		||||
  isApplying.value = true;
 | 
			
		||||
  lastApplyResult.value = null;
 | 
			
		||||
 | 
			
		||||
  try {
 | 
			
		||||
    const client = AuthManager.createAuthenticatedLogicAnalyzerClient();
 | 
			
		||||
 | 
			
		||||
    // 准备配置数据
 | 
			
		||||
    const enabledSignals = signalConfigs.filter((signal) => signal.enabled);
 | 
			
		||||
    const config = new CaptureConfig({
 | 
			
		||||
      globalMode: currentGlobalMode.value,
 | 
			
		||||
      signalConfigs: enabledSignals.map(
 | 
			
		||||
        (signal) =>
 | 
			
		||||
          ({
 | 
			
		||||
            signalIndex: signal.signalIndex,
 | 
			
		||||
            operator: signal.operator,
 | 
			
		||||
            value: signal.value,
 | 
			
		||||
          }) as SignalTriggerConfig,
 | 
			
		||||
      ),
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // 发送配置
 | 
			
		||||
    const success = await client.configureCapture(config);
 | 
			
		||||
 | 
			
		||||
    if (success) {
 | 
			
		||||
      lastApplyResult.value = {
 | 
			
		||||
        success: true,
 | 
			
		||||
        message: `配置已成功应用,启用了 ${enabledSignals.length} 个通道`,
 | 
			
		||||
      };
 | 
			
		||||
    } else {
 | 
			
		||||
      throw new Error("应用配置失败");
 | 
			
		||||
    }
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.error("应用配置失败:", error);
 | 
			
		||||
    lastApplyResult.value = {
 | 
			
		||||
      success: false,
 | 
			
		||||
      message: "应用配置失败,请检查设备连接",
 | 
			
		||||
    };
 | 
			
		||||
  } finally {
 | 
			
		||||
    isApplying.value = false;
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 重置配置
 | 
			
		||||
const resetConfiguration = () => {
 | 
			
		||||
  currentGlobalMode.value = GlobalCaptureMode.AND;
 | 
			
		||||
  signalConfigs.forEach((signal) => {
 | 
			
		||||
    signal.operator = SignalOperator.Equal;
 | 
			
		||||
    signal.value = SignalValue.Logic1;
 | 
			
		||||
    signal.enabled = false;
 | 
			
		||||
  });
 | 
			
		||||
  lastApplyResult.value = null;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 清除状态消息
 | 
			
		||||
setTimeout(() => {
 | 
			
		||||
  if (lastApplyResult.value) {
 | 
			
		||||
    lastApplyResult.value = null;
 | 
			
		||||
  }
 | 
			
		||||
}, 5000);
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										78
									
								
								src/components/LogicAnalyzer/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								src/components/LogicAnalyzer/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
			
		||||
import LogicalWaveFormDisplay from "./LogicalWaveFormDisplay.vue";
 | 
			
		||||
 | 
			
		||||
type LogicDataType = {
 | 
			
		||||
  x: number[];
 | 
			
		||||
  y: number[][]; // 8 channels of digital data (0 or 1)
 | 
			
		||||
  xUnit: "s" | "ms" | "us" | "ns";
 | 
			
		||||
  channelNames: string[];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Test data generator for 8-channel digital signals
 | 
			
		||||
function generateTestLogicData(): LogicDataType {
 | 
			
		||||
  const sampleRate = 10000; // 10kHz sampling
 | 
			
		||||
  const duration = 1;
 | 
			
		||||
  const points = Math.floor(sampleRate * duration);
 | 
			
		||||
 | 
			
		||||
  const x = Array.from({ length: points }, (_, i) => (i / sampleRate) * 1000); // time in ms
 | 
			
		||||
 | 
			
		||||
  // Generate 8 channels with different digital patterns
 | 
			
		||||
  const y = [
 | 
			
		||||
    // Channel 0: Clock signal 100Hz
 | 
			
		||||
    Array.from(
 | 
			
		||||
      { length: points },
 | 
			
		||||
      (_, i) => Math.floor((100 * i) / sampleRate) % 2,
 | 
			
		||||
    ),
 | 
			
		||||
    // Channel 1: Clock/2 signal 50Hz
 | 
			
		||||
    Array.from(
 | 
			
		||||
      { length: points },
 | 
			
		||||
      (_, i) => Math.floor((50 * i) / sampleRate) % 2,
 | 
			
		||||
    ),
 | 
			
		||||
    // Channel 2: Clock/4 signal 25Hz
 | 
			
		||||
    Array.from(
 | 
			
		||||
      { length: points },
 | 
			
		||||
      (_, i) => Math.floor((25 * i) / sampleRate) % 2,
 | 
			
		||||
    ),
 | 
			
		||||
    // Channel 3: Clock/8 signal 12.5Hz
 | 
			
		||||
    Array.from(
 | 
			
		||||
      { length: points },
 | 
			
		||||
      (_, i) => Math.floor((12.5 * i) / sampleRate) % 2,
 | 
			
		||||
    ),
 | 
			
		||||
    // Channel 4: Data signal (pseudo-random pattern)
 | 
			
		||||
    Array.from(
 | 
			
		||||
      { length: points },
 | 
			
		||||
      (_, i) => Math.abs( Math.floor(Math.sin(i * 0.01) * 10) % 2 ),
 | 
			
		||||
    ),
 | 
			
		||||
    // Channel 5: Enable signal (periodic pulse)
 | 
			
		||||
    Array.from(
 | 
			
		||||
      { length: points },
 | 
			
		||||
      (_, i) => (Math.floor(i / 50) % 10) < 3 ? 1 : 0,
 | 
			
		||||
    ),
 | 
			
		||||
    // Channel 6: Reset signal (occasional pulse)
 | 
			
		||||
    Array.from(
 | 
			
		||||
      { length: points },
 | 
			
		||||
      (_, i) => (Math.floor(i / 200) % 20) === 0 ? 1 : 0,
 | 
			
		||||
    ),
 | 
			
		||||
    // Channel 7: Status signal (slow changing)
 | 
			
		||||
    Array.from(
 | 
			
		||||
      { length: points },
 | 
			
		||||
      (_, i) => Math.floor(i / 1000) % 2,
 | 
			
		||||
    ),
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  const channelNames = [
 | 
			
		||||
    "CLK",
 | 
			
		||||
    "CLK/2", 
 | 
			
		||||
    "CLK/4",
 | 
			
		||||
    "CLK/8",
 | 
			
		||||
    "PWM",
 | 
			
		||||
    "ENABLE",
 | 
			
		||||
    "RESET",
 | 
			
		||||
    "STATUS"
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  return { x, y, xUnit: "ms", channelNames };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export { LogicalWaveFormDisplay, generateTestLogicData, type LogicDataType };
 | 
			
		||||
export { default as TriggerSettings } from './TriggerSettings.vue'
 | 
			
		||||
export { default as ChannelConfig } from './ChannelConfig.vue'
 | 
			
		||||
@@ -31,7 +31,6 @@ import { CanvasRenderer } from "echarts/renderers";
 | 
			
		||||
import type { ComposeOption } from "echarts/core";
 | 
			
		||||
import type { LineSeriesOption } from "echarts/charts";
 | 
			
		||||
import type {
 | 
			
		||||
  TitleComponentOption,
 | 
			
		||||
  TooltipComponentOption,
 | 
			
		||||
  LegendComponentOption,
 | 
			
		||||
  ToolboxComponentOption,
 | 
			
		||||
@@ -40,7 +39,6 @@ import type {
 | 
			
		||||
} from "echarts/components";
 | 
			
		||||
 | 
			
		||||
use([
 | 
			
		||||
  TitleComponent,
 | 
			
		||||
  TooltipComponent,
 | 
			
		||||
  LegendComponent,
 | 
			
		||||
  ToolboxComponent,
 | 
			
		||||
@@ -51,7 +49,6 @@ use([
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
type EChartsOption = ComposeOption<
 | 
			
		||||
  | TitleComponentOption
 | 
			
		||||
  | TooltipComponentOption
 | 
			
		||||
  | LegendComponentOption
 | 
			
		||||
  | ToolboxComponentOption
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,12 @@
 | 
			
		||||
          <div class="waveform-display">
 | 
			
		||||
            <svg width="100%" height="120" viewBox="0 0 300 120">
 | 
			
		||||
              <rect width="300" height="120" fill="#1a1f25" />
 | 
			
		||||
              <path :d="currentWaveformPath" stroke="lime" stroke-width="2" fill="none" />
 | 
			
		||||
              <path
 | 
			
		||||
                :d="currentWaveformPath"
 | 
			
		||||
                stroke="lime"
 | 
			
		||||
                stroke-width="2"
 | 
			
		||||
                fill="none"
 | 
			
		||||
              />
 | 
			
		||||
 | 
			
		||||
              <!-- 频率和相位显示 -->
 | 
			
		||||
              <text x="20" y="25" fill="#0f0" font-size="14">
 | 
			
		||||
@@ -16,7 +21,13 @@
 | 
			
		||||
              <text x="200" y="25" fill="#0f0" font-size="14">
 | 
			
		||||
                φ: {{ phase }}°
 | 
			
		||||
              </text>
 | 
			
		||||
              <text x="150" y="110" fill="#0f0" font-size="14" text-anchor="middle">
 | 
			
		||||
              <text
 | 
			
		||||
                x="150"
 | 
			
		||||
                y="110"
 | 
			
		||||
                fill="#0f0"
 | 
			
		||||
                font-size="14"
 | 
			
		||||
                text-anchor="middle"
 | 
			
		||||
              >
 | 
			
		||||
                {{ displayTimebase }}
 | 
			
		||||
              </text>
 | 
			
		||||
            </svg>
 | 
			
		||||
@@ -35,10 +46,15 @@
 | 
			
		||||
 | 
			
		||||
          <!-- 波形选择区 -->
 | 
			
		||||
          <div class="waveform-selector">
 | 
			
		||||
            <div v-for="(name, index) in waveformNames" :key="`wave-${index}`" :class="[
 | 
			
		||||
              'waveform-option',
 | 
			
		||||
              { active: currentWaveformIndex === index },
 | 
			
		||||
            ]" @click="selectWaveform(index)">
 | 
			
		||||
            <div
 | 
			
		||||
              v-for="(name, index) in waveformNames"
 | 
			
		||||
              :key="`wave-${index}`"
 | 
			
		||||
              :class="[
 | 
			
		||||
                'waveform-option',
 | 
			
		||||
                { active: currentWaveformIndex === index },
 | 
			
		||||
              ]"
 | 
			
		||||
              @click="selectWaveform(index)"
 | 
			
		||||
            >
 | 
			
		||||
              {{ name }}
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
@@ -51,8 +67,13 @@
 | 
			
		||||
                <button class="control-button" @click="decreaseFrequency">
 | 
			
		||||
                  -
 | 
			
		||||
                </button>
 | 
			
		||||
                <input v-model="frequencyInput" @blur="applyFrequencyInput" @keyup.enter="applyFrequencyInput"
 | 
			
		||||
                  class="control-input" type="text" />
 | 
			
		||||
                <input
 | 
			
		||||
                  v-model="frequencyInput"
 | 
			
		||||
                  @blur="applyFrequencyInput"
 | 
			
		||||
                  @keyup.enter="applyFrequencyInput"
 | 
			
		||||
                  class="control-input"
 | 
			
		||||
                  type="text"
 | 
			
		||||
                />
 | 
			
		||||
                <button class="control-button" @click="increaseFrequency">
 | 
			
		||||
                  +
 | 
			
		||||
                </button>
 | 
			
		||||
@@ -63,8 +84,13 @@
 | 
			
		||||
              <span class="control-label">相位:</span>
 | 
			
		||||
              <div class="control-buttons">
 | 
			
		||||
                <button class="control-button" @click="decreasePhase">-</button>
 | 
			
		||||
                <input v-model="phaseInput" @blur="applyPhaseInput" @keyup.enter="applyPhaseInput" class="control-input"
 | 
			
		||||
                  type="text" />
 | 
			
		||||
                <input
 | 
			
		||||
                  v-model="phaseInput"
 | 
			
		||||
                  @blur="applyPhaseInput"
 | 
			
		||||
                  @keyup.enter="applyPhaseInput"
 | 
			
		||||
                  class="control-input"
 | 
			
		||||
                  type="text"
 | 
			
		||||
                />
 | 
			
		||||
                <button class="control-button" @click="increasePhase">+</button>
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
@@ -75,9 +101,12 @@
 | 
			
		||||
            <div class="section-heading">自定义波形</div>
 | 
			
		||||
            <div class="input-group">
 | 
			
		||||
              <label class="input-label">函数表达式:</label>
 | 
			
		||||
              <input v-model="customWaveformExpression" class="function-input"
 | 
			
		||||
              <input
 | 
			
		||||
                v-model="customWaveformExpression"
 | 
			
		||||
                class="function-input"
 | 
			
		||||
                placeholder="例如: sin(t) 或 x^(2/3)+0.9*sqrt(3.3-x^2)*sin(a*PI*x) [a=7.8]"
 | 
			
		||||
                @keyup.enter="applyCustomWaveform" />
 | 
			
		||||
                @keyup.enter="applyCustomWaveform"
 | 
			
		||||
              />
 | 
			
		||||
              <button class="apply-button" @click="applyCustomWaveform">
 | 
			
		||||
                应用
 | 
			
		||||
              </button>
 | 
			
		||||
@@ -86,17 +115,26 @@
 | 
			
		||||
            <div class="example-functions">
 | 
			
		||||
              <div class="example-label">示例函数:</div>
 | 
			
		||||
              <div class="example-buttons">
 | 
			
		||||
                <button class="example-button" @click="applyExampleFunction('sin(t)')">
 | 
			
		||||
                <button
 | 
			
		||||
                  class="example-button"
 | 
			
		||||
                  @click="applyExampleFunction('sin(t)')"
 | 
			
		||||
                >
 | 
			
		||||
                  正弦波
 | 
			
		||||
                </button>
 | 
			
		||||
                <button class="example-button" @click="applyExampleFunction('sin(t)^3')">
 | 
			
		||||
                <button
 | 
			
		||||
                  class="example-button"
 | 
			
		||||
                  @click="applyExampleFunction('sin(t)^3')"
 | 
			
		||||
                >
 | 
			
		||||
                  立方正弦
 | 
			
		||||
                </button>
 | 
			
		||||
                <button class="example-button" @click="
 | 
			
		||||
                  applyExampleFunction(
 | 
			
		||||
                    '((x)^(2/3)+0.9*sqrt(3.3-(x)^2)*sin(10*PI*(x)))*0.75',
 | 
			
		||||
                  )
 | 
			
		||||
                  ">
 | 
			
		||||
                <button
 | 
			
		||||
                  class="example-button"
 | 
			
		||||
                  @click="
 | 
			
		||||
                    applyExampleFunction(
 | 
			
		||||
                      '((x)^(2/3)+0.9*sqrt(3.3-(x)^2)*sin(10*PI*(x)))*0.75',
 | 
			
		||||
                    )
 | 
			
		||||
                  "
 | 
			
		||||
                >
 | 
			
		||||
                  心形函数
 | 
			
		||||
                </button>
 | 
			
		||||
              </div>
 | 
			
		||||
@@ -105,8 +143,16 @@
 | 
			
		||||
            <div class="drawing-area">
 | 
			
		||||
              <div class="section-heading">波形绘制</div>
 | 
			
		||||
              <div class="waveform-canvas-container" ref="canvasContainer">
 | 
			
		||||
                <canvas ref="drawingCanvas" class="drawing-canvas" width="280" height="100" @mousedown="startDrawing"
 | 
			
		||||
                  @mousemove="draw" @mouseup="stopDrawing" @mouseleave="stopDrawing"></canvas>
 | 
			
		||||
                <canvas
 | 
			
		||||
                  ref="drawingCanvas"
 | 
			
		||||
                  class="drawing-canvas"
 | 
			
		||||
                  width="280"
 | 
			
		||||
                  height="100"
 | 
			
		||||
                  @mousedown="startDrawing"
 | 
			
		||||
                  @mousemove="draw"
 | 
			
		||||
                  @mouseup="stopDrawing"
 | 
			
		||||
                  @mouseleave="stopDrawing"
 | 
			
		||||
                ></canvas>
 | 
			
		||||
                <div class="canvas-actions">
 | 
			
		||||
                  <button class="canvas-button" @click="clearCanvas">
 | 
			
		||||
                    清除
 | 
			
		||||
@@ -123,19 +169,30 @@
 | 
			
		||||
          <div class="saved-waveforms">
 | 
			
		||||
            <div class="section-heading">波形存储槽</div>
 | 
			
		||||
            <div class="slot-container">
 | 
			
		||||
              <div v-for="(slot, index) in waveformSlots" :key="`slot-${index}`"
 | 
			
		||||
                :class="['waveform-slot', { empty: !slot.name }]" @click="loadWaveformSlot(index)">
 | 
			
		||||
              <div
 | 
			
		||||
                v-for="(slot, index) in waveformSlots"
 | 
			
		||||
                :key="`slot-${index}`"
 | 
			
		||||
                :class="['waveform-slot', { empty: !slot.name }]"
 | 
			
		||||
                @click="loadWaveformSlot(index)"
 | 
			
		||||
              >
 | 
			
		||||
                <span class="slot-name">{{
 | 
			
		||||
                  slot.name || `槽 ${index + 1}`
 | 
			
		||||
                  }}</span>
 | 
			
		||||
                <button class="save-button" @click.stop="saveCurrentToSlot(index)">
 | 
			
		||||
                }}</span>
 | 
			
		||||
                <button
 | 
			
		||||
                  class="save-button"
 | 
			
		||||
                  @click.stop="saveCurrentToSlot(index)"
 | 
			
		||||
                >
 | 
			
		||||
                  保存
 | 
			
		||||
                </button>
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
          <button class="btn btn-primary text-primary-content w-full" :disabled="isApplying" @click="applyOutputWave">
 | 
			
		||||
          <button
 | 
			
		||||
            class="btn btn-primary text-primary-content w-full"
 | 
			
		||||
            :disabled="isApplying"
 | 
			
		||||
            @click="applyOutputWave"
 | 
			
		||||
          >
 | 
			
		||||
            <div v-if="isApplying">
 | 
			
		||||
              <span class="loading loading-spinner"></span>
 | 
			
		||||
              应用中...
 | 
			
		||||
@@ -151,10 +208,10 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { ref, computed, watch, onMounted } from "vue";
 | 
			
		||||
import CollapsibleSection from "../CollapsibleSection.vue";
 | 
			
		||||
import { DDSClient } from "@/APIClient";
 | 
			
		||||
import { useEquipments } from "@/stores/equipments";
 | 
			
		||||
import { useDialogStore } from "@/stores/dialog";
 | 
			
		||||
import { toInteger } from "lodash";
 | 
			
		||||
import { AuthManager } from "@/utils/AuthManager";
 | 
			
		||||
 | 
			
		||||
// Component Attributes
 | 
			
		||||
const props = defineProps<{
 | 
			
		||||
@@ -164,7 +221,7 @@ const props = defineProps<{
 | 
			
		||||
const emit = defineEmits(["update:modelValue"]);
 | 
			
		||||
 | 
			
		||||
// Global varibles
 | 
			
		||||
const dds = new DDSClient();
 | 
			
		||||
const dds = AuthManager.createAuthenticatedDDSClient();
 | 
			
		||||
const eqps = useEquipments();
 | 
			
		||||
const dialog = useDialogStore();
 | 
			
		||||
 | 
			
		||||
@@ -793,7 +850,7 @@ function saveCurrentToSlot(index: number) {
 | 
			
		||||
    type: waveforms[currentWaveformIndex.value],
 | 
			
		||||
    data:
 | 
			
		||||
      drawPoints.value.length > 0 &&
 | 
			
		||||
        currentWaveformIndex.value === waveforms.indexOf("custom")
 | 
			
		||||
      currentWaveformIndex.value === waveforms.indexOf("custom")
 | 
			
		||||
        ? [...drawPoints.value]
 | 
			
		||||
        : null,
 | 
			
		||||
  };
 | 
			
		||||
 
 | 
			
		||||
@@ -1,42 +1,55 @@
 | 
			
		||||
import { ref, reactive, watchPostEffect } from 'vue'
 | 
			
		||||
import { defineStore } from 'pinia'
 | 
			
		||||
import { useLocalStorage } from '@vueuse/core'
 | 
			
		||||
import { isString, toNumber } from 'lodash';
 | 
			
		||||
import { Common } from '@/utils/Common';
 | 
			
		||||
import z from "zod"
 | 
			
		||||
import { isNumber } from 'mathjs';
 | 
			
		||||
import { ref, reactive, watchPostEffect } from "vue";
 | 
			
		||||
import { defineStore } from "pinia";
 | 
			
		||||
import { useLocalStorage } from "@vueuse/core";
 | 
			
		||||
import { isString, toNumber } from "lodash";
 | 
			
		||||
import z from "zod";
 | 
			
		||||
import { isNumber } from "mathjs";
 | 
			
		||||
import { JtagClient, MatrixKeyClient, PowerClient } from "@/APIClient";
 | 
			
		||||
import { Mutex, withTimeout } from 'async-mutex';
 | 
			
		||||
import { Mutex, withTimeout } from "async-mutex";
 | 
			
		||||
import { useConstraintsStore } from "@/stores/constraints";
 | 
			
		||||
import { useDialogStore } from './dialog';
 | 
			
		||||
import { useDialogStore } from "./dialog";
 | 
			
		||||
import { toFileParameterOrUndefined } from "@/utils/Common";
 | 
			
		||||
import { AuthManager } from "@/utils/AuthManager";
 | 
			
		||||
 | 
			
		||||
export const useEquipments = defineStore('equipments', () => {
 | 
			
		||||
export const useEquipments = defineStore("equipments", () => {
 | 
			
		||||
  // Global Stores
 | 
			
		||||
  const constrainsts = useConstraintsStore();
 | 
			
		||||
  const dialog = useDialogStore();
 | 
			
		||||
 | 
			
		||||
  const boardAddr = useLocalStorage('fpga-board-addr', "127.0.0.1");
 | 
			
		||||
  const boardPort = useLocalStorage('fpga-board-port', 1234);
 | 
			
		||||
  const boardAddr = useLocalStorage("fpga-board-addr", "127.0.0.1");
 | 
			
		||||
  const boardPort = useLocalStorage("fpga-board-port", 1234);
 | 
			
		||||
 | 
			
		||||
  // Jtag
 | 
			
		||||
  const jtagBitstream = ref<File>();
 | 
			
		||||
  const jtagBoundaryScanFreq = ref(100);
 | 
			
		||||
  const jtagClientMutex = withTimeout(new Mutex(), 1000, new Error("JtagClient Mutex Timeout!"))
 | 
			
		||||
  const jtagClient = new JtagClient();
 | 
			
		||||
  const jtagClientMutex = withTimeout(
 | 
			
		||||
    new Mutex(),
 | 
			
		||||
    1000,
 | 
			
		||||
    new Error("JtagClient Mutex Timeout!"),
 | 
			
		||||
  );
 | 
			
		||||
  const jtagClient = AuthManager.createAuthenticatedJtagClient();
 | 
			
		||||
 | 
			
		||||
  // Matrix Key
 | 
			
		||||
  const matrixKeyStates = reactive(new Array<boolean>(16).fill(false))
 | 
			
		||||
  const matrixKeypadClientMutex = withTimeout(new Mutex(), 1000, new Error("Matrixkeyclient Mutex Timeout!"));
 | 
			
		||||
  const matrixKeypadClient = new MatrixKeyClient();
 | 
			
		||||
  const matrixKeyStates = reactive(new Array<boolean>(16).fill(false));
 | 
			
		||||
  const matrixKeypadClientMutex = withTimeout(
 | 
			
		||||
    new Mutex(),
 | 
			
		||||
    1000,
 | 
			
		||||
    new Error("Matrixkeyclient Mutex Timeout!"),
 | 
			
		||||
  );
 | 
			
		||||
  const matrixKeypadClient = AuthManager.createAuthenticatedMatrixKeyClient();
 | 
			
		||||
 | 
			
		||||
  // Power
 | 
			
		||||
  const powerClientMutex = withTimeout(new Mutex(), 1000, new Error("Matrixkeyclient Mutex Timeout!"));
 | 
			
		||||
  const powerClient = new PowerClient();
 | 
			
		||||
  const powerClientMutex = withTimeout(
 | 
			
		||||
    new Mutex(),
 | 
			
		||||
    1000,
 | 
			
		||||
    new Error("Matrixkeyclient Mutex Timeout!"),
 | 
			
		||||
  );
 | 
			
		||||
  const powerClient = AuthManager.createAuthenticatedPowerClient();
 | 
			
		||||
 | 
			
		||||
  // Enable Setting
 | 
			
		||||
  const enableJtagBoundaryScan = ref(false);
 | 
			
		||||
  const enableMatrixKey = ref(false);
 | 
			
		||||
  const enablePower = ref(false)
 | 
			
		||||
  const enablePower = ref(false);
 | 
			
		||||
 | 
			
		||||
  // Watch
 | 
			
		||||
  watchPostEffect(async () => {
 | 
			
		||||
@@ -60,8 +73,7 @@ export const useEquipments = defineStore('equipments', () => {
 | 
			
		||||
        boardPort.value = portNumber;
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    else if (isNumber(port)) {
 | 
			
		||||
    } else if (isNumber(port)) {
 | 
			
		||||
      if (z.number().nonnegative().max(65535).safeParse(port).success) {
 | 
			
		||||
        boardPort.value = port;
 | 
			
		||||
        return true;
 | 
			
		||||
@@ -70,7 +82,10 @@ export const useEquipments = defineStore('equipments', () => {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function setMatrixKey(keyNum: number | string | undefined, keyValue: boolean): boolean {
 | 
			
		||||
  function setMatrixKey(
 | 
			
		||||
    keyNum: number | string | undefined,
 | 
			
		||||
    keyValue: boolean,
 | 
			
		||||
  ): boolean {
 | 
			
		||||
    let _keyNum: number;
 | 
			
		||||
    if (isString(keyNum)) {
 | 
			
		||||
      _keyNum = toNumber(keyNum);
 | 
			
		||||
@@ -112,7 +127,7 @@ export const useEquipments = defineStore('equipments', () => {
 | 
			
		||||
    try {
 | 
			
		||||
      const resp = await jtagClient.uploadBitstream(
 | 
			
		||||
        boardAddr.value,
 | 
			
		||||
        Common.toFileParameterOrNull(bitstream),
 | 
			
		||||
        toFileParameterOrUndefined(bitstream),
 | 
			
		||||
      );
 | 
			
		||||
      return resp;
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
@@ -127,7 +142,7 @@ export const useEquipments = defineStore('equipments', () => {
 | 
			
		||||
    try {
 | 
			
		||||
      const resp = await jtagClient.downloadBitstream(
 | 
			
		||||
        boardAddr.value,
 | 
			
		||||
        boardPort.value
 | 
			
		||||
        boardPort.value,
 | 
			
		||||
      );
 | 
			
		||||
      return resp;
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
@@ -144,7 +159,7 @@ export const useEquipments = defineStore('equipments', () => {
 | 
			
		||||
    try {
 | 
			
		||||
      const resp = await jtagClient.getDeviceIDCode(
 | 
			
		||||
        boardAddr.value,
 | 
			
		||||
        boardPort.value
 | 
			
		||||
        boardPort.value,
 | 
			
		||||
      );
 | 
			
		||||
      return resp;
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
@@ -161,7 +176,7 @@ export const useEquipments = defineStore('equipments', () => {
 | 
			
		||||
      const resp = await jtagClient.setSpeed(
 | 
			
		||||
        boardAddr.value,
 | 
			
		||||
        boardPort.value,
 | 
			
		||||
        speed
 | 
			
		||||
        speed,
 | 
			
		||||
      );
 | 
			
		||||
      return resp;
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
@@ -179,7 +194,7 @@ export const useEquipments = defineStore('equipments', () => {
 | 
			
		||||
      const resp = await matrixKeypadClient.setMatrixKeyStatus(
 | 
			
		||||
        boardAddr.value,
 | 
			
		||||
        boardPort.value,
 | 
			
		||||
        keyStates
 | 
			
		||||
        keyStates,
 | 
			
		||||
      );
 | 
			
		||||
      return resp;
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
@@ -223,7 +238,7 @@ export const useEquipments = defineStore('equipments', () => {
 | 
			
		||||
      const resp = await powerClient.setPowerOnOff(
 | 
			
		||||
        boardAddr.value,
 | 
			
		||||
        boardPort.value,
 | 
			
		||||
        enable
 | 
			
		||||
        enable,
 | 
			
		||||
      );
 | 
			
		||||
      return resp;
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
@@ -266,6 +281,5 @@ export const useEquipments = defineStore('equipments', () => {
 | 
			
		||||
    powerClient,
 | 
			
		||||
    powerClientMutex,
 | 
			
		||||
    powerSetOnOff,
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
  };
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@ import {
 | 
			
		||||
  RemoteUpdateClient,
 | 
			
		||||
  TutorialClient,
 | 
			
		||||
  UDPClient,
 | 
			
		||||
  LogicAnalyzerClient,
 | 
			
		||||
} from "@/APIClient";
 | 
			
		||||
 | 
			
		||||
// 支持的客户端类型联合类型
 | 
			
		||||
@@ -22,6 +23,7 @@ type SupportedClient =
 | 
			
		||||
  | PowerClient
 | 
			
		||||
  | RemoteUpdateClient
 | 
			
		||||
  | TutorialClient
 | 
			
		||||
  | LogicAnalyzerClient
 | 
			
		||||
  | UDPClient;
 | 
			
		||||
 | 
			
		||||
export class AuthManager {
 | 
			
		||||
@@ -151,6 +153,10 @@ export class AuthManager {
 | 
			
		||||
    return AuthManager.createAuthenticatedClient(UDPClient);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static createAuthenticatedLogicAnalyzerClient(): LogicAnalyzerClient {
 | 
			
		||||
    return AuthManager.createAuthenticatedClient(LogicAnalyzerClient);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // 登录函数
 | 
			
		||||
  public static async login(
 | 
			
		||||
    username: string,
 | 
			
		||||
@@ -212,11 +218,7 @@ export class AuthManager {
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      // 只有在token完全无效的情况下才清除token
 | 
			
		||||
      // 401错误表示token有效但权限不足,不应清除token
 | 
			
		||||
      if (
 | 
			
		||||
        error &&
 | 
			
		||||
        typeof error === "object" &&
 | 
			
		||||
        "status" in error
 | 
			
		||||
      ) {
 | 
			
		||||
      if (error && typeof error === "object" && "status" in error) {
 | 
			
		||||
        // 如果是403 (Forbidden) 或401 (Unauthorized),说明token有效但权限不足
 | 
			
		||||
        if (error.status === 401 || error.status === 403) {
 | 
			
		||||
          return false;
 | 
			
		||||
@@ -225,7 +227,7 @@ export class AuthManager {
 | 
			
		||||
        AuthManager.clearToken();
 | 
			
		||||
      } else {
 | 
			
		||||
        // 网络错误等,不清除token
 | 
			
		||||
        console.error('管理员权限验证失败:', error);
 | 
			
		||||
        console.error("管理员权限验证失败:", error);
 | 
			
		||||
      }
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
import { ref } from "vue";
 | 
			
		||||
import { createInjectionState } from "@vueuse/core";
 | 
			
		||||
import { RemoteUpdateClient, DataClient, Board } from "@/APIClient";
 | 
			
		||||
import { Common } from "@/utils/Common";
 | 
			
		||||
import { isUndefined } from "lodash";
 | 
			
		||||
import { AuthManager } from "@/utils/AuthManager";
 | 
			
		||||
import { toFileParameterOrNull } from "./Common";
 | 
			
		||||
 | 
			
		||||
// 统一的板卡数据接口,扩展原有的Board类型
 | 
			
		||||
export interface BoardData extends Board {
 | 
			
		||||
@@ -17,7 +17,7 @@ export interface BoardData extends Board {
 | 
			
		||||
const [useProvideBoardManager, useBoardManager] = createInjectionState(() => {
 | 
			
		||||
  // 远程升级相关参数
 | 
			
		||||
  const devPort = 1234;
 | 
			
		||||
  const remoteUpdater = new RemoteUpdateClient();
 | 
			
		||||
  const remoteUpdater = AuthManager.createAuthenticatedRemoteUpdateClient();
 | 
			
		||||
 | 
			
		||||
  // 统一的板卡数据
 | 
			
		||||
  const boards = ref<BoardData[]>([]);
 | 
			
		||||
@@ -178,10 +178,10 @@ const [useProvideBoardManager, useBoardManager] = createInjectionState(() => {
 | 
			
		||||
      
 | 
			
		||||
      const uploadResult = await remoteUpdater.uploadBitstreams(
 | 
			
		||||
        board.ipAddr,
 | 
			
		||||
        Common.toFileParameterOrNull(goldBitstream),
 | 
			
		||||
        Common.toFileParameterOrNull(appBitstream1),
 | 
			
		||||
        Common.toFileParameterOrNull(appBitstream2),
 | 
			
		||||
        Common.toFileParameterOrNull(appBitstream3),
 | 
			
		||||
        toFileParameterOrNull(goldBitstream),
 | 
			
		||||
        toFileParameterOrNull(appBitstream1),
 | 
			
		||||
        toFileParameterOrNull(appBitstream2),
 | 
			
		||||
        toFileParameterOrNull(appBitstream3),
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      if (!uploadResult) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,22 +1,50 @@
 | 
			
		||||
import { type FileParameter } from "@/APIClient";
 | 
			
		||||
import { isNull, isUndefined } from "lodash";
 | 
			
		||||
 | 
			
		||||
export namespace Common {
 | 
			
		||||
  export function toFileParameter(object: File): FileParameter {
 | 
			
		||||
    if (isNull(object) || isUndefined(object))
 | 
			
		||||
      throw new Error("File is Null or Undefined");
 | 
			
		||||
export function toFileParameter(object: File): FileParameter {
 | 
			
		||||
  if (isNull(object) || isUndefined(object))
 | 
			
		||||
    throw new Error("File is Null or Undefined");
 | 
			
		||||
  return {
 | 
			
		||||
    data: object,
 | 
			
		||||
    fileName: object.name,
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function toFileParameterOrNull(
 | 
			
		||||
  object?: File | null,
 | 
			
		||||
): FileParameter | null {
 | 
			
		||||
  if (isNull(object) || isUndefined(object)) return null;
 | 
			
		||||
  else
 | 
			
		||||
    return {
 | 
			
		||||
      data: object,
 | 
			
		||||
      fileName: object.name
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  export function toFileParameterOrNull(object?: File | null): FileParameter | null {
 | 
			
		||||
    if (isNull(object) || isUndefined(object)) return null;
 | 
			
		||||
    else return {
 | 
			
		||||
      data: object,
 | 
			
		||||
      fileName: object.name
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
      fileName: object.name,
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function toFileParameterOrUndefined(
 | 
			
		||||
  object?: File | undefined,
 | 
			
		||||
): FileParameter | undefined {
 | 
			
		||||
  if (isNull(object) || isUndefined(object)) return undefined;
 | 
			
		||||
  else
 | 
			
		||||
    return {
 | 
			
		||||
      data: object,
 | 
			
		||||
      fileName: object.name,
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 自定义 Hook:检查依赖注入值是否为空
 | 
			
		||||
export function useRequiredInjection<T>(useFn: () => T | undefined): T {
 | 
			
		||||
  const value = useFn();
 | 
			
		||||
  if (value === undefined) {
 | 
			
		||||
    throw new Error("Missing required injection");
 | 
			
		||||
  }
 | 
			
		||||
  return value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function useOptionalInjection<T>(
 | 
			
		||||
  useFn: () => T | undefined,
 | 
			
		||||
  defaultValue: T,
 | 
			
		||||
): T {
 | 
			
		||||
  const value = useFn();
 | 
			
		||||
  return value ?? defaultValue;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@
 | 
			
		||||
          type="radio"
 | 
			
		||||
          name="function-bar"
 | 
			
		||||
          id="1"
 | 
			
		||||
          checked
 | 
			
		||||
          :checked="checkID === 1"
 | 
			
		||||
          @change="handleTabChange"
 | 
			
		||||
        />
 | 
			
		||||
        <TerminalIcon class="icon" />
 | 
			
		||||
@@ -17,6 +17,7 @@
 | 
			
		||||
          type="radio"
 | 
			
		||||
          name="function-bar"
 | 
			
		||||
          id="2"
 | 
			
		||||
          :checked="checkID === 2"
 | 
			
		||||
          @change="handleTabChange"
 | 
			
		||||
        />
 | 
			
		||||
        <VideoIcon class="icon" />
 | 
			
		||||
@@ -27,6 +28,7 @@
 | 
			
		||||
          type="radio"
 | 
			
		||||
          name="function-bar"
 | 
			
		||||
          id="3"
 | 
			
		||||
          :checked="checkID === 3"
 | 
			
		||||
          @change="handleTabChange"
 | 
			
		||||
        />
 | 
			
		||||
        <SquareActivityIcon class="icon" />
 | 
			
		||||
@@ -37,6 +39,7 @@
 | 
			
		||||
          type="radio"
 | 
			
		||||
          name="function-bar"
 | 
			
		||||
          id="4"
 | 
			
		||||
          :checked="checkID === 4"
 | 
			
		||||
          @change="handleTabChange"
 | 
			
		||||
        />
 | 
			
		||||
        <Zap class="icon" />
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@
 | 
			
		||||
          <Zap class="w-5 h-5" />
 | 
			
		||||
          逻辑信号分析
 | 
			
		||||
        </h2>
 | 
			
		||||
        <LogicalWaveFormDisplay :data="generateTestLogicData()" />
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
@@ -37,7 +38,13 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { Zap, Settings, Layers } from "lucide-vue-next";
 | 
			
		||||
import { useEquipments } from "@/stores/equipments";
 | 
			
		||||
import { 
 | 
			
		||||
  LogicalWaveFormDisplay, 
 | 
			
		||||
  generateTestLogicData,
 | 
			
		||||
  TriggerSettings,
 | 
			
		||||
  ChannelConfig 
 | 
			
		||||
} from "@/components/LogicAnalyzer";
 | 
			
		||||
 | 
			
		||||
// 使用全局设备配置
 | 
			
		||||
const equipments = useEquipments();
 | 
			
		||||
</script>
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user