├── doc ├── case.jpg └── notification.jpg ├── zip.py ├── Case.scad ├── camera_pins.h ├── README.md ├── auto_exposure.py ├── CameraWebServer.ino ├── app_httpd.cpp └── camera_index.h /doc/case.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grapeot/alexa-esp32-cam/HEAD/doc/case.jpg -------------------------------------------------------------------------------- /doc/notification.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grapeot/alexa-esp32-cam/HEAD/doc/notification.jpg -------------------------------------------------------------------------------- /zip.py: -------------------------------------------------------------------------------- 1 | """ 2 | This script helps to generate the gzipped index.html in camera_index.h 3 | """ 4 | 5 | content = open('./index.html.gz', 'rb').read() 6 | codes = [hex(n) for n in content] 7 | with open('output.txt', 'w') as fp: 8 | fp.write('#define index_ov2640_html_gz_len {}\n'.format(len(codes))) 9 | fp.write('const uint8_t index_ov2640_html_gz[] = {') 10 | count = 0 11 | for c in codes: 12 | if count % 16 == 0: 13 | fp.write('\n ') 14 | count = 0 15 | count += 1 16 | fp.write(c) 17 | fp.write(', ') 18 | fp.write('\n};') 19 | -------------------------------------------------------------------------------- /Case.scad: -------------------------------------------------------------------------------- 1 | total_size = [ 50, 30, 25 ]; 2 | wall_depth = [ 2, 2, 2 ]; 3 | screen_hole_size = [24, 36, 10]; 4 | slider_gap_depth = 1; 5 | epsilon = 0.01; 6 | margin = 0.8; 7 | 8 | module case(with_antenna_hole=false) { 9 | $fn=100; 10 | 11 | // cube body 12 | translate([0, 0, (total_size[2] + wall_depth[2]) / 2]) 13 | rotate([180, 0, 0]) 14 | difference() { 15 | cube(total_size + wall_depth * 2, center=true); 16 | // center hole 17 | cube(total_size, center=true); 18 | // slider gap 19 | translate([ wall_depth[0] / 2 + epsilon / 2, 0, -total_size[2] / 2 + wall_depth[2] / 2 + epsilon / 2 ]) 20 | cube([ total_size[0] + wall_depth[0] + epsilon, total_size[1] + 2 * slider_gap_depth + epsilon, slider_gap_depth ], center=true); 21 | // remove the bottom 22 | translate([ 0, 0, -total_size[2] / 2 - wall_depth[2] / 2 - epsilon ]) 23 | cube([ total_size[0], total_size[1], wall_depth[2] + 3 * epsilon], center=true); 24 | // remove the edge which might cause the bridging issue 25 | translate([ total_size[0] / 2 + wall_depth[0] / 2 + epsilon / 2, 0, -total_size[2] / 2 - wall_depth[2] / 2 - epsilon ]) 26 | cube([ wall_depth[0] + 2 * epsilon, total_size[1] + epsilon, wall_depth[2] * 2 + 3 * epsilon], center=true); 27 | // remove the hole for the micro USB 28 | // translate([-total_size[0] / 2, 0, -5]) 29 | // cube([10, 13, 7], center=true); 30 | // remove the hole for the camera 31 | translate([10, 0, (total_size[2] + wall_depth[2]) / 2]) 32 | // cylinder(r=8/2, h=10, center=true); 33 | cube([8.5, 8.5, 10], center=true); 34 | 35 | if (with_antenna_hole) { 36 | translate([total_size[0]/2, total_size[1]/2-5, 0]) 37 | rotate([0, 90, 0]) 38 | cylinder(r=6.5/2, h=10, center=true); 39 | } 40 | } 41 | } 42 | 43 | module slider() { 44 | // slider 45 | translate([ -40, 50, 0 ]) 46 | cube([ total_size[0] + wall_depth[0] - margin - 10, total_size[1] + 2 * slider_gap_depth - margin, slider_gap_depth - 0.2 ]); 47 | } 48 | 49 | case(true); 50 | slider(); -------------------------------------------------------------------------------- /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_WIDE) 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_AI_THINKER) 79 | #define PWDN_GPIO_NUM 32 80 | #define RESET_GPIO_NUM -1 81 | #define XCLK_GPIO_NUM 0 82 | #define SIOD_GPIO_NUM 26 83 | #define SIOC_GPIO_NUM 27 84 | 85 | #define Y9_GPIO_NUM 35 86 | #define Y8_GPIO_NUM 34 87 | #define Y7_GPIO_NUM 39 88 | #define Y6_GPIO_NUM 36 89 | #define Y5_GPIO_NUM 21 90 | #define Y4_GPIO_NUM 19 91 | #define Y3_GPIO_NUM 18 92 | #define Y2_GPIO_NUM 5 93 | #define VSYNC_GPIO_NUM 25 94 | #define HREF_GPIO_NUM 23 95 | #define PCLK_GPIO_NUM 22 96 | 97 | #else 98 | #error "Camera model not selected" 99 | #endif 100 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ESP32-Cam Surveillance Camera with Alexa Support 2 | 3 | The ESP32-Cam already has a feature-rich demo named [CameraWebServer](https://github.com/espressif/arduino-esp32/blob/master/libraries/ESP32/examples/Camera/CameraWebServer/CameraWebServer.ino). 4 | This repo further adds several useful features to it. 5 | The core is the support of Alexa voice commands. 6 | We used a [modified version](https://github.com/grapeot/esp32-alexa-wemo-emulator) of [this repo](https://github.com/igorantolic/esp32-alexa-wemo-emulator) to emulate a Wemo plug. 7 | Eventually one can say "Alexa turn on camera one" and then receive a notice from IFTTT on the phone. 8 | The rich notice contains a thumbnail to the captured photo, and tapping it leads to the ESP32-Cam server. 9 | 10 | ![Notification screenshot](doc/notification.jpg) 11 | 12 | ## How to Use 13 | 14 | This repo is for information only as is. 15 | Due to the limit of time, the author provides minimal support. 16 | Please raise all questions in the issues, and I will try to answer that if time permits. 17 | 18 | 1. Clone the repo. Open the `CameraWebServer.ino`. 19 | 2. Download the code from [this repo](https://github.com/grapeot/esp32-alexa-wemo-emulator) as a zip file. And add this zip file to the library using Sketch -> Include Library -> Add .zip library in Arduino IDE. 20 | 3. Change related configs, especially the ssid, password, etc. You may need to read the code to understand what the config means. 21 | 4. In Alexa app, discover new devices (choose Wemo Plug). It should discover a new device with the name as set in `alexa_name`. 22 | 5. In IFTTT, set up an applet that if receive a WebHook as in the variable `ifttt_event` (e.g. `richnotice`), then send a rich notice to the phone. Put `value1` in the title, `value2` in the image, and `value3` in the link. You also need to get the WebHook key and fill it in `ifttt_key` in the code. 23 | 6. Compile and upload. 24 | 25 | ## Implementation Details 26 | 27 | In order to achieve this, we made the following changes: 28 | 29 | 1. Integrate with the mDNS libaray to get rid of the hard coded IP. 30 | 2. Integrate with the [esp32-alexa-wemo-emulator](https://github.com/grapeot/esp32-alexa-wemo-emulator) libaray. Since Wemo PnP needs port 80, we have to move the camera server to 8080 and 8081. In addition to change the C code, this also involves changing the index.html, gzipping it, and putting it in `camera_index.h`. 31 | 3. Running Wemo daemon and AsyncWebServer didn't work out of the box, considering they both have separate message queues. Fortunately ESP32 has two cores, so we have to pin each task to a core, and let them run in parallel. This works, but the system gets more sensitive on the power supply. It seems to draw more current and heats more when both cores are used. 32 | 4. "Alexa turn on the camera" won't do anything if the device is already on. And memorizing the device's state is quite unpractical. So we added code to manually turn off the device immediately after it executes the turning on callback. This makes "alexa turn on the camera" always work. That's why we need a modified version of esp32-alexa-wemo-emulator. 33 | 5. In order to get good streaming speed, it's highly suggested to get an external antenna. 34 | 35 | ## Utilities 36 | 37 | This repo also provides some useful utilities: 38 | 39 | 1. `case.scad` provides a 3D print design file for a small case with an optional external interface. 40 | ![3D printed case](doc/case.jpg) 41 | 2. `auto_exposure.py` provides more extended auto exposure and time lapse support through python. 42 | 3. `zip.py` generates the index code in the `camera_index.h` from a gzipped html. -------------------------------------------------------------------------------- /auto_exposure.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import logging 3 | import cv2 4 | import numpy as np 5 | from time import sleep, time 6 | from datetime import datetime 7 | from os.path import join 8 | from threading import Thread 9 | 10 | logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', 11 | level=logging.INFO) 12 | 13 | 14 | class ESP32Camera: 15 | # completely control by camera, darkest 16 | EXPOSURE_TIER_0_AEC = 0 17 | # longest exposure. gain controlled by camera. 18 | EXPOSURE_TIER_1_AGC = 1 19 | # gain controlled by us 20 | EXPOSURE_TIER_2_MANUAL = 2 21 | EXPOSURE_TIER_MIN = EXPOSURE_TIER_0_AEC 22 | EXPOSURE_TIER_MAX = EXPOSURE_TIER_2_MANUAL 23 | 24 | # controls how to switch exposure tier 25 | EXPOSURE_TIER_URL_MAP = { 26 | EXPOSURE_TIER_0_AEC: [ 27 | '{url}/control?var=aec&val=1' 28 | ], 29 | EXPOSURE_TIER_1_AGC: [ 30 | '{url}/control?var=aec&val=0', 31 | '{url}/control?var=aec_value&val=1200', 32 | '{url}/control?var=agc&val=1', 33 | ], 34 | EXPOSURE_TIER_2_MANUAL: [ 35 | '{url}/control?var=aec&val=0', 36 | '{url}/control?var=agc&val=0', 37 | '{url}/control?var=agc_gain&val={gain}', 38 | ], 39 | } 40 | 41 | # Controls when to switch to a higher or lower exposure tier 42 | EXPOSURE_DARK_MEDIAN = 50 43 | EXPOSURE_BRIGHT_MEDIAN = 200 44 | 45 | EXPOSURE_MAX_GAIN = 31 46 | 47 | def __init__(self, url): 48 | # Remove the trailing '/' 49 | self.url = url.rstrip('/') 50 | # Only used in EXPOSURE_TIER_2_MANUAL 51 | self.gain = 1 52 | # Default in ESP32-cam code 53 | self.exposure_tier = ESP32Camera.EXPOSURE_TIER_1_AGC 54 | 55 | # photo_content is encoded jpg stream 56 | # returns tier, gain 57 | def calculate_exposure_tier(self, photo_content): 58 | np_arr = np.frombuffer(photo_content, np.uint8) 59 | img = cv2.imdecode(np_arr, cv2.IMREAD_COLOR) 60 | if img is None: 61 | logging.error('Cannot parse image from {}.'.format(self.url)) 62 | return self.exposure_tier, self.gain 63 | median = np.median(img) 64 | if median >= ESP32Camera.EXPOSURE_BRIGHT_MEDIAN: 65 | if self.exposure_tier == ESP32Camera.EXPOSURE_TIER_MIN: 66 | # Scene too bright. We can do nothing here. 67 | return self.exposure_tier, self.gain 68 | if self.exposure_tier == ESP32Camera.EXPOSURE_TIER_2_MANUAL: 69 | # We should try to reduce gain first 70 | if self.gain > 0: 71 | return self.exposure_tier, self.gain - 1 72 | # Downgrade one tier. We set gain to be 1 here. 73 | return self.exposure_tier - 1, 1 74 | elif median <= ESP32Camera.EXPOSURE_DARK_MEDIAN: 75 | if self.exposure_tier == ESP32Camera.EXPOSURE_TIER_MAX \ 76 | and self.gain == ESP32Camera.EXPOSURE_MAX_GAIN: 77 | # Scene too dark. We can do nothing here. 78 | return self.exposure_tier, self.gain 79 | if self.exposure_tier < ESP32Camera.EXPOSURE_TIER_MAX: 80 | # We can upgrade the tier 81 | return self.exposure_tier + 1, 1 82 | else: 83 | # In this case, we can only increase the gain 84 | return self.exposure_tier, self.gain + 1 85 | # Do nothing 86 | return self.exposure_tier, self.gain 87 | 88 | # Actually set the exposure tier on the camera 89 | def switch_exposure_tier(self, tier, gain): 90 | for url in ESP32Camera.EXPOSURE_TIER_URL_MAP[tier]: 91 | requests.get(url.format(url=self.url, gain=gain)) 92 | 93 | # Store the photo without decoding when outfn != None 94 | # Return raw bytes 95 | def take_photo(self, out_fn=None, adjust_exposure=False): 96 | try: 97 | req = requests.get(self.url + '/capture') 98 | except Exception as e: 99 | logging.error(e) 100 | return None 101 | if req.status_code != 200: 102 | logging.error('Cannot read from {}'.format(self.url)) 103 | return None 104 | content = req.content 105 | if out_fn is not None: 106 | open(out_fn, 'wb').write(content) 107 | logging.info('File written to {}.'.format(out_fn)) 108 | if adjust_exposure: 109 | tier, gain = self.calculate_exposure_tier(content) 110 | if tier != self.exposure_tier or gain != self.gain: 111 | self.switch_exposure_tier(tier, gain) 112 | self.exposure_tier = tier 113 | self.gain = gain 114 | return content 115 | 116 | 117 | class CameraThread(Thread): 118 | def __init__(self, url, outdir): 119 | Thread.__init__(self) 120 | self.cam = ESP32Camera(url) 121 | self.outdir = outdir 122 | 123 | def run(self): 124 | while True: 125 | oldtime = time() 126 | fn = join(self.outdir, '{}.jpg'.format(datetime.now().strftime( 127 | '%Y%m%d_%H%M%S'))) 128 | self.cam.take_photo(fn, True) 129 | while time() - oldtime < 10: 130 | sleep(1) 131 | 132 | 133 | if __name__ == '__main__': 134 | patio_thread = CameraThread('http://esppatio.local:8080', 'patio') 135 | patio_thread.start() -------------------------------------------------------------------------------- /CameraWebServer.ino: -------------------------------------------------------------------------------- 1 | #include "esp_camera.h" 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define LED_BUILTIN 33 11 | #define FLASH 4 12 | 13 | // 14 | // WARNING!!! Make sure that you have either selected ESP32 Wrover Module, 15 | // or another board which has PSRAM enabled 16 | // 17 | 18 | // Select camera model 19 | //#define CAMERA_MODEL_WROVER_KIT 20 | //#define CAMERA_MODEL_ESP_EYE 21 | //#define CAMERA_MODEL_M5STACK_PSRAM 22 | //#define CAMERA_MODEL_M5STACK_WIDE 23 | #define CAMERA_MODEL_AI_THINKER 24 | 25 | #include "camera_pins.h" 26 | 27 | const char *ssid = "YOUR_SSID"; 28 | const char *password = "YOUR_PASSWORD"; 29 | const char *ifttt_key = "YOUR_KEY"; 30 | const char *ifttt_event = "richnotice"; 31 | const char *mdns_name = "esppatio"; 32 | const char *alexa_name = "camera one"; 33 | const char *alexa_name_url = "Camera+One"; 34 | 35 | // Camera wemo related declarations 36 | WemoSwitch *cameraDevice = NULL; 37 | WemoSwitch *ledDevice = NULL; 38 | WemoManager wemoManager; 39 | TaskHandle_t wemoTask; 40 | void wemo_loop(void * pvParameters); 41 | void camera_loop(void * pvParameters); 42 | void cameraOn(); 43 | void cameraOff(); 44 | void LEDOn(); 45 | void LEDOff(); 46 | String httpGETRequest(const char* serverName); 47 | 48 | TaskHandle_t cameraTask; 49 | void cameraLoop(void * pvParameters); 50 | void startCameraServer(int port); 51 | 52 | void setup() { 53 | Serial.begin(115200); 54 | Serial.setDebugOutput(true); 55 | Serial.println(); 56 | 57 | pinMode(LED_BUILTIN, OUTPUT); 58 | pinMode(FLASH, OUTPUT); 59 | 60 | camera_config_t config; 61 | config.ledc_channel = LEDC_CHANNEL_0; 62 | config.ledc_timer = LEDC_TIMER_0; 63 | config.pin_d0 = Y2_GPIO_NUM; 64 | config.pin_d1 = Y3_GPIO_NUM; 65 | config.pin_d2 = Y4_GPIO_NUM; 66 | config.pin_d3 = Y5_GPIO_NUM; 67 | config.pin_d4 = Y6_GPIO_NUM; 68 | config.pin_d5 = Y7_GPIO_NUM; 69 | config.pin_d6 = Y8_GPIO_NUM; 70 | config.pin_d7 = Y9_GPIO_NUM; 71 | config.pin_xclk = XCLK_GPIO_NUM; 72 | config.pin_pclk = PCLK_GPIO_NUM; 73 | config.pin_vsync = VSYNC_GPIO_NUM; 74 | config.pin_href = HREF_GPIO_NUM; 75 | config.pin_sscb_sda = SIOD_GPIO_NUM; 76 | config.pin_sscb_scl = SIOC_GPIO_NUM; 77 | config.pin_pwdn = PWDN_GPIO_NUM; 78 | config.pin_reset = RESET_GPIO_NUM; 79 | config.xclk_freq_hz = 20000000; 80 | config.pixel_format = PIXFORMAT_JPEG; 81 | //init with high specs to pre-allocate larger buffers 82 | if(psramFound()){ 83 | config.frame_size = FRAMESIZE_UXGA; 84 | config.jpeg_quality = 10; 85 | config.fb_count = 2; 86 | } else { 87 | config.frame_size = FRAMESIZE_SVGA; 88 | config.jpeg_quality = 12; 89 | config.fb_count = 1; 90 | } 91 | 92 | #if defined(CAMERA_MODEL_ESP_EYE) 93 | pinMode(13, INPUT_PULLUP); 94 | pinMode(14, INPUT_PULLUP); 95 | #endif 96 | 97 | // camera init 98 | esp_err_t err = esp_camera_init(&config); 99 | if (err != ESP_OK) { 100 | Serial.printf("Camera init failed with error 0x%x", err); 101 | return; 102 | } 103 | 104 | sensor_t * s = esp_camera_sensor_get(); 105 | //initial sensors are flipped vertically and colors are a bit saturated 106 | if (s->id.PID == OV3660_PID) { 107 | s->set_vflip(s, 1);//flip it back 108 | s->set_brightness(s, 1);//up the blightness just a bit 109 | s->set_saturation(s, -2);//lower the saturation 110 | } 111 | //drop down frame size for higher initial frame rate 112 | 113 | // overwrite default settings 114 | s->set_framesize(s, FRAMESIZE_UXGA); 115 | s->set_exposure_ctrl(s, 0); 116 | s->set_aec_value(s, 1200); 117 | 118 | #if defined(CAMERA_MODEL_M5STACK_WIDE) 119 | s->set_vflip(s, 1); 120 | s->set_hmirror(s, 1); 121 | #endif 122 | 123 | // Set WiFi to station mode and disconnect from an AP if it was Previously 124 | // connected 125 | WiFi.mode(WIFI_STA); 126 | WiFi.disconnect(); 127 | delay(100); 128 | 129 | WiFi.begin(ssid, password); 130 | 131 | bool isHigh = true; 132 | while (WiFi.status() != WL_CONNECTED) { 133 | delay(500); 134 | Serial.print("."); 135 | 136 | digitalWrite(LED_BUILTIN, isHigh ? HIGH: LOW); 137 | isHigh = !isHigh; 138 | } 139 | Serial.println(""); 140 | Serial.println("WiFi connected"); 141 | 142 | if(!MDNS.begin(mdns_name)) { 143 | Serial.println("Error starting mDNS"); 144 | return; 145 | } 146 | 147 | // emulate a wemo device 148 | wemoManager.begin(); 149 | cameraDevice = new WemoSwitch(alexa_name, 80, cameraOn, cameraOff); 150 | wemoManager.addDevice(*cameraDevice); 151 | // ledDevice = new WemoSwitch("camera one flash", 81, LEDOn, LEDOff); 152 | // wemoManager.addDevice(*ledDevice); 153 | 154 | // Set up task to run the wemo server loop at core 0 155 | xTaskCreatePinnedToCore( 156 | wemo_loop, /* Task function. */ 157 | "Wemo", /* name of task. */ 158 | 10000, /* Stack size of task */ 159 | NULL, /* parameter of the task */ 160 | 1, /* priority of the task */ 161 | &wemoTask, /* Task handle to keep track of created task */ 162 | 0); /* pin task to core 0 */ 163 | delay(500); 164 | 165 | xTaskCreatePinnedToCore( 166 | camera_loop, /* Task function. */ 167 | "Camera", /* name of task. */ 168 | 10000, /* Stack size of task */ 169 | NULL, /* parameter of the task */ 170 | 1, /* priority of the task */ 171 | &cameraTask, /* Task handle to keep track of created task */ 172 | 1); /* pin task to core 0 */ 173 | delay(500); 174 | } 175 | 176 | void loop() { 177 | // put your main code here, to run repeatedly: 178 | delay(10000); 179 | } 180 | 181 | void camera_loop(void * pvParameters) { 182 | Serial.print("Camera running on core "); 183 | Serial.println(xPortGetCoreID()); 184 | 185 | startCameraServer(8080); 186 | 187 | Serial.print("Camera Ready! Use 'http://"); 188 | Serial.print(WiFi.localIP()); 189 | Serial.println("' to connect"); 190 | 191 | while(true) { 192 | delay(10000); 193 | } 194 | } 195 | 196 | void wemo_loop(void * pvParameters) { 197 | Serial.print("Wemo running on core "); 198 | Serial.println(xPortGetCoreID()); 199 | while(true) { 200 | wemoManager.serverLoop(); 201 | } 202 | } 203 | 204 | void cameraOn() { 205 | char url_template[] = "https://maker.ifttt.com/trigger/%s/with/key/%s/?value1=%s+On&value2=http%%3A%%2F%%2F%s.local%%3A8080%%2F&value3=http%%3A%%2F%%2F%s.local%%3A8080%%2Fcapture"; 206 | const size_t buff_len = sizeof(url_template) + strlen(ifttt_event) + strlen(mdns_name) + strlen(mdns_name) + strlen(ifttt_key) + strlen(alexa_name_url) + 1; 207 | char *buff = (char *)malloc(buff_len); 208 | if (!buff) { 209 | Serial.println("Error: cannot allocate memory for the URL."); 210 | return; 211 | } 212 | size_t n = sprintf(buff, url_template, ifttt_event, ifttt_key, alexa_name_url, mdns_name, mdns_name); 213 | Serial.println(httpGETRequest(buff)); 214 | free(buff); 215 | buff = NULL; 216 | 217 | // manually turn off the camera so it could be turn on again 218 | cameraDevice->turnOff(); 219 | } 220 | 221 | void cameraOff(){ 222 | // Do nothing 223 | } 224 | 225 | void LEDOn() { 226 | digitalWrite(FLASH, HIGH); 227 | } 228 | 229 | void LEDOff() { 230 | digitalWrite(FLASH, LOW); 231 | } 232 | 233 | String httpGETRequest(const char* serverName) { 234 | Serial.print("Sending request to "); 235 | Serial.println(serverName); 236 | 237 | HTTPClient http; 238 | 239 | // Your IP address with path or Domain name with URL path 240 | http.begin(serverName); 241 | 242 | // Send HTTP GET request 243 | int httpResponseCode = http.GET(); 244 | 245 | String payload = "--"; 246 | 247 | if (httpResponseCode>0) { 248 | Serial.print("HTTP Response code: "); 249 | Serial.println(httpResponseCode); 250 | payload = http.getString(); 251 | } 252 | else { 253 | Serial.print("Error code: "); 254 | Serial.println(httpResponseCode); 255 | } 256 | // Free resources 257 | http.end(); 258 | 259 | return payload; 260 | } 261 | -------------------------------------------------------------------------------- /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 | typedef struct { 26 | httpd_req_t *req; 27 | size_t len; 28 | } jpg_chunking_t; 29 | 30 | #define PART_BOUNDARY "123456789000000000000987654321" 31 | static const char* _STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY; 32 | static const char* _STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n"; 33 | static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n"; 34 | 35 | httpd_handle_t stream_httpd = NULL; 36 | httpd_handle_t camera_httpd = NULL; 37 | 38 | static size_t jpg_encode_stream(void * arg, size_t index, const void* data, size_t len){ 39 | jpg_chunking_t *j = (jpg_chunking_t *)arg; 40 | if(!index){ 41 | j->len = 0; 42 | } 43 | if(httpd_resp_send_chunk(j->req, (const char *)data, len) != ESP_OK){ 44 | return 0; 45 | } 46 | j->len += len; 47 | return len; 48 | } 49 | 50 | static esp_err_t capture_handler(httpd_req_t *req){ 51 | camera_fb_t * fb = NULL; 52 | esp_err_t res = ESP_OK; 53 | int64_t fr_start = esp_timer_get_time(); 54 | 55 | fb = esp_camera_fb_get(); 56 | if (!fb) { 57 | Serial.println("Camera capture failed"); 58 | httpd_resp_send_500(req); 59 | return ESP_FAIL; 60 | } 61 | 62 | httpd_resp_set_type(req, "image/jpeg"); 63 | httpd_resp_set_hdr(req, "Content-Disposition", "inline; filename=capture.jpg"); 64 | httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); 65 | 66 | size_t out_len, out_width, out_height; 67 | uint8_t * out_buf; 68 | bool s; 69 | if(fb->width > 400){ 70 | size_t fb_len = 0; 71 | if(fb->format == PIXFORMAT_JPEG){ 72 | fb_len = fb->len; 73 | res = httpd_resp_send(req, (const char *)fb->buf, fb->len); 74 | } else { 75 | jpg_chunking_t jchunk = {req, 0}; 76 | res = frame2jpg_cb(fb, 80, jpg_encode_stream, &jchunk)?ESP_OK:ESP_FAIL; 77 | httpd_resp_send_chunk(req, NULL, 0); 78 | fb_len = jchunk.len; 79 | } 80 | esp_camera_fb_return(fb); 81 | int64_t fr_end = esp_timer_get_time(); 82 | Serial.printf("JPG: %uB %ums\n", (uint32_t)(fb_len), (uint32_t)((fr_end - fr_start)/1000)); 83 | return res; 84 | } 85 | 86 | dl_matrix3du_t *image_matrix = dl_matrix3du_alloc(1, fb->width, fb->height, 3); 87 | if (!image_matrix) { 88 | esp_camera_fb_return(fb); 89 | Serial.println("dl_matrix3du_alloc failed"); 90 | httpd_resp_send_500(req); 91 | return ESP_FAIL; 92 | } 93 | 94 | out_buf = image_matrix->item; 95 | out_len = fb->width * fb->height * 3; 96 | out_width = fb->width; 97 | out_height = fb->height; 98 | 99 | s = fmt2rgb888(fb->buf, fb->len, fb->format, out_buf); 100 | esp_camera_fb_return(fb); 101 | if(!s){ 102 | dl_matrix3du_free(image_matrix); 103 | Serial.println("to rgb888 failed"); 104 | httpd_resp_send_500(req); 105 | return ESP_FAIL; 106 | } 107 | 108 | jpg_chunking_t jchunk = {req, 0}; 109 | s = fmt2jpg_cb(out_buf, out_len, out_width, out_height, PIXFORMAT_RGB888, 90, jpg_encode_stream, &jchunk); 110 | dl_matrix3du_free(image_matrix); 111 | if(!s){ 112 | Serial.println("JPEG compression failed"); 113 | return ESP_FAIL; 114 | } 115 | 116 | int64_t fr_end = esp_timer_get_time(); 117 | return res; 118 | } 119 | 120 | static esp_err_t stream_handler(httpd_req_t *req){ 121 | camera_fb_t * fb = NULL; 122 | esp_err_t res = ESP_OK; 123 | size_t _jpg_buf_len = 0; 124 | uint8_t * _jpg_buf = NULL; 125 | char * part_buf[64]; 126 | dl_matrix3du_t *image_matrix = NULL; 127 | int64_t fr_start = 0; 128 | int64_t fr_ready = 0; 129 | int64_t fr_encode = 0; 130 | 131 | static int64_t last_frame = 0; 132 | if(!last_frame) { 133 | last_frame = esp_timer_get_time(); 134 | } 135 | 136 | res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE); 137 | if(res != ESP_OK){ 138 | return res; 139 | } 140 | 141 | httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); 142 | 143 | while(true){ 144 | fb = esp_camera_fb_get(); 145 | if (!fb) { 146 | Serial.println("Camera capture failed"); 147 | res = ESP_FAIL; 148 | } else { 149 | fr_start = esp_timer_get_time(); 150 | fr_ready = fr_start; 151 | fr_encode = fr_start; 152 | if(fb->width > 400){ 153 | if(fb->format != PIXFORMAT_JPEG){ 154 | bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len); 155 | esp_camera_fb_return(fb); 156 | fb = NULL; 157 | if(!jpeg_converted){ 158 | Serial.println("JPEG compression failed"); 159 | res = ESP_FAIL; 160 | } 161 | } else { 162 | _jpg_buf_len = fb->len; 163 | _jpg_buf = fb->buf; 164 | } 165 | } else { 166 | 167 | image_matrix = dl_matrix3du_alloc(1, fb->width, fb->height, 3); 168 | 169 | if (!image_matrix) { 170 | Serial.println("dl_matrix3du_alloc failed"); 171 | res = ESP_FAIL; 172 | } else { 173 | if(!fmt2rgb888(fb->buf, fb->len, fb->format, image_matrix->item)){ 174 | Serial.println("fmt2rgb888 failed"); 175 | res = ESP_FAIL; 176 | } else { 177 | fr_ready = esp_timer_get_time(); 178 | box_array_t *net_boxes = NULL; 179 | _jpg_buf = fb->buf; 180 | _jpg_buf_len = fb->len; 181 | fr_encode = esp_timer_get_time(); 182 | } 183 | dl_matrix3du_free(image_matrix); 184 | } 185 | } 186 | } 187 | if(res == ESP_OK){ 188 | size_t hlen = snprintf((char *)part_buf, 64, _STREAM_PART, _jpg_buf_len); 189 | res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen); 190 | } 191 | if(res == ESP_OK){ 192 | res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len); 193 | } 194 | if(res == ESP_OK){ 195 | res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY)); 196 | } 197 | if(fb){ 198 | esp_camera_fb_return(fb); 199 | fb = NULL; 200 | _jpg_buf = NULL; 201 | } else if(_jpg_buf){ 202 | free(_jpg_buf); 203 | _jpg_buf = NULL; 204 | } 205 | if(res != ESP_OK){ 206 | break; 207 | } 208 | int64_t fr_end = esp_timer_get_time(); 209 | 210 | int64_t ready_time = (fr_ready - fr_start)/1000; 211 | int64_t encode_time = (fr_encode - fr_ready)/1000; 212 | int64_t process_time = (fr_encode - fr_start)/1000; 213 | 214 | int64_t frame_time = fr_end - last_frame; 215 | last_frame = fr_end; 216 | frame_time /= 1000; 217 | Serial.printf("MJPG: %uB %ums (%.1ffps), %u+%u+%u+%u=%u %s%d\n", 218 | (uint32_t)(_jpg_buf_len), 219 | (uint32_t)frame_time, 1000.0 / (uint32_t)frame_time, 220 | (uint32_t)ready_time, (uint32_t)0, (uint32_t)0, (uint32_t)encode_time, (uint32_t)process_time, 221 | "0" 222 | ); 223 | } 224 | 225 | last_frame = 0; 226 | return res; 227 | } 228 | 229 | static esp_err_t cmd_handler(httpd_req_t *req){ 230 | char* buf; 231 | size_t buf_len; 232 | char variable[32] = {0,}; 233 | char value[32] = {0,}; 234 | 235 | buf_len = httpd_req_get_url_query_len(req) + 1; 236 | if (buf_len > 1) { 237 | buf = (char*)malloc(buf_len); 238 | if(!buf){ 239 | httpd_resp_send_500(req); 240 | return ESP_FAIL; 241 | } 242 | if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) { 243 | if (httpd_query_key_value(buf, "var", variable, sizeof(variable)) == ESP_OK && 244 | httpd_query_key_value(buf, "val", value, sizeof(value)) == ESP_OK) { 245 | } else { 246 | free(buf); 247 | httpd_resp_send_404(req); 248 | return ESP_FAIL; 249 | } 250 | } else { 251 | free(buf); 252 | httpd_resp_send_404(req); 253 | return ESP_FAIL; 254 | } 255 | free(buf); 256 | } else { 257 | httpd_resp_send_404(req); 258 | return ESP_FAIL; 259 | } 260 | 261 | int val = atoi(value); 262 | sensor_t * s = esp_camera_sensor_get(); 263 | int res = 0; 264 | 265 | if(!strcmp(variable, "framesize")) { 266 | if(s->pixformat == PIXFORMAT_JPEG) res = s->set_framesize(s, (framesize_t)val); 267 | } 268 | else if(!strcmp(variable, "quality")) res = s->set_quality(s, val); 269 | else if(!strcmp(variable, "contrast")) res = s->set_contrast(s, val); 270 | else if(!strcmp(variable, "brightness")) res = s->set_brightness(s, val); 271 | else if(!strcmp(variable, "saturation")) res = s->set_saturation(s, val); 272 | else if(!strcmp(variable, "gainceiling")) res = s->set_gainceiling(s, (gainceiling_t)val); 273 | else if(!strcmp(variable, "colorbar")) res = s->set_colorbar(s, val); 274 | else if(!strcmp(variable, "awb")) res = s->set_whitebal(s, val); 275 | else if(!strcmp(variable, "agc")) res = s->set_gain_ctrl(s, val); 276 | else if(!strcmp(variable, "aec")) res = s->set_exposure_ctrl(s, val); 277 | else if(!strcmp(variable, "hmirror")) res = s->set_hmirror(s, val); 278 | else if(!strcmp(variable, "vflip")) res = s->set_vflip(s, val); 279 | else if(!strcmp(variable, "awb_gain")) res = s->set_awb_gain(s, val); 280 | else if(!strcmp(variable, "agc_gain")) res = s->set_agc_gain(s, val); 281 | else if(!strcmp(variable, "aec_value")) res = s->set_aec_value(s, val); 282 | else if(!strcmp(variable, "aec2")) res = s->set_aec2(s, val); 283 | else if(!strcmp(variable, "dcw")) res = s->set_dcw(s, val); 284 | else if(!strcmp(variable, "bpc")) res = s->set_bpc(s, val); 285 | else if(!strcmp(variable, "wpc")) res = s->set_wpc(s, val); 286 | else if(!strcmp(variable, "raw_gma")) res = s->set_raw_gma(s, val); 287 | else if(!strcmp(variable, "lenc")) res = s->set_lenc(s, val); 288 | else if(!strcmp(variable, "special_effect")) res = s->set_special_effect(s, val); 289 | else if(!strcmp(variable, "wb_mode")) res = s->set_wb_mode(s, val); 290 | else if(!strcmp(variable, "ae_level")) res = s->set_ae_level(s, val); 291 | else { 292 | res = -1; 293 | } 294 | 295 | if(res){ 296 | return httpd_resp_send_500(req); 297 | } 298 | 299 | httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); 300 | return httpd_resp_send(req, NULL, 0); 301 | } 302 | 303 | static esp_err_t status_handler(httpd_req_t *req){ 304 | static char json_response[1024]; 305 | 306 | sensor_t * s = esp_camera_sensor_get(); 307 | char * p = json_response; 308 | *p++ = '{'; 309 | 310 | p+=sprintf(p, "\"framesize\":%u,", s->status.framesize); 311 | p+=sprintf(p, "\"quality\":%u,", s->status.quality); 312 | p+=sprintf(p, "\"brightness\":%d,", s->status.brightness); 313 | p+=sprintf(p, "\"contrast\":%d,", s->status.contrast); 314 | p+=sprintf(p, "\"saturation\":%d,", s->status.saturation); 315 | p+=sprintf(p, "\"sharpness\":%d,", s->status.sharpness); 316 | p+=sprintf(p, "\"special_effect\":%u,", s->status.special_effect); 317 | p+=sprintf(p, "\"wb_mode\":%u,", s->status.wb_mode); 318 | p+=sprintf(p, "\"awb\":%u,", s->status.awb); 319 | p+=sprintf(p, "\"awb_gain\":%u,", s->status.awb_gain); 320 | p+=sprintf(p, "\"aec\":%u,", s->status.aec); 321 | p+=sprintf(p, "\"aec2\":%u,", s->status.aec2); 322 | p+=sprintf(p, "\"ae_level\":%d,", s->status.ae_level); 323 | p+=sprintf(p, "\"aec_value\":%u,", s->status.aec_value); 324 | p+=sprintf(p, "\"agc\":%u,", s->status.agc); 325 | p+=sprintf(p, "\"agc_gain\":%u,", s->status.agc_gain); 326 | p+=sprintf(p, "\"gainceiling\":%u,", s->status.gainceiling); 327 | p+=sprintf(p, "\"bpc\":%u,", s->status.bpc); 328 | p+=sprintf(p, "\"wpc\":%u,", s->status.wpc); 329 | p+=sprintf(p, "\"raw_gma\":%u,", s->status.raw_gma); 330 | p+=sprintf(p, "\"lenc\":%u,", s->status.lenc); 331 | p+=sprintf(p, "\"vflip\":%u,", s->status.vflip); 332 | p+=sprintf(p, "\"hmirror\":%u,", s->status.hmirror); 333 | p+=sprintf(p, "\"dcw\":%u,", s->status.dcw); 334 | p+=sprintf(p, "\"colorbar\":%u", s->status.colorbar); 335 | *p++ = '}'; 336 | *p++ = 0; 337 | httpd_resp_set_type(req, "application/json"); 338 | httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); 339 | return httpd_resp_send(req, json_response, strlen(json_response)); 340 | } 341 | 342 | static esp_err_t index_handler(httpd_req_t *req){ 343 | httpd_resp_set_type(req, "text/html"); 344 | httpd_resp_set_hdr(req, "Content-Encoding", "gzip"); 345 | sensor_t * s = esp_camera_sensor_get(); 346 | return httpd_resp_send(req, (const char *)index_ov2640_html_gz, index_ov2640_html_gz_len); 347 | } 348 | 349 | void startCameraServer(int port) { 350 | httpd_config_t config = HTTPD_DEFAULT_CONFIG(); 351 | config.server_port = port; 352 | config.ctrl_port = port; 353 | 354 | httpd_uri_t index_uri = { 355 | .uri = "/", 356 | .method = HTTP_GET, 357 | .handler = index_handler, 358 | .user_ctx = NULL 359 | }; 360 | 361 | httpd_uri_t status_uri = { 362 | .uri = "/status", 363 | .method = HTTP_GET, 364 | .handler = status_handler, 365 | .user_ctx = NULL 366 | }; 367 | 368 | httpd_uri_t cmd_uri = { 369 | .uri = "/control", 370 | .method = HTTP_GET, 371 | .handler = cmd_handler, 372 | .user_ctx = NULL 373 | }; 374 | 375 | httpd_uri_t capture_uri = { 376 | .uri = "/capture", 377 | .method = HTTP_GET, 378 | .handler = capture_handler, 379 | .user_ctx = NULL 380 | }; 381 | 382 | httpd_uri_t stream_uri = { 383 | .uri = "/stream", 384 | .method = HTTP_GET, 385 | .handler = stream_handler, 386 | .user_ctx = NULL 387 | }; 388 | 389 | Serial.printf("Starting web server on port: '%d'\n", config.server_port); 390 | if (httpd_start(&camera_httpd, &config) == ESP_OK) { 391 | httpd_register_uri_handler(camera_httpd, &index_uri); 392 | httpd_register_uri_handler(camera_httpd, &cmd_uri); 393 | httpd_register_uri_handler(camera_httpd, &status_uri); 394 | httpd_register_uri_handler(camera_httpd, &capture_uri); 395 | } 396 | 397 | config.server_port += 1; 398 | config.ctrl_port += 1; 399 | Serial.printf("Starting stream server on port: '%d'\n", config.server_port); 400 | if (httpd_start(&stream_httpd, &config) == ESP_OK) { 401 | httpd_register_uri_handler(stream_httpd, &stream_uri); 402 | } 403 | } 404 | -------------------------------------------------------------------------------- /camera_index.h: -------------------------------------------------------------------------------- 1 | #define index_ov2640_html_gz_len 4038 2 | const uint8_t index_ov2640_html_gz[] = { 3 | 0x1f, 0x8b, 0x8, 0x8, 0x74, 0xd6, 0xe7, 0x5f, 0x0, 0x3, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 4 | 0x68, 0x74, 0x6d, 0x6c, 0x0, 0xe5, 0x5d, 0xeb, 0x92, 0xd3, 0xc6, 0x12, 0xfe, 0xcf, 0x53, 0x8, 5 | 0x41, 0xb0, 0x5d, 0x59, 0x5f, 0xd7, 0x2c, 0x8b, 0x63, 0x9b, 0x3, 0xcb, 0x6, 0x52, 0xc5, 0x25, 6 | 0x61, 0x13, 0x48, 0x55, 0x2a, 0x5, 0x63, 0x69, 0x64, 0x2b, 0xc8, 0x92, 0x22, 0x8d, 0xec, 0xdd, 7 | 0x50, 0xfb, 0x1c, 0xe7, 0x81, 0xce, 0x8b, 0x9d, 0x9e, 0x8b, 0xa4, 0x91, 0x3c, 0xba, 0xd8, 0x86, 8 | 0x35, 0x87, 0xe3, 0xad, 0xa, 0xb2, 0x35, 0xdd, 0xd3, 0xdd, 0x5f, 0xdf, 0x66, 0x74, 0xc9, 0xf8, 9 | 0xb6, 0xe9, 0x19, 0xe4, 0xca, 0xc7, 0xda, 0x82, 0x2c, 0x9d, 0xe9, 0xad, 0x31, 0xff, 0x47, 0x83, 10 | 0xcf, 0x78, 0x81, 0x91, 0xc9, 0xf, 0xd9, 0xd7, 0x25, 0x26, 0x48, 0x33, 0x16, 0x28, 0x8, 0x31, 11 | 0x99, 0xe8, 0x11, 0xb1, 0xda, 0xa7, 0x7a, 0xfe, 0xb4, 0x8b, 0x96, 0x78, 0xa2, 0xaf, 0x6c, 0xbc, 12 | 0xf6, 0xbd, 0x80, 0xe8, 0x9a, 0xe1, 0xb9, 0x4, 0xbb, 0x30, 0x7c, 0x6d, 0x9b, 0x64, 0x31, 0x31, 13 | 0xf1, 0xca, 0x36, 0x70, 0x9b, 0x7d, 0x39, 0xb2, 0x5d, 0x9b, 0xd8, 0xc8, 0x69, 0x87, 0x6, 0x72, 14 | 0xf0, 0xa4, 0x2f, 0xf3, 0x22, 0x36, 0x71, 0xf0, 0xf4, 0xfc, 0xe2, 0xe7, 0xe3, 0x81, 0xf6, 0xfa, 15 | 0xed, 0x60, 0x78, 0xd2, 0x1b, 0x77, 0xf9, 0x6f, 0xe9, 0x98, 0x90, 0x5c, 0xc9, 0xdf, 0xe9, 0x67, 16 | 0xe6, 0x99, 0x57, 0xda, 0xa7, 0xcc, 0x4f, 0xf4, 0x63, 0x81, 0x10, 0x6d, 0xb, 0x2d, 0x6d, 0xe7, 17 | 0x6a, 0xa4, 0x3d, 0xe, 0x60, 0xce, 0xa3, 0xe7, 0xd8, 0x59, 0x61, 0x62, 0x1b, 0xe8, 0x28, 0x44, 18 | 0x6e, 0xd8, 0xe, 0x71, 0x60, 0x5b, 0x3f, 0x6c, 0x10, 0xce, 0x90, 0xf1, 0x71, 0x1e, 0x78, 0x91, 19 | 0x6b, 0x8e, 0xb4, 0x3b, 0xfd, 0x53, 0xfa, 0xb7, 0x39, 0xc8, 0xf0, 0x1c, 0x2f, 0x80, 0xf3, 0xe7, 20 | 0x3f, 0xd2, 0xbf, 0xcd, 0xf3, 0x6c, 0xf6, 0xd0, 0xfe, 0x7, 0x8f, 0xb4, 0xfe, 0x89, 0x7f, 0x99, 21 | 0x39, 0x7f, 0x7d, 0x2b, 0xf3, 0x75, 0x31, 0x28, 0x92, 0x5e, 0xd0, 0x9f, 0x96, 0xd3, 0x87, 0xd8, 22 | 0x20, 0xb6, 0xe7, 0x76, 0x96, 0xc8, 0x76, 0x15, 0x9c, 0x4c, 0x3b, 0xf4, 0x1d, 0x4, 0x36, 0xb0, 23 | 0x1c, 0x5c, 0xca, 0xe7, 0xce, 0x12, 0xbb, 0xd1, 0x51, 0x5, 0x37, 0xca, 0xa4, 0x6d, 0xda, 0x1, 24 | 0x1f, 0x35, 0xa2, 0x76, 0x88, 0x96, 0x6e, 0x25, 0xdb, 0x32, 0xb9, 0x5c, 0xcf, 0xc5, 0xa, 0x3, 25 | 0xd2, 0x89, 0xd6, 0x1, 0xf2, 0xe9, 0x0, 0xfa, 0xef, 0xe6, 0x90, 0xa5, 0xed, 0x72, 0xa7, 0x1a, 26 | 0x69, 0xc7, 0xc3, 0x9e, 0x7f, 0x59, 0x1, 0xe5, 0xf1, 0x9, 0xfd, 0xdb, 0x1c, 0xe4, 0x23, 0xd3, 27 | 0xb4, 0xdd, 0xf9, 0x48, 0x3b, 0x55, 0xb2, 0xf0, 0x2, 0x13, 0x7, 0xed, 0x0, 0x99, 0x76, 0x14, 28 | 0x8e, 0xb4, 0xa1, 0x6a, 0xcc, 0x12, 0x5, 0x73, 0x90, 0x85, 0x78, 0x20, 0x6c, 0xbb, 0xaf, 0x94, 29 | 0x44, 0xc, 0x9, 0xec, 0xf9, 0x82, 0x0, 0xa4, 0x1b, 0x63, 0xf2, 0x46, 0x13, 0x21, 0x54, 0x85, 30 | 0x67, 0xa9, 0xdd, 0xd4, 0x56, 0x43, 0x8e, 0x3d, 0x77, 0xdb, 0x36, 0xc1, 0x4b, 0x50, 0x27, 0x24, 31 | 0x1, 0x26, 0xc6, 0xa2, 0x4c, 0x14, 0xcb, 0x9e, 0x47, 0x1, 0x56, 0x8, 0x92, 0xd8, 0xad, 0x44, 32 | 0x61, 0x38, 0xb9, 0x79, 0xaa, 0xbd, 0xc6, 0xb3, 0x8f, 0x36, 0x69, 0xb, 0x9b, 0xcc, 0xb0, 0xe5, 33 | 0x5, 0x58, 0x39, 0x32, 0x1e, 0xe1, 0x78, 0xc6, 0xc7, 0x76, 0x48, 0x50, 0x40, 0xea, 0x30, 0x44, 34 | 0x16, 0xc1, 0x41, 0x35, 0x3f, 0x4c, 0xbd, 0xa2, 0x9a, 0x5b, 0xf1, 0xb4, 0x62, 0x80, 0xed, 0x3a, 35 | 0xb6, 0x8b, 0xeb, 0x8b, 0x57, 0x34, 0x6f, 0x96, 0x1d, 0x1f, 0x55, 0x3, 0x18, 0x7b, 0x39, 0x2f, 36 | 0xf3, 0x12, 0xa6, 0xeb, 0xe6, 0x64, 0x22, 0x6e, 0xfa, 0xbd, 0xde, 0x77, 0x9b, 0x27, 0x17, 0x98, 37 | 0xbb, 0x29, 0x8a, 0x88, 0xb7, 0x7f, 0x44, 0x6c, 0x84, 0x55, 0x4e, 0x8f, 0x7f, 0x2d, 0xb1, 0x69, 38 | 0x23, 0xad, 0x29, 0x85, 0xf3, 0x69, 0xf, 0x7c, 0xaa, 0xa5, 0x21, 0xd7, 0xd4, 0x9a, 0x5e, 0x60, 39 | 0x43, 0x20, 0x20, 0x96, 0x6e, 0x1c, 0xf8, 0x5, 0xa, 0x87, 0x8f, 0x5b, 0xa, 0x95, 0x4b, 0x62, 40 | 0x46, 0xb6, 0x88, 0x3a, 0x6c, 0xe8, 0xa7, 0x46, 0xca, 0xa1, 0x9f, 0xca, 0x0, 0x52, 0xe8, 0xc8, 41 | 0xd8, 0x97, 0xe1, 0x25, 0x4b, 0x58, 0x84, 0x19, 0xfd, 0x2c, 0xd1, 0x65, 0xbb, 0x14, 0xbb, 0x78, 42 | 0x50, 0x8c, 0x21, 0x94, 0x59, 0xa3, 0x9, 0x43, 0x57, 0xb, 0xad, 0xad, 0xd1, 0x2c, 0xd9, 0x52, 43 | 0xd3, 0x8, 0xa6, 0x6a, 0xc8, 0xe9, 0x47, 0x76, 0x8a, 0x2d, 0xd4, 0x55, 0xab, 0x9a, 0xe6, 0xe, 44 | 0xfe, 0xa7, 0xf2, 0x21, 0xae, 0x49, 0x61, 0x16, 0xa1, 0x9f, 0xfa, 0x99, 0x24, 0x65, 0x56, 0x99, 45 | 0x4d, 0x14, 0x8c, 0x8b, 0x33, 0xca, 0x6, 0xdf, 0xa2, 0xe8, 0x56, 0x70, 0x2d, 0x17, 0xa1, 0x6e, 46 | 0x76, 0x51, 0x30, 0x2e, 0x93, 0xa1, 0x32, 0xcb, 0xd0, 0xcf, 0x75, 0x8d, 0x7e, 0xe3, 0xce, 0x2c, 47 | 0x22, 0xc4, 0x73, 0xc3, 0xbd, 0x4a, 0x54, 0x51, 0x9c, 0xfd, 0x15, 0x85, 0xc4, 0xb6, 0xae, 0xda, 48 | 0x22, 0xa4, 0x21, 0xce, 0x7c, 0x4, 0x2d, 0xe4, 0xc, 0x93, 0x35, 0xc6, 0xe5, 0xed, 0x86, 0x8b, 49 | 0x56, 0x90, 0x77, 0xe6, 0x73, 0x47, 0xe5, 0x7b, 0x46, 0x14, 0x84, 0xb4, 0x6f, 0xf3, 0x3d, 0x1b, 50 | 0x18, 0x7, 0x9b, 0x13, 0x67, 0x63, 0xb0, 0xe6, 0x44, 0x6d, 0x63, 0xa6, 0x98, 0xcb, 0x8b, 0x8, 51 | 0xb5, 0xb1, 0x12, 0x9, 0xf, 0xd4, 0xb1, 0xc9, 0x95, 0xf2, 0x9c, 0x88, 0x44, 0xc5, 0x99, 0x38, 52 | 0x4, 0x4b, 0xcb, 0x42, 0x56, 0xae, 0x91, 0xb1, 0xc0, 0xc6, 0x47, 0x6c, 0x7e, 0x5f, 0xd9, 0x86, 53 | 0x55, 0xb5, 0x87, 0x1d, 0xdb, 0xf5, 0x23, 0xd2, 0xa6, 0xed, 0x94, 0xff, 0x45, 0x30, 0x67, 0xe, 54 | 0x19, 0xab, 0x38, 0x18, 0x94, 0x35, 0x15, 0xf7, 0xfd, 0xcb, 0x72, 0x23, 0xc8, 0xc2, 0x4e, 0x1d, 55 | 0x34, 0xc3, 0x4e, 0x99, 0xc8, 0x22, 0x18, 0xa, 0xd2, 0xae, 0xc8, 0x55, 0xc5, 0xbd, 0x1b, 0x93, 56 | 0x2c, 0x2d, 0x5e, 0xc3, 0x7, 0xdf, 0xd5, 0xb6, 0x23, 0x3b, 0x3e, 0xca, 0xfc, 0x14, 0x62, 0x7, 57 | 0x2, 0xac, 0xa8, 0xf5, 0x86, 0x31, 0x6b, 0x90, 0xa1, 0x74, 0x82, 0x0, 0xb9, 0x73, 0xc, 0xb9, 58 | 0xe0, 0xf2, 0x28, 0x3e, 0x2c, 0x5f, 0x18, 0xd4, 0x52, 0x9f, 0xa6, 0xea, 0xfb, 0xe5, 0xb, 0x11, 59 | 0x9e, 0x10, 0x76, 0x68, 0x46, 0x24, 0x58, 0x4b, 0xe7, 0xef, 0x2b, 0x9d, 0x82, 0xf7, 0x23, 0xca, 60 | 0x80, 0xc9, 0xba, 0x94, 0xb2, 0xbf, 0xaf, 0xcc, 0x8, 0xf1, 0x4a, 0xcf, 0xb2, 0xaa, 0xd6, 0x8a, 61 | 0x96, 0x75, 0xdc, 0x3b, 0x1e, 0x56, 0x36, 0x4c, 0x4a, 0x2d, 0x73, 0xeb, 0x45, 0x45, 0xc6, 0x48, 62 | 0xb2, 0x49, 0x35, 0x4, 0xa3, 0x85, 0xb7, 0xc2, 0x81, 0x2, 0x88, 0x9c, 0xb8, 0xc3, 0x87, 0x43, 63 | 0xb3, 0x6, 0x37, 0x4, 0xf9, 0x7e, 0xa5, 0xca, 0xa6, 0x59, 0x76, 0x83, 0xbe, 0x31, 0x28, 0x75, 64 | 0x4c, 0xce, 0xae, 0x3, 0xde, 0x80, 0x66, 0xe, 0x36, 0x4b, 0xd2, 0xb3, 0x89, 0x2d, 0x14, 0x39, 65 | 0xa4, 0xc2, 0xde, 0xa8, 0x47, 0xff, 0xca, 0x66, 0x64, 0x71, 0xf5, 0x7, 0xdd, 0xe8, 0x98, 0xb0, 66 | 0x48, 0xf8, 0x53, 0x31, 0x67, 0x5c, 0x3b, 0x91, 0xef, 0x63, 0x4, 0xa3, 0xc, 0x5c, 0xb4, 0x24, 67 | 0xad, 0xd5, 0x33, 0xab, 0x13, 0x57, 0xad, 0x85, 0x68, 0xa5, 0x2b, 0x26, 0xdd, 0xd0, 0x56, 0x3a, 68 | 0x8f, 0x2c, 0xcf, 0x88, 0x54, 0x65, 0xba, 0x9e, 0x4b, 0x6d, 0xf2, 0x1b, 0xc5, 0x26, 0xb, 0x1d, 69 | 0x9b, 0x39, 0x76, 0xe4, 0xba, 0x14, 0xd1, 0x36, 0x9, 0x40, 0x4d, 0xc5, 0x44, 0xf5, 0xc, 0xb7, 70 | 0x53, 0x74, 0x66, 0xc, 0x5b, 0xb4, 0x19, 0x93, 0xb, 0x40, 0x45, 0xa2, 0x48, 0x72, 0x88, 0x16, 71 | 0x7a, 0xa0, 0x54, 0xcc, 0x6a, 0x3f, 0xbb, 0x90, 0x45, 0xb4, 0x54, 0x35, 0x6, 0xf1, 0x64, 0x7d, 72 | 0xa8, 0x62, 0x7c, 0xba, 0x60, 0x3e, 0x43, 0xcd, 0xde, 0x51, 0xef, 0xe8, 0x18, 0xfe, 0xa3, 0x68, 73 | 0xd0, 0xcb, 0x9d, 0x4b, 0x98, 0xb7, 0xc0, 0xf3, 0x72, 0xc9, 0xa7, 0x7a, 0x9f, 0xa4, 0x28, 0x8d, 74 | 0x55, 0x62, 0x51, 0x3f, 0x92, 0xb2, 0x1b, 0x26, 0xfd, 0x4e, 0x45, 0x61, 0x29, 0x70, 0xe9, 0xed, 75 | 0x1d, 0x51, 0xe1, 0x2d, 0xdb, 0x42, 0xbc, 0xf4, 0xfe, 0x69, 0xf3, 0xaa, 0xfa, 0x7f, 0xef, 0xed, 76 | 0x92, 0x29, 0xbe, 0x69, 0x4f, 0xdf, 0xda, 0x2e, 0xe1, 0xa1, 0x7d, 0xa3, 0x57, 0x8c, 0x7a, 0x5b, 77 | 0xf4, 0x33, 0x20, 0xa1, 0xb, 0x8b, 0xaa, 0x0, 0x56, 0x57, 0x85, 0x3d, 0x8f, 0x34, 0x66, 0x7, 78 | 0x1b, 0x58, 0xb6, 0xe3, 0xb4, 0x1d, 0x6f, 0x5d, 0xdd, 0x89, 0x94, 0x7b, 0xf2, 0x86, 0x9f, 0x56, 79 | 0xbb, 0xfc, 0xae, 0xd2, 0x46, 0x90, 0xb9, 0xfe, 0x27, 0xa4, 0xfd, 0xb6, 0x3, 0xae, 0x34, 0x34, 80 | 0x76, 0x2b, 0x14, 0x3b, 0xf8, 0xe3, 0x7e, 0x13, 0xd5, 0x72, 0x25, 0xde, 0x9, 0x96, 0x2e, 0xe6, 81 | 0xc2, 0xb5, 0x4d, 0x8c, 0xc5, 0xe, 0x8b, 0x2a, 0xdf, 0xb, 0x6d, 0x7e, 0x8d, 0x26, 0xc0, 0xe, 82 | 0xa2, 0x1d, 0xfc, 0x4e, 0x4b, 0xee, 0xca, 0x85, 0x89, 0x4c, 0x5e, 0x47, 0x13, 0x66, 0xba, 0xaf, 83 | 0x67, 0xbb, 0xa4, 0xc3, 0x7b, 0x87, 0xe2, 0x5c, 0xad, 0x76, 0xeb, 0x8a, 0x76, 0x3f, 0x1b, 0x19, 84 | 0xea, 0x41, 0x5b, 0x64, 0xf4, 0x38, 0x69, 0xcf, 0x3, 0x7c, 0x55, 0x43, 0x99, 0x23, 0xf1, 0xef, 85 | 0x88, 0x6f, 0x88, 0xee, 0xbe, 0xf6, 0x67, 0x5, 0x40, 0x78, 0x51, 0x67, 0x18, 0xd6, 0x98, 0xba, 86 | 0x78, 0xca, 0x3a, 0xfe, 0x98, 0x6c, 0xf7, 0xe9, 0x7a, 0x8d, 0x74, 0x53, 0x52, 0x42, 0xd5, 0xae, 87 | 0x1a, 0x57, 0x5f, 0xe5, 0x49, 0x7, 0x5b, 0xa4, 0xe0, 0x6a, 0x6, 0xeb, 0x53, 0x8f, 0xcb, 0xb3, 88 | 0x5b, 0x5b, 0xda, 0x27, 0xa8, 0xcc, 0x1c, 0xc9, 0xae, 0x5c, 0xb1, 0xf7, 0x29, 0x39, 0xd3, 0xec, 89 | 0xb9, 0x35, 0xf3, 0x62, 0x48, 0xe2, 0xf6, 0x99, 0xc1, 0xc, 0x63, 0x96, 0xa2, 0xe4, 0x3, 0x3c, 90 | 0xf8, 0xf7, 0xe6, 0xe0, 0x44, 0x79, 0xb1, 0xa0, 0x64, 0x70, 0x99, 0x68, 0x85, 0xdb, 0x5a, 0x9b, 91 | 0x25, 0xab, 0x70, 0x81, 0x2c, 0xe7, 0x22, 0x25, 0x50, 0xe5, 0x51, 0x59, 0x96, 0x61, 0x36, 0xf7, 92 | 0x68, 0x4a, 0x9d, 0xdd, 0x5e, 0x22, 0x68, 0x7b, 0xa9, 0xbb, 0x22, 0xe0, 0xa8, 0xc2, 0xaf, 0x8e, 93 | 0xbb, 0x4b, 0x9b, 0x86, 0xfd, 0x93, 0x5e, 0xc5, 0x94, 0x86, 0xe3, 0x85, 0xe5, 0x71, 0x85, 0x66, 94 | 0x60, 0xbf, 0x88, 0x28, 0x26, 0x12, 0x5b, 0x97, 0xca, 0x9d, 0x27, 0xe6, 0xdc, 0xca, 0x33, 0xb5, 95 | 0x4a, 0x77, 0x69, 0x4c, 0x95, 0x87, 0x63, 0xce, 0xe6, 0xfd, 0x9e, 0x32, 0xd3, 0x96, 0xee, 0xbf, 96 | 0x11, 0x7c, 0x9, 0xeb, 0x4d, 0x7a, 0x41, 0x6e, 0xa4, 0x19, 0x58, 0x9d, 0x46, 0x33, 0x45, 0xae, 97 | 0x5f, 0x67, 0x13, 0xb0, 0x14, 0x87, 0x85, 0x6d, 0x9a, 0xb8, 0x74, 0x97, 0x93, 0xae, 0x79, 0x73, 98 | 0x2c, 0xe2, 0xa3, 0x71, 0x57, 0xba, 0x81, 0x65, 0xdc, 0x4d, 0xef, 0xb5, 0x19, 0xd3, 0xbb, 0x58, 99 | 0xe4, 0xfb, 0x5c, 0xf8, 0x45, 0x16, 0xcd, 0x70, 0x50, 0x18, 0x4e, 0x74, 0x7a, 0x37, 0x86, 0x9e, 100 | 0xbd, 0xed, 0x65, 0x6c, 0xda, 0x2b, 0xcd, 0x36, 0x27, 0xba, 0xe3, 0xcd, 0xbd, 0xdc, 0x39, 0x76, 101 | 0x9e, 0x6f, 0x7b, 0x43, 0xa4, 0x4e, 0xf4, 0xcc, 0x25, 0x1, 0x9d, 0x51, 0xa5, 0x3f, 0xe9, 0xd3, 102 | 0x7b, 0x77, 0x1e, 0x3e, 0x78, 0x70, 0xf2, 0xc3, 0x3d, 0x77, 0x16, 0xfa, 0xe2, 0xbf, 0xbf, 0xf2, 103 | 0x2b, 0x28, 0xaf, 0xdf, 0xe, 0x4e, 0x86, 0xd0, 0xd0, 0x62, 0x42, 0x6c, 0x77, 0x1e, 0x8e, 0xbb, 104 | 0x8c, 0x69, 0x4e, 0x90, 0x2e, 0x48, 0x52, 0x20, 0x9b, 0x48, 0xe8, 0x2a, 0xf1, 0xe2, 0x21, 0x21, 105 | 0xe4, 0xa8, 0x19, 0xa, 0x14, 0x43, 0xd8, 0x30, 0xde, 0x2e, 0xb0, 0x4e, 0x4b, 0x67, 0x89, 0x6d, 106 | 0xe6, 0x5d, 0xe6, 0x35, 0x60, 0x4a, 0x89, 0xac, 0x27, 0x46, 0x61, 0xb3, 0x88, 0x21, 0x90, 0x31, 107 | 0x72, 0x7a, 0x3d, 0xa4, 0x60, 0x4c, 0x22, 0x9f, 0xb0, 0xbe, 0xb4, 0x3d, 0xcf, 0xa7, 0xb6, 0x2, 108 | 0xb4, 0xc4, 0x34, 0x11, 0x89, 0x1f, 0x8b, 0xd9, 0xe4, 0x91, 0x48, 0x28, 0xf5, 0xe9, 0x1b, 0xcc, 109 | 0xc2, 0x15, 0x50, 0x56, 0x9a, 0x75, 0x83, 0x8b, 0xc8, 0xa0, 0x99, 0xf9, 0xf5, 0x58, 0x44, 0xb1, 110 | 0x63, 0xda, 0x46, 0xcc, 0x6d, 0x2a, 0x4, 0x62, 0xec, 0x3c, 0x9f, 0x39, 0xd8, 0xa, 0x39, 0x11, 111 | 0x98, 0xb6, 0xdf, 0xd3, 0xa7, 0xbf, 0xfd, 0xfe, 0xec, 0x71, 0x13, 0x12, 0x51, 0xef, 0xb2, 0x3f, 112 | 0xe8, 0xf5, 0x5a, 0xe3, 0x2e, 0x1f, 0xb2, 0x35, 0xaf, 0x87, 0xfa, 0xf4, 0x82, 0xb1, 0x1a, 0x9c, 113 | 0x2, 0xab, 0xde, 0x60, 0xb8, 0x3b, 0xab, 0x53, 0x7d, 0xca, 0x38, 0x1, 0x93, 0xcb, 0x7, 0x27, 114 | 0xa7, 0xbb, 0x33, 0x7a, 0x0, 0x32, 0xbd, 0x5, 0x4e, 0xa7, 0xa0, 0xdd, 0xc9, 0x3e, 0xca, 0x9d, 115 | 0xe8, 0x53, 0xca, 0x7, 0xa2, 0xe2, 0x72, 0x78, 0xba, 0x7, 0x9f, 0xfb, 0xba, 0x28, 0x89, 0xd4, 116 | 0x65, 0xe3, 0x23, 0x7d, 0x7a, 0xf6, 0xd3, 0x8f, 0xcd, 0x21, 0xc8, 0x38, 0x78, 0x78, 0xb2, 0x3b, 117 | 0xef, 0xa1, 0x3e, 0xfd, 0x85, 0xa, 0x79, 0x3c, 0x0, 0x46, 0xc3, 0x3d, 0x84, 0x3c, 0xd6, 0xa7, 118 | 0xcf, 0x19, 0x27, 0xe0, 0x72, 0xd9, 0x7f, 0xb0, 0x87, 0x48, 0xe0, 0x5e, 0xbf, 0x30, 0x4e, 0xe0, 119 | 0x5f, 0xd4, 0xbd, 0x6a, 0x72, 0x82, 0x7c, 0xc9, 0x4c, 0x53, 0x12, 0xa7, 0x9b, 0xd9, 0x27, 0x73, 120 | 0xba, 0x2c, 0x8c, 0xff, 0x8e, 0xa0, 0x74, 0x90, 0xab, 0xad, 0x83, 0x58, 0xd0, 0x81, 0x4a, 0xfc, 121 | 0xa0, 0x5e, 0xfc, 0x4a, 0x92, 0x24, 0x97, 0xe5, 0xf4, 0x69, 0xbf, 0x57, 0xa1, 0x1, 0xa3, 0x95, 122 | 0xb3, 0x20, 0x23, 0xce, 0x28, 0xa0, 0xd3, 0x4e, 0x82, 0xc5, 0x30, 0xbd, 0xf5, 0x3, 0x7c, 0xf4, 123 | 0x58, 0x97, 0xe2, 0x7a, 0xa7, 0x14, 0xa1, 0x90, 0x16, 0x5d, 0xea, 0xd3, 0x93, 0xe3, 0x2a, 0x7b, 124 | 0xef, 0x1, 0xc7, 0x8c, 0xb5, 0x29, 0x2e, 0xe, 0xc3, 0xad, 0x11, 0x49, 0x49, 0xf5, 0xe9, 0x93, 125 | 0xe4, 0x78, 0x1f, 0x5c, 0xda, 0x83, 0x3d, 0x70, 0x91, 0xc4, 0xe1, 0xd0, 0xb4, 0x7, 0x2, 0x9a, 126 | 0x81, 0x9e, 0x46, 0xc4, 0xe7, 0x4, 0xa6, 0x4a, 0xda, 0x7d, 0x70, 0xa1, 0x45, 0x3c, 0x40, 0x21, 127 | 0xd9, 0x1a, 0x95, 0x98, 0x10, 0xd2, 0x9a, 0x38, 0x3a, 0x18, 0x22, 0x89, 0x28, 0xdf, 0x0, 0x1e, 128 | 0x21, 0x22, 0x51, 0xc0, 0x6e, 0x88, 0xdb, 0x1a, 0x91, 0x94, 0x14, 0xea, 0x61, 0x72, 0x7c, 0x30, 129 | 0x54, 0x24, 0x71, 0xbe, 0x5, 0x5c, 0x7c, 0x6c, 0xd8, 0xc8, 0x79, 0x8f, 0x2d, 0xb, 0x4a, 0xd6, 130 | 0xf6, 0xd8, 0x64, 0xc8, 0x1, 0x1f, 0xfe, 0x5d, 0x3b, 0x67, 0xdf, 0xb7, 0xee, 0x11, 0x73, 0xec, 131 | 0x3e, 0x57, 0xa3, 0xd8, 0x53, 0xf7, 0x2d, 0xaf, 0xbc, 0x44, 0xce, 0x1d, 0x3b, 0x84, 0x3e, 0x30, 132 | 0xc1, 0x73, 0xb6, 0x52, 0xde, 0x99, 0xc7, 0x40, 0x9f, 0x3e, 0xb, 0xd0, 0x15, 0x7b, 0xb6, 0x60, 133 | 0x9f, 0xa6, 0xe7, 0xd, 0x36, 0xb5, 0x5f, 0x61, 0x29, 0xb8, 0x4f, 0x7, 0xf6, 0x2c, 0xc0, 0xb0, 134 | 0x4c, 0xdc, 0x8b, 0xcb, 0x7d, 0x28, 0x66, 0x70, 0xb0, 0x1f, 0x13, 0x68, 0x58, 0x2f, 0xb0, 0x6f, 135 | 0xa3, 0xaf, 0xa1, 0xe1, 0x42, 0xeb, 0xd9, 0xd6, 0x61, 0x1, 0x34, 0xfa, 0xf4, 0xf1, 0xbb, 0x27, 136 | 0x5b, 0x27, 0x29, 0xbe, 0xdf, 0x5c, 0xc7, 0xc3, 0x79, 0x76, 0x12, 0x2, 0xea, 0x1b, 0x8b, 0x4d, 137 | 0x75, 0xe4, 0xd4, 0x5d, 0x70, 0x2a, 0xf4, 0x8a, 0x5, 0x64, 0xdb, 0x73, 0xba, 0xa4, 0x66, 0x3d, 138 | 0x1d, 0xbf, 0x5c, 0x6, 0x3, 0x21, 0xde, 0xcf, 0x91, 0xbd, 0x7d, 0x5d, 0x89, 0x9, 0x19, 0x52, 139 | 0xda, 0x33, 0x38, 0xba, 0x29, 0xb8, 0xf8, 0xb4, 0x7, 0xc3, 0x4c, 0x68, 0x7d, 0x68, 0xe0, 0x40, 140 | 0x90, 0xa5, 0x67, 0x6e, 0xbf, 0x1d, 0x21, 0xe8, 0xf4, 0x29, 0xa0, 0xf6, 0x12, 0xe, 0xb6, 0xae, 141 | 0x32, 0x31, 0x83, 0x2f, 0x5c, 0x5e, 0x1e, 0x47, 0xc4, 0xdb, 0xa7, 0xb2, 0x5c, 0x44, 0xae, 0x7b, 142 | 0xb5, 0x4f, 0x59, 0x39, 0x73, 0xbc, 0xc8, 0xdc, 0x9d, 0x3, 0xd4, 0x94, 0xd7, 0x96, 0x65, 0x1b, 143 | 0xbb, 0x57, 0x25, 0xa8, 0x28, 0xcf, 0xbd, 0x65, 0x4d, 0xfa, 0x2f, 0x9c, 0xc5, 0xb1, 0xb1, 0x7d, 144 | 0x82, 0xc0, 0x6, 0xa0, 0x78, 0x7e, 0xa6, 0x5d, 0x9c, 0xbf, 0xba, 0x78, 0xfd, 0xe6, 0x66, 0xb2, 145 | 0x3, 0xcc, 0x79, 0xa0, 0xc4, 0x40, 0xb5, 0x3d, 0x74, 0x4e, 0x0, 0x21, 0x6, 0xbb, 0xe0, 0x34, 146 | 0xe0, 0x40, 0x3d, 0xbd, 0xf8, 0xf9, 0xa6, 0x50, 0x1a, 0x1c, 0xe, 0xa6, 0xc1, 0xd7, 0x80, 0xd3, 147 | 0x7b, 0x7, 0xaf, 0xb0, 0xb3, 0x3, 0x56, 0x9c, 0x90, 0xe2, 0xa5, 0xbd, 0xa0, 0x47, 0x7, 0x5b, 148 | 0xc8, 0x25, 0xa2, 0x7c, 0x3, 0xcb, 0x38, 0xf0, 0x8a, 0xf7, 0x4c, 0xe8, 0x5d, 0x82, 0x87, 0x53, 149 | 0xea, 0xd3, 0xf3, 0x4b, 0xdf, 0xb, 0xa3, 0xa0, 0x66, 0x41, 0x55, 0x23, 0xb2, 0xcf, 0xce, 0x60, 150 | 0x2a, 0xa, 0x47, 0x24, 0xde, 0x1a, 0xa4, 0x3b, 0xfb, 0x9, 0x26, 0x83, 0xde, 0xf0, 0xb3, 0xa2, 151 | 0x42, 0x99, 0x7f, 0x49, 0x60, 0xe6, 0x3b, 0xd4, 0x9d, 0x39, 0xad, 0x3b, 0xcf, 0xce, 0x6e, 0x26, 152 | 0x95, 0xcd, 0xf, 0x56, 0x70, 0xe6, 0x7, 0x2d, 0x38, 0x1a, 0xbf, 0x28, 0x9a, 0xc0, 0xb4, 0xe3, 153 | 0x22, 0x42, 0x10, 0xc2, 0xda, 0x79, 0x97, 0x5, 0x84, 0xbc, 0xa9, 0x7e, 0xb9, 0x4f, 0xe8, 0xc4, 154 | 0x62, 0x64, 0x23, 0xe7, 0x38, 0x8d, 0x9b, 0xfb, 0x9f, 0x35, 0x6a, 0x8e, 0x2b, 0xa5, 0xdd, 0x27, 155 | 0x68, 0xa8, 0x26, 0x6, 0xb6, 0x1d, 0xfa, 0x4, 0xd3, 0xb6, 0x80, 0x48, 0xb4, 0x1c, 0x13, 0xed, 156 | 0x8c, 0x7f, 0xdb, 0x7, 0x9b, 0xc1, 0x3e, 0xd8, 0xc8, 0x12, 0x65, 0xe1, 0x39, 0xf9, 0x42, 0x95, 157 | 0xa6, 0x3f, 0x38, 0xfd, 0x92, 0xf0, 0xcc, 0xfc, 0xed, 0x73, 0x1a, 0xd0, 0xe8, 0xd3, 0x27, 0x3f, 158 | 0xdf, 0x4c, 0x4e, 0xa3, 0x93, 0xd5, 0xcc, 0x69, 0x7b, 0x65, 0x30, 0xa6, 0xd4, 0xa1, 0x5b, 0xb1, 159 | 0xf5, 0xe, 0x68, 0xac, 0xa9, 0xe0, 0xef, 0x6e, 0x8, 0x8d, 0x75, 0x7d, 0x34, 0x3e, 0x73, 0x85, 160 | 0x59, 0x7f, 0xd, 0xf8, 0x4, 0x68, 0xfd, 0x7e, 0xbe, 0x44, 0x5b, 0x63, 0x24, 0xe8, 0xf4, 0xe9, 161 | 0x1b, 0xb4, 0xd6, 0x9e, 0xbd, 0x7c, 0x7c, 0x23, 0x58, 0xc5, 0x93, 0x1e, 0x6, 0xaf, 0x44, 0xe5, 162 | 0x43, 0x63, 0xe6, 0x60, 0x77, 0xfb, 0xa0, 0xa2, 0x44, 0xfa, 0xf4, 0x5, 0x76, 0x43, 0xed, 0xcc, 163 | 0xb, 0xc4, 0xdb, 0x66, 0x6e, 0x4, 0x35, 0x36, 0xf3, 0x61, 0x20, 0xe3, 0x4a, 0x1f, 0x1a, 0xaf, 164 | 0xc5, 0xd2, 0xe, 0x2, 0x2f, 0xd8, 0x1a, 0x32, 0x41, 0xa7, 0x4f, 0x9f, 0xb7, 0x5f, 0xb2, 0xa3, 165 | 0x1b, 0x81, 0x2b, 0x9e, 0xf5, 0x30, 0x88, 0x25, 0x3a, 0x1f, 0x1a, 0xb4, 0x95, 0xe5, 0xd8, 0xfe, 166 | 0xd6, 0x90, 0x31, 0x2a, 0x7d, 0xfa, 0xb6, 0xfd, 0x23, 0xfc, 0x7b, 0x23, 0x70, 0xf1, 0x19, 0xf, 167 | 0x3, 0x96, 0xd0, 0xf6, 0xd0, 0x50, 0x99, 0xc6, 0x7a, 0x6b, 0xa0, 0x80, 0x46, 0x9f, 0x3e, 0x3d, 168 | 0x7b, 0xa7, 0x35, 0x9f, 0x7a, 0x6b, 0x97, 0xde, 0xf8, 0xa7, 0x9d, 0xbf, 0x6a, 0xdd, 0x8, 0x62, 169 | 0x74, 0xea, 0xc3, 0xe0, 0xc5, 0x94, 0x3e, 0x34, 0x5a, 0xec, 0xee, 0xe3, 0x19, 0xda, 0x3e, 0x1d, 170 | 0xc6, 0x84, 0xf4, 0xde, 0x17, 0x38, 0xd2, 0x9e, 0xa0, 0x9b, 0x49, 0x88, 0xc9, 0xbc, 0x37, 0xd1, 171 | 0xb4, 0xa7, 0x4a, 0xde, 0x4, 0x4e, 0xf1, 0x3d, 0xd1, 0x6c, 0x59, 0xc2, 0x5f, 0x3e, 0x53, 0x5, 172 | 0x88, 0x78, 0x25, 0x5, 0x5b, 0x3a, 0x62, 0xd2, 0xe, 0x89, 0xed, 0x38, 0xb0, 0x94, 0xc5, 0x44, 173 | 0xbb, 0xa0, 0x87, 0xe3, 0x2e, 0x1f, 0x50, 0x9f, 0x8b, 0xb8, 0xe1, 0x98, 0xbe, 0xf6, 0x9, 0x2d, 174 | 0xf5, 0xe9, 0x5, 0x7d, 0x2d, 0xf, 0xf0, 0xa2, 0xdf, 0xaa, 0x99, 0xd1, 0xcb, 0x32, 0x46, 0xf1, 175 | 0xd5, 0x9b, 0x71, 0xd7, 0x45, 0xa, 0xfd, 0xb, 0xcc, 0x32, 0xe6, 0x2f, 0x58, 0x2a, 0x60, 0x95, 176 | 0xdc, 0x5d, 0xcd, 0x44, 0x4b, 0x9f, 0x54, 0x48, 0xdc, 0x20, 0xff, 0x4, 0x83, 0xd8, 0xc1, 0xa9, 177 | 0x17, 0x26, 0xec, 0x59, 0x4, 0x11, 0x20, 0xf4, 0x30, 0xb1, 0xc7, 0x7f, 0xfe, 0x5d, 0x5, 0x22, 178 | 0x7d, 0xfd, 0x55, 0x2a, 0x98, 0xae, 0x85, 0x81, 0x31, 0xd1, 0x8b, 0xee, 0xd5, 0x2e, 0xd0, 0xbc, 179 | 0xab, 0x52, 0x3d, 0x37, 0x58, 0x61, 0xeb, 0x71, 0x68, 0x4, 0xb6, 0x4f, 0xa6, 0xb7, 0x4c, 0xcf, 180 | 0x88, 0x96, 0xd8, 0x25, 0x1d, 0x64, 0x9a, 0xe7, 0x2b, 0x38, 0x78, 0x61, 0x87, 0x4, 0x83, 0x15, 181 | 0x9a, 0x8d, 0xa7, 0xaf, 0x5f, 0x9e, 0xf1, 0x7b, 0xd6, 0x5f, 0x78, 0xc8, 0xc4, 0x66, 0xe3, 0x48, 182 | 0xb3, 0x22, 0x97, 0xfb, 0x5d, 0x13, 0xd3, 0xb1, 0xfc, 0xd5, 0x63, 0x2b, 0x14, 0x68, 0x33, 0x14, 183 | 0xe2, 0xe7, 0x5e, 0x48, 0xb4, 0x89, 0x96, 0x70, 0x74, 0x3c, 0x83, 0xdd, 0xcf, 0xd4, 0x59, 0xc0, 184 | 0x9, 0xfa, 0x5e, 0x4c, 0x31, 0x96, 0xab, 0xfb, 0x5b, 0xe0, 0xc0, 0xe0, 0xc6, 0x82, 0x10, 0x7f, 185 | 0xd4, 0xed, 0x36, 0xb4, 0xef, 0x53, 0x1e, 0xdf, 0x6b, 0x8d, 0xd1, 0x69, 0xef, 0xb4, 0xdf, 0xa0, 186 | 0x8f, 0x1b, 0x0, 0x2c, 0xf0, 0x13, 0x40, 0x82, 0x61, 0x38, 0xc4, 0xde, 0x64, 0x2a, 0x9e, 0x37, 187 | 0xc0, 0x4e, 0x87, 0x41, 0x40, 0x5, 0xa6, 0xd2, 0x37, 0x1b, 0x1c, 0xb7, 0x6, 0x7d, 0xf6, 0xe6, 188 | 0x3a, 0xa1, 0xc, 0x17, 0xde, 0xba, 0x8c, 0x32, 0xc0, 0x4b, 0x6f, 0x85, 0x73, 0xc4, 0x9, 0xb5, 189 | 0x78, 0x41, 0x47, 0xe5, 0xd4, 0xf1, 0x8b, 0x3c, 0x1a, 0xad, 0x78, 0x40, 0xf2, 0x6a, 0x8f, 0x89, 190 | 0x46, 0x82, 0x8, 0x67, 0xd9, 0x62, 0xb7, 0x8a, 0x6b, 0x2c, 0x56, 0x29, 0x63, 0xb, 0x39, 0x61, 191 | 0x8e, 0x73, 0xe4, 0x9b, 0x88, 0xe0, 0xb7, 0x74, 0xfb, 0x7, 0x6, 0x34, 0xb1, 0x73, 0xc4, 0xf7, 192 | 0x82, 0x8e, 0xc4, 0x99, 0x37, 0xc0, 0x97, 0xe0, 0x56, 0x3a, 0xab, 0xfc, 0x33, 0x50, 0x64, 0xbf, 193 | 0x4e, 0x34, 0x37, 0x72, 0x1c, 0xed, 0x11, 0x53, 0x41, 0x1b, 0x65, 0xce, 0x32, 0x6a, 0x7, 0xd2, 194 | 0x87, 0x78, 0x8d, 0x29, 0x9b, 0x93, 0xfd, 0x68, 0x5b, 0x74, 0xe2, 0xe, 0x7b, 0xa9, 0xea, 0x4, 195 | 0x78, 0x34, 0xe2, 0xc4, 0xdb, 0x48, 0xdf, 0x55, 0x27, 0x13, 0x31, 0x3b, 0x74, 0x44, 0xa1, 0x14, 196 | 0xe7, 0x57, 0xe2, 0xc4, 0xed, 0xdb, 0xab, 0x84, 0xaf, 0x26, 0xd, 0x83, 0x53, 0xe9, 0x89, 0x6b, 197 | 0x38, 0x21, 0x3d, 0x10, 0xb4, 0xc9, 0x3b, 0xc7, 0x23, 0x66, 0x2e, 0x71, 0xb8, 0x95, 0x48, 0x9e, 198 | 0xb1, 0xc0, 0xbd, 0x7b, 0x59, 0x6e, 0xb7, 0x27, 0x82, 0x2a, 0xd5, 0x84, 0x8f, 0x87, 0x48, 0x81, 199 | 0x48, 0x4, 0xb5, 0xc5, 0x63, 0x62, 0x42, 0x24, 0xdb, 0x6a, 0xde, 0xce, 0x18, 0x3e, 0x91, 0xd1, 200 | 0xa2, 0x26, 0xb2, 0x4d, 0x66, 0x20, 0x76, 0x91, 0xb4, 0x95, 0x3e, 0x46, 0xc3, 0xe5, 0x7b, 0xc4, 201 | 0xbc, 0xbe, 0x89, 0xc5, 0xe5, 0x93, 0x16, 0xd8, 0x9f, 0x3a, 0x73, 0xfa, 0x83, 0x18, 0x9f, 0x4e, 202 | 0x25, 0x73, 0x9c, 0x67, 0x38, 0x52, 0xc5, 0x72, 0x72, 0xd3, 0xf, 0xe3, 0x47, 0x37, 0x12, 0xc5, 203 | 0x66, 0xa6, 0xfc, 0xd8, 0x1a, 0x9b, 0x1c, 0xd8, 0xd0, 0xcd, 0xce, 0xf4, 0xf7, 0x9c, 0xa9, 0x93, 204 | 0x81, 0x5, 0x4c, 0xd8, 0x4, 0x9b, 0x4c, 0x4a, 0x25, 0x8f, 0xef, 0x24, 0x51, 0x18, 0x84, 0xb1, 205 | 0x5b, 0xcf, 0xa8, 0x29, 0xd8, 0xac, 0x70, 0x78, 0x4b, 0x66, 0x79, 0x1d, 0x7, 0x43, 0x92, 0xa8, 206 | 0x64, 0x74, 0xa8, 0x57, 0xc6, 0xfa, 0x53, 0xc7, 0x4d, 0xe1, 0x17, 0xcf, 0xe3, 0xc6, 0x5e, 0x9b, 207 | 0x1a, 0xc9, 0x80, 0x9c, 0x24, 0xf9, 0xef, 0x28, 0x27, 0x91, 0xec, 0xb8, 0x20, 0x5e, 0x5f, 0x93, 208 | 0x9f, 0xb0, 0x9d, 0x41, 0x9a, 0xfb, 0x98, 0xe1, 0xc3, 0xf6, 0x52, 0x13, 0x26, 0xfc, 0x37, 0x7e, 209 | 0x77, 0x42, 0xdb, 0x73, 0xb1, 0x9a, 0xbb, 0xec, 0xba, 0x2a, 0x9e, 0xbc, 0xd0, 0xe6, 0x99, 0x46, 210 | 0xb3, 0xa5, 0x4d, 0x14, 0xc, 0x1b, 0x90, 0x54, 0x55, 0xbc, 0x44, 0x27, 0x94, 0x12, 0x4, 0x98, 211 | 0x44, 0x81, 0x2b, 0xc7, 0x6, 0xcf, 0x2f, 0x7f, 0x47, 0x38, 0xb8, 0x2, 0x46, 0x1f, 0x44, 0xe2, 212 | 0xbe, 0xfb, 0x29, 0x4e, 0xdb, 0xd7, 0x34, 0x67, 0xf7, 0xba, 0xec, 0xee, 0x62, 0xcf, 0x79, 0x4, 213 | 0x99, 0x7e, 0x72, 0xf7, 0x13, 0xc3, 0xf5, 0xfa, 0x1e, 0x4c, 0xf, 0x5f, 0x98, 0x10, 0xd7, 0x1f, 214 | 0x38, 0x3b, 0x8b, 0xbe, 0x2b, 0xb2, 0xc9, 0xd8, 0xc5, 0x18, 0x76, 0xc8, 0x2, 0xbb, 0xcd, 0x0, 215 | 0x87, 0x3e, 0x4c, 0x85, 0xd3, 0x14, 0x15, 0xcf, 0xee, 0x39, 0x18, 0x8a, 0xca, 0xbc, 0xf9, 0x21, 216 | 0xc0, 0x40, 0x7, 0xc2, 0x10, 0x4f, 0xbb, 0xfb, 0x89, 0xb1, 0xb8, 0xd6, 0x2c, 0x88, 0xd3, 0x70, 217 | 0x81, 0xcd, 0x23, 0xa8, 0x2f, 0x88, 0xd0, 0x87, 0xe8, 0xee, 0x7e, 0x8a, 0x59, 0x75, 0xf8, 0x4f, 218 | 0xd7, 0x1f, 0x12, 0x6f, 0x49, 0xd2, 0x7c, 0x5c, 0xad, 0xd8, 0x89, 0xe, 0xe3, 0x75, 0xc1, 0x10, 219 | 0xf1, 0x82, 0xc7, 0x8e, 0xd3, 0x6c, 0xf0, 0x67, 0xd, 0x45, 0xf6, 0xed, 0x40, 0xa7, 0x77, 0x8e, 220 | 0x40, 0x6c, 0x39, 0x6d, 0xb3, 0x8c, 0xe2, 0xb9, 0x86, 0x63, 0x1b, 0x1f, 0x69, 0xca, 0x6d, 0x65, 221 | 0x5, 0xe7, 0x31, 0xec, 0x74, 0xf8, 0xbb, 0x23, 0x5e, 0x79, 0x26, 0xce, 0xb9, 0x6c, 0x8b, 0x8a, 222 | 0xd1, 0xed, 0x82, 0xc5, 0x91, 0x19, 0x27, 0x1b, 0x8e, 0x17, 0x7d, 0xc8, 0x98, 0x9b, 0xa9, 0xd0, 223 | 0xda, 0x5c, 0x31, 0xa1, 0x17, 0xb7, 0x5f, 0x5a, 0xa3, 0x63, 0xf5, 0x53, 0x77, 0xe6, 0xa8, 0x6a, 224 | 0x89, 0x5d, 0xfe, 0xa, 0x3d, 0xb7, 0xd9, 0xba, 0x95, 0x98, 0x64, 0x93, 0x7, 0x9d, 0x40, 0x62, 225 | 0x90, 0x31, 0x57, 0x91, 0xc9, 0xb2, 0x6d, 0x75, 0x23, 0x8d, 0xfb, 0x2, 0xfb, 0xd1, 0x8f, 0x54, 226 | 0xb7, 0x58, 0xd1, 0x62, 0xf3, 0xfe, 0xc1, 0xdc, 0xe7, 0xcf, 0x23, 0x5e, 0xe8, 0xa4, 0xfc, 0xd1, 227 | 0x92, 0x4c, 0xc7, 0xfd, 0x92, 0xbe, 0x71, 0x5b, 0x6e, 0x3e, 0xa0, 0xc5, 0x3d, 0x77, 0x30, 0x3d, 228 | 0x7c, 0x72, 0xf5, 0x13, 0x14, 0x68, 0xde, 0x74, 0x30, 0x59, 0x52, 0x82, 0xb3, 0xa4, 0xe5, 0xab, 229 | 0xa4, 0x4c, 0xdb, 0x43, 0x89, 0x7, 0xeb, 0xa1, 0x9f, 0xf0, 0x8e, 0xb8, 0x84, 0x43, 0xd2, 0x6e, 230 | 0x67, 0x48, 0x29, 0xd7, 0x6a, 0xda, 0x4c, 0x93, 0x2d, 0xd1, 0x33, 0xb7, 0xac, 0x26, 0x97, 0x5b, 231 | 0xd2, 0x86, 0x64, 0xae, 0x90, 0x78, 0x3e, 0x6f, 0xd5, 0x73, 0x2e, 0xbb, 0xb6, 0x5d, 0xd3, 0x5b, 232 | 0x77, 0xe8, 0xf9, 0xa6, 0x28, 0x65, 0xb2, 0xa8, 0x1d, 0xdb, 0x5, 0x13, 0x3c, 0xff, 0xf5, 0xe5, 233 | 0xb, 0x9a, 0x4c, 0xe4, 0x96, 0xbf, 0x91, 0xed, 0x43, 0xd8, 0x4b, 0x3a, 0x95, 0x33, 0x50, 0xc3, 234 | 0x77, 0xa0, 0xd5, 0xa5, 0x49, 0xe4, 0xee, 0xa7, 0xa4, 0x19, 0xbc, 0xee, 0xf2, 0xc3, 0xf, 0x7c, 235 | 0x4e, 0x9a, 0xe8, 0x33, 0x10, 0xb5, 0x2a, 0x65, 0xf1, 0xfc, 0xbc, 0x28, 0x10, 0x55, 0x8f, 0x9, 236 | 0x1, 0x87, 0xd3, 0xb8, 0x2b, 0x86, 0x34, 0x63, 0x88, 0xe5, 0xd2, 0x2d, 0x4d, 0x86, 0xaf, 0x20, 237 | 0x80, 0x53, 0x33, 0x89, 0x28, 0x91, 0x85, 0x2f, 0xcc, 0x80, 0xc8, 0x87, 0x28, 0xc3, 0x8f, 0xde, 238 | 0x1b, 0x33, 0x48, 0x7a, 0x4f, 0xc1, 0x8f, 0x3b, 0x2e, 0x68, 0xd3, 0xba, 0x2e, 0x53, 0x8d, 0x9b, 239 | 0x2e, 0x5, 0xb5, 0xae, 0x40, 0x2c, 0xbd, 0xa8, 0xb9, 0x65, 0x6c, 0xa5, 0x66, 0x27, 0xfb, 0xe2, 240 | 0xb9, 0x1b, 0xb7, 0x95, 0x45, 0x46, 0x9e, 0x6c, 0x9a, 0x99, 0x77, 0x16, 0x19, 0x6, 0x69, 0xb2, 241 | 0xd8, 0x10, 0x36, 0xd7, 0x3c, 0x48, 0x3e, 0x12, 0xf, 0xd8, 0x44, 0x4e, 0x24, 0x13, 0x8d, 0x3e, 242 | 0x0, 0xbc, 0xa0, 0xf5, 0x53, 0x60, 0x59, 0x27, 0x77, 0x2b, 0x13, 0x51, 0x69, 0x12, 0xe7, 0x33, 243 | 0xc4, 0x46, 0xca, 0xb7, 0x76, 0xd9, 0x84, 0x7d, 0x16, 0x81, 0x82, 0xcb, 0xd8, 0xb5, 0xf8, 0x6f, 244 | 0xb4, 0xcf, 0x49, 0x62, 0x0, 0xfa, 0x9e, 0xb2, 0xd8, 0x84, 0xd3, 0x52, 0x40, 0x8b, 0x26, 0xa9, 245 | 0x82, 0x40, 0xba, 0x9b, 0x40, 0xa2, 0x95, 0x9a, 0xaf, 0xd2, 0x3c, 0x94, 0xbf, 0xfe, 0xcd, 0x58, 246 | 0x0, 0xd7, 0x4d, 0xcd, 0xe5, 0xb5, 0x81, 0xd0, 0x1f, 0xc6, 0xb5, 0x12, 0xc4, 0x29, 0x91, 0xe8, 247 | 0x7b, 0x24, 0xbc, 0xb, 0xba, 0xc9, 0xcd, 0x4e, 0x32, 0xe7, 0x8, 0x45, 0x1d, 0xe4, 0x66, 0xf7, 248 | 0x28, 0x3b, 0x48, 0x7c, 0x5f, 0x51, 0x6a, 0x42, 0x5c, 0x6e, 0x6f, 0x2c, 0xdb, 0x3b, 0xee, 0xa2, 249 | 0x2b, 0x28, 0xe4, 0xdb, 0x9f, 0xb8, 0xb9, 0x70, 0x4d, 0x73, 0x61, 0x61, 0x2e, 0x4a, 0x90, 0xb6, 250 | 0x88, 0xd5, 0x2d, 0x7d, 0xe2, 0xff, 0xef, 0x9e, 0xa4, 0x9a, 0xad, 0x67, 0xa5, 0x72, 0x8a, 0x96, 251 | 0x59, 0x52, 0xaf, 0x9c, 0x20, 0x73, 0x8f, 0x34, 0x57, 0x6b, 0x3d, 0xab, 0xa7, 0x56, 0xdc, 0x72, 252 | 0x53, 0x82, 0x54, 0x2d, 0x75, 0x63, 0x2e, 0xd5, 0x83, 0xe4, 0x31, 0xed, 0x32, 0xb1, 0x92, 0x41, 253 | 0xbc, 0x54, 0x25, 0x5f, 0x6b, 0x49, 0x96, 0x8c, 0xe6, 0x33, 0xf3, 0x30, 0xe5, 0x9f, 0x71, 0x37, 254 | 0xde, 0xee, 0xe0, 0xdf, 0xf8, 0xb, 0x6, 0xc6, 0x5d, 0xfe, 0xbf, 0xfa, 0xf8, 0x2f, 0xa3, 0xf6, 255 | 0xd6, 0x9b, 0x2, 0x64, 0x0, 0x0 256 | }; 257 | --------------------------------------------------------------------------------