├── .gitignore ├── 3dmodel ├── Bottom.stl ├── Top.stl ├── sg90-2.scad ├── sg90-2.stl ├── sg90.scad └── sg90.stl ├── README.md ├── board ├── .gitignore ├── include │ └── README ├── lib │ └── README ├── platformio.ini ├── src │ ├── action.h │ ├── app_httpd.cpp │ ├── camera_index.h │ ├── camera_pins.h │ └── main.cpp └── test │ └── README ├── image ├── ESP32-CAM-CONNECTION.png ├── ESP32-CAM.png ├── circuit.sketch ├── product.jpg └── v1.1.0.png └── servers ├── .gitignore ├── build-linux.sh ├── build.sh ├── go.mod ├── go.sum ├── html ├── client.html └── uploader.html ├── src ├── main.go └── socket │ ├── action.go │ ├── client.go │ ├── hub.go │ ├── uploader.go │ └── wscore.go ├── start.sh └── stop.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea -------------------------------------------------------------------------------- /3dmodel/Bottom.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guohuanwen/esp32-cam/75d955c908edf3ded0384bde639c9907d97fd5f9/3dmodel/Bottom.stl -------------------------------------------------------------------------------- /3dmodel/Top.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guohuanwen/esp32-cam/75d955c908edf3ded0384bde639c9907d97fd5f9/3dmodel/Top.stl -------------------------------------------------------------------------------- /3dmodel/sg90-2.scad: -------------------------------------------------------------------------------- 1 | //精度 2 | $fs=0.5; 3 | $fa=0.5; 4 | 5 | // 长22.6mm 宽12.4 高15.5,线宽3.5mm 6 | //孔 5mm 7 | space=0.5; 8 | sgLength=22.6 + space; 9 | sgWidth=12.6 + space; 10 | sgHeight=15.5 + space; 11 | lineWidth=3.5; 12 | board=1; 13 | cube([sgLength + board *2, sgWidth + board * 2, 1]); 14 | cube([sgLength + board *2, 1, 10]); 15 | 16 | 17 | bracketSpace=2;//支撑间隔 18 | bracketHeight=15;//支撑高度 19 | bracketWidth=sgWidth + board * 2;//支撑宽度 20 | bracketHole=5/2;//孔半径 21 | holeHeight=6;//孔到盒子距离 22 | transX=(sgLength)/2 + board; 23 | holeBoard=1; 24 | translate([transX + 0, 0, -bracketHeight]) { 25 | difference() { 26 | translate([0, sgWidth/2 + board, 12]) { 27 | cube([holeBoard, bracketWidth, bracketHeight/2], center=true); 28 | } 29 | translate([0, sgWidth/2 + board, holeHeight]) rotate([0, 90, 0]) { 30 | cylinder(h=10, r1= bracketHole, r2= bracketHole, center=true, cy= 1); 31 | } 32 | } 33 | difference() { 34 | translate([0, sgWidth/2 + board, bracketHeight/2]) rotate([0, 90, 0]) { 35 | cylinder(h=holeBoard, r1= bracketWidth/2, r2= bracketWidth/2, center=true, cy= 1); 36 | } 37 | translate([0, sgWidth/2 + board, holeHeight]) rotate([0, 90, 0]) { 38 | cylinder(h=10, r1= bracketHole, r2= bracketHole, center=true, cy= 1); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /3dmodel/sg90-2.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guohuanwen/esp32-cam/75d955c908edf3ded0384bde639c9907d97fd5f9/3dmodel/sg90-2.stl -------------------------------------------------------------------------------- /3dmodel/sg90.scad: -------------------------------------------------------------------------------- 1 | //精度 2 | $fs=0.5; 3 | $fa=0.5; 4 | 5 | // 长22.6mm 宽12.4 高15.5,线宽3.5mm 6 | //孔 5mm 7 | space=0.5; 8 | sgLength=22.6 + space; 9 | sgWidth=12.6 + space; 10 | sgHeight=15.5 + space; 11 | lineWidth=3.5; 12 | board=1; 13 | cube([sgLength + board *2, sgWidth + board * 2, 1]); 14 | cube([sgLength + board *2, 1, sgHeight + board * 2]); 15 | translate([0, sgWidth + board, 0]) { 16 | cube([sgLength + board *2, 1, sgHeight + board * 2]); 17 | } 18 | cube([1, sgWidth + board * 2, sgHeight + board * 2]); 19 | 20 | difference(){ 21 | translate([sgLength + board, 0, 0]) { 22 | cube([1, sgWidth + board * 2, sgHeight + board * 2]); 23 | } 24 | translate([sgLength, (sgWidth - lineWidth)/2 + board, 0]) { 25 | cube([3, lineWidth, sgHeight + board * 3]); 26 | } 27 | } 28 | 29 | 30 | 31 | bracketSpace=2;//支撑间隔 32 | bracketHeight=15;//支撑高度 33 | bracketWidth=sgWidth + board * 2;//支撑宽度 34 | bracketHole=5/2;//孔半径 35 | holeHeight=6;//孔到盒子距离 36 | transX=(sgLength - bracketSpace)/2; 37 | translate([transX + 0, 0, -bracketHeight]) { 38 | difference() { 39 | translate([0, sgWidth/2 + board, 12]) { 40 | cube([board, bracketWidth, bracketHeight/2], center=true); 41 | } 42 | translate([0, sgWidth/2 + board, holeHeight]) rotate([0, 90, 0]) { 43 | cylinder(h=10, r1= bracketHole, r2= bracketHole, center=true, cy= 1); 44 | } 45 | } 46 | difference() { 47 | translate([0, sgWidth/2 + board, bracketHeight/2]) rotate([0, 90, 0]) { 48 | cylinder(h=board, r1= bracketWidth/2, r2= bracketWidth/2, center=true, cy= 1); 49 | } 50 | translate([0, sgWidth/2 + board, holeHeight]) rotate([0, 90, 0]) { 51 | cylinder(h=10, r1= bracketHole, r2= bracketHole, center=true, cy= 1); 52 | } 53 | } 54 | } 55 | translate([transX + bracketSpace + board, 0, -bracketHeight]) { 56 | difference() { 57 | translate([0, sgWidth/2 + board, 12]) { 58 | cube([board, bracketWidth, bracketHeight/2], center=true); 59 | } 60 | translate([0, sgWidth/2 + board, holeHeight]) rotate([0, 90, 0]) { 61 | cylinder(h=10, r1= bracketHole, r2= bracketHole, center=true, cy= 1); 62 | } 63 | } 64 | difference() { 65 | translate([0, sgWidth/2 + board, bracketHeight/2]) rotate([0, 90, 0]) { 66 | cylinder(h=board, r1= bracketWidth/2, r2= bracketWidth/2, center=true, cy= 1); 67 | } 68 | translate([0, sgWidth/2 + board, holeHeight]) rotate([0, 90, 0]) { 69 | cylinder(h=10, r1= bracketHole, r2= bracketHole, center=true, cy= 1); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /3dmodel/sg90.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guohuanwen/esp32-cam/75d955c908edf3ded0384bde639c9907d97fd5f9/3dmodel/sg90.stl -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # esp32-cam 2 | 基于esp32-cam的一个项目 3 | ![image1](./image/product.jpg) 4 | ## 功能 5 | + 本地监控 ✅ 6 | + 远程监控 ✅ 7 | + 摄像头旋转 ✅ 8 | + 远程操控 ✅ 9 | + Client界面优化 ❌ 10 | + 帧率优化 ❌ 11 | + 服务端数据缓冲 12 | + H5数据缓冲 13 | 14 | ## 目录结构 15 | + 3dmodel 16 | + 3D模型,整体框架连接与固定 17 | + board 18 | + 开发板相关代码 19 | + servers 20 | + 服务器相关代码 21 | 22 | ## 材料 23 | + ESP32-CAM 开发版 24 | + USB TO TTL下载器 25 | + 舵机(SG90) 26 | + 电源(5V 2A) 27 | + 我直接用普通手机充电器代替 28 | + 耗材若干 29 | + 如果没有3D打印机,整体框架可用胶水固定 30 | 31 | ## 开发工具 32 | ### ESP32开发 33 | + PlatformIO 34 | + https://docs.platformio.org/en/latest/core/installation.html 35 | + CLion 2020.3 36 | + https://www.jetbrains.com/clion/ 37 | + 安装插件 platformio 38 | ### 服务端开发(go) 39 | + IntelliJ IDEA 2019.3.3 40 | ### 模型 41 | + OpenSCAD(建模) 42 | + Ultimaker Cura (切片) 43 | 44 | ## 使用 45 | ### Clone整个项目 46 | ```Shell 47 | git clone https://github.com/guohuanwen/esp32-cam.git 48 | ``` 49 | ### 运行服务器 50 | 项目分两种运行方式,主要区别是部署服务器在本地局域网还是远程机器上。 51 | ```Shell 52 | # 需要安装GO环境 53 | cd ./esp32-cam/servers 54 | bash start.sh 55 | ``` 56 | #### 局域网运行 57 | 服务端部署在局域网内的一台电脑上,由于在局域网内,视频数据上传下载更快,帧数更加稳定,但是只能与单片机在同一个Wi-Fi环境下使用。 58 | #### 远程运行 59 | 服务端部署在阿里云\腾讯云的机器上,受限于网络,帧数不稳定,服务器也需要成本,但是可以任何地方使用。 60 | ### 配置ESP32-Cam,编译并上传 61 | + ./esp32-cam/board/src 目录下新建config.h文件,文件内容如下 62 | ```c 63 | //配置你的wifi名称和密码,配置2.4G的WIFI 64 | #define WIFI_NAME "xxx" 65 | #define WIFI_PASSWORD "xxxx" 66 | //本地运行填写路由器给电脑分配的IP,远程运行填写服务器IP 67 | #define WEBSOCKET_HOST "192.168.1.101" 68 | //服务对应的端口 69 | #define WEBSOCKET_PORT 8080 70 | //视频流的socket地址,一般不用更改 71 | #define WEBSOCKET_URL "/camera/uploader/ws" 72 | ``` 73 | ### 编译项目 74 | ### 接线 75 | + ESP32-CAM 引脚 76 | ![image1](./image/ESP32-CAM.png) 77 | + ESP32-CAM 调试接线 78 | ![image2](./image/ESP32-CAM-CONNECTION.png) 79 | + V1.1.0版本 接线 80 | ![image2](./image/v1.1.0.png) 81 | | 电源 | ESP32-Cam | 舵机(SG90) | 82 | | :-: | :-: | :-: | 83 | | 5V | 5V | 5V | 84 | | GND | GND | GND | 85 | | | GPIO12 | Singal | 86 | ### 上传源码到ESP32-Cam 87 | ### 查看日志 88 | ```Shell 89 | #terminal 执行 90 | platformio device monitor 91 | ``` 92 | 如果看到下面日志,则说明以上流程走通了 93 | ``` 94 | [WSc] Connected to url: xxxx 95 | ``` 96 | ### 视频访问 97 | 浏览器打开 http://${服务端IP}/camera/client 98 | 99 | ## 技术点 100 | + 3D建模 101 | + 3D打印 102 | + Golang 103 | + Arduino/Esp32 104 | + Websocket 105 | + Html/JavaScript -------------------------------------------------------------------------------- /board/.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | CMakeLists.txt 3 | CMakeListsPrivate.txt 4 | cmake-build-*/ 5 | /src/config.h 6 | .idea 7 | .vscode -------------------------------------------------------------------------------- /board/include/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project header files. 3 | 4 | A header file is a file containing C declarations and macro definitions 5 | to be shared between several project source files. You request the use of a 6 | header file in your project source file (C, C++, etc) located in `src` folder 7 | by including it, with the C preprocessing directive `#include'. 8 | 9 | ```src/main.c 10 | 11 | #include "header.h" 12 | 13 | int main (void) 14 | { 15 | ... 16 | } 17 | ``` 18 | 19 | Including a header file produces the same results as copying the header file 20 | into each source file that needs it. Such copying would be time-consuming 21 | and error-prone. With a header file, the related declarations appear 22 | in only one place. If they need to be changed, they can be changed in one 23 | place, and programs that include the header file will automatically use the 24 | new version when next recompiled. The header file eliminates the labor of 25 | finding and changing all the copies as well as the risk that a failure to 26 | find one copy will result in inconsistencies within a program. 27 | 28 | In C, the usual convention is to give header files names that end with `.h'. 29 | It is most portable to use only letters, digits, dashes, and underscores in 30 | header file names, and at most one dot. 31 | 32 | Read more about using header files in official GCC documentation: 33 | 34 | * Include Syntax 35 | * Include Operation 36 | * Once-Only Headers 37 | * Computed Includes 38 | 39 | https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html 40 | -------------------------------------------------------------------------------- /board/lib/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link into executable file. 4 | 5 | The source code of each library should be placed in a an own separate directory 6 | ("lib/your_library_name/[here are source files]"). 7 | 8 | For example, see a structure of the following two libraries `Foo` and `Bar`: 9 | 10 | |--lib 11 | | | 12 | | |--Bar 13 | | | |--docs 14 | | | |--examples 15 | | | |--src 16 | | | |- Bar.c 17 | | | |- Bar.h 18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html 19 | | | 20 | | |--Foo 21 | | | |- Foo.c 22 | | | |- Foo.h 23 | | | 24 | | |- README --> THIS FILE 25 | | 26 | |- platformio.ini 27 | |--src 28 | |- main.c 29 | 30 | and a contents of `src/main.c`: 31 | ``` 32 | #include 33 | #include 34 | 35 | int main (void) 36 | { 37 | ... 38 | } 39 | 40 | ``` 41 | 42 | PlatformIO Library Dependency Finder will find automatically dependent 43 | libraries scanning project source files. 44 | 45 | More information about PlatformIO Library Dependency Finder 46 | - https://docs.platformio.org/page/librarymanager/ldf.html 47 | -------------------------------------------------------------------------------- /board/platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [env:esp32doit-devkit-v1] 12 | platform = espressif32 13 | board = esp32cam 14 | framework = arduino 15 | monitor_speed = 115200 16 | 17 | lib_deps = 18 | links2004/WebSockets @ 2.3.6 19 | madhephaestus/ESP32Servo @ 0.9.0 -------------------------------------------------------------------------------- /board/src/action.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by huanwen guo on 2021/5/7. 3 | // 4 | 5 | #ifndef BOARD_ACTION_H 6 | #define BOARD_ACTION_H 7 | #define ACTION_OPEN_CAMERA "OpenCamera" 8 | #define ACTION_CLOSE_CAMERA "CloseCamera" 9 | #define ACTION_TURN0 "Turn0" 10 | #define ACTION_TURN90 "Turn90" 11 | #define ACTION_TURN180 "Turn180" 12 | #endif //BOARD_ACTION_H 13 | -------------------------------------------------------------------------------- /board/src/app_httpd.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #include "esp_http_server.h" 15 | #include "esp_timer.h" 16 | #include "esp_camera.h" 17 | #include "img_converters.h" 18 | #include "camera_index.h" 19 | #include "Arduino.h" 20 | 21 | #include "fb_gfx.h" 22 | #include "fd_forward.h" 23 | #include "fr_forward.h" 24 | 25 | #define ENROLL_CONFIRM_TIMES 5 26 | #define FACE_ID_SAVE_NUMBER 7 27 | 28 | #define FACE_COLOR_WHITE 0x00FFFFFF 29 | #define FACE_COLOR_BLACK 0x00000000 30 | #define FACE_COLOR_RED 0x000000FF 31 | #define FACE_COLOR_GREEN 0x0000FF00 32 | #define FACE_COLOR_BLUE 0x00FF0000 33 | #define FACE_COLOR_YELLOW (FACE_COLOR_RED | FACE_COLOR_GREEN) 34 | #define FACE_COLOR_CYAN (FACE_COLOR_BLUE | FACE_COLOR_GREEN) 35 | #define FACE_COLOR_PURPLE (FACE_COLOR_BLUE | FACE_COLOR_RED) 36 | 37 | typedef struct { 38 | size_t size; //number of values used for filtering 39 | size_t index; //current value index 40 | size_t count; //value count 41 | int sum; 42 | int * values; //array to be filled with values 43 | } ra_filter_t; 44 | 45 | typedef struct { 46 | httpd_req_t *req; 47 | size_t len; 48 | } jpg_chunking_t; 49 | 50 | #define PART_BOUNDARY "123456789000000000000987654321" 51 | static const char* _STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY; 52 | static const char* _STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n"; 53 | static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n"; 54 | 55 | static ra_filter_t ra_filter; 56 | httpd_handle_t stream_httpd = NULL; 57 | httpd_handle_t camera_httpd = NULL; 58 | 59 | static mtmn_config_t mtmn_config = {0}; 60 | static int8_t detection_enabled = 0; 61 | static int8_t recognition_enabled = 0; 62 | static int8_t is_enrolling = 0; 63 | static face_id_list id_list = {0}; 64 | 65 | static ra_filter_t * ra_filter_init(ra_filter_t * filter, size_t sample_size){ 66 | memset(filter, 0, sizeof(ra_filter_t)); 67 | 68 | filter->values = (int *)malloc(sample_size * sizeof(int)); 69 | if(!filter->values){ 70 | return NULL; 71 | } 72 | memset(filter->values, 0, sample_size * sizeof(int)); 73 | 74 | filter->size = sample_size; 75 | return filter; 76 | } 77 | 78 | static int ra_filter_run(ra_filter_t * filter, int value){ 79 | if(!filter->values){ 80 | return value; 81 | } 82 | filter->sum -= filter->values[filter->index]; 83 | filter->values[filter->index] = value; 84 | filter->sum += filter->values[filter->index]; 85 | filter->index++; 86 | filter->index = filter->index % filter->size; 87 | if (filter->count < filter->size) { 88 | filter->count++; 89 | } 90 | return filter->sum / filter->count; 91 | } 92 | 93 | static void rgb_print(dl_matrix3du_t *image_matrix, uint32_t color, const char * str){ 94 | fb_data_t fb; 95 | fb.width = image_matrix->w; 96 | fb.height = image_matrix->h; 97 | fb.data = image_matrix->item; 98 | fb.bytes_per_pixel = 3; 99 | fb.format = FB_BGR888; 100 | fb_gfx_print(&fb, (fb.width - (strlen(str) * 14)) / 2, 10, color, str); 101 | } 102 | 103 | static int rgb_printf(dl_matrix3du_t *image_matrix, uint32_t color, const char *format, ...){ 104 | char loc_buf[64]; 105 | char * temp = loc_buf; 106 | int len; 107 | va_list arg; 108 | va_list copy; 109 | va_start(arg, format); 110 | va_copy(copy, arg); 111 | len = vsnprintf(loc_buf, sizeof(loc_buf), format, arg); 112 | va_end(copy); 113 | if(len >= sizeof(loc_buf)){ 114 | temp = (char*)malloc(len+1); 115 | if(temp == NULL) { 116 | return 0; 117 | } 118 | } 119 | vsnprintf(temp, len+1, format, arg); 120 | va_end(arg); 121 | rgb_print(image_matrix, color, temp); 122 | if(len > 64){ 123 | free(temp); 124 | } 125 | return len; 126 | } 127 | 128 | static void draw_face_boxes(dl_matrix3du_t *image_matrix, box_array_t *boxes, int face_id){ 129 | int x, y, w, h, i; 130 | uint32_t color = FACE_COLOR_YELLOW; 131 | if(face_id < 0){ 132 | color = FACE_COLOR_RED; 133 | } else if(face_id > 0){ 134 | color = FACE_COLOR_GREEN; 135 | } 136 | fb_data_t fb; 137 | fb.width = image_matrix->w; 138 | fb.height = image_matrix->h; 139 | fb.data = image_matrix->item; 140 | fb.bytes_per_pixel = 3; 141 | fb.format = FB_BGR888; 142 | for (i = 0; i < boxes->len; i++){ 143 | // rectangle box 144 | x = (int)boxes->box[i].box_p[0]; 145 | y = (int)boxes->box[i].box_p[1]; 146 | w = (int)boxes->box[i].box_p[2] - x + 1; 147 | h = (int)boxes->box[i].box_p[3] - y + 1; 148 | fb_gfx_drawFastHLine(&fb, x, y, w, color); 149 | fb_gfx_drawFastHLine(&fb, x, y+h-1, w, color); 150 | fb_gfx_drawFastVLine(&fb, x, y, h, color); 151 | fb_gfx_drawFastVLine(&fb, x+w-1, y, h, color); 152 | #if 0 153 | // landmark 154 | int x0, y0, j; 155 | for (j = 0; j < 10; j+=2) { 156 | x0 = (int)boxes->landmark[i].landmark_p[j]; 157 | y0 = (int)boxes->landmark[i].landmark_p[j+1]; 158 | fb_gfx_fillRect(&fb, x0, y0, 3, 3, color); 159 | } 160 | #endif 161 | } 162 | } 163 | 164 | static int run_face_recognition(dl_matrix3du_t *image_matrix, box_array_t *net_boxes){ 165 | dl_matrix3du_t *aligned_face = NULL; 166 | int matched_id = 0; 167 | 168 | aligned_face = dl_matrix3du_alloc(1, FACE_WIDTH, FACE_HEIGHT, 3); 169 | if(!aligned_face){ 170 | Serial.println("Could not allocate face recognition buffer"); 171 | return matched_id; 172 | } 173 | if (align_face(net_boxes, image_matrix, aligned_face) == ESP_OK){ 174 | if (is_enrolling == 1){ 175 | int8_t left_sample_face = enroll_face(&id_list, aligned_face); 176 | 177 | if(left_sample_face == (ENROLL_CONFIRM_TIMES - 1)){ 178 | Serial.printf("Enrolling Face ID: %d\n", id_list.tail); 179 | } 180 | Serial.printf("Enrolling Face ID: %d sample %d\n", id_list.tail, ENROLL_CONFIRM_TIMES - left_sample_face); 181 | rgb_printf(image_matrix, FACE_COLOR_CYAN, "ID[%u] Sample[%u]", id_list.tail, ENROLL_CONFIRM_TIMES - left_sample_face); 182 | if (left_sample_face == 0){ 183 | is_enrolling = 0; 184 | Serial.printf("Enrolled Face ID: %d\n", id_list.tail); 185 | } 186 | } else { 187 | matched_id = recognize_face(&id_list, aligned_face); 188 | if (matched_id >= 0) { 189 | Serial.printf("Match Face ID: %u\n", matched_id); 190 | rgb_printf(image_matrix, FACE_COLOR_GREEN, "Hello Subject %u", matched_id); 191 | } else { 192 | Serial.println("No Match Found"); 193 | rgb_print(image_matrix, FACE_COLOR_RED, "Intruder Alert!"); 194 | matched_id = -1; 195 | } 196 | } 197 | } else { 198 | Serial.println("Face Not Aligned"); 199 | //rgb_print(image_matrix, FACE_COLOR_YELLOW, "Human Detected"); 200 | } 201 | 202 | dl_matrix3du_free(aligned_face); 203 | return matched_id; 204 | } 205 | 206 | static size_t jpg_encode_stream(void * arg, size_t index, const void* data, size_t len){ 207 | jpg_chunking_t *j = (jpg_chunking_t *)arg; 208 | if(!index){ 209 | j->len = 0; 210 | } 211 | if(httpd_resp_send_chunk(j->req, (const char *)data, len) != ESP_OK){ 212 | return 0; 213 | } 214 | j->len += len; 215 | return len; 216 | } 217 | 218 | static esp_err_t capture_handler(httpd_req_t *req){ 219 | camera_fb_t * fb = NULL; 220 | esp_err_t res = ESP_OK; 221 | int64_t fr_start = esp_timer_get_time(); 222 | 223 | fb = esp_camera_fb_get(); 224 | if (!fb) { 225 | Serial.println("Camera capture failed"); 226 | httpd_resp_send_500(req); 227 | return ESP_FAIL; 228 | } 229 | 230 | httpd_resp_set_type(req, "image/jpeg"); 231 | httpd_resp_set_hdr(req, "Content-Disposition", "inline; filename=capture.jpg"); 232 | httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); 233 | 234 | size_t out_len, out_width, out_height; 235 | uint8_t * out_buf; 236 | bool s; 237 | bool detected = false; 238 | int face_id = 0; 239 | if(!detection_enabled || fb->width > 400){ 240 | size_t fb_len = 0; 241 | if(fb->format == PIXFORMAT_JPEG){ 242 | fb_len = fb->len; 243 | res = httpd_resp_send(req, (const char *)fb->buf, fb->len); 244 | } else { 245 | jpg_chunking_t jchunk = {req, 0}; 246 | res = frame2jpg_cb(fb, 80, jpg_encode_stream, &jchunk)?ESP_OK:ESP_FAIL; 247 | httpd_resp_send_chunk(req, NULL, 0); 248 | fb_len = jchunk.len; 249 | } 250 | esp_camera_fb_return(fb); 251 | int64_t fr_end = esp_timer_get_time(); 252 | Serial.printf("JPG: %uB %ums\n", (uint32_t)(fb_len), (uint32_t)((fr_end - fr_start)/1000)); 253 | return res; 254 | } 255 | 256 | dl_matrix3du_t *image_matrix = dl_matrix3du_alloc(1, fb->width, fb->height, 3); 257 | if (!image_matrix) { 258 | esp_camera_fb_return(fb); 259 | Serial.println("dl_matrix3du_alloc failed"); 260 | httpd_resp_send_500(req); 261 | return ESP_FAIL; 262 | } 263 | 264 | out_buf = image_matrix->item; 265 | out_len = fb->width * fb->height * 3; 266 | out_width = fb->width; 267 | out_height = fb->height; 268 | 269 | s = fmt2rgb888(fb->buf, fb->len, fb->format, out_buf); 270 | esp_camera_fb_return(fb); 271 | if(!s){ 272 | dl_matrix3du_free(image_matrix); 273 | Serial.println("to rgb888 failed"); 274 | httpd_resp_send_500(req); 275 | return ESP_FAIL; 276 | } 277 | 278 | box_array_t *net_boxes = face_detect(image_matrix, &mtmn_config); 279 | 280 | if (net_boxes){ 281 | detected = true; 282 | if(recognition_enabled){ 283 | face_id = run_face_recognition(image_matrix, net_boxes); 284 | } 285 | draw_face_boxes(image_matrix, net_boxes, face_id); 286 | free(net_boxes->score); 287 | free(net_boxes->box); 288 | free(net_boxes->landmark); 289 | free(net_boxes); 290 | } 291 | 292 | jpg_chunking_t jchunk = {req, 0}; 293 | s = fmt2jpg_cb(out_buf, out_len, out_width, out_height, PIXFORMAT_RGB888, 90, jpg_encode_stream, &jchunk); 294 | dl_matrix3du_free(image_matrix); 295 | if(!s){ 296 | Serial.println("JPEG compression failed"); 297 | return ESP_FAIL; 298 | } 299 | 300 | int64_t fr_end = esp_timer_get_time(); 301 | Serial.printf("FACE: %uB %ums %s%d\n", (uint32_t)(jchunk.len), (uint32_t)((fr_end - fr_start)/1000), detected?"DETECTED ":"", face_id); 302 | return res; 303 | } 304 | 305 | static esp_err_t stream_handler(httpd_req_t *req){ 306 | camera_fb_t * fb = NULL; 307 | esp_err_t res = ESP_OK; 308 | size_t _jpg_buf_len = 0; 309 | uint8_t * _jpg_buf = NULL; 310 | char * part_buf[64]; 311 | dl_matrix3du_t *image_matrix = NULL; 312 | bool detected = false; 313 | int face_id = 0; 314 | int64_t fr_start = 0; 315 | int64_t fr_ready = 0; 316 | int64_t fr_face = 0; 317 | int64_t fr_recognize = 0; 318 | int64_t fr_encode = 0; 319 | 320 | static int64_t last_frame = 0; 321 | if(!last_frame) { 322 | last_frame = esp_timer_get_time(); 323 | } 324 | 325 | res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE); 326 | if(res != ESP_OK){ 327 | return res; 328 | } 329 | 330 | httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); 331 | 332 | while(true){ 333 | detected = false; 334 | face_id = 0; 335 | fb = esp_camera_fb_get(); 336 | if (!fb) { 337 | Serial.println("Camera capture failed"); 338 | res = ESP_FAIL; 339 | } else { 340 | fr_start = esp_timer_get_time(); 341 | fr_ready = fr_start; 342 | fr_face = fr_start; 343 | fr_encode = fr_start; 344 | fr_recognize = fr_start; 345 | if(!detection_enabled || fb->width > 400){ 346 | if(fb->format != PIXFORMAT_JPEG){ 347 | bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len); 348 | esp_camera_fb_return(fb); 349 | fb = NULL; 350 | if(!jpeg_converted){ 351 | Serial.println("JPEG compression failed"); 352 | res = ESP_FAIL; 353 | } 354 | } else { 355 | _jpg_buf_len = fb->len; 356 | _jpg_buf = fb->buf; 357 | } 358 | } else { 359 | 360 | image_matrix = dl_matrix3du_alloc(1, fb->width, fb->height, 3); 361 | 362 | if (!image_matrix) { 363 | Serial.println("dl_matrix3du_alloc failed"); 364 | res = ESP_FAIL; 365 | } else { 366 | if(!fmt2rgb888(fb->buf, fb->len, fb->format, image_matrix->item)){ 367 | Serial.println("fmt2rgb888 failed"); 368 | res = ESP_FAIL; 369 | } else { 370 | fr_ready = esp_timer_get_time(); 371 | box_array_t *net_boxes = NULL; 372 | if(detection_enabled){ 373 | net_boxes = face_detect(image_matrix, &mtmn_config); 374 | } 375 | fr_face = esp_timer_get_time(); 376 | fr_recognize = fr_face; 377 | if (net_boxes || fb->format != PIXFORMAT_JPEG){ 378 | if(net_boxes){ 379 | detected = true; 380 | if(recognition_enabled){ 381 | face_id = run_face_recognition(image_matrix, net_boxes); 382 | } 383 | fr_recognize = esp_timer_get_time(); 384 | draw_face_boxes(image_matrix, net_boxes, face_id); 385 | free(net_boxes->score); 386 | free(net_boxes->box); 387 | free(net_boxes->landmark); 388 | free(net_boxes); 389 | } 390 | if(!fmt2jpg(image_matrix->item, fb->width*fb->height*3, fb->width, fb->height, PIXFORMAT_RGB888, 90, &_jpg_buf, &_jpg_buf_len)){ 391 | Serial.println("fmt2jpg failed"); 392 | res = ESP_FAIL; 393 | } 394 | esp_camera_fb_return(fb); 395 | fb = NULL; 396 | } else { 397 | _jpg_buf = fb->buf; 398 | _jpg_buf_len = fb->len; 399 | } 400 | fr_encode = esp_timer_get_time(); 401 | } 402 | dl_matrix3du_free(image_matrix); 403 | } 404 | } 405 | } 406 | if(res == ESP_OK){ 407 | res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY)); 408 | } 409 | if(res == ESP_OK){ 410 | size_t hlen = snprintf((char *)part_buf, 64, _STREAM_PART, _jpg_buf_len); 411 | res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen); 412 | } 413 | if(res == ESP_OK){ 414 | res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len); 415 | } 416 | if(fb){ 417 | esp_camera_fb_return(fb); 418 | fb = NULL; 419 | _jpg_buf = NULL; 420 | } else if(_jpg_buf){ 421 | free(_jpg_buf); 422 | _jpg_buf = NULL; 423 | } 424 | if(res != ESP_OK){ 425 | break; 426 | } 427 | int64_t fr_end = esp_timer_get_time(); 428 | 429 | int64_t ready_time = (fr_ready - fr_start)/1000; 430 | int64_t face_time = (fr_face - fr_ready)/1000; 431 | int64_t recognize_time = (fr_recognize - fr_face)/1000; 432 | int64_t encode_time = (fr_encode - fr_recognize)/1000; 433 | int64_t process_time = (fr_encode - fr_start)/1000; 434 | 435 | int64_t frame_time = fr_end - last_frame; 436 | last_frame = fr_end; 437 | frame_time /= 1000; 438 | uint32_t avg_frame_time = ra_filter_run(&ra_filter, frame_time); 439 | Serial.printf("MJPG: %uB %ums (%.1ffps), AVG: %ums (%.1ffps), %u+%u+%u+%u=%u %s%d\n", 440 | (uint32_t)(_jpg_buf_len), 441 | (uint32_t)frame_time, 1000.0 / (uint32_t)frame_time, 442 | avg_frame_time, 1000.0 / avg_frame_time, 443 | (uint32_t)ready_time, (uint32_t)face_time, (uint32_t)recognize_time, (uint32_t)encode_time, (uint32_t)process_time, 444 | (detected)?"DETECTED ":"", face_id 445 | ); 446 | } 447 | 448 | last_frame = 0; 449 | return res; 450 | } 451 | 452 | static esp_err_t cmd_handler(httpd_req_t *req){ 453 | char* buf; 454 | size_t buf_len; 455 | char variable[32] = {0,}; 456 | char value[32] = {0,}; 457 | 458 | buf_len = httpd_req_get_url_query_len(req) + 1; 459 | if (buf_len > 1) { 460 | buf = (char*)malloc(buf_len); 461 | if(!buf){ 462 | httpd_resp_send_500(req); 463 | return ESP_FAIL; 464 | } 465 | if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) { 466 | if (httpd_query_key_value(buf, "var", variable, sizeof(variable)) == ESP_OK && 467 | httpd_query_key_value(buf, "val", value, sizeof(value)) == ESP_OK) { 468 | } else { 469 | free(buf); 470 | httpd_resp_send_404(req); 471 | return ESP_FAIL; 472 | } 473 | } else { 474 | free(buf); 475 | httpd_resp_send_404(req); 476 | return ESP_FAIL; 477 | } 478 | free(buf); 479 | } else { 480 | httpd_resp_send_404(req); 481 | return ESP_FAIL; 482 | } 483 | 484 | int val = atoi(value); 485 | sensor_t * s = esp_camera_sensor_get(); 486 | int res = 0; 487 | 488 | if(!strcmp(variable, "framesize")) { 489 | if(s->pixformat == PIXFORMAT_JPEG) res = s->set_framesize(s, (framesize_t)val); 490 | } 491 | else if(!strcmp(variable, "quality")) res = s->set_quality(s, val); 492 | else if(!strcmp(variable, "contrast")) res = s->set_contrast(s, val); 493 | else if(!strcmp(variable, "brightness")) res = s->set_brightness(s, val); 494 | else if(!strcmp(variable, "saturation")) res = s->set_saturation(s, val); 495 | else if(!strcmp(variable, "gainceiling")) res = s->set_gainceiling(s, (gainceiling_t)val); 496 | else if(!strcmp(variable, "colorbar")) res = s->set_colorbar(s, val); 497 | else if(!strcmp(variable, "awb")) res = s->set_whitebal(s, val); 498 | else if(!strcmp(variable, "agc")) res = s->set_gain_ctrl(s, val); 499 | else if(!strcmp(variable, "aec")) res = s->set_exposure_ctrl(s, val); 500 | else if(!strcmp(variable, "hmirror")) res = s->set_hmirror(s, val); 501 | else if(!strcmp(variable, "vflip")) res = s->set_vflip(s, val); 502 | else if(!strcmp(variable, "awb_gain")) res = s->set_awb_gain(s, val); 503 | else if(!strcmp(variable, "agc_gain")) res = s->set_agc_gain(s, val); 504 | else if(!strcmp(variable, "aec_value")) res = s->set_aec_value(s, val); 505 | else if(!strcmp(variable, "aec2")) res = s->set_aec2(s, val); 506 | else if(!strcmp(variable, "dcw")) res = s->set_dcw(s, val); 507 | else if(!strcmp(variable, "bpc")) res = s->set_bpc(s, val); 508 | else if(!strcmp(variable, "wpc")) res = s->set_wpc(s, val); 509 | else if(!strcmp(variable, "raw_gma")) res = s->set_raw_gma(s, val); 510 | else if(!strcmp(variable, "lenc")) res = s->set_lenc(s, val); 511 | else if(!strcmp(variable, "special_effect")) res = s->set_special_effect(s, val); 512 | else if(!strcmp(variable, "wb_mode")) res = s->set_wb_mode(s, val); 513 | else if(!strcmp(variable, "ae_level")) res = s->set_ae_level(s, val); 514 | else if(!strcmp(variable, "face_detect")) { 515 | detection_enabled = val; 516 | if(!detection_enabled) { 517 | recognition_enabled = 0; 518 | } 519 | } 520 | else if(!strcmp(variable, "face_enroll")) is_enrolling = val; 521 | else if(!strcmp(variable, "face_recognize")) { 522 | recognition_enabled = val; 523 | if(recognition_enabled){ 524 | detection_enabled = val; 525 | } 526 | } 527 | else { 528 | res = -1; 529 | } 530 | 531 | if(res){ 532 | return httpd_resp_send_500(req); 533 | } 534 | 535 | httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); 536 | return httpd_resp_send(req, NULL, 0); 537 | } 538 | 539 | static esp_err_t status_handler(httpd_req_t *req){ 540 | static char json_response[1024]; 541 | 542 | sensor_t * s = esp_camera_sensor_get(); 543 | char * p = json_response; 544 | *p++ = '{'; 545 | 546 | p+=sprintf(p, "\"framesize\":%u,", s->status.framesize); 547 | p+=sprintf(p, "\"quality\":%u,", s->status.quality); 548 | p+=sprintf(p, "\"brightness\":%d,", s->status.brightness); 549 | p+=sprintf(p, "\"contrast\":%d,", s->status.contrast); 550 | p+=sprintf(p, "\"saturation\":%d,", s->status.saturation); 551 | p+=sprintf(p, "\"sharpness\":%d,", s->status.sharpness); 552 | p+=sprintf(p, "\"special_effect\":%u,", s->status.special_effect); 553 | p+=sprintf(p, "\"wb_mode\":%u,", s->status.wb_mode); 554 | p+=sprintf(p, "\"awb\":%u,", s->status.awb); 555 | p+=sprintf(p, "\"awb_gain\":%u,", s->status.awb_gain); 556 | p+=sprintf(p, "\"aec\":%u,", s->status.aec); 557 | p+=sprintf(p, "\"aec2\":%u,", s->status.aec2); 558 | p+=sprintf(p, "\"ae_level\":%d,", s->status.ae_level); 559 | p+=sprintf(p, "\"aec_value\":%u,", s->status.aec_value); 560 | p+=sprintf(p, "\"agc\":%u,", s->status.agc); 561 | p+=sprintf(p, "\"agc_gain\":%u,", s->status.agc_gain); 562 | p+=sprintf(p, "\"gainceiling\":%u,", s->status.gainceiling); 563 | p+=sprintf(p, "\"bpc\":%u,", s->status.bpc); 564 | p+=sprintf(p, "\"wpc\":%u,", s->status.wpc); 565 | p+=sprintf(p, "\"raw_gma\":%u,", s->status.raw_gma); 566 | p+=sprintf(p, "\"lenc\":%u,", s->status.lenc); 567 | p+=sprintf(p, "\"vflip\":%u,", s->status.vflip); 568 | p+=sprintf(p, "\"hmirror\":%u,", s->status.hmirror); 569 | p+=sprintf(p, "\"dcw\":%u,", s->status.dcw); 570 | p+=sprintf(p, "\"colorbar\":%u,", s->status.colorbar); 571 | p+=sprintf(p, "\"face_detect\":%u,", detection_enabled); 572 | p+=sprintf(p, "\"face_enroll\":%u,", is_enrolling); 573 | p+=sprintf(p, "\"face_recognize\":%u", recognition_enabled); 574 | *p++ = '}'; 575 | *p++ = 0; 576 | httpd_resp_set_type(req, "application/json"); 577 | httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); 578 | return httpd_resp_send(req, json_response, strlen(json_response)); 579 | } 580 | 581 | static esp_err_t index_handler(httpd_req_t *req){ 582 | httpd_resp_set_type(req, "text/html"); 583 | httpd_resp_set_hdr(req, "Content-Encoding", "gzip"); 584 | sensor_t * s = esp_camera_sensor_get(); 585 | if (s->id.PID == OV3660_PID) { 586 | return httpd_resp_send(req, (const char *)index_ov3660_html_gz, index_ov3660_html_gz_len); 587 | } 588 | return httpd_resp_send(req, (const char *)index_ov2640_html_gz, index_ov2640_html_gz_len); 589 | } 590 | 591 | void startCameraServer(){ 592 | httpd_config_t config = HTTPD_DEFAULT_CONFIG(); 593 | 594 | httpd_uri_t index_uri = { 595 | .uri = "/", 596 | .method = HTTP_GET, 597 | .handler = index_handler, 598 | .user_ctx = NULL 599 | }; 600 | 601 | httpd_uri_t status_uri = { 602 | .uri = "/status", 603 | .method = HTTP_GET, 604 | .handler = status_handler, 605 | .user_ctx = NULL 606 | }; 607 | 608 | httpd_uri_t cmd_uri = { 609 | .uri = "/control", 610 | .method = HTTP_GET, 611 | .handler = cmd_handler, 612 | .user_ctx = NULL 613 | }; 614 | 615 | httpd_uri_t capture_uri = { 616 | .uri = "/capture", 617 | .method = HTTP_GET, 618 | .handler = capture_handler, 619 | .user_ctx = NULL 620 | }; 621 | 622 | httpd_uri_t stream_uri = { 623 | .uri = "/stream", 624 | .method = HTTP_GET, 625 | .handler = stream_handler, 626 | .user_ctx = NULL 627 | }; 628 | 629 | 630 | ra_filter_init(&ra_filter, 20); 631 | 632 | mtmn_config.type = FAST; 633 | mtmn_config.min_face = 80; 634 | mtmn_config.pyramid = 0.707; 635 | mtmn_config.pyramid_times = 4; 636 | mtmn_config.p_threshold.score = 0.6; 637 | mtmn_config.p_threshold.nms = 0.7; 638 | mtmn_config.p_threshold.candidate_number = 20; 639 | mtmn_config.r_threshold.score = 0.7; 640 | mtmn_config.r_threshold.nms = 0.7; 641 | mtmn_config.r_threshold.candidate_number = 10; 642 | mtmn_config.o_threshold.score = 0.7; 643 | mtmn_config.o_threshold.nms = 0.7; 644 | mtmn_config.o_threshold.candidate_number = 1; 645 | 646 | face_id_init(&id_list, FACE_ID_SAVE_NUMBER, ENROLL_CONFIRM_TIMES); 647 | 648 | Serial.printf("Starting web server on port: '%d'\n", config.server_port); 649 | if (httpd_start(&camera_httpd, &config) == ESP_OK) { 650 | httpd_register_uri_handler(camera_httpd, &index_uri); 651 | httpd_register_uri_handler(camera_httpd, &cmd_uri); 652 | httpd_register_uri_handler(camera_httpd, &status_uri); 653 | httpd_register_uri_handler(camera_httpd, &capture_uri); 654 | } 655 | 656 | config.server_port += 1; 657 | config.ctrl_port += 1; 658 | Serial.printf("Starting stream server on port: '%d'\n", config.server_port); 659 | if (httpd_start(&stream_httpd, &config) == ESP_OK) { 660 | httpd_register_uri_handler(stream_httpd, &stream_uri); 661 | } 662 | } 663 | -------------------------------------------------------------------------------- /board/src/camera_index.h: -------------------------------------------------------------------------------- 1 | 2 | //File: index_ov2640.html.gz, Size: 4316 3 | #define index_ov2640_html_gz_len 4316 4 | const uint8_t index_ov2640_html_gz[] = { 5 | 0x1F, 0x8B, 0x08, 0x08, 0x50, 0x5C, 0xAE, 0x5C, 0x00, 0x03, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x5F, 6 | 0x6F, 0x76, 0x32, 0x36, 0x34, 0x30, 0x2E, 0x68, 0x74, 0x6D, 0x6C, 0x00, 0xE5, 0x5D, 0x7B, 0x73, 7 | 0xD3, 0xC6, 0x16, 0xFF, 0x9F, 0x4F, 0x21, 0x04, 0x25, 0xF6, 0x34, 0x76, 0x6C, 0xC7, 0x84, 0xE0, 8 | 0xDA, 0xE2, 0x42, 0x08, 0xD0, 0x19, 0x5E, 0x25, 0x2D, 0x74, 0xA6, 0xD3, 0x81, 0xB5, 0xB4, 0xB2, 9 | 0x55, 0x64, 0xC9, 0x95, 0x56, 0x76, 0x52, 0x26, 0x9F, 0xE3, 0x7E, 0xA0, 0xFB, 0xC5, 0xEE, 0xD9, 10 | 0x87, 0xA4, 0x95, 0xBC, 0x7A, 0xD8, 0x26, 0x36, 0x97, 0xEB, 0xCC, 0x14, 0xD9, 0xDA, 0x73, 0xF6, 11 | 0x9C, 0xF3, 0x3B, 0xAF, 0x5D, 0x3D, 0x3A, 0xBC, 0x6D, 0xF9, 0x26, 0xB9, 0x9A, 0x63, 0x6D, 0x4A, 12 | 0x66, 0xAE, 0x71, 0x6B, 0xC8, 0xFF, 0xD1, 0xE0, 0x33, 0x9C, 0x62, 0x64, 0xF1, 0x43, 0xF6, 0x75, 13 | 0x86, 0x09, 0xD2, 0xCC, 0x29, 0x0A, 0x42, 0x4C, 0x46, 0x7A, 0x44, 0xEC, 0xD6, 0xA9, 0x9E, 0x3F, 14 | 0xED, 0xA1, 0x19, 0x1E, 0xE9, 0x0B, 0x07, 0x2F, 0xE7, 0x7E, 0x40, 0x74, 0xCD, 0xF4, 0x3D, 0x82, 15 | 0x3D, 0x18, 0xBE, 0x74, 0x2C, 0x32, 0x1D, 0x59, 0x78, 0xE1, 0x98, 0xB8, 0xC5, 0xBE, 0x1C, 0x3A, 16 | 0x9E, 0x43, 0x1C, 0xE4, 0xB6, 0x42, 0x13, 0xB9, 0x78, 0xD4, 0x95, 0x79, 0x11, 0x87, 0xB8, 0xD8, 17 | 0x38, 0xBF, 0x78, 0x7B, 0xDC, 0xD3, 0xDE, 0xBC, 0xEF, 0xF5, 0x4F, 0x3A, 0xC3, 0x23, 0xFE, 0x5B, 18 | 0x3A, 0x26, 0x24, 0x57, 0xF2, 0x77, 0xFA, 0x19, 0xFB, 0xD6, 0x95, 0xF6, 0x25, 0xF3, 0x13, 0xFD, 19 | 0xD8, 0x20, 0x44, 0xCB, 0x46, 0x33, 0xC7, 0xBD, 0x1A, 0x68, 0x8F, 0x03, 0x98, 0xF3, 0xF0, 0x05, 20 | 0x76, 0x17, 0x98, 0x38, 0x26, 0x3A, 0x0C, 0x91, 0x17, 0xB6, 0x42, 0x1C, 0x38, 0xF6, 0x4F, 0x2B, 21 | 0x84, 0x63, 0x64, 0x7E, 0x9E, 0x04, 0x7E, 0xE4, 0x59, 0x03, 0xED, 0x4E, 0xF7, 0x94, 0xFE, 0xAD, 22 | 0x0E, 0x32, 0x7D, 0xD7, 0x0F, 0xE0, 0xFC, 0xF9, 0x33, 0xFA, 0xB7, 0x7A, 0x9E, 0xCD, 0x1E, 0x3A, 23 | 0xFF, 0xE0, 0x81, 0xD6, 0x3D, 0x99, 0x5F, 0x66, 0xCE, 0x5F, 0xDF, 0xCA, 0x7C, 0x9D, 0xF6, 0x8A, 24 | 0xA4, 0x17, 0xF4, 0xA7, 0xE5, 0xF4, 0x21, 0x36, 0x89, 0xE3, 0x7B, 0xED, 0x19, 0x72, 0x3C, 0x05, 25 | 0x27, 0xCB, 0x09, 0xE7, 0x2E, 0x02, 0x1B, 0xD8, 0x2E, 0x2E, 0xE5, 0x73, 0x67, 0x86, 0xBD, 0xE8, 26 | 0xB0, 0x82, 0x1B, 0x65, 0xD2, 0xB2, 0x9C, 0x80, 0x8F, 0x1A, 0x50, 0x3B, 0x44, 0x33, 0xAF, 0x92, 27 | 0x6D, 0x99, 0x5C, 0x9E, 0xEF, 0x61, 0x85, 0x01, 0xE9, 0x44, 0xCB, 0x00, 0xCD, 0xE9, 0x00, 0xFA, 28 | 0xEF, 0xEA, 0x90, 0x99, 0xE3, 0x71, 0xA7, 0x1A, 0x68, 0xC7, 0xFD, 0xCE, 0xFC, 0xB2, 0x02, 0xCA, 29 | 0xE3, 0x13, 0xFA, 0xB7, 0x3A, 0x68, 0x8E, 0x2C, 0xCB, 0xF1, 0x26, 0x03, 0xED, 0x54, 0xC9, 0xC2, 30 | 0x0F, 0x2C, 0x1C, 0xB4, 0x02, 0x64, 0x39, 0x51, 0x38, 0xD0, 0xFA, 0xAA, 0x31, 0x33, 0x14, 0x4C, 31 | 0x40, 0x16, 0xE2, 0x83, 0xB0, 0xAD, 0xAE, 0x52, 0x12, 0x31, 0x24, 0x70, 0x26, 0x53, 0x02, 0x90, 32 | 0xAE, 0x8C, 0xC9, 0x1B, 0x4D, 0x84, 0x50, 0x15, 0x9E, 0xA5, 0x76, 0x53, 0x5B, 0x0D, 0xB9, 0xCE, 33 | 0xC4, 0x6B, 0x39, 0x04, 0xCF, 0x40, 0x9D, 0x90, 0x04, 0x98, 0x98, 0xD3, 0x32, 0x51, 0x6C, 0x67, 34 | 0x12, 0x05, 0x58, 0x21, 0x48, 0x62, 0xB7, 0x12, 0x85, 0xE1, 0xE4, 0xEA, 0xA9, 0xD6, 0x12, 0x8F, 35 | 0x3F, 0x3B, 0xA4, 0x25, 0x6C, 0x32, 0xC6, 0xB6, 0x1F, 0x60, 0xE5, 0xC8, 0x78, 0x84, 0xEB, 0x9B, 36 | 0x9F, 0x5B, 0x21, 0x41, 0x01, 0xA9, 0xC3, 0x10, 0xD9, 0x04, 0x07, 0xD5, 0xFC, 0x30, 0xF5, 0x8A, 37 | 0x6A, 0x6E, 0xC5, 0xD3, 0x8A, 0x01, 0x8E, 0xE7, 0x3A, 0x1E, 0xAE, 0x2F, 0x5E, 0xD1, 0xBC, 0x59, 38 | 0x76, 0x7C, 0x54, 0x0D, 0x60, 0x9C, 0xD9, 0xA4, 0xCC, 0x4B, 0x98, 0xAE, 0xAB, 0x93, 0x89, 0xB8, 39 | 0xE9, 0x76, 0x3A, 0x3F, 0xAC, 0x9E, 0x9C, 0x62, 0xEE, 0xA6, 0x28, 0x22, 0xFE, 0xF6, 0x11, 0xB1, 40 | 0x12, 0x56, 0x39, 0x3D, 0xFE, 0x35, 0xC3, 0x96, 0x83, 0xB4, 0x86, 0x14, 0xCE, 0xA7, 0x1D, 0xF0, 41 | 0xA9, 0xA6, 0x86, 0x3C, 0x4B, 0x6B, 0xF8, 0x81, 0x03, 0x81, 0x80, 0x58, 0xBA, 0x71, 0xE1, 0x17, 42 | 0x28, 0x1C, 0x73, 0xDC, 0x54, 0xA8, 0x5C, 0x12, 0x33, 0xB2, 0x45, 0xD4, 0x61, 0x43, 0x3F, 0x35, 43 | 0x52, 0x0E, 0xFD, 0x54, 0x06, 0x90, 0x42, 0x47, 0xC6, 0xBE, 0x0C, 0x2F, 0x59, 0xC2, 0x22, 0xCC, 44 | 0xE8, 0x67, 0x86, 0x2E, 0x5B, 0xA5, 0xD8, 0xC5, 0x83, 0x62, 0x0C, 0xA1, 0xCC, 0x9A, 0x0D, 0x18, 45 | 0xBA, 0x98, 0x6A, 0x2D, 0x8D, 0x66, 0xC9, 0xA6, 0x9A, 0x46, 0x30, 0x55, 0x43, 0x4E, 0x3F, 0xB2, 46 | 0x53, 0xAC, 0xA1, 0xAE, 0x5A, 0xD5, 0x34, 0x77, 0xF0, 0x3F, 0x95, 0x0F, 0x71, 0x4D, 0x0A, 0xB3, 47 | 0x08, 0xFD, 0xD4, 0xCF, 0x24, 0x29, 0xB3, 0xCA, 0x6C, 0xA2, 0x60, 0x5C, 0x9C, 0x51, 0x56, 0xF8, 48 | 0x16, 0x45, 0xB7, 0x82, 0x6B, 0xB9, 0x08, 0x75, 0xB3, 0x8B, 0x82, 0x71, 0x99, 0x0C, 0x95, 0x59, 49 | 0x86, 0x7E, 0xAE, 0x6B, 0xF4, 0x1B, 0x77, 0xC6, 0x11, 0x21, 0xBE, 0x17, 0x6E, 0x55, 0xA2, 0x8A, 50 | 0xE2, 0xEC, 0xAF, 0x28, 0x24, 0x8E, 0x7D, 0xD5, 0x12, 0x21, 0x0D, 0x71, 0x36, 0x47, 0xD0, 0x42, 51 | 0x8E, 0x31, 0x59, 0x62, 0x5C, 0xDE, 0x6E, 0x78, 0x68, 0x01, 0x79, 0x67, 0x32, 0x71, 0x55, 0xBE, 52 | 0x67, 0x46, 0x41, 0x48, 0xFB, 0xB6, 0xB9, 0xEF, 0x00, 0xE3, 0x60, 0x75, 0xE2, 0x6C, 0x0C, 0xD6, 53 | 0x9C, 0xA8, 0x65, 0x8E, 0x15, 0x73, 0xF9, 0x11, 0xA1, 0x36, 0x56, 0x22, 0xE1, 0x83, 0x3A, 0x0E, 54 | 0xB9, 0x52, 0x9E, 0x13, 0x91, 0xA8, 0x38, 0x13, 0x87, 0x60, 0x69, 0x59, 0xC8, 0xCA, 0x35, 0x30, 55 | 0xA7, 0xD8, 0xFC, 0x8C, 0xAD, 0x1F, 0x2B, 0xDB, 0xB0, 0xAA, 0xF6, 0xB0, 0xED, 0x78, 0xF3, 0x88, 56 | 0xB4, 0x68, 0x3B, 0x35, 0xBF, 0x11, 0xCC, 0x99, 0x43, 0xC6, 0x2A, 0xF6, 0x7A, 0x65, 0x4D, 0xC5, 57 | 0xFD, 0xF9, 0x65, 0xB9, 0x11, 0x64, 0x61, 0x0D, 0x17, 0x8D, 0xB1, 0x5B, 0x26, 0xB2, 0x08, 0x86, 58 | 0x82, 0xB4, 0x2B, 0x72, 0x55, 0x71, 0xEF, 0xC6, 0x24, 0x4B, 0x8B, 0x57, 0xFF, 0xC1, 0x0F, 0xB5, 59 | 0xED, 0xC8, 0x8E, 0x0F, 0x33, 0x3F, 0x85, 0xD8, 0x85, 0x00, 0x2B, 0x6A, 0xBD, 0x61, 0xCC, 0x12, 60 | 0x64, 0x28, 0x9D, 0x20, 0x40, 0xDE, 0x04, 0x43, 0x2E, 0xB8, 0x3C, 0x8C, 0x0F, 0xCB, 0x17, 0x06, 61 | 0xB5, 0xD4, 0xA7, 0xA9, 0xFA, 0x7E, 0xF9, 0x42, 0x84, 0x27, 0x84, 0x0D, 0x9A, 0x11, 0x09, 0xD6, 62 | 0xD2, 0xF9, 0xBB, 0x4A, 0xA7, 0xE0, 0xFD, 0x88, 0x32, 0x60, 0xB2, 0x2E, 0xA5, 0xEC, 0xEF, 0x2B, 63 | 0x33, 0x42, 0xBC, 0xD2, 0xB3, 0xED, 0xAA, 0xB5, 0xA2, 0x6D, 0x1F, 0x77, 0x8E, 0xFB, 0x95, 0x0D, 64 | 0x93, 0x52, 0xCB, 0xDC, 0x7A, 0x51, 0x91, 0x31, 0x92, 0x6C, 0x52, 0x0D, 0xC1, 0x60, 0xEA, 0x2F, 65 | 0x70, 0xA0, 0x00, 0x22, 0x27, 0x6E, 0xFF, 0x61, 0xDF, 0xAA, 0xC1, 0x0D, 0x41, 0xBE, 0x5F, 0xA8, 66 | 0xB2, 0x69, 0x96, 0x5D, 0xAF, 0x6B, 0xF6, 0x4A, 0x1D, 0x93, 0xB3, 0x6B, 0x83, 0x37, 0xA0, 0xB1, 67 | 0x8B, 0xAD, 0x92, 0xF4, 0x6C, 0x61, 0x1B, 0x45, 0x2E, 0xA9, 0xB0, 0x37, 0xEA, 0xD0, 0xBF, 0xB2, 68 | 0x19, 0x59, 0x5C, 0xFD, 0x41, 0x37, 0x3A, 0x46, 0x2C, 0x12, 0xFE, 0x54, 0xCC, 0x19, 0xD7, 0x4E, 69 | 0x34, 0x9F, 0x63, 0x04, 0xA3, 0x4C, 0x5C, 0xB4, 0x24, 0xAD, 0xD5, 0x33, 0xAB, 0x13, 0x57, 0xAD, 70 | 0x85, 0x68, 0xA5, 0x2B, 0x26, 0xDD, 0xD0, 0x5A, 0x3A, 0x0F, 0x6C, 0xDF, 0x8C, 0x54, 0x65, 0xBA, 71 | 0x9E, 0x4B, 0xAD, 0xF2, 0x1B, 0xC4, 0x26, 0x0B, 0x5D, 0x87, 0x39, 0x76, 0xE4, 0x79, 0x14, 0xD1, 72 | 0x16, 0x09, 0x40, 0x4D, 0xC5, 0x44, 0xF5, 0x0C, 0xB7, 0x51, 0x74, 0x66, 0x0C, 0x5B, 0xB4, 0x19, 73 | 0x93, 0x0B, 0x40, 0x45, 0xA2, 0x48, 0x72, 0x88, 0x16, 0xFA, 0xA0, 0x54, 0xCC, 0x6A, 0x3B, 0xBB, 74 | 0x90, 0x69, 0x34, 0x53, 0x35, 0x06, 0xF1, 0x64, 0x5D, 0xA8, 0x62, 0x7C, 0xBA, 0x60, 0x32, 0x46, 75 | 0x8D, 0xCE, 0x61, 0xE7, 0xF0, 0x18, 0xFE, 0xA3, 0x68, 0xD0, 0xCB, 0x9D, 0x4B, 0x98, 0xB7, 0xC0, 76 | 0xF3, 0x72, 0xC9, 0xA7, 0x7A, 0x9F, 0xA4, 0x28, 0x8D, 0x55, 0x62, 0x51, 0x3F, 0x92, 0xB2, 0x1B, 77 | 0x26, 0xDD, 0x76, 0x45, 0x61, 0x29, 0x70, 0xE9, 0xF5, 0x1D, 0x51, 0xE1, 0x2D, 0xEB, 0x42, 0x3C, 78 | 0xF3, 0xFF, 0x69, 0xF1, 0xAA, 0xFA, 0x7F, 0xEF, 0xED, 0x92, 0x29, 0xBE, 0x6B, 0x4F, 0x5F, 0xDB, 79 | 0x2E, 0xE1, 0xBE, 0x7D, 0xA3, 0x53, 0x8C, 0x7A, 0x4B, 0xF4, 0x33, 0x20, 0xA1, 0x07, 0x8B, 0xAA, 80 | 0x00, 0x56, 0x57, 0x85, 0x3D, 0x8F, 0x34, 0x66, 0x03, 0x1B, 0xD8, 0x8E, 0xEB, 0xB6, 0x5C, 0x7F, 81 | 0x59, 0xDD, 0x89, 0x94, 0x7B, 0xF2, 0x8A, 0x9F, 0x56, 0xBB, 0xFC, 0xA6, 0xD2, 0x46, 0x90, 0xB9, 82 | 0xFE, 0x27, 0xA4, 0xFD, 0xBE, 0x03, 0xAE, 0x34, 0x34, 0x36, 0x2B, 0x14, 0x1B, 0xF8, 0xE3, 0x76, 83 | 0x13, 0xD5, 0x72, 0x25, 0xDE, 0x09, 0x96, 0x2E, 0xE6, 0xC2, 0xA5, 0x43, 0xCC, 0xE9, 0x06, 0x8B, 84 | 0xAA, 0xB9, 0x1F, 0x3A, 0xFC, 0x1A, 0x4D, 0x80, 0x5D, 0x44, 0x3B, 0xF8, 0x8D, 0x96, 0xDC, 0x95, 85 | 0x0B, 0x13, 0x99, 0xBC, 0x8E, 0x26, 0xCC, 0x74, 0xDF, 0xCE, 0x76, 0x49, 0x9B, 0xF7, 0x0E, 0xC5, 86 | 0xB9, 0x5A, 0xED, 0xD6, 0x15, 0xED, 0x7E, 0x36, 0x32, 0xD4, 0x83, 0xD6, 0xC8, 0xE8, 0x71, 0xD2, 87 | 0x9E, 0x04, 0xF8, 0xAA, 0x86, 0x32, 0x87, 0xE2, 0xDF, 0x01, 0xDF, 0x10, 0xDD, 0x7C, 0xED, 0xCF, 88 | 0x0A, 0x80, 0xF0, 0xA2, 0x76, 0x3F, 0xAC, 0x31, 0x75, 0xF1, 0x94, 0x75, 0xFC, 0x31, 0xD9, 0xEE, 89 | 0xD3, 0xF5, 0x1A, 0xE9, 0xA6, 0xA4, 0x84, 0xAA, 0x5D, 0x35, 0xAE, 0xBE, 0xCA, 0x93, 0x2E, 0xB6, 90 | 0x49, 0xC1, 0xD5, 0x0C, 0xD6, 0xA7, 0x1E, 0x97, 0x67, 0xB7, 0x96, 0xB4, 0x4F, 0x50, 0x99, 0x39, 91 | 0x92, 0x5D, 0xB9, 0x62, 0xEF, 0x53, 0x72, 0xA6, 0xD9, 0x73, 0x6D, 0xE6, 0xC5, 0x90, 0xC4, 0xED, 92 | 0x33, 0x83, 0x19, 0xC6, 0xCC, 0x44, 0xC9, 0x07, 0x78, 0xF0, 0xEF, 0x8D, 0xDE, 0x89, 0xF2, 0x62, 93 | 0x41, 0xC9, 0xE0, 0x32, 0xD1, 0x0A, 0xB7, 0xB5, 0x56, 0x4B, 0x56, 0xE1, 0x02, 0x59, 0xCE, 0x45, 94 | 0x4A, 0xA0, 0xCA, 0xA3, 0xB2, 0x2C, 0xC3, 0xAC, 0xEE, 0xD1, 0x94, 0x3A, 0xBB, 0x33, 0x43, 0xD0, 95 | 0xF6, 0x52, 0x77, 0x45, 0xC0, 0x51, 0x85, 0x5F, 0x1D, 0x77, 0x97, 0x36, 0x0D, 0xBB, 0x27, 0x9D, 96 | 0x8A, 0x29, 0x4D, 0xD7, 0x0F, 0xCB, 0xE3, 0x0A, 0x8D, 0xC1, 0x7E, 0x11, 0x51, 0x4C, 0x24, 0xB6, 97 | 0x2E, 0x95, 0x3B, 0x4F, 0xCC, 0xB9, 0x95, 0x67, 0x6A, 0x95, 0xEE, 0xD2, 0x98, 0x2A, 0x0F, 0xC7, 98 | 0x9C, 0xCD, 0xBB, 0x1D, 0x65, 0xA6, 0x2D, 0xDD, 0x7F, 0x23, 0xF8, 0x12, 0xD6, 0x9B, 0xF4, 0x82, 99 | 0xDC, 0x40, 0x33, 0xB1, 0x3A, 0x8D, 0x66, 0x8A, 0x5C, 0xB7, 0xCE, 0x26, 0x60, 0x29, 0x0E, 0x53, 100 | 0xC7, 0xB2, 0x70, 0xE9, 0x2E, 0x27, 0x5D, 0xF3, 0xE6, 0x58, 0xC4, 0x47, 0xC3, 0x23, 0xE9, 0x06, 101 | 0x96, 0xE1, 0x51, 0x7A, 0xAF, 0xCD, 0x90, 0xDE, 0xC5, 0x22, 0xDF, 0xE7, 0xC2, 0x2F, 0xB2, 0x68, 102 | 0xA6, 0x8B, 0xC2, 0x70, 0xA4, 0xD3, 0xBB, 0x31, 0xF4, 0xEC, 0x6D, 0x2F, 0x43, 0xCB, 0x59, 0x68, 103 | 0x8E, 0x35, 0xD2, 0x5D, 0x7F, 0xE2, 0xE7, 0xCE, 0xB1, 0xF3, 0x7C, 0xDB, 0x1B, 0x22, 0x75, 0xA4, 104 | 0x67, 0x2E, 0x09, 0xE8, 0x8C, 0x2A, 0xFD, 0x49, 0x37, 0xEE, 0xDD, 0x79, 0xF8, 0xE0, 0xC1, 0xC9, 105 | 0x4F, 0xF7, 0xBC, 0x71, 0x38, 0x17, 0xFF, 0xFD, 0x95, 0x5F, 0x41, 0x79, 0xF3, 0xBE, 0x77, 0xD2, 106 | 0x87, 0x86, 0x16, 0x13, 0xE2, 0x78, 0x93, 0x70, 0x78, 0xC4, 0x98, 0xE6, 0x04, 0x39, 0x02, 0x49, 107 | 0x0A, 0x64, 0x13, 0x09, 0x5D, 0x25, 0x5E, 0x3C, 0x24, 0x84, 0x1C, 0x35, 0x46, 0x81, 0x62, 0x08, 108 | 0x1B, 0xC6, 0xDB, 0x05, 0xD6, 0x69, 0xE9, 0x2C, 0xB1, 0x8D, 0xFD, 0xCB, 0xBC, 0x06, 0x4C, 0x29, 109 | 0x91, 0xF5, 0xC4, 0x28, 0x6C, 0x15, 0x31, 0x04, 0x32, 0x46, 0x4E, 0xAF, 0x87, 0x14, 0x8C, 0x49, 110 | 0xE4, 0x13, 0xD6, 0x97, 0xB6, 0xE7, 0xF9, 0xD4, 0x76, 0x80, 0x66, 0x98, 0x26, 0x22, 0xF1, 0x63, 111 | 0x31, 0x9B, 0x3C, 0x12, 0x09, 0xA5, 0x6E, 0xBC, 0xC3, 0x2C, 0x5C, 0x01, 0x65, 0xA5, 0x59, 0x57, 112 | 0xB8, 0x88, 0x0C, 0x9A, 0x99, 0x5F, 0x8F, 0x45, 0x14, 0x3B, 0xA6, 0x2D, 0xC4, 0xDC, 0xA6, 0x42, 113 | 0x20, 0xC6, 0xCE, 0x9F, 0x33, 0x07, 0x5B, 0x20, 0x37, 0x02, 0xD3, 0x76, 0x3B, 0xBA, 0xF1, 0xDB, 114 | 0xEF, 0xCF, 0x1F, 0x37, 0x20, 0x11, 0x75, 0x2E, 0xBB, 0xBD, 0x4E, 0xA7, 0x39, 0x3C, 0xE2, 0x43, 115 | 0xD6, 0xE6, 0xF5, 0x50, 0x37, 0x2E, 0x18, 0xAB, 0xDE, 0x29, 0xB0, 0xEA, 0xF4, 0xFA, 0x9B, 0xB3, 116 | 0x3A, 0xD5, 0x0D, 0xC6, 0x09, 0x98, 0x5C, 0x3E, 0x38, 0x39, 0xDD, 0x9C, 0xD1, 0x03, 0x90, 0xE9, 117 | 0x3D, 0x70, 0x3A, 0x05, 0xED, 0x4E, 0xB6, 0x51, 0xEE, 0x44, 0x37, 0x28, 0x1F, 0x88, 0x8A, 0xCB, 118 | 0xFE, 0xE9, 0x16, 0x7C, 0xEE, 0xEB, 0xA2, 0x24, 0x52, 0x97, 0x8D, 0x8F, 0x74, 0xE3, 0xEC, 0xE7, 119 | 0x67, 0x8D, 0x3E, 0xC8, 0xD8, 0x7B, 0x78, 0xB2, 0x39, 0xEF, 0xBE, 0x6E, 0xFC, 0x42, 0x85, 0x3C, 120 | 0xEE, 0x01, 0xA3, 0xFE, 0x16, 0x42, 0x1E, 0xEB, 0xC6, 0x0B, 0xC6, 0x09, 0xB8, 0x5C, 0x76, 0x1F, 121 | 0x6C, 0x21, 0x12, 0xB8, 0xD7, 0x2F, 0x8C, 0x13, 0xF8, 0x17, 0x75, 0xAF, 0x9A, 0x9C, 0x20, 0x5F, 122 | 0x32, 0xD3, 0x94, 0xC4, 0xE9, 0x6A, 0xF6, 0xC9, 0x9C, 0x2E, 0x0B, 0xE3, 0xBF, 0x23, 0x28, 0x1D, 123 | 0xE4, 0x6A, 0xED, 0x20, 0x16, 0x74, 0xA0, 0x12, 0x3F, 0xA8, 0x17, 0xBF, 0x92, 0x24, 0xC9, 0x65, 124 | 0x39, 0xDD, 0xE8, 0x76, 0x2A, 0x34, 0x60, 0xB4, 0x72, 0x16, 0x64, 0xC4, 0x19, 0x05, 0x74, 0xDA, 125 | 0x49, 0xB0, 0x18, 0xA6, 0xB7, 0x7E, 0x80, 0x8F, 0x1E, 0xEB, 0x52, 0x5C, 0x6F, 0x94, 0x22, 0x14, 126 | 0xD2, 0xA2, 0x4B, 0xDD, 0x38, 0x39, 0xAE, 0xB2, 0xF7, 0x16, 0x70, 0x8C, 0x59, 0x9B, 0xE2, 0xE1, 127 | 0x30, 0x5C, 0x1B, 0x91, 0x94, 0x54, 0x37, 0x9E, 0x24, 0xC7, 0xDB, 0xE0, 0xD2, 0xEA, 0x6D, 0x81, 128 | 0x8B, 0x24, 0x0E, 0x87, 0xA6, 0xD5, 0x13, 0xD0, 0xF4, 0xF4, 0x34, 0x22, 0xBE, 0x26, 0x30, 0x55, 129 | 0xD2, 0x6E, 0x83, 0x0B, 0x2D, 0xE2, 0x01, 0x0A, 0xC9, 0xDA, 0xA8, 0xC4, 0x84, 0x90, 0xD6, 0xC4, 130 | 0xD1, 0xDE, 0x10, 0x49, 0x44, 0xF9, 0x0E, 0xF0, 0x08, 0x11, 0x89, 0x02, 0x76, 0x43, 0xDC, 0xDA, 131 | 0x88, 0xA4, 0xA4, 0x50, 0x0F, 0x93, 0xE3, 0xBD, 0xA1, 0x22, 0x89, 0xF3, 0x3D, 0xE0, 0x32, 0xC7, 132 | 0xA6, 0x83, 0xDC, 0x8F, 0xD8, 0xB6, 0xA1, 0x64, 0xAD, 0x8F, 0x4D, 0x86, 0x1C, 0xF0, 0xE1, 0xDF, 133 | 0xB5, 0x73, 0xF6, 0x7D, 0xED, 0x1E, 0x31, 0xC7, 0xEE, 0x6B, 0x35, 0x8A, 0x1D, 0x75, 0xDF, 0xF2, 134 | 0xDA, 0x4F, 0xE4, 0xDC, 0xB0, 0x43, 0xE8, 0x02, 0x13, 0x3C, 0x61, 0x2B, 0xE5, 0x8D, 0x79, 0xF4, 135 | 0x74, 0xE3, 0x79, 0x80, 0xAE, 0xD8, 0xB3, 0x05, 0xDB, 0x34, 0x3D, 0xEF, 0xB0, 0xA5, 0xFD, 0x0A, 136 | 0x4B, 0xC1, 0x6D, 0x3A, 0xB0, 0xE7, 0x01, 0x86, 0x65, 0xE2, 0x56, 0x5C, 0xEE, 0x43, 0x31, 0x83, 137 | 0x83, 0xED, 0x98, 0x40, 0xC3, 0x7A, 0x81, 0xE7, 0x0E, 0xFA, 0x16, 0x1A, 0x2E, 0xB4, 0x1C, 0xAF, 138 | 0x1D, 0x16, 0x40, 0xA3, 0x1B, 0x8F, 0x3F, 0x3C, 0x59, 0x3B, 0x49, 0xF1, 0xFD, 0xE6, 0x3A, 0x1E, 139 | 0xCE, 0xB3, 0x93, 0x10, 0x50, 0x5F, 0x59, 0x6C, 0xAA, 0x23, 0xA7, 0xEE, 0x82, 0x53, 0xA1, 0x57, 140 | 0x2C, 0x20, 0xDB, 0x9E, 0xD3, 0x25, 0x35, 0xEB, 0xE9, 0x78, 0x73, 0x19, 0x0C, 0x84, 0xF8, 0x38, 141 | 0x41, 0xCE, 0xFA, 0x75, 0x25, 0x26, 0x64, 0x48, 0x69, 0xCF, 0xE1, 0x68, 0x57, 0x70, 0xF1, 0x69, 142 | 0xF7, 0x86, 0x99, 0xD0, 0x7A, 0xDF, 0xC0, 0x81, 0x20, 0x33, 0xDF, 0x5A, 0x7F, 0x3B, 0x42, 0xD0, 143 | 0xE9, 0x06, 0xA0, 0xF6, 0x0A, 0x0E, 0xD6, 0xAE, 0x32, 0x31, 0x83, 0x1B, 0x2E, 0x2F, 0x8F, 0x23, 144 | 0xE2, 0x6F, 0x53, 0x59, 0x2E, 0x22, 0xCF, 0xBB, 0xDA, 0xA6, 0xAC, 0x9C, 0xB9, 0x7E, 0x64, 0x6D, 145 | 0xCE, 0x01, 0x6A, 0xCA, 0x1B, 0xDB, 0x76, 0xCC, 0xCD, 0xAB, 0x12, 0x54, 0x94, 0x17, 0xFE, 0xAC, 146 | 0x26, 0xFD, 0x0D, 0x67, 0x71, 0x6C, 0xAE, 0x9F, 0x20, 0xB0, 0x09, 0x28, 0x9E, 0x9F, 0x69, 0x17, 147 | 0xE7, 0xAF, 0x2F, 0xDE, 0xBC, 0xDB, 0x4D, 0x76, 0x80, 0x39, 0xF7, 0x94, 0x18, 0xA8, 0xB6, 0xFB, 148 | 0xCE, 0x09, 0x20, 0x44, 0x6F, 0x13, 0x9C, 0x7A, 0x1C, 0xA8, 0xA7, 0x17, 0x6F, 0x77, 0x85, 0x52, 149 | 0x6F, 0x7F, 0x30, 0xF5, 0xBE, 0x05, 0x9C, 0x3E, 0xBA, 0x78, 0x81, 0xDD, 0x0D, 0xB0, 0xE2, 0x84, 150 | 0x14, 0x2F, 0xED, 0x25, 0x3D, 0xDA, 0xDB, 0x42, 0x2E, 0x11, 0xE5, 0x3B, 0x58, 0xC6, 0x81, 0x57, 151 | 0x7C, 0x64, 0x42, 0x6F, 0x12, 0x3C, 0x9C, 0x52, 0x37, 0xCE, 0x2F, 0xE7, 0x7E, 0x18, 0x05, 0x35, 152 | 0x0B, 0xAA, 0x1A, 0x91, 0x6D, 0x76, 0x06, 0x53, 0x51, 0x38, 0x22, 0xF1, 0xD6, 0x20, 0xDD, 0xD9, 153 | 0x4F, 0x30, 0xE9, 0x75, 0xFA, 0x5F, 0x15, 0x15, 0xCA, 0xFC, 0x26, 0x81, 0x99, 0x6C, 0x50, 0x77, 154 | 0x26, 0xB4, 0xEE, 0x3C, 0x3F, 0xDB, 0x4D, 0x2A, 0x9B, 0xEC, 0xAD, 0xE0, 0x4C, 0xF6, 0x5A, 0x70, 155 | 0x34, 0x7E, 0x51, 0x34, 0x81, 0x69, 0xC3, 0x45, 0x84, 0x20, 0x84, 0xB5, 0xF3, 0x26, 0x0B, 0x08, 156 | 0x79, 0x53, 0xFD, 0x72, 0x9B, 0xD0, 0x89, 0xC5, 0xC8, 0x46, 0xCE, 0x71, 0x1A, 0x37, 0xF7, 0xBF, 157 | 0x6A, 0xD4, 0x1C, 0x57, 0x4A, 0xBB, 0x4D, 0xD0, 0x50, 0x4D, 0x4C, 0xEC, 0xB8, 0xF4, 0x09, 0xA6, 158 | 0x75, 0x01, 0x91, 0x68, 0x39, 0x26, 0xDA, 0x19, 0xFF, 0xB6, 0x0D, 0x36, 0xBD, 0x6D, 0xB0, 0x91, 159 | 0x25, 0xCA, 0xC2, 0x73, 0x72, 0x43, 0x95, 0xA6, 0xDB, 0x3B, 0xBD, 0x49, 0x78, 0xC6, 0xF3, 0xF5, 160 | 0x73, 0x1A, 0xD0, 0xE8, 0xC6, 0x93, 0xB7, 0xBB, 0xC9, 0x69, 0x74, 0xB2, 0x9A, 0x39, 0x6D, 0xAB, 161 | 0x0C, 0xC6, 0x94, 0xDA, 0x77, 0x2B, 0xB6, 0xDC, 0x00, 0x8D, 0x25, 0x15, 0xFC, 0xC3, 0x8E, 0xD0, 162 | 0x58, 0xD6, 0x47, 0xE3, 0x2B, 0x57, 0x98, 0xE5, 0xB7, 0x80, 0x4F, 0x80, 0x96, 0x1F, 0x27, 0x33, 163 | 0xB4, 0x36, 0x46, 0x82, 0x4E, 0x37, 0xDE, 0xA1, 0xA5, 0xF6, 0xFC, 0xD5, 0xE3, 0x9D, 0x60, 0x15, 164 | 0x4F, 0xBA, 0x1F, 0xBC, 0x12, 0x95, 0xF7, 0x8D, 0x99, 0x8B, 0xBD, 0xF5, 0x83, 0x8A, 0x12, 0xE9, 165 | 0xC6, 0x4B, 0xEC, 0x85, 0xDA, 0x99, 0x1F, 0x88, 0xB7, 0xCD, 0xEC, 0x04, 0x35, 0x36, 0xF3, 0x7E, 166 | 0x20, 0xE3, 0x4A, 0xEF, 0x1B, 0xAF, 0xE9, 0xCC, 0x09, 0x02, 0x3F, 0x58, 0x1B, 0x32, 0x41, 0xA7, 167 | 0x1B, 0x2F, 0x5A, 0xAF, 0xD8, 0xD1, 0x4E, 0xE0, 0x8A, 0x67, 0xDD, 0x0F, 0x62, 0x89, 0xCE, 0xFB, 168 | 0x06, 0x6D, 0x61, 0xBB, 0xCE, 0x7C, 0x6D, 0xC8, 0x18, 0x95, 0x6E, 0xBC, 0x6F, 0x3D, 0x83, 0x7F, 169 | 0x77, 0x02, 0x17, 0x9F, 0x71, 0x3F, 0x60, 0x09, 0x6D, 0xF7, 0x0D, 0x95, 0x65, 0x2E, 0xD7, 0x06, 170 | 0x0A, 0x68, 0x74, 0xE3, 0xE9, 0xD9, 0x07, 0xAD, 0xF1, 0xD4, 0x5F, 0x7A, 0xF4, 0xC6, 0x3F, 0xED, 171 | 0xFC, 0x75, 0x73, 0x27, 0x88, 0xD1, 0xA9, 0xF7, 0x83, 0x17, 0x53, 0x7A, 0xDF, 0x68, 0xB1, 0xBB, 172 | 0x8F, 0xC7, 0x68, 0xFD, 0x74, 0x18, 0x13, 0xD2, 0x7B, 0x5F, 0xE0, 0x48, 0x7B, 0x82, 0x76, 0x93, 173 | 0x10, 0x93, 0x79, 0x77, 0xD1, 0xB4, 0xA7, 0x4A, 0xEE, 0x1B, 0x27, 0x1B, 0x99, 0xF8, 0xA3, 0x85, 174 | 0xC9, 0x26, 0x37, 0x5E, 0x48, 0xB4, 0xBA, 0xF1, 0x0C, 0xBE, 0x68, 0x4F, 0xD9, 0x97, 0x5D, 0xB5, 175 | 0x1C, 0xF2, 0xFC, 0xBB, 0x40, 0x2D, 0xA3, 0xEF, 0x37, 0x01, 0x1C, 0x34, 0x78, 0xFE, 0xC4, 0xDB, 176 | 0xE8, 0x7E, 0xEA, 0x0C, 0xB9, 0x80, 0xEF, 0x1D, 0xFF, 0xBE, 0x5B, 0x00, 0x53, 0x21, 0x76, 0x86, 177 | 0xA1, 0xA4, 0xF7, 0x2E, 0x60, 0x8C, 0x9F, 0x49, 0x60, 0xDB, 0x02, 0xFC, 0xE5, 0x4F, 0x55, 0x48, 178 | 0x89, 0x57, 0xC2, 0xB0, 0xAD, 0x1B, 0x4C, 0x5A, 0x21, 0x71, 0x5C, 0x57, 0x37, 0x9E, 0x63, 0xA2, 179 | 0x5D, 0xD0, 0xC3, 0xE1, 0x11, 0x1F, 0x50, 0x9F, 0x8B, 0xB8, 0xE1, 0x9F, 0xBE, 0x76, 0x0D, 0xCD, 180 | 0x74, 0xE3, 0x82, 0xBE, 0x16, 0x0B, 0x78, 0xD1, 0x6F, 0xEB, 0x33, 0x63, 0x46, 0xC4, 0x5E, 0xE0, 181 | 0x83, 0x50, 0x09, 0x48, 0xE2, 0xED, 0x24, 0xBA, 0x16, 0x1F, 0x49, 0xBF, 0x19, 0xE7, 0x6C, 0xB0, 182 | 0x46, 0xBD, 0xAC, 0x7A, 0x3A, 0x7A, 0x15, 0xD6, 0x2C, 0xBE, 0x58, 0x3B, 0x3C, 0xF2, 0x90, 0xC2, 183 | 0xDC, 0x05, 0x28, 0x0C, 0xF9, 0xFB, 0xD4, 0x0A, 0x58, 0x25, 0x0F, 0x53, 0x30, 0x4B, 0xA4, 0x0F, 184 | 0x26, 0x25, 0x6A, 0xE5, 0x1F, 0x58, 0x12, 0x1B, 0xB6, 0xF5, 0x82, 0x96, 0x3D, 0x7A, 0x24, 0xEA, 185 | 0x21, 0x3D, 0x4C, 0xCC, 0xFF, 0x9F, 0x7F, 0x57, 0xF9, 0x0C, 0x7D, 0xDB, 0x5D, 0x2A, 0x98, 0xAE, 186 | 0x85, 0x81, 0x39, 0xD2, 0x8B, 0x1E, 0xCD, 0x28, 0xD0, 0xFC, 0x48, 0xA5, 0x7A, 0x6E, 0xB0, 0xC2, 187 | 0xD6, 0xC3, 0xD0, 0x0C, 0x9C, 0x39, 0x31, 0x6E, 0x59, 0xBE, 0x19, 0xCD, 0xB0, 0x47, 0xDA, 0xC8, 188 | 0xB2, 0xCE, 0x17, 0x70, 0xF0, 0xD2, 0x09, 0x09, 0x06, 0x2B, 0x34, 0x0E, 0x9E, 0xBE, 0x79, 0x75, 189 | 0xC6, 0x1F, 0x51, 0x79, 0xE9, 0x23, 0x0B, 0x5B, 0x07, 0x87, 0x9A, 0x1D, 0x79, 0xDC, 0xCD, 0x1B, 190 | 0x98, 0x8E, 0xE5, 0x6F, 0x1A, 0x5C, 0xA0, 0x40, 0x1B, 0xA3, 0x10, 0xBF, 0xF0, 0x43, 0xA2, 0x8D, 191 | 0xB4, 0x84, 0xA3, 0xEB, 0x9B, 0xEC, 0xF6, 0xC5, 0xB6, 0x1F, 0x38, 0x13, 0xC7, 0x13, 0x23, 0xB9, 192 | 0xB2, 0xBF, 0x05, 0x2E, 0x0C, 0x4D, 0xA8, 0x7E, 0xD4, 0x0E, 0x06, 0xA7, 0xDD, 0x03, 0xFA, 0x34, 193 | 0x11, 0xC0, 0x00, 0x3F, 0x00, 0x04, 0x18, 0x06, 0x40, 0x80, 0x8F, 0x0C, 0xF1, 0x38, 0x11, 0x76, 194 | 0xDB, 0xCC, 0xE4, 0x54, 0x40, 0x2A, 0x6D, 0xE3, 0x80, 0xE3, 0x74, 0x40, 0x1F, 0xAD, 0xBB, 0x4E, 195 | 0x28, 0xC3, 0xA9, 0xBF, 0x2C, 0xA3, 0x0C, 0xF0, 0xCC, 0x5F, 0xE0, 0x1C, 0x71, 0x42, 0x2D, 0xBC, 196 | 0xB9, 0x72, 0xEA, 0xD8, 0xEB, 0x0F, 0x9A, 0xF1, 0x80, 0xE4, 0xCD, 0x3D, 0x23, 0x8D, 0x04, 0x11, 197 | 0xCE, 0xB2, 0xC5, 0x5E, 0x15, 0xD7, 0x58, 0xAC, 0x52, 0xC6, 0x36, 0x72, 0xC3, 0x1C, 0xE7, 0x68, 198 | 0x6E, 0x21, 0x82, 0xDF, 0xD3, 0xDD, 0x5D, 0x18, 0xD0, 0xC0, 0xEE, 0x21, 0xDF, 0xEA, 0x3D, 0x14, 199 | 0x67, 0xDE, 0x01, 0x5F, 0x82, 0x9B, 0xE9, 0xAC, 0xF2, 0xCF, 0x40, 0x91, 0xFD, 0x3A, 0xD2, 0xBC, 200 | 0x08, 0x42, 0xF8, 0x11, 0x53, 0x41, 0x1B, 0x64, 0xCE, 0x32, 0x6A, 0x17, 0xB2, 0x93, 0x78, 0x4B, 201 | 0x31, 0x9B, 0x93, 0xFD, 0xE8, 0xD8, 0x74, 0xE2, 0x36, 0x7B, 0x67, 0xF2, 0x08, 0x78, 0x1C, 0xC4, 202 | 0xD9, 0xFD, 0x20, 0x7D, 0x15, 0xA5, 0x4C, 0xC4, 0xEC, 0xD0, 0x16, 0x7D, 0xB0, 0x38, 0xBF, 0x10, 203 | 0x27, 0x6E, 0xDF, 0x5E, 0x24, 0x7C, 0x35, 0x69, 0x18, 0x9C, 0x4A, 0x4F, 0x5C, 0xC3, 0x09, 0xE9, 204 | 0x79, 0xBF, 0x55, 0xDE, 0x39, 0x1E, 0x31, 0x73, 0x89, 0xC3, 0xAD, 0x44, 0xF2, 0x8C, 0x05, 0xEE, 205 | 0xDD, 0xCB, 0x72, 0xBB, 0x3D, 0x12, 0x54, 0xA9, 0x26, 0x7C, 0x3C, 0x44, 0x06, 0x44, 0x1E, 0xA8, 206 | 0x2D, 0x9E, 0x02, 0x15, 0x22, 0x39, 0x76, 0xE3, 0x76, 0xC6, 0xF0, 0x89, 0x8C, 0x36, 0x35, 0x91, 207 | 0x63, 0x31, 0x03, 0xB1, 0x7B, 0x20, 0x9A, 0xE9, 0x53, 0x72, 0x5C, 0xBE, 0x47, 0xCC, 0xEB, 0x1B, 208 | 0x58, 0x5C, 0x1D, 0x6D, 0x82, 0xFD, 0xA9, 0x33, 0xA7, 0x3F, 0x88, 0xF1, 0xE9, 0x54, 0x32, 0xC7, 209 | 0x49, 0x86, 0x23, 0x55, 0x2C, 0x27, 0x37, 0xFD, 0x30, 0x7E, 0xF4, 0x3A, 0x81, 0xB8, 0x56, 0x21, 210 | 0x3F, 0x95, 0xCA, 0x26, 0x07, 0x36, 0xF4, 0x5A, 0x46, 0xFA, 0x7B, 0xCE, 0xD4, 0xC9, 0xC0, 0x02, 211 | 0x26, 0x6C, 0x82, 0x55, 0x26, 0xA5, 0x92, 0xC7, 0x37, 0x8A, 0x29, 0x0C, 0xC2, 0xD8, 0x2D, 0xC7, 212 | 0xD4, 0x14, 0x6C, 0x56, 0x38, 0x2C, 0x63, 0x95, 0x2B, 0xFC, 0x0A, 0x86, 0x3C, 0x10, 0x1B, 0xBC, 213 | 0xAE, 0x3D, 0x61, 0x35, 0x8A, 0x32, 0x17, 0x31, 0x96, 0xFD, 0xFD, 0x96, 0x2C, 0xFC, 0x75, 0x1C, 214 | 0x76, 0x49, 0x0A, 0x94, 0xFD, 0x80, 0xFA, 0x7F, 0x6C, 0x69, 0x1A, 0x22, 0xA9, 0xA3, 0x89, 0x07, 215 | 0xFB, 0xE3, 0xF8, 0x48, 0xE1, 0x30, 0x21, 0xF7, 0x49, 0x91, 0x32, 0xC8, 0x89, 0x2A, 0x87, 0x08, 216 | 0xC8, 0xDD, 0xD5, 0xE4, 0x47, 0xF5, 0xC7, 0x90, 0x42, 0x3F, 0x67, 0xF8, 0xB0, 0x8B, 0x32, 0x09, 217 | 0x13, 0xFE, 0x1B, 0xBF, 0xCD, 0xA9, 0xE5, 0x7B, 0x58, 0xCD, 0x5D, 0x0E, 0x12, 0x15, 0x4F, 0x5E, 218 | 0xC2, 0xF3, 0x4C, 0xA3, 0xF1, 0xCC, 0x21, 0x0A, 0x86, 0x07, 0x90, 0xBE, 0x55, 0xBC, 0x44, 0x63, 219 | 0x97, 0x12, 0x04, 0x98, 0x44, 0x81, 0x27, 0x47, 0x21, 0xCF, 0x64, 0x7F, 0x47, 0x38, 0xB8, 0x02, 220 | 0x46, 0x9F, 0xEE, 0x7E, 0x89, 0xEB, 0xC2, 0xF5, 0x11, 0x7B, 0x34, 0xC1, 0x77, 0x1F, 0x41, 0xE5, 221 | 0x18, 0xDD, 0xFD, 0xC2, 0xA0, 0xBE, 0xBE, 0x07, 0x53, 0xC2, 0x17, 0x36, 0xF1, 0xF5, 0x27, 0xCE, 222 | 0xC2, 0xA6, 0x2F, 0x9A, 0x6D, 0x30, 0x16, 0x31, 0x6E, 0x6D, 0x32, 0xC5, 0x5E, 0x23, 0xC0, 0xE1, 223 | 0x1C, 0xD8, 0xE3, 0x34, 0x01, 0xC6, 0x33, 0xFA, 0x2E, 0x86, 0x12, 0x35, 0x69, 0x7C, 0x0A, 0x30, 224 | 0xD0, 0x81, 0x00, 0xC4, 0xD7, 0xEE, 0x7E, 0x61, 0x2C, 0xAE, 0x35, 0x1B, 0xB2, 0x40, 0x38, 0xC5, 225 | 0xD6, 0x21, 0xD4, 0x2B, 0x44, 0xE8, 0x13, 0xB8, 0x77, 0xBF, 0xC4, 0xAC, 0xDA, 0xFC, 0xA7, 0xEB, 226 | 0x4F, 0x89, 0x87, 0x24, 0x45, 0x24, 0xAE, 0x7D, 0xEC, 0x44, 0x9B, 0xF1, 0xBA, 0x60, 0x28, 0xF8, 227 | 0xC1, 0x63, 0xD7, 0x6D, 0x1C, 0xF0, 0x07, 0x95, 0x45, 0x6E, 0x6F, 0x43, 0xB3, 0x7A, 0x8E, 0x40, 228 | 0x6C, 0xB9, 0x28, 0xB0, 0x7C, 0xE5, 0x7B, 0xA6, 0xEB, 0x98, 0x9F, 0x69, 0x42, 0x6F, 0x66, 0x05, 229 | 0xE7, 0x19, 0xC2, 0x6D, 0xF3, 0x17, 0xCF, 0xBC, 0xF6, 0x2D, 0x9C, 0x73, 0xD3, 0x26, 0x15, 0xE3, 230 | 0xE8, 0x08, 0xAC, 0x8C, 0xAC, 0x38, 0x95, 0x71, 0x8C, 0xE8, 0x1B, 0x0A, 0xB8, 0x99, 0x32, 0x16, 231 | 0xE6, 0xCA, 0x08, 0x5D, 0xB8, 0xCD, 0xD2, 0x2A, 0x1F, 0xAB, 0x9C, 0xBA, 0x2D, 0x47, 0x4F, 0x4B, 232 | 0x6C, 0xF1, 0x57, 0xE8, 0x7B, 0x8D, 0xE6, 0xAD, 0xC4, 0x0C, 0xAB, 0x3C, 0xE8, 0x04, 0x12, 0x83, 233 | 0x8C, 0x89, 0x8A, 0xCC, 0x94, 0x5D, 0x0D, 0x1C, 0xA4, 0x99, 0xA4, 0xC0, 0x66, 0xF4, 0x23, 0x55, 234 | 0x42, 0x56, 0x06, 0xD9, 0xBC, 0x7F, 0x30, 0x97, 0xF9, 0xF3, 0x90, 0x97, 0x4E, 0x29, 0x23, 0x35, 235 | 0x25, 0x73, 0x71, 0xFF, 0xA3, 0xAF, 0xE8, 0x97, 0xDB, 0x17, 0xE8, 0xC9, 0xCF, 0x5D, 0x4C, 0x0F, 236 | 0x9F, 0x5C, 0xFD, 0x0C, 0x25, 0x9F, 0x37, 0x2E, 0x4C, 0x96, 0x94, 0xE0, 0x2C, 0x69, 0x1A, 0x2B, 237 | 0x29, 0xD3, 0x06, 0x53, 0xE2, 0xC1, 0x9A, 0x7E, 0x9E, 0x6F, 0xCA, 0x38, 0x24, 0xEB, 0x83, 0x0C, 238 | 0x29, 0xE5, 0x5A, 0x4D, 0x9B, 0x59, 0x15, 0x48, 0xF4, 0x72, 0xAE, 0x2B, 0xA3, 0x97, 0x16, 0x02, 239 | 0x12, 0x35, 0x73, 0xE4, 0x6A, 0x62, 0xB9, 0x25, 0x3E, 0x90, 0x8C, 0x1D, 0x12, 0x7F, 0xCE, 0x57, 240 | 0x26, 0x39, 0x27, 0x5F, 0x3A, 0x9E, 0xE5, 0x2F, 0xDB, 0xF4, 0x7C, 0x43, 0x94, 0x56, 0x59, 0xD1, 241 | 0xB6, 0xE3, 0x81, 0x01, 0x5F, 0xFC, 0xFA, 0xEA, 0x25, 0x4D, 0x39, 0xF2, 0x0A, 0xE7, 0x20, 0xDB, 242 | 0x17, 0xB1, 0x77, 0x02, 0x2B, 0x67, 0xA0, 0xB0, 0xB5, 0xA1, 0xD5, 0xE6, 0xA9, 0x26, 0x69, 0x47, 243 | 0x69, 0x24, 0xD0, 0xC3, 0x4F, 0x7C, 0x4E, 0x5A, 0x78, 0x32, 0x00, 0x37, 0x2B, 0x65, 0xF1, 0xE7, 244 | 0x79, 0x51, 0x20, 0x0E, 0x1F, 0x13, 0x02, 0xEE, 0xAA, 0x71, 0x47, 0x0E, 0x69, 0x8E, 0x11, 0xAB, 245 | 0xC3, 0x5B, 0x9A, 0x0C, 0x7E, 0x41, 0xC8, 0xA7, 0x66, 0x12, 0x31, 0x96, 0x15, 0x5E, 0xCA, 0x93, 246 | 0x68, 0x0E, 0x71, 0x89, 0x1F, 0x7D, 0x34, 0xC7, 0x90, 0x1A, 0x9F, 0x82, 0xE7, 0xB7, 0x3D, 0xD0, 247 | 0xA0, 0x79, 0x5D, 0xA6, 0x0E, 0x37, 0x57, 0x0A, 0x64, 0x5D, 0x21, 0x58, 0x12, 0x52, 0x73, 0xCB, 248 | 0xD8, 0x47, 0xCD, 0x4E, 0xF6, 0xDE, 0x73, 0x2F, 0x6E, 0x6D, 0x8B, 0x0C, 0x3B, 0x5A, 0x35, 0x2D, 249 | 0xEF, 0x6E, 0x32, 0x0C, 0xD2, 0xF4, 0xB2, 0x22, 0x6C, 0xAE, 0x81, 0x91, 0xFC, 0x22, 0x1E, 0x10, 250 | 0xCB, 0x2E, 0x07, 0x44, 0x81, 0xEC, 0xD9, 0xDE, 0x2F, 0xD7, 0x2C, 0xE4, 0x20, 0x17, 0x39, 0x4C, 251 | 0xA3, 0x2F, 0x2A, 0x98, 0xD2, 0xF2, 0x2C, 0x9C, 0xA0, 0x4E, 0x99, 0x50, 0xE6, 0xBF, 0xD2, 0x7A, 252 | 0xC1, 0x67, 0x88, 0xA5, 0xCD, 0xF7, 0xA8, 0xD9, 0xDA, 0x70, 0x16, 0x81, 0x95, 0x66, 0xB1, 0x4F, 253 | 0xF2, 0xDF, 0x68, 0xC3, 0x96, 0x04, 0x0F, 0x34, 0x70, 0x65, 0x41, 0x0D, 0xA7, 0xA5, 0x4C, 0x20, 254 | 0xBA, 0xBD, 0x0A, 0x02, 0xE9, 0xAE, 0x27, 0x89, 0x56, 0xEA, 0x22, 0x4B, 0xD3, 0x5F, 0xFE, 0x3E, 255 | 0x1D, 0xC6, 0x02, 0xB8, 0xAE, 0x6A, 0xAE, 0xC0, 0x09, 0xC6, 0x35, 0x13, 0xB7, 0xA1, 0x44, 0xA2, 256 | 0xAD, 0x92, 0x9C, 0xA6, 0xA0, 0x2D, 0x5E, 0x6D, 0x89, 0x73, 0xDE, 0x54, 0xD4, 0x0A, 0xAF, 0xB6, 257 | 0xC1, 0xD7, 0x92, 0x83, 0xC4, 0xF7, 0x3F, 0xA6, 0x26, 0xC4, 0xE5, 0xF6, 0xC6, 0xB2, 0xBD, 0xE3, 258 | 0xE5, 0x40, 0x05, 0x85, 0x7C, 0x9B, 0x26, 0x37, 0x17, 0xAE, 0x69, 0x2E, 0x2C, 0xCC, 0x45, 0x09, 259 | 0xD2, 0x0E, 0xB4, 0x7A, 0x6D, 0x92, 0xF8, 0xFF, 0x87, 0x27, 0xA9, 0x66, 0xCB, 0x71, 0xA9, 0x9C, 260 | 0xA2, 0xF7, 0x97, 0xD4, 0x2B, 0x27, 0xC8, 0x3C, 0xCB, 0xC1, 0xD5, 0x5A, 0x8E, 0xEB, 0xA9, 0x15, 261 | 0xAF, 0x1D, 0x28, 0x41, 0xAA, 0x96, 0x7A, 0x85, 0x11, 0xAB, 0x92, 0xEC, 0x75, 0xB3, 0xFF, 0xDD, 262 | 0x42, 0xF2, 0x66, 0x89, 0x44, 0x58, 0xBE, 0x51, 0x5C, 0x59, 0x3D, 0xF9, 0x30, 0x49, 0xC9, 0x64, 263 | 0x8D, 0x52, 0x49, 0x9A, 0x8C, 0x94, 0xA8, 0x13, 0x39, 0x4A, 0xA9, 0xE3, 0x41, 0xBC, 0xEC, 0x26, 264 | 0x5F, 0x6B, 0x19, 0x2B, 0x19, 0x9D, 0x06, 0x4E, 0xCA, 0x80, 0x77, 0xFC, 0x86, 0x76, 0x3F, 0xBF, 265 | 0x26, 0xE6, 0xBD, 0x17, 0x57, 0x36, 0xD7, 0x71, 0xC9, 0x03, 0x12, 0x95, 0x32, 0x63, 0x92, 0x00, 266 | 0xE1, 0xF4, 0x45, 0x62, 0x56, 0x8A, 0x82, 0x5C, 0x1C, 0x90, 0x86, 0xFE, 0xD6, 0xC5, 0x74, 0xBD, 267 | 0x22, 0x9E, 0xC6, 0x39, 0xFB, 0xF9, 0x99, 0xE6, 0x07, 0x1A, 0x7F, 0xC1, 0x5D, 0x90, 0xBC, 0x5B, 268 | 0x44, 0x13, 0x6F, 0x7F, 0x62, 0xAB, 0x42, 0x9A, 0x83, 0xC8, 0xD4, 0x09, 0xA1, 0x49, 0xA6, 0x4F, 269 | 0xDE, 0xE2, 0xDB, 0x7A, 0xF2, 0x82, 0xA7, 0x4A, 0xF5, 0x78, 0x57, 0xFC, 0x53, 0xA2, 0x48, 0xCE, 270 | 0x9C, 0x9C, 0x26, 0xB5, 0xE5, 0x6D, 0xA1, 0xE3, 0x4A, 0x22, 0x2A, 0x5B, 0x87, 0xAE, 0x61, 0xC2, 271 | 0xE4, 0xF4, 0x37, 0x6B, 0x45, 0xB5, 0x02, 0x95, 0x86, 0x4C, 0xC8, 0x52, 0x5B, 0xA6, 0xBA, 0xAE, 272 | 0x58, 0x53, 0xB5, 0xD8, 0x2F, 0x41, 0x94, 0xEE, 0x79, 0x29, 0xB3, 0x7C, 0x31, 0x2A, 0xDC, 0xE2, 273 | 0xBC, 0xB0, 0xF2, 0xCF, 0xF0, 0x28, 0xDE, 0x59, 0xE5, 0xDF, 0xF8, 0xAB, 0x8B, 0x86, 0x47, 0xFC, 274 | 0x7F, 0x22, 0xF6, 0x5F, 0x04, 0x9C, 0x39, 0x76, 0x5C, 0x6C, 0x00, 0x00 275 | }; 276 | 277 | 278 | //File: index_ov3660.html.gz, Size: 4408 279 | #define index_ov3660_html_gz_len 4408 280 | const uint8_t index_ov3660_html_gz[] = { 281 | 0x1F, 0x8B, 0x08, 0x08, 0x28, 0x5C, 0xAE, 0x5C, 0x00, 0x03, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x5F, 282 | 0x6F, 0x76, 0x33, 0x36, 0x36, 0x30, 0x2E, 0x68, 0x74, 0x6D, 0x6C, 0x00, 0xE5, 0x5D, 0xEB, 0x92, 283 | 0xD3, 0xC6, 0x12, 0xFE, 0xCF, 0x53, 0x08, 0x41, 0x58, 0x6F, 0x65, 0xED, 0xF5, 0x6D, 0xCD, 0xE2, 284 | 0xD8, 0xE6, 0xC0, 0xB2, 0x84, 0x54, 0x01, 0x49, 0x20, 0x21, 0xA9, 0x4A, 0xA5, 0x60, 0x2C, 0x8D, 285 | 0xED, 0x09, 0xB2, 0xE4, 0x48, 0x23, 0x7B, 0x37, 0xD4, 0x3E, 0xC7, 0x79, 0xA0, 0xF3, 0x62, 0xA7, 286 | 0xE7, 0x22, 0x69, 0x24, 0x8F, 0x2E, 0xB6, 0x59, 0x9B, 0xC3, 0x31, 0x55, 0x20, 0x5B, 0xD3, 0x3D, 287 | 0xDD, 0xFD, 0xF5, 0x6D, 0x46, 0x17, 0x06, 0x77, 0x6D, 0xCF, 0xA2, 0xD7, 0x0B, 0x6C, 0xCC, 0xE8, 288 | 0xDC, 0x19, 0xDD, 0x19, 0x88, 0x7F, 0x0C, 0xF8, 0x0C, 0x66, 0x18, 0xD9, 0xE2, 0x90, 0x7F, 0x9D, 289 | 0x63, 0x8A, 0x0C, 0x6B, 0x86, 0xFC, 0x00, 0xD3, 0xA1, 0x19, 0xD2, 0x49, 0xFD, 0xDC, 0xCC, 0x9E, 290 | 0x76, 0xD1, 0x1C, 0x0F, 0xCD, 0x25, 0xC1, 0xAB, 0x85, 0xE7, 0x53, 0xD3, 0xB0, 0x3C, 0x97, 0x62, 291 | 0x17, 0x86, 0xAF, 0x88, 0x4D, 0x67, 0x43, 0x1B, 0x2F, 0x89, 0x85, 0xEB, 0xFC, 0xCB, 0x09, 0x71, 292 | 0x09, 0x25, 0xC8, 0xA9, 0x07, 0x16, 0x72, 0xF0, 0xB0, 0xA5, 0xF2, 0xA2, 0x84, 0x3A, 0x78, 0x74, 293 | 0xF9, 0xF6, 0xA7, 0x4E, 0xDB, 0xF8, 0xF1, 0x5D, 0xA7, 0xD7, 0x6B, 0x0E, 0x4E, 0xC5, 0x6F, 0xC9, 294 | 0x98, 0x80, 0x5E, 0xAB, 0xDF, 0xD9, 0x67, 0xEC, 0xD9, 0xD7, 0xC6, 0xA7, 0xD4, 0x4F, 0xEC, 0x33, 295 | 0x01, 0x21, 0xEA, 0x13, 0x34, 0x27, 0xCE, 0x75, 0xDF, 0x78, 0xE2, 0xC3, 0x9C, 0x27, 0x2F, 0xB0, 296 | 0xB3, 0xC4, 0x94, 0x58, 0xE8, 0x24, 0x40, 0x6E, 0x50, 0x0F, 0xB0, 0x4F, 0x26, 0xDF, 0xAD, 0x11, 297 | 0x8E, 0x91, 0xF5, 0x71, 0xEA, 0x7B, 0xA1, 0x6B, 0xF7, 0x8D, 0x7B, 0xAD, 0x73, 0xF6, 0x67, 0x7D, 298 | 0x90, 0xE5, 0x39, 0x9E, 0x0F, 0xE7, 0x2F, 0x9F, 0xB3, 0x3F, 0xEB, 0xE7, 0xF9, 0xEC, 0x01, 0xF9, 299 | 0x07, 0xF7, 0x8D, 0x56, 0x6F, 0x71, 0x95, 0x3A, 0x7F, 0x73, 0x27, 0xF5, 0x75, 0xD6, 0xCE, 0x93, 300 | 0x5E, 0xD2, 0x9F, 0x17, 0xD3, 0x07, 0xD8, 0xA2, 0xC4, 0x73, 0x1B, 0x73, 0x44, 0x5C, 0x0D, 0x27, 301 | 0x9B, 0x04, 0x0B, 0x07, 0x81, 0x0D, 0x26, 0x0E, 0x2E, 0xE4, 0x73, 0x6F, 0x8E, 0xDD, 0xF0, 0xA4, 302 | 0x84, 0x1B, 0x63, 0x52, 0xB7, 0x89, 0x2F, 0x46, 0xF5, 0x99, 0x1D, 0xC2, 0xB9, 0x5B, 0xCA, 0xB6, 303 | 0x48, 0x2E, 0xD7, 0x73, 0xB1, 0xC6, 0x80, 0x6C, 0xA2, 0x95, 0x8F, 0x16, 0x6C, 0x00, 0xFB, 0x77, 304 | 0x7D, 0xC8, 0x9C, 0xB8, 0xC2, 0xA9, 0xFA, 0x46, 0xA7, 0xDB, 0x5C, 0x5C, 0x95, 0x40, 0xD9, 0xE9, 305 | 0xB1, 0x3F, 0xEB, 0x83, 0x16, 0xC8, 0xB6, 0x89, 0x3B, 0xED, 0x1B, 0xE7, 0x5A, 0x16, 0x9E, 0x6F, 306 | 0x63, 0xBF, 0xEE, 0x23, 0x9B, 0x84, 0x41, 0xDF, 0xE8, 0xEA, 0xC6, 0xCC, 0x91, 0x3F, 0x05, 0x59, 307 | 0xA8, 0x07, 0xC2, 0xD6, 0x5B, 0x5A, 0x49, 0xE4, 0x10, 0x9F, 0x4C, 0x67, 0x14, 0x20, 0x5D, 0x1B, 308 | 0x93, 0x35, 0x9A, 0x0C, 0xA1, 0x32, 0x3C, 0x0B, 0xED, 0xA6, 0xB7, 0x1A, 0x72, 0xC8, 0xD4, 0xAD, 309 | 0x13, 0x8A, 0xE7, 0xA0, 0x4E, 0x40, 0x7D, 0x4C, 0xAD, 0x59, 0x91, 0x28, 0x13, 0x32, 0x0D, 0x7D, 310 | 0xAC, 0x11, 0x24, 0xB6, 0x5B, 0x81, 0xC2, 0x70, 0x72, 0xFD, 0x54, 0x7D, 0x85, 0xC7, 0x1F, 0x09, 311 | 0xAD, 0x4B, 0x9B, 0x8C, 0xF1, 0xC4, 0xF3, 0xB1, 0x76, 0x64, 0x34, 0xC2, 0xF1, 0xAC, 0x8F, 0xF5, 312 | 0x80, 0x22, 0x9F, 0x56, 0x61, 0x88, 0x26, 0x14, 0xFB, 0xE5, 0xFC, 0x30, 0xF3, 0x8A, 0x72, 0x6E, 313 | 0xF9, 0xD3, 0xCA, 0x01, 0xC4, 0x75, 0x88, 0x8B, 0xAB, 0x8B, 0x97, 0x37, 0x6F, 0x9A, 0x9D, 0x18, 314 | 0x55, 0x01, 0x18, 0x32, 0x9F, 0x16, 0x79, 0x09, 0xD7, 0x75, 0x7D, 0x32, 0x19, 0x37, 0xAD, 0x66, 315 | 0xF3, 0x9B, 0xF5, 0x93, 0x33, 0x2C, 0xDC, 0x14, 0x85, 0xD4, 0xDB, 0x3D, 0x22, 0xD6, 0xC2, 0x2A, 316 | 0xA3, 0xC7, 0xBF, 0xE6, 0xD8, 0x26, 0xC8, 0xA8, 0x29, 0xE1, 0x7C, 0xDE, 0x04, 0x9F, 0x3A, 0x36, 317 | 0x90, 0x6B, 0x1B, 0x35, 0xCF, 0x27, 0x10, 0x08, 0x88, 0xA7, 0x1B, 0x07, 0x7E, 0x81, 0xC2, 0xB1, 318 | 0xC0, 0xC7, 0x1A, 0x95, 0x0B, 0x62, 0x46, 0xB5, 0x88, 0x3E, 0x6C, 0xD8, 0xA7, 0x42, 0xCA, 0x61, 319 | 0x9F, 0xD2, 0x00, 0xD2, 0xE8, 0xC8, 0xD9, 0x17, 0xE1, 0xA5, 0x4A, 0x98, 0x87, 0x19, 0xFB, 0xCC, 320 | 0xD1, 0x55, 0xBD, 0x10, 0xBB, 0x68, 0x50, 0x84, 0x21, 0x94, 0x59, 0xAB, 0x06, 0x43, 0x97, 0x33, 321 | 0xA3, 0x6E, 0xB0, 0x2C, 0x79, 0xAC, 0xA7, 0x91, 0x4C, 0xF5, 0x90, 0xB3, 0x8F, 0xEA, 0x14, 0x1B, 322 | 0xA8, 0xAB, 0x57, 0x35, 0xC9, 0x1D, 0xE2, 0x8F, 0xCE, 0x87, 0x84, 0x26, 0xB9, 0x59, 0x84, 0x7D, 323 | 0xAA, 0x67, 0x92, 0x84, 0x59, 0x69, 0x36, 0xD1, 0x30, 0xCE, 0xCF, 0x28, 0x6B, 0x7C, 0xF3, 0xA2, 324 | 0x5B, 0xC3, 0xB5, 0x58, 0x84, 0xAA, 0xD9, 0x45, 0xC3, 0xB8, 0x48, 0x86, 0xD2, 0x2C, 0xC3, 0x3E, 325 | 0x37, 0x15, 0xFA, 0x8D, 0x7B, 0xE3, 0x90, 0x52, 0xCF, 0x0D, 0x76, 0x2A, 0x51, 0x79, 0x71, 0xF6, 326 | 0x57, 0x18, 0x50, 0x32, 0xB9, 0xAE, 0xCB, 0x90, 0x86, 0x38, 0x5B, 0x20, 0x68, 0x21, 0xC7, 0x98, 327 | 0xAE, 0x30, 0x2E, 0x6E, 0x37, 0x5C, 0xB4, 0x84, 0xBC, 0x33, 0x9D, 0x3A, 0x3A, 0xDF, 0xB3, 0x42, 328 | 0x3F, 0x60, 0x7D, 0xDB, 0xC2, 0x23, 0xC0, 0xD8, 0x5F, 0x9F, 0x38, 0x1D, 0x83, 0x15, 0x27, 0xAA, 329 | 0x5B, 0x63, 0xCD, 0x5C, 0x5E, 0x48, 0x99, 0x8D, 0xB5, 0x48, 0x78, 0xA0, 0x0E, 0xA1, 0xD7, 0xDA, 330 | 0x73, 0x32, 0x12, 0x35, 0x67, 0xA2, 0x10, 0x2C, 0x2C, 0x0B, 0x69, 0xB9, 0xFA, 0xD6, 0x0C, 0x5B, 331 | 0x1F, 0xB1, 0xFD, 0x6D, 0x69, 0x1B, 0x56, 0xD6, 0x1E, 0x36, 0x88, 0xBB, 0x08, 0x69, 0x9D, 0xB5, 332 | 0x53, 0x8B, 0x5B, 0xC1, 0x9C, 0x3B, 0x64, 0xA4, 0x62, 0xBB, 0x5D, 0xD4, 0x54, 0x9C, 0x2D, 0xAE, 333 | 0x8A, 0x8D, 0xA0, 0x0A, 0x3B, 0x72, 0xD0, 0x18, 0x3B, 0x45, 0x22, 0xCB, 0x60, 0xC8, 0x49, 0xBB, 334 | 0x32, 0x57, 0xE5, 0xF7, 0x6E, 0x5C, 0xB2, 0xA4, 0x78, 0x75, 0x1F, 0x7E, 0x53, 0xD9, 0x8E, 0xFC, 335 | 0xF8, 0x24, 0xF5, 0x53, 0x80, 0x1D, 0x08, 0xB0, 0xBC, 0xD6, 0x1B, 0xC6, 0xAC, 0x40, 0x86, 0xC2, 336 | 0x09, 0x7C, 0xE4, 0x4E, 0x31, 0xE4, 0x82, 0xAB, 0x93, 0xE8, 0xB0, 0x78, 0x61, 0x50, 0x49, 0x7D, 337 | 0x96, 0xAA, 0xCF, 0x8A, 0x17, 0x22, 0x22, 0x21, 0x6C, 0xD1, 0x8C, 0x28, 0xB0, 0x16, 0xCE, 0xDF, 338 | 0xD2, 0x3A, 0x85, 0xE8, 0x47, 0xB4, 0x01, 0x93, 0x76, 0x29, 0x6D, 0x7F, 0x5F, 0x9A, 0x11, 0xA2, 339 | 0x95, 0xDE, 0x64, 0x52, 0xB6, 0x56, 0x9C, 0x4C, 0x3A, 0xCD, 0x4E, 0xB7, 0xB4, 0x61, 0xD2, 0x6A, 340 | 0x99, 0x59, 0x2F, 0x6A, 0x32, 0x46, 0x9C, 0x4D, 0xCA, 0x21, 0xE8, 0xCF, 0xBC, 0x25, 0xF6, 0x35, 341 | 0x40, 0x64, 0xC4, 0xED, 0x3E, 0xEA, 0xDA, 0x15, 0xB8, 0x21, 0xC8, 0xF7, 0x4B, 0x5D, 0x36, 0x4D, 342 | 0xB3, 0x6B, 0xB7, 0xAC, 0x76, 0xA1, 0x63, 0x0A, 0x76, 0x0D, 0xF0, 0x06, 0x34, 0x76, 0xB0, 0x5D, 343 | 0x90, 0x9E, 0x6D, 0x3C, 0x41, 0xA1, 0x43, 0x4B, 0xEC, 0x8D, 0x9A, 0xEC, 0x4F, 0xD1, 0x8C, 0x3C, 344 | 0xAE, 0xFE, 0x60, 0x1B, 0x1D, 0x43, 0x1E, 0x09, 0x7F, 0x6A, 0xE6, 0x8C, 0x6A, 0x27, 0x5A, 0x2C, 345 | 0x30, 0x82, 0x51, 0x16, 0xCE, 0x5B, 0x92, 0x56, 0xEA, 0x99, 0xF5, 0x89, 0xAB, 0xD2, 0x42, 0xB4, 346 | 0xD4, 0x15, 0xE3, 0x6E, 0x68, 0x23, 0x9D, 0xFB, 0x13, 0xCF, 0x0A, 0x75, 0x65, 0xBA, 0x9A, 0x4B, 347 | 0xAD, 0xF3, 0xEB, 0x47, 0x26, 0x0B, 0x1C, 0xC2, 0x1D, 0x3B, 0x74, 0x5D, 0x86, 0x68, 0x9D, 0xFA, 348 | 0xA0, 0xA6, 0x66, 0xA2, 0x6A, 0x86, 0xDB, 0x2A, 0x3A, 0x53, 0x86, 0xCD, 0xDB, 0x8C, 0xC9, 0x04, 349 | 0xA0, 0x26, 0x51, 0xC4, 0x39, 0xC4, 0x08, 0x3C, 0x50, 0x2A, 0x62, 0xB5, 0x9B, 0x5D, 0xE8, 0x2C, 350 | 0x9C, 0xEB, 0x1A, 0x83, 0x68, 0xB2, 0x16, 0x54, 0x31, 0x31, 0x9D, 0x3F, 0x1D, 0xA3, 0x5A, 0xF3, 351 | 0xA4, 0x79, 0xD2, 0x81, 0xBF, 0x34, 0x0D, 0x7A, 0xB1, 0x73, 0x49, 0xF3, 0xE6, 0x78, 0x5E, 0x26, 352 | 0xF9, 0x94, 0xEF, 0x93, 0xE4, 0xA5, 0xB1, 0x52, 0x2C, 0xAA, 0x47, 0x52, 0x7A, 0xC3, 0xA4, 0xD5, 353 | 0x28, 0x29, 0x2C, 0x39, 0x2E, 0xBD, 0xB9, 0x23, 0x6A, 0xBC, 0x65, 0x53, 0x88, 0xE7, 0xDE, 0x3F, 354 | 0x75, 0x51, 0x55, 0xFF, 0xEF, 0xBD, 0x5D, 0x31, 0xC5, 0x57, 0xED, 0xE9, 0x1B, 0xDB, 0x25, 0x38, 355 | 0xB4, 0x6F, 0x34, 0xF3, 0x51, 0xAF, 0xCB, 0x7E, 0x06, 0x24, 0x74, 0x61, 0x51, 0xE5, 0xC3, 0xEA, 356 | 0x2A, 0xB7, 0xE7, 0x51, 0xC6, 0x6C, 0x61, 0x83, 0x09, 0x71, 0x9C, 0xBA, 0xE3, 0xAD, 0xCA, 0x3B, 357 | 0x91, 0x62, 0x4F, 0x5E, 0xF3, 0xD3, 0x72, 0x97, 0xDF, 0x56, 0xDA, 0x10, 0x32, 0xD7, 0xFF, 0x84, 358 | 0xB4, 0x5F, 0x77, 0xC0, 0x15, 0x86, 0xC6, 0x76, 0x85, 0x62, 0x0B, 0x7F, 0xDC, 0x6D, 0xA2, 0x4A, 359 | 0xAE, 0x24, 0x3A, 0xC1, 0xC2, 0xC5, 0x5C, 0xB0, 0x22, 0xD4, 0x9A, 0x6D, 0xB1, 0xA8, 0x5A, 0x78, 360 | 0x01, 0x11, 0xD7, 0x68, 0x7C, 0xEC, 0x20, 0xD6, 0xC1, 0x6F, 0xB5, 0xE4, 0x2E, 0x5D, 0x98, 0xA8, 361 | 0xE4, 0x55, 0x34, 0xE1, 0xA6, 0xFB, 0x72, 0xB6, 0x4B, 0x1A, 0xA2, 0x77, 0xC8, 0xCF, 0xD5, 0x7A, 362 | 0xB7, 0x2E, 0x69, 0xF7, 0xD3, 0x91, 0xA1, 0x1F, 0xB4, 0x41, 0x46, 0x8F, 0x92, 0xF6, 0xD4, 0xC7, 363 | 0xD7, 0x15, 0x94, 0x39, 0x91, 0xFF, 0xF6, 0xC5, 0x86, 0xE8, 0xF6, 0x6B, 0x7F, 0x5E, 0x00, 0xA4, 364 | 0x17, 0x35, 0xBA, 0x41, 0x85, 0xA9, 0xF3, 0xA7, 0xAC, 0xE2, 0x8F, 0xF1, 0x76, 0x9F, 0x69, 0x56, 365 | 0x48, 0x37, 0x05, 0x25, 0x54, 0xEF, 0xAA, 0x51, 0xF5, 0xD5, 0x9E, 0x74, 0xF0, 0x84, 0xE6, 0x5C, 366 | 0xCD, 0xE0, 0x7D, 0x6A, 0xA7, 0x38, 0xBB, 0xD5, 0x95, 0x7D, 0x82, 0xD2, 0xCC, 0x11, 0xEF, 0xCA, 367 | 0xE5, 0x7B, 0x9F, 0x96, 0x33, 0xCB, 0x9E, 0x1B, 0x33, 0xCF, 0x87, 0x24, 0x6A, 0x9F, 0x39, 0xCC, 368 | 0x30, 0x66, 0x2E, 0x4B, 0x3E, 0xC0, 0x83, 0x7F, 0xAF, 0xB5, 0x7B, 0xDA, 0x8B, 0x05, 0x05, 0x83, 369 | 0x8B, 0x44, 0xCB, 0xDD, 0xD6, 0x5A, 0x2F, 0x59, 0xB9, 0x0B, 0x64, 0x35, 0x17, 0x69, 0x81, 0x2A, 370 | 0x8E, 0xCA, 0xA2, 0x0C, 0xB3, 0xBE, 0x47, 0x53, 0xE8, 0xEC, 0x64, 0x8E, 0xA0, 0xED, 0x65, 0xEE, 371 | 0x8A, 0x80, 0xA3, 0x0E, 0xBF, 0x2A, 0xEE, 0xAE, 0x6C, 0x1A, 0xB6, 0x7A, 0xCD, 0x92, 0x29, 0x2D, 372 | 0xC7, 0x0B, 0x8A, 0xE3, 0x0A, 0x8D, 0xC1, 0x7E, 0x21, 0xD5, 0x4C, 0x24, 0xB7, 0x2E, 0xB5, 0x3B, 373 | 0x4F, 0xDC, 0xB9, 0xB5, 0x67, 0x2A, 0x95, 0xEE, 0xC2, 0x98, 0x2A, 0x0E, 0xC7, 0x8C, 0xCD, 0x5B, 374 | 0x4D, 0x6D, 0xA6, 0x2D, 0xDC, 0x7F, 0xA3, 0xF8, 0x0A, 0xD6, 0x9B, 0xEC, 0x82, 0x5C, 0xDF, 0xB0, 375 | 0xB0, 0x3E, 0x8D, 0xA6, 0x8A, 0x5C, 0xAB, 0xCA, 0x26, 0x60, 0x21, 0x0E, 0x33, 0x62, 0xDB, 0xB8, 376 | 0x70, 0x97, 0x93, 0xAD, 0x79, 0x2B, 0x36, 0x0F, 0x4C, 0x7E, 0xDD, 0xA6, 0xD4, 0xAD, 0x04, 0x45, 377 | 0xE1, 0x75, 0xFA, 0xD6, 0x6D, 0x47, 0x8C, 0x2C, 0x34, 0x79, 0x7B, 0xC4, 0xE9, 0x56, 0xA4, 0x50, 378 | 0x54, 0x6D, 0x70, 0xC7, 0xDB, 0xC4, 0xCC, 0x64, 0x60, 0x07, 0x36, 0x6A, 0x3D, 0x9B, 0x2B, 0x52, 379 | 0x0D, 0x4E, 0x95, 0x7B, 0x89, 0x06, 0xA7, 0xC9, 0x6D, 0x4F, 0x03, 0x76, 0x43, 0x91, 0x7A, 0xCB, 380 | 0x91, 0xB8, 0xDE, 0x65, 0x58, 0x0E, 0x0A, 0x82, 0xA1, 0xC9, 0x6E, 0x8C, 0x31, 0xD3, 0x77, 0x20, 381 | 0x0D, 0x6C, 0xB2, 0x34, 0x88, 0x3D, 0x34, 0x1D, 0x6F, 0xEA, 0x65, 0xCE, 0xF1, 0xF3, 0xE2, 0x0A, 382 | 0x04, 0x24, 0xCD, 0xA1, 0x99, 0xBA, 0x3A, 0x63, 0x72, 0xAA, 0xE4, 0x27, 0x73, 0xF4, 0xE0, 0xDE, 383 | 0xA3, 0x87, 0x0F, 0x7B, 0xDF, 0x3D, 0x70, 0xC7, 0xC1, 0x42, 0xFE, 0xFD, 0x8B, 0xB8, 0x98, 0x25, 384 | 0xEE, 0x88, 0x82, 0x3C, 0x4A, 0x29, 0xE8, 0x19, 0x0C, 0x4E, 0x39, 0xD3, 0x8C, 0x20, 0xA7, 0x20, 385 | 0x49, 0x8E, 0x6C, 0xB2, 0xB6, 0xEA, 0xC4, 0x8B, 0x86, 0x04, 0x50, 0x2E, 0xC6, 0xC8, 0xD7, 0x0C, 386 | 0xE1, 0xC3, 0x44, 0xE7, 0xC6, 0xFD, 0xD6, 0xE4, 0x35, 0x66, 0xEC, 0x5D, 0x65, 0x35, 0xE0, 0x4A, 387 | 0xC9, 0x02, 0x24, 0x47, 0x61, 0x3B, 0x8F, 0x21, 0x90, 0x71, 0x72, 0x76, 0x69, 0x2A, 0x67, 0x4C, 388 | 0x2C, 0x9F, 0xB4, 0xBE, 0x72, 0xA5, 0x44, 0x4C, 0x3D, 0xF1, 0xD1, 0x1C, 0x33, 0xF7, 0x97, 0x3F, 389 | 0xE6, 0xB3, 0xC9, 0x22, 0x11, 0x53, 0x9A, 0xA3, 0x37, 0x98, 0x67, 0x4E, 0x40, 0x59, 0x6B, 0xD6, 390 | 0x35, 0x2E, 0xB2, 0x98, 0xA5, 0xE6, 0x37, 0x23, 0x11, 0xE5, 0xE6, 0x75, 0x1D, 0x71, 0xB7, 0x29, 391 | 0x11, 0x88, 0xB3, 0xF3, 0x16, 0xDC, 0xC1, 0x96, 0xC8, 0x09, 0xC1, 0xB4, 0xAD, 0x96, 0x39, 0xFA, 392 | 0xF9, 0xF7, 0xEF, 0x9F, 0xD4, 0xDA, 0xCD, 0xEE, 0xF9, 0x55, 0xEB, 0xAC, 0xD7, 0x3D, 0x1E, 0x9C, 393 | 0x8A, 0x21, 0x9B, 0xF3, 0x6A, 0x9A, 0xA3, 0x5F, 0x19, 0x2F, 0xA8, 0x2F, 0xCD, 0xAB, 0x56, 0xBB, 394 | 0xD9, 0xDC, 0x9E, 0xD7, 0x23, 0x73, 0xF4, 0x96, 0xB3, 0x6A, 0x9F, 0x03, 0xAB, 0x66, 0x7B, 0x07, 395 | 0xB1, 0xCE, 0xCD, 0x11, 0xE7, 0x04, 0x4C, 0xAE, 0x1E, 0xF6, 0xCE, 0xB7, 0x67, 0xF4, 0x10, 0x64, 396 | 0x7A, 0x07, 0x9C, 0xCE, 0x41, 0xBB, 0xDE, 0x2E, 0xCA, 0xF5, 0xCC, 0x11, 0xE3, 0xD3, 0xEB, 0x36, 397 | 0xAF, 0xBA, 0xE7, 0x3B, 0xF0, 0x39, 0x33, 0x65, 0xA7, 0xC3, 0xDC, 0x3F, 0x3A, 0x32, 0x47, 0x17, 398 | 0x3F, 0x3C, 0xAF, 0x75, 0x41, 0xC6, 0xF6, 0xA3, 0xDE, 0xF6, 0xBC, 0xBB, 0xE0, 0x17, 0x4C, 0xC8, 399 | 0x4E, 0x1B, 0x18, 0x75, 0x77, 0x10, 0xB2, 0x63, 0x8E, 0x5E, 0x70, 0x4E, 0xC0, 0xE5, 0xAA, 0xF5, 400 | 0x70, 0x07, 0x91, 0xC0, 0xBD, 0x7E, 0xE6, 0x9C, 0xC0, 0xBF, 0x98, 0x7B, 0x55, 0xE4, 0x04, 0xB9, 401 | 0x97, 0x9B, 0xA6, 0x20, 0xE6, 0xD7, 0x33, 0x59, 0xEA, 0x74, 0x51, 0x4A, 0xF8, 0x3B, 0x84, 0x8E, 402 | 0x80, 0x5E, 0x6F, 0x9C, 0x10, 0x24, 0x1D, 0xA8, 0x24, 0x0E, 0xAA, 0xE5, 0x02, 0x45, 0x92, 0xF8, 403 | 0x6A, 0xAB, 0x39, 0xEA, 0x96, 0x28, 0xC0, 0x49, 0xD5, 0x84, 0xCA, 0x69, 0x53, 0xF2, 0x9B, 0xAC, 404 | 0x3F, 0x64, 0xA8, 0xB3, 0xFB, 0x79, 0xC0, 0x43, 0x3B, 0xA6, 0x12, 0xD5, 0x5B, 0x25, 0x1B, 0x8D, 405 | 0xAC, 0xE8, 0xCA, 0x1C, 0xF5, 0x3A, 0x65, 0xD6, 0xDE, 0x01, 0x8C, 0x31, 0xEF, 0x3D, 0x5D, 0x1C, 406 | 0x04, 0x1B, 0xE3, 0x91, 0x90, 0x9A, 0xA3, 0xA7, 0xF1, 0xF1, 0x2E, 0xA8, 0xD4, 0xCB, 0x34, 0xE5, 407 | 0xB4, 0x39, 0xB0, 0x28, 0xE2, 0x08, 0x64, 0xEA, 0x1D, 0x09, 0x4D, 0x82, 0xCC, 0xE7, 0x05, 0xE6, 408 | 0x36, 0x71, 0x61, 0xED, 0x80, 0x8F, 0x02, 0xBA, 0x31, 0x2A, 0x11, 0x21, 0x24, 0x35, 0x79, 0x74, 409 | 0x30, 0x44, 0x62, 0x51, 0xBE, 0x02, 0x3C, 0x02, 0x44, 0x43, 0x9F, 0xDF, 0xE5, 0xB8, 0x31, 0x22, 410 | 0x09, 0x29, 0x54, 0xC3, 0xF8, 0x78, 0x27, 0x54, 0x76, 0x49, 0x5F, 0x8A, 0x38, 0x12, 0x97, 0x28, 411 | 0x85, 0x75, 0x6F, 0x09, 0x97, 0x32, 0x69, 0x77, 0xC2, 0x65, 0x86, 0xFC, 0xC5, 0x56, 0xE9, 0x2B, 412 | 0xA6, 0x04, 0x54, 0xA2, 0xC3, 0x83, 0x85, 0x4A, 0x22, 0xCC, 0x57, 0x10, 0x2B, 0xB0, 0xFE, 0xF6, 413 | 0x48, 0xB0, 0x79, 0xC7, 0x2F, 0xE9, 0xCC, 0xD1, 0x33, 0x5C, 0x7F, 0xCD, 0x8E, 0x76, 0x81, 0xE3, 414 | 0x49, 0x48, 0xBD, 0x1D, 0x00, 0x89, 0x64, 0x11, 0x70, 0x34, 0x25, 0x1A, 0xE7, 0xB7, 0x84, 0xC6, 415 | 0xF9, 0x2D, 0xA2, 0x81, 0xF0, 0x7B, 0x07, 0x2F, 0xB1, 0xB3, 0x31, 0x1C, 0x11, 0xA1, 0x39, 0xBA, 416 | 0xBC, 0x5A, 0x78, 0x01, 0xBB, 0x5B, 0xF8, 0x25, 0xFB, 0xBE, 0x53, 0x90, 0x9C, 0xED, 0x80, 0x49, 417 | 0x2C, 0x90, 0x8C, 0x91, 0x33, 0x89, 0xCA, 0xD9, 0x2D, 0xA1, 0x52, 0x26, 0xEB, 0x2E, 0xA8, 0x4C, 418 | 0x11, 0x71, 0x2D, 0x4C, 0x1C, 0x76, 0xE7, 0xE2, 0xA6, 0xC0, 0x28, 0xB4, 0xE6, 0xE8, 0xFB, 0xE4, 419 | 0xCB, 0x2E, 0xC0, 0x34, 0x77, 0xC0, 0x45, 0x95, 0x27, 0x1D, 0x2F, 0x67, 0xB0, 0x58, 0xBE, 0x25, 420 | 0x6C, 0x5A, 0xAD, 0xDB, 0xAC, 0x2A, 0x0B, 0x6C, 0x11, 0xE4, 0xBC, 0xC7, 0x93, 0x09, 0x2C, 0x83, 421 | 0x36, 0x2F, 0x2D, 0x29, 0x72, 0xA8, 0x2F, 0xE2, 0xBB, 0x71, 0xC9, 0xBF, 0x6F, 0xBC, 0x87, 0x91, 422 | 0x61, 0xF7, 0xB9, 0x36, 0x32, 0x9A, 0xFA, 0xB5, 0xF0, 0x6B, 0x2F, 0x96, 0x73, 0xDB, 0x5D, 0x0D, 423 | 0x60, 0x82, 0xA7, 0x7C, 0x53, 0x7D, 0x6B, 0x1E, 0x6D, 0xF0, 0x6C, 0x1F, 0x5D, 0xF3, 0xC7, 0x10, 424 | 0x77, 0x59, 0x48, 0xBF, 0xC1, 0xB6, 0xF1, 0x0B, 0x71, 0xB7, 0x57, 0xA6, 0xCB, 0x04, 0xC1, 0xD8, 425 | 0xDD, 0x8D, 0xCB, 0x19, 0x2C, 0x91, 0xE0, 0x60, 0x37, 0x26, 0x3D, 0xF0, 0x24, 0xBC, 0x20, 0xE8, 426 | 0x4B, 0x58, 0xC4, 0xA3, 0xD5, 0x78, 0xF3, 0x82, 0xB2, 0x1A, 0x43, 0x5D, 0xFE, 0xED, 0xA9, 0x71, 427 | 0xC9, 0x6F, 0x03, 0xDB, 0x38, 0x5D, 0x89, 0x2B, 0xD4, 0x55, 0x1C, 0x5D, 0x24, 0x2A, 0x29, 0xA7, 428 | 0xB9, 0xB6, 0x27, 0xAA, 0x0F, 0xA0, 0xAA, 0xFB, 0xA2, 0x1A, 0xF5, 0x22, 0x01, 0xF9, 0x05, 0x3D, 429 | 0x53, 0xD1, 0xB6, 0x9A, 0x8E, 0xB7, 0xD8, 0x8A, 0x59, 0xAB, 0xCD, 0xDB, 0x30, 0x6B, 0x05, 0x30, 430 | 0xD9, 0x4B, 0x76, 0x87, 0xA0, 0x6D, 0x00, 0x5E, 0x7B, 0x01, 0x8A, 0xCD, 0x7A, 0x18, 0xA0, 0xB8, 431 | 0xBE, 0x87, 0x06, 0x0A, 0xBC, 0xE5, 0x3D, 0xAB, 0xA3, 0xDB, 0x04, 0x15, 0x27, 0x34, 0x47, 0xAF, 432 | 0x90, 0x1B, 0x42, 0x91, 0xD9, 0x17, 0x60, 0xF1, 0xC4, 0x07, 0x0B, 0x2F, 0xA9, 0xF7, 0xA1, 0xA1, 433 | 0x03, 0x41, 0xE6, 0x9E, 0xBD, 0xF9, 0x72, 0x47, 0xD2, 0x89, 0x94, 0xF8, 0x0A, 0x8E, 0x36, 0x6E, 434 | 0x0C, 0x22, 0x0E, 0xB7, 0xDC, 0x11, 0x88, 0xA5, 0xD4, 0xF6, 0xCD, 0xC0, 0xDB, 0xD0, 0x75, 0xAF, 435 | 0x77, 0xE9, 0x04, 0x2E, 0x1C, 0x2F, 0xB4, 0xB7, 0xE7, 0x00, 0x6D, 0xC0, 0x8F, 0x93, 0x09, 0xB1, 436 | 0xB6, 0x6F, 0x24, 0xA0, 0x09, 0x78, 0xE1, 0xCD, 0x2B, 0xD2, 0xDF, 0x72, 0xE1, 0xC5, 0xD6, 0x16, 437 | 0x2B, 0x39, 0x0B, 0x50, 0xBC, 0xBC, 0xD8, 0x6B, 0xE1, 0x85, 0x39, 0x0F, 0x94, 0x19, 0x98, 0xB6, 438 | 0x87, 0x4E, 0x0A, 0x20, 0xC4, 0x7B, 0xEE, 0x3C, 0xDB, 0x80, 0x25, 0x28, 0xE3, 0x8C, 0x1E, 0x2D, 439 | 0xBF, 0x0F, 0xB5, 0xBE, 0x4B, 0x24, 0x4A, 0xAF, 0xEE, 0x5A, 0x67, 0x9D, 0x5E, 0xBC, 0xBC, 0xEB, 440 | 0xB4, 0x3F, 0xEF, 0x02, 0x8F, 0x31, 0xBF, 0x5D, 0x7C, 0xDA, 0xDB, 0x40, 0x03, 0xD9, 0xE8, 0x35, 441 | 0xBB, 0xCE, 0xB0, 0x41, 0xC2, 0xDE, 0x3D, 0x90, 0xDA, 0x87, 0x8B, 0xA4, 0xF6, 0x17, 0x10, 0x4A, 442 | 0xD3, 0x2D, 0x32, 0xDE, 0x94, 0x65, 0xBC, 0xEF, 0x2F, 0xF6, 0x83, 0xD0, 0xF4, 0x60, 0xA9, 0x6E, 443 | 0x7A, 0xD0, 0x54, 0x67, 0x88, 0x9B, 0xAD, 0x62, 0x98, 0xB6, 0xEC, 0x60, 0x25, 0xA1, 0xD8, 0xCB, 444 | 0xDA, 0x25, 0xC9, 0xB5, 0xAE, 0x76, 0xC9, 0x72, 0x91, 0x18, 0xE9, 0x24, 0xD7, 0x4B, 0xAE, 0x8A, 445 | 0x9C, 0x7D, 0xDE, 0xCB, 0xBA, 0xDD, 0x32, 0x69, 0x77, 0x09, 0x1A, 0x1F, 0xAD, 0xDE, 0x4F, 0xE7, 446 | 0x68, 0x63, 0x30, 0x24, 0x1D, 0x60, 0xF1, 0xEA, 0xC9, 0x3E, 0xDB, 0x85, 0x68, 0xDE, 0xC3, 0xC4, 447 | 0x51, 0xAC, 0xF5, 0xA1, 0x73, 0x9D, 0x83, 0xDD, 0xCD, 0x93, 0x1D, 0x23, 0x32, 0x47, 0x2F, 0xB1, 448 | 0x1B, 0x18, 0x17, 0x9E, 0x2F, 0xDF, 0xFD, 0xB4, 0x17, 0xD4, 0xF8, 0xCC, 0x87, 0x81, 0x4C, 0x28, 449 | 0x7D, 0x68, 0xBC, 0x66, 0x73, 0xE2, 0xFB, 0x9E, 0xBF, 0x31, 0x64, 0x92, 0x0E, 0x96, 0x15, 0xF5, 450 | 0x57, 0xFC, 0x68, 0x2F, 0x70, 0x45, 0xB3, 0x1E, 0x06, 0xB1, 0x58, 0xE7, 0x43, 0x83, 0xB6, 0x9C, 451 | 0x38, 0x64, 0xB1, 0x31, 0x64, 0x9C, 0xCA, 0x1C, 0xBD, 0xAB, 0x3F, 0x87, 0x7F, 0xF7, 0x02, 0x97, 452 | 0x98, 0xF1, 0x30, 0x60, 0x49, 0x6D, 0x0F, 0x0D, 0xD5, 0x78, 0xB1, 0x79, 0x3A, 0x04, 0x1A, 0x73, 453 | 0xF4, 0xF4, 0xA7, 0xFD, 0xF4, 0x7E, 0x6C, 0xB2, 0x8A, 0x08, 0xED, 0x84, 0x07, 0x57, 0xEA, 0xD0, 454 | 0x68, 0xAC, 0xB6, 0x40, 0x63, 0xC5, 0x04, 0xFF, 0x6D, 0x4F, 0x68, 0xAC, 0xAA, 0xA3, 0xF1, 0x99, 455 | 0xE3, 0x65, 0xF5, 0x25, 0xE0, 0xC3, 0x9F, 0xC5, 0x18, 0xA3, 0xCD, 0xCB, 0x51, 0x44, 0xC8, 0x6E, 456 | 0x1A, 0x83, 0x23, 0xE3, 0x29, 0xDA, 0x4F, 0x41, 0x8A, 0xE7, 0xDD, 0x47, 0x08, 0x25, 0x4A, 0x1E, 457 | 0x1A, 0xA7, 0x09, 0xB2, 0xF0, 0x7B, 0x1B, 0xD3, 0x6D, 0xAE, 0x2D, 0x2B, 0xB4, 0xE6, 0xE8, 0x39, 458 | 0x7C, 0x31, 0x9E, 0xF1, 0x2F, 0xFB, 0x6A, 0xF9, 0xD4, 0xF9, 0xF7, 0x81, 0x5A, 0x4A, 0xDF, 0x2F, 459 | 0x02, 0x38, 0x68, 0xB0, 0xBD, 0xA9, 0xBB, 0xD5, 0x23, 0x0D, 0x29, 0x72, 0x09, 0xDF, 0x1B, 0xF1, 460 | 0x7D, 0xBF, 0x00, 0x26, 0x42, 0xEC, 0x0D, 0x43, 0x45, 0xEF, 0x7D, 0xC0, 0x18, 0x3D, 0x16, 0xC4, 461 | 0x8B, 0xB4, 0x78, 0x15, 0x5E, 0x19, 0x52, 0xF2, 0xE1, 0x27, 0x7E, 0x4B, 0x0B, 0xA6, 0xF5, 0x80, 462 | 0x12, 0xC7, 0x81, 0x85, 0x30, 0xA6, 0xC6, 0x5B, 0x76, 0x38, 0x38, 0x15, 0x03, 0xAA, 0x73, 0x91, 463 | 0xCF, 0xDC, 0xB0, 0x97, 0x50, 0xA2, 0xB9, 0x39, 0x7A, 0xCB, 0x5E, 0x12, 0x08, 0xBC, 0xD8, 0xB7, 464 | 0xCD, 0x99, 0x71, 0x23, 0x62, 0xD7, 0xF7, 0x40, 0xA8, 0x18, 0x24, 0xF9, 0xAE, 0x26, 0xD3, 0x88, 465 | 0x8E, 0x94, 0xDF, 0x46, 0x97, 0x7C, 0xB0, 0xC1, 0xBC, 0xAC, 0x7C, 0x3A, 0x76, 0xD5, 0xC2, 0xCA, 466 | 0xBF, 0xB8, 0x31, 0x38, 0x75, 0x91, 0xC6, 0xDC, 0x39, 0x28, 0x0C, 0xC4, 0xDB, 0x25, 0x73, 0x58, 467 | 0xC5, 0xCF, 0x33, 0x71, 0x4B, 0x24, 0x8F, 0x69, 0xC6, 0x6A, 0x65, 0x1F, 0xDF, 0x94, 0xDB, 0x4C, 468 | 0xD5, 0x82, 0x96, 0x3F, 0x88, 0x29, 0xEB, 0x21, 0x3B, 0x8C, 0xCD, 0xFF, 0x9F, 0x7F, 0x97, 0xF9, 469 | 0x0C, 0x7B, 0xF7, 0x67, 0x22, 0x98, 0x69, 0x04, 0xBE, 0x35, 0x34, 0xF3, 0x9E, 0x8E, 0xCA, 0xD1, 470 | 0xFC, 0x54, 0xA7, 0x7A, 0x66, 0xB0, 0xC6, 0xD6, 0x83, 0xC0, 0xF2, 0xC9, 0x82, 0x8E, 0xEE, 0xD8, 471 | 0x9E, 0x15, 0xCE, 0xB1, 0x4B, 0x1B, 0xC8, 0xB6, 0x2F, 0x97, 0x70, 0xF0, 0x92, 0x04, 0x14, 0x83, 472 | 0x15, 0x6A, 0x47, 0xCF, 0x7E, 0x7C, 0x75, 0x21, 0x9E, 0x12, 0x7B, 0xE9, 0x21, 0x1B, 0xDB, 0x47, 473 | 0x27, 0xC6, 0x24, 0x74, 0x85, 0x9B, 0xD7, 0x30, 0x1B, 0x2B, 0xDE, 0xBB, 0xBA, 0x44, 0xBE, 0x31, 474 | 0x46, 0x01, 0x7E, 0xE1, 0x05, 0xD4, 0x18, 0x1A, 0x31, 0x47, 0xC7, 0xB3, 0xF8, 0x7D, 0xBF, 0x0D, 475 | 0xCF, 0x27, 0x53, 0xE2, 0xCA, 0x91, 0x42, 0xD9, 0x5F, 0x7D, 0x07, 0x86, 0xC6, 0x54, 0xDF, 0x1A, 476 | 0x47, 0xFD, 0xF3, 0xD6, 0x11, 0x7B, 0x1C, 0x0F, 0x60, 0x80, 0x1F, 0x00, 0x02, 0x0C, 0x03, 0x20, 477 | 0xC0, 0x87, 0x23, 0xF9, 0x78, 0x20, 0x76, 0x1A, 0xDC, 0xE4, 0x4C, 0x40, 0x26, 0x6D, 0xED, 0x48, 478 | 0xE0, 0x74, 0xC4, 0x1E, 0x34, 0xBE, 0x89, 0x29, 0x83, 0x99, 0xB7, 0x2A, 0xA2, 0xF4, 0xF1, 0xDC, 479 | 0x5B, 0xE2, 0x0C, 0x71, 0x4C, 0x2D, 0xBD, 0xB9, 0x74, 0xEA, 0xC8, 0xEB, 0x8F, 0x8E, 0xA3, 0x01, 480 | 0xF1, 0x7B, 0xCC, 0x86, 0x06, 0xF5, 0x43, 0x9C, 0x66, 0x8B, 0xDD, 0x32, 0xAE, 0x91, 0x58, 0x85, 481 | 0x8C, 0x27, 0xC8, 0x09, 0x32, 0x9C, 0xC3, 0x85, 0x8D, 0x28, 0x7E, 0xC7, 0x76, 0x0C, 0x61, 0x40, 482 | 0x0D, 0x3B, 0x27, 0x62, 0xFB, 0xF0, 0x44, 0x9E, 0x79, 0x03, 0x7C, 0x29, 0x3E, 0x4E, 0x66, 0x55, 483 | 0x7F, 0x06, 0x8A, 0xF4, 0xD7, 0xA1, 0xE1, 0x86, 0x10, 0xC2, 0x8F, 0xB9, 0x0A, 0x46, 0x3F, 0x75, 484 | 0x96, 0x53, 0x3B, 0x90, 0x9D, 0xE4, 0x3B, 0xDB, 0xF9, 0x9C, 0xFC, 0x47, 0x32, 0x61, 0x13, 0x37, 485 | 0xF8, 0x1B, 0xE4, 0x87, 0xC0, 0xE3, 0x28, 0xCA, 0xEE, 0x47, 0xC9, 0x8B, 0x79, 0x55, 0x22, 0x6E, 486 | 0x87, 0x86, 0xEC, 0x83, 0xE5, 0xF9, 0xA5, 0x3C, 0x71, 0xF7, 0xEE, 0x32, 0xE6, 0x6B, 0x28, 0xC3, 487 | 0xE0, 0x54, 0x72, 0xE2, 0x06, 0x4E, 0x28, 0x4F, 0x3F, 0xAF, 0xF3, 0xCE, 0xF0, 0x88, 0x98, 0x2B, 488 | 0x1C, 0xEE, 0xC4, 0x92, 0xA7, 0x2C, 0xF0, 0xE0, 0x41, 0x9A, 0xDB, 0xDD, 0xA1, 0xA4, 0x4A, 0x34, 489 | 0x11, 0xE3, 0x21, 0x32, 0x20, 0xF2, 0x40, 0x6D, 0xF9, 0x4C, 0xBC, 0x14, 0x89, 0x4C, 0x6A, 0x77, 490 | 0x53, 0x86, 0x8F, 0x65, 0x9C, 0x30, 0x13, 0x11, 0x9B, 0x1B, 0x88, 0x5F, 0x33, 0x3C, 0x4E, 0x9E, 491 | 0x7A, 0x15, 0xF2, 0x3D, 0xE6, 0x5E, 0x5F, 0xC3, 0xF2, 0xF2, 0xDB, 0x31, 0xD8, 0x9F, 0x39, 0x73, 492 | 0xF2, 0x83, 0x1C, 0x9F, 0x4C, 0xA5, 0x72, 0x9C, 0xA6, 0x38, 0x32, 0xC5, 0x32, 0x72, 0xB3, 0x0F, 493 | 0x9F, 0x00, 0x86, 0xB2, 0x9D, 0xEF, 0xE4, 0xF9, 0xFC, 0x8C, 0x39, 0xD9, 0x87, 0x4F, 0xBC, 0x3E, 494 | 0xB0, 0x50, 0x82, 0xE8, 0x0E, 0x09, 0x8D, 0x62, 0x9C, 0xDD, 0x6A, 0xCC, 0x54, 0xE2, 0x22, 0xC0, 495 | 0x61, 0x11, 0xAB, 0x4C, 0x01, 0xD7, 0x30, 0x14, 0x01, 0x55, 0x13, 0xF5, 0xE9, 0x29, 0xAF, 0x35, 496 | 0x8C, 0xB9, 0x8C, 0x95, 0xF4, 0xEF, 0x77, 0x54, 0xE1, 0x6F, 0xA2, 0xF0, 0x89, 0x53, 0x99, 0x8A, 497 | 0x27, 0xF3, 0xE3, 0xC8, 0x62, 0xCC, 0xD5, 0x13, 0x87, 0x91, 0xAF, 0x2B, 0x89, 0xFC, 0x3C, 0x31, 498 | 0xAB, 0x05, 0x39, 0x4C, 0xF1, 0xF8, 0x7E, 0x46, 0x54, 0xD5, 0xD5, 0x41, 0xEE, 0x96, 0xA1, 0xBE, 499 | 0x80, 0x64, 0x0C, 0xA9, 0xF0, 0x63, 0x8A, 0x0F, 0xDF, 0xB0, 0x8F, 0x99, 0x88, 0xDF, 0xC4, 0xE5, 500 | 0xFD, 0xBA, 0xE7, 0x62, 0x3D, 0x77, 0xD5, 0xD9, 0x75, 0x3C, 0x45, 0x29, 0xCE, 0x32, 0x0D, 0xC7, 501 | 0x73, 0x42, 0x35, 0x0C, 0x8F, 0x20, 0x0D, 0xEB, 0x78, 0xC9, 0x06, 0x2D, 0x21, 0xF0, 0x31, 0x0D, 502 | 0x7D, 0x57, 0x8D, 0x26, 0x91, 0x91, 0xFE, 0x0E, 0xB1, 0x7F, 0x0D, 0x8C, 0x3E, 0xDC, 0xFF, 0x14, 503 | 0xE5, 0xF7, 0x9B, 0x53, 0xFE, 0x6C, 0x8E, 0xE7, 0x3C, 0x86, 0x0A, 0x30, 0xBC, 0xFF, 0x89, 0x43, 504 | 0x7D, 0xF3, 0x00, 0xA6, 0x84, 0x2F, 0x7C, 0xE2, 0x9B, 0x0F, 0x82, 0xC5, 0x84, 0xBD, 0x3E, 0xBB, 505 | 0xC6, 0x59, 0x44, 0xB8, 0x35, 0xE8, 0x0C, 0xBB, 0x35, 0x1F, 0x07, 0x0B, 0x60, 0x8F, 0x93, 0x44, 506 | 0x16, 0xCD, 0xE8, 0x39, 0x18, 0x4A, 0xCD, 0xB4, 0xF6, 0xC1, 0xC7, 0x40, 0x07, 0x02, 0x50, 0xCF, 507 | 0xB8, 0xFF, 0x89, 0xB3, 0xB8, 0x31, 0x26, 0x10, 0xCD, 0xC1, 0x0C, 0xDB, 0x27, 0x50, 0x77, 0x10, 508 | 0x65, 0x4F, 0xA6, 0xDF, 0xFF, 0x14, 0xB1, 0x6A, 0x88, 0x9F, 0x6E, 0x3E, 0xC4, 0x1E, 0x12, 0x17, 509 | 0x83, 0xA8, 0x86, 0xF1, 0x13, 0x0D, 0xCE, 0xEB, 0x2D, 0x47, 0xC1, 0xF3, 0x9F, 0x38, 0x4E, 0xED, 510 | 0x48, 0xBC, 0x7E, 0x41, 0xE6, 0xE8, 0x06, 0x34, 0x9D, 0x97, 0x08, 0xC4, 0x56, 0x93, 0x3B, 0xCF, 511 | 0x3B, 0x9E, 0x6B, 0x39, 0xC4, 0xFA, 0xC8, 0x12, 0xF3, 0x71, 0x5A, 0x70, 0x11, 0xE9, 0x4E, 0x43, 512 | 0xBC, 0x4E, 0xEB, 0xB5, 0x67, 0xE3, 0x8C, 0x9B, 0x1E, 0x33, 0x31, 0x4E, 0x4F, 0xC1, 0xCA, 0xC8, 513 | 0x8E, 0x52, 0x92, 0xC0, 0x88, 0xBD, 0x77, 0x45, 0x98, 0x29, 0x65, 0x61, 0xA1, 0x8C, 0xD4, 0x45, 514 | 0xD8, 0x2C, 0xA9, 0xD6, 0x91, 0xCA, 0x89, 0xDB, 0x0A, 0xF4, 0x8C, 0xD8, 0x16, 0x7F, 0x05, 0x9E, 515 | 0x5B, 0x3B, 0xBE, 0x13, 0x9B, 0x61, 0x9D, 0x07, 0x9B, 0x40, 0x61, 0x90, 0x32, 0x51, 0x9E, 0x99, 516 | 0xD2, 0x5D, 0xFD, 0x51, 0x92, 0x49, 0x72, 0x6C, 0x26, 0x3E, 0x4A, 0x4D, 0xE3, 0x05, 0x8D, 0xCF, 517 | 0xFC, 0x07, 0x77, 0x9A, 0x3F, 0x4F, 0x44, 0x11, 0x54, 0x72, 0xD2, 0xB1, 0x62, 0x30, 0xE1, 0x81, 518 | 0xEC, 0xBF, 0x1E, 0x51, 0x1B, 0x11, 0xE8, 0xAE, 0x2F, 0x1D, 0xCC, 0x0E, 0x9F, 0x5E, 0xFF, 0x00, 519 | 0xC5, 0x5B, 0xB4, 0x20, 0x5C, 0x9A, 0x84, 0xE0, 0x22, 0x6E, 0xFF, 0x4A, 0x29, 0x93, 0x56, 0x51, 520 | 0xE1, 0xC1, 0xDB, 0x77, 0x91, 0x71, 0x8A, 0x38, 0xC4, 0x9D, 0x7E, 0x8A, 0x94, 0x71, 0x2D, 0xA7, 521 | 0x4D, 0xF5, 0xF7, 0x0A, 0xBD, 0x9A, 0xED, 0x8A, 0xE8, 0x95, 0x96, 0x5E, 0xA1, 0xE6, 0xAE, 0x5C, 522 | 0x4E, 0xAC, 0x36, 0xB7, 0x47, 0x8A, 0xB1, 0x03, 0xEA, 0x2D, 0xC4, 0x1A, 0x23, 0xE3, 0xE6, 0x2B, 523 | 0xE2, 0xDA, 0xDE, 0xAA, 0xC1, 0xCE, 0xD7, 0x64, 0x91, 0x54, 0x15, 0x6D, 0x10, 0x17, 0x0C, 0xF8, 524 | 0xE2, 0x97, 0x57, 0x2F, 0x59, 0xD2, 0x51, 0xD7, 0x2A, 0x47, 0xE9, 0x0E, 0x87, 0xBF, 0xEB, 0x5C, 525 | 0x3B, 0x03, 0x83, 0xAD, 0x01, 0x4D, 0xB3, 0x48, 0x36, 0x71, 0x63, 0xC9, 0x62, 0x81, 0x1D, 0x7E, 526 | 0x10, 0x73, 0xB2, 0xD2, 0x93, 0x02, 0xF8, 0xB8, 0x54, 0x16, 0x6F, 0x91, 0x15, 0x05, 0x22, 0xF1, 527 | 0x09, 0xA5, 0xE0, 0xB0, 0x86, 0x70, 0xE5, 0x80, 0x65, 0x19, 0xB9, 0xCE, 0xBB, 0x63, 0xA8, 0xE0, 528 | 0xE7, 0x04, 0x7D, 0x62, 0x26, 0x19, 0x65, 0x69, 0xE1, 0x95, 0x4C, 0x89, 0x16, 0x10, 0x99, 0xF8, 529 | 0xF1, 0x7B, 0x6B, 0x0C, 0xC9, 0xF1, 0x19, 0x78, 0x7E, 0xC3, 0x05, 0x0D, 0x8E, 0x6F, 0x8A, 0xD4, 530 | 0x11, 0xE6, 0x4A, 0x80, 0xAC, 0x2A, 0x04, 0x4F, 0x43, 0x7A, 0x6E, 0x29, 0xFB, 0xE8, 0xD9, 0xA9, 531 | 0xDE, 0x2B, 0xAE, 0xDD, 0xB2, 0x36, 0x2D, 0xCF, 0xB0, 0xC3, 0x75, 0xD3, 0x8A, 0x3E, 0x25, 0xC5, 532 | 0x20, 0x49, 0x30, 0x6B, 0xC2, 0x66, 0xDA, 0x14, 0xC5, 0x2F, 0xA2, 0x01, 0x91, 0xEC, 0x6A, 0x40, 533 | 0xE4, 0xC8, 0x9E, 0xEE, 0xE2, 0x32, 0xED, 0x42, 0x06, 0x72, 0x99, 0xC5, 0x0C, 0xF6, 0xD6, 0x8F, 534 | 0x19, 0x2B, 0xD0, 0xD2, 0x09, 0xAA, 0x14, 0x0A, 0x6D, 0x06, 0x2C, 0xAC, 0x18, 0x62, 0x86, 0x48, 535 | 0xDA, 0x6C, 0xB7, 0x99, 0xAE, 0x0E, 0x17, 0x21, 0x58, 0x69, 0x1E, 0xF9, 0xA4, 0xF8, 0x8D, 0xB5, 536 | 0x6C, 0x71, 0xF0, 0x40, 0x0B, 0x57, 0x14, 0xD4, 0x70, 0x5A, 0xC9, 0x04, 0xB2, 0xDF, 0x2B, 0x21, 537 | 0x50, 0xEE, 0xBA, 0xE0, 0xB4, 0xF0, 0xD3, 0xBA, 0xD8, 0x1A, 0x23, 0xC3, 0xB8, 0xE3, 0x18, 0x73, 538 | 0x46, 0x24, 0xBB, 0xA2, 0x04, 0xF1, 0xF5, 0xEE, 0x34, 0x0B, 0xF9, 0x5A, 0x57, 0x7A, 0xA3, 0xA0, 539 | 0x15, 0xDD, 0xB7, 0x96, 0xE8, 0x83, 0x8B, 0x95, 0xC7, 0xAA, 0xF2, 0x51, 0x97, 0x5D, 0x42, 0xA1, 540 | 0xDE, 0x65, 0x27, 0xD4, 0xC7, 0x15, 0xD5, 0xC7, 0x52, 0x7D, 0x46, 0x90, 0x34, 0x84, 0xE5, 0x2D, 541 | 0x7F, 0xEC, 0x8C, 0xBF, 0x3D, 0x4D, 0x34, 0x5B, 0x8D, 0x0B, 0xE5, 0x94, 0xAD, 0xB8, 0xA2, 0x5E, 542 | 0x31, 0x41, 0xEA, 0x9E, 0x62, 0xA1, 0xD6, 0x6A, 0x5C, 0x4D, 0xAD, 0xA8, 0x95, 0x67, 0x04, 0x89, 543 | 0x5A, 0xFA, 0x86, 0x3F, 0x52, 0x25, 0xDE, 0x42, 0xE6, 0xFF, 0xA7, 0x4B, 0xFC, 0xCE, 0x94, 0x58, 544 | 0x58, 0xB1, 0xFF, 0x5A, 0x5A, 0xCA, 0xC4, 0x30, 0x45, 0xC9, 0x78, 0xC9, 0x50, 0x4A, 0x1A, 0x8F, 545 | 0x54, 0xA8, 0x63, 0x39, 0x0A, 0xA9, 0xA3, 0x41, 0xA2, 0x06, 0xC6, 0x5F, 0x2B, 0x19, 0x2B, 0x1E, 546 | 0x9D, 0x04, 0x42, 0xC2, 0x40, 0x34, 0xE0, 0x23, 0xE3, 0x2C, 0xBB, 0xD4, 0x14, 0x8D, 0x90, 0x50, 547 | 0x36, 0xD3, 0xFE, 0xA8, 0x03, 0x62, 0x95, 0x52, 0x63, 0xE2, 0x00, 0x11, 0xF4, 0x79, 0x62, 0x96, 548 | 0x8A, 0x82, 0x1C, 0xEC, 0xD3, 0x9A, 0xF9, 0x93, 0x83, 0xD9, 0xF2, 0x41, 0xDE, 0x14, 0x7E, 0xF1, 549 | 0xC3, 0x73, 0xC3, 0xF3, 0x0D, 0xF1, 0x16, 0x4D, 0x3F, 0x7E, 0x6B, 0x8E, 0x21, 0x5F, 0x31, 0xC7, 550 | 0x17, 0x69, 0xC4, 0x9D, 0x1A, 0x74, 0x46, 0x02, 0xE8, 0x59, 0xD9, 0x93, 0xE0, 0xF8, 0xAE, 0x19, 551 | 0xBF, 0x45, 0xAE, 0x54, 0x3D, 0xD1, 0xA4, 0x7E, 0x17, 0x2B, 0x92, 0x31, 0xA7, 0xA0, 0x49, 0x6C, 552 | 0x79, 0x57, 0xEA, 0xB8, 0x96, 0x58, 0x8A, 0x96, 0x85, 0x1B, 0x98, 0x30, 0x3E, 0xFD, 0xC5, 0x5A, 553 | 0x51, 0xAF, 0x40, 0xA9, 0x21, 0x63, 0xB2, 0xC4, 0x96, 0x89, 0xAE, 0x6B, 0xD6, 0xD4, 0xAD, 0xBD, 554 | 0x0B, 0x10, 0x65, 0x5B, 0x49, 0xDA, 0x6C, 0x9E, 0x8F, 0x8A, 0xB0, 0xB8, 0xA8, 0x72, 0xE2, 0x33, 555 | 0x38, 0x8D, 0x36, 0x2C, 0xC5, 0x37, 0xF1, 0x52, 0xAE, 0xC1, 0xA9, 0xF8, 0x9F, 0x0A, 0xFF, 0x0B, 556 | 0x9B, 0xFC, 0x8E, 0x51, 0xC1, 0x70, 0x00, 0x00 557 | }; 558 | -------------------------------------------------------------------------------- /board/src/camera_pins.h: -------------------------------------------------------------------------------- 1 | 2 | #if defined(CAMERA_MODEL_WROVER_KIT) 3 | #define PWDN_GPIO_NUM -1 4 | #define RESET_GPIO_NUM -1 5 | #define XCLK_GPIO_NUM 21 6 | #define SIOD_GPIO_NUM 26 7 | #define SIOC_GPIO_NUM 27 8 | 9 | #define Y9_GPIO_NUM 35 10 | #define Y8_GPIO_NUM 34 11 | #define Y7_GPIO_NUM 39 12 | #define Y6_GPIO_NUM 36 13 | #define Y5_GPIO_NUM 19 14 | #define Y4_GPIO_NUM 18 15 | #define Y3_GPIO_NUM 5 16 | #define Y2_GPIO_NUM 4 17 | #define VSYNC_GPIO_NUM 25 18 | #define HREF_GPIO_NUM 23 19 | #define PCLK_GPIO_NUM 22 20 | 21 | #elif defined(CAMERA_MODEL_ESP_EYE) 22 | #define PWDN_GPIO_NUM -1 23 | #define RESET_GPIO_NUM -1 24 | #define XCLK_GPIO_NUM 4 25 | #define SIOD_GPIO_NUM 18 26 | #define SIOC_GPIO_NUM 23 27 | 28 | #define Y9_GPIO_NUM 36 29 | #define Y8_GPIO_NUM 37 30 | #define Y7_GPIO_NUM 38 31 | #define Y6_GPIO_NUM 39 32 | #define Y5_GPIO_NUM 35 33 | #define Y4_GPIO_NUM 14 34 | #define Y3_GPIO_NUM 13 35 | #define Y2_GPIO_NUM 34 36 | #define VSYNC_GPIO_NUM 5 37 | #define HREF_GPIO_NUM 27 38 | #define PCLK_GPIO_NUM 25 39 | 40 | #elif defined(CAMERA_MODEL_M5STACK_PSRAM) 41 | #define PWDN_GPIO_NUM -1 42 | #define RESET_GPIO_NUM 15 43 | #define XCLK_GPIO_NUM 27 44 | #define SIOD_GPIO_NUM 25 45 | #define SIOC_GPIO_NUM 23 46 | 47 | #define Y9_GPIO_NUM 19 48 | #define Y8_GPIO_NUM 36 49 | #define Y7_GPIO_NUM 18 50 | #define Y6_GPIO_NUM 39 51 | #define Y5_GPIO_NUM 5 52 | #define Y4_GPIO_NUM 34 53 | #define Y3_GPIO_NUM 35 54 | #define Y2_GPIO_NUM 32 55 | #define VSYNC_GPIO_NUM 22 56 | #define HREF_GPIO_NUM 26 57 | #define PCLK_GPIO_NUM 21 58 | 59 | #elif defined(CAMERA_MODEL_M5STACK_V2_PSRAM) 60 | #define PWDN_GPIO_NUM -1 61 | #define RESET_GPIO_NUM 15 62 | #define XCLK_GPIO_NUM 27 63 | #define SIOD_GPIO_NUM 22 64 | #define SIOC_GPIO_NUM 23 65 | 66 | #define Y9_GPIO_NUM 19 67 | #define Y8_GPIO_NUM 36 68 | #define Y7_GPIO_NUM 18 69 | #define Y6_GPIO_NUM 39 70 | #define Y5_GPIO_NUM 5 71 | #define Y4_GPIO_NUM 34 72 | #define Y3_GPIO_NUM 35 73 | #define Y2_GPIO_NUM 32 74 | #define VSYNC_GPIO_NUM 25 75 | #define HREF_GPIO_NUM 26 76 | #define PCLK_GPIO_NUM 21 77 | 78 | #elif defined(CAMERA_MODEL_M5STACK_WIDE) 79 | #define PWDN_GPIO_NUM -1 80 | #define RESET_GPIO_NUM 15 81 | #define XCLK_GPIO_NUM 27 82 | #define SIOD_GPIO_NUM 22 83 | #define SIOC_GPIO_NUM 23 84 | 85 | #define Y9_GPIO_NUM 19 86 | #define Y8_GPIO_NUM 36 87 | #define Y7_GPIO_NUM 18 88 | #define Y6_GPIO_NUM 39 89 | #define Y5_GPIO_NUM 5 90 | #define Y4_GPIO_NUM 34 91 | #define Y3_GPIO_NUM 35 92 | #define Y2_GPIO_NUM 32 93 | #define VSYNC_GPIO_NUM 25 94 | #define HREF_GPIO_NUM 26 95 | #define PCLK_GPIO_NUM 21 96 | 97 | #elif defined(CAMERA_MODEL_M5STACK_ESP32CAM) 98 | #define PWDN_GPIO_NUM -1 99 | #define RESET_GPIO_NUM 15 100 | #define XCLK_GPIO_NUM 27 101 | #define SIOD_GPIO_NUM 25 102 | #define SIOC_GPIO_NUM 23 103 | 104 | #define Y9_GPIO_NUM 19 105 | #define Y8_GPIO_NUM 36 106 | #define Y7_GPIO_NUM 18 107 | #define Y6_GPIO_NUM 39 108 | #define Y5_GPIO_NUM 5 109 | #define Y4_GPIO_NUM 34 110 | #define Y3_GPIO_NUM 35 111 | #define Y2_GPIO_NUM 17 112 | #define VSYNC_GPIO_NUM 22 113 | #define HREF_GPIO_NUM 26 114 | #define PCLK_GPIO_NUM 21 115 | 116 | #elif defined(CAMERA_MODEL_AI_THINKER) 117 | #define PWDN_GPIO_NUM 32 118 | #define RESET_GPIO_NUM -1 119 | #define XCLK_GPIO_NUM 0 120 | #define SIOD_GPIO_NUM 26 121 | #define SIOC_GPIO_NUM 27 122 | 123 | #define Y9_GPIO_NUM 35 124 | #define Y8_GPIO_NUM 34 125 | #define Y7_GPIO_NUM 39 126 | #define Y6_GPIO_NUM 36 127 | #define Y5_GPIO_NUM 21 128 | #define Y4_GPIO_NUM 19 129 | #define Y3_GPIO_NUM 18 130 | #define Y2_GPIO_NUM 5 131 | #define VSYNC_GPIO_NUM 25 132 | #define HREF_GPIO_NUM 23 133 | #define PCLK_GPIO_NUM 22 134 | 135 | #elif defined(CAMERA_MODEL_TTGO_T_JOURNAL) 136 | #define PWDN_GPIO_NUM 0 137 | #define RESET_GPIO_NUM 15 138 | #define XCLK_GPIO_NUM 27 139 | #define SIOD_GPIO_NUM 25 140 | #define SIOC_GPIO_NUM 23 141 | 142 | #define Y9_GPIO_NUM 19 143 | #define Y8_GPIO_NUM 36 144 | #define Y7_GPIO_NUM 18 145 | #define Y6_GPIO_NUM 39 146 | #define Y5_GPIO_NUM 5 147 | #define Y4_GPIO_NUM 34 148 | #define Y3_GPIO_NUM 35 149 | #define Y2_GPIO_NUM 17 150 | #define VSYNC_GPIO_NUM 22 151 | #define HREF_GPIO_NUM 26 152 | #define PCLK_GPIO_NUM 21 153 | 154 | #else 155 | #error "Camera model not selected" 156 | #endif 157 | -------------------------------------------------------------------------------- /board/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "esp_camera.h" 4 | #include 5 | #include "WebSocketsClient.h" 6 | 7 | // 8 | // WARNING!!! PSRAM IC required for UXGA resolution and high JPEG quality 9 | // Ensure ESP32 Wrover Module or other board with PSRAM is selected 10 | // Partial images will be transmitted if image exceeds buffer size 11 | // 12 | 13 | // Select camera model 14 | //#define CAMERA_MODEL_WROVER_KIT // Has PSRAM 15 | //#define CAMERA_MODEL_ESP_EYE // Has PSRAM 16 | //#define CAMERA_MODEL_M5STACK_PSRAM // Has PSRAM 17 | //#define CAMERA_MODEL_M5STACK_V2_PSRAM // M5Camera version B Has PSRAM 18 | //#define CAMERA_MODEL_M5STACK_WIDE // Has PSRAM 19 | //#define CAMERA_MODEL_M5STACK_ESP32CAM // No PSRAM 20 | #define CAMERA_MODEL_AI_THINKER // Has PSRAM 21 | //#define CAMERA_MODEL_TTGO_T_JOURNAL // No PSRAM 22 | 23 | #include "camera_pins.h" 24 | #include "config.h" 25 | #include "action.h" 26 | 27 | const char *ssid = WIFI_NAME; 28 | const char *password = WIFI_PASSWORD; 29 | WebSocketsClient webSocket; 30 | 31 | #include "ESP32Servo.h" 32 | #define PIN_SERVO 12 //定义舵机引脚 33 | Servo servo; 34 | const int minUs = 1000; 35 | const int maxUs = 2000; 36 | 37 | bool isOpenCamera; 38 | 39 | //本地http服务器渲染 40 | void startCameraServer(); 41 | 42 | void log(const char *format, ...) { 43 | Serial.printf(format); 44 | } 45 | 46 | void logln(const char *format, ...) { 47 | 48 | } 49 | 50 | bool initCamera() { 51 | camera_config_t config; 52 | config.ledc_channel = LEDC_CHANNEL_0; 53 | config.ledc_timer = LEDC_TIMER_0; 54 | config.pin_d0 = Y2_GPIO_NUM; 55 | config.pin_d1 = Y3_GPIO_NUM; 56 | config.pin_d2 = Y4_GPIO_NUM; 57 | config.pin_d3 = Y5_GPIO_NUM; 58 | config.pin_d4 = Y6_GPIO_NUM; 59 | config.pin_d5 = Y7_GPIO_NUM; 60 | config.pin_d6 = Y8_GPIO_NUM; 61 | config.pin_d7 = Y9_GPIO_NUM; 62 | config.pin_xclk = XCLK_GPIO_NUM; 63 | config.pin_pclk = PCLK_GPIO_NUM; 64 | config.pin_vsync = VSYNC_GPIO_NUM; 65 | config.pin_href = HREF_GPIO_NUM; 66 | config.pin_sscb_sda = SIOD_GPIO_NUM; 67 | config.pin_sscb_scl = SIOC_GPIO_NUM; 68 | config.pin_pwdn = PWDN_GPIO_NUM; 69 | config.pin_reset = RESET_GPIO_NUM; 70 | config.xclk_freq_hz = 20000000; 71 | config.pixel_format = PIXFORMAT_JPEG; 72 | 73 | // if PSRAM IC present, init with UXGA resolution and higher JPEG quality 74 | // for larger pre-allocated frame buffer. 75 | if (psramFound()) { 76 | config.frame_size = FRAMESIZE_UXGA; 77 | config.jpeg_quality = 10; 78 | config.fb_count = 2; 79 | } else { 80 | config.frame_size = FRAMESIZE_SVGA; 81 | config.jpeg_quality = 12; 82 | config.fb_count = 1; 83 | } 84 | 85 | #if defined(CAMERA_MODEL_ESP_EYE) 86 | pinMode(13, INPUT_PULLUP); 87 | pinMode(14, INPUT_PULLUP); 88 | #endif 89 | 90 | // camera init 91 | esp_err_t err = esp_camera_init(&config); 92 | if (err != ESP_OK) { 93 | Serial.printf("Camera init failed with error 0x%x", err); 94 | return false; 95 | } 96 | 97 | sensor_t *s = esp_camera_sensor_get(); 98 | // initial sensors are flipped vertically and colors are a bit saturated 99 | if (s->id.PID == OV3660_PID) { 100 | s->set_vflip(s, 1); // flip it back 101 | s->set_brightness(s, 1); // up the brightness just a bit 102 | s->set_saturation(s, -2); // lower the saturation 103 | } 104 | // drop down frame size for higher initial frame rate 105 | s->set_framesize(s, FRAMESIZE_VGA); 106 | 107 | #if defined(CAMERA_MODEL_M5STACK_WIDE) || defined(CAMERA_MODEL_M5STACK_ESP32CAM) 108 | s->set_vflip(s, 1); 109 | s->set_hmirror(s, 1); 110 | #endif 111 | Serial.printf("Camera init success"); 112 | return true; 113 | } 114 | 115 | void captureVideo() { 116 | camera_fb_t *fb = NULL; 117 | 118 | fb = esp_camera_fb_get(); 119 | if (NULL == fb) { 120 | Serial.println("Camera capture failed"); 121 | } else { 122 | webSocket.sendBIN(fb->buf, fb->len); 123 | esp_camera_fb_return(fb); 124 | fb = NULL; 125 | } 126 | } 127 | 128 | void initWifi() { 129 | WiFi.begin(ssid, password); 130 | while (WiFi.status() != WL_CONNECTED) { 131 | delay(500); 132 | Serial.print("."); 133 | } 134 | Serial.println(""); 135 | Serial.println("WiFi connected"); 136 | } 137 | 138 | void hexdump(const void *mem, uint32_t len, uint8_t cols = 16) { 139 | const uint8_t* src = (const uint8_t*) mem; 140 | Serial.printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len); 141 | for(uint32_t i = 0; i < len; i++) { 142 | if(i % cols == 0) { 143 | Serial.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i); 144 | } 145 | Serial.printf("%02X ", *src); 146 | src++; 147 | } 148 | Serial.printf("\n"); 149 | } 150 | 151 | void initServo() { 152 | int channel = ESP32PWM::timerAndIndexToChannel(2, 0); 153 | ESP32PWM::allocateTimer(2); 154 | servo.setPeriodHertz(50); 155 | servo.attach(PIN_SERVO, minUs, maxUs); 156 | Serial.printf("ESP32PWM channel %d", channel); 157 | } 158 | 159 | void turnTo(int degree) { 160 | if (degree < 0) degree = 0; 161 | if (degree > 180) degree = 180; 162 | servo.write(degree); 163 | delay(100); 164 | } 165 | 166 | void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) { 167 | const char* message = reinterpret_cast(payload); 168 | switch(type) { 169 | case WStype_DISCONNECTED: 170 | Serial.printf("[WSc] Disconnected!\n"); 171 | break; 172 | case WStype_CONNECTED: 173 | Serial.printf("[WSc] Connected to url: %s\n", payload); 174 | // send message to server when Connected 175 | webSocket.sendTXT("Uploader Connected"); 176 | break; 177 | case WStype_TEXT: 178 | Serial.printf("[WSc] get text: %s\n", message); 179 | if (strcmp(message, ACTION_OPEN_CAMERA) == 0) { 180 | Serial.println("[WSc] action: open camera"); 181 | isOpenCamera = true; 182 | } 183 | if (strcmp(message, ACTION_CLOSE_CAMERA) == 0) { 184 | Serial.println("[WSc] action: close camera"); 185 | isOpenCamera = false; 186 | } 187 | if (strcmp(message, ACTION_TURN0) == 0) { 188 | Serial.println("[WSc] action: turn0"); 189 | turnTo(0); 190 | } 191 | if (strcmp(message, ACTION_TURN90) == 0) { 192 | Serial.println("[WSc] action: turn90"); 193 | turnTo(90); 194 | } 195 | if (strcmp(message, ACTION_TURN180) == 0) { 196 | Serial.println("[WSc] action: turn180"); 197 | turnTo(180); 198 | } 199 | // send message to server 200 | // webSocket.sendTXT("message here"); 201 | break; 202 | case WStype_BIN: 203 | Serial.printf("[WSc] get binary length: %u\n", length); 204 | hexdump(payload, length); 205 | // send data to server 206 | // webSocket.sendBIN(payload, length); 207 | break; 208 | case WStype_ERROR: 209 | Serial.printf("[WSc] ERROR : %s\n", payload); 210 | break; 211 | case WStype_FRAGMENT_TEXT_START: 212 | Serial.printf("[WSc] FRAGMENT_TEXT_START : %s\n", payload); 213 | break; 214 | case WStype_FRAGMENT_BIN_START: 215 | Serial.printf("[WSc] FRAGMENT_BIN_START: %s\n", payload); 216 | break; 217 | case WStype_FRAGMENT: 218 | Serial.printf("[WSc] FRAGMENT: %s\n", payload); 219 | break; 220 | case WStype_FRAGMENT_FIN: 221 | Serial.printf("[WSc] FRAGMENT_FIN: %s\n", payload); 222 | break; 223 | } 224 | } 225 | 226 | void initWebSocket() { 227 | Serial.println("initWebSocket"); 228 | webSocket.begin(WEBSOCKET_HOST, WEBSOCKET_PORT, WEBSOCKET_URL); 229 | // event handler 230 | webSocket.onEvent(webSocketEvent); 231 | webSocket.setReconnectInterval(3000); 232 | webSocket.enableHeartbeat(15000, 3000, 2); 233 | } 234 | 235 | void setup() { 236 | Serial.begin(115200); 237 | Serial.println(); 238 | 239 | initCamera(); 240 | initWifi(); 241 | initWebSocket(); 242 | initServo(); 243 | turnTo(0); 244 | } 245 | 246 | void loop() { 247 | webSocket.loop(); 248 | if (webSocket.isConnected() && isOpenCamera) { 249 | captureVideo(); 250 | } 251 | } -------------------------------------------------------------------------------- /board/test/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for PlatformIO Unit Testing and project tests. 3 | 4 | Unit Testing is a software testing method by which individual units of 5 | source code, sets of one or more MCU program modules together with associated 6 | control data, usage procedures, and operating procedures, are tested to 7 | determine whether they are fit for use. Unit testing finds problems early 8 | in the development cycle. 9 | 10 | More information about PlatformIO Unit Testing: 11 | - https://docs.platformio.org/page/plus/unit-testing.html 12 | -------------------------------------------------------------------------------- /image/ESP32-CAM-CONNECTION.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guohuanwen/esp32-cam/75d955c908edf3ded0384bde639c9907d97fd5f9/image/ESP32-CAM-CONNECTION.png -------------------------------------------------------------------------------- /image/ESP32-CAM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guohuanwen/esp32-cam/75d955c908edf3ded0384bde639c9907d97fd5f9/image/ESP32-CAM.png -------------------------------------------------------------------------------- /image/circuit.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guohuanwen/esp32-cam/75d955c908edf3ded0384bde639c9907d97fd5f9/image/circuit.sketch -------------------------------------------------------------------------------- /image/product.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guohuanwen/esp32-cam/75d955c908edf3ded0384bde639c9907d97fd5f9/image/product.jpg -------------------------------------------------------------------------------- /image/v1.1.0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guohuanwen/esp32-cam/75d955c908edf3ded0384bde639c9907d97fd5f9/image/v1.1.0.png -------------------------------------------------------------------------------- /servers/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | camera.log -------------------------------------------------------------------------------- /servers/build-linux.sh: -------------------------------------------------------------------------------- 1 | CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o ./build/camera src/main.go -------------------------------------------------------------------------------- /servers/build.sh: -------------------------------------------------------------------------------- 1 | go build -o ./build/camera src/main.go -------------------------------------------------------------------------------- /servers/go.mod: -------------------------------------------------------------------------------- 1 | module camera 2 | 3 | go 1.15 4 | 5 | require github.com/gorilla/websocket v1.4.2 -------------------------------------------------------------------------------- /servers/go.sum: -------------------------------------------------------------------------------- 1 | github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= 2 | github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 3 | -------------------------------------------------------------------------------- /servers/html/client.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | CANVAS VIDEO 7 | 12 | 13 | 14 | 15 | 16 |

 17 | 

 18 | 
 19 | 
 20 | 
 21 | 
 22 | 
 23 | 
 24 | 
118 | 
119 | 
120 | 


--------------------------------------------------------------------------------
/servers/html/uploader.html:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 | 
 4 |     Chat Example
 5 |     
53 |     
90 | 
91 | 
92 | 
93 |
94 | 95 | 96 |
97 | 98 | 99 | -------------------------------------------------------------------------------- /servers/src/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "camera/src/socket" 5 | "log" 6 | "net/http" 7 | ) 8 | 9 | const ( 10 | PART_BOUNDARY = "123456789000000000000987654321" 11 | STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" + PART_BOUNDARY 12 | STREAM_BOUNDARY = "\r\n--" + PART_BOUNDARY + "\r\n" 13 | STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %d\r\n\r\n" 14 | ) 15 | 16 | func init() { 17 | log.Print("init") 18 | } 19 | 20 | func main() { 21 | defer log.Printf("serves exited...") 22 | log.Printf("serves start") 23 | serverMux := http.NewServeMux() 24 | var hub *socket.Hub 25 | hub = socket.SetupHub() 26 | socket.SetupUploader(serverMux, hub) 27 | socket.SetupClient(serverMux, hub) 28 | server := http.Server{ 29 | Addr: ":8080", 30 | Handler: serverMux, 31 | } 32 | server.ListenAndServe() 33 | } -------------------------------------------------------------------------------- /servers/src/socket/action.go: -------------------------------------------------------------------------------- 1 | package socket 2 | 3 | const ( 4 | ACTION_OPEN_CAMERA = "OpenCamera" 5 | ACTION_CLOSE_CAMERA = "CloseCamera" 6 | ACTION_TURN0 = "Turn0" 7 | ACTION_TURN90 = "Turn90" 8 | ACTION_TURN180 = "Turn180" 9 | ) 10 | -------------------------------------------------------------------------------- /servers/src/socket/client.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package socket 6 | 7 | import ( 8 | "bytes" 9 | "log" 10 | "time" 11 | "github.com/gorilla/websocket" 12 | ) 13 | 14 | const ( 15 | // Time allowed to write a message to the peer. 16 | writeWait = 10 * time.Second 17 | 18 | // Time allowed to read the next pong message from the peer. 19 | pongWait = 60 * time.Second 20 | 21 | // Send pings to peer with this period. Must be less than pongWait. 22 | pingPeriod = (pongWait * 9) / 10 23 | 24 | // Maximum message size allowed from peer. 25 | maxMessageSize = 51200 26 | ) 27 | 28 | var ( 29 | newline = []byte{'\n'} 30 | space = []byte{' '} 31 | ) 32 | 33 | // Client is a middleman between the websocket connection and the hub. 34 | type Client struct { 35 | hub *Hub 36 | 37 | // The websocket connection. 38 | conn *websocket.Conn 39 | 40 | // Buffered channel of outbound messages. 41 | send chan []byte 42 | 43 | sender int 44 | } 45 | 46 | // readPump pumps messages from the websocket connection to the hub. 47 | // 48 | // The application runs readPump in a per-connection goroutine. The application 49 | // ensures that there is at most one reader on a connection by executing all 50 | // reads from this goroutine. 51 | func (c *Client) readPump() { 52 | defer func() { 53 | c.hub.unregister <- c 54 | c.conn.Close() 55 | }() 56 | c.conn.SetReadLimit(maxMessageSize) 57 | c.conn.SetReadDeadline(time.Now().Add(pongWait)) 58 | c.conn.SetPongHandler(func(string) error { c.conn.SetReadDeadline(time.Now().Add(pongWait)); return nil }) 59 | for { 60 | msgType, message, err := c.conn.ReadMessage() 61 | if err != nil { 62 | if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) { 63 | log.Printf("error: %v", err) 64 | } 65 | break 66 | } 67 | switch msgType { 68 | case websocket.TextMessage: 69 | message = bytes.TrimSpace(bytes.Replace(message, newline, space, -1)) 70 | var text = string(message) 71 | log.Print("rev text " + text) 72 | c.hub.broadcast <- &Broadcast{data: message, sender: c.sender} 73 | if text == "open" { 74 | log.Print("open") 75 | log.Print("startPushStream") 76 | } else if text == "close" { 77 | log.Print("close") 78 | log.Print("stopPushStream") 79 | } else if text == "turnTo0" { 80 | log.Print("turnTo0") 81 | } else if text == "turnTo90" { 82 | log.Print("turnTo90") 83 | } else if text == "turnTo180" { 84 | log.Print("turnTo180") 85 | } 86 | break 87 | case websocket.BinaryMessage: 88 | log.Print("rev binary size %d", len(message)) 89 | break 90 | case websocket.CloseMessage: 91 | log.Print("rev closes") 92 | break 93 | } 94 | } 95 | } 96 | 97 | // writePump pumps messages from the hub to the websocket connection. 98 | // 99 | // A goroutine running writePump is started for each connection. The 100 | // application ensures that there is at most one writer to a connection by 101 | // executing all writes from this goroutine. 102 | func (c *Client) writePump() { 103 | ticker := time.NewTicker(pingPeriod) 104 | defer func() { 105 | ticker.Stop() 106 | c.conn.Close() 107 | }() 108 | for { 109 | select { 110 | case message, ok := <-c.send: 111 | c.conn.SetWriteDeadline(time.Now().Add(writeWait)) 112 | if !ok { 113 | // The hub closed the channel. 114 | c.conn.WriteMessage(websocket.CloseMessage, []byte{}) 115 | return 116 | } 117 | 118 | w, err := c.conn.NextWriter(websocket.BinaryMessage) 119 | if err != nil { 120 | return 121 | } 122 | w.Write(message) 123 | 124 | // Add queued chat messages to the current websocket message. 125 | n := len(c.send) 126 | for i := 0; i < n; i++ { 127 | w.Write(newline) 128 | w.Write(<-c.send) 129 | } 130 | 131 | if err := w.Close(); err != nil { 132 | return 133 | } 134 | case <-ticker.C: 135 | c.conn.SetWriteDeadline(time.Now().Add(writeWait)) 136 | if err := c.conn.WriteMessage(websocket.PingMessage, nil); err != nil { 137 | return 138 | } 139 | } 140 | } 141 | } -------------------------------------------------------------------------------- /servers/src/socket/hub.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package socket 6 | 7 | import "log" 8 | 9 | type Broadcast struct { 10 | data []byte 11 | sender int 12 | } 13 | 14 | // Hub maintains the set of active clients and broadcasts messages to the 15 | // clients. 16 | type Hub struct { 17 | // Registered clients. 18 | clients map[*Client]bool 19 | 20 | // Inbound messages from the clients. 21 | broadcast chan *Broadcast 22 | 23 | // Register requests from the clients. 24 | register chan *Client 25 | 26 | // Unregister requests from clients. 27 | unregister chan *Client 28 | } 29 | 30 | func newHub() *Hub { 31 | return &Hub{ 32 | broadcast: make(chan *Broadcast), 33 | register: make(chan *Client), 34 | unregister: make(chan *Client), 35 | clients: make(map[*Client]bool), 36 | } 37 | } 38 | 39 | func (h *Hub) run() { 40 | for { 41 | select { 42 | case client := <-h.register: 43 | h.clients[client] = true 44 | if (client.sender != UID_UPLOADER) {//客户端连上了 45 | log.Printf("client connent %d", client.sender) 46 | for client := range h.clients { 47 | if client.sender == UID_UPLOADER { 48 | select { 49 | case client.send <- []byte(ACTION_OPEN_CAMERA): 50 | log.Printf("notify auto open ") 51 | default: 52 | } 53 | } 54 | } 55 | } 56 | case client := <-h.unregister: 57 | if _, ok := h.clients[client]; ok { 58 | delete(h.clients, client) 59 | close(client.send) 60 | } 61 | log.Printf("client disconnent %d size = %d", client.sender, len(h.clients)) 62 | if len(h.clients) == 1 {//只剩下uploader 63 | for client := range h.clients { 64 | if client.sender == UID_UPLOADER { 65 | select { 66 | case client.send <- []byte(ACTION_CLOSE_CAMERA): 67 | log.Printf("notify auto close ") 68 | default: 69 | } 70 | } 71 | } 72 | } 73 | case broadcast := <-h.broadcast: 74 | //uploader的视频 75 | for client := range h.clients { 76 | if broadcast.sender == UID_UPLOADER { 77 | if client.sender != UID_UPLOADER { 78 | select { 79 | case client.send <- broadcast.data: 80 | default: 81 | close(client.send) 82 | delete(h.clients, client) 83 | } 84 | } 85 | } else { 86 | if client.sender == UID_UPLOADER { 87 | select { 88 | case client.send <- broadcast.data: 89 | default: 90 | close(client.send) 91 | delete(h.clients, client) 92 | } 93 | } 94 | } 95 | } 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /servers/src/socket/uploader.go: -------------------------------------------------------------------------------- 1 | package socket 2 | 3 | import ( 4 | "bytes" 5 | "github.com/gorilla/websocket" 6 | "log" 7 | "time" 8 | ) 9 | 10 | const ( 11 | PART_BOUNDARY = "123456789000000000000987654321" 12 | STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" + PART_BOUNDARY 13 | STREAM_BOUNDARY = "\r\n--" + PART_BOUNDARY + "\r\n" 14 | STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %d\r\n\r\n" 15 | ) 16 | 17 | func (up *Client) readUploaderPump() { 18 | defer func() { 19 | up.hub.unregister <- up 20 | up.conn.Close() 21 | }() 22 | up.conn.SetReadLimit(maxMessageSize) 23 | up.conn.SetReadDeadline(time.Now().Add(pongWait)) 24 | up.conn.SetPongHandler(func(string) error { up.conn.SetReadDeadline(time.Now().Add(pongWait)); return nil }) 25 | for { 26 | msgType, message, err := up.conn.ReadMessage() 27 | if err != nil { 28 | if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) { 29 | log.Printf("error: %v", err) 30 | } 31 | break 32 | } 33 | switch msgType { 34 | case websocket.TextMessage: 35 | message = bytes.TrimSpace(bytes.Replace(message, newline, space, -1)) 36 | var text = string(message) 37 | up.hub.broadcast <- &Broadcast{data: message, sender: up.sender} 38 | log.Print("rev text " + text) 39 | if text == "open" { 40 | log.Print("open") 41 | log.Print("startPushStream") 42 | } else if text == "close" { 43 | log.Print("close") 44 | log.Print("stopPushStream") 45 | } else if text == "turnTo0" { 46 | log.Print("turnTo0") 47 | } else if text == "turnTo90" { 48 | log.Print("turnTo90") 49 | } else if text == "turnTo180" { 50 | log.Print("turnTo180") 51 | } 52 | break 53 | case websocket.BinaryMessage: 54 | up.hub.broadcast <- &Broadcast{data: message, sender: up.sender} 55 | break 56 | case websocket.CloseMessage: 57 | log.Print("rev closes") 58 | break 59 | } 60 | } 61 | } 62 | 63 | func (c *Client) writeUploaderPump() { 64 | ticker := time.NewTicker(pingPeriod) 65 | defer func() { 66 | ticker.Stop() 67 | c.conn.Close() 68 | }() 69 | for { 70 | select { 71 | case message, ok := <-c.send: 72 | c.conn.SetWriteDeadline(time.Now().Add(writeWait)) 73 | if !ok { 74 | // The hub closed the channel. 75 | c.conn.WriteMessage(websocket.CloseMessage, []byte{}) 76 | return 77 | } 78 | 79 | w, err := c.conn.NextWriter(websocket.TextMessage) 80 | if err != nil { 81 | return 82 | } 83 | w.Write(message) 84 | 85 | // Add queued chat messages to the current websocket message. 86 | n := len(c.send) 87 | for i := 0; i < n; i++ { 88 | w.Write(newline) 89 | w.Write(<-c.send) 90 | } 91 | 92 | if err := w.Close(); err != nil { 93 | return 94 | } 95 | case <-ticker.C: 96 | c.conn.SetWriteDeadline(time.Now().Add(writeWait)) 97 | if err := c.conn.WriteMessage(websocket.PingMessage, nil); err != nil { 98 | return 99 | } 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /servers/src/socket/wscore.go: -------------------------------------------------------------------------------- 1 | package socket 2 | 3 | import ( 4 | "github.com/gorilla/websocket" 5 | "html/template" 6 | "log" 7 | "net/http" 8 | ) 9 | 10 | const ( 11 | UID_UPLOADER = 1 12 | ) 13 | var UID_CLIENT = UID_UPLOADER 14 | 15 | func uploaderHandler(w http.ResponseWriter, r *http.Request, hub *Hub) { 16 | tmpl := template.Must(template.ParseFiles("./html/uploader.html")) 17 | var data = map[string]interface{}{} 18 | tmpl.Execute(w, data) 19 | } 20 | 21 | func uploaderWs(w http.ResponseWriter, r *http.Request, hub *Hub) { 22 | conn, err := bwUpgrader.Upgrade(w, r, nil) 23 | if err != nil { 24 | log.Println(err) 25 | return 26 | } 27 | uploader := &Client{hub: hub, conn: conn, send: make(chan []byte, 256), sender: UID_UPLOADER} 28 | uploader.hub.register <- uploader 29 | go uploader.writeUploaderPump() 30 | go uploader.readUploaderPump() 31 | } 32 | 33 | func clientHandler(w http.ResponseWriter, r *http.Request) { 34 | tmpl := template.Must(template.ParseFiles("./html/client.html")) 35 | var data = map[string]interface{}{} 36 | tmpl.Execute(w, data) 37 | } 38 | 39 | func clientWs(w http.ResponseWriter, r *http.Request, hub *Hub,) { 40 | conn, err := bwUpgrader.Upgrade(w, r, nil) 41 | if err != nil { 42 | log.Println(err) 43 | return 44 | } 45 | client := &Client{hub: hub, conn: conn, send: make(chan []byte, 256), sender: GetClientUid()} 46 | client.hub.register <- client 47 | go client.writePump() 48 | go client.readPump() 49 | } 50 | 51 | var bwUpgrader = websocket.Upgrader{ 52 | ReadBufferSize: 1024, 53 | WriteBufferSize: 1024, 54 | 55 | CheckOrigin: func(r *http.Request) bool { 56 | return true 57 | }, 58 | } 59 | 60 | func SetupHub() *Hub { 61 | hub := newHub() 62 | go hub.run() 63 | return hub 64 | } 65 | 66 | func SetupClient(serverMux *http.ServeMux, hub *Hub) { 67 | serverMux.HandleFunc("/camera/client", clientHandler) 68 | serverMux.HandleFunc("/camera/client/ws", func(writer http.ResponseWriter, request *http.Request) { 69 | clientWs(writer, request, hub) 70 | }) 71 | } 72 | 73 | func SetupUploader(serverMux *http.ServeMux, hub *Hub) { 74 | serverMux.HandleFunc("/camera/uploader", func(writer http.ResponseWriter, request *http.Request) { 75 | uploaderHandler(writer, request, hub); 76 | }) 77 | serverMux.HandleFunc("/camera/uploader/ws", func(writer http.ResponseWriter, request *http.Request) { 78 | uploaderWs(writer, request, hub); 79 | }) 80 | } 81 | 82 | func GetClientUid() int { 83 | UID_CLIENT = UID_CLIENT + 1 84 | return UID_CLIENT 85 | } 86 | -------------------------------------------------------------------------------- /servers/start.sh: -------------------------------------------------------------------------------- 1 | go build -o ./build/camera src/main.go 2 | nohup ./build/camera > camera.log & -------------------------------------------------------------------------------- /servers/stop.sh: -------------------------------------------------------------------------------- 1 | kill -9 `lsof -t -i tcp:8080` --------------------------------------------------------------------------------