From af42ebca626987171f77c68df54d23320f2bc360 Mon Sep 17 00:00:00 2001 From: Liu Yongkai <506680965@qq.com> Date: Tue, 3 Aug 2021 15:37:21 +0800 Subject: [PATCH 01/18] feat(.gitignore): add rtt bsp k210 gitignore & macOS gitignore --- .gitignore | 1 + Ubiquitous/RT_Thread/bsp/k210/.gitignore | 228 +++++++++++++++++++++++ 2 files changed, 229 insertions(+) create mode 100644 Ubiquitous/RT_Thread/bsp/k210/.gitignore diff --git a/.gitignore b/.gitignore index 874eb330..1d3ecbc1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *.vscode *.o +.DS_Store \ No newline at end of file diff --git a/Ubiquitous/RT_Thread/bsp/k210/.gitignore b/Ubiquitous/RT_Thread/bsp/k210/.gitignore new file mode 100644 index 00000000..c5012036 --- /dev/null +++ b/Ubiquitous/RT_Thread/bsp/k210/.gitignore @@ -0,0 +1,228 @@ +# this +*.old +*.dblite +cconfig.h +*.bin +*.map +rtconfig.h +.config + +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.con \ No newline at end of file From 545f1f1b3c0ecace677df74219098830328b38e5 Mon Sep 17 00:00:00 2001 From: Liu Yongkai <506680965@qq.com> Date: Tue, 3 Aug 2021 15:43:03 +0800 Subject: [PATCH 02/18] fix(yolov2): change static input size to dynamic --- .../kpu-postprocessing/yolov2/region_layer.c | 214 +++++++----------- .../kpu-postprocessing/yolov2/region_layer.h | 2 +- 2 files changed, 87 insertions(+), 129 deletions(-) diff --git a/APP_Framework/Framework/knowing/kpu-postprocessing/yolov2/region_layer.c b/APP_Framework/Framework/knowing/kpu-postprocessing/yolov2/region_layer.c index 6ca2182e..dad31268 100644 --- a/APP_Framework/Framework/knowing/kpu-postprocessing/yolov2/region_layer.c +++ b/APP_Framework/Framework/knowing/kpu-postprocessing/yolov2/region_layer.c @@ -1,66 +1,63 @@ -#include +#include "region_layer.h" + #include #include -#include "region_layer.h" +#include -typedef struct -{ +typedef struct { float x; float y; float w; float h; } box_t; -typedef struct -{ +typedef struct { int index; int class; float **probs; } sortable_box_t; - int region_layer_init(region_layer_t *rl, int width, int height, int channels, int origin_width, int origin_height) { int flag = 0; rl->coords = 4; - rl->image_width = 320; - rl->image_height = 240; + /* As no more parameter adding to this function, + image width(height) is regarded as net input shape as well as image capture from sensor. + If net input did not match sensor input, `dvp_set_image_size` function can set sensor output shape. + */ + rl->image_width = origin_width; + rl->image_height = origin_height; rl->classes = channels / 5 - 5; rl->net_width = origin_width; rl->net_height = origin_height; rl->layer_width = width; rl->layer_height = height; - rl->boxes_number = (rl->layer_width * rl->layer_height * rl->anchor_number); + rl->boxes_number = (rl->layer_width * rl->layer_height * rl->anchor_number); rl->output_number = (rl->boxes_number * (rl->classes + rl->coords + 1)); rl->output = malloc(rl->output_number * sizeof(float)); - if (rl->output == NULL) - { + if (rl->output == NULL) { flag = -1; goto malloc_error; } rl->boxes = malloc(rl->boxes_number * sizeof(box_t)); - if (rl->boxes == NULL) - { + if (rl->boxes == NULL) { flag = -2; goto malloc_error; } rl->probs_buf = malloc(rl->boxes_number * (rl->classes + 1) * sizeof(float)); - if (rl->probs_buf == NULL) - { + if (rl->probs_buf == NULL) { flag = -3; goto malloc_error; } rl->probs = malloc(rl->boxes_number * sizeof(float *)); - if (rl->probs == NULL) - { + if (rl->probs == NULL) { flag = -4; goto malloc_error; } - for (uint32_t i = 0; i < rl->boxes_number; i++) - rl->probs[i] = &(rl->probs_buf[i * (rl->classes + 1)]); + for (uint32_t i = 0; i < rl->boxes_number; i++) rl->probs[i] = &(rl->probs_buf[i * (rl->classes + 1)]); return 0; malloc_error: free(rl->output); @@ -78,24 +75,20 @@ void region_layer_deinit(region_layer_t *rl) free(rl->probs); } -static inline float sigmoid(float x) -{ - return 1.f / (1.f + expf(-x)); -} +static inline float sigmoid(float x) { return 1.f / (1.f + expf(-x)); } static void activate_array(region_layer_t *rl, int index, int n) { float *output = &rl->output[index]; float *input = &rl->input[index]; - for (int i = 0; i < n; ++i) - output[i] = sigmoid(input[i]); + for (int i = 0; i < n; ++i) output[i] = sigmoid(input[i]); } static int entry_index(region_layer_t *rl, int location, int entry) { int wh = rl->layer_width * rl->layer_height; - int n = location / wh; + int n = location / wh; int loc = location % wh; return n * wh * (rl->coords + rl->classes + 1) + entry * wh + loc; @@ -109,10 +102,8 @@ static void softmax(region_layer_t *rl, float *input, int n, int stride, float * float sum = 0; float largest_i = input[0]; - for (i = 0; i < n; ++i) - { - if (input[i * stride] > largest_i) - largest_i = input[i * stride]; + for (i = 0; i < n; ++i) { + if (input[i * stride] > largest_i) largest_i = input[i * stride]; } for (i = 0; i < n; ++i) { @@ -121,17 +112,16 @@ static void softmax(region_layer_t *rl, float *input, int n, int stride, float * sum += e; output[i * stride] = e; } - for (i = 0; i < n; ++i) - output[i * stride] /= sum; + for (i = 0; i < n; ++i) output[i * stride] /= sum; } -static void softmax_cpu(region_layer_t *rl, float *input, int n, int batch, int batch_offset, int groups, int stride, float *output) +static void softmax_cpu(region_layer_t *rl, float *input, int n, int batch, int batch_offset, int groups, int stride, + float *output) { int g, b; for (b = 0; b < batch; ++b) { - for (g = 0; g < groups; ++g) - softmax(rl, input + b * batch_offset + g, n, stride, output + b * batch_offset + g); + for (g = 0; g < groups; ++g) softmax(rl, input + b * batch_offset + g, n, stride, output + b * batch_offset + g); } } @@ -139,11 +129,9 @@ static void forward_region_layer(region_layer_t *rl) { int index; - for (index = 0; index < rl->output_number; index++) - rl->output[index] = rl->input[index]; + for (index = 0; index < rl->output_number; index++) rl->output[index] = rl->input[index]; - for (int n = 0; n < rl->anchor_number; ++n) - { + for (int n = 0; n < rl->anchor_number; ++n) { index = entry_index(rl, n * rl->layer_width * rl->layer_height, 0); activate_array(rl, index, 2 * rl->layer_width * rl->layer_height); index = entry_index(rl, n * rl->layer_width * rl->layer_height, 4); @@ -151,9 +139,8 @@ static void forward_region_layer(region_layer_t *rl) } index = entry_index(rl, 0, rl->coords + 1); - softmax_cpu(rl, rl->input + index, rl->classes, rl->anchor_number, - rl->output_number / rl->anchor_number, rl->layer_width * rl->layer_height, - rl->layer_width * rl->layer_height, rl->output + index); + softmax_cpu(rl, rl->input + index, rl->classes, rl->anchor_number, rl->output_number / rl->anchor_number, + rl->layer_width * rl->layer_height, rl->layer_width * rl->layer_height, rl->output + index); } static void correct_region_boxes(region_layer_t *rl, box_t *boxes) @@ -166,8 +153,7 @@ static void correct_region_boxes(region_layer_t *rl, box_t *boxes) int new_w = 0; int new_h = 0; - if (((float)net_width / image_width) < - ((float)net_height / image_height)) { + if (((float)net_width / image_width) < ((float)net_height / image_height)) { new_w = net_width; new_h = (image_height * net_width) / image_width; } else { @@ -177,10 +163,8 @@ static void correct_region_boxes(region_layer_t *rl, box_t *boxes) for (int i = 0; i < boxes_number; ++i) { box_t b = boxes[i]; - b.x = (b.x - (net_width - new_w) / 2. / net_width) / - ((float)new_w / net_width); - b.y = (b.y - (net_height - new_h) / 2. / net_height) / - ((float)new_h / net_height); + b.x = (b.x - (net_width - new_w) / 2. / net_width) / ((float)new_w / net_width); + b.y = (b.y - (net_height - new_h) / 2. / net_height) / ((float)new_h / net_height); b.w *= (float)net_width / new_w; b.h *= (float)net_height / new_h; boxes[i] = b; @@ -207,34 +191,29 @@ static void get_region_boxes(region_layer_t *rl, float *predictions, float **pro uint32_t coords = rl->coords; float threshold = rl->threshold; - for (int i = 0; i < layer_width * layer_height; ++i) - { + for (int i = 0; i < layer_width * layer_height; ++i) { int row = i / layer_width; int col = i % layer_width; - for (int n = 0; n < anchor_number; ++n) - { + for (int n = 0; n < anchor_number; ++n) { int index = n * layer_width * layer_height + i; - for (int j = 0; j < classes; ++j) - probs[index][j] = 0; + for (int j = 0; j < classes; ++j) probs[index][j] = 0; int obj_index = entry_index(rl, n * layer_width * layer_height + i, coords); int box_index = entry_index(rl, n * layer_width * layer_height + i, 0); - float scale = predictions[obj_index]; + float scale = predictions[obj_index]; - boxes[index] = get_region_box(predictions, rl->anchor, n, box_index, col, row, - layer_width, layer_height, layer_width * layer_height); + boxes[index] = get_region_box(predictions, rl->anchor, n, box_index, col, row, layer_width, layer_height, + layer_width * layer_height); float max = 0; - for (int j = 0; j < classes; ++j) - { + for (int j = 0; j < classes; ++j) { int class_index = entry_index(rl, n * layer_width * layer_height + i, coords + 1 + j); float prob = scale * predictions[class_index]; probs[index][j] = (prob > threshold) ? prob : 0; - if (prob > max) - max = prob; + if (prob > max) max = prob; } probs[index][classes] = max; } @@ -257,11 +236,11 @@ static int nms_comparator(void *pa, void *pb) static float overlap(float x1, float w1, float x2, float w2) { - float l1 = x1 - w1/2; - float l2 = x2 - w2/2; + float l1 = x1 - w1 / 2; + float l2 = x2 - w2 / 2; float left = l1 > l2 ? l1 : l2; - float r1 = x1 + w1/2; - float r2 = x2 + w2/2; + float r1 = x1 + w1 / 2; + float r2 = x2 + w2 / 2; float right = r1 < r2 ? r1 : r2; return right - left; @@ -272,8 +251,7 @@ static float box_intersection(box_t a, box_t b) float w = overlap(a.x, a.w, b.x, b.w); float h = overlap(a.y, a.h, b.y, b.h); - if (w < 0 || h < 0) - return 0; + if (w < 0 || h < 0) return 0; return w * h; } @@ -285,10 +263,7 @@ static float box_union(box_t a, box_t b) return u; } -static float box_iou(box_t a, box_t b) -{ - return box_intersection(a, b) / box_union(a, b); -} +static float box_iou(box_t a, box_t b) { return box_intersection(a, b) / box_union(a, b); } static void do_nms_sort(region_layer_t *rl, box_t *boxes, float **probs) { @@ -298,30 +273,23 @@ static void do_nms_sort(region_layer_t *rl, box_t *boxes, float **probs) int i, j, k; sortable_box_t s[boxes_number]; - for (i = 0; i < boxes_number; ++i) - { + for (i = 0; i < boxes_number; ++i) { s[i].index = i; s[i].class = 0; s[i].probs = probs; } - for (k = 0; k < classes; ++k) - { - for (i = 0; i < boxes_number; ++i) - s[i].class = k; + for (k = 0; k < classes; ++k) { + for (i = 0; i < boxes_number; ++i) s[i].class = k; qsort(s, boxes_number, sizeof(sortable_box_t), nms_comparator); - for (i = 0; i < boxes_number; ++i) - { - if (probs[s[i].index][k] == 0) - continue; + for (i = 0; i < boxes_number; ++i) { + if (probs[s[i].index][k] == 0) continue; box_t a = boxes[s[i].index]; - for (j = i + 1; j < boxes_number; ++j) - { + for (j = i + 1; j < boxes_number; ++j) { box_t b = boxes[s[j].index]; - if (box_iou(a, b) > nms_value) - probs[s[j].index][k] = 0; + if (box_iou(a, b) > nms_value) probs[s[j].index][k] = 0; } } } @@ -332,11 +300,9 @@ static int max_index(float *a, int n) int i, max_i = 0; float max = a[0]; - for (i = 1; i < n; ++i) - { - if (a[i] > max) - { - max = a[i]; + for (i = 1; i < n; ++i) { + if (a[i] > max) { + max = a[i]; max_i = i; } } @@ -351,14 +317,12 @@ static void region_layer_output(region_layer_t *rl, obj_info_t *obj_info) uint32_t boxes_number = rl->boxes_number; float threshold = rl->threshold; box_t *boxes = (box_t *)rl->boxes; - - for (int i = 0; i < rl->boxes_number; ++i) - { - int class = max_index(rl->probs[i], rl->classes); + + for (int i = 0; i < rl->boxes_number; ++i) { + int class = max_index(rl->probs[i], rl->classes); float prob = rl->probs[i][class]; - if (prob > threshold) - { + if (prob > threshold) { box_t *b = boxes + i; obj_info->obj[obj_number].x1 = b->x * image_width - (b->w * image_width / 2); obj_info->obj[obj_number].y1 = b->y * image_height - (b->h * image_height / 2); @@ -380,7 +344,8 @@ void region_layer_run(region_layer_t *rl, obj_info_t *obj_info) region_layer_output(rl, obj_info); } -void draw_edge(uint32_t *gram, obj_info_t *obj_info, uint32_t index, uint16_t color) +void draw_edge(uint32_t *gram, obj_info_t *obj_info, uint32_t index, uint16_t color, uint16_t image_width, + uint16_t image_height) { uint32_t data = ((uint32_t)color << 16) | (uint32_t)color; uint32_t *addr1, *addr2, *addr3, *addr4, x1, y1, x2, y2; @@ -390,48 +355,41 @@ void draw_edge(uint32_t *gram, obj_info_t *obj_info, uint32_t index, uint16_t co x2 = obj_info->obj[index].x2; y2 = obj_info->obj[index].y2; - if (x1 <= 0) - x1 = 1; - if (x2 >= 319) - x2 = 318; - if (y1 <= 0) - y1 = 1; - if (y2 >= 239) - y2 = 238; - - addr1 = gram + (320 * y1 + x1) / 2; - addr2 = gram + (320 * y1 + x2 - 8) / 2; - addr3 = gram + (320 * (y2 - 1) + x1) / 2; - addr4 = gram + (320 * (y2 - 1) + x2 - 8) / 2; - for (uint32_t i = 0; i < 4; i++) - { + if (x1 <= 0) x1 = 1; + if (x2 >= image_width - 1) x2 = image_width - 2; + if (y1 <= 0) y1 = 1; + if (y2 >= image_height - 1) y2 = image_height - 2; + + addr1 = gram + (image_width * y1 + x1) / 2; + addr2 = gram + (image_width * y1 + x2 - 8) / 2; + addr3 = gram + (image_width * (y2 - 1) + x1) / 2; + addr4 = gram + (image_width * (y2 - 1) + x2 - 8) / 2; + for (uint32_t i = 0; i < 4; i++) { *addr1 = data; - *(addr1 + 160) = data; + *(addr1 + image_width / 2) = data; *addr2 = data; - *(addr2 + 160) = data; + *(addr2 + image_width / 2) = data; *addr3 = data; - *(addr3 + 160) = data; + *(addr3 + image_width / 2) = data; *addr4 = data; - *(addr4 + 160) = data; + *(addr4 + image_width / 2) = data; addr1++; addr2++; addr3++; addr4++; } - addr1 = gram + (320 * y1 + x1) / 2; - addr2 = gram + (320 * y1 + x2 - 2) / 2; - addr3 = gram + (320 * (y2 - 8) + x1) / 2; - addr4 = gram + (320 * (y2 - 8) + x2 - 2) / 2; - for (uint32_t i = 0; i < 8; i++) - { + addr1 = gram + (image_width * y1 + x1) / 2; + addr2 = gram + (image_width * y1 + x2 - 2) / 2; + addr3 = gram + (image_width * (y2 - 8) + x1) / 2; + addr4 = gram + (image_width * (y2 - 8) + x2 - 2) / 2; + for (uint32_t i = 0; i < 8; i++) { *addr1 = data; *addr2 = data; *addr3 = data; *addr4 = data; - addr1 += 160; - addr2 += 160; - addr3 += 160; - addr4 += 160; + addr1 += image_width / 2; + addr2 += image_width / 2; + addr3 += image_width / 2; + addr4 += image_width / 2; } } - diff --git a/APP_Framework/Framework/knowing/kpu-postprocessing/yolov2/region_layer.h b/APP_Framework/Framework/knowing/kpu-postprocessing/yolov2/region_layer.h index 9b8a5219..70d0ea99 100644 --- a/APP_Framework/Framework/knowing/kpu-postprocessing/yolov2/region_layer.h +++ b/APP_Framework/Framework/knowing/kpu-postprocessing/yolov2/region_layer.h @@ -44,6 +44,6 @@ typedef struct int region_layer_init(region_layer_t *rl, int width, int height, int channels, int origin_width, int origin_height); void region_layer_deinit(region_layer_t *rl); void region_layer_run(region_layer_t *rl, obj_info_t *obj_info); -void draw_edge(uint32_t *gram, obj_info_t *obj_info, uint32_t index, uint16_t color); +void draw_edge(uint32_t *gram, obj_info_t *obj_info, uint32_t index, uint16_t color, uint16_t image_width, uint16_t image_height); #endif // _REGION_LAYER From b3667294edbd284992b5b1bea1c19a8a7b6036c8 Mon Sep 17 00:00:00 2001 From: Liu Yongkai <506680965@qq.com> Date: Tue, 3 Aug 2021 15:47:42 +0800 Subject: [PATCH 03/18] feat(face_detect): read all parameters from SD card json file --- .../knowing_app/face_detect/cJSON.c | 3110 +++++++++++++++++ .../knowing_app/face_detect/cJSON.h | 293 ++ .../knowing_app/face_detect/detect.json | 31 + .../knowing_app/face_detect/face_detect.c | 391 ++- Ubiquitous/RT_Thread/bsp/k210/.config | 39 +- Ubiquitous/RT_Thread/bsp/k210/.gitignore | 4 +- Ubiquitous/RT_Thread/bsp/k210/rtconfig.h | 26 + 7 files changed, 3739 insertions(+), 155 deletions(-) create mode 100644 APP_Framework/Applications/knowing_app/face_detect/cJSON.c create mode 100644 APP_Framework/Applications/knowing_app/face_detect/cJSON.h create mode 100644 APP_Framework/Applications/knowing_app/face_detect/detect.json diff --git a/APP_Framework/Applications/knowing_app/face_detect/cJSON.c b/APP_Framework/Applications/knowing_app/face_detect/cJSON.c new file mode 100644 index 00000000..030311ce --- /dev/null +++ b/APP_Framework/Applications/knowing_app/face_detect/cJSON.c @@ -0,0 +1,3110 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +/* cJSON */ +/* JSON parser in C. */ + +/* disable warnings about old C89 functions in MSVC */ +#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) +#define _CRT_SECURE_NO_DEPRECATE +#endif + +#ifdef __GNUC__ +#pragma GCC visibility push(default) +#endif +#if defined(_MSC_VER) +#pragma warning (push) +/* disable warning about single line comments in system headers */ +#pragma warning (disable : 4001) +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifdef ENABLE_LOCALES +#include +#endif + +#if defined(_MSC_VER) +#pragma warning (pop) +#endif +#ifdef __GNUC__ +#pragma GCC visibility pop +#endif + +#include "cJSON.h" + +/* define our own boolean type */ +#ifdef true +#undef true +#endif +#define true ((cJSON_bool)1) + +#ifdef false +#undef false +#endif +#define false ((cJSON_bool)0) + +/* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */ +#ifndef isinf +#define isinf(d) (isnan((d - d)) && !isnan(d)) +#endif +#ifndef isnan +#define isnan(d) (d != d) +#endif + +#ifndef NAN +#ifdef _WIN32 +#define NAN sqrt(-1.0) +#else +#define NAN 0.0/0.0 +#endif +#endif + +typedef struct { + const unsigned char *json; + size_t position; +} error; +static error global_error = { NULL, 0 }; + +CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) +{ + return (const char*) (global_error.json + global_error.position); +} + +CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item) +{ + if (!cJSON_IsString(item)) + { + return NULL; + } + + return item->valuestring; +} + +CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item) +{ + if (!cJSON_IsNumber(item)) + { + return (double) NAN; + } + + return item->valuedouble; +} + +/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 14) + #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. +#endif + +CJSON_PUBLIC(const char*) cJSON_Version(void) +{ + static char version[15]; + sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); + + return version; +} + +/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */ +static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) +{ + if ((string1 == NULL) || (string2 == NULL)) + { + return 1; + } + + if (string1 == string2) + { + return 0; + } + + for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++) + { + if (*string1 == '\0') + { + return 0; + } + } + + return tolower(*string1) - tolower(*string2); +} + +typedef struct internal_hooks +{ + void *(CJSON_CDECL *allocate)(size_t size); + void (CJSON_CDECL *deallocate)(void *pointer); + void *(CJSON_CDECL *reallocate)(void *pointer, size_t size); +} internal_hooks; + +#if defined(_MSC_VER) +/* work around MSVC error C2322: '...' address of dllimport '...' is not static */ +static void * CJSON_CDECL internal_malloc(size_t size) +{ + return malloc(size); +} +static void CJSON_CDECL internal_free(void *pointer) +{ + free(pointer); +} +static void * CJSON_CDECL internal_realloc(void *pointer, size_t size) +{ + return realloc(pointer, size); +} +#else +#define internal_malloc malloc +#define internal_free free +#define internal_realloc realloc +#endif + +/* strlen of character literals resolved at compile time */ +#define static_strlen(string_literal) (sizeof(string_literal) - sizeof("")) + +static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc }; + +static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks) +{ + size_t length = 0; + unsigned char *copy = NULL; + + if (string == NULL) + { + return NULL; + } + + length = strlen((const char*)string) + sizeof(""); + copy = (unsigned char*)hooks->allocate(length); + if (copy == NULL) + { + return NULL; + } + memcpy(copy, string, length); + + return copy; +} + +CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) +{ + if (hooks == NULL) + { + /* Reset hooks */ + global_hooks.allocate = malloc; + global_hooks.deallocate = free; + global_hooks.reallocate = realloc; + return; + } + + global_hooks.allocate = malloc; + if (hooks->malloc_fn != NULL) + { + global_hooks.allocate = hooks->malloc_fn; + } + + global_hooks.deallocate = free; + if (hooks->free_fn != NULL) + { + global_hooks.deallocate = hooks->free_fn; + } + + /* use realloc only if both free and malloc are used */ + global_hooks.reallocate = NULL; + if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free)) + { + global_hooks.reallocate = realloc; + } +} + +/* Internal constructor. */ +static cJSON *cJSON_New_Item(const internal_hooks * const hooks) +{ + cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON)); + if (node) + { + memset(node, '\0', sizeof(cJSON)); + } + + return node; +} + +/* Delete a cJSON structure. */ +CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) +{ + cJSON *next = NULL; + while (item != NULL) + { + next = item->next; + if (!(item->type & cJSON_IsReference) && (item->child != NULL)) + { + cJSON_Delete(item->child); + } + if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) + { + global_hooks.deallocate(item->valuestring); + } + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) + { + global_hooks.deallocate(item->string); + } + global_hooks.deallocate(item); + item = next; + } +} + +/* get the decimal point character of the current locale */ +static unsigned char get_decimal_point(void) +{ +#ifdef ENABLE_LOCALES + struct lconv *lconv = localeconv(); + return (unsigned char) lconv->decimal_point[0]; +#else + return '.'; +#endif +} + +typedef struct +{ + const unsigned char *content; + size_t length; + size_t offset; + size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */ + internal_hooks hooks; +} parse_buffer; + +/* check if the given size is left to read in a given parse buffer (starting with 1) */ +#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length)) +/* check if the buffer can be accessed at the given index (starting with 0) */ +#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length)) +#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index)) +/* get a pointer to the buffer at the position */ +#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset) + +/* Parse the input text to generate a number, and populate the result into item. */ +static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer) +{ + double number = 0; + unsigned char *after_end = NULL; + unsigned char number_c_string[64]; + unsigned char decimal_point = get_decimal_point(); + size_t i = 0; + + if ((input_buffer == NULL) || (input_buffer->content == NULL)) + { + return false; + } + + /* copy the number into a temporary buffer and replace '.' with the decimal point + * of the current locale (for strtod) + * This also takes care of '\0' not necessarily being available for marking the end of the input */ + for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) + { + switch (buffer_at_offset(input_buffer)[i]) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '+': + case '-': + case 'e': + case 'E': + number_c_string[i] = buffer_at_offset(input_buffer)[i]; + break; + + case '.': + number_c_string[i] = decimal_point; + break; + + default: + goto loop_end; + } + } +loop_end: + number_c_string[i] = '\0'; + + number = strtod((const char*)number_c_string, (char**)&after_end); + if (number_c_string == after_end) + { + return false; /* parse_error */ + } + + item->valuedouble = number; + + /* use saturation in case of overflow */ + if (number >= INT_MAX) + { + item->valueint = INT_MAX; + } + else if (number <= (double)INT_MIN) + { + item->valueint = INT_MIN; + } + else + { + item->valueint = (int)number; + } + + item->type = cJSON_Number; + + input_buffer->offset += (size_t)(after_end - number_c_string); + return true; +} + +/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ +CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) +{ + if (number >= INT_MAX) + { + object->valueint = INT_MAX; + } + else if (number <= (double)INT_MIN) + { + object->valueint = INT_MIN; + } + else + { + object->valueint = (int)number; + } + + return object->valuedouble = number; +} + +CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring) +{ + char *copy = NULL; + /* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */ + if (!(object->type & cJSON_String) || (object->type & cJSON_IsReference)) + { + return NULL; + } + if (strlen(valuestring) <= strlen(object->valuestring)) + { + strcpy(object->valuestring, valuestring); + return object->valuestring; + } + copy = (char*) cJSON_strdup((const unsigned char*)valuestring, &global_hooks); + if (copy == NULL) + { + return NULL; + } + if (object->valuestring != NULL) + { + cJSON_free(object->valuestring); + } + object->valuestring = copy; + + return copy; +} + +typedef struct +{ + unsigned char *buffer; + size_t length; + size_t offset; + size_t depth; /* current nesting depth (for formatted printing) */ + cJSON_bool noalloc; + cJSON_bool format; /* is this print a formatted print */ + internal_hooks hooks; +} printbuffer; + +/* realloc printbuffer if necessary to have at least "needed" bytes more */ +static unsigned char* ensure(printbuffer * const p, size_t needed) +{ + unsigned char *newbuffer = NULL; + size_t newsize = 0; + + if ((p == NULL) || (p->buffer == NULL)) + { + return NULL; + } + + if ((p->length > 0) && (p->offset >= p->length)) + { + /* make sure that offset is valid */ + return NULL; + } + + if (needed > INT_MAX) + { + /* sizes bigger than INT_MAX are currently not supported */ + return NULL; + } + + needed += p->offset + 1; + if (needed <= p->length) + { + return p->buffer + p->offset; + } + + if (p->noalloc) { + return NULL; + } + + /* calculate new buffer size */ + if (needed > (INT_MAX / 2)) + { + /* overflow of int, use INT_MAX if possible */ + if (needed <= INT_MAX) + { + newsize = INT_MAX; + } + else + { + return NULL; + } + } + else + { + newsize = needed * 2; + } + + if (p->hooks.reallocate != NULL) + { + /* reallocate with realloc if available */ + newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize); + if (newbuffer == NULL) + { + p->hooks.deallocate(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + } + else + { + /* otherwise reallocate manually */ + newbuffer = (unsigned char*)p->hooks.allocate(newsize); + if (!newbuffer) + { + p->hooks.deallocate(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + + memcpy(newbuffer, p->buffer, p->offset + 1); + p->hooks.deallocate(p->buffer); + } + p->length = newsize; + p->buffer = newbuffer; + + return newbuffer + p->offset; +} + +/* calculate the new length of the string in a printbuffer and update the offset */ +static void update_offset(printbuffer * const buffer) +{ + const unsigned char *buffer_pointer = NULL; + if ((buffer == NULL) || (buffer->buffer == NULL)) + { + return; + } + buffer_pointer = buffer->buffer + buffer->offset; + + buffer->offset += strlen((const char*)buffer_pointer); +} + +/* securely comparison of floating-point variables */ +static cJSON_bool compare_double(double a, double b) +{ + double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b); + return (fabs(a - b) <= maxVal * DBL_EPSILON); +} + +/* Render the number nicely from the given item into a string. */ +static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + double d = item->valuedouble; + int length = 0; + size_t i = 0; + unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */ + unsigned char decimal_point = get_decimal_point(); + double test = 0.0; + + if (output_buffer == NULL) + { + return false; + } + + /* This checks for NaN and Infinity */ + if (isnan(d) || isinf(d)) + { + length = sprintf((char*)number_buffer, "null"); + } + else + { + /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ + length = sprintf((char*)number_buffer, "%1.15g", d); + + /* Check whether the original double can be recovered */ + if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d)) + { + /* If not, print with 17 decimal places of precision */ + length = sprintf((char*)number_buffer, "%1.17g", d); + } + } + + /* sprintf failed or buffer overrun occurred */ + if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) + { + return false; + } + + /* reserve appropriate space in the output */ + output_pointer = ensure(output_buffer, (size_t)length + sizeof("")); + if (output_pointer == NULL) + { + return false; + } + + /* copy the printed number to the output and replace locale + * dependent decimal point with '.' */ + for (i = 0; i < ((size_t)length); i++) + { + if (number_buffer[i] == decimal_point) + { + output_pointer[i] = '.'; + continue; + } + + output_pointer[i] = number_buffer[i]; + } + output_pointer[i] = '\0'; + + output_buffer->offset += (size_t)length; + + return true; +} + +/* parse 4 digit hexadecimal number */ +static unsigned parse_hex4(const unsigned char * const input) +{ + unsigned int h = 0; + size_t i = 0; + + for (i = 0; i < 4; i++) + { + /* parse digit */ + if ((input[i] >= '0') && (input[i] <= '9')) + { + h += (unsigned int) input[i] - '0'; + } + else if ((input[i] >= 'A') && (input[i] <= 'F')) + { + h += (unsigned int) 10 + input[i] - 'A'; + } + else if ((input[i] >= 'a') && (input[i] <= 'f')) + { + h += (unsigned int) 10 + input[i] - 'a'; + } + else /* invalid */ + { + return 0; + } + + if (i < 3) + { + /* shift left to make place for the next nibble */ + h = h << 4; + } + } + + return h; +} + +/* converts a UTF-16 literal to UTF-8 + * A literal can be one or two sequences of the form \uXXXX */ +static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer) +{ + long unsigned int codepoint = 0; + unsigned int first_code = 0; + const unsigned char *first_sequence = input_pointer; + unsigned char utf8_length = 0; + unsigned char utf8_position = 0; + unsigned char sequence_length = 0; + unsigned char first_byte_mark = 0; + + if ((input_end - first_sequence) < 6) + { + /* input ends unexpectedly */ + goto fail; + } + + /* get the first utf16 sequence */ + first_code = parse_hex4(first_sequence + 2); + + /* check that the code is valid */ + if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) + { + goto fail; + } + + /* UTF16 surrogate pair */ + if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) + { + const unsigned char *second_sequence = first_sequence + 6; + unsigned int second_code = 0; + sequence_length = 12; /* \uXXXX\uXXXX */ + + if ((input_end - second_sequence) < 6) + { + /* input ends unexpectedly */ + goto fail; + } + + if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) + { + /* missing second half of the surrogate pair */ + goto fail; + } + + /* get the second utf16 sequence */ + second_code = parse_hex4(second_sequence + 2); + /* check that the code is valid */ + if ((second_code < 0xDC00) || (second_code > 0xDFFF)) + { + /* invalid second half of the surrogate pair */ + goto fail; + } + + + /* calculate the unicode codepoint from the surrogate pair */ + codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF)); + } + else + { + sequence_length = 6; /* \uXXXX */ + codepoint = first_code; + } + + /* encode as UTF-8 + * takes at maximum 4 bytes to encode: + * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ + if (codepoint < 0x80) + { + /* normal ascii, encoding 0xxxxxxx */ + utf8_length = 1; + } + else if (codepoint < 0x800) + { + /* two bytes, encoding 110xxxxx 10xxxxxx */ + utf8_length = 2; + first_byte_mark = 0xC0; /* 11000000 */ + } + else if (codepoint < 0x10000) + { + /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ + utf8_length = 3; + first_byte_mark = 0xE0; /* 11100000 */ + } + else if (codepoint <= 0x10FFFF) + { + /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ + utf8_length = 4; + first_byte_mark = 0xF0; /* 11110000 */ + } + else + { + /* invalid unicode codepoint */ + goto fail; + } + + /* encode as utf8 */ + for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) + { + /* 10xxxxxx */ + (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF); + codepoint >>= 6; + } + /* encode first byte */ + if (utf8_length > 1) + { + (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF); + } + else + { + (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F); + } + + *output_pointer += utf8_length; + + return sequence_length; + +fail: + return 0; +} + +/* Parse the input text into an unescaped cinput, and populate item. */ +static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer) +{ + const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; + const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; + unsigned char *output_pointer = NULL; + unsigned char *output = NULL; + + /* not a string */ + if (buffer_at_offset(input_buffer)[0] != '\"') + { + goto fail; + } + + { + /* calculate approximate size of the output (overestimate) */ + size_t allocation_length = 0; + size_t skipped_bytes = 0; + while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) + { + /* is escape sequence */ + if (input_end[0] == '\\') + { + if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) + { + /* prevent buffer overflow when last input character is a backslash */ + goto fail; + } + skipped_bytes++; + input_end++; + } + input_end++; + } + if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) + { + goto fail; /* string ended unexpectedly */ + } + + /* This is at most how much we need for the output */ + allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes; + output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof("")); + if (output == NULL) + { + goto fail; /* allocation failure */ + } + } + + output_pointer = output; + /* loop through the string literal */ + while (input_pointer < input_end) + { + if (*input_pointer != '\\') + { + *output_pointer++ = *input_pointer++; + } + /* escape sequence */ + else + { + unsigned char sequence_length = 2; + if ((input_end - input_pointer) < 1) + { + goto fail; + } + + switch (input_pointer[1]) + { + case 'b': + *output_pointer++ = '\b'; + break; + case 'f': + *output_pointer++ = '\f'; + break; + case 'n': + *output_pointer++ = '\n'; + break; + case 'r': + *output_pointer++ = '\r'; + break; + case 't': + *output_pointer++ = '\t'; + break; + case '\"': + case '\\': + case '/': + *output_pointer++ = input_pointer[1]; + break; + + /* UTF-16 literal */ + case 'u': + sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); + if (sequence_length == 0) + { + /* failed to convert UTF16-literal to UTF-8 */ + goto fail; + } + break; + + default: + goto fail; + } + input_pointer += sequence_length; + } + } + + /* zero terminate the output */ + *output_pointer = '\0'; + + item->type = cJSON_String; + item->valuestring = (char*)output; + + input_buffer->offset = (size_t) (input_end - input_buffer->content); + input_buffer->offset++; + + return true; + +fail: + if (output != NULL) + { + input_buffer->hooks.deallocate(output); + } + + if (input_pointer != NULL) + { + input_buffer->offset = (size_t)(input_pointer - input_buffer->content); + } + + return false; +} + +/* Render the cstring provided to an escaped version that can be printed. */ +static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer) +{ + const unsigned char *input_pointer = NULL; + unsigned char *output = NULL; + unsigned char *output_pointer = NULL; + size_t output_length = 0; + /* numbers of additional characters needed for escaping */ + size_t escape_characters = 0; + + if (output_buffer == NULL) + { + return false; + } + + /* empty string */ + if (input == NULL) + { + output = ensure(output_buffer, sizeof("\"\"")); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "\"\""); + + return true; + } + + /* set "flag" to 1 if something needs to be escaped */ + for (input_pointer = input; *input_pointer; input_pointer++) + { + switch (*input_pointer) + { + case '\"': + case '\\': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + /* one character escape sequence */ + escape_characters++; + break; + default: + if (*input_pointer < 32) + { + /* UTF-16 escape sequence uXXXX */ + escape_characters += 5; + } + break; + } + } + output_length = (size_t)(input_pointer - input) + escape_characters; + + output = ensure(output_buffer, output_length + sizeof("\"\"")); + if (output == NULL) + { + return false; + } + + /* no characters have to be escaped */ + if (escape_characters == 0) + { + output[0] = '\"'; + memcpy(output + 1, input, output_length); + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; + } + + output[0] = '\"'; + output_pointer = output + 1; + /* copy the string */ + for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) + { + if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) + { + /* normal character, copy */ + *output_pointer = *input_pointer; + } + else + { + /* character needs to be escaped */ + *output_pointer++ = '\\'; + switch (*input_pointer) + { + case '\\': + *output_pointer = '\\'; + break; + case '\"': + *output_pointer = '\"'; + break; + case '\b': + *output_pointer = 'b'; + break; + case '\f': + *output_pointer = 'f'; + break; + case '\n': + *output_pointer = 'n'; + break; + case '\r': + *output_pointer = 'r'; + break; + case '\t': + *output_pointer = 't'; + break; + default: + /* escape and print as unicode codepoint */ + sprintf((char*)output_pointer, "u%04x", *input_pointer); + output_pointer += 4; + break; + } + } + } + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; +} + +/* Invoke print_string_ptr (which is useful) on an item. */ +static cJSON_bool print_string(const cJSON * const item, printbuffer * const p) +{ + return print_string_ptr((unsigned char*)item->valuestring, p); +} + +/* Predeclare these prototypes. */ +static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer); +static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer); +static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer); + +/* Utility to jump whitespace and cr/lf */ +static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) +{ + if ((buffer == NULL) || (buffer->content == NULL)) + { + return NULL; + } + + if (cannot_access_at_index(buffer, 0)) + { + return buffer; + } + + while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) + { + buffer->offset++; + } + + if (buffer->offset == buffer->length) + { + buffer->offset--; + } + + return buffer; +} + +/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */ +static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) +{ + if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) + { + return NULL; + } + + if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) + { + buffer->offset += 3; + } + + return buffer; +} + +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) +{ + size_t buffer_length; + + if (NULL == value) + { + return NULL; + } + + /* Adding null character size due to require_null_terminated. */ + buffer_length = strlen(value) + sizeof(""); + + return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated); +} + +/* Parse an object - create a new root, and populate. */ +CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated) +{ + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + cJSON *item = NULL; + + /* reset error position */ + global_error.json = NULL; + global_error.position = 0; + + if (value == NULL || 0 == buffer_length) + { + goto fail; + } + + buffer.content = (const unsigned char*)value; + buffer.length = buffer_length; + buffer.offset = 0; + buffer.hooks = global_hooks; + + item = cJSON_New_Item(&global_hooks); + if (item == NULL) /* memory fail */ + { + goto fail; + } + + if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))) + { + /* parse failure. ep is set. */ + goto fail; + } + + /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ + if (require_null_terminated) + { + buffer_skip_whitespace(&buffer); + if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') + { + goto fail; + } + } + if (return_parse_end) + { + *return_parse_end = (const char*)buffer_at_offset(&buffer); + } + + return item; + +fail: + if (item != NULL) + { + cJSON_Delete(item); + } + + if (value != NULL) + { + error local_error; + local_error.json = (const unsigned char*)value; + local_error.position = 0; + + if (buffer.offset < buffer.length) + { + local_error.position = buffer.offset; + } + else if (buffer.length > 0) + { + local_error.position = buffer.length - 1; + } + + if (return_parse_end != NULL) + { + *return_parse_end = (const char*)local_error.json + local_error.position; + } + + global_error = local_error; + } + + return NULL; +} + +/* Default options for cJSON_Parse */ +CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) +{ + return cJSON_ParseWithOpts(value, 0, 0); +} + +CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length) +{ + return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0); +} + +#define cjson_min(a, b) (((a) < (b)) ? (a) : (b)) + +static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks) +{ + static const size_t default_buffer_size = 256; + printbuffer buffer[1]; + unsigned char *printed = NULL; + + memset(buffer, 0, sizeof(buffer)); + + /* create buffer */ + buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size); + buffer->length = default_buffer_size; + buffer->format = format; + buffer->hooks = *hooks; + if (buffer->buffer == NULL) + { + goto fail; + } + + /* print the value */ + if (!print_value(item, buffer)) + { + goto fail; + } + update_offset(buffer); + + /* check if reallocate is available */ + if (hooks->reallocate != NULL) + { + printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1); + if (printed == NULL) { + goto fail; + } + buffer->buffer = NULL; + } + else /* otherwise copy the JSON over to a new buffer */ + { + printed = (unsigned char*) hooks->allocate(buffer->offset + 1); + if (printed == NULL) + { + goto fail; + } + memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1)); + printed[buffer->offset] = '\0'; /* just to be sure */ + + /* free the buffer */ + hooks->deallocate(buffer->buffer); + } + + return printed; + +fail: + if (buffer->buffer != NULL) + { + hooks->deallocate(buffer->buffer); + } + + if (printed != NULL) + { + hooks->deallocate(printed); + } + + return NULL; +} + +/* Render a cJSON item/entity/structure to text. */ +CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) +{ + return (char*)print(item, true, &global_hooks); +} + +CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) +{ + return (char*)print(item, false, &global_hooks); +} + +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) +{ + printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + + if (prebuffer < 0) + { + return NULL; + } + + p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer); + if (!p.buffer) + { + return NULL; + } + + p.length = (size_t)prebuffer; + p.offset = 0; + p.noalloc = false; + p.format = fmt; + p.hooks = global_hooks; + + if (!print_value(item, &p)) + { + global_hooks.deallocate(p.buffer); + return NULL; + } + + return (char*)p.buffer; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) +{ + printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + + if ((length < 0) || (buffer == NULL)) + { + return false; + } + + p.buffer = (unsigned char*)buffer; + p.length = (size_t)length; + p.offset = 0; + p.noalloc = true; + p.format = format; + p.hooks = global_hooks; + + return print_value(item, &p); +} + +/* Parser core - when encountering text, process appropriately. */ +static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer) +{ + if ((input_buffer == NULL) || (input_buffer->content == NULL)) + { + return false; /* no input */ + } + + /* parse the different types of values */ + /* null */ + if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0)) + { + item->type = cJSON_NULL; + input_buffer->offset += 4; + return true; + } + /* false */ + if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0)) + { + item->type = cJSON_False; + input_buffer->offset += 5; + return true; + } + /* true */ + if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0)) + { + item->type = cJSON_True; + item->valueint = 1; + input_buffer->offset += 4; + return true; + } + /* string */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) + { + return parse_string(item, input_buffer); + } + /* number */ + if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) + { + return parse_number(item, input_buffer); + } + /* array */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) + { + return parse_array(item, input_buffer); + } + /* object */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) + { + return parse_object(item, input_buffer); + } + + return false; +} + +/* Render a value to text. */ +static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output = NULL; + + if ((item == NULL) || (output_buffer == NULL)) + { + return false; + } + + switch ((item->type) & 0xFF) + { + case cJSON_NULL: + output = ensure(output_buffer, 5); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "null"); + return true; + + case cJSON_False: + output = ensure(output_buffer, 6); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "false"); + return true; + + case cJSON_True: + output = ensure(output_buffer, 5); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "true"); + return true; + + case cJSON_Number: + return print_number(item, output_buffer); + + case cJSON_Raw: + { + size_t raw_length = 0; + if (item->valuestring == NULL) + { + return false; + } + + raw_length = strlen(item->valuestring) + sizeof(""); + output = ensure(output_buffer, raw_length); + if (output == NULL) + { + return false; + } + memcpy(output, item->valuestring, raw_length); + return true; + } + + case cJSON_String: + return print_string(item, output_buffer); + + case cJSON_Array: + return print_array(item, output_buffer); + + case cJSON_Object: + return print_object(item, output_buffer); + + default: + return false; + } +} + +/* Build an array from input text. */ +static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer) +{ + cJSON *head = NULL; /* head of the linked list */ + cJSON *current_item = NULL; + + if (input_buffer->depth >= CJSON_NESTING_LIMIT) + { + return false; /* to deeply nested */ + } + input_buffer->depth++; + + if (buffer_at_offset(input_buffer)[0] != '[') + { + /* not an array */ + goto fail; + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) + { + /* empty array */ + goto success; + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) + { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do + { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + if (new_item == NULL) + { + goto fail; /* allocation failure */ + } + + /* attach next item to list */ + if (head == NULL) + { + /* start the linked list */ + current_item = head = new_item; + } + else + { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse next value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_value(current_item, input_buffer)) + { + goto fail; /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + } + while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') + { + goto fail; /* expected end of array */ + } + +success: + input_buffer->depth--; + + if (head != NULL) { + head->prev = current_item; + } + + item->type = cJSON_Array; + item->child = head; + + input_buffer->offset++; + + return true; + +fail: + if (head != NULL) + { + cJSON_Delete(head); + } + + return false; +} + +/* Render an array to text */ +static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + size_t length = 0; + cJSON *current_element = item->child; + + if (output_buffer == NULL) + { + return false; + } + + /* Compose the output array. */ + /* opening square bracket */ + output_pointer = ensure(output_buffer, 1); + if (output_pointer == NULL) + { + return false; + } + + *output_pointer = '['; + output_buffer->offset++; + output_buffer->depth++; + + while (current_element != NULL) + { + if (!print_value(current_element, output_buffer)) + { + return false; + } + update_offset(output_buffer); + if (current_element->next) + { + length = (size_t) (output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ','; + if(output_buffer->format) + { + *output_pointer++ = ' '; + } + *output_pointer = '\0'; + output_buffer->offset += length; + } + current_element = current_element->next; + } + + output_pointer = ensure(output_buffer, 2); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ']'; + *output_pointer = '\0'; + output_buffer->depth--; + + return true; +} + +/* Build an object from the text. */ +static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer) +{ + cJSON *head = NULL; /* linked list head */ + cJSON *current_item = NULL; + + if (input_buffer->depth >= CJSON_NESTING_LIMIT) + { + return false; /* to deeply nested */ + } + input_buffer->depth++; + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) + { + goto fail; /* not an object */ + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) + { + goto success; /* empty object */ + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) + { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do + { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + if (new_item == NULL) + { + goto fail; /* allocation failure */ + } + + /* attach next item to list */ + if (head == NULL) + { + /* start the linked list */ + current_item = head = new_item; + } + else + { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse the name of the child */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_string(current_item, input_buffer)) + { + goto fail; /* failed to parse name */ + } + buffer_skip_whitespace(input_buffer); + + /* swap valuestring and string, because we parsed the name */ + current_item->string = current_item->valuestring; + current_item->valuestring = NULL; + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) + { + goto fail; /* invalid object */ + } + + /* parse the value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_value(current_item, input_buffer)) + { + goto fail; /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + } + while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) + { + goto fail; /* expected end of object */ + } + +success: + input_buffer->depth--; + + if (head != NULL) { + head->prev = current_item; + } + + item->type = cJSON_Object; + item->child = head; + + input_buffer->offset++; + return true; + +fail: + if (head != NULL) + { + cJSON_Delete(head); + } + + return false; +} + +/* Render an object to text. */ +static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + size_t length = 0; + cJSON *current_item = item->child; + + if (output_buffer == NULL) + { + return false; + } + + /* Compose the output: */ + length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */ + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + + *output_pointer++ = '{'; + output_buffer->depth++; + if (output_buffer->format) + { + *output_pointer++ = '\n'; + } + output_buffer->offset += length; + + while (current_item) + { + if (output_buffer->format) + { + size_t i; + output_pointer = ensure(output_buffer, output_buffer->depth); + if (output_pointer == NULL) + { + return false; + } + for (i = 0; i < output_buffer->depth; i++) + { + *output_pointer++ = '\t'; + } + output_buffer->offset += output_buffer->depth; + } + + /* print key */ + if (!print_string_ptr((unsigned char*)current_item->string, output_buffer)) + { + return false; + } + update_offset(output_buffer); + + length = (size_t) (output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ':'; + if (output_buffer->format) + { + *output_pointer++ = '\t'; + } + output_buffer->offset += length; + + /* print value */ + if (!print_value(current_item, output_buffer)) + { + return false; + } + update_offset(output_buffer); + + /* print comma if not last */ + length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0)); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + if (current_item->next) + { + *output_pointer++ = ','; + } + + if (output_buffer->format) + { + *output_pointer++ = '\n'; + } + *output_pointer = '\0'; + output_buffer->offset += length; + + current_item = current_item->next; + } + + output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2); + if (output_pointer == NULL) + { + return false; + } + if (output_buffer->format) + { + size_t i; + for (i = 0; i < (output_buffer->depth - 1); i++) + { + *output_pointer++ = '\t'; + } + } + *output_pointer++ = '}'; + *output_pointer = '\0'; + output_buffer->depth--; + + return true; +} + +/* Get Array size/item / object item. */ +CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) +{ + cJSON *child = NULL; + size_t size = 0; + + if (array == NULL) + { + return 0; + } + + child = array->child; + + while(child != NULL) + { + size++; + child = child->next; + } + + /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ + + return (int)size; +} + +static cJSON* get_array_item(const cJSON *array, size_t index) +{ + cJSON *current_child = NULL; + + if (array == NULL) + { + return NULL; + } + + current_child = array->child; + while ((current_child != NULL) && (index > 0)) + { + index--; + current_child = current_child->next; + } + + return current_child; +} + +CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index) +{ + if (index < 0) + { + return NULL; + } + + return get_array_item(array, (size_t)index); +} + +static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive) +{ + cJSON *current_element = NULL; + + if ((object == NULL) || (name == NULL)) + { + return NULL; + } + + current_element = object->child; + if (case_sensitive) + { + while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0)) + { + current_element = current_element->next; + } + } + else + { + while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0)) + { + current_element = current_element->next; + } + } + + if ((current_element == NULL) || (current_element->string == NULL)) { + return NULL; + } + + return current_element; +} + +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string) +{ + return get_object_item(object, string, false); +} + +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) +{ + return get_object_item(object, string, true); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string) +{ + return cJSON_GetObjectItem(object, string) ? 1 : 0; +} + +/* Utility for array list handling. */ +static void suffix_object(cJSON *prev, cJSON *item) +{ + prev->next = item; + item->prev = prev; +} + +/* Utility for handling references. */ +static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks) +{ + cJSON *reference = NULL; + if (item == NULL) + { + return NULL; + } + + reference = cJSON_New_Item(hooks); + if (reference == NULL) + { + return NULL; + } + + memcpy(reference, item, sizeof(cJSON)); + reference->string = NULL; + reference->type |= cJSON_IsReference; + reference->next = reference->prev = NULL; + return reference; +} + +static cJSON_bool add_item_to_array(cJSON *array, cJSON *item) +{ + cJSON *child = NULL; + + if ((item == NULL) || (array == NULL) || (array == item)) + { + return false; + } + + child = array->child; + /* + * To find the last item in array quickly, we use prev in array + */ + if (child == NULL) + { + /* list is empty, start new one */ + array->child = item; + item->prev = item; + item->next = NULL; + } + else + { + /* append to the end */ + if (child->prev) + { + suffix_object(child->prev, item); + array->child->prev = item; + } + } + + return true; +} + +/* Add item to array/object. */ +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item) +{ + return add_item_to_array(array, item); +} + +#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) + #pragma GCC diagnostic push +#endif +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif +/* helper function to cast away const */ +static void* cast_away_const(const void* string) +{ + return (void*)string; +} +#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) + #pragma GCC diagnostic pop +#endif + + +static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key) +{ + char *new_key = NULL; + int new_type = cJSON_Invalid; + + if ((object == NULL) || (string == NULL) || (item == NULL) || (object == item)) + { + return false; + } + + if (constant_key) + { + new_key = (char*)cast_away_const(string); + new_type = item->type | cJSON_StringIsConst; + } + else + { + new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks); + if (new_key == NULL) + { + return false; + } + + new_type = item->type & ~cJSON_StringIsConst; + } + + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) + { + hooks->deallocate(item->string); + } + + item->string = new_key; + item->type = new_type; + + return add_item_to_array(object, item); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) +{ + return add_item_to_object(object, string, item, &global_hooks, false); +} + +/* Add an item to an object with constant string as key */ +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) +{ + return add_item_to_object(object, string, item, &global_hooks, true); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) +{ + if (array == NULL) + { + return false; + } + + return add_item_to_array(array, create_reference(item, &global_hooks)); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) +{ + if ((object == NULL) || (string == NULL)) + { + return false; + } + + return add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false); +} + +CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name) +{ + cJSON *null = cJSON_CreateNull(); + if (add_item_to_object(object, name, null, &global_hooks, false)) + { + return null; + } + + cJSON_Delete(null); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name) +{ + cJSON *true_item = cJSON_CreateTrue(); + if (add_item_to_object(object, name, true_item, &global_hooks, false)) + { + return true_item; + } + + cJSON_Delete(true_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name) +{ + cJSON *false_item = cJSON_CreateFalse(); + if (add_item_to_object(object, name, false_item, &global_hooks, false)) + { + return false_item; + } + + cJSON_Delete(false_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean) +{ + cJSON *bool_item = cJSON_CreateBool(boolean); + if (add_item_to_object(object, name, bool_item, &global_hooks, false)) + { + return bool_item; + } + + cJSON_Delete(bool_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number) +{ + cJSON *number_item = cJSON_CreateNumber(number); + if (add_item_to_object(object, name, number_item, &global_hooks, false)) + { + return number_item; + } + + cJSON_Delete(number_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string) +{ + cJSON *string_item = cJSON_CreateString(string); + if (add_item_to_object(object, name, string_item, &global_hooks, false)) + { + return string_item; + } + + cJSON_Delete(string_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw) +{ + cJSON *raw_item = cJSON_CreateRaw(raw); + if (add_item_to_object(object, name, raw_item, &global_hooks, false)) + { + return raw_item; + } + + cJSON_Delete(raw_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name) +{ + cJSON *object_item = cJSON_CreateObject(); + if (add_item_to_object(object, name, object_item, &global_hooks, false)) + { + return object_item; + } + + cJSON_Delete(object_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name) +{ + cJSON *array = cJSON_CreateArray(); + if (add_item_to_object(object, name, array, &global_hooks, false)) + { + return array; + } + + cJSON_Delete(array); + return NULL; +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) +{ + if ((parent == NULL) || (item == NULL)) + { + return NULL; + } + + if (item != parent->child) + { + /* not the first element */ + item->prev->next = item->next; + } + if (item->next != NULL) + { + /* not the last element */ + item->next->prev = item->prev; + } + + if (item == parent->child) + { + /* first element */ + parent->child = item->next; + } + else if (item->next == NULL) + { + /* last element */ + parent->child->prev = item->prev; + } + + /* make sure the detached item doesn't point anywhere anymore */ + item->prev = NULL; + item->next = NULL; + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which) +{ + if (which < 0) + { + return NULL; + } + + return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which)); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) +{ + cJSON_Delete(cJSON_DetachItemFromArray(array, which)); +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string) +{ + cJSON *to_detach = cJSON_GetObjectItem(object, string); + + return cJSON_DetachItemViaPointer(object, to_detach); +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string) +{ + cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string); + + return cJSON_DetachItemViaPointer(object, to_detach); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) +{ + cJSON_Delete(cJSON_DetachItemFromObject(object, string)); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string) +{ + cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string)); +} + +/* Replace array/object items with new ones. */ +CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) +{ + cJSON *after_inserted = NULL; + + if (which < 0) + { + return false; + } + + after_inserted = get_array_item(array, (size_t)which); + if (after_inserted == NULL) + { + return add_item_to_array(array, newitem); + } + + newitem->next = after_inserted; + newitem->prev = after_inserted->prev; + after_inserted->prev = newitem; + if (after_inserted == array->child) + { + array->child = newitem; + } + else + { + newitem->prev->next = newitem; + } + return true; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement) +{ + if ((parent == NULL) || (replacement == NULL) || (item == NULL)) + { + return false; + } + + if (replacement == item) + { + return true; + } + + replacement->next = item->next; + replacement->prev = item->prev; + + if (replacement->next != NULL) + { + replacement->next->prev = replacement; + } + if (parent->child == item) + { + if (parent->child->prev == parent->child) + { + replacement->prev = replacement; + } + parent->child = replacement; + } + else + { /* + * To find the last item in array quickly, we use prev in array. + * We can't modify the last item's next pointer where this item was the parent's child + */ + if (replacement->prev != NULL) + { + replacement->prev->next = replacement; + } + if (replacement->next == NULL) + { + parent->child->prev = replacement; + } + } + + item->next = NULL; + item->prev = NULL; + cJSON_Delete(item); + + return true; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) +{ + if (which < 0) + { + return false; + } + + return cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem); +} + +static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive) +{ + if ((replacement == NULL) || (string == NULL)) + { + return false; + } + + /* replace the name in the replacement */ + if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL)) + { + cJSON_free(replacement->string); + } + replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); + replacement->type &= ~cJSON_StringIsConst; + + return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) +{ + return replace_item_in_object(object, string, newitem, false); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) +{ + return replace_item_in_object(object, string, newitem, true); +} + +/* Create basic types: */ +CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_NULL; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_True; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_False; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = boolean ? cJSON_True : cJSON_False; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_Number; + item->valuedouble = num; + + /* use saturation in case of overflow */ + if (num >= INT_MAX) + { + item->valueint = INT_MAX; + } + else if (num <= (double)INT_MIN) + { + item->valueint = INT_MIN; + } + else + { + item->valueint = (int)num; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_String; + item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); + if(!item->valuestring) + { + cJSON_Delete(item); + return NULL; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) + { + item->type = cJSON_String | cJSON_IsReference; + item->valuestring = (char*)cast_away_const(string); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) { + item->type = cJSON_Object | cJSON_IsReference; + item->child = (cJSON*)cast_away_const(child); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) { + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) { + item->type = cJSON_Array | cJSON_IsReference; + item->child = (cJSON*)cast_away_const(child); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_Raw; + item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks); + if(!item->valuestring) + { + cJSON_Delete(item); + return NULL; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type=cJSON_Array; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item) + { + item->type = cJSON_Object; + } + + return item; +} + +/* Create Arrays: */ +CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for(i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber(numbers[i]); + if (!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + if (a && a->child) { + a->child->prev = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for(i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber((double)numbers[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + if (a && a->child) { + a->child->prev = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for(i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber(numbers[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + if (a && a->child) { + a->child->prev = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (strings == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for (i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateString(strings[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p,n); + } + p = n; + } + + if (a && a->child) { + a->child->prev = n; + } + + return a; +} + +/* Duplication */ +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) +{ + cJSON *newitem = NULL; + cJSON *child = NULL; + cJSON *next = NULL; + cJSON *newchild = NULL; + + /* Bail on bad ptr */ + if (!item) + { + goto fail; + } + /* Create new item */ + newitem = cJSON_New_Item(&global_hooks); + if (!newitem) + { + goto fail; + } + /* Copy over all vars */ + newitem->type = item->type & (~cJSON_IsReference); + newitem->valueint = item->valueint; + newitem->valuedouble = item->valuedouble; + if (item->valuestring) + { + newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks); + if (!newitem->valuestring) + { + goto fail; + } + } + if (item->string) + { + newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks); + if (!newitem->string) + { + goto fail; + } + } + /* If non-recursive, then we're done! */ + if (!recurse) + { + return newitem; + } + /* Walk the ->next chain for the child. */ + child = item->child; + while (child != NULL) + { + newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ + if (!newchild) + { + goto fail; + } + if (next != NULL) + { + /* If newitem->child already set, then crosswire ->prev and ->next and move on */ + next->next = newchild; + newchild->prev = next; + next = newchild; + } + else + { + /* Set newitem->child and move to it */ + newitem->child = newchild; + next = newchild; + } + child = child->next; + } + if (newitem && newitem->child) + { + newitem->child->prev = newchild; + } + + return newitem; + +fail: + if (newitem != NULL) + { + cJSON_Delete(newitem); + } + + return NULL; +} + +static void skip_oneline_comment(char **input) +{ + *input += static_strlen("//"); + + for (; (*input)[0] != '\0'; ++(*input)) + { + if ((*input)[0] == '\n') { + *input += static_strlen("\n"); + return; + } + } +} + +static void skip_multiline_comment(char **input) +{ + *input += static_strlen("/*"); + + for (; (*input)[0] != '\0'; ++(*input)) + { + if (((*input)[0] == '*') && ((*input)[1] == '/')) + { + *input += static_strlen("*/"); + return; + } + } +} + +static void minify_string(char **input, char **output) { + (*output)[0] = (*input)[0]; + *input += static_strlen("\""); + *output += static_strlen("\""); + + + for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) { + (*output)[0] = (*input)[0]; + + if ((*input)[0] == '\"') { + (*output)[0] = '\"'; + *input += static_strlen("\""); + *output += static_strlen("\""); + return; + } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) { + (*output)[1] = (*input)[1]; + *input += static_strlen("\""); + *output += static_strlen("\""); + } + } +} + +CJSON_PUBLIC(void) cJSON_Minify(char *json) +{ + char *into = json; + + if (json == NULL) + { + return; + } + + while (json[0] != '\0') + { + switch (json[0]) + { + case ' ': + case '\t': + case '\r': + case '\n': + json++; + break; + + case '/': + if (json[1] == '/') + { + skip_oneline_comment(&json); + } + else if (json[1] == '*') + { + skip_multiline_comment(&json); + } else { + json++; + } + break; + + case '\"': + minify_string(&json, (char**)&into); + break; + + default: + into[0] = json[0]; + json++; + into++; + } + } + + /* and null-terminate. */ + *into = '\0'; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Invalid; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_False; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xff) == cJSON_True; +} + + +CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & (cJSON_True | cJSON_False)) != 0; +} +CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_NULL; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Number; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_String; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Array; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Object; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Raw; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive) +{ + if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) + { + return false; + } + + /* check if type is valid */ + switch (a->type & 0xFF) + { + case cJSON_False: + case cJSON_True: + case cJSON_NULL: + case cJSON_Number: + case cJSON_String: + case cJSON_Raw: + case cJSON_Array: + case cJSON_Object: + break; + + default: + return false; + } + + /* identical objects are equal */ + if (a == b) + { + return true; + } + + switch (a->type & 0xFF) + { + /* in these cases and equal type is enough */ + case cJSON_False: + case cJSON_True: + case cJSON_NULL: + return true; + + case cJSON_Number: + if (compare_double(a->valuedouble, b->valuedouble)) + { + return true; + } + return false; + + case cJSON_String: + case cJSON_Raw: + if ((a->valuestring == NULL) || (b->valuestring == NULL)) + { + return false; + } + if (strcmp(a->valuestring, b->valuestring) == 0) + { + return true; + } + + return false; + + case cJSON_Array: + { + cJSON *a_element = a->child; + cJSON *b_element = b->child; + + for (; (a_element != NULL) && (b_element != NULL);) + { + if (!cJSON_Compare(a_element, b_element, case_sensitive)) + { + return false; + } + + a_element = a_element->next; + b_element = b_element->next; + } + + /* one of the arrays is longer than the other */ + if (a_element != b_element) { + return false; + } + + return true; + } + + case cJSON_Object: + { + cJSON *a_element = NULL; + cJSON *b_element = NULL; + cJSON_ArrayForEach(a_element, a) + { + /* TODO This has O(n^2) runtime, which is horrible! */ + b_element = get_object_item(b, a_element->string, case_sensitive); + if (b_element == NULL) + { + return false; + } + + if (!cJSON_Compare(a_element, b_element, case_sensitive)) + { + return false; + } + } + + /* doing this twice, once on a and b to prevent true comparison if a subset of b + * TODO: Do this the proper way, this is just a fix for now */ + cJSON_ArrayForEach(b_element, b) + { + a_element = get_object_item(a, b_element->string, case_sensitive); + if (a_element == NULL) + { + return false; + } + + if (!cJSON_Compare(b_element, a_element, case_sensitive)) + { + return false; + } + } + + return true; + } + + default: + return false; + } +} + +CJSON_PUBLIC(void *) cJSON_malloc(size_t size) +{ + return global_hooks.allocate(size); +} + +CJSON_PUBLIC(void) cJSON_free(void *object) +{ + global_hooks.deallocate(object); +} diff --git a/APP_Framework/Applications/knowing_app/face_detect/cJSON.h b/APP_Framework/Applications/knowing_app/face_detect/cJSON.h new file mode 100644 index 00000000..e97e5f4c --- /dev/null +++ b/APP_Framework/Applications/knowing_app/face_detect/cJSON.h @@ -0,0 +1,293 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef cJSON__h +#define cJSON__h + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) +#define __WINDOWS__ +#endif + +#ifdef __WINDOWS__ + +/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options: + +CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols +CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) +CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol + +For *nix builds that support visibility attribute, you can define similar behavior by + +setting default visibility to hidden by adding +-fvisibility=hidden (for gcc) +or +-xldscope=hidden (for sun cc) +to CFLAGS + +then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does + +*/ + +#define CJSON_CDECL __cdecl +#define CJSON_STDCALL __stdcall + +/* export symbols by default, this is necessary for copy pasting the C and header file */ +#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_EXPORT_SYMBOLS +#endif + +#if defined(CJSON_HIDE_SYMBOLS) +#define CJSON_PUBLIC(type) type CJSON_STDCALL +#elif defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL +#elif defined(CJSON_IMPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL +#endif +#else /* !__WINDOWS__ */ +#define CJSON_CDECL +#define CJSON_STDCALL + +#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) +#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type +#else +#define CJSON_PUBLIC(type) type +#endif +#endif + +/* project version */ +#define CJSON_VERSION_MAJOR 1 +#define CJSON_VERSION_MINOR 7 +#define CJSON_VERSION_PATCH 14 + +#include + +/* cJSON Types: */ +#define cJSON_Invalid (0) +#define cJSON_False (1 << 0) +#define cJSON_True (1 << 1) +#define cJSON_NULL (1 << 2) +#define cJSON_Number (1 << 3) +#define cJSON_String (1 << 4) +#define cJSON_Array (1 << 5) +#define cJSON_Object (1 << 6) +#define cJSON_Raw (1 << 7) /* raw json */ + +#define cJSON_IsReference 256 +#define cJSON_StringIsConst 512 + +/* The cJSON structure: */ +typedef struct cJSON +{ + /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ + struct cJSON *next; + struct cJSON *prev; + /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ + struct cJSON *child; + + /* The type of the item, as above. */ + int type; + + /* The item's string, if type==cJSON_String and type == cJSON_Raw */ + char *valuestring; + /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ + int valueint; + /* The item's number, if type==cJSON_Number */ + double valuedouble; + + /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ + char *string; +} cJSON; + +typedef struct cJSON_Hooks +{ + /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */ + void *(CJSON_CDECL *malloc_fn)(size_t sz); + void (CJSON_CDECL *free_fn)(void *ptr); +} cJSON_Hooks; + +typedef int cJSON_bool; + +/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them. + * This is to prevent stack overflows. */ +#ifndef CJSON_NESTING_LIMIT +#define CJSON_NESTING_LIMIT 1000 +#endif + +/* returns the version of cJSON as a string */ +CJSON_PUBLIC(const char*) cJSON_Version(void); + +/* Supply malloc, realloc and free functions to cJSON */ +CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); + +/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ +/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ +CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); +CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length); +/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ +/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */ +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); +CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated); + +/* Render a cJSON entity to text for transfer/storage. */ +CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); +/* Render a cJSON entity to text for transfer/storage without any formatting. */ +CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); +/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); +/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ +/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); +/* Delete a cJSON entity and all subentities. */ +CJSON_PUBLIC(void) cJSON_Delete(cJSON *item); + +/* Returns the number of items in an array (or object). */ +CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); +/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */ +CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); +/* Get item "string" from object. Case insensitive. */ +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); +CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string); +/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ +CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); + +/* Check item type and return its value */ +CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item); +CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item); + +/* These functions check the type of an item */ +CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item); + +/* These calls create a cJSON item of the appropriate type. */ +CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); +CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); +CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); +/* raw json */ +CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); +CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); + +/* Create a string where valuestring references a string so + * it will not be freed by cJSON_Delete */ +CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); +/* Create an object/array that only references it's elements so + * they will not be freed by cJSON_Delete */ +CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); +CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); + +/* These utilities create an Array of count items. + * The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/ +CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count); + +/* Append item to the specified array/object. */ +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item); +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); +/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. + * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before + * writing to `item->string` */ +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); +/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); + +/* Remove/Detach items from Arrays/Objects. */ +CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); +CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); +CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); +CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); + +/* Update array items. */ +CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem); + +/* Duplicate a cJSON item */ +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); +/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will + * need to be released. With recurse!=0, it will duplicate any children connected to the item. + * The item->next and ->prev pointers are always zero on return from Duplicate. */ +/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal. + * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ +CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); + +/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings. + * The input pointer json cannot point to a read-only address area, such as a string constant, + * but should point to a readable and writable adress area. */ +CJSON_PUBLIC(void) cJSON_Minify(char *json); + +/* Helper functions for creating and adding items to an object at the same time. + * They return the added item or NULL on failure. */ +CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean); +CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number); +CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string); +CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw); +CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name); + +/* When assigning an integer value, it needs to be propagated to valuedouble too. */ +#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) +/* helper for the cJSON_SetNumberValue macro */ +CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); +#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) +/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */ +CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring); + +/* Macro for iterating over an array or object */ +#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) + +/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ +CJSON_PUBLIC(void *) cJSON_malloc(size_t size); +CJSON_PUBLIC(void) cJSON_free(void *object); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/APP_Framework/Applications/knowing_app/face_detect/detect.json b/APP_Framework/Applications/knowing_app/face_detect/detect.json new file mode 100644 index 00000000..f3d181ef --- /dev/null +++ b/APP_Framework/Applications/knowing_app/face_detect/detect.json @@ -0,0 +1,31 @@ +{ + "net_input_size": [ + 240, + 320 + ], + "net_output_shape": [ + 20, + 15, + 30 + ], + "sensor_output_size": [ + 240, + 320 + ], + "anchors": [ + 1.889, + 2.5245, + 2.9465, + 3.94056, + 3.99987, + 5.3658, + 5.155437, + 6.92275, + 6.718375, + 9.01025 + ], + "kmodel_path": "/kmodel/detect.kmodel", + "kmodel_size": 388776, + "obj_thresh": 0.7, + "nms_thresh": 0.3 +} \ No newline at end of file diff --git a/APP_Framework/Applications/knowing_app/face_detect/face_detect.c b/APP_Framework/Applications/knowing_app/face_detect/face_detect.c index bf84ba2f..702b43c6 100644 --- a/APP_Framework/Applications/knowing_app/face_detect/face_detect.c +++ b/APP_Framework/Applications/knowing_app/face_detect/face_detect.c @@ -1,118 +1,225 @@ #include -#include"region_layer.h" -#define SHOW_RGB_BUF_SIZE (320*240*2) -#define AI_KPU_RGB_BUF_SIZE (320*240*3) -#define KMODEL_SIZE (388776) //face model size -#define ANCHOR_NUM 5 -#define KPUIMAGEWIDTH (320) -#define KPUIMAGEHEIGHT (240) +#include "cJSON.h" +#include "region_layer.h" +#define ANCHOR_NUM 5 +#define STACK_SIZE (128 * 1024) +#define JSON_FILE_PATH "/kmodel/detect.json" +#define JSON_BUFFER_SIZE (4 * 1024) -static float anchor[ANCHOR_NUM * 2] = {1.889,2.5245, 2.9465,3.94056, 3.99987,5.3658, 5.155437,6.92275, 6.718375,9.01025}; +// params from json +float anchor[ANCHOR_NUM * 2] = {}; +int net_output_shape[3] = {}; +int net_input_size[2] = {}; +int sensor_output_size[2] = {}; +char kmodel_path[127] = ""; +int kmodel_size = 0; +float obj_thresh = 1.0; +float nms_thresh = 0.0; +// float anchor[ANCHOR_NUM * 2] = {1.889, 2.5245, 2.9465, 3.94056, 3.99987, 5.3658, 5.155437, 6.92275, 6.718375, 9.01025}; +// int net_output_shape[3] = {20, 15, 30}; +// int net_input_size[2] = {240, 320}; +// int sensor_output_size[2] = {240, 320}; +// char kmodel_path[127] = "/kmodel/detect.kmodel"; +// int kmodel_size = 388776; +// float obj_thresh = 0.7; +// float nms_thresh = 0.3; -#define THREAD_PRIORITY_FACE_D (11) -static pthread_t facetid = 0; -static void* thread_face_detcet_entry(void *parameter); +#define THREAD_PRIORITY_FACE_D (11) +static pthread_t facetid = 0; +static void *thread_face_detcet_entry(void *parameter); static int g_fd = 0; static int kmodel_fd = 0; -static int if_exit = 0; -static unsigned char * showbuffer = NULL ; -static unsigned char * kpurgbbuffer = NULL ; +static int if_exit = 0; +static unsigned char *showbuffer = NULL; +static unsigned char *kpurgbbuffer = NULL; static _ioctl_shoot_para shoot_para_t = {0}; -unsigned char * model_data = NULL; //kpu data load memory -unsigned char *model_data_align = NULL; +unsigned char *model_data = NULL; // kpu data load memory +unsigned char *model_data_align = NULL; kpu_model_context_t face_detect_task; static region_layer_t face_detect_rl; static obj_info_t face_detect_info; volatile uint32_t g_ai_done_flag; -static void ai_done(void *ctx) +static void ai_done(void *ctx) { g_ai_done_flag = 1; } + +static void param_parse() { - g_ai_done_flag = 1; -} + int fin; + char buffer[JSON_BUFFER_SIZE] = ""; + // char *buffer; + // if (NULL != (buffer = (char*)malloc(JSON_BUFFER_SIZE * sizeof(char)))) { + // memset(buffer, 0, JSON_BUFFER_SIZE * sizeof(char)); + // } else { + // printf("Json buffer malloc failed!"); + // exit(-1); + // } + int array_size; + cJSON *json_obj; + cJSON *json_item; + cJSON *json_array_item; + + fin = open(JSON_FILE_PATH, O_RDONLY); + if (!fin) { + printf("Error open file %s", JSON_FILE_PATH); + exit(-1); + } + read(fin, buffer, sizeof(buffer)); + close(fin); + // read json string + json_obj = cJSON_Parse(buffer); + // free(buffer); + char *json_print_str = cJSON_Print(json_obj); + printf("Json file content: \n%s\n", json_print_str); + cJSON_free(json_print_str); + // get anchors + json_item = cJSON_GetObjectItem(json_obj, "anchors"); + array_size = cJSON_GetArraySize(json_item); + if (ANCHOR_NUM * 2 != array_size) { + printf("Expect anchor size: %d, got %d in json file", ANCHOR_NUM * 2, array_size); + exit(-1); + } else { + printf("Got %d anchors from json file\n", ANCHOR_NUM); + } + for (int i = 0; i < ANCHOR_NUM * 2; i++) { + json_array_item = cJSON_GetArrayItem(json_item, i); + anchor[i] = json_array_item->valuedouble; + printf("%d: %f\n", i, anchor[i]); + } + // net_input_size + json_item = cJSON_GetObjectItem(json_obj, "net_input_size"); + array_size = cJSON_GetArraySize(json_item); + if (2 != array_size) { + printf("Expect net_input_size: %d, got %d in json file", 2, array_size); + exit(-1); + } else { + printf("Got %d net_input_size from json file\n", 2); + } + for (int i = 0; i < 2; i++) { + json_array_item = cJSON_GetArrayItem(json_item, i); + net_input_size[i] = json_array_item->valueint; + printf("%d: %d\n", i, net_input_size[i]); + } + // net_output_shape + json_item = cJSON_GetObjectItem(json_obj, "net_output_shape"); + array_size = cJSON_GetArraySize(json_item); + if (3 != array_size) { + printf("Expect net_output_shape: %d, got %d in json file", 3, array_size); + exit(-1); + } else { + printf("Got %d net_output_shape from json file\n", 3); + } + for (int i = 0; i < 3; i++) { + json_array_item = cJSON_GetArrayItem(json_item, i); + net_output_shape[i] = json_array_item->valueint; + printf("%d: %d\n", i, net_output_shape[i]); + } + // sensor_output_size + json_item = cJSON_GetObjectItem(json_obj, "sensor_output_size"); + array_size = cJSON_GetArraySize(json_item); + if (2 != array_size) { + printf("Expect sensor_output_size: %d, got %d in json file", 2, array_size); + exit(-1); + } else { + printf("Got %d sensor_output_size from json file\n", 2); + } + for (int i = 0; i < 2; i++) { + json_array_item = cJSON_GetArrayItem(json_item, i); + sensor_output_size[i] = json_array_item->valueint; + printf("%d: %d\n", i, sensor_output_size[i]); + } + // kmodel_path + json_item = cJSON_GetObjectItem(json_obj, "kmodel_path"); + memcpy(kmodel_path, json_item->valuestring, strlen(json_item->valuestring)); + printf("Got kmodel_path: %s\n", kmodel_path); + // kmodel_size + json_item = cJSON_GetObjectItem(json_obj, "kmodel_size"); + kmodel_size = json_item->valueint; + printf("Got kmodel_size: %d\n", kmodel_size); + // obj_thresh + json_item = cJSON_GetObjectItem(json_obj, "obj_thresh"); + obj_thresh = json_item->valuedouble; + printf("Got obj_thresh: %f\n", obj_thresh); + // nms_thresh + json_item = cJSON_GetObjectItem(json_obj, "nms_thresh"); + nms_thresh = json_item->valuedouble; + printf("Got nms_thresh: %f\n", nms_thresh); + cJSON_Delete(json_obj); + return; +} void face_detect() { int ret = 0; int result = 0; int size = 0; - g_fd = open("/dev/ov2640",O_RDONLY); - if(g_fd < 0) - { + param_parse(); + g_fd = open("/dev/ov2640", O_RDONLY); + if (g_fd < 0) { printf("open ov2640 fail !!"); return; } - showbuffer = (unsigned char*)malloc(SHOW_RGB_BUF_SIZE); - if(NULL ==showbuffer) - { + showbuffer = (unsigned char *)malloc(sensor_output_size[0] * sensor_output_size[1] * 2); + if (NULL == showbuffer) { close(g_fd); printf("showbuffer apply memory fail !!"); - return ; + return; } - kpurgbbuffer = (unsigned char*)malloc(AI_KPU_RGB_BUF_SIZE); - if(NULL ==kpurgbbuffer) - { + kpurgbbuffer = (unsigned char *)malloc(net_input_size[0] * net_input_size[1] * 3); + if (NULL == kpurgbbuffer) { close(g_fd); free(showbuffer); printf("kpurgbbuffer apply memory fail !!"); - return ; + return; } - model_data = (unsigned char *)malloc(KMODEL_SIZE + 255); - if(NULL ==model_data) - { + model_data = (unsigned char *)malloc(kmodel_size + 255); + if (NULL == model_data) { free(showbuffer); free(kpurgbbuffer); close(g_fd); printf("model_data apply memory fail !!"); - return ; + return; } - memset(model_data,0,KMODEL_SIZE + 255); - memset(showbuffer,0,SHOW_RGB_BUF_SIZE); - memset(kpurgbbuffer,0,AI_KPU_RGB_BUF_SIZE); + memset(model_data, 0, kmodel_size + 255); + memset(showbuffer, 0, sensor_output_size[0] * sensor_output_size[1] * 2); + memset(kpurgbbuffer, 0, net_input_size[0] * net_input_size[1] * 3); shoot_para_t.pdata = (unsigned int *)(showbuffer); - shoot_para_t.length = SHOW_RGB_BUF_SIZE; + shoot_para_t.length = (size_t)(sensor_output_size[0] * sensor_output_size[1] * 2); /* - load memory + load memory */ - kmodel_fd = open("/kmodel/detect.kmodel",O_RDONLY); - if(kmodel_fd <0) - { - printf("open kmodel fail"); - close(g_fd); - free(showbuffer); - free(kpurgbbuffer); - free(model_data); - return; - } - else - { - size = read(kmodel_fd, model_data, KMODEL_SIZE); - if(size != KMODEL_SIZE) - { - printf("read kmodel error size %d\n",size); + kmodel_fd = open(kmodel_path, O_RDONLY); + if (kmodel_fd < 0) { + printf("open kmodel fail"); + close(g_fd); + free(showbuffer); + free(kpurgbbuffer); + free(model_data); + return; + } else { + size = read(kmodel_fd, model_data, kmodel_size); + if (size != kmodel_size) { + printf("read kmodel error size %d\n", size); close(g_fd); close(kmodel_fd); free(showbuffer); free(kpurgbbuffer); free(model_data); return; - - } - else - { - printf("read kmodel success \n"); - } - - } - unsigned char *model_data_align = (unsigned char *)(((unsigned int)model_data+255)&(~255)); - dvp_set_ai_addr((uint32_t)kpurgbbuffer, (uint32_t)(kpurgbbuffer + 320 * 240), (uint32_t)(kpurgbbuffer + 320 * 240 * 2)); - if (kpu_load_kmodel(&face_detect_task, model_data_align) != 0) - { + + } else { + printf("read kmodel success \n"); + } + } + unsigned char *model_data_align = (unsigned char *)(((unsigned int)model_data + 255) & (~255)); + dvp_set_ai_addr((uint32_t)kpurgbbuffer, (uint32_t)(kpurgbbuffer + net_input_size[0] * net_input_size[1]), + (uint32_t)(kpurgbbuffer + net_input_size[0] * net_input_size[1] * 2)); + if (kpu_load_kmodel(&face_detect_task, model_data_align) != 0) { printf("\nmodel init error\n"); close(g_fd); close(kmodel_fd); @@ -123,131 +230,121 @@ void face_detect() } face_detect_rl.anchor_number = ANCHOR_NUM; face_detect_rl.anchor = anchor; - face_detect_rl.threshold = 0.7; - face_detect_rl.nms_value = 0.3; - result = region_layer_init(&face_detect_rl, 20, 15, 30, KPUIMAGEWIDTH, KPUIMAGEHEIGHT); - printf("region_layer_init result %d \n\r",result); - size_t stack_size = 32*1024; - pthread_attr_t attr; /* 线程属性 */ - struct sched_param prio; /* 线程优先级 */ - prio.sched_priority = 8; /* 优先级设置为 8 */ - pthread_attr_init(&attr); /* 先使用默认值初始化属性 */ - pthread_attr_setschedparam(&attr,&prio); /* 修改属性对应的优先级 */ + face_detect_rl.threshold = obj_thresh; + face_detect_rl.nms_value = nms_thresh; + result = region_layer_init(&face_detect_rl, net_output_shape[0], net_output_shape[1], net_output_shape[2], + net_input_size[1], net_input_size[0]); + printf("region_layer_init result %d \n\r", result); + size_t stack_size = STACK_SIZE; + pthread_attr_t attr; /* 线程属性 */ + struct sched_param prio; /* 线程优先级 */ + prio.sched_priority = 8; /* 优先级设置为 8 */ + pthread_attr_init(&attr); /* 先使用默认值初始化属性 */ + pthread_attr_setschedparam(&attr, &prio); /* 修改属性对应的优先级 */ pthread_attr_setstacksize(&attr, stack_size); /* 创建线程 1, 属性为 attr,入口函数是 thread_entry,入口函数参数是 1 */ - result = pthread_create(&facetid,&attr,thread_face_detcet_entry,NULL); - if (0 == result) - { + result = pthread_create(&facetid, &attr, thread_face_detcet_entry, NULL); + if (0 == result) { printf("thread_face_detcet_entry successfully!\n"); - } - else - { - printf("thread_face_detcet_entry failed! error code is %d\n",result); + } else { + printf("thread_face_detcet_entry failed! error code is %d\n", result); close(g_fd); - } + } } #ifdef __RT_THREAD_H__ -MSH_CMD_EXPORT(face_detect,face detect task); +MSH_CMD_EXPORT(face_detect, face detect task); #endif -static void* thread_face_detcet_entry(void *parameter) -{ - extern void lcd_draw_picture(uint16_t x1, uint16_t y1, uint16_t width, uint16_t height, uint32_t *ptr); + +static void *thread_face_detcet_entry(void *parameter) +{ + extern void lcd_draw_picture(uint16_t x1, uint16_t y1, uint16_t width, uint16_t height, uint32_t * ptr); printf("thread_face_detcet_entry start!\n"); int ret = 0; - //sysctl_enable_irq(); - while(1) - { - //memset(showbuffer,0,320*240*2); + // sysctl_enable_irq(); + while (1) { + // memset(showbuffer,0,320*240*2); g_ai_done_flag = 0; - ret = ioctl(g_fd,IOCTRL_CAMERA_START_SHOT,&shoot_para_t); - if(RT_ERROR == ret) - { + ret = ioctl(g_fd, IOCTRL_CAMERA_START_SHOT, &shoot_para_t); + if (RT_ERROR == ret) { printf("ov2640 can't wait event flag"); rt_free(showbuffer); close(g_fd); - pthread_exit(NULL); + pthread_exit(NULL); return NULL; } kpu_run_kmodel(&face_detect_task, kpurgbbuffer, DMAC_CHANNEL5, ai_done, NULL); - while(!g_ai_done_flag); + while (!g_ai_done_flag) + ; float *output; size_t output_size; kpu_get_output(&face_detect_task, 0, (uint8_t **)&output, &output_size); - face_detect_rl.input = output; + face_detect_rl.input = output; region_layer_run(&face_detect_rl, &face_detect_info); - /* display result */ - #ifdef BSP_USING_LCD - for (int face_cnt = 0; face_cnt < face_detect_info.obj_number; face_cnt++) - { - draw_edge((uint32_t *)showbuffer, &face_detect_info, face_cnt, 0xF800); +/* display result */ +#ifdef BSP_USING_LCD + for (int face_cnt = 0; face_cnt < face_detect_info.obj_number; face_cnt++) { + draw_edge((uint32_t *)showbuffer, &face_detect_info, face_cnt, 0xF800, (uint16_t)sensor_output_size[1], + (uint16_t)sensor_output_size[0]); + printf("%d: (%d, %d, %d, %d) cls: %d conf: %f\t", face_cnt, face_detect_info.obj[face_cnt].x1, + face_detect_info.obj[face_cnt].y1, face_detect_info.obj[face_cnt].x2, face_detect_info.obj[face_cnt].y2, + face_detect_info.obj[face_cnt].class_id, face_detect_info.obj[face_cnt].prob); + } + if (0 != face_detect_info.obj_number) printf("\n"); + lcd_draw_picture(0, 0, (uint16_t)sensor_output_size[1], (uint16_t)sensor_output_size[0], (unsigned int *)showbuffer); +#endif + usleep(1); + if (1 == if_exit) { + if_exit = 0; + printf("thread_face_detcet_entry exit"); + pthread_exit(NULL); } - lcd_draw_picture(0, 0, 320, 240, (unsigned int*)showbuffer); - #endif - usleep(1); - if(1 == if_exit) - { - if_exit = 0; - printf("thread_face_detcet_entry exit"); - pthread_exit(NULL); - } } - } void face_detect_delete() { - if(showbuffer != NULL) - { + if (showbuffer != NULL) { int ret = 0; close(g_fd); close(kmodel_fd); free(showbuffer); free(kpurgbbuffer); free(model_data); - printf("face detect task cancel!!! ret %d ",ret); + printf("face detect task cancel!!! ret %d ", ret); if_exit = 1; } - } #ifdef __RT_THREAD_H__ -MSH_CMD_EXPORT(face_detect_delete,face detect task delete); +MSH_CMD_EXPORT(face_detect_delete, face detect task delete); #endif -void kmodel_load(unsigned char * model_data) + +void kmodel_load(unsigned char *model_data) { int kmodel_fd = 0; int size = 0; - kmodel_fd = open("/kmodel/detect.kmodel",O_RDONLY); - - model_data = (unsigned char *)malloc(KMODEL_SIZE + 255); - if(NULL ==model_data) - { + kmodel_fd = open(kmodel_path, O_RDONLY); + + model_data = (unsigned char *)malloc(kmodel_size + 255); + if (NULL == model_data) { printf("model_data apply memory fail !!"); - return ; - } - memset(model_data,0,KMODEL_SIZE + 255); - - if (kmodel_fd>= 0) - { - size = read(kmodel_fd, model_data, KMODEL_SIZE); - if(size != KMODEL_SIZE) - { - printf("read kmodel error size %d\n",size); - - } - else - { - printf("read kmodel success"); - } - } - else - { + return; + } + memset(model_data, 0, kmodel_size + 255); + + if (kmodel_fd >= 0) { + size = read(kmodel_fd, model_data, kmodel_size); + if (size != kmodel_size) { + printf("read kmodel error size %d\n", size); + + } else { + printf("read kmodel success"); + } + } else { free(model_data); printf("open kmodel fail"); } - } #ifdef __RT_THREAD_H__ -MSH_CMD_EXPORT(kmodel_load,kmodel load memory); +MSH_CMD_EXPORT(kmodel_load, kmodel load memory); #endif - diff --git a/Ubiquitous/RT_Thread/bsp/k210/.config b/Ubiquitous/RT_Thread/bsp/k210/.config index 1715fdbf..71a42734 100644 --- a/Ubiquitous/RT_Thread/bsp/k210/.config +++ b/Ubiquitous/RT_Thread/bsp/k210/.config @@ -237,7 +237,8 @@ CONFIG_RT_WLAN_WORKQUEUE_THREAD_PRIO=15 # POSIX layer and C standard library # CONFIG_RT_USING_LIBC=y -# CONFIG_RT_USING_PTHREADS is not set +CONFIG_RT_USING_PTHREADS=y +CONFIG_PTHREAD_NUM_MAX=8 CONFIG_RT_USING_POSIX=y # CONFIG_RT_USING_POSIX_MMAP is not set # CONFIG_RT_USING_POSIX_TERMIOS is not set @@ -379,9 +380,27 @@ CONFIG_BSP_SPI1_USING_SS1=y CONFIG_BSP_SPI1_SS1_PIN=8 # CONFIG_BSP_SPI1_USING_SS2 is not set # CONFIG_BSP_SPI1_USING_SS3 is not set -# CONFIG_BSP_USING_LCD is not set +CONFIG_BSP_USING_LCD=y +CONFIG_BSP_LCD_CS_PIN=36 +CONFIG_BSP_LCD_WR_PIN=39 +CONFIG_BSP_LCD_DC_PIN=38 +CONFIG_BSP_LCD_RST_PIN=37 +CONFIG_BSP_LCD_X_MAX=240 +CONFIG_BSP_LCD_Y_MAX=320 CONFIG_BSP_USING_SDCARD=y -# CONFIG_BSP_USING_DVP is not set +CONFIG_BSP_USING_DVP=y + +# +# The default pin assignment is based on the Maix Duino K210 development board +# +CONFIG_BSP_DVP_SCCB_SDA_PIN=40 +CONFIG_BSP_DVP_SCCB_SCLK_PIN=41 +CONFIG_BSP_DVP_CMOS_RST_PIN=42 +CONFIG_BSP_DVP_CMOS_VSYNC_PIN=43 +CONFIG_BSP_DVP_CMOS_PWDN_PIN=44 +CONFIG_BSP_DVP_CMOS_XCLK_PIN=46 +CONFIG_BSP_DVP_CMOS_PCLK_PIN=47 +CONFIG_BSP_DVP_CMOS_HREF_PIN=45 # # Kendryte SDK Config @@ -392,7 +411,7 @@ CONFIG_PKG_KENDRYTE_SDK_VERNUM=0x0055 # More Drivers # # CONFIG_PKG_USING_RW007 is not set -# CONFIG_DRV_USING_OV2640 is not set +CONFIG_DRV_USING_OV2640=y # # APP_Framework @@ -424,7 +443,7 @@ CONFIG_MAIN_KTASK_STACK_SIZE=1024 # # knowing app # -# CONFIG_APPLICATION_KNOWING is not set +CONFIG_FACE_DETECT=y # # sensor app @@ -438,9 +457,17 @@ CONFIG_TRANSFORM_LAYER_ATTRIUBUTE=y CONFIG_ADD_XIUOS_FETURES=y # CONFIG_ADD_NUTTX_FETURES is not set # CONFIG_ADD_RTTHREAD_FETURES is not set -# CONFIG_SUPPORT_SENSOR_FRAMEWORK is not set +CONFIG_SUPPORT_SENSOR_FRAMEWORK=y +# CONFIG_SENSOR_CO2 is not set +# CONFIG_SENSOR_PM is not set +# CONFIG_SENSOR_VOICE is not set +# CONFIG_SENSOR_TEMPERATURE is not set +# CONFIG_SENSOR_HUMIDITY is not set # CONFIG_SUPPORT_CONNECTION_FRAMEWORK is not set CONFIG_SUPPORT_KNOWING_FRAMEWORK=y +# CONFIG_USING_TENSORFLOWLITEMICRO is not set +CONFIG_USING_KPU_POSTPROCESSING=y +CONFIG_USING_YOLOV2=y # CONFIG_SUPPORT_CONTROL_FRAMEWORK is not set # diff --git a/Ubiquitous/RT_Thread/bsp/k210/.gitignore b/Ubiquitous/RT_Thread/bsp/k210/.gitignore index c5012036..14e2fd4e 100644 --- a/Ubiquitous/RT_Thread/bsp/k210/.gitignore +++ b/Ubiquitous/RT_Thread/bsp/k210/.gitignore @@ -4,8 +4,8 @@ cconfig.h *.bin *.map -rtconfig.h -.config +# rtconfig.h +# .config # General .DS_Store diff --git a/Ubiquitous/RT_Thread/bsp/k210/rtconfig.h b/Ubiquitous/RT_Thread/bsp/k210/rtconfig.h index afa6175b..4730b618 100644 --- a/Ubiquitous/RT_Thread/bsp/k210/rtconfig.h +++ b/Ubiquitous/RT_Thread/bsp/k210/rtconfig.h @@ -160,6 +160,8 @@ /* POSIX layer and C standard library */ #define RT_USING_LIBC +#define RT_USING_PTHREADS +#define PTHREAD_NUM_MAX 8 #define RT_USING_POSIX #define RT_LIBC_FIXED_TIMEZONE 8 @@ -254,7 +256,26 @@ #define BSP_SPI1_SS0_PIN 29 #define BSP_SPI1_USING_SS1 #define BSP_SPI1_SS1_PIN 8 +#define BSP_USING_LCD +#define BSP_LCD_CS_PIN 36 +#define BSP_LCD_WR_PIN 39 +#define BSP_LCD_DC_PIN 38 +#define BSP_LCD_RST_PIN 37 +#define BSP_LCD_X_MAX 240 +#define BSP_LCD_Y_MAX 320 #define BSP_USING_SDCARD +#define BSP_USING_DVP + +/* The default pin assignment is based on the Maix Duino K210 development board */ + +#define BSP_DVP_SCCB_SDA_PIN 40 +#define BSP_DVP_SCCB_SCLK_PIN 41 +#define BSP_DVP_CMOS_RST_PIN 42 +#define BSP_DVP_CMOS_VSYNC_PIN 43 +#define BSP_DVP_CMOS_PWDN_PIN 44 +#define BSP_DVP_CMOS_XCLK_PIN 46 +#define BSP_DVP_CMOS_PCLK_PIN 47 +#define BSP_DVP_CMOS_HREF_PIN 45 /* Kendryte SDK Config */ @@ -262,6 +283,7 @@ /* More Drivers */ +#define DRV_USING_OV2640 /* APP_Framework */ @@ -281,6 +303,7 @@ /* knowing app */ +#define FACE_DETECT /* sensor app */ @@ -289,7 +312,10 @@ #define TRANSFORM_LAYER_ATTRIUBUTE #define ADD_XIUOS_FETURES +#define SUPPORT_SENSOR_FRAMEWORK #define SUPPORT_KNOWING_FRAMEWORK +#define USING_KPU_POSTPROCESSING +#define USING_YOLOV2 /* app lib */ From 3b74443dacf18929fc78567b65d64fbf2cb9cada Mon Sep 17 00:00:00 2001 From: chunyexixiaoyu <834670833@qq.com> Date: Wed, 4 Aug 2021 16:24:16 +0800 Subject: [PATCH 04/18] APP_Framework/lib/:add cJSON library --- .../Applications/knowing_app/face_detect/Kconfig | 1 + .../knowing_app/face_detect/face_detect.c | 5 +++-- APP_Framework/lib/Kconfig | 6 +++--- APP_Framework/lib/SConscript | 14 ++++++++++++++ APP_Framework/lib/cJSON/Kconfig | 3 +++ APP_Framework/lib/cJSON/SConscript | 10 ++++++++++ .../knowing_app/face_detect => lib/cJSON}/cJSON.c | 0 .../knowing_app/face_detect => lib/cJSON}/cJSON.h | 0 Ubiquitous/RT_Thread/bsp/k210/SConstruct | 3 ++- .../bsp/stm32f407-atk-coreboard/SConstruct | 3 ++- 10 files changed, 38 insertions(+), 7 deletions(-) create mode 100644 APP_Framework/lib/SConscript create mode 100644 APP_Framework/lib/cJSON/Kconfig create mode 100644 APP_Framework/lib/cJSON/SConscript rename APP_Framework/{Applications/knowing_app/face_detect => lib/cJSON}/cJSON.c (100%) rename APP_Framework/{Applications/knowing_app/face_detect => lib/cJSON}/cJSON.h (100%) diff --git a/APP_Framework/Applications/knowing_app/face_detect/Kconfig b/APP_Framework/Applications/knowing_app/face_detect/Kconfig index 92738ada..7d3b84e8 100644 --- a/APP_Framework/Applications/knowing_app/face_detect/Kconfig +++ b/APP_Framework/Applications/knowing_app/face_detect/Kconfig @@ -4,4 +4,5 @@ config FACE_DETECT depends on DRV_USING_OV2640 depends on USING_KPU_POSTPROCESSING depends on USING_YOLOV2 + select LIB_USING_CJSON default n diff --git a/APP_Framework/Applications/knowing_app/face_detect/face_detect.c b/APP_Framework/Applications/knowing_app/face_detect/face_detect.c index 702b43c6..3ce3319a 100644 --- a/APP_Framework/Applications/knowing_app/face_detect/face_detect.c +++ b/APP_Framework/Applications/knowing_app/face_detect/face_detect.c @@ -1,6 +1,7 @@ #include - -#include "cJSON.h" +#ifdef LIB_USING_CJSON +#include +#endif #include "region_layer.h" #define ANCHOR_NUM 5 #define STACK_SIZE (128 * 1024) diff --git a/APP_Framework/lib/Kconfig b/APP_Framework/lib/Kconfig index bec09361..d5064ee3 100755 --- a/APP_Framework/lib/Kconfig +++ b/APP_Framework/lib/Kconfig @@ -1,5 +1,5 @@ -menu "app lib" - +menu "lib" + choice prompt "chose a kind of lib for app" default APP_SELECT_NEWLIB @@ -10,5 +10,5 @@ menu "app lib" config APP_SELECT_OTHER_LIB bool "app select other lib" endchoice - + source "$APP_DIR/lib/cJSON/Kconfig" endmenu diff --git a/APP_Framework/lib/SConscript b/APP_Framework/lib/SConscript new file mode 100644 index 00000000..f307e3f7 --- /dev/null +++ b/APP_Framework/lib/SConscript @@ -0,0 +1,14 @@ +import os +Import('RTT_ROOT') +from building import * + +cwd = GetCurrentDir() +objs = [] +list = os.listdir(cwd) + +for d in list: + path = os.path.join(cwd, d) + if os.path.isfile(os.path.join(path, 'SConscript')): + objs = objs + SConscript(os.path.join(path, 'SConscript')) + +Return('objs') diff --git a/APP_Framework/lib/cJSON/Kconfig b/APP_Framework/lib/cJSON/Kconfig new file mode 100644 index 00000000..79a2d589 --- /dev/null +++ b/APP_Framework/lib/cJSON/Kconfig @@ -0,0 +1,3 @@ +menuconfig LIB_USING_CJSON + bool "USING cJSON" + default n diff --git a/APP_Framework/lib/cJSON/SConscript b/APP_Framework/lib/cJSON/SConscript new file mode 100644 index 00000000..42322db2 --- /dev/null +++ b/APP_Framework/lib/cJSON/SConscript @@ -0,0 +1,10 @@ +from building import * +import os + +cwd = GetCurrentDir() + +src = Glob('*.c') + +group = DefineGroup('cjson', src, depend = ['LIB_USING_CJSON'], CPPPATH = [cwd]) + +Return('group') \ No newline at end of file diff --git a/APP_Framework/Applications/knowing_app/face_detect/cJSON.c b/APP_Framework/lib/cJSON/cJSON.c similarity index 100% rename from APP_Framework/Applications/knowing_app/face_detect/cJSON.c rename to APP_Framework/lib/cJSON/cJSON.c diff --git a/APP_Framework/Applications/knowing_app/face_detect/cJSON.h b/APP_Framework/lib/cJSON/cJSON.h similarity index 100% rename from APP_Framework/Applications/knowing_app/face_detect/cJSON.h rename to APP_Framework/lib/cJSON/cJSON.h diff --git a/Ubiquitous/RT_Thread/bsp/k210/SConstruct b/Ubiquitous/RT_Thread/bsp/k210/SConstruct index 55247bc1..8aad441d 100644 --- a/Ubiquitous/RT_Thread/bsp/k210/SConstruct +++ b/Ubiquitous/RT_Thread/bsp/k210/SConstruct @@ -59,6 +59,7 @@ objs.extend(SConscript(os.getcwd() + '/../../../../APP_Framework/Framework/SCons # include APP_Framework/Applications objs.extend(SConscript(os.getcwd() + '/../../../../APP_Framework/Applications/SConscript')) - +# include APP_Framework/lib +objs.extend(SConscript(os.getcwd() + '/../../../../APP_Framework/lib/SConscript')) # make a building DoBuilding(TARGET, objs) diff --git a/Ubiquitous/RT_Thread/bsp/stm32f407-atk-coreboard/SConstruct b/Ubiquitous/RT_Thread/bsp/stm32f407-atk-coreboard/SConstruct index 6e447c6c..2bc33db0 100644 --- a/Ubiquitous/RT_Thread/bsp/stm32f407-atk-coreboard/SConstruct +++ b/Ubiquitous/RT_Thread/bsp/stm32f407-atk-coreboard/SConstruct @@ -81,6 +81,7 @@ objs.extend(SConscript(os.getcwd() + '/../../../../APP_Framework/Framework/SCons # include APP_Framework/Applications objs.extend(SConscript(os.getcwd() + '/../../../../APP_Framework/Applications/SConscript')) - +# include APP_Framework/lib +objs.extend(SConscript(os.getcwd() + '/../../../../APP_Framework/lib/SConscript')) # make a building DoBuilding(TARGET, objs) From 2d8147a92b82e63a238ed01d2806067a933aefa4 Mon Sep 17 00:00:00 2001 From: Liu Yongkai <506680965@qq.com> Date: Wed, 4 Aug 2021 15:35:47 +0800 Subject: [PATCH 05/18] feat(instrusion detect): add knowing app instrusion detect --- .../Applications/knowing_app/Kconfig | 1 + .../knowing_app/instrusion_detect/Kconfig | 7 + .../knowing_app/instrusion_detect/SConscript | 9 + .../knowing_app/instrusion_detect/cJSON.c | 3110 +++++++++++++++++ .../knowing_app/instrusion_detect/cJSON.h | 293 ++ .../knowing_app/instrusion_detect/human.json | 31 + .../instrusion_detect/instrusion_detect.c | 350 ++ 7 files changed, 3801 insertions(+) create mode 100644 APP_Framework/Applications/knowing_app/instrusion_detect/Kconfig create mode 100644 APP_Framework/Applications/knowing_app/instrusion_detect/SConscript create mode 100644 APP_Framework/Applications/knowing_app/instrusion_detect/cJSON.c create mode 100644 APP_Framework/Applications/knowing_app/instrusion_detect/cJSON.h create mode 100644 APP_Framework/Applications/knowing_app/instrusion_detect/human.json create mode 100644 APP_Framework/Applications/knowing_app/instrusion_detect/instrusion_detect.c diff --git a/APP_Framework/Applications/knowing_app/Kconfig b/APP_Framework/Applications/knowing_app/Kconfig index ece7acb3..b0705d4f 100755 --- a/APP_Framework/Applications/knowing_app/Kconfig +++ b/APP_Framework/Applications/knowing_app/Kconfig @@ -1,4 +1,5 @@ menu "knowing app" source "$APP_DIR/Applications/knowing_app/mnist/Kconfig" source "$APP_DIR/Applications/knowing_app/face_detect/Kconfig" + source "$APP_DIR/Applications/knowing_app/instrusion_detect/Kconfig" endmenu diff --git a/APP_Framework/Applications/knowing_app/instrusion_detect/Kconfig b/APP_Framework/Applications/knowing_app/instrusion_detect/Kconfig new file mode 100644 index 00000000..c8fb4637 --- /dev/null +++ b/APP_Framework/Applications/knowing_app/instrusion_detect/Kconfig @@ -0,0 +1,7 @@ +config INSTRUSION_DETECT + bool "enable apps/instrusion detect" + depends on BOARD_K210_EVB + depends on DRV_USING_OV2640 + depends on USING_KPU_POSTPROCESSING + depends on USING_YOLOV2 + default n diff --git a/APP_Framework/Applications/knowing_app/instrusion_detect/SConscript b/APP_Framework/Applications/knowing_app/instrusion_detect/SConscript new file mode 100644 index 00000000..fd445746 --- /dev/null +++ b/APP_Framework/Applications/knowing_app/instrusion_detect/SConscript @@ -0,0 +1,9 @@ +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') + Glob('*.cpp') +CPPPATH = [cwd] + +group = DefineGroup('Applications', src, depend = ['INSTRUSION_DETECT'], LOCAL_CPPPATH = CPPPATH) + +Return('group') diff --git a/APP_Framework/Applications/knowing_app/instrusion_detect/cJSON.c b/APP_Framework/Applications/knowing_app/instrusion_detect/cJSON.c new file mode 100644 index 00000000..030311ce --- /dev/null +++ b/APP_Framework/Applications/knowing_app/instrusion_detect/cJSON.c @@ -0,0 +1,3110 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +/* cJSON */ +/* JSON parser in C. */ + +/* disable warnings about old C89 functions in MSVC */ +#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) +#define _CRT_SECURE_NO_DEPRECATE +#endif + +#ifdef __GNUC__ +#pragma GCC visibility push(default) +#endif +#if defined(_MSC_VER) +#pragma warning (push) +/* disable warning about single line comments in system headers */ +#pragma warning (disable : 4001) +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifdef ENABLE_LOCALES +#include +#endif + +#if defined(_MSC_VER) +#pragma warning (pop) +#endif +#ifdef __GNUC__ +#pragma GCC visibility pop +#endif + +#include "cJSON.h" + +/* define our own boolean type */ +#ifdef true +#undef true +#endif +#define true ((cJSON_bool)1) + +#ifdef false +#undef false +#endif +#define false ((cJSON_bool)0) + +/* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */ +#ifndef isinf +#define isinf(d) (isnan((d - d)) && !isnan(d)) +#endif +#ifndef isnan +#define isnan(d) (d != d) +#endif + +#ifndef NAN +#ifdef _WIN32 +#define NAN sqrt(-1.0) +#else +#define NAN 0.0/0.0 +#endif +#endif + +typedef struct { + const unsigned char *json; + size_t position; +} error; +static error global_error = { NULL, 0 }; + +CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) +{ + return (const char*) (global_error.json + global_error.position); +} + +CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item) +{ + if (!cJSON_IsString(item)) + { + return NULL; + } + + return item->valuestring; +} + +CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item) +{ + if (!cJSON_IsNumber(item)) + { + return (double) NAN; + } + + return item->valuedouble; +} + +/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 14) + #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. +#endif + +CJSON_PUBLIC(const char*) cJSON_Version(void) +{ + static char version[15]; + sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); + + return version; +} + +/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */ +static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) +{ + if ((string1 == NULL) || (string2 == NULL)) + { + return 1; + } + + if (string1 == string2) + { + return 0; + } + + for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++) + { + if (*string1 == '\0') + { + return 0; + } + } + + return tolower(*string1) - tolower(*string2); +} + +typedef struct internal_hooks +{ + void *(CJSON_CDECL *allocate)(size_t size); + void (CJSON_CDECL *deallocate)(void *pointer); + void *(CJSON_CDECL *reallocate)(void *pointer, size_t size); +} internal_hooks; + +#if defined(_MSC_VER) +/* work around MSVC error C2322: '...' address of dllimport '...' is not static */ +static void * CJSON_CDECL internal_malloc(size_t size) +{ + return malloc(size); +} +static void CJSON_CDECL internal_free(void *pointer) +{ + free(pointer); +} +static void * CJSON_CDECL internal_realloc(void *pointer, size_t size) +{ + return realloc(pointer, size); +} +#else +#define internal_malloc malloc +#define internal_free free +#define internal_realloc realloc +#endif + +/* strlen of character literals resolved at compile time */ +#define static_strlen(string_literal) (sizeof(string_literal) - sizeof("")) + +static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc }; + +static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks) +{ + size_t length = 0; + unsigned char *copy = NULL; + + if (string == NULL) + { + return NULL; + } + + length = strlen((const char*)string) + sizeof(""); + copy = (unsigned char*)hooks->allocate(length); + if (copy == NULL) + { + return NULL; + } + memcpy(copy, string, length); + + return copy; +} + +CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) +{ + if (hooks == NULL) + { + /* Reset hooks */ + global_hooks.allocate = malloc; + global_hooks.deallocate = free; + global_hooks.reallocate = realloc; + return; + } + + global_hooks.allocate = malloc; + if (hooks->malloc_fn != NULL) + { + global_hooks.allocate = hooks->malloc_fn; + } + + global_hooks.deallocate = free; + if (hooks->free_fn != NULL) + { + global_hooks.deallocate = hooks->free_fn; + } + + /* use realloc only if both free and malloc are used */ + global_hooks.reallocate = NULL; + if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free)) + { + global_hooks.reallocate = realloc; + } +} + +/* Internal constructor. */ +static cJSON *cJSON_New_Item(const internal_hooks * const hooks) +{ + cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON)); + if (node) + { + memset(node, '\0', sizeof(cJSON)); + } + + return node; +} + +/* Delete a cJSON structure. */ +CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) +{ + cJSON *next = NULL; + while (item != NULL) + { + next = item->next; + if (!(item->type & cJSON_IsReference) && (item->child != NULL)) + { + cJSON_Delete(item->child); + } + if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) + { + global_hooks.deallocate(item->valuestring); + } + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) + { + global_hooks.deallocate(item->string); + } + global_hooks.deallocate(item); + item = next; + } +} + +/* get the decimal point character of the current locale */ +static unsigned char get_decimal_point(void) +{ +#ifdef ENABLE_LOCALES + struct lconv *lconv = localeconv(); + return (unsigned char) lconv->decimal_point[0]; +#else + return '.'; +#endif +} + +typedef struct +{ + const unsigned char *content; + size_t length; + size_t offset; + size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */ + internal_hooks hooks; +} parse_buffer; + +/* check if the given size is left to read in a given parse buffer (starting with 1) */ +#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length)) +/* check if the buffer can be accessed at the given index (starting with 0) */ +#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length)) +#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index)) +/* get a pointer to the buffer at the position */ +#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset) + +/* Parse the input text to generate a number, and populate the result into item. */ +static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer) +{ + double number = 0; + unsigned char *after_end = NULL; + unsigned char number_c_string[64]; + unsigned char decimal_point = get_decimal_point(); + size_t i = 0; + + if ((input_buffer == NULL) || (input_buffer->content == NULL)) + { + return false; + } + + /* copy the number into a temporary buffer and replace '.' with the decimal point + * of the current locale (for strtod) + * This also takes care of '\0' not necessarily being available for marking the end of the input */ + for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) + { + switch (buffer_at_offset(input_buffer)[i]) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '+': + case '-': + case 'e': + case 'E': + number_c_string[i] = buffer_at_offset(input_buffer)[i]; + break; + + case '.': + number_c_string[i] = decimal_point; + break; + + default: + goto loop_end; + } + } +loop_end: + number_c_string[i] = '\0'; + + number = strtod((const char*)number_c_string, (char**)&after_end); + if (number_c_string == after_end) + { + return false; /* parse_error */ + } + + item->valuedouble = number; + + /* use saturation in case of overflow */ + if (number >= INT_MAX) + { + item->valueint = INT_MAX; + } + else if (number <= (double)INT_MIN) + { + item->valueint = INT_MIN; + } + else + { + item->valueint = (int)number; + } + + item->type = cJSON_Number; + + input_buffer->offset += (size_t)(after_end - number_c_string); + return true; +} + +/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ +CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) +{ + if (number >= INT_MAX) + { + object->valueint = INT_MAX; + } + else if (number <= (double)INT_MIN) + { + object->valueint = INT_MIN; + } + else + { + object->valueint = (int)number; + } + + return object->valuedouble = number; +} + +CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring) +{ + char *copy = NULL; + /* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */ + if (!(object->type & cJSON_String) || (object->type & cJSON_IsReference)) + { + return NULL; + } + if (strlen(valuestring) <= strlen(object->valuestring)) + { + strcpy(object->valuestring, valuestring); + return object->valuestring; + } + copy = (char*) cJSON_strdup((const unsigned char*)valuestring, &global_hooks); + if (copy == NULL) + { + return NULL; + } + if (object->valuestring != NULL) + { + cJSON_free(object->valuestring); + } + object->valuestring = copy; + + return copy; +} + +typedef struct +{ + unsigned char *buffer; + size_t length; + size_t offset; + size_t depth; /* current nesting depth (for formatted printing) */ + cJSON_bool noalloc; + cJSON_bool format; /* is this print a formatted print */ + internal_hooks hooks; +} printbuffer; + +/* realloc printbuffer if necessary to have at least "needed" bytes more */ +static unsigned char* ensure(printbuffer * const p, size_t needed) +{ + unsigned char *newbuffer = NULL; + size_t newsize = 0; + + if ((p == NULL) || (p->buffer == NULL)) + { + return NULL; + } + + if ((p->length > 0) && (p->offset >= p->length)) + { + /* make sure that offset is valid */ + return NULL; + } + + if (needed > INT_MAX) + { + /* sizes bigger than INT_MAX are currently not supported */ + return NULL; + } + + needed += p->offset + 1; + if (needed <= p->length) + { + return p->buffer + p->offset; + } + + if (p->noalloc) { + return NULL; + } + + /* calculate new buffer size */ + if (needed > (INT_MAX / 2)) + { + /* overflow of int, use INT_MAX if possible */ + if (needed <= INT_MAX) + { + newsize = INT_MAX; + } + else + { + return NULL; + } + } + else + { + newsize = needed * 2; + } + + if (p->hooks.reallocate != NULL) + { + /* reallocate with realloc if available */ + newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize); + if (newbuffer == NULL) + { + p->hooks.deallocate(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + } + else + { + /* otherwise reallocate manually */ + newbuffer = (unsigned char*)p->hooks.allocate(newsize); + if (!newbuffer) + { + p->hooks.deallocate(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + + memcpy(newbuffer, p->buffer, p->offset + 1); + p->hooks.deallocate(p->buffer); + } + p->length = newsize; + p->buffer = newbuffer; + + return newbuffer + p->offset; +} + +/* calculate the new length of the string in a printbuffer and update the offset */ +static void update_offset(printbuffer * const buffer) +{ + const unsigned char *buffer_pointer = NULL; + if ((buffer == NULL) || (buffer->buffer == NULL)) + { + return; + } + buffer_pointer = buffer->buffer + buffer->offset; + + buffer->offset += strlen((const char*)buffer_pointer); +} + +/* securely comparison of floating-point variables */ +static cJSON_bool compare_double(double a, double b) +{ + double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b); + return (fabs(a - b) <= maxVal * DBL_EPSILON); +} + +/* Render the number nicely from the given item into a string. */ +static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + double d = item->valuedouble; + int length = 0; + size_t i = 0; + unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */ + unsigned char decimal_point = get_decimal_point(); + double test = 0.0; + + if (output_buffer == NULL) + { + return false; + } + + /* This checks for NaN and Infinity */ + if (isnan(d) || isinf(d)) + { + length = sprintf((char*)number_buffer, "null"); + } + else + { + /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ + length = sprintf((char*)number_buffer, "%1.15g", d); + + /* Check whether the original double can be recovered */ + if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d)) + { + /* If not, print with 17 decimal places of precision */ + length = sprintf((char*)number_buffer, "%1.17g", d); + } + } + + /* sprintf failed or buffer overrun occurred */ + if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) + { + return false; + } + + /* reserve appropriate space in the output */ + output_pointer = ensure(output_buffer, (size_t)length + sizeof("")); + if (output_pointer == NULL) + { + return false; + } + + /* copy the printed number to the output and replace locale + * dependent decimal point with '.' */ + for (i = 0; i < ((size_t)length); i++) + { + if (number_buffer[i] == decimal_point) + { + output_pointer[i] = '.'; + continue; + } + + output_pointer[i] = number_buffer[i]; + } + output_pointer[i] = '\0'; + + output_buffer->offset += (size_t)length; + + return true; +} + +/* parse 4 digit hexadecimal number */ +static unsigned parse_hex4(const unsigned char * const input) +{ + unsigned int h = 0; + size_t i = 0; + + for (i = 0; i < 4; i++) + { + /* parse digit */ + if ((input[i] >= '0') && (input[i] <= '9')) + { + h += (unsigned int) input[i] - '0'; + } + else if ((input[i] >= 'A') && (input[i] <= 'F')) + { + h += (unsigned int) 10 + input[i] - 'A'; + } + else if ((input[i] >= 'a') && (input[i] <= 'f')) + { + h += (unsigned int) 10 + input[i] - 'a'; + } + else /* invalid */ + { + return 0; + } + + if (i < 3) + { + /* shift left to make place for the next nibble */ + h = h << 4; + } + } + + return h; +} + +/* converts a UTF-16 literal to UTF-8 + * A literal can be one or two sequences of the form \uXXXX */ +static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer) +{ + long unsigned int codepoint = 0; + unsigned int first_code = 0; + const unsigned char *first_sequence = input_pointer; + unsigned char utf8_length = 0; + unsigned char utf8_position = 0; + unsigned char sequence_length = 0; + unsigned char first_byte_mark = 0; + + if ((input_end - first_sequence) < 6) + { + /* input ends unexpectedly */ + goto fail; + } + + /* get the first utf16 sequence */ + first_code = parse_hex4(first_sequence + 2); + + /* check that the code is valid */ + if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) + { + goto fail; + } + + /* UTF16 surrogate pair */ + if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) + { + const unsigned char *second_sequence = first_sequence + 6; + unsigned int second_code = 0; + sequence_length = 12; /* \uXXXX\uXXXX */ + + if ((input_end - second_sequence) < 6) + { + /* input ends unexpectedly */ + goto fail; + } + + if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) + { + /* missing second half of the surrogate pair */ + goto fail; + } + + /* get the second utf16 sequence */ + second_code = parse_hex4(second_sequence + 2); + /* check that the code is valid */ + if ((second_code < 0xDC00) || (second_code > 0xDFFF)) + { + /* invalid second half of the surrogate pair */ + goto fail; + } + + + /* calculate the unicode codepoint from the surrogate pair */ + codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF)); + } + else + { + sequence_length = 6; /* \uXXXX */ + codepoint = first_code; + } + + /* encode as UTF-8 + * takes at maximum 4 bytes to encode: + * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ + if (codepoint < 0x80) + { + /* normal ascii, encoding 0xxxxxxx */ + utf8_length = 1; + } + else if (codepoint < 0x800) + { + /* two bytes, encoding 110xxxxx 10xxxxxx */ + utf8_length = 2; + first_byte_mark = 0xC0; /* 11000000 */ + } + else if (codepoint < 0x10000) + { + /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ + utf8_length = 3; + first_byte_mark = 0xE0; /* 11100000 */ + } + else if (codepoint <= 0x10FFFF) + { + /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ + utf8_length = 4; + first_byte_mark = 0xF0; /* 11110000 */ + } + else + { + /* invalid unicode codepoint */ + goto fail; + } + + /* encode as utf8 */ + for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) + { + /* 10xxxxxx */ + (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF); + codepoint >>= 6; + } + /* encode first byte */ + if (utf8_length > 1) + { + (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF); + } + else + { + (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F); + } + + *output_pointer += utf8_length; + + return sequence_length; + +fail: + return 0; +} + +/* Parse the input text into an unescaped cinput, and populate item. */ +static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer) +{ + const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; + const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; + unsigned char *output_pointer = NULL; + unsigned char *output = NULL; + + /* not a string */ + if (buffer_at_offset(input_buffer)[0] != '\"') + { + goto fail; + } + + { + /* calculate approximate size of the output (overestimate) */ + size_t allocation_length = 0; + size_t skipped_bytes = 0; + while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) + { + /* is escape sequence */ + if (input_end[0] == '\\') + { + if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) + { + /* prevent buffer overflow when last input character is a backslash */ + goto fail; + } + skipped_bytes++; + input_end++; + } + input_end++; + } + if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) + { + goto fail; /* string ended unexpectedly */ + } + + /* This is at most how much we need for the output */ + allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes; + output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof("")); + if (output == NULL) + { + goto fail; /* allocation failure */ + } + } + + output_pointer = output; + /* loop through the string literal */ + while (input_pointer < input_end) + { + if (*input_pointer != '\\') + { + *output_pointer++ = *input_pointer++; + } + /* escape sequence */ + else + { + unsigned char sequence_length = 2; + if ((input_end - input_pointer) < 1) + { + goto fail; + } + + switch (input_pointer[1]) + { + case 'b': + *output_pointer++ = '\b'; + break; + case 'f': + *output_pointer++ = '\f'; + break; + case 'n': + *output_pointer++ = '\n'; + break; + case 'r': + *output_pointer++ = '\r'; + break; + case 't': + *output_pointer++ = '\t'; + break; + case '\"': + case '\\': + case '/': + *output_pointer++ = input_pointer[1]; + break; + + /* UTF-16 literal */ + case 'u': + sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); + if (sequence_length == 0) + { + /* failed to convert UTF16-literal to UTF-8 */ + goto fail; + } + break; + + default: + goto fail; + } + input_pointer += sequence_length; + } + } + + /* zero terminate the output */ + *output_pointer = '\0'; + + item->type = cJSON_String; + item->valuestring = (char*)output; + + input_buffer->offset = (size_t) (input_end - input_buffer->content); + input_buffer->offset++; + + return true; + +fail: + if (output != NULL) + { + input_buffer->hooks.deallocate(output); + } + + if (input_pointer != NULL) + { + input_buffer->offset = (size_t)(input_pointer - input_buffer->content); + } + + return false; +} + +/* Render the cstring provided to an escaped version that can be printed. */ +static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer) +{ + const unsigned char *input_pointer = NULL; + unsigned char *output = NULL; + unsigned char *output_pointer = NULL; + size_t output_length = 0; + /* numbers of additional characters needed for escaping */ + size_t escape_characters = 0; + + if (output_buffer == NULL) + { + return false; + } + + /* empty string */ + if (input == NULL) + { + output = ensure(output_buffer, sizeof("\"\"")); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "\"\""); + + return true; + } + + /* set "flag" to 1 if something needs to be escaped */ + for (input_pointer = input; *input_pointer; input_pointer++) + { + switch (*input_pointer) + { + case '\"': + case '\\': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + /* one character escape sequence */ + escape_characters++; + break; + default: + if (*input_pointer < 32) + { + /* UTF-16 escape sequence uXXXX */ + escape_characters += 5; + } + break; + } + } + output_length = (size_t)(input_pointer - input) + escape_characters; + + output = ensure(output_buffer, output_length + sizeof("\"\"")); + if (output == NULL) + { + return false; + } + + /* no characters have to be escaped */ + if (escape_characters == 0) + { + output[0] = '\"'; + memcpy(output + 1, input, output_length); + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; + } + + output[0] = '\"'; + output_pointer = output + 1; + /* copy the string */ + for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) + { + if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) + { + /* normal character, copy */ + *output_pointer = *input_pointer; + } + else + { + /* character needs to be escaped */ + *output_pointer++ = '\\'; + switch (*input_pointer) + { + case '\\': + *output_pointer = '\\'; + break; + case '\"': + *output_pointer = '\"'; + break; + case '\b': + *output_pointer = 'b'; + break; + case '\f': + *output_pointer = 'f'; + break; + case '\n': + *output_pointer = 'n'; + break; + case '\r': + *output_pointer = 'r'; + break; + case '\t': + *output_pointer = 't'; + break; + default: + /* escape and print as unicode codepoint */ + sprintf((char*)output_pointer, "u%04x", *input_pointer); + output_pointer += 4; + break; + } + } + } + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; +} + +/* Invoke print_string_ptr (which is useful) on an item. */ +static cJSON_bool print_string(const cJSON * const item, printbuffer * const p) +{ + return print_string_ptr((unsigned char*)item->valuestring, p); +} + +/* Predeclare these prototypes. */ +static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer); +static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer); +static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer); + +/* Utility to jump whitespace and cr/lf */ +static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) +{ + if ((buffer == NULL) || (buffer->content == NULL)) + { + return NULL; + } + + if (cannot_access_at_index(buffer, 0)) + { + return buffer; + } + + while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) + { + buffer->offset++; + } + + if (buffer->offset == buffer->length) + { + buffer->offset--; + } + + return buffer; +} + +/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */ +static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) +{ + if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) + { + return NULL; + } + + if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) + { + buffer->offset += 3; + } + + return buffer; +} + +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) +{ + size_t buffer_length; + + if (NULL == value) + { + return NULL; + } + + /* Adding null character size due to require_null_terminated. */ + buffer_length = strlen(value) + sizeof(""); + + return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated); +} + +/* Parse an object - create a new root, and populate. */ +CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated) +{ + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + cJSON *item = NULL; + + /* reset error position */ + global_error.json = NULL; + global_error.position = 0; + + if (value == NULL || 0 == buffer_length) + { + goto fail; + } + + buffer.content = (const unsigned char*)value; + buffer.length = buffer_length; + buffer.offset = 0; + buffer.hooks = global_hooks; + + item = cJSON_New_Item(&global_hooks); + if (item == NULL) /* memory fail */ + { + goto fail; + } + + if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))) + { + /* parse failure. ep is set. */ + goto fail; + } + + /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ + if (require_null_terminated) + { + buffer_skip_whitespace(&buffer); + if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') + { + goto fail; + } + } + if (return_parse_end) + { + *return_parse_end = (const char*)buffer_at_offset(&buffer); + } + + return item; + +fail: + if (item != NULL) + { + cJSON_Delete(item); + } + + if (value != NULL) + { + error local_error; + local_error.json = (const unsigned char*)value; + local_error.position = 0; + + if (buffer.offset < buffer.length) + { + local_error.position = buffer.offset; + } + else if (buffer.length > 0) + { + local_error.position = buffer.length - 1; + } + + if (return_parse_end != NULL) + { + *return_parse_end = (const char*)local_error.json + local_error.position; + } + + global_error = local_error; + } + + return NULL; +} + +/* Default options for cJSON_Parse */ +CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) +{ + return cJSON_ParseWithOpts(value, 0, 0); +} + +CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length) +{ + return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0); +} + +#define cjson_min(a, b) (((a) < (b)) ? (a) : (b)) + +static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks) +{ + static const size_t default_buffer_size = 256; + printbuffer buffer[1]; + unsigned char *printed = NULL; + + memset(buffer, 0, sizeof(buffer)); + + /* create buffer */ + buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size); + buffer->length = default_buffer_size; + buffer->format = format; + buffer->hooks = *hooks; + if (buffer->buffer == NULL) + { + goto fail; + } + + /* print the value */ + if (!print_value(item, buffer)) + { + goto fail; + } + update_offset(buffer); + + /* check if reallocate is available */ + if (hooks->reallocate != NULL) + { + printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1); + if (printed == NULL) { + goto fail; + } + buffer->buffer = NULL; + } + else /* otherwise copy the JSON over to a new buffer */ + { + printed = (unsigned char*) hooks->allocate(buffer->offset + 1); + if (printed == NULL) + { + goto fail; + } + memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1)); + printed[buffer->offset] = '\0'; /* just to be sure */ + + /* free the buffer */ + hooks->deallocate(buffer->buffer); + } + + return printed; + +fail: + if (buffer->buffer != NULL) + { + hooks->deallocate(buffer->buffer); + } + + if (printed != NULL) + { + hooks->deallocate(printed); + } + + return NULL; +} + +/* Render a cJSON item/entity/structure to text. */ +CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) +{ + return (char*)print(item, true, &global_hooks); +} + +CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) +{ + return (char*)print(item, false, &global_hooks); +} + +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) +{ + printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + + if (prebuffer < 0) + { + return NULL; + } + + p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer); + if (!p.buffer) + { + return NULL; + } + + p.length = (size_t)prebuffer; + p.offset = 0; + p.noalloc = false; + p.format = fmt; + p.hooks = global_hooks; + + if (!print_value(item, &p)) + { + global_hooks.deallocate(p.buffer); + return NULL; + } + + return (char*)p.buffer; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) +{ + printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + + if ((length < 0) || (buffer == NULL)) + { + return false; + } + + p.buffer = (unsigned char*)buffer; + p.length = (size_t)length; + p.offset = 0; + p.noalloc = true; + p.format = format; + p.hooks = global_hooks; + + return print_value(item, &p); +} + +/* Parser core - when encountering text, process appropriately. */ +static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer) +{ + if ((input_buffer == NULL) || (input_buffer->content == NULL)) + { + return false; /* no input */ + } + + /* parse the different types of values */ + /* null */ + if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0)) + { + item->type = cJSON_NULL; + input_buffer->offset += 4; + return true; + } + /* false */ + if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0)) + { + item->type = cJSON_False; + input_buffer->offset += 5; + return true; + } + /* true */ + if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0)) + { + item->type = cJSON_True; + item->valueint = 1; + input_buffer->offset += 4; + return true; + } + /* string */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) + { + return parse_string(item, input_buffer); + } + /* number */ + if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) + { + return parse_number(item, input_buffer); + } + /* array */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) + { + return parse_array(item, input_buffer); + } + /* object */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) + { + return parse_object(item, input_buffer); + } + + return false; +} + +/* Render a value to text. */ +static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output = NULL; + + if ((item == NULL) || (output_buffer == NULL)) + { + return false; + } + + switch ((item->type) & 0xFF) + { + case cJSON_NULL: + output = ensure(output_buffer, 5); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "null"); + return true; + + case cJSON_False: + output = ensure(output_buffer, 6); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "false"); + return true; + + case cJSON_True: + output = ensure(output_buffer, 5); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "true"); + return true; + + case cJSON_Number: + return print_number(item, output_buffer); + + case cJSON_Raw: + { + size_t raw_length = 0; + if (item->valuestring == NULL) + { + return false; + } + + raw_length = strlen(item->valuestring) + sizeof(""); + output = ensure(output_buffer, raw_length); + if (output == NULL) + { + return false; + } + memcpy(output, item->valuestring, raw_length); + return true; + } + + case cJSON_String: + return print_string(item, output_buffer); + + case cJSON_Array: + return print_array(item, output_buffer); + + case cJSON_Object: + return print_object(item, output_buffer); + + default: + return false; + } +} + +/* Build an array from input text. */ +static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer) +{ + cJSON *head = NULL; /* head of the linked list */ + cJSON *current_item = NULL; + + if (input_buffer->depth >= CJSON_NESTING_LIMIT) + { + return false; /* to deeply nested */ + } + input_buffer->depth++; + + if (buffer_at_offset(input_buffer)[0] != '[') + { + /* not an array */ + goto fail; + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) + { + /* empty array */ + goto success; + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) + { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do + { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + if (new_item == NULL) + { + goto fail; /* allocation failure */ + } + + /* attach next item to list */ + if (head == NULL) + { + /* start the linked list */ + current_item = head = new_item; + } + else + { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse next value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_value(current_item, input_buffer)) + { + goto fail; /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + } + while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') + { + goto fail; /* expected end of array */ + } + +success: + input_buffer->depth--; + + if (head != NULL) { + head->prev = current_item; + } + + item->type = cJSON_Array; + item->child = head; + + input_buffer->offset++; + + return true; + +fail: + if (head != NULL) + { + cJSON_Delete(head); + } + + return false; +} + +/* Render an array to text */ +static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + size_t length = 0; + cJSON *current_element = item->child; + + if (output_buffer == NULL) + { + return false; + } + + /* Compose the output array. */ + /* opening square bracket */ + output_pointer = ensure(output_buffer, 1); + if (output_pointer == NULL) + { + return false; + } + + *output_pointer = '['; + output_buffer->offset++; + output_buffer->depth++; + + while (current_element != NULL) + { + if (!print_value(current_element, output_buffer)) + { + return false; + } + update_offset(output_buffer); + if (current_element->next) + { + length = (size_t) (output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ','; + if(output_buffer->format) + { + *output_pointer++ = ' '; + } + *output_pointer = '\0'; + output_buffer->offset += length; + } + current_element = current_element->next; + } + + output_pointer = ensure(output_buffer, 2); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ']'; + *output_pointer = '\0'; + output_buffer->depth--; + + return true; +} + +/* Build an object from the text. */ +static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer) +{ + cJSON *head = NULL; /* linked list head */ + cJSON *current_item = NULL; + + if (input_buffer->depth >= CJSON_NESTING_LIMIT) + { + return false; /* to deeply nested */ + } + input_buffer->depth++; + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) + { + goto fail; /* not an object */ + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) + { + goto success; /* empty object */ + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) + { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do + { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + if (new_item == NULL) + { + goto fail; /* allocation failure */ + } + + /* attach next item to list */ + if (head == NULL) + { + /* start the linked list */ + current_item = head = new_item; + } + else + { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse the name of the child */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_string(current_item, input_buffer)) + { + goto fail; /* failed to parse name */ + } + buffer_skip_whitespace(input_buffer); + + /* swap valuestring and string, because we parsed the name */ + current_item->string = current_item->valuestring; + current_item->valuestring = NULL; + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) + { + goto fail; /* invalid object */ + } + + /* parse the value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_value(current_item, input_buffer)) + { + goto fail; /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + } + while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) + { + goto fail; /* expected end of object */ + } + +success: + input_buffer->depth--; + + if (head != NULL) { + head->prev = current_item; + } + + item->type = cJSON_Object; + item->child = head; + + input_buffer->offset++; + return true; + +fail: + if (head != NULL) + { + cJSON_Delete(head); + } + + return false; +} + +/* Render an object to text. */ +static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + size_t length = 0; + cJSON *current_item = item->child; + + if (output_buffer == NULL) + { + return false; + } + + /* Compose the output: */ + length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */ + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + + *output_pointer++ = '{'; + output_buffer->depth++; + if (output_buffer->format) + { + *output_pointer++ = '\n'; + } + output_buffer->offset += length; + + while (current_item) + { + if (output_buffer->format) + { + size_t i; + output_pointer = ensure(output_buffer, output_buffer->depth); + if (output_pointer == NULL) + { + return false; + } + for (i = 0; i < output_buffer->depth; i++) + { + *output_pointer++ = '\t'; + } + output_buffer->offset += output_buffer->depth; + } + + /* print key */ + if (!print_string_ptr((unsigned char*)current_item->string, output_buffer)) + { + return false; + } + update_offset(output_buffer); + + length = (size_t) (output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ':'; + if (output_buffer->format) + { + *output_pointer++ = '\t'; + } + output_buffer->offset += length; + + /* print value */ + if (!print_value(current_item, output_buffer)) + { + return false; + } + update_offset(output_buffer); + + /* print comma if not last */ + length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0)); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + if (current_item->next) + { + *output_pointer++ = ','; + } + + if (output_buffer->format) + { + *output_pointer++ = '\n'; + } + *output_pointer = '\0'; + output_buffer->offset += length; + + current_item = current_item->next; + } + + output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2); + if (output_pointer == NULL) + { + return false; + } + if (output_buffer->format) + { + size_t i; + for (i = 0; i < (output_buffer->depth - 1); i++) + { + *output_pointer++ = '\t'; + } + } + *output_pointer++ = '}'; + *output_pointer = '\0'; + output_buffer->depth--; + + return true; +} + +/* Get Array size/item / object item. */ +CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) +{ + cJSON *child = NULL; + size_t size = 0; + + if (array == NULL) + { + return 0; + } + + child = array->child; + + while(child != NULL) + { + size++; + child = child->next; + } + + /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ + + return (int)size; +} + +static cJSON* get_array_item(const cJSON *array, size_t index) +{ + cJSON *current_child = NULL; + + if (array == NULL) + { + return NULL; + } + + current_child = array->child; + while ((current_child != NULL) && (index > 0)) + { + index--; + current_child = current_child->next; + } + + return current_child; +} + +CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index) +{ + if (index < 0) + { + return NULL; + } + + return get_array_item(array, (size_t)index); +} + +static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive) +{ + cJSON *current_element = NULL; + + if ((object == NULL) || (name == NULL)) + { + return NULL; + } + + current_element = object->child; + if (case_sensitive) + { + while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0)) + { + current_element = current_element->next; + } + } + else + { + while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0)) + { + current_element = current_element->next; + } + } + + if ((current_element == NULL) || (current_element->string == NULL)) { + return NULL; + } + + return current_element; +} + +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string) +{ + return get_object_item(object, string, false); +} + +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) +{ + return get_object_item(object, string, true); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string) +{ + return cJSON_GetObjectItem(object, string) ? 1 : 0; +} + +/* Utility for array list handling. */ +static void suffix_object(cJSON *prev, cJSON *item) +{ + prev->next = item; + item->prev = prev; +} + +/* Utility for handling references. */ +static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks) +{ + cJSON *reference = NULL; + if (item == NULL) + { + return NULL; + } + + reference = cJSON_New_Item(hooks); + if (reference == NULL) + { + return NULL; + } + + memcpy(reference, item, sizeof(cJSON)); + reference->string = NULL; + reference->type |= cJSON_IsReference; + reference->next = reference->prev = NULL; + return reference; +} + +static cJSON_bool add_item_to_array(cJSON *array, cJSON *item) +{ + cJSON *child = NULL; + + if ((item == NULL) || (array == NULL) || (array == item)) + { + return false; + } + + child = array->child; + /* + * To find the last item in array quickly, we use prev in array + */ + if (child == NULL) + { + /* list is empty, start new one */ + array->child = item; + item->prev = item; + item->next = NULL; + } + else + { + /* append to the end */ + if (child->prev) + { + suffix_object(child->prev, item); + array->child->prev = item; + } + } + + return true; +} + +/* Add item to array/object. */ +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item) +{ + return add_item_to_array(array, item); +} + +#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) + #pragma GCC diagnostic push +#endif +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif +/* helper function to cast away const */ +static void* cast_away_const(const void* string) +{ + return (void*)string; +} +#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) + #pragma GCC diagnostic pop +#endif + + +static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key) +{ + char *new_key = NULL; + int new_type = cJSON_Invalid; + + if ((object == NULL) || (string == NULL) || (item == NULL) || (object == item)) + { + return false; + } + + if (constant_key) + { + new_key = (char*)cast_away_const(string); + new_type = item->type | cJSON_StringIsConst; + } + else + { + new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks); + if (new_key == NULL) + { + return false; + } + + new_type = item->type & ~cJSON_StringIsConst; + } + + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) + { + hooks->deallocate(item->string); + } + + item->string = new_key; + item->type = new_type; + + return add_item_to_array(object, item); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) +{ + return add_item_to_object(object, string, item, &global_hooks, false); +} + +/* Add an item to an object with constant string as key */ +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) +{ + return add_item_to_object(object, string, item, &global_hooks, true); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) +{ + if (array == NULL) + { + return false; + } + + return add_item_to_array(array, create_reference(item, &global_hooks)); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) +{ + if ((object == NULL) || (string == NULL)) + { + return false; + } + + return add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false); +} + +CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name) +{ + cJSON *null = cJSON_CreateNull(); + if (add_item_to_object(object, name, null, &global_hooks, false)) + { + return null; + } + + cJSON_Delete(null); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name) +{ + cJSON *true_item = cJSON_CreateTrue(); + if (add_item_to_object(object, name, true_item, &global_hooks, false)) + { + return true_item; + } + + cJSON_Delete(true_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name) +{ + cJSON *false_item = cJSON_CreateFalse(); + if (add_item_to_object(object, name, false_item, &global_hooks, false)) + { + return false_item; + } + + cJSON_Delete(false_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean) +{ + cJSON *bool_item = cJSON_CreateBool(boolean); + if (add_item_to_object(object, name, bool_item, &global_hooks, false)) + { + return bool_item; + } + + cJSON_Delete(bool_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number) +{ + cJSON *number_item = cJSON_CreateNumber(number); + if (add_item_to_object(object, name, number_item, &global_hooks, false)) + { + return number_item; + } + + cJSON_Delete(number_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string) +{ + cJSON *string_item = cJSON_CreateString(string); + if (add_item_to_object(object, name, string_item, &global_hooks, false)) + { + return string_item; + } + + cJSON_Delete(string_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw) +{ + cJSON *raw_item = cJSON_CreateRaw(raw); + if (add_item_to_object(object, name, raw_item, &global_hooks, false)) + { + return raw_item; + } + + cJSON_Delete(raw_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name) +{ + cJSON *object_item = cJSON_CreateObject(); + if (add_item_to_object(object, name, object_item, &global_hooks, false)) + { + return object_item; + } + + cJSON_Delete(object_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name) +{ + cJSON *array = cJSON_CreateArray(); + if (add_item_to_object(object, name, array, &global_hooks, false)) + { + return array; + } + + cJSON_Delete(array); + return NULL; +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) +{ + if ((parent == NULL) || (item == NULL)) + { + return NULL; + } + + if (item != parent->child) + { + /* not the first element */ + item->prev->next = item->next; + } + if (item->next != NULL) + { + /* not the last element */ + item->next->prev = item->prev; + } + + if (item == parent->child) + { + /* first element */ + parent->child = item->next; + } + else if (item->next == NULL) + { + /* last element */ + parent->child->prev = item->prev; + } + + /* make sure the detached item doesn't point anywhere anymore */ + item->prev = NULL; + item->next = NULL; + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which) +{ + if (which < 0) + { + return NULL; + } + + return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which)); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) +{ + cJSON_Delete(cJSON_DetachItemFromArray(array, which)); +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string) +{ + cJSON *to_detach = cJSON_GetObjectItem(object, string); + + return cJSON_DetachItemViaPointer(object, to_detach); +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string) +{ + cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string); + + return cJSON_DetachItemViaPointer(object, to_detach); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) +{ + cJSON_Delete(cJSON_DetachItemFromObject(object, string)); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string) +{ + cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string)); +} + +/* Replace array/object items with new ones. */ +CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) +{ + cJSON *after_inserted = NULL; + + if (which < 0) + { + return false; + } + + after_inserted = get_array_item(array, (size_t)which); + if (after_inserted == NULL) + { + return add_item_to_array(array, newitem); + } + + newitem->next = after_inserted; + newitem->prev = after_inserted->prev; + after_inserted->prev = newitem; + if (after_inserted == array->child) + { + array->child = newitem; + } + else + { + newitem->prev->next = newitem; + } + return true; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement) +{ + if ((parent == NULL) || (replacement == NULL) || (item == NULL)) + { + return false; + } + + if (replacement == item) + { + return true; + } + + replacement->next = item->next; + replacement->prev = item->prev; + + if (replacement->next != NULL) + { + replacement->next->prev = replacement; + } + if (parent->child == item) + { + if (parent->child->prev == parent->child) + { + replacement->prev = replacement; + } + parent->child = replacement; + } + else + { /* + * To find the last item in array quickly, we use prev in array. + * We can't modify the last item's next pointer where this item was the parent's child + */ + if (replacement->prev != NULL) + { + replacement->prev->next = replacement; + } + if (replacement->next == NULL) + { + parent->child->prev = replacement; + } + } + + item->next = NULL; + item->prev = NULL; + cJSON_Delete(item); + + return true; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) +{ + if (which < 0) + { + return false; + } + + return cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem); +} + +static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive) +{ + if ((replacement == NULL) || (string == NULL)) + { + return false; + } + + /* replace the name in the replacement */ + if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL)) + { + cJSON_free(replacement->string); + } + replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); + replacement->type &= ~cJSON_StringIsConst; + + return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) +{ + return replace_item_in_object(object, string, newitem, false); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) +{ + return replace_item_in_object(object, string, newitem, true); +} + +/* Create basic types: */ +CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_NULL; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_True; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_False; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = boolean ? cJSON_True : cJSON_False; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_Number; + item->valuedouble = num; + + /* use saturation in case of overflow */ + if (num >= INT_MAX) + { + item->valueint = INT_MAX; + } + else if (num <= (double)INT_MIN) + { + item->valueint = INT_MIN; + } + else + { + item->valueint = (int)num; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_String; + item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); + if(!item->valuestring) + { + cJSON_Delete(item); + return NULL; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) + { + item->type = cJSON_String | cJSON_IsReference; + item->valuestring = (char*)cast_away_const(string); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) { + item->type = cJSON_Object | cJSON_IsReference; + item->child = (cJSON*)cast_away_const(child); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) { + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) { + item->type = cJSON_Array | cJSON_IsReference; + item->child = (cJSON*)cast_away_const(child); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_Raw; + item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks); + if(!item->valuestring) + { + cJSON_Delete(item); + return NULL; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type=cJSON_Array; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item) + { + item->type = cJSON_Object; + } + + return item; +} + +/* Create Arrays: */ +CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for(i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber(numbers[i]); + if (!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + if (a && a->child) { + a->child->prev = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for(i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber((double)numbers[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + if (a && a->child) { + a->child->prev = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for(i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber(numbers[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + if (a && a->child) { + a->child->prev = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (strings == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for (i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateString(strings[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p,n); + } + p = n; + } + + if (a && a->child) { + a->child->prev = n; + } + + return a; +} + +/* Duplication */ +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) +{ + cJSON *newitem = NULL; + cJSON *child = NULL; + cJSON *next = NULL; + cJSON *newchild = NULL; + + /* Bail on bad ptr */ + if (!item) + { + goto fail; + } + /* Create new item */ + newitem = cJSON_New_Item(&global_hooks); + if (!newitem) + { + goto fail; + } + /* Copy over all vars */ + newitem->type = item->type & (~cJSON_IsReference); + newitem->valueint = item->valueint; + newitem->valuedouble = item->valuedouble; + if (item->valuestring) + { + newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks); + if (!newitem->valuestring) + { + goto fail; + } + } + if (item->string) + { + newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks); + if (!newitem->string) + { + goto fail; + } + } + /* If non-recursive, then we're done! */ + if (!recurse) + { + return newitem; + } + /* Walk the ->next chain for the child. */ + child = item->child; + while (child != NULL) + { + newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ + if (!newchild) + { + goto fail; + } + if (next != NULL) + { + /* If newitem->child already set, then crosswire ->prev and ->next and move on */ + next->next = newchild; + newchild->prev = next; + next = newchild; + } + else + { + /* Set newitem->child and move to it */ + newitem->child = newchild; + next = newchild; + } + child = child->next; + } + if (newitem && newitem->child) + { + newitem->child->prev = newchild; + } + + return newitem; + +fail: + if (newitem != NULL) + { + cJSON_Delete(newitem); + } + + return NULL; +} + +static void skip_oneline_comment(char **input) +{ + *input += static_strlen("//"); + + for (; (*input)[0] != '\0'; ++(*input)) + { + if ((*input)[0] == '\n') { + *input += static_strlen("\n"); + return; + } + } +} + +static void skip_multiline_comment(char **input) +{ + *input += static_strlen("/*"); + + for (; (*input)[0] != '\0'; ++(*input)) + { + if (((*input)[0] == '*') && ((*input)[1] == '/')) + { + *input += static_strlen("*/"); + return; + } + } +} + +static void minify_string(char **input, char **output) { + (*output)[0] = (*input)[0]; + *input += static_strlen("\""); + *output += static_strlen("\""); + + + for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) { + (*output)[0] = (*input)[0]; + + if ((*input)[0] == '\"') { + (*output)[0] = '\"'; + *input += static_strlen("\""); + *output += static_strlen("\""); + return; + } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) { + (*output)[1] = (*input)[1]; + *input += static_strlen("\""); + *output += static_strlen("\""); + } + } +} + +CJSON_PUBLIC(void) cJSON_Minify(char *json) +{ + char *into = json; + + if (json == NULL) + { + return; + } + + while (json[0] != '\0') + { + switch (json[0]) + { + case ' ': + case '\t': + case '\r': + case '\n': + json++; + break; + + case '/': + if (json[1] == '/') + { + skip_oneline_comment(&json); + } + else if (json[1] == '*') + { + skip_multiline_comment(&json); + } else { + json++; + } + break; + + case '\"': + minify_string(&json, (char**)&into); + break; + + default: + into[0] = json[0]; + json++; + into++; + } + } + + /* and null-terminate. */ + *into = '\0'; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Invalid; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_False; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xff) == cJSON_True; +} + + +CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & (cJSON_True | cJSON_False)) != 0; +} +CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_NULL; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Number; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_String; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Array; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Object; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Raw; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive) +{ + if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) + { + return false; + } + + /* check if type is valid */ + switch (a->type & 0xFF) + { + case cJSON_False: + case cJSON_True: + case cJSON_NULL: + case cJSON_Number: + case cJSON_String: + case cJSON_Raw: + case cJSON_Array: + case cJSON_Object: + break; + + default: + return false; + } + + /* identical objects are equal */ + if (a == b) + { + return true; + } + + switch (a->type & 0xFF) + { + /* in these cases and equal type is enough */ + case cJSON_False: + case cJSON_True: + case cJSON_NULL: + return true; + + case cJSON_Number: + if (compare_double(a->valuedouble, b->valuedouble)) + { + return true; + } + return false; + + case cJSON_String: + case cJSON_Raw: + if ((a->valuestring == NULL) || (b->valuestring == NULL)) + { + return false; + } + if (strcmp(a->valuestring, b->valuestring) == 0) + { + return true; + } + + return false; + + case cJSON_Array: + { + cJSON *a_element = a->child; + cJSON *b_element = b->child; + + for (; (a_element != NULL) && (b_element != NULL);) + { + if (!cJSON_Compare(a_element, b_element, case_sensitive)) + { + return false; + } + + a_element = a_element->next; + b_element = b_element->next; + } + + /* one of the arrays is longer than the other */ + if (a_element != b_element) { + return false; + } + + return true; + } + + case cJSON_Object: + { + cJSON *a_element = NULL; + cJSON *b_element = NULL; + cJSON_ArrayForEach(a_element, a) + { + /* TODO This has O(n^2) runtime, which is horrible! */ + b_element = get_object_item(b, a_element->string, case_sensitive); + if (b_element == NULL) + { + return false; + } + + if (!cJSON_Compare(a_element, b_element, case_sensitive)) + { + return false; + } + } + + /* doing this twice, once on a and b to prevent true comparison if a subset of b + * TODO: Do this the proper way, this is just a fix for now */ + cJSON_ArrayForEach(b_element, b) + { + a_element = get_object_item(a, b_element->string, case_sensitive); + if (a_element == NULL) + { + return false; + } + + if (!cJSON_Compare(b_element, a_element, case_sensitive)) + { + return false; + } + } + + return true; + } + + default: + return false; + } +} + +CJSON_PUBLIC(void *) cJSON_malloc(size_t size) +{ + return global_hooks.allocate(size); +} + +CJSON_PUBLIC(void) cJSON_free(void *object) +{ + global_hooks.deallocate(object); +} diff --git a/APP_Framework/Applications/knowing_app/instrusion_detect/cJSON.h b/APP_Framework/Applications/knowing_app/instrusion_detect/cJSON.h new file mode 100644 index 00000000..e97e5f4c --- /dev/null +++ b/APP_Framework/Applications/knowing_app/instrusion_detect/cJSON.h @@ -0,0 +1,293 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef cJSON__h +#define cJSON__h + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) +#define __WINDOWS__ +#endif + +#ifdef __WINDOWS__ + +/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options: + +CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols +CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) +CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol + +For *nix builds that support visibility attribute, you can define similar behavior by + +setting default visibility to hidden by adding +-fvisibility=hidden (for gcc) +or +-xldscope=hidden (for sun cc) +to CFLAGS + +then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does + +*/ + +#define CJSON_CDECL __cdecl +#define CJSON_STDCALL __stdcall + +/* export symbols by default, this is necessary for copy pasting the C and header file */ +#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_EXPORT_SYMBOLS +#endif + +#if defined(CJSON_HIDE_SYMBOLS) +#define CJSON_PUBLIC(type) type CJSON_STDCALL +#elif defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL +#elif defined(CJSON_IMPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL +#endif +#else /* !__WINDOWS__ */ +#define CJSON_CDECL +#define CJSON_STDCALL + +#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) +#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type +#else +#define CJSON_PUBLIC(type) type +#endif +#endif + +/* project version */ +#define CJSON_VERSION_MAJOR 1 +#define CJSON_VERSION_MINOR 7 +#define CJSON_VERSION_PATCH 14 + +#include + +/* cJSON Types: */ +#define cJSON_Invalid (0) +#define cJSON_False (1 << 0) +#define cJSON_True (1 << 1) +#define cJSON_NULL (1 << 2) +#define cJSON_Number (1 << 3) +#define cJSON_String (1 << 4) +#define cJSON_Array (1 << 5) +#define cJSON_Object (1 << 6) +#define cJSON_Raw (1 << 7) /* raw json */ + +#define cJSON_IsReference 256 +#define cJSON_StringIsConst 512 + +/* The cJSON structure: */ +typedef struct cJSON +{ + /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ + struct cJSON *next; + struct cJSON *prev; + /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ + struct cJSON *child; + + /* The type of the item, as above. */ + int type; + + /* The item's string, if type==cJSON_String and type == cJSON_Raw */ + char *valuestring; + /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ + int valueint; + /* The item's number, if type==cJSON_Number */ + double valuedouble; + + /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ + char *string; +} cJSON; + +typedef struct cJSON_Hooks +{ + /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */ + void *(CJSON_CDECL *malloc_fn)(size_t sz); + void (CJSON_CDECL *free_fn)(void *ptr); +} cJSON_Hooks; + +typedef int cJSON_bool; + +/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them. + * This is to prevent stack overflows. */ +#ifndef CJSON_NESTING_LIMIT +#define CJSON_NESTING_LIMIT 1000 +#endif + +/* returns the version of cJSON as a string */ +CJSON_PUBLIC(const char*) cJSON_Version(void); + +/* Supply malloc, realloc and free functions to cJSON */ +CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); + +/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ +/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ +CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); +CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length); +/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ +/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */ +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); +CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated); + +/* Render a cJSON entity to text for transfer/storage. */ +CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); +/* Render a cJSON entity to text for transfer/storage without any formatting. */ +CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); +/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); +/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ +/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); +/* Delete a cJSON entity and all subentities. */ +CJSON_PUBLIC(void) cJSON_Delete(cJSON *item); + +/* Returns the number of items in an array (or object). */ +CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); +/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */ +CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); +/* Get item "string" from object. Case insensitive. */ +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); +CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string); +/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ +CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); + +/* Check item type and return its value */ +CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item); +CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item); + +/* These functions check the type of an item */ +CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item); + +/* These calls create a cJSON item of the appropriate type. */ +CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); +CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); +CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); +/* raw json */ +CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); +CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); + +/* Create a string where valuestring references a string so + * it will not be freed by cJSON_Delete */ +CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); +/* Create an object/array that only references it's elements so + * they will not be freed by cJSON_Delete */ +CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); +CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); + +/* These utilities create an Array of count items. + * The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/ +CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count); + +/* Append item to the specified array/object. */ +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item); +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); +/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. + * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before + * writing to `item->string` */ +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); +/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); + +/* Remove/Detach items from Arrays/Objects. */ +CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); +CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); +CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); +CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); + +/* Update array items. */ +CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem); + +/* Duplicate a cJSON item */ +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); +/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will + * need to be released. With recurse!=0, it will duplicate any children connected to the item. + * The item->next and ->prev pointers are always zero on return from Duplicate. */ +/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal. + * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ +CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); + +/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings. + * The input pointer json cannot point to a read-only address area, such as a string constant, + * but should point to a readable and writable adress area. */ +CJSON_PUBLIC(void) cJSON_Minify(char *json); + +/* Helper functions for creating and adding items to an object at the same time. + * They return the added item or NULL on failure. */ +CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean); +CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number); +CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string); +CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw); +CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name); + +/* When assigning an integer value, it needs to be propagated to valuedouble too. */ +#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) +/* helper for the cJSON_SetNumberValue macro */ +CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); +#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) +/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */ +CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring); + +/* Macro for iterating over an array or object */ +#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) + +/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ +CJSON_PUBLIC(void *) cJSON_malloc(size_t size); +CJSON_PUBLIC(void) cJSON_free(void *object); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/APP_Framework/Applications/knowing_app/instrusion_detect/human.json b/APP_Framework/Applications/knowing_app/instrusion_detect/human.json new file mode 100644 index 00000000..bf8ca5c1 --- /dev/null +++ b/APP_Framework/Applications/knowing_app/instrusion_detect/human.json @@ -0,0 +1,31 @@ +{ + "net_input_size": [ + 224, + 320 + ], + "net_output_shape": [ + 10, + 7, + 30 + ], + "sensor_output_size": [ + 240, + 320 + ], + "anchors": [ + 1.0432, + 1.0920, + 0.8391, + 2.1250, + 1.1085, + 2.7463, + 1.3783, + 3.6706, + 2.0491, + 4.6711 + ], + "kmodel_path": "/kmodel/human.kmodel", + "kmodel_size": 1903016, + "obj_thresh": 0.3, + "nms_thresh": 0.3 +} \ No newline at end of file diff --git a/APP_Framework/Applications/knowing_app/instrusion_detect/instrusion_detect.c b/APP_Framework/Applications/knowing_app/instrusion_detect/instrusion_detect.c new file mode 100644 index 00000000..541ef7d6 --- /dev/null +++ b/APP_Framework/Applications/knowing_app/instrusion_detect/instrusion_detect.c @@ -0,0 +1,350 @@ +#include + +#include "cJSON.h" +#include "region_layer.h" +#define ANCHOR_NUM 5 +#define STACK_SIZE (128 * 1024) +#define JSON_FILE_PATH "/kmodel/human.json" +#define JSON_BUFFER_SIZE (4 * 1024) + +// params from json +float anchor[ANCHOR_NUM * 2] = {}; +int net_output_shape[3] = {}; +int net_input_size[2] = {}; +int sensor_output_size[2] = {}; +char kmodel_path[127] = ""; +int kmodel_size = 0; +float obj_thresh = 1.0; +float nms_thresh = 0.0; + +#define THREAD_PRIORITY_HUMAN_D (11) +static pthread_t instrusiontid = 0; +static void *thread_instrusion_detect_entry(void *parameter); +static int g_fd = 0; +static int kmodel_fd = 0; +static int if_exit = 0; +static unsigned char *showbuffer = NULL; +static unsigned char *kpurgbbuffer = NULL; + +static _ioctl_shoot_para shoot_para_t = {0}; +unsigned char *model_data = NULL; // kpu data load memory +unsigned char *model_data_align = NULL; + +kpu_model_context_t instrusion_detect_task; +static region_layer_t instrusion_detect_rl; +static obj_info_t instrusion_detect_info; +volatile uint32_t g_ai_done_flag; + +static void ai_done(void *ctx) { g_ai_done_flag = 1; } + +static void param_parse() +{ + int fin; + char buffer[JSON_BUFFER_SIZE] = ""; + // char *buffer; + // if (NULL != (buffer = (char*)malloc(JSON_BUFFER_SIZE * sizeof(char)))) { + // memset(buffer, 0, JSON_BUFFER_SIZE * sizeof(char)); + // } else { + // printf("Json buffer malloc failed!"); + // exit(-1); + // } + int array_size; + cJSON *json_obj; + cJSON *json_item; + cJSON *json_array_item; + + fin = open(JSON_FILE_PATH, O_RDONLY); + if (!fin) { + printf("Error open file %s", JSON_FILE_PATH); + exit(-1); + } + read(fin, buffer, sizeof(buffer)); + close(fin); + + // read json string + json_obj = cJSON_Parse(buffer); + // free(buffer); + char *json_print_str = cJSON_Print(json_obj); + printf("Json file content: \n%s\n", json_print_str); + cJSON_free(json_print_str); + // get anchors + json_item = cJSON_GetObjectItem(json_obj, "anchors"); + array_size = cJSON_GetArraySize(json_item); + if (ANCHOR_NUM * 2 != array_size) { + printf("Expect anchor size: %d, got %d in json file", ANCHOR_NUM * 2, array_size); + exit(-1); + } else { + printf("Got %d anchors from json file\n", ANCHOR_NUM); + } + for (int i = 0; i < ANCHOR_NUM * 2; i++) { + json_array_item = cJSON_GetArrayItem(json_item, i); + anchor[i] = json_array_item->valuedouble; + printf("%d: %f\n", i, anchor[i]); + } + // net_input_size + json_item = cJSON_GetObjectItem(json_obj, "net_input_size"); + array_size = cJSON_GetArraySize(json_item); + if (2 != array_size) { + printf("Expect net_input_size: %d, got %d in json file", 2, array_size); + exit(-1); + } else { + printf("Got %d net_input_size from json file\n", 2); + } + for (int i = 0; i < 2; i++) { + json_array_item = cJSON_GetArrayItem(json_item, i); + net_input_size[i] = json_array_item->valueint; + printf("%d: %d\n", i, net_input_size[i]); + } + // net_output_shape + json_item = cJSON_GetObjectItem(json_obj, "net_output_shape"); + array_size = cJSON_GetArraySize(json_item); + if (3 != array_size) { + printf("Expect net_output_shape: %d, got %d in json file", 3, array_size); + exit(-1); + } else { + printf("Got %d net_output_shape from json file\n", 3); + } + for (int i = 0; i < 3; i++) { + json_array_item = cJSON_GetArrayItem(json_item, i); + net_output_shape[i] = json_array_item->valueint; + printf("%d: %d\n", i, net_output_shape[i]); + } + // sensor_output_size + json_item = cJSON_GetObjectItem(json_obj, "sensor_output_size"); + array_size = cJSON_GetArraySize(json_item); + if (2 != array_size) { + printf("Expect sensor_output_size: %d, got %d in json file", 2, array_size); + exit(-1); + } else { + printf("Got %d sensor_output_size from json file\n", 2); + } + for (int i = 0; i < 2; i++) { + json_array_item = cJSON_GetArrayItem(json_item, i); + sensor_output_size[i] = json_array_item->valueint; + printf("%d: %d\n", i, sensor_output_size[i]); + } + // kmodel_path + json_item = cJSON_GetObjectItem(json_obj, "kmodel_path"); + memcpy(kmodel_path, json_item->valuestring, strlen(json_item->valuestring)); + printf("Got kmodel_path: %s\n", kmodel_path); + // kmodel_size + json_item = cJSON_GetObjectItem(json_obj, "kmodel_size"); + kmodel_size = json_item->valueint; + printf("Got kmodel_size: %d\n", kmodel_size); + // obj_thresh + json_item = cJSON_GetObjectItem(json_obj, "obj_thresh"); + obj_thresh = json_item->valuedouble; + printf("Got obj_thresh: %f\n", obj_thresh); + // nms_thresh + json_item = cJSON_GetObjectItem(json_obj, "nms_thresh"); + nms_thresh = json_item->valuedouble; + printf("Got nms_thresh: %f\n", nms_thresh); + + cJSON_Delete(json_obj); + return; +} + +void instrusion_detect() +{ + int ret = 0; + int result = 0; + int size = 0; + param_parse(); + g_fd = open("/dev/ov2640", O_RDONLY); + if (g_fd < 0) { + printf("open ov2640 fail !!"); + return; + } + showbuffer = (unsigned char *)malloc(sensor_output_size[0] * sensor_output_size[1] * 2); + if (NULL == showbuffer) { + close(g_fd); + printf("showbuffer apply memory fail !!"); + return; + } + kpurgbbuffer = (unsigned char *)malloc(net_input_size[0] * net_input_size[1] * 3); + if (NULL == kpurgbbuffer) { + close(g_fd); + free(showbuffer); + printf("kpurgbbuffer apply memory fail !!"); + return; + } + model_data = (unsigned char *)malloc(kmodel_size + 255); + if (NULL == model_data) { + free(showbuffer); + free(kpurgbbuffer); + close(g_fd); + printf("model_data apply memory fail !!"); + return; + } + memset(model_data, 0, kmodel_size + 255); + memset(showbuffer, 0, sensor_output_size[0] * sensor_output_size[1] * 2); + memset(kpurgbbuffer, 127, net_input_size[0] * net_input_size[1] * 3); + shoot_para_t.pdata = (unsigned int *)(showbuffer); + shoot_para_t.length = (size_t)(sensor_output_size[0] * sensor_output_size[1] * 2); + /* + load memory + */ + kmodel_fd = open(kmodel_path, O_RDONLY); + if (kmodel_fd < 0) { + printf("open kmodel fail"); + close(g_fd); + free(showbuffer); + free(kpurgbbuffer); + free(model_data); + return; + } else { + size = read(kmodel_fd, model_data, kmodel_size); + if (size != kmodel_size) { + printf("read kmodel error size %d\n", size); + close(g_fd); + close(kmodel_fd); + free(showbuffer); + free(kpurgbbuffer); + free(model_data); + return; + + } else { + printf("read kmodel success \n"); + } + } + unsigned char *model_data_align = (unsigned char *)(((unsigned int)model_data + 255) & (~255)); + dvp_set_ai_addr((uint32_t)(kpurgbbuffer + net_input_size[1] * (net_input_size[0] - sensor_output_size[0])), + (uint32_t)(kpurgbbuffer + net_input_size[1] * (net_input_size[0] - sensor_output_size[0]) + + net_input_size[0] * net_input_size[1]), + (uint32_t)(kpurgbbuffer + net_input_size[0] * net_input_size[1] * 2 + + net_input_size[1] * (net_input_size[0] - sensor_output_size[0]))); + if (kpu_load_kmodel(&instrusion_detect_task, model_data_align) != 0) { + printf("\nmodel init error\n"); + close(g_fd); + close(kmodel_fd); + free(showbuffer); + free(kpurgbbuffer); + free(model_data); + return; + } + instrusion_detect_rl.anchor_number = ANCHOR_NUM; + instrusion_detect_rl.anchor = anchor; + instrusion_detect_rl.threshold = obj_thresh; + instrusion_detect_rl.nms_value = nms_thresh; + result = region_layer_init(&instrusion_detect_rl, net_output_shape[0], net_output_shape[1], net_output_shape[2], + net_input_size[1], net_input_size[0]); + printf("region_layer_init result %d \n\r", result); + size_t stack_size = STACK_SIZE; + pthread_attr_t attr; /* 线程属性 */ + struct sched_param prio; /* 线程优先级 */ + prio.sched_priority = 8; /* 优先级设置为 8 */ + pthread_attr_init(&attr); /* 先使用默认值初始化属性 */ + pthread_attr_setschedparam(&attr, &prio); /* 修改属性对应的优先级 */ + pthread_attr_setstacksize(&attr, stack_size); + + /* 创建线程 1, 属性为 attr,入口函数是 thread_entry,入口函数参数是 1 */ + result = pthread_create(&instrusiontid, &attr, thread_instrusion_detect_entry, NULL); + if (0 == result) { + printf("thread_instrusion_detect_entry successfully!\n"); + } else { + printf("thread_instrusion_detect_entry failed! error code is %d\n", result); + close(g_fd); + } +} +#ifdef __RT_THREAD_H__ +MSH_CMD_EXPORT(instrusion_detect, instrusion detect task); +#endif + +static void *thread_instrusion_detect_entry(void *parameter) +{ + extern void lcd_draw_picture(uint16_t x1, uint16_t y1, uint16_t width, uint16_t height, uint32_t * ptr); + printf("thread_instrusion_detect_entry start!\n"); + int ret = 0; + // sysctl_enable_irq(); + while (1) { + // memset(showbuffer,0,320*240*2); + g_ai_done_flag = 0; + ret = ioctl(g_fd, IOCTRL_CAMERA_START_SHOT, &shoot_para_t); + if (RT_ERROR == ret) { + printf("ov2640 can't wait event flag"); + rt_free(showbuffer); + close(g_fd); + pthread_exit(NULL); + return NULL; + } + kpu_run_kmodel(&instrusion_detect_task, kpurgbbuffer, DMAC_CHANNEL5, ai_done, NULL); + while (!g_ai_done_flag) + ; + float *output; + size_t output_size; + kpu_get_output(&instrusion_detect_task, 0, (uint8_t **)&output, &output_size); + instrusion_detect_rl.input = output; + region_layer_run(&instrusion_detect_rl, &instrusion_detect_info); +/* display result */ +#ifdef BSP_USING_LCD + for (int instrusion_cnt = 0; instrusion_cnt < instrusion_detect_info.obj_number; instrusion_cnt++) { + // draw_edge((uint32_t *)showbuffer, &instrusion_detect_info, instrusion_cnt, 0xF800, + // (uint16_t)sensor_output_size[1], + // (uint16_t)sensor_output_size[0]); + printf("%d: (%d, %d, %d, %d) cls: %d conf: %f\t", instrusion_cnt, instrusion_detect_info.obj[instrusion_cnt].x1, + instrusion_detect_info.obj[instrusion_cnt].y1, instrusion_detect_info.obj[instrusion_cnt].x2, + instrusion_detect_info.obj[instrusion_cnt].y2, instrusion_detect_info.obj[instrusion_cnt].class_id, + instrusion_detect_info.obj[instrusion_cnt].prob); + } + if (0 != instrusion_detect_info.obj_number) { + printf("\n"); + } else { + printf("No human found!\n"); + } + lcd_draw_picture(0, 0, (uint16_t)sensor_output_size[1], (uint16_t)sensor_output_size[0], (unsigned int *)showbuffer); +#endif + usleep(1); + if (1 == if_exit) { + if_exit = 0; + printf("thread_instrusion_detect_entry exit"); + pthread_exit(NULL); + } + } +} + +void instrusion_detect_delete() +{ + if (showbuffer != NULL) { + int ret = 0; + close(g_fd); + close(kmodel_fd); + free(showbuffer); + free(kpurgbbuffer); + free(model_data); + printf("instrusion detect task cancel!!! ret %d ", ret); + if_exit = 1; + } +} +#ifdef __RT_THREAD_H__ +MSH_CMD_EXPORT(instrusion_detect_delete, instrusion detect task delete); +#endif + +void kmodel_load(unsigned char *model_data) +{ + int kmodel_fd = 0; + int size = 0; + kmodel_fd = open(kmodel_path, O_RDONLY); + + model_data = (unsigned char *)malloc(kmodel_size + 255); + if (NULL == model_data) { + printf("model_data apply memory fail !!"); + return; + } + memset(model_data, 0, kmodel_size + 255); + + if (kmodel_fd >= 0) { + size = read(kmodel_fd, model_data, kmodel_size); + if (size != kmodel_size) { + printf("read kmodel error size %d\n", size); + + } else { + printf("read kmodel success"); + } + } else { + free(model_data); + printf("open kmodel fail"); + } +} +#ifdef __RT_THREAD_H__ +MSH_CMD_EXPORT(kmodel_load, kmodel load memory); +#endif From 21f57bf2293301645b4eb110105ca1f838976ff3 Mon Sep 17 00:00:00 2001 From: Liu Yongkai <506680965@qq.com> Date: Wed, 4 Aug 2021 17:45:56 +0800 Subject: [PATCH 06/18] feat(helmet detect): add knowing app helmet detect --- .../Applications/knowing_app/Kconfig | 1 + .../knowing_app/helmet_detect/Kconfig | 7 + .../knowing_app/helmet_detect/SConscript | 9 + .../knowing_app/helmet_detect/cJSON.c | 3110 +++++++++++++++++ .../knowing_app/helmet_detect/cJSON.h | 293 ++ .../knowing_app/helmet_detect/helmet.json | 38 + .../knowing_app/helmet_detect/helmet_detect.c | 379 ++ .../knowing_app/instrusion_detect/human.json | 7 +- .../instrusion_detect/instrusion_detect.c | 37 +- .../kpu-postprocessing/yolov2/region_layer.c | 8 +- .../kpu-postprocessing/yolov2/region_layer.h | 2 +- .../RT_Thread/bsp/k210/base-drivers/drv_dvp.c | 3 +- 12 files changed, 3883 insertions(+), 11 deletions(-) create mode 100644 APP_Framework/Applications/knowing_app/helmet_detect/Kconfig create mode 100644 APP_Framework/Applications/knowing_app/helmet_detect/SConscript create mode 100644 APP_Framework/Applications/knowing_app/helmet_detect/cJSON.c create mode 100644 APP_Framework/Applications/knowing_app/helmet_detect/cJSON.h create mode 100644 APP_Framework/Applications/knowing_app/helmet_detect/helmet.json create mode 100644 APP_Framework/Applications/knowing_app/helmet_detect/helmet_detect.c diff --git a/APP_Framework/Applications/knowing_app/Kconfig b/APP_Framework/Applications/knowing_app/Kconfig index b0705d4f..8e0305b6 100755 --- a/APP_Framework/Applications/knowing_app/Kconfig +++ b/APP_Framework/Applications/knowing_app/Kconfig @@ -2,4 +2,5 @@ menu "knowing app" source "$APP_DIR/Applications/knowing_app/mnist/Kconfig" source "$APP_DIR/Applications/knowing_app/face_detect/Kconfig" source "$APP_DIR/Applications/knowing_app/instrusion_detect/Kconfig" + source "$APP_DIR/Applications/knowing_app/helmet_detect/Kconfig" endmenu diff --git a/APP_Framework/Applications/knowing_app/helmet_detect/Kconfig b/APP_Framework/Applications/knowing_app/helmet_detect/Kconfig new file mode 100644 index 00000000..c279e86b --- /dev/null +++ b/APP_Framework/Applications/knowing_app/helmet_detect/Kconfig @@ -0,0 +1,7 @@ +config HELMET_DETECT + bool "enable apps/helmet detect" + depends on BOARD_K210_EVB + depends on DRV_USING_OV2640 + depends on USING_KPU_POSTPROCESSING + depends on USING_YOLOV2 + default n diff --git a/APP_Framework/Applications/knowing_app/helmet_detect/SConscript b/APP_Framework/Applications/knowing_app/helmet_detect/SConscript new file mode 100644 index 00000000..26ac700a --- /dev/null +++ b/APP_Framework/Applications/knowing_app/helmet_detect/SConscript @@ -0,0 +1,9 @@ +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') + Glob('*.cpp') +CPPPATH = [cwd] + +group = DefineGroup('Applications', src, depend = ['HELMET_DETECT'], LOCAL_CPPPATH = CPPPATH) + +Return('group') diff --git a/APP_Framework/Applications/knowing_app/helmet_detect/cJSON.c b/APP_Framework/Applications/knowing_app/helmet_detect/cJSON.c new file mode 100644 index 00000000..030311ce --- /dev/null +++ b/APP_Framework/Applications/knowing_app/helmet_detect/cJSON.c @@ -0,0 +1,3110 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +/* cJSON */ +/* JSON parser in C. */ + +/* disable warnings about old C89 functions in MSVC */ +#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) +#define _CRT_SECURE_NO_DEPRECATE +#endif + +#ifdef __GNUC__ +#pragma GCC visibility push(default) +#endif +#if defined(_MSC_VER) +#pragma warning (push) +/* disable warning about single line comments in system headers */ +#pragma warning (disable : 4001) +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifdef ENABLE_LOCALES +#include +#endif + +#if defined(_MSC_VER) +#pragma warning (pop) +#endif +#ifdef __GNUC__ +#pragma GCC visibility pop +#endif + +#include "cJSON.h" + +/* define our own boolean type */ +#ifdef true +#undef true +#endif +#define true ((cJSON_bool)1) + +#ifdef false +#undef false +#endif +#define false ((cJSON_bool)0) + +/* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */ +#ifndef isinf +#define isinf(d) (isnan((d - d)) && !isnan(d)) +#endif +#ifndef isnan +#define isnan(d) (d != d) +#endif + +#ifndef NAN +#ifdef _WIN32 +#define NAN sqrt(-1.0) +#else +#define NAN 0.0/0.0 +#endif +#endif + +typedef struct { + const unsigned char *json; + size_t position; +} error; +static error global_error = { NULL, 0 }; + +CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) +{ + return (const char*) (global_error.json + global_error.position); +} + +CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item) +{ + if (!cJSON_IsString(item)) + { + return NULL; + } + + return item->valuestring; +} + +CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item) +{ + if (!cJSON_IsNumber(item)) + { + return (double) NAN; + } + + return item->valuedouble; +} + +/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 14) + #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. +#endif + +CJSON_PUBLIC(const char*) cJSON_Version(void) +{ + static char version[15]; + sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); + + return version; +} + +/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */ +static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) +{ + if ((string1 == NULL) || (string2 == NULL)) + { + return 1; + } + + if (string1 == string2) + { + return 0; + } + + for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++) + { + if (*string1 == '\0') + { + return 0; + } + } + + return tolower(*string1) - tolower(*string2); +} + +typedef struct internal_hooks +{ + void *(CJSON_CDECL *allocate)(size_t size); + void (CJSON_CDECL *deallocate)(void *pointer); + void *(CJSON_CDECL *reallocate)(void *pointer, size_t size); +} internal_hooks; + +#if defined(_MSC_VER) +/* work around MSVC error C2322: '...' address of dllimport '...' is not static */ +static void * CJSON_CDECL internal_malloc(size_t size) +{ + return malloc(size); +} +static void CJSON_CDECL internal_free(void *pointer) +{ + free(pointer); +} +static void * CJSON_CDECL internal_realloc(void *pointer, size_t size) +{ + return realloc(pointer, size); +} +#else +#define internal_malloc malloc +#define internal_free free +#define internal_realloc realloc +#endif + +/* strlen of character literals resolved at compile time */ +#define static_strlen(string_literal) (sizeof(string_literal) - sizeof("")) + +static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc }; + +static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks) +{ + size_t length = 0; + unsigned char *copy = NULL; + + if (string == NULL) + { + return NULL; + } + + length = strlen((const char*)string) + sizeof(""); + copy = (unsigned char*)hooks->allocate(length); + if (copy == NULL) + { + return NULL; + } + memcpy(copy, string, length); + + return copy; +} + +CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) +{ + if (hooks == NULL) + { + /* Reset hooks */ + global_hooks.allocate = malloc; + global_hooks.deallocate = free; + global_hooks.reallocate = realloc; + return; + } + + global_hooks.allocate = malloc; + if (hooks->malloc_fn != NULL) + { + global_hooks.allocate = hooks->malloc_fn; + } + + global_hooks.deallocate = free; + if (hooks->free_fn != NULL) + { + global_hooks.deallocate = hooks->free_fn; + } + + /* use realloc only if both free and malloc are used */ + global_hooks.reallocate = NULL; + if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free)) + { + global_hooks.reallocate = realloc; + } +} + +/* Internal constructor. */ +static cJSON *cJSON_New_Item(const internal_hooks * const hooks) +{ + cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON)); + if (node) + { + memset(node, '\0', sizeof(cJSON)); + } + + return node; +} + +/* Delete a cJSON structure. */ +CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) +{ + cJSON *next = NULL; + while (item != NULL) + { + next = item->next; + if (!(item->type & cJSON_IsReference) && (item->child != NULL)) + { + cJSON_Delete(item->child); + } + if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) + { + global_hooks.deallocate(item->valuestring); + } + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) + { + global_hooks.deallocate(item->string); + } + global_hooks.deallocate(item); + item = next; + } +} + +/* get the decimal point character of the current locale */ +static unsigned char get_decimal_point(void) +{ +#ifdef ENABLE_LOCALES + struct lconv *lconv = localeconv(); + return (unsigned char) lconv->decimal_point[0]; +#else + return '.'; +#endif +} + +typedef struct +{ + const unsigned char *content; + size_t length; + size_t offset; + size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */ + internal_hooks hooks; +} parse_buffer; + +/* check if the given size is left to read in a given parse buffer (starting with 1) */ +#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length)) +/* check if the buffer can be accessed at the given index (starting with 0) */ +#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length)) +#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index)) +/* get a pointer to the buffer at the position */ +#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset) + +/* Parse the input text to generate a number, and populate the result into item. */ +static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer) +{ + double number = 0; + unsigned char *after_end = NULL; + unsigned char number_c_string[64]; + unsigned char decimal_point = get_decimal_point(); + size_t i = 0; + + if ((input_buffer == NULL) || (input_buffer->content == NULL)) + { + return false; + } + + /* copy the number into a temporary buffer and replace '.' with the decimal point + * of the current locale (for strtod) + * This also takes care of '\0' not necessarily being available for marking the end of the input */ + for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) + { + switch (buffer_at_offset(input_buffer)[i]) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '+': + case '-': + case 'e': + case 'E': + number_c_string[i] = buffer_at_offset(input_buffer)[i]; + break; + + case '.': + number_c_string[i] = decimal_point; + break; + + default: + goto loop_end; + } + } +loop_end: + number_c_string[i] = '\0'; + + number = strtod((const char*)number_c_string, (char**)&after_end); + if (number_c_string == after_end) + { + return false; /* parse_error */ + } + + item->valuedouble = number; + + /* use saturation in case of overflow */ + if (number >= INT_MAX) + { + item->valueint = INT_MAX; + } + else if (number <= (double)INT_MIN) + { + item->valueint = INT_MIN; + } + else + { + item->valueint = (int)number; + } + + item->type = cJSON_Number; + + input_buffer->offset += (size_t)(after_end - number_c_string); + return true; +} + +/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ +CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) +{ + if (number >= INT_MAX) + { + object->valueint = INT_MAX; + } + else if (number <= (double)INT_MIN) + { + object->valueint = INT_MIN; + } + else + { + object->valueint = (int)number; + } + + return object->valuedouble = number; +} + +CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring) +{ + char *copy = NULL; + /* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */ + if (!(object->type & cJSON_String) || (object->type & cJSON_IsReference)) + { + return NULL; + } + if (strlen(valuestring) <= strlen(object->valuestring)) + { + strcpy(object->valuestring, valuestring); + return object->valuestring; + } + copy = (char*) cJSON_strdup((const unsigned char*)valuestring, &global_hooks); + if (copy == NULL) + { + return NULL; + } + if (object->valuestring != NULL) + { + cJSON_free(object->valuestring); + } + object->valuestring = copy; + + return copy; +} + +typedef struct +{ + unsigned char *buffer; + size_t length; + size_t offset; + size_t depth; /* current nesting depth (for formatted printing) */ + cJSON_bool noalloc; + cJSON_bool format; /* is this print a formatted print */ + internal_hooks hooks; +} printbuffer; + +/* realloc printbuffer if necessary to have at least "needed" bytes more */ +static unsigned char* ensure(printbuffer * const p, size_t needed) +{ + unsigned char *newbuffer = NULL; + size_t newsize = 0; + + if ((p == NULL) || (p->buffer == NULL)) + { + return NULL; + } + + if ((p->length > 0) && (p->offset >= p->length)) + { + /* make sure that offset is valid */ + return NULL; + } + + if (needed > INT_MAX) + { + /* sizes bigger than INT_MAX are currently not supported */ + return NULL; + } + + needed += p->offset + 1; + if (needed <= p->length) + { + return p->buffer + p->offset; + } + + if (p->noalloc) { + return NULL; + } + + /* calculate new buffer size */ + if (needed > (INT_MAX / 2)) + { + /* overflow of int, use INT_MAX if possible */ + if (needed <= INT_MAX) + { + newsize = INT_MAX; + } + else + { + return NULL; + } + } + else + { + newsize = needed * 2; + } + + if (p->hooks.reallocate != NULL) + { + /* reallocate with realloc if available */ + newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize); + if (newbuffer == NULL) + { + p->hooks.deallocate(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + } + else + { + /* otherwise reallocate manually */ + newbuffer = (unsigned char*)p->hooks.allocate(newsize); + if (!newbuffer) + { + p->hooks.deallocate(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + + memcpy(newbuffer, p->buffer, p->offset + 1); + p->hooks.deallocate(p->buffer); + } + p->length = newsize; + p->buffer = newbuffer; + + return newbuffer + p->offset; +} + +/* calculate the new length of the string in a printbuffer and update the offset */ +static void update_offset(printbuffer * const buffer) +{ + const unsigned char *buffer_pointer = NULL; + if ((buffer == NULL) || (buffer->buffer == NULL)) + { + return; + } + buffer_pointer = buffer->buffer + buffer->offset; + + buffer->offset += strlen((const char*)buffer_pointer); +} + +/* securely comparison of floating-point variables */ +static cJSON_bool compare_double(double a, double b) +{ + double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b); + return (fabs(a - b) <= maxVal * DBL_EPSILON); +} + +/* Render the number nicely from the given item into a string. */ +static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + double d = item->valuedouble; + int length = 0; + size_t i = 0; + unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */ + unsigned char decimal_point = get_decimal_point(); + double test = 0.0; + + if (output_buffer == NULL) + { + return false; + } + + /* This checks for NaN and Infinity */ + if (isnan(d) || isinf(d)) + { + length = sprintf((char*)number_buffer, "null"); + } + else + { + /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ + length = sprintf((char*)number_buffer, "%1.15g", d); + + /* Check whether the original double can be recovered */ + if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d)) + { + /* If not, print with 17 decimal places of precision */ + length = sprintf((char*)number_buffer, "%1.17g", d); + } + } + + /* sprintf failed or buffer overrun occurred */ + if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) + { + return false; + } + + /* reserve appropriate space in the output */ + output_pointer = ensure(output_buffer, (size_t)length + sizeof("")); + if (output_pointer == NULL) + { + return false; + } + + /* copy the printed number to the output and replace locale + * dependent decimal point with '.' */ + for (i = 0; i < ((size_t)length); i++) + { + if (number_buffer[i] == decimal_point) + { + output_pointer[i] = '.'; + continue; + } + + output_pointer[i] = number_buffer[i]; + } + output_pointer[i] = '\0'; + + output_buffer->offset += (size_t)length; + + return true; +} + +/* parse 4 digit hexadecimal number */ +static unsigned parse_hex4(const unsigned char * const input) +{ + unsigned int h = 0; + size_t i = 0; + + for (i = 0; i < 4; i++) + { + /* parse digit */ + if ((input[i] >= '0') && (input[i] <= '9')) + { + h += (unsigned int) input[i] - '0'; + } + else if ((input[i] >= 'A') && (input[i] <= 'F')) + { + h += (unsigned int) 10 + input[i] - 'A'; + } + else if ((input[i] >= 'a') && (input[i] <= 'f')) + { + h += (unsigned int) 10 + input[i] - 'a'; + } + else /* invalid */ + { + return 0; + } + + if (i < 3) + { + /* shift left to make place for the next nibble */ + h = h << 4; + } + } + + return h; +} + +/* converts a UTF-16 literal to UTF-8 + * A literal can be one or two sequences of the form \uXXXX */ +static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer) +{ + long unsigned int codepoint = 0; + unsigned int first_code = 0; + const unsigned char *first_sequence = input_pointer; + unsigned char utf8_length = 0; + unsigned char utf8_position = 0; + unsigned char sequence_length = 0; + unsigned char first_byte_mark = 0; + + if ((input_end - first_sequence) < 6) + { + /* input ends unexpectedly */ + goto fail; + } + + /* get the first utf16 sequence */ + first_code = parse_hex4(first_sequence + 2); + + /* check that the code is valid */ + if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) + { + goto fail; + } + + /* UTF16 surrogate pair */ + if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) + { + const unsigned char *second_sequence = first_sequence + 6; + unsigned int second_code = 0; + sequence_length = 12; /* \uXXXX\uXXXX */ + + if ((input_end - second_sequence) < 6) + { + /* input ends unexpectedly */ + goto fail; + } + + if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) + { + /* missing second half of the surrogate pair */ + goto fail; + } + + /* get the second utf16 sequence */ + second_code = parse_hex4(second_sequence + 2); + /* check that the code is valid */ + if ((second_code < 0xDC00) || (second_code > 0xDFFF)) + { + /* invalid second half of the surrogate pair */ + goto fail; + } + + + /* calculate the unicode codepoint from the surrogate pair */ + codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF)); + } + else + { + sequence_length = 6; /* \uXXXX */ + codepoint = first_code; + } + + /* encode as UTF-8 + * takes at maximum 4 bytes to encode: + * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ + if (codepoint < 0x80) + { + /* normal ascii, encoding 0xxxxxxx */ + utf8_length = 1; + } + else if (codepoint < 0x800) + { + /* two bytes, encoding 110xxxxx 10xxxxxx */ + utf8_length = 2; + first_byte_mark = 0xC0; /* 11000000 */ + } + else if (codepoint < 0x10000) + { + /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ + utf8_length = 3; + first_byte_mark = 0xE0; /* 11100000 */ + } + else if (codepoint <= 0x10FFFF) + { + /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ + utf8_length = 4; + first_byte_mark = 0xF0; /* 11110000 */ + } + else + { + /* invalid unicode codepoint */ + goto fail; + } + + /* encode as utf8 */ + for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) + { + /* 10xxxxxx */ + (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF); + codepoint >>= 6; + } + /* encode first byte */ + if (utf8_length > 1) + { + (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF); + } + else + { + (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F); + } + + *output_pointer += utf8_length; + + return sequence_length; + +fail: + return 0; +} + +/* Parse the input text into an unescaped cinput, and populate item. */ +static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer) +{ + const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; + const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; + unsigned char *output_pointer = NULL; + unsigned char *output = NULL; + + /* not a string */ + if (buffer_at_offset(input_buffer)[0] != '\"') + { + goto fail; + } + + { + /* calculate approximate size of the output (overestimate) */ + size_t allocation_length = 0; + size_t skipped_bytes = 0; + while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) + { + /* is escape sequence */ + if (input_end[0] == '\\') + { + if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) + { + /* prevent buffer overflow when last input character is a backslash */ + goto fail; + } + skipped_bytes++; + input_end++; + } + input_end++; + } + if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) + { + goto fail; /* string ended unexpectedly */ + } + + /* This is at most how much we need for the output */ + allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes; + output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof("")); + if (output == NULL) + { + goto fail; /* allocation failure */ + } + } + + output_pointer = output; + /* loop through the string literal */ + while (input_pointer < input_end) + { + if (*input_pointer != '\\') + { + *output_pointer++ = *input_pointer++; + } + /* escape sequence */ + else + { + unsigned char sequence_length = 2; + if ((input_end - input_pointer) < 1) + { + goto fail; + } + + switch (input_pointer[1]) + { + case 'b': + *output_pointer++ = '\b'; + break; + case 'f': + *output_pointer++ = '\f'; + break; + case 'n': + *output_pointer++ = '\n'; + break; + case 'r': + *output_pointer++ = '\r'; + break; + case 't': + *output_pointer++ = '\t'; + break; + case '\"': + case '\\': + case '/': + *output_pointer++ = input_pointer[1]; + break; + + /* UTF-16 literal */ + case 'u': + sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); + if (sequence_length == 0) + { + /* failed to convert UTF16-literal to UTF-8 */ + goto fail; + } + break; + + default: + goto fail; + } + input_pointer += sequence_length; + } + } + + /* zero terminate the output */ + *output_pointer = '\0'; + + item->type = cJSON_String; + item->valuestring = (char*)output; + + input_buffer->offset = (size_t) (input_end - input_buffer->content); + input_buffer->offset++; + + return true; + +fail: + if (output != NULL) + { + input_buffer->hooks.deallocate(output); + } + + if (input_pointer != NULL) + { + input_buffer->offset = (size_t)(input_pointer - input_buffer->content); + } + + return false; +} + +/* Render the cstring provided to an escaped version that can be printed. */ +static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer) +{ + const unsigned char *input_pointer = NULL; + unsigned char *output = NULL; + unsigned char *output_pointer = NULL; + size_t output_length = 0; + /* numbers of additional characters needed for escaping */ + size_t escape_characters = 0; + + if (output_buffer == NULL) + { + return false; + } + + /* empty string */ + if (input == NULL) + { + output = ensure(output_buffer, sizeof("\"\"")); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "\"\""); + + return true; + } + + /* set "flag" to 1 if something needs to be escaped */ + for (input_pointer = input; *input_pointer; input_pointer++) + { + switch (*input_pointer) + { + case '\"': + case '\\': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + /* one character escape sequence */ + escape_characters++; + break; + default: + if (*input_pointer < 32) + { + /* UTF-16 escape sequence uXXXX */ + escape_characters += 5; + } + break; + } + } + output_length = (size_t)(input_pointer - input) + escape_characters; + + output = ensure(output_buffer, output_length + sizeof("\"\"")); + if (output == NULL) + { + return false; + } + + /* no characters have to be escaped */ + if (escape_characters == 0) + { + output[0] = '\"'; + memcpy(output + 1, input, output_length); + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; + } + + output[0] = '\"'; + output_pointer = output + 1; + /* copy the string */ + for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) + { + if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) + { + /* normal character, copy */ + *output_pointer = *input_pointer; + } + else + { + /* character needs to be escaped */ + *output_pointer++ = '\\'; + switch (*input_pointer) + { + case '\\': + *output_pointer = '\\'; + break; + case '\"': + *output_pointer = '\"'; + break; + case '\b': + *output_pointer = 'b'; + break; + case '\f': + *output_pointer = 'f'; + break; + case '\n': + *output_pointer = 'n'; + break; + case '\r': + *output_pointer = 'r'; + break; + case '\t': + *output_pointer = 't'; + break; + default: + /* escape and print as unicode codepoint */ + sprintf((char*)output_pointer, "u%04x", *input_pointer); + output_pointer += 4; + break; + } + } + } + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; +} + +/* Invoke print_string_ptr (which is useful) on an item. */ +static cJSON_bool print_string(const cJSON * const item, printbuffer * const p) +{ + return print_string_ptr((unsigned char*)item->valuestring, p); +} + +/* Predeclare these prototypes. */ +static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer); +static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer); +static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer); + +/* Utility to jump whitespace and cr/lf */ +static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) +{ + if ((buffer == NULL) || (buffer->content == NULL)) + { + return NULL; + } + + if (cannot_access_at_index(buffer, 0)) + { + return buffer; + } + + while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) + { + buffer->offset++; + } + + if (buffer->offset == buffer->length) + { + buffer->offset--; + } + + return buffer; +} + +/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */ +static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) +{ + if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) + { + return NULL; + } + + if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) + { + buffer->offset += 3; + } + + return buffer; +} + +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) +{ + size_t buffer_length; + + if (NULL == value) + { + return NULL; + } + + /* Adding null character size due to require_null_terminated. */ + buffer_length = strlen(value) + sizeof(""); + + return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated); +} + +/* Parse an object - create a new root, and populate. */ +CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated) +{ + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + cJSON *item = NULL; + + /* reset error position */ + global_error.json = NULL; + global_error.position = 0; + + if (value == NULL || 0 == buffer_length) + { + goto fail; + } + + buffer.content = (const unsigned char*)value; + buffer.length = buffer_length; + buffer.offset = 0; + buffer.hooks = global_hooks; + + item = cJSON_New_Item(&global_hooks); + if (item == NULL) /* memory fail */ + { + goto fail; + } + + if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))) + { + /* parse failure. ep is set. */ + goto fail; + } + + /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ + if (require_null_terminated) + { + buffer_skip_whitespace(&buffer); + if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') + { + goto fail; + } + } + if (return_parse_end) + { + *return_parse_end = (const char*)buffer_at_offset(&buffer); + } + + return item; + +fail: + if (item != NULL) + { + cJSON_Delete(item); + } + + if (value != NULL) + { + error local_error; + local_error.json = (const unsigned char*)value; + local_error.position = 0; + + if (buffer.offset < buffer.length) + { + local_error.position = buffer.offset; + } + else if (buffer.length > 0) + { + local_error.position = buffer.length - 1; + } + + if (return_parse_end != NULL) + { + *return_parse_end = (const char*)local_error.json + local_error.position; + } + + global_error = local_error; + } + + return NULL; +} + +/* Default options for cJSON_Parse */ +CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) +{ + return cJSON_ParseWithOpts(value, 0, 0); +} + +CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length) +{ + return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0); +} + +#define cjson_min(a, b) (((a) < (b)) ? (a) : (b)) + +static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks) +{ + static const size_t default_buffer_size = 256; + printbuffer buffer[1]; + unsigned char *printed = NULL; + + memset(buffer, 0, sizeof(buffer)); + + /* create buffer */ + buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size); + buffer->length = default_buffer_size; + buffer->format = format; + buffer->hooks = *hooks; + if (buffer->buffer == NULL) + { + goto fail; + } + + /* print the value */ + if (!print_value(item, buffer)) + { + goto fail; + } + update_offset(buffer); + + /* check if reallocate is available */ + if (hooks->reallocate != NULL) + { + printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1); + if (printed == NULL) { + goto fail; + } + buffer->buffer = NULL; + } + else /* otherwise copy the JSON over to a new buffer */ + { + printed = (unsigned char*) hooks->allocate(buffer->offset + 1); + if (printed == NULL) + { + goto fail; + } + memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1)); + printed[buffer->offset] = '\0'; /* just to be sure */ + + /* free the buffer */ + hooks->deallocate(buffer->buffer); + } + + return printed; + +fail: + if (buffer->buffer != NULL) + { + hooks->deallocate(buffer->buffer); + } + + if (printed != NULL) + { + hooks->deallocate(printed); + } + + return NULL; +} + +/* Render a cJSON item/entity/structure to text. */ +CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) +{ + return (char*)print(item, true, &global_hooks); +} + +CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) +{ + return (char*)print(item, false, &global_hooks); +} + +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) +{ + printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + + if (prebuffer < 0) + { + return NULL; + } + + p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer); + if (!p.buffer) + { + return NULL; + } + + p.length = (size_t)prebuffer; + p.offset = 0; + p.noalloc = false; + p.format = fmt; + p.hooks = global_hooks; + + if (!print_value(item, &p)) + { + global_hooks.deallocate(p.buffer); + return NULL; + } + + return (char*)p.buffer; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) +{ + printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + + if ((length < 0) || (buffer == NULL)) + { + return false; + } + + p.buffer = (unsigned char*)buffer; + p.length = (size_t)length; + p.offset = 0; + p.noalloc = true; + p.format = format; + p.hooks = global_hooks; + + return print_value(item, &p); +} + +/* Parser core - when encountering text, process appropriately. */ +static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer) +{ + if ((input_buffer == NULL) || (input_buffer->content == NULL)) + { + return false; /* no input */ + } + + /* parse the different types of values */ + /* null */ + if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0)) + { + item->type = cJSON_NULL; + input_buffer->offset += 4; + return true; + } + /* false */ + if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0)) + { + item->type = cJSON_False; + input_buffer->offset += 5; + return true; + } + /* true */ + if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0)) + { + item->type = cJSON_True; + item->valueint = 1; + input_buffer->offset += 4; + return true; + } + /* string */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) + { + return parse_string(item, input_buffer); + } + /* number */ + if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) + { + return parse_number(item, input_buffer); + } + /* array */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) + { + return parse_array(item, input_buffer); + } + /* object */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) + { + return parse_object(item, input_buffer); + } + + return false; +} + +/* Render a value to text. */ +static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output = NULL; + + if ((item == NULL) || (output_buffer == NULL)) + { + return false; + } + + switch ((item->type) & 0xFF) + { + case cJSON_NULL: + output = ensure(output_buffer, 5); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "null"); + return true; + + case cJSON_False: + output = ensure(output_buffer, 6); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "false"); + return true; + + case cJSON_True: + output = ensure(output_buffer, 5); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "true"); + return true; + + case cJSON_Number: + return print_number(item, output_buffer); + + case cJSON_Raw: + { + size_t raw_length = 0; + if (item->valuestring == NULL) + { + return false; + } + + raw_length = strlen(item->valuestring) + sizeof(""); + output = ensure(output_buffer, raw_length); + if (output == NULL) + { + return false; + } + memcpy(output, item->valuestring, raw_length); + return true; + } + + case cJSON_String: + return print_string(item, output_buffer); + + case cJSON_Array: + return print_array(item, output_buffer); + + case cJSON_Object: + return print_object(item, output_buffer); + + default: + return false; + } +} + +/* Build an array from input text. */ +static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer) +{ + cJSON *head = NULL; /* head of the linked list */ + cJSON *current_item = NULL; + + if (input_buffer->depth >= CJSON_NESTING_LIMIT) + { + return false; /* to deeply nested */ + } + input_buffer->depth++; + + if (buffer_at_offset(input_buffer)[0] != '[') + { + /* not an array */ + goto fail; + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) + { + /* empty array */ + goto success; + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) + { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do + { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + if (new_item == NULL) + { + goto fail; /* allocation failure */ + } + + /* attach next item to list */ + if (head == NULL) + { + /* start the linked list */ + current_item = head = new_item; + } + else + { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse next value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_value(current_item, input_buffer)) + { + goto fail; /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + } + while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') + { + goto fail; /* expected end of array */ + } + +success: + input_buffer->depth--; + + if (head != NULL) { + head->prev = current_item; + } + + item->type = cJSON_Array; + item->child = head; + + input_buffer->offset++; + + return true; + +fail: + if (head != NULL) + { + cJSON_Delete(head); + } + + return false; +} + +/* Render an array to text */ +static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + size_t length = 0; + cJSON *current_element = item->child; + + if (output_buffer == NULL) + { + return false; + } + + /* Compose the output array. */ + /* opening square bracket */ + output_pointer = ensure(output_buffer, 1); + if (output_pointer == NULL) + { + return false; + } + + *output_pointer = '['; + output_buffer->offset++; + output_buffer->depth++; + + while (current_element != NULL) + { + if (!print_value(current_element, output_buffer)) + { + return false; + } + update_offset(output_buffer); + if (current_element->next) + { + length = (size_t) (output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ','; + if(output_buffer->format) + { + *output_pointer++ = ' '; + } + *output_pointer = '\0'; + output_buffer->offset += length; + } + current_element = current_element->next; + } + + output_pointer = ensure(output_buffer, 2); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ']'; + *output_pointer = '\0'; + output_buffer->depth--; + + return true; +} + +/* Build an object from the text. */ +static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer) +{ + cJSON *head = NULL; /* linked list head */ + cJSON *current_item = NULL; + + if (input_buffer->depth >= CJSON_NESTING_LIMIT) + { + return false; /* to deeply nested */ + } + input_buffer->depth++; + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) + { + goto fail; /* not an object */ + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) + { + goto success; /* empty object */ + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) + { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do + { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + if (new_item == NULL) + { + goto fail; /* allocation failure */ + } + + /* attach next item to list */ + if (head == NULL) + { + /* start the linked list */ + current_item = head = new_item; + } + else + { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse the name of the child */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_string(current_item, input_buffer)) + { + goto fail; /* failed to parse name */ + } + buffer_skip_whitespace(input_buffer); + + /* swap valuestring and string, because we parsed the name */ + current_item->string = current_item->valuestring; + current_item->valuestring = NULL; + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) + { + goto fail; /* invalid object */ + } + + /* parse the value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_value(current_item, input_buffer)) + { + goto fail; /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + } + while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) + { + goto fail; /* expected end of object */ + } + +success: + input_buffer->depth--; + + if (head != NULL) { + head->prev = current_item; + } + + item->type = cJSON_Object; + item->child = head; + + input_buffer->offset++; + return true; + +fail: + if (head != NULL) + { + cJSON_Delete(head); + } + + return false; +} + +/* Render an object to text. */ +static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + size_t length = 0; + cJSON *current_item = item->child; + + if (output_buffer == NULL) + { + return false; + } + + /* Compose the output: */ + length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */ + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + + *output_pointer++ = '{'; + output_buffer->depth++; + if (output_buffer->format) + { + *output_pointer++ = '\n'; + } + output_buffer->offset += length; + + while (current_item) + { + if (output_buffer->format) + { + size_t i; + output_pointer = ensure(output_buffer, output_buffer->depth); + if (output_pointer == NULL) + { + return false; + } + for (i = 0; i < output_buffer->depth; i++) + { + *output_pointer++ = '\t'; + } + output_buffer->offset += output_buffer->depth; + } + + /* print key */ + if (!print_string_ptr((unsigned char*)current_item->string, output_buffer)) + { + return false; + } + update_offset(output_buffer); + + length = (size_t) (output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ':'; + if (output_buffer->format) + { + *output_pointer++ = '\t'; + } + output_buffer->offset += length; + + /* print value */ + if (!print_value(current_item, output_buffer)) + { + return false; + } + update_offset(output_buffer); + + /* print comma if not last */ + length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0)); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + if (current_item->next) + { + *output_pointer++ = ','; + } + + if (output_buffer->format) + { + *output_pointer++ = '\n'; + } + *output_pointer = '\0'; + output_buffer->offset += length; + + current_item = current_item->next; + } + + output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2); + if (output_pointer == NULL) + { + return false; + } + if (output_buffer->format) + { + size_t i; + for (i = 0; i < (output_buffer->depth - 1); i++) + { + *output_pointer++ = '\t'; + } + } + *output_pointer++ = '}'; + *output_pointer = '\0'; + output_buffer->depth--; + + return true; +} + +/* Get Array size/item / object item. */ +CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) +{ + cJSON *child = NULL; + size_t size = 0; + + if (array == NULL) + { + return 0; + } + + child = array->child; + + while(child != NULL) + { + size++; + child = child->next; + } + + /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ + + return (int)size; +} + +static cJSON* get_array_item(const cJSON *array, size_t index) +{ + cJSON *current_child = NULL; + + if (array == NULL) + { + return NULL; + } + + current_child = array->child; + while ((current_child != NULL) && (index > 0)) + { + index--; + current_child = current_child->next; + } + + return current_child; +} + +CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index) +{ + if (index < 0) + { + return NULL; + } + + return get_array_item(array, (size_t)index); +} + +static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive) +{ + cJSON *current_element = NULL; + + if ((object == NULL) || (name == NULL)) + { + return NULL; + } + + current_element = object->child; + if (case_sensitive) + { + while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0)) + { + current_element = current_element->next; + } + } + else + { + while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0)) + { + current_element = current_element->next; + } + } + + if ((current_element == NULL) || (current_element->string == NULL)) { + return NULL; + } + + return current_element; +} + +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string) +{ + return get_object_item(object, string, false); +} + +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) +{ + return get_object_item(object, string, true); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string) +{ + return cJSON_GetObjectItem(object, string) ? 1 : 0; +} + +/* Utility for array list handling. */ +static void suffix_object(cJSON *prev, cJSON *item) +{ + prev->next = item; + item->prev = prev; +} + +/* Utility for handling references. */ +static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks) +{ + cJSON *reference = NULL; + if (item == NULL) + { + return NULL; + } + + reference = cJSON_New_Item(hooks); + if (reference == NULL) + { + return NULL; + } + + memcpy(reference, item, sizeof(cJSON)); + reference->string = NULL; + reference->type |= cJSON_IsReference; + reference->next = reference->prev = NULL; + return reference; +} + +static cJSON_bool add_item_to_array(cJSON *array, cJSON *item) +{ + cJSON *child = NULL; + + if ((item == NULL) || (array == NULL) || (array == item)) + { + return false; + } + + child = array->child; + /* + * To find the last item in array quickly, we use prev in array + */ + if (child == NULL) + { + /* list is empty, start new one */ + array->child = item; + item->prev = item; + item->next = NULL; + } + else + { + /* append to the end */ + if (child->prev) + { + suffix_object(child->prev, item); + array->child->prev = item; + } + } + + return true; +} + +/* Add item to array/object. */ +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item) +{ + return add_item_to_array(array, item); +} + +#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) + #pragma GCC diagnostic push +#endif +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif +/* helper function to cast away const */ +static void* cast_away_const(const void* string) +{ + return (void*)string; +} +#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) + #pragma GCC diagnostic pop +#endif + + +static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key) +{ + char *new_key = NULL; + int new_type = cJSON_Invalid; + + if ((object == NULL) || (string == NULL) || (item == NULL) || (object == item)) + { + return false; + } + + if (constant_key) + { + new_key = (char*)cast_away_const(string); + new_type = item->type | cJSON_StringIsConst; + } + else + { + new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks); + if (new_key == NULL) + { + return false; + } + + new_type = item->type & ~cJSON_StringIsConst; + } + + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) + { + hooks->deallocate(item->string); + } + + item->string = new_key; + item->type = new_type; + + return add_item_to_array(object, item); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) +{ + return add_item_to_object(object, string, item, &global_hooks, false); +} + +/* Add an item to an object with constant string as key */ +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) +{ + return add_item_to_object(object, string, item, &global_hooks, true); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) +{ + if (array == NULL) + { + return false; + } + + return add_item_to_array(array, create_reference(item, &global_hooks)); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) +{ + if ((object == NULL) || (string == NULL)) + { + return false; + } + + return add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false); +} + +CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name) +{ + cJSON *null = cJSON_CreateNull(); + if (add_item_to_object(object, name, null, &global_hooks, false)) + { + return null; + } + + cJSON_Delete(null); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name) +{ + cJSON *true_item = cJSON_CreateTrue(); + if (add_item_to_object(object, name, true_item, &global_hooks, false)) + { + return true_item; + } + + cJSON_Delete(true_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name) +{ + cJSON *false_item = cJSON_CreateFalse(); + if (add_item_to_object(object, name, false_item, &global_hooks, false)) + { + return false_item; + } + + cJSON_Delete(false_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean) +{ + cJSON *bool_item = cJSON_CreateBool(boolean); + if (add_item_to_object(object, name, bool_item, &global_hooks, false)) + { + return bool_item; + } + + cJSON_Delete(bool_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number) +{ + cJSON *number_item = cJSON_CreateNumber(number); + if (add_item_to_object(object, name, number_item, &global_hooks, false)) + { + return number_item; + } + + cJSON_Delete(number_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string) +{ + cJSON *string_item = cJSON_CreateString(string); + if (add_item_to_object(object, name, string_item, &global_hooks, false)) + { + return string_item; + } + + cJSON_Delete(string_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw) +{ + cJSON *raw_item = cJSON_CreateRaw(raw); + if (add_item_to_object(object, name, raw_item, &global_hooks, false)) + { + return raw_item; + } + + cJSON_Delete(raw_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name) +{ + cJSON *object_item = cJSON_CreateObject(); + if (add_item_to_object(object, name, object_item, &global_hooks, false)) + { + return object_item; + } + + cJSON_Delete(object_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name) +{ + cJSON *array = cJSON_CreateArray(); + if (add_item_to_object(object, name, array, &global_hooks, false)) + { + return array; + } + + cJSON_Delete(array); + return NULL; +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) +{ + if ((parent == NULL) || (item == NULL)) + { + return NULL; + } + + if (item != parent->child) + { + /* not the first element */ + item->prev->next = item->next; + } + if (item->next != NULL) + { + /* not the last element */ + item->next->prev = item->prev; + } + + if (item == parent->child) + { + /* first element */ + parent->child = item->next; + } + else if (item->next == NULL) + { + /* last element */ + parent->child->prev = item->prev; + } + + /* make sure the detached item doesn't point anywhere anymore */ + item->prev = NULL; + item->next = NULL; + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which) +{ + if (which < 0) + { + return NULL; + } + + return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which)); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) +{ + cJSON_Delete(cJSON_DetachItemFromArray(array, which)); +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string) +{ + cJSON *to_detach = cJSON_GetObjectItem(object, string); + + return cJSON_DetachItemViaPointer(object, to_detach); +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string) +{ + cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string); + + return cJSON_DetachItemViaPointer(object, to_detach); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) +{ + cJSON_Delete(cJSON_DetachItemFromObject(object, string)); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string) +{ + cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string)); +} + +/* Replace array/object items with new ones. */ +CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) +{ + cJSON *after_inserted = NULL; + + if (which < 0) + { + return false; + } + + after_inserted = get_array_item(array, (size_t)which); + if (after_inserted == NULL) + { + return add_item_to_array(array, newitem); + } + + newitem->next = after_inserted; + newitem->prev = after_inserted->prev; + after_inserted->prev = newitem; + if (after_inserted == array->child) + { + array->child = newitem; + } + else + { + newitem->prev->next = newitem; + } + return true; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement) +{ + if ((parent == NULL) || (replacement == NULL) || (item == NULL)) + { + return false; + } + + if (replacement == item) + { + return true; + } + + replacement->next = item->next; + replacement->prev = item->prev; + + if (replacement->next != NULL) + { + replacement->next->prev = replacement; + } + if (parent->child == item) + { + if (parent->child->prev == parent->child) + { + replacement->prev = replacement; + } + parent->child = replacement; + } + else + { /* + * To find the last item in array quickly, we use prev in array. + * We can't modify the last item's next pointer where this item was the parent's child + */ + if (replacement->prev != NULL) + { + replacement->prev->next = replacement; + } + if (replacement->next == NULL) + { + parent->child->prev = replacement; + } + } + + item->next = NULL; + item->prev = NULL; + cJSON_Delete(item); + + return true; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) +{ + if (which < 0) + { + return false; + } + + return cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem); +} + +static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive) +{ + if ((replacement == NULL) || (string == NULL)) + { + return false; + } + + /* replace the name in the replacement */ + if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL)) + { + cJSON_free(replacement->string); + } + replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); + replacement->type &= ~cJSON_StringIsConst; + + return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) +{ + return replace_item_in_object(object, string, newitem, false); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) +{ + return replace_item_in_object(object, string, newitem, true); +} + +/* Create basic types: */ +CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_NULL; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_True; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_False; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = boolean ? cJSON_True : cJSON_False; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_Number; + item->valuedouble = num; + + /* use saturation in case of overflow */ + if (num >= INT_MAX) + { + item->valueint = INT_MAX; + } + else if (num <= (double)INT_MIN) + { + item->valueint = INT_MIN; + } + else + { + item->valueint = (int)num; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_String; + item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); + if(!item->valuestring) + { + cJSON_Delete(item); + return NULL; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) + { + item->type = cJSON_String | cJSON_IsReference; + item->valuestring = (char*)cast_away_const(string); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) { + item->type = cJSON_Object | cJSON_IsReference; + item->child = (cJSON*)cast_away_const(child); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) { + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) { + item->type = cJSON_Array | cJSON_IsReference; + item->child = (cJSON*)cast_away_const(child); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_Raw; + item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks); + if(!item->valuestring) + { + cJSON_Delete(item); + return NULL; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type=cJSON_Array; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item) + { + item->type = cJSON_Object; + } + + return item; +} + +/* Create Arrays: */ +CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for(i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber(numbers[i]); + if (!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + if (a && a->child) { + a->child->prev = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for(i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber((double)numbers[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + if (a && a->child) { + a->child->prev = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for(i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber(numbers[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + if (a && a->child) { + a->child->prev = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (strings == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for (i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateString(strings[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p,n); + } + p = n; + } + + if (a && a->child) { + a->child->prev = n; + } + + return a; +} + +/* Duplication */ +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) +{ + cJSON *newitem = NULL; + cJSON *child = NULL; + cJSON *next = NULL; + cJSON *newchild = NULL; + + /* Bail on bad ptr */ + if (!item) + { + goto fail; + } + /* Create new item */ + newitem = cJSON_New_Item(&global_hooks); + if (!newitem) + { + goto fail; + } + /* Copy over all vars */ + newitem->type = item->type & (~cJSON_IsReference); + newitem->valueint = item->valueint; + newitem->valuedouble = item->valuedouble; + if (item->valuestring) + { + newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks); + if (!newitem->valuestring) + { + goto fail; + } + } + if (item->string) + { + newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks); + if (!newitem->string) + { + goto fail; + } + } + /* If non-recursive, then we're done! */ + if (!recurse) + { + return newitem; + } + /* Walk the ->next chain for the child. */ + child = item->child; + while (child != NULL) + { + newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ + if (!newchild) + { + goto fail; + } + if (next != NULL) + { + /* If newitem->child already set, then crosswire ->prev and ->next and move on */ + next->next = newchild; + newchild->prev = next; + next = newchild; + } + else + { + /* Set newitem->child and move to it */ + newitem->child = newchild; + next = newchild; + } + child = child->next; + } + if (newitem && newitem->child) + { + newitem->child->prev = newchild; + } + + return newitem; + +fail: + if (newitem != NULL) + { + cJSON_Delete(newitem); + } + + return NULL; +} + +static void skip_oneline_comment(char **input) +{ + *input += static_strlen("//"); + + for (; (*input)[0] != '\0'; ++(*input)) + { + if ((*input)[0] == '\n') { + *input += static_strlen("\n"); + return; + } + } +} + +static void skip_multiline_comment(char **input) +{ + *input += static_strlen("/*"); + + for (; (*input)[0] != '\0'; ++(*input)) + { + if (((*input)[0] == '*') && ((*input)[1] == '/')) + { + *input += static_strlen("*/"); + return; + } + } +} + +static void minify_string(char **input, char **output) { + (*output)[0] = (*input)[0]; + *input += static_strlen("\""); + *output += static_strlen("\""); + + + for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) { + (*output)[0] = (*input)[0]; + + if ((*input)[0] == '\"') { + (*output)[0] = '\"'; + *input += static_strlen("\""); + *output += static_strlen("\""); + return; + } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) { + (*output)[1] = (*input)[1]; + *input += static_strlen("\""); + *output += static_strlen("\""); + } + } +} + +CJSON_PUBLIC(void) cJSON_Minify(char *json) +{ + char *into = json; + + if (json == NULL) + { + return; + } + + while (json[0] != '\0') + { + switch (json[0]) + { + case ' ': + case '\t': + case '\r': + case '\n': + json++; + break; + + case '/': + if (json[1] == '/') + { + skip_oneline_comment(&json); + } + else if (json[1] == '*') + { + skip_multiline_comment(&json); + } else { + json++; + } + break; + + case '\"': + minify_string(&json, (char**)&into); + break; + + default: + into[0] = json[0]; + json++; + into++; + } + } + + /* and null-terminate. */ + *into = '\0'; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Invalid; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_False; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xff) == cJSON_True; +} + + +CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & (cJSON_True | cJSON_False)) != 0; +} +CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_NULL; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Number; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_String; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Array; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Object; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Raw; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive) +{ + if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) + { + return false; + } + + /* check if type is valid */ + switch (a->type & 0xFF) + { + case cJSON_False: + case cJSON_True: + case cJSON_NULL: + case cJSON_Number: + case cJSON_String: + case cJSON_Raw: + case cJSON_Array: + case cJSON_Object: + break; + + default: + return false; + } + + /* identical objects are equal */ + if (a == b) + { + return true; + } + + switch (a->type & 0xFF) + { + /* in these cases and equal type is enough */ + case cJSON_False: + case cJSON_True: + case cJSON_NULL: + return true; + + case cJSON_Number: + if (compare_double(a->valuedouble, b->valuedouble)) + { + return true; + } + return false; + + case cJSON_String: + case cJSON_Raw: + if ((a->valuestring == NULL) || (b->valuestring == NULL)) + { + return false; + } + if (strcmp(a->valuestring, b->valuestring) == 0) + { + return true; + } + + return false; + + case cJSON_Array: + { + cJSON *a_element = a->child; + cJSON *b_element = b->child; + + for (; (a_element != NULL) && (b_element != NULL);) + { + if (!cJSON_Compare(a_element, b_element, case_sensitive)) + { + return false; + } + + a_element = a_element->next; + b_element = b_element->next; + } + + /* one of the arrays is longer than the other */ + if (a_element != b_element) { + return false; + } + + return true; + } + + case cJSON_Object: + { + cJSON *a_element = NULL; + cJSON *b_element = NULL; + cJSON_ArrayForEach(a_element, a) + { + /* TODO This has O(n^2) runtime, which is horrible! */ + b_element = get_object_item(b, a_element->string, case_sensitive); + if (b_element == NULL) + { + return false; + } + + if (!cJSON_Compare(a_element, b_element, case_sensitive)) + { + return false; + } + } + + /* doing this twice, once on a and b to prevent true comparison if a subset of b + * TODO: Do this the proper way, this is just a fix for now */ + cJSON_ArrayForEach(b_element, b) + { + a_element = get_object_item(a, b_element->string, case_sensitive); + if (a_element == NULL) + { + return false; + } + + if (!cJSON_Compare(b_element, a_element, case_sensitive)) + { + return false; + } + } + + return true; + } + + default: + return false; + } +} + +CJSON_PUBLIC(void *) cJSON_malloc(size_t size) +{ + return global_hooks.allocate(size); +} + +CJSON_PUBLIC(void) cJSON_free(void *object) +{ + global_hooks.deallocate(object); +} diff --git a/APP_Framework/Applications/knowing_app/helmet_detect/cJSON.h b/APP_Framework/Applications/knowing_app/helmet_detect/cJSON.h new file mode 100644 index 00000000..e97e5f4c --- /dev/null +++ b/APP_Framework/Applications/knowing_app/helmet_detect/cJSON.h @@ -0,0 +1,293 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef cJSON__h +#define cJSON__h + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) +#define __WINDOWS__ +#endif + +#ifdef __WINDOWS__ + +/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options: + +CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols +CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) +CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol + +For *nix builds that support visibility attribute, you can define similar behavior by + +setting default visibility to hidden by adding +-fvisibility=hidden (for gcc) +or +-xldscope=hidden (for sun cc) +to CFLAGS + +then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does + +*/ + +#define CJSON_CDECL __cdecl +#define CJSON_STDCALL __stdcall + +/* export symbols by default, this is necessary for copy pasting the C and header file */ +#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_EXPORT_SYMBOLS +#endif + +#if defined(CJSON_HIDE_SYMBOLS) +#define CJSON_PUBLIC(type) type CJSON_STDCALL +#elif defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL +#elif defined(CJSON_IMPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL +#endif +#else /* !__WINDOWS__ */ +#define CJSON_CDECL +#define CJSON_STDCALL + +#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) +#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type +#else +#define CJSON_PUBLIC(type) type +#endif +#endif + +/* project version */ +#define CJSON_VERSION_MAJOR 1 +#define CJSON_VERSION_MINOR 7 +#define CJSON_VERSION_PATCH 14 + +#include + +/* cJSON Types: */ +#define cJSON_Invalid (0) +#define cJSON_False (1 << 0) +#define cJSON_True (1 << 1) +#define cJSON_NULL (1 << 2) +#define cJSON_Number (1 << 3) +#define cJSON_String (1 << 4) +#define cJSON_Array (1 << 5) +#define cJSON_Object (1 << 6) +#define cJSON_Raw (1 << 7) /* raw json */ + +#define cJSON_IsReference 256 +#define cJSON_StringIsConst 512 + +/* The cJSON structure: */ +typedef struct cJSON +{ + /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ + struct cJSON *next; + struct cJSON *prev; + /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ + struct cJSON *child; + + /* The type of the item, as above. */ + int type; + + /* The item's string, if type==cJSON_String and type == cJSON_Raw */ + char *valuestring; + /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ + int valueint; + /* The item's number, if type==cJSON_Number */ + double valuedouble; + + /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ + char *string; +} cJSON; + +typedef struct cJSON_Hooks +{ + /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */ + void *(CJSON_CDECL *malloc_fn)(size_t sz); + void (CJSON_CDECL *free_fn)(void *ptr); +} cJSON_Hooks; + +typedef int cJSON_bool; + +/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them. + * This is to prevent stack overflows. */ +#ifndef CJSON_NESTING_LIMIT +#define CJSON_NESTING_LIMIT 1000 +#endif + +/* returns the version of cJSON as a string */ +CJSON_PUBLIC(const char*) cJSON_Version(void); + +/* Supply malloc, realloc and free functions to cJSON */ +CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); + +/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ +/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ +CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); +CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length); +/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ +/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */ +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); +CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated); + +/* Render a cJSON entity to text for transfer/storage. */ +CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); +/* Render a cJSON entity to text for transfer/storage without any formatting. */ +CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); +/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); +/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ +/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); +/* Delete a cJSON entity and all subentities. */ +CJSON_PUBLIC(void) cJSON_Delete(cJSON *item); + +/* Returns the number of items in an array (or object). */ +CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); +/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */ +CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); +/* Get item "string" from object. Case insensitive. */ +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); +CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string); +/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ +CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); + +/* Check item type and return its value */ +CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item); +CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item); + +/* These functions check the type of an item */ +CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item); + +/* These calls create a cJSON item of the appropriate type. */ +CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); +CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); +CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); +/* raw json */ +CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); +CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); + +/* Create a string where valuestring references a string so + * it will not be freed by cJSON_Delete */ +CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); +/* Create an object/array that only references it's elements so + * they will not be freed by cJSON_Delete */ +CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); +CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); + +/* These utilities create an Array of count items. + * The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/ +CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count); + +/* Append item to the specified array/object. */ +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item); +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); +/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. + * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before + * writing to `item->string` */ +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); +/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); + +/* Remove/Detach items from Arrays/Objects. */ +CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); +CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); +CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); +CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); + +/* Update array items. */ +CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem); + +/* Duplicate a cJSON item */ +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); +/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will + * need to be released. With recurse!=0, it will duplicate any children connected to the item. + * The item->next and ->prev pointers are always zero on return from Duplicate. */ +/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal. + * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ +CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); + +/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings. + * The input pointer json cannot point to a read-only address area, such as a string constant, + * but should point to a readable and writable adress area. */ +CJSON_PUBLIC(void) cJSON_Minify(char *json); + +/* Helper functions for creating and adding items to an object at the same time. + * They return the added item or NULL on failure. */ +CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean); +CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number); +CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string); +CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw); +CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name); + +/* When assigning an integer value, it needs to be propagated to valuedouble too. */ +#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) +/* helper for the cJSON_SetNumberValue macro */ +CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); +#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) +/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */ +CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring); + +/* Macro for iterating over an array or object */ +#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) + +/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ +CJSON_PUBLIC(void *) cJSON_malloc(size_t size); +CJSON_PUBLIC(void) cJSON_free(void *object); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/APP_Framework/Applications/knowing_app/helmet_detect/helmet.json b/APP_Framework/Applications/knowing_app/helmet_detect/helmet.json new file mode 100644 index 00000000..856dc4fe --- /dev/null +++ b/APP_Framework/Applications/knowing_app/helmet_detect/helmet.json @@ -0,0 +1,38 @@ +{ + "net_input_size": [ + 256, + 256 + ], + "net_output_shape": [ + 8, + 8, + 35 + ], + "sensor_output_size": [ + 256, + 256 + ], + "anchors": [ + 1.0432, + 1.0920, + 0.8391, + 2.1250, + 1.1085, + 2.7463, + 1.3783, + 3.6706, + 2.0491, + 4.6711 + ], + "kmodel_path": "/kmodel/helmet.kmodel", + "kmodel_size": 2714044, + "obj_thresh": [ + 0.85, + 0.6 + ], + "labels": [ + "helmet", + "head" + ], + "nms_thresh": 0.3 +} \ No newline at end of file diff --git a/APP_Framework/Applications/knowing_app/helmet_detect/helmet_detect.c b/APP_Framework/Applications/knowing_app/helmet_detect/helmet_detect.c new file mode 100644 index 00000000..68956f5b --- /dev/null +++ b/APP_Framework/Applications/knowing_app/helmet_detect/helmet_detect.c @@ -0,0 +1,379 @@ +#include + +#include "cJSON.h" +#include "region_layer.h" +#define ANCHOR_NUM 5 +#define STACK_SIZE (128 * 1024) +#define JSON_FILE_PATH "/kmodel/helmet.json" +#define JSON_BUFFER_SIZE (4 * 1024) + +// params from json +float anchor[ANCHOR_NUM * 2] = {}; +int net_output_shape[3] = {}; +int net_input_size[2] = {}; +int sensor_output_size[2] = {}; +char kmodel_path[127] = ""; +int kmodel_size = 0; +float obj_thresh[20] = {}; +float nms_thresh = 0.0; +char labels[20][32] = {}; +int class_num = 0; + +#define THREAD_PRIORITY_HELMET_D (11) +static pthread_t helmettid = 0; +static void *thread_helmet_detect_entry(void *parameter); +static int g_fd = 0; +static int kmodel_fd = 0; +static int if_exit = 0; +static unsigned char *showbuffer = NULL; +static unsigned char *kpurgbbuffer = NULL; + +static _ioctl_shoot_para shoot_para_t = {0}; +unsigned char *model_data = NULL; // kpu data load memory +unsigned char *model_data_align = NULL; + +kpu_model_context_t helmet_detect_task; +static region_layer_t helmet_detect_rl; +static obj_info_t helmet_detect_info; +volatile uint32_t g_ai_done_flag; + +static void ai_done(void *ctx) { g_ai_done_flag = 1; } + +static void param_parse() +{ + int fin; + char buffer[JSON_BUFFER_SIZE] = ""; + // char *buffer; + // if (NULL != (buffer = (char*)malloc(JSON_BUFFER_SIZE * sizeof(char)))) { + // memset(buffer, 0, JSON_BUFFER_SIZE * sizeof(char)); + // } else { + // printf("Json buffer malloc failed!"); + // exit(-1); + // } + int array_size; + cJSON *json_obj; + cJSON *json_item; + cJSON *json_array_item; + + fin = open(JSON_FILE_PATH, O_RDONLY); + if (!fin) { + printf("Error open file %s", JSON_FILE_PATH); + exit(-1); + } + read(fin, buffer, sizeof(buffer)); + close(fin); + + // read json string + json_obj = cJSON_Parse(buffer); + // free(buffer); + char *json_print_str = cJSON_Print(json_obj); + printf("Json file content: \n%s\n", json_print_str); + cJSON_free(json_print_str); + // get anchors + json_item = cJSON_GetObjectItem(json_obj, "anchors"); + array_size = cJSON_GetArraySize(json_item); + if (ANCHOR_NUM * 2 != array_size) { + printf("Expect anchor size: %d, got %d in json file", ANCHOR_NUM * 2, array_size); + exit(-1); + } else { + printf("Got %d anchors from json file\n", ANCHOR_NUM); + } + for (int i = 0; i < ANCHOR_NUM * 2; i++) { + json_array_item = cJSON_GetArrayItem(json_item, i); + anchor[i] = json_array_item->valuedouble; + printf("%d: %f\n", i, anchor[i]); + } + // net_input_size + json_item = cJSON_GetObjectItem(json_obj, "net_input_size"); + array_size = cJSON_GetArraySize(json_item); + if (2 != array_size) { + printf("Expect net_input_size: %d, got %d in json file", 2, array_size); + exit(-1); + } else { + printf("Got %d net_input_size from json file\n", 2); + } + for (int i = 0; i < 2; i++) { + json_array_item = cJSON_GetArrayItem(json_item, i); + net_input_size[i] = json_array_item->valueint; + printf("%d: %d\n", i, net_input_size[i]); + } + // net_output_shape + json_item = cJSON_GetObjectItem(json_obj, "net_output_shape"); + array_size = cJSON_GetArraySize(json_item); + if (3 != array_size) { + printf("Expect net_output_shape: %d, got %d in json file", 3, array_size); + exit(-1); + } else { + printf("Got %d net_output_shape from json file\n", 3); + } + for (int i = 0; i < 3; i++) { + json_array_item = cJSON_GetArrayItem(json_item, i); + net_output_shape[i] = json_array_item->valueint; + printf("%d: %d\n", i, net_output_shape[i]); + } + // sensor_output_size + json_item = cJSON_GetObjectItem(json_obj, "sensor_output_size"); + array_size = cJSON_GetArraySize(json_item); + if (2 != array_size) { + printf("Expect sensor_output_size: %d, got %d in json file", 2, array_size); + exit(-1); + } else { + printf("Got %d sensor_output_size from json file\n", 2); + } + for (int i = 0; i < 2; i++) { + json_array_item = cJSON_GetArrayItem(json_item, i); + sensor_output_size[i] = json_array_item->valueint; + printf("%d: %d\n", i, sensor_output_size[i]); + } + // kmodel_path + json_item = cJSON_GetObjectItem(json_obj, "kmodel_path"); + memcpy(kmodel_path, json_item->valuestring, strlen(json_item->valuestring)); + printf("Got kmodel_path: %s\n", kmodel_path); + // kmodel_size + json_item = cJSON_GetObjectItem(json_obj, "kmodel_size"); + kmodel_size = json_item->valueint; + printf("Got kmodel_size: %d\n", kmodel_size); + // labels + json_item = cJSON_GetObjectItem(json_obj, "labels"); + class_num = cJSON_GetArraySize(json_item); + if (0 >= class_num) { + printf("No labels!"); + exit(-1); + } else { + printf("Got %d labels\n"); + } + for (int i = 0; i < class_num; i++) { + json_array_item = cJSON_GetArrayItem(json_item, i); + memcpy(labels[i], json_item->valuestring, strlen(json_item->valuestring)); + printf("%d: %f\n", i, labels[i]); + } + // obj_thresh + json_item = cJSON_GetObjectItem(json_obj, "obj_thresh"); + array_size = cJSON_GetArraySize(json_item); + if (class_num != array_size) { + printf("label number and thresh number mismatch! label number : %d, obj thresh number %d", class_num, array_size); + exit(-1); + } else { + printf("Got %d obj_thresh\n"); + } + for (int i = 0; i < array_size; i++) { + json_array_item = cJSON_GetArrayItem(json_item, i); + obj_thresh[i] = json_array_item->valuedouble; + printf("%d: %f\n", i, obj_thresh[i]); + } + // nms_thresh + json_item = cJSON_GetObjectItem(json_obj, "nms_thresh"); + nms_thresh = json_item->valuedouble; + printf("Got nms_thresh: %f\n", nms_thresh); + + cJSON_Delete(json_obj); + return; +} + +void helmet_detect() +{ + int ret = 0; + int result = 0; + int size = 0; + param_parse(); + g_fd = open("/dev/ov2640", O_RDONLY); + if (g_fd < 0) { + printf("open ov2640 fail !!"); + return; + } + showbuffer = (unsigned char *)malloc(sensor_output_size[0] * sensor_output_size[1] * 2); + if (NULL == showbuffer) { + close(g_fd); + printf("showbuffer apply memory fail !!"); + return; + } + kpurgbbuffer = (unsigned char *)malloc(net_input_size[0] * net_input_size[1] * 3); + if (NULL == kpurgbbuffer) { + close(g_fd); + free(showbuffer); + printf("kpurgbbuffer apply memory fail !!"); + return; + } + model_data = (unsigned char *)malloc(kmodel_size + 255); + if (NULL == model_data) { + free(showbuffer); + free(kpurgbbuffer); + close(g_fd); + printf("model_data apply memory fail !!"); + return; + } + memset(model_data, 0, kmodel_size + 255); + memset(showbuffer, 0, sensor_output_size[0] * sensor_output_size[1] * 2); + memset(kpurgbbuffer, 127, net_input_size[0] * net_input_size[1] * 3); + shoot_para_t.pdata = (unsigned int *)(showbuffer); + shoot_para_t.length = (size_t)(sensor_output_size[0] * sensor_output_size[1] * 2); + /* + load memory + */ + kmodel_fd = open(kmodel_path, O_RDONLY); + if (kmodel_fd < 0) { + printf("open kmodel fail"); + close(g_fd); + free(showbuffer); + free(kpurgbbuffer); + free(model_data); + return; + } else { + size = read(kmodel_fd, model_data, kmodel_size); + if (size != kmodel_size) { + printf("read kmodel error size %d\n", size); + close(g_fd); + close(kmodel_fd); + free(showbuffer); + free(kpurgbbuffer); + free(model_data); + return; + + } else { + printf("read kmodel success \n"); + } + } + unsigned char *model_data_align = (unsigned char *)(((unsigned int)model_data + 255) & (~255)); + dvp_set_ai_addr((uint32_t)(kpurgbbuffer + net_input_size[1] * (net_input_size[0] - sensor_output_size[0])), + (uint32_t)(kpurgbbuffer + net_input_size[1] * (net_input_size[0] - sensor_output_size[0]) + + net_input_size[0] * net_input_size[1]), + (uint32_t)(kpurgbbuffer + net_input_size[0] * net_input_size[1] * 2 + + net_input_size[1] * (net_input_size[0] - sensor_output_size[0]))); + if (kpu_load_kmodel(&helmet_detect_task, model_data_align) != 0) { + printf("\nmodel init error\n"); + close(g_fd); + close(kmodel_fd); + free(showbuffer); + free(kpurgbbuffer); + free(model_data); + return; + } + helmet_detect_rl.anchor_number = ANCHOR_NUM; + helmet_detect_rl.anchor = anchor; + helmet_detect_rl.threshold = malloc(class_num * sizeof(float)); + for (int idx = 0; idx < class_num; idx++) { + helmet_detect_rl.threshold[idx] = obj_thresh[idx]; + } + helmet_detect_rl.nms_value = nms_thresh; + result = region_layer_init(&helmet_detect_rl, net_output_shape[0], net_output_shape[1], net_output_shape[2], + net_input_size[1], net_input_size[0]); + printf("region_layer_init result %d \n\r", result); + size_t stack_size = STACK_SIZE; + pthread_attr_t attr; /* 线程属性 */ + struct sched_param prio; /* 线程优先级 */ + prio.sched_priority = 8; /* 优先级设置为 8 */ + pthread_attr_init(&attr); /* 先使用默认值初始化属性 */ + pthread_attr_setschedparam(&attr, &prio); /* 修改属性对应的优先级 */ + pthread_attr_setstacksize(&attr, stack_size); + + /* 创建线程 1, 属性为 attr,入口函数是 thread_entry,入口函数参数是 1 */ + result = pthread_create(&helmettid, &attr, thread_helmet_detect_entry, NULL); + if (0 == result) { + printf("thread_helmet_detect_entry successfully!\n"); + } else { + printf("thread_helmet_detect_entry failed! error code is %d\n", result); + close(g_fd); + } +} +#ifdef __RT_THREAD_H__ +MSH_CMD_EXPORT(helmet_detect, helmet detect task); +#endif + +static void *thread_helmet_detect_entry(void *parameter) +{ + extern void lcd_draw_picture(uint16_t x1, uint16_t y1, uint16_t width, uint16_t height, uint32_t * ptr); + printf("thread_helmet_detect_entry start!\n"); + int ret = 0; + // sysctl_enable_irq(); + while (1) { + // memset(showbuffer,0,320*240*2); + g_ai_done_flag = 0; + ret = ioctl(g_fd, IOCTRL_CAMERA_START_SHOT, &shoot_para_t); + if (RT_ERROR == ret) { + printf("ov2640 can't wait event flag"); + rt_free(showbuffer); + close(g_fd); + pthread_exit(NULL); + return NULL; + } + kpu_run_kmodel(&helmet_detect_task, kpurgbbuffer, DMAC_CHANNEL5, ai_done, NULL); + while (!g_ai_done_flag) + ; + float *output; + size_t output_size; + kpu_get_output(&helmet_detect_task, 0, (uint8_t **)&output, &output_size); + helmet_detect_rl.input = output; + region_layer_run(&helmet_detect_rl, &helmet_detect_info); +/* display result */ +#ifdef BSP_USING_LCD + for (int helmet_cnt = 0; helmet_cnt < helmet_detect_info.obj_number; helmet_cnt++) { + // draw_edge((uint32_t *)showbuffer, &helmet_detect_info, helmet_cnt, 0xF800, + // (uint16_t)sensor_output_size[1], + // (uint16_t)sensor_output_size[0]); + printf("%d: (%d, %d, %d, %d) cls: %s conf: %f\t", helmet_cnt, helmet_detect_info.obj[helmet_cnt].x1, + helmet_detect_info.obj[helmet_cnt].y1, helmet_detect_info.obj[helmet_cnt].x2, + helmet_detect_info.obj[helmet_cnt].y2, labels[helmet_detect_info.obj[helmet_cnt].class_id], + helmet_detect_info.obj[helmet_cnt].prob); + } + if (0 != helmet_detect_info.obj_number) { + printf("\n"); + } else { + printf("No helmet or head found!\n"); + } + lcd_draw_picture(0, 0, (uint16_t)sensor_output_size[1], (uint16_t)sensor_output_size[0], (unsigned int *)showbuffer); +#endif + usleep(1); + if (1 == if_exit) { + if_exit = 0; + printf("thread_helmet_detect_entry exit"); + pthread_exit(NULL); + } + } +} + +void helmet_detect_delete() +{ + if (showbuffer != NULL) { + int ret = 0; + close(g_fd); + close(kmodel_fd); + free(showbuffer); + free(kpurgbbuffer); + free(model_data); + printf("helmet detect task cancel!!! ret %d ", ret); + if_exit = 1; + } +} +#ifdef __RT_THREAD_H__ +MSH_CMD_EXPORT(helmet_detect_delete, helmet detect task delete); +#endif + +void kmodel_load(unsigned char *model_data) +{ + int kmodel_fd = 0; + int size = 0; + kmodel_fd = open(kmodel_path, O_RDONLY); + + model_data = (unsigned char *)malloc(kmodel_size + 255); + if (NULL == model_data) { + printf("model_data apply memory fail !!"); + return; + } + memset(model_data, 0, kmodel_size + 255); + + if (kmodel_fd >= 0) { + size = read(kmodel_fd, model_data, kmodel_size); + if (size != kmodel_size) { + printf("read kmodel error size %d\n", size); + + } else { + printf("read kmodel success"); + } + } else { + free(model_data); + printf("open kmodel fail"); + } +} +#ifdef __RT_THREAD_H__ +MSH_CMD_EXPORT(kmodel_load, kmodel load memory); +#endif diff --git a/APP_Framework/Applications/knowing_app/instrusion_detect/human.json b/APP_Framework/Applications/knowing_app/instrusion_detect/human.json index bf8ca5c1..74d1d096 100644 --- a/APP_Framework/Applications/knowing_app/instrusion_detect/human.json +++ b/APP_Framework/Applications/knowing_app/instrusion_detect/human.json @@ -26,6 +26,11 @@ ], "kmodel_path": "/kmodel/human.kmodel", "kmodel_size": 1903016, - "obj_thresh": 0.3, + "obj_thresh": [ + 0.3 + ], + "labels": [ + "human" + ], "nms_thresh": 0.3 } \ No newline at end of file diff --git a/APP_Framework/Applications/knowing_app/instrusion_detect/instrusion_detect.c b/APP_Framework/Applications/knowing_app/instrusion_detect/instrusion_detect.c index 541ef7d6..8fad834c 100644 --- a/APP_Framework/Applications/knowing_app/instrusion_detect/instrusion_detect.c +++ b/APP_Framework/Applications/knowing_app/instrusion_detect/instrusion_detect.c @@ -14,8 +14,10 @@ int net_input_size[2] = {}; int sensor_output_size[2] = {}; char kmodel_path[127] = ""; int kmodel_size = 0; -float obj_thresh = 1.0; +float obj_thresh[20] = {}; float nms_thresh = 0.0; +char labels[20][32] = {}; +int class_num = 0; #define THREAD_PRIORITY_HUMAN_D (11) static pthread_t instrusiontid = 0; @@ -131,10 +133,34 @@ static void param_parse() json_item = cJSON_GetObjectItem(json_obj, "kmodel_size"); kmodel_size = json_item->valueint; printf("Got kmodel_size: %d\n", kmodel_size); + // labels + json_item = cJSON_GetObjectItem(json_obj, "labels"); + class_num = cJSON_GetArraySize(json_item); + if (0 >= class_num) { + printf("No labels!"); + exit(-1); + } else { + printf("Got %d labels\n"); + } + for (int i = 0; i < class_num; i++) { + json_array_item = cJSON_GetArrayItem(json_item, i); + memcpy(labels[i], json_item->valuestring, strlen(json_item->valuestring)); + printf("%d: %f\n", i, labels[i]); + } // obj_thresh json_item = cJSON_GetObjectItem(json_obj, "obj_thresh"); - obj_thresh = json_item->valuedouble; - printf("Got obj_thresh: %f\n", obj_thresh); + array_size = cJSON_GetArraySize(json_item); + if (class_num != array_size) { + printf("label number and thresh number mismatch! label number : %d, obj thresh number %d", class_num, array_size); + exit(-1); + } else { + printf("Got %d obj_thresh\n"); + } + for (int i = 0; i < array_size; i++) { + json_array_item = cJSON_GetArrayItem(json_item, i); + obj_thresh[i] = json_array_item->valuedouble; + printf("%d: %f\n", i, obj_thresh[i]); + } // nms_thresh json_item = cJSON_GetObjectItem(json_obj, "nms_thresh"); nms_thresh = json_item->valuedouble; @@ -224,7 +250,10 @@ void instrusion_detect() } instrusion_detect_rl.anchor_number = ANCHOR_NUM; instrusion_detect_rl.anchor = anchor; - instrusion_detect_rl.threshold = obj_thresh; + instrusion_detect_rl.threshold = malloc(class_num * sizeof(float)); + for (int idx = 0; idx < class_num; idx++) { + instrusion_detect_rl.threshold[idx] = obj_thresh[idx]; + ; instrusion_detect_rl.nms_value = nms_thresh; result = region_layer_init(&instrusion_detect_rl, net_output_shape[0], net_output_shape[1], net_output_shape[2], net_input_size[1], net_input_size[0]); diff --git a/APP_Framework/Framework/knowing/kpu-postprocessing/yolov2/region_layer.c b/APP_Framework/Framework/knowing/kpu-postprocessing/yolov2/region_layer.c index dad31268..bb37e6d9 100644 --- a/APP_Framework/Framework/knowing/kpu-postprocessing/yolov2/region_layer.c +++ b/APP_Framework/Framework/knowing/kpu-postprocessing/yolov2/region_layer.c @@ -189,7 +189,7 @@ static void get_region_boxes(region_layer_t *rl, float *predictions, float **pro uint32_t anchor_number = rl->anchor_number; uint32_t classes = rl->classes; uint32_t coords = rl->coords; - float threshold = rl->threshold; + float *threshold = rl->threshold; for (int i = 0; i < layer_width * layer_height; ++i) { int row = i / layer_width; @@ -212,7 +212,7 @@ static void get_region_boxes(region_layer_t *rl, float *predictions, float **pro int class_index = entry_index(rl, n * layer_width * layer_height + i, coords + 1 + j); float prob = scale * predictions[class_index]; - probs[index][j] = (prob > threshold) ? prob : 0; + probs[index][j] = (prob > threshold[j]) ? prob : 0; if (prob > max) max = prob; } probs[index][classes] = max; @@ -315,14 +315,14 @@ static void region_layer_output(region_layer_t *rl, obj_info_t *obj_info) uint32_t image_width = rl->image_width; uint32_t image_height = rl->image_height; uint32_t boxes_number = rl->boxes_number; - float threshold = rl->threshold; + float *threshold = rl->threshold; box_t *boxes = (box_t *)rl->boxes; for (int i = 0; i < rl->boxes_number; ++i) { int class = max_index(rl->probs[i], rl->classes); float prob = rl->probs[i][class]; - if (prob > threshold) { + if (prob > threshold[class]) { box_t *b = boxes + i; obj_info->obj[obj_number].x1 = b->x * image_width - (b->w * image_width / 2); obj_info->obj[obj_number].y1 = b->y * image_height - (b->h * image_height / 2); diff --git a/APP_Framework/Framework/knowing/kpu-postprocessing/yolov2/region_layer.h b/APP_Framework/Framework/knowing/kpu-postprocessing/yolov2/region_layer.h index 70d0ea99..3b9ae4cb 100644 --- a/APP_Framework/Framework/knowing/kpu-postprocessing/yolov2/region_layer.h +++ b/APP_Framework/Framework/knowing/kpu-postprocessing/yolov2/region_layer.h @@ -20,7 +20,7 @@ typedef struct typedef struct { - float threshold; + float *threshold; float nms_value; uint32_t coords; uint32_t anchor_number; diff --git a/Ubiquitous/RT_Thread/bsp/k210/base-drivers/drv_dvp.c b/Ubiquitous/RT_Thread/bsp/k210/base-drivers/drv_dvp.c index c1dbc389..41cd834e 100644 --- a/Ubiquitous/RT_Thread/bsp/k210/base-drivers/drv_dvp.c +++ b/Ubiquitous/RT_Thread/bsp/k210/base-drivers/drv_dvp.c @@ -67,7 +67,8 @@ static rt_err_t rt_dvp_init(rt_device_t dev) dvp_set_output_enable(0, 1); dvp_set_output_enable(1, 1); dvp_set_image_format(DVP_CFG_RGB_FORMAT);//////////////// - dvp_set_image_size(320, 240); + // dvp_set_image_size(320, 240); + dvp_set_image_size(256, 256); dvp_config_interrupt(DVP_CFG_FINISH_INT_ENABLE, 0); dvp_disable_auto(); plic_set_priority(IRQN_DVP_INTERRUPT, 1); From 168e36d09edfd90d8f209551b92291168ddbc212 Mon Sep 17 00:00:00 2001 From: Liu Yongkai <506680965@qq.com> Date: Thu, 5 Aug 2021 11:37:28 +0800 Subject: [PATCH 07/18] fix(knowing apps): adapting new cjson lib usage and some little bug fix --- .../knowing_app/face_detect/detect.json | 7 +- .../knowing_app/face_detect/face_detect.c | 66 +- .../knowing_app/helmet_detect/Kconfig | 1 + .../knowing_app/helmet_detect/cJSON.c | 3110 ----------------- .../knowing_app/helmet_detect/cJSON.h | 293 -- .../knowing_app/helmet_detect/helmet_detect.c | 35 +- .../knowing_app/instrusion_detect/Kconfig | 1 + .../knowing_app/instrusion_detect/cJSON.c | 3110 ----------------- .../knowing_app/instrusion_detect/cJSON.h | 293 -- .../knowing_app/instrusion_detect/human.json | 2 +- .../instrusion_detect/instrusion_detect.c | 41 +- 11 files changed, 89 insertions(+), 6870 deletions(-) delete mode 100644 APP_Framework/Applications/knowing_app/helmet_detect/cJSON.c delete mode 100644 APP_Framework/Applications/knowing_app/helmet_detect/cJSON.h delete mode 100644 APP_Framework/Applications/knowing_app/instrusion_detect/cJSON.c delete mode 100644 APP_Framework/Applications/knowing_app/instrusion_detect/cJSON.h diff --git a/APP_Framework/Applications/knowing_app/face_detect/detect.json b/APP_Framework/Applications/knowing_app/face_detect/detect.json index f3d181ef..b59731aa 100644 --- a/APP_Framework/Applications/knowing_app/face_detect/detect.json +++ b/APP_Framework/Applications/knowing_app/face_detect/detect.json @@ -26,6 +26,11 @@ ], "kmodel_path": "/kmodel/detect.kmodel", "kmodel_size": 388776, - "obj_thresh": 0.7, + "obj_thresh": [ + 0.7 + ], + "labels": [ + "face" + ], "nms_thresh": 0.3 } \ No newline at end of file diff --git a/APP_Framework/Applications/knowing_app/face_detect/face_detect.c b/APP_Framework/Applications/knowing_app/face_detect/face_detect.c index 3ce3319a..dc9c6568 100644 --- a/APP_Framework/Applications/knowing_app/face_detect/face_detect.c +++ b/APP_Framework/Applications/knowing_app/face_detect/face_detect.c @@ -8,24 +8,17 @@ #define JSON_FILE_PATH "/kmodel/detect.json" #define JSON_BUFFER_SIZE (4 * 1024) -// params from json -float anchor[ANCHOR_NUM * 2] = {}; -int net_output_shape[3] = {}; -int net_input_size[2] = {}; -int sensor_output_size[2] = {}; -char kmodel_path[127] = ""; -int kmodel_size = 0; -float obj_thresh = 1.0; -float nms_thresh = 0.0; - -// float anchor[ANCHOR_NUM * 2] = {1.889, 2.5245, 2.9465, 3.94056, 3.99987, 5.3658, 5.155437, 6.92275, 6.718375, 9.01025}; -// int net_output_shape[3] = {20, 15, 30}; -// int net_input_size[2] = {240, 320}; -// int sensor_output_size[2] = {240, 320}; -// char kmodel_path[127] = "/kmodel/detect.kmodel"; -// int kmodel_size = 388776; -// float obj_thresh = 0.7; -// float nms_thresh = 0.3; +// params from json +static float anchor[ANCHOR_NUM * 2] = {}; +static int net_output_shape[3] = {}; +static int net_input_size[2] = {}; +static int sensor_output_size[2] = {}; +static char kmodel_path[127] = ""; +static int kmodel_size = 0; +static float obj_thresh[20] = {}; +static float nms_thresh = 0.0; +static char labels[20][32] = {}; +static int class_num = 0; #define THREAD_PRIORITY_FACE_D (11) static pthread_t facetid = 0; @@ -141,10 +134,34 @@ static void param_parse() json_item = cJSON_GetObjectItem(json_obj, "kmodel_size"); kmodel_size = json_item->valueint; printf("Got kmodel_size: %d\n", kmodel_size); + // labels + json_item = cJSON_GetObjectItem(json_obj, "labels"); + class_num = cJSON_GetArraySize(json_item); + if (0 >= class_num) { + printf("No labels!"); + exit(-1); + } else { + printf("Got %d labels\n", class_num); + } + for (int i = 0; i < class_num; i++) { + json_array_item = cJSON_GetArrayItem(json_item, i); + memcpy(labels[i], json_array_item->valuestring, strlen(json_array_item->valuestring)); + printf("%d: %s\n", i, labels[i]); + } // obj_thresh json_item = cJSON_GetObjectItem(json_obj, "obj_thresh"); - obj_thresh = json_item->valuedouble; - printf("Got obj_thresh: %f\n", obj_thresh); + array_size = cJSON_GetArraySize(json_item); + if (class_num != array_size) { + printf("label number and thresh number mismatch! label number : %d, obj thresh number %d", class_num, array_size); + exit(-1); + } else { + printf("Got %d obj_thresh\n", array_size); + } + for (int i = 0; i < array_size; i++) { + json_array_item = cJSON_GetArrayItem(json_item, i); + obj_thresh[i] = json_array_item->valuedouble; + printf("%d: %f\n", i, obj_thresh[i]); + } // nms_thresh json_item = cJSON_GetObjectItem(json_obj, "nms_thresh"); nms_thresh = json_item->valuedouble; @@ -231,7 +248,10 @@ void face_detect() } face_detect_rl.anchor_number = ANCHOR_NUM; face_detect_rl.anchor = anchor; - face_detect_rl.threshold = obj_thresh; + face_detect_rl.threshold = malloc(class_num * sizeof(float)); + for (int idx = 0; idx < class_num; idx++) { + face_detect_rl.threshold[idx] = obj_thresh[idx]; + } face_detect_rl.nms_value = nms_thresh; result = region_layer_init(&face_detect_rl, net_output_shape[0], net_output_shape[1], net_output_shape[2], net_input_size[1], net_input_size[0]); @@ -287,9 +307,9 @@ static void *thread_face_detcet_entry(void *parameter) for (int face_cnt = 0; face_cnt < face_detect_info.obj_number; face_cnt++) { draw_edge((uint32_t *)showbuffer, &face_detect_info, face_cnt, 0xF800, (uint16_t)sensor_output_size[1], (uint16_t)sensor_output_size[0]); - printf("%d: (%d, %d, %d, %d) cls: %d conf: %f\t", face_cnt, face_detect_info.obj[face_cnt].x1, + printf("%d: (%d, %d, %d, %d) cls: %s conf: %f\t", face_cnt, face_detect_info.obj[face_cnt].x1, face_detect_info.obj[face_cnt].y1, face_detect_info.obj[face_cnt].x2, face_detect_info.obj[face_cnt].y2, - face_detect_info.obj[face_cnt].class_id, face_detect_info.obj[face_cnt].prob); + labels[face_detect_info.obj[face_cnt].class_id], face_detect_info.obj[face_cnt].prob); } if (0 != face_detect_info.obj_number) printf("\n"); lcd_draw_picture(0, 0, (uint16_t)sensor_output_size[1], (uint16_t)sensor_output_size[0], (unsigned int *)showbuffer); diff --git a/APP_Framework/Applications/knowing_app/helmet_detect/Kconfig b/APP_Framework/Applications/knowing_app/helmet_detect/Kconfig index c279e86b..3a090133 100644 --- a/APP_Framework/Applications/knowing_app/helmet_detect/Kconfig +++ b/APP_Framework/Applications/knowing_app/helmet_detect/Kconfig @@ -4,4 +4,5 @@ config HELMET_DETECT depends on DRV_USING_OV2640 depends on USING_KPU_POSTPROCESSING depends on USING_YOLOV2 + select LIB_USING_CJSON default n diff --git a/APP_Framework/Applications/knowing_app/helmet_detect/cJSON.c b/APP_Framework/Applications/knowing_app/helmet_detect/cJSON.c deleted file mode 100644 index 030311ce..00000000 --- a/APP_Framework/Applications/knowing_app/helmet_detect/cJSON.c +++ /dev/null @@ -1,3110 +0,0 @@ -/* - Copyright (c) 2009-2017 Dave Gamble and cJSON contributors - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*/ - -/* cJSON */ -/* JSON parser in C. */ - -/* disable warnings about old C89 functions in MSVC */ -#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) -#define _CRT_SECURE_NO_DEPRECATE -#endif - -#ifdef __GNUC__ -#pragma GCC visibility push(default) -#endif -#if defined(_MSC_VER) -#pragma warning (push) -/* disable warning about single line comments in system headers */ -#pragma warning (disable : 4001) -#endif - -#include -#include -#include -#include -#include -#include -#include - -#ifdef ENABLE_LOCALES -#include -#endif - -#if defined(_MSC_VER) -#pragma warning (pop) -#endif -#ifdef __GNUC__ -#pragma GCC visibility pop -#endif - -#include "cJSON.h" - -/* define our own boolean type */ -#ifdef true -#undef true -#endif -#define true ((cJSON_bool)1) - -#ifdef false -#undef false -#endif -#define false ((cJSON_bool)0) - -/* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */ -#ifndef isinf -#define isinf(d) (isnan((d - d)) && !isnan(d)) -#endif -#ifndef isnan -#define isnan(d) (d != d) -#endif - -#ifndef NAN -#ifdef _WIN32 -#define NAN sqrt(-1.0) -#else -#define NAN 0.0/0.0 -#endif -#endif - -typedef struct { - const unsigned char *json; - size_t position; -} error; -static error global_error = { NULL, 0 }; - -CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) -{ - return (const char*) (global_error.json + global_error.position); -} - -CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item) -{ - if (!cJSON_IsString(item)) - { - return NULL; - } - - return item->valuestring; -} - -CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item) -{ - if (!cJSON_IsNumber(item)) - { - return (double) NAN; - } - - return item->valuedouble; -} - -/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 14) - #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. -#endif - -CJSON_PUBLIC(const char*) cJSON_Version(void) -{ - static char version[15]; - sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); - - return version; -} - -/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */ -static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) -{ - if ((string1 == NULL) || (string2 == NULL)) - { - return 1; - } - - if (string1 == string2) - { - return 0; - } - - for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++) - { - if (*string1 == '\0') - { - return 0; - } - } - - return tolower(*string1) - tolower(*string2); -} - -typedef struct internal_hooks -{ - void *(CJSON_CDECL *allocate)(size_t size); - void (CJSON_CDECL *deallocate)(void *pointer); - void *(CJSON_CDECL *reallocate)(void *pointer, size_t size); -} internal_hooks; - -#if defined(_MSC_VER) -/* work around MSVC error C2322: '...' address of dllimport '...' is not static */ -static void * CJSON_CDECL internal_malloc(size_t size) -{ - return malloc(size); -} -static void CJSON_CDECL internal_free(void *pointer) -{ - free(pointer); -} -static void * CJSON_CDECL internal_realloc(void *pointer, size_t size) -{ - return realloc(pointer, size); -} -#else -#define internal_malloc malloc -#define internal_free free -#define internal_realloc realloc -#endif - -/* strlen of character literals resolved at compile time */ -#define static_strlen(string_literal) (sizeof(string_literal) - sizeof("")) - -static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc }; - -static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks) -{ - size_t length = 0; - unsigned char *copy = NULL; - - if (string == NULL) - { - return NULL; - } - - length = strlen((const char*)string) + sizeof(""); - copy = (unsigned char*)hooks->allocate(length); - if (copy == NULL) - { - return NULL; - } - memcpy(copy, string, length); - - return copy; -} - -CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) -{ - if (hooks == NULL) - { - /* Reset hooks */ - global_hooks.allocate = malloc; - global_hooks.deallocate = free; - global_hooks.reallocate = realloc; - return; - } - - global_hooks.allocate = malloc; - if (hooks->malloc_fn != NULL) - { - global_hooks.allocate = hooks->malloc_fn; - } - - global_hooks.deallocate = free; - if (hooks->free_fn != NULL) - { - global_hooks.deallocate = hooks->free_fn; - } - - /* use realloc only if both free and malloc are used */ - global_hooks.reallocate = NULL; - if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free)) - { - global_hooks.reallocate = realloc; - } -} - -/* Internal constructor. */ -static cJSON *cJSON_New_Item(const internal_hooks * const hooks) -{ - cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON)); - if (node) - { - memset(node, '\0', sizeof(cJSON)); - } - - return node; -} - -/* Delete a cJSON structure. */ -CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) -{ - cJSON *next = NULL; - while (item != NULL) - { - next = item->next; - if (!(item->type & cJSON_IsReference) && (item->child != NULL)) - { - cJSON_Delete(item->child); - } - if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) - { - global_hooks.deallocate(item->valuestring); - } - if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) - { - global_hooks.deallocate(item->string); - } - global_hooks.deallocate(item); - item = next; - } -} - -/* get the decimal point character of the current locale */ -static unsigned char get_decimal_point(void) -{ -#ifdef ENABLE_LOCALES - struct lconv *lconv = localeconv(); - return (unsigned char) lconv->decimal_point[0]; -#else - return '.'; -#endif -} - -typedef struct -{ - const unsigned char *content; - size_t length; - size_t offset; - size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */ - internal_hooks hooks; -} parse_buffer; - -/* check if the given size is left to read in a given parse buffer (starting with 1) */ -#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length)) -/* check if the buffer can be accessed at the given index (starting with 0) */ -#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length)) -#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index)) -/* get a pointer to the buffer at the position */ -#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset) - -/* Parse the input text to generate a number, and populate the result into item. */ -static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer) -{ - double number = 0; - unsigned char *after_end = NULL; - unsigned char number_c_string[64]; - unsigned char decimal_point = get_decimal_point(); - size_t i = 0; - - if ((input_buffer == NULL) || (input_buffer->content == NULL)) - { - return false; - } - - /* copy the number into a temporary buffer and replace '.' with the decimal point - * of the current locale (for strtod) - * This also takes care of '\0' not necessarily being available for marking the end of the input */ - for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) - { - switch (buffer_at_offset(input_buffer)[i]) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '+': - case '-': - case 'e': - case 'E': - number_c_string[i] = buffer_at_offset(input_buffer)[i]; - break; - - case '.': - number_c_string[i] = decimal_point; - break; - - default: - goto loop_end; - } - } -loop_end: - number_c_string[i] = '\0'; - - number = strtod((const char*)number_c_string, (char**)&after_end); - if (number_c_string == after_end) - { - return false; /* parse_error */ - } - - item->valuedouble = number; - - /* use saturation in case of overflow */ - if (number >= INT_MAX) - { - item->valueint = INT_MAX; - } - else if (number <= (double)INT_MIN) - { - item->valueint = INT_MIN; - } - else - { - item->valueint = (int)number; - } - - item->type = cJSON_Number; - - input_buffer->offset += (size_t)(after_end - number_c_string); - return true; -} - -/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ -CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) -{ - if (number >= INT_MAX) - { - object->valueint = INT_MAX; - } - else if (number <= (double)INT_MIN) - { - object->valueint = INT_MIN; - } - else - { - object->valueint = (int)number; - } - - return object->valuedouble = number; -} - -CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring) -{ - char *copy = NULL; - /* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */ - if (!(object->type & cJSON_String) || (object->type & cJSON_IsReference)) - { - return NULL; - } - if (strlen(valuestring) <= strlen(object->valuestring)) - { - strcpy(object->valuestring, valuestring); - return object->valuestring; - } - copy = (char*) cJSON_strdup((const unsigned char*)valuestring, &global_hooks); - if (copy == NULL) - { - return NULL; - } - if (object->valuestring != NULL) - { - cJSON_free(object->valuestring); - } - object->valuestring = copy; - - return copy; -} - -typedef struct -{ - unsigned char *buffer; - size_t length; - size_t offset; - size_t depth; /* current nesting depth (for formatted printing) */ - cJSON_bool noalloc; - cJSON_bool format; /* is this print a formatted print */ - internal_hooks hooks; -} printbuffer; - -/* realloc printbuffer if necessary to have at least "needed" bytes more */ -static unsigned char* ensure(printbuffer * const p, size_t needed) -{ - unsigned char *newbuffer = NULL; - size_t newsize = 0; - - if ((p == NULL) || (p->buffer == NULL)) - { - return NULL; - } - - if ((p->length > 0) && (p->offset >= p->length)) - { - /* make sure that offset is valid */ - return NULL; - } - - if (needed > INT_MAX) - { - /* sizes bigger than INT_MAX are currently not supported */ - return NULL; - } - - needed += p->offset + 1; - if (needed <= p->length) - { - return p->buffer + p->offset; - } - - if (p->noalloc) { - return NULL; - } - - /* calculate new buffer size */ - if (needed > (INT_MAX / 2)) - { - /* overflow of int, use INT_MAX if possible */ - if (needed <= INT_MAX) - { - newsize = INT_MAX; - } - else - { - return NULL; - } - } - else - { - newsize = needed * 2; - } - - if (p->hooks.reallocate != NULL) - { - /* reallocate with realloc if available */ - newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize); - if (newbuffer == NULL) - { - p->hooks.deallocate(p->buffer); - p->length = 0; - p->buffer = NULL; - - return NULL; - } - } - else - { - /* otherwise reallocate manually */ - newbuffer = (unsigned char*)p->hooks.allocate(newsize); - if (!newbuffer) - { - p->hooks.deallocate(p->buffer); - p->length = 0; - p->buffer = NULL; - - return NULL; - } - - memcpy(newbuffer, p->buffer, p->offset + 1); - p->hooks.deallocate(p->buffer); - } - p->length = newsize; - p->buffer = newbuffer; - - return newbuffer + p->offset; -} - -/* calculate the new length of the string in a printbuffer and update the offset */ -static void update_offset(printbuffer * const buffer) -{ - const unsigned char *buffer_pointer = NULL; - if ((buffer == NULL) || (buffer->buffer == NULL)) - { - return; - } - buffer_pointer = buffer->buffer + buffer->offset; - - buffer->offset += strlen((const char*)buffer_pointer); -} - -/* securely comparison of floating-point variables */ -static cJSON_bool compare_double(double a, double b) -{ - double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b); - return (fabs(a - b) <= maxVal * DBL_EPSILON); -} - -/* Render the number nicely from the given item into a string. */ -static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer) -{ - unsigned char *output_pointer = NULL; - double d = item->valuedouble; - int length = 0; - size_t i = 0; - unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */ - unsigned char decimal_point = get_decimal_point(); - double test = 0.0; - - if (output_buffer == NULL) - { - return false; - } - - /* This checks for NaN and Infinity */ - if (isnan(d) || isinf(d)) - { - length = sprintf((char*)number_buffer, "null"); - } - else - { - /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ - length = sprintf((char*)number_buffer, "%1.15g", d); - - /* Check whether the original double can be recovered */ - if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d)) - { - /* If not, print with 17 decimal places of precision */ - length = sprintf((char*)number_buffer, "%1.17g", d); - } - } - - /* sprintf failed or buffer overrun occurred */ - if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) - { - return false; - } - - /* reserve appropriate space in the output */ - output_pointer = ensure(output_buffer, (size_t)length + sizeof("")); - if (output_pointer == NULL) - { - return false; - } - - /* copy the printed number to the output and replace locale - * dependent decimal point with '.' */ - for (i = 0; i < ((size_t)length); i++) - { - if (number_buffer[i] == decimal_point) - { - output_pointer[i] = '.'; - continue; - } - - output_pointer[i] = number_buffer[i]; - } - output_pointer[i] = '\0'; - - output_buffer->offset += (size_t)length; - - return true; -} - -/* parse 4 digit hexadecimal number */ -static unsigned parse_hex4(const unsigned char * const input) -{ - unsigned int h = 0; - size_t i = 0; - - for (i = 0; i < 4; i++) - { - /* parse digit */ - if ((input[i] >= '0') && (input[i] <= '9')) - { - h += (unsigned int) input[i] - '0'; - } - else if ((input[i] >= 'A') && (input[i] <= 'F')) - { - h += (unsigned int) 10 + input[i] - 'A'; - } - else if ((input[i] >= 'a') && (input[i] <= 'f')) - { - h += (unsigned int) 10 + input[i] - 'a'; - } - else /* invalid */ - { - return 0; - } - - if (i < 3) - { - /* shift left to make place for the next nibble */ - h = h << 4; - } - } - - return h; -} - -/* converts a UTF-16 literal to UTF-8 - * A literal can be one or two sequences of the form \uXXXX */ -static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer) -{ - long unsigned int codepoint = 0; - unsigned int first_code = 0; - const unsigned char *first_sequence = input_pointer; - unsigned char utf8_length = 0; - unsigned char utf8_position = 0; - unsigned char sequence_length = 0; - unsigned char first_byte_mark = 0; - - if ((input_end - first_sequence) < 6) - { - /* input ends unexpectedly */ - goto fail; - } - - /* get the first utf16 sequence */ - first_code = parse_hex4(first_sequence + 2); - - /* check that the code is valid */ - if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) - { - goto fail; - } - - /* UTF16 surrogate pair */ - if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) - { - const unsigned char *second_sequence = first_sequence + 6; - unsigned int second_code = 0; - sequence_length = 12; /* \uXXXX\uXXXX */ - - if ((input_end - second_sequence) < 6) - { - /* input ends unexpectedly */ - goto fail; - } - - if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) - { - /* missing second half of the surrogate pair */ - goto fail; - } - - /* get the second utf16 sequence */ - second_code = parse_hex4(second_sequence + 2); - /* check that the code is valid */ - if ((second_code < 0xDC00) || (second_code > 0xDFFF)) - { - /* invalid second half of the surrogate pair */ - goto fail; - } - - - /* calculate the unicode codepoint from the surrogate pair */ - codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF)); - } - else - { - sequence_length = 6; /* \uXXXX */ - codepoint = first_code; - } - - /* encode as UTF-8 - * takes at maximum 4 bytes to encode: - * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ - if (codepoint < 0x80) - { - /* normal ascii, encoding 0xxxxxxx */ - utf8_length = 1; - } - else if (codepoint < 0x800) - { - /* two bytes, encoding 110xxxxx 10xxxxxx */ - utf8_length = 2; - first_byte_mark = 0xC0; /* 11000000 */ - } - else if (codepoint < 0x10000) - { - /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ - utf8_length = 3; - first_byte_mark = 0xE0; /* 11100000 */ - } - else if (codepoint <= 0x10FFFF) - { - /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ - utf8_length = 4; - first_byte_mark = 0xF0; /* 11110000 */ - } - else - { - /* invalid unicode codepoint */ - goto fail; - } - - /* encode as utf8 */ - for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) - { - /* 10xxxxxx */ - (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF); - codepoint >>= 6; - } - /* encode first byte */ - if (utf8_length > 1) - { - (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF); - } - else - { - (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F); - } - - *output_pointer += utf8_length; - - return sequence_length; - -fail: - return 0; -} - -/* Parse the input text into an unescaped cinput, and populate item. */ -static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer) -{ - const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; - const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; - unsigned char *output_pointer = NULL; - unsigned char *output = NULL; - - /* not a string */ - if (buffer_at_offset(input_buffer)[0] != '\"') - { - goto fail; - } - - { - /* calculate approximate size of the output (overestimate) */ - size_t allocation_length = 0; - size_t skipped_bytes = 0; - while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) - { - /* is escape sequence */ - if (input_end[0] == '\\') - { - if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) - { - /* prevent buffer overflow when last input character is a backslash */ - goto fail; - } - skipped_bytes++; - input_end++; - } - input_end++; - } - if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) - { - goto fail; /* string ended unexpectedly */ - } - - /* This is at most how much we need for the output */ - allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes; - output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof("")); - if (output == NULL) - { - goto fail; /* allocation failure */ - } - } - - output_pointer = output; - /* loop through the string literal */ - while (input_pointer < input_end) - { - if (*input_pointer != '\\') - { - *output_pointer++ = *input_pointer++; - } - /* escape sequence */ - else - { - unsigned char sequence_length = 2; - if ((input_end - input_pointer) < 1) - { - goto fail; - } - - switch (input_pointer[1]) - { - case 'b': - *output_pointer++ = '\b'; - break; - case 'f': - *output_pointer++ = '\f'; - break; - case 'n': - *output_pointer++ = '\n'; - break; - case 'r': - *output_pointer++ = '\r'; - break; - case 't': - *output_pointer++ = '\t'; - break; - case '\"': - case '\\': - case '/': - *output_pointer++ = input_pointer[1]; - break; - - /* UTF-16 literal */ - case 'u': - sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); - if (sequence_length == 0) - { - /* failed to convert UTF16-literal to UTF-8 */ - goto fail; - } - break; - - default: - goto fail; - } - input_pointer += sequence_length; - } - } - - /* zero terminate the output */ - *output_pointer = '\0'; - - item->type = cJSON_String; - item->valuestring = (char*)output; - - input_buffer->offset = (size_t) (input_end - input_buffer->content); - input_buffer->offset++; - - return true; - -fail: - if (output != NULL) - { - input_buffer->hooks.deallocate(output); - } - - if (input_pointer != NULL) - { - input_buffer->offset = (size_t)(input_pointer - input_buffer->content); - } - - return false; -} - -/* Render the cstring provided to an escaped version that can be printed. */ -static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer) -{ - const unsigned char *input_pointer = NULL; - unsigned char *output = NULL; - unsigned char *output_pointer = NULL; - size_t output_length = 0; - /* numbers of additional characters needed for escaping */ - size_t escape_characters = 0; - - if (output_buffer == NULL) - { - return false; - } - - /* empty string */ - if (input == NULL) - { - output = ensure(output_buffer, sizeof("\"\"")); - if (output == NULL) - { - return false; - } - strcpy((char*)output, "\"\""); - - return true; - } - - /* set "flag" to 1 if something needs to be escaped */ - for (input_pointer = input; *input_pointer; input_pointer++) - { - switch (*input_pointer) - { - case '\"': - case '\\': - case '\b': - case '\f': - case '\n': - case '\r': - case '\t': - /* one character escape sequence */ - escape_characters++; - break; - default: - if (*input_pointer < 32) - { - /* UTF-16 escape sequence uXXXX */ - escape_characters += 5; - } - break; - } - } - output_length = (size_t)(input_pointer - input) + escape_characters; - - output = ensure(output_buffer, output_length + sizeof("\"\"")); - if (output == NULL) - { - return false; - } - - /* no characters have to be escaped */ - if (escape_characters == 0) - { - output[0] = '\"'; - memcpy(output + 1, input, output_length); - output[output_length + 1] = '\"'; - output[output_length + 2] = '\0'; - - return true; - } - - output[0] = '\"'; - output_pointer = output + 1; - /* copy the string */ - for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) - { - if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) - { - /* normal character, copy */ - *output_pointer = *input_pointer; - } - else - { - /* character needs to be escaped */ - *output_pointer++ = '\\'; - switch (*input_pointer) - { - case '\\': - *output_pointer = '\\'; - break; - case '\"': - *output_pointer = '\"'; - break; - case '\b': - *output_pointer = 'b'; - break; - case '\f': - *output_pointer = 'f'; - break; - case '\n': - *output_pointer = 'n'; - break; - case '\r': - *output_pointer = 'r'; - break; - case '\t': - *output_pointer = 't'; - break; - default: - /* escape and print as unicode codepoint */ - sprintf((char*)output_pointer, "u%04x", *input_pointer); - output_pointer += 4; - break; - } - } - } - output[output_length + 1] = '\"'; - output[output_length + 2] = '\0'; - - return true; -} - -/* Invoke print_string_ptr (which is useful) on an item. */ -static cJSON_bool print_string(const cJSON * const item, printbuffer * const p) -{ - return print_string_ptr((unsigned char*)item->valuestring, p); -} - -/* Predeclare these prototypes. */ -static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer); -static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer); -static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer); -static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer); -static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer); -static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer); - -/* Utility to jump whitespace and cr/lf */ -static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) -{ - if ((buffer == NULL) || (buffer->content == NULL)) - { - return NULL; - } - - if (cannot_access_at_index(buffer, 0)) - { - return buffer; - } - - while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) - { - buffer->offset++; - } - - if (buffer->offset == buffer->length) - { - buffer->offset--; - } - - return buffer; -} - -/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */ -static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) -{ - if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) - { - return NULL; - } - - if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) - { - buffer->offset += 3; - } - - return buffer; -} - -CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) -{ - size_t buffer_length; - - if (NULL == value) - { - return NULL; - } - - /* Adding null character size due to require_null_terminated. */ - buffer_length = strlen(value) + sizeof(""); - - return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated); -} - -/* Parse an object - create a new root, and populate. */ -CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated) -{ - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; - cJSON *item = NULL; - - /* reset error position */ - global_error.json = NULL; - global_error.position = 0; - - if (value == NULL || 0 == buffer_length) - { - goto fail; - } - - buffer.content = (const unsigned char*)value; - buffer.length = buffer_length; - buffer.offset = 0; - buffer.hooks = global_hooks; - - item = cJSON_New_Item(&global_hooks); - if (item == NULL) /* memory fail */ - { - goto fail; - } - - if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))) - { - /* parse failure. ep is set. */ - goto fail; - } - - /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ - if (require_null_terminated) - { - buffer_skip_whitespace(&buffer); - if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') - { - goto fail; - } - } - if (return_parse_end) - { - *return_parse_end = (const char*)buffer_at_offset(&buffer); - } - - return item; - -fail: - if (item != NULL) - { - cJSON_Delete(item); - } - - if (value != NULL) - { - error local_error; - local_error.json = (const unsigned char*)value; - local_error.position = 0; - - if (buffer.offset < buffer.length) - { - local_error.position = buffer.offset; - } - else if (buffer.length > 0) - { - local_error.position = buffer.length - 1; - } - - if (return_parse_end != NULL) - { - *return_parse_end = (const char*)local_error.json + local_error.position; - } - - global_error = local_error; - } - - return NULL; -} - -/* Default options for cJSON_Parse */ -CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) -{ - return cJSON_ParseWithOpts(value, 0, 0); -} - -CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length) -{ - return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0); -} - -#define cjson_min(a, b) (((a) < (b)) ? (a) : (b)) - -static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks) -{ - static const size_t default_buffer_size = 256; - printbuffer buffer[1]; - unsigned char *printed = NULL; - - memset(buffer, 0, sizeof(buffer)); - - /* create buffer */ - buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size); - buffer->length = default_buffer_size; - buffer->format = format; - buffer->hooks = *hooks; - if (buffer->buffer == NULL) - { - goto fail; - } - - /* print the value */ - if (!print_value(item, buffer)) - { - goto fail; - } - update_offset(buffer); - - /* check if reallocate is available */ - if (hooks->reallocate != NULL) - { - printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1); - if (printed == NULL) { - goto fail; - } - buffer->buffer = NULL; - } - else /* otherwise copy the JSON over to a new buffer */ - { - printed = (unsigned char*) hooks->allocate(buffer->offset + 1); - if (printed == NULL) - { - goto fail; - } - memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1)); - printed[buffer->offset] = '\0'; /* just to be sure */ - - /* free the buffer */ - hooks->deallocate(buffer->buffer); - } - - return printed; - -fail: - if (buffer->buffer != NULL) - { - hooks->deallocate(buffer->buffer); - } - - if (printed != NULL) - { - hooks->deallocate(printed); - } - - return NULL; -} - -/* Render a cJSON item/entity/structure to text. */ -CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) -{ - return (char*)print(item, true, &global_hooks); -} - -CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) -{ - return (char*)print(item, false, &global_hooks); -} - -CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) -{ - printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; - - if (prebuffer < 0) - { - return NULL; - } - - p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer); - if (!p.buffer) - { - return NULL; - } - - p.length = (size_t)prebuffer; - p.offset = 0; - p.noalloc = false; - p.format = fmt; - p.hooks = global_hooks; - - if (!print_value(item, &p)) - { - global_hooks.deallocate(p.buffer); - return NULL; - } - - return (char*)p.buffer; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) -{ - printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; - - if ((length < 0) || (buffer == NULL)) - { - return false; - } - - p.buffer = (unsigned char*)buffer; - p.length = (size_t)length; - p.offset = 0; - p.noalloc = true; - p.format = format; - p.hooks = global_hooks; - - return print_value(item, &p); -} - -/* Parser core - when encountering text, process appropriately. */ -static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer) -{ - if ((input_buffer == NULL) || (input_buffer->content == NULL)) - { - return false; /* no input */ - } - - /* parse the different types of values */ - /* null */ - if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0)) - { - item->type = cJSON_NULL; - input_buffer->offset += 4; - return true; - } - /* false */ - if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0)) - { - item->type = cJSON_False; - input_buffer->offset += 5; - return true; - } - /* true */ - if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0)) - { - item->type = cJSON_True; - item->valueint = 1; - input_buffer->offset += 4; - return true; - } - /* string */ - if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) - { - return parse_string(item, input_buffer); - } - /* number */ - if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) - { - return parse_number(item, input_buffer); - } - /* array */ - if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) - { - return parse_array(item, input_buffer); - } - /* object */ - if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) - { - return parse_object(item, input_buffer); - } - - return false; -} - -/* Render a value to text. */ -static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer) -{ - unsigned char *output = NULL; - - if ((item == NULL) || (output_buffer == NULL)) - { - return false; - } - - switch ((item->type) & 0xFF) - { - case cJSON_NULL: - output = ensure(output_buffer, 5); - if (output == NULL) - { - return false; - } - strcpy((char*)output, "null"); - return true; - - case cJSON_False: - output = ensure(output_buffer, 6); - if (output == NULL) - { - return false; - } - strcpy((char*)output, "false"); - return true; - - case cJSON_True: - output = ensure(output_buffer, 5); - if (output == NULL) - { - return false; - } - strcpy((char*)output, "true"); - return true; - - case cJSON_Number: - return print_number(item, output_buffer); - - case cJSON_Raw: - { - size_t raw_length = 0; - if (item->valuestring == NULL) - { - return false; - } - - raw_length = strlen(item->valuestring) + sizeof(""); - output = ensure(output_buffer, raw_length); - if (output == NULL) - { - return false; - } - memcpy(output, item->valuestring, raw_length); - return true; - } - - case cJSON_String: - return print_string(item, output_buffer); - - case cJSON_Array: - return print_array(item, output_buffer); - - case cJSON_Object: - return print_object(item, output_buffer); - - default: - return false; - } -} - -/* Build an array from input text. */ -static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer) -{ - cJSON *head = NULL; /* head of the linked list */ - cJSON *current_item = NULL; - - if (input_buffer->depth >= CJSON_NESTING_LIMIT) - { - return false; /* to deeply nested */ - } - input_buffer->depth++; - - if (buffer_at_offset(input_buffer)[0] != '[') - { - /* not an array */ - goto fail; - } - - input_buffer->offset++; - buffer_skip_whitespace(input_buffer); - if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) - { - /* empty array */ - goto success; - } - - /* check if we skipped to the end of the buffer */ - if (cannot_access_at_index(input_buffer, 0)) - { - input_buffer->offset--; - goto fail; - } - - /* step back to character in front of the first element */ - input_buffer->offset--; - /* loop through the comma separated array elements */ - do - { - /* allocate next item */ - cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); - if (new_item == NULL) - { - goto fail; /* allocation failure */ - } - - /* attach next item to list */ - if (head == NULL) - { - /* start the linked list */ - current_item = head = new_item; - } - else - { - /* add to the end and advance */ - current_item->next = new_item; - new_item->prev = current_item; - current_item = new_item; - } - - /* parse next value */ - input_buffer->offset++; - buffer_skip_whitespace(input_buffer); - if (!parse_value(current_item, input_buffer)) - { - goto fail; /* failed to parse value */ - } - buffer_skip_whitespace(input_buffer); - } - while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); - - if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') - { - goto fail; /* expected end of array */ - } - -success: - input_buffer->depth--; - - if (head != NULL) { - head->prev = current_item; - } - - item->type = cJSON_Array; - item->child = head; - - input_buffer->offset++; - - return true; - -fail: - if (head != NULL) - { - cJSON_Delete(head); - } - - return false; -} - -/* Render an array to text */ -static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer) -{ - unsigned char *output_pointer = NULL; - size_t length = 0; - cJSON *current_element = item->child; - - if (output_buffer == NULL) - { - return false; - } - - /* Compose the output array. */ - /* opening square bracket */ - output_pointer = ensure(output_buffer, 1); - if (output_pointer == NULL) - { - return false; - } - - *output_pointer = '['; - output_buffer->offset++; - output_buffer->depth++; - - while (current_element != NULL) - { - if (!print_value(current_element, output_buffer)) - { - return false; - } - update_offset(output_buffer); - if (current_element->next) - { - length = (size_t) (output_buffer->format ? 2 : 1); - output_pointer = ensure(output_buffer, length + 1); - if (output_pointer == NULL) - { - return false; - } - *output_pointer++ = ','; - if(output_buffer->format) - { - *output_pointer++ = ' '; - } - *output_pointer = '\0'; - output_buffer->offset += length; - } - current_element = current_element->next; - } - - output_pointer = ensure(output_buffer, 2); - if (output_pointer == NULL) - { - return false; - } - *output_pointer++ = ']'; - *output_pointer = '\0'; - output_buffer->depth--; - - return true; -} - -/* Build an object from the text. */ -static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer) -{ - cJSON *head = NULL; /* linked list head */ - cJSON *current_item = NULL; - - if (input_buffer->depth >= CJSON_NESTING_LIMIT) - { - return false; /* to deeply nested */ - } - input_buffer->depth++; - - if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) - { - goto fail; /* not an object */ - } - - input_buffer->offset++; - buffer_skip_whitespace(input_buffer); - if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) - { - goto success; /* empty object */ - } - - /* check if we skipped to the end of the buffer */ - if (cannot_access_at_index(input_buffer, 0)) - { - input_buffer->offset--; - goto fail; - } - - /* step back to character in front of the first element */ - input_buffer->offset--; - /* loop through the comma separated array elements */ - do - { - /* allocate next item */ - cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); - if (new_item == NULL) - { - goto fail; /* allocation failure */ - } - - /* attach next item to list */ - if (head == NULL) - { - /* start the linked list */ - current_item = head = new_item; - } - else - { - /* add to the end and advance */ - current_item->next = new_item; - new_item->prev = current_item; - current_item = new_item; - } - - /* parse the name of the child */ - input_buffer->offset++; - buffer_skip_whitespace(input_buffer); - if (!parse_string(current_item, input_buffer)) - { - goto fail; /* failed to parse name */ - } - buffer_skip_whitespace(input_buffer); - - /* swap valuestring and string, because we parsed the name */ - current_item->string = current_item->valuestring; - current_item->valuestring = NULL; - - if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) - { - goto fail; /* invalid object */ - } - - /* parse the value */ - input_buffer->offset++; - buffer_skip_whitespace(input_buffer); - if (!parse_value(current_item, input_buffer)) - { - goto fail; /* failed to parse value */ - } - buffer_skip_whitespace(input_buffer); - } - while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); - - if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) - { - goto fail; /* expected end of object */ - } - -success: - input_buffer->depth--; - - if (head != NULL) { - head->prev = current_item; - } - - item->type = cJSON_Object; - item->child = head; - - input_buffer->offset++; - return true; - -fail: - if (head != NULL) - { - cJSON_Delete(head); - } - - return false; -} - -/* Render an object to text. */ -static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer) -{ - unsigned char *output_pointer = NULL; - size_t length = 0; - cJSON *current_item = item->child; - - if (output_buffer == NULL) - { - return false; - } - - /* Compose the output: */ - length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */ - output_pointer = ensure(output_buffer, length + 1); - if (output_pointer == NULL) - { - return false; - } - - *output_pointer++ = '{'; - output_buffer->depth++; - if (output_buffer->format) - { - *output_pointer++ = '\n'; - } - output_buffer->offset += length; - - while (current_item) - { - if (output_buffer->format) - { - size_t i; - output_pointer = ensure(output_buffer, output_buffer->depth); - if (output_pointer == NULL) - { - return false; - } - for (i = 0; i < output_buffer->depth; i++) - { - *output_pointer++ = '\t'; - } - output_buffer->offset += output_buffer->depth; - } - - /* print key */ - if (!print_string_ptr((unsigned char*)current_item->string, output_buffer)) - { - return false; - } - update_offset(output_buffer); - - length = (size_t) (output_buffer->format ? 2 : 1); - output_pointer = ensure(output_buffer, length); - if (output_pointer == NULL) - { - return false; - } - *output_pointer++ = ':'; - if (output_buffer->format) - { - *output_pointer++ = '\t'; - } - output_buffer->offset += length; - - /* print value */ - if (!print_value(current_item, output_buffer)) - { - return false; - } - update_offset(output_buffer); - - /* print comma if not last */ - length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0)); - output_pointer = ensure(output_buffer, length + 1); - if (output_pointer == NULL) - { - return false; - } - if (current_item->next) - { - *output_pointer++ = ','; - } - - if (output_buffer->format) - { - *output_pointer++ = '\n'; - } - *output_pointer = '\0'; - output_buffer->offset += length; - - current_item = current_item->next; - } - - output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2); - if (output_pointer == NULL) - { - return false; - } - if (output_buffer->format) - { - size_t i; - for (i = 0; i < (output_buffer->depth - 1); i++) - { - *output_pointer++ = '\t'; - } - } - *output_pointer++ = '}'; - *output_pointer = '\0'; - output_buffer->depth--; - - return true; -} - -/* Get Array size/item / object item. */ -CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) -{ - cJSON *child = NULL; - size_t size = 0; - - if (array == NULL) - { - return 0; - } - - child = array->child; - - while(child != NULL) - { - size++; - child = child->next; - } - - /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ - - return (int)size; -} - -static cJSON* get_array_item(const cJSON *array, size_t index) -{ - cJSON *current_child = NULL; - - if (array == NULL) - { - return NULL; - } - - current_child = array->child; - while ((current_child != NULL) && (index > 0)) - { - index--; - current_child = current_child->next; - } - - return current_child; -} - -CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index) -{ - if (index < 0) - { - return NULL; - } - - return get_array_item(array, (size_t)index); -} - -static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive) -{ - cJSON *current_element = NULL; - - if ((object == NULL) || (name == NULL)) - { - return NULL; - } - - current_element = object->child; - if (case_sensitive) - { - while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0)) - { - current_element = current_element->next; - } - } - else - { - while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0)) - { - current_element = current_element->next; - } - } - - if ((current_element == NULL) || (current_element->string == NULL)) { - return NULL; - } - - return current_element; -} - -CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string) -{ - return get_object_item(object, string, false); -} - -CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) -{ - return get_object_item(object, string, true); -} - -CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string) -{ - return cJSON_GetObjectItem(object, string) ? 1 : 0; -} - -/* Utility for array list handling. */ -static void suffix_object(cJSON *prev, cJSON *item) -{ - prev->next = item; - item->prev = prev; -} - -/* Utility for handling references. */ -static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks) -{ - cJSON *reference = NULL; - if (item == NULL) - { - return NULL; - } - - reference = cJSON_New_Item(hooks); - if (reference == NULL) - { - return NULL; - } - - memcpy(reference, item, sizeof(cJSON)); - reference->string = NULL; - reference->type |= cJSON_IsReference; - reference->next = reference->prev = NULL; - return reference; -} - -static cJSON_bool add_item_to_array(cJSON *array, cJSON *item) -{ - cJSON *child = NULL; - - if ((item == NULL) || (array == NULL) || (array == item)) - { - return false; - } - - child = array->child; - /* - * To find the last item in array quickly, we use prev in array - */ - if (child == NULL) - { - /* list is empty, start new one */ - array->child = item; - item->prev = item; - item->next = NULL; - } - else - { - /* append to the end */ - if (child->prev) - { - suffix_object(child->prev, item); - array->child->prev = item; - } - } - - return true; -} - -/* Add item to array/object. */ -CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item) -{ - return add_item_to_array(array, item); -} - -#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) - #pragma GCC diagnostic push -#endif -#ifdef __GNUC__ -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif -/* helper function to cast away const */ -static void* cast_away_const(const void* string) -{ - return (void*)string; -} -#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) - #pragma GCC diagnostic pop -#endif - - -static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key) -{ - char *new_key = NULL; - int new_type = cJSON_Invalid; - - if ((object == NULL) || (string == NULL) || (item == NULL) || (object == item)) - { - return false; - } - - if (constant_key) - { - new_key = (char*)cast_away_const(string); - new_type = item->type | cJSON_StringIsConst; - } - else - { - new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks); - if (new_key == NULL) - { - return false; - } - - new_type = item->type & ~cJSON_StringIsConst; - } - - if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) - { - hooks->deallocate(item->string); - } - - item->string = new_key; - item->type = new_type; - - return add_item_to_array(object, item); -} - -CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) -{ - return add_item_to_object(object, string, item, &global_hooks, false); -} - -/* Add an item to an object with constant string as key */ -CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) -{ - return add_item_to_object(object, string, item, &global_hooks, true); -} - -CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) -{ - if (array == NULL) - { - return false; - } - - return add_item_to_array(array, create_reference(item, &global_hooks)); -} - -CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) -{ - if ((object == NULL) || (string == NULL)) - { - return false; - } - - return add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false); -} - -CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name) -{ - cJSON *null = cJSON_CreateNull(); - if (add_item_to_object(object, name, null, &global_hooks, false)) - { - return null; - } - - cJSON_Delete(null); - return NULL; -} - -CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name) -{ - cJSON *true_item = cJSON_CreateTrue(); - if (add_item_to_object(object, name, true_item, &global_hooks, false)) - { - return true_item; - } - - cJSON_Delete(true_item); - return NULL; -} - -CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name) -{ - cJSON *false_item = cJSON_CreateFalse(); - if (add_item_to_object(object, name, false_item, &global_hooks, false)) - { - return false_item; - } - - cJSON_Delete(false_item); - return NULL; -} - -CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean) -{ - cJSON *bool_item = cJSON_CreateBool(boolean); - if (add_item_to_object(object, name, bool_item, &global_hooks, false)) - { - return bool_item; - } - - cJSON_Delete(bool_item); - return NULL; -} - -CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number) -{ - cJSON *number_item = cJSON_CreateNumber(number); - if (add_item_to_object(object, name, number_item, &global_hooks, false)) - { - return number_item; - } - - cJSON_Delete(number_item); - return NULL; -} - -CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string) -{ - cJSON *string_item = cJSON_CreateString(string); - if (add_item_to_object(object, name, string_item, &global_hooks, false)) - { - return string_item; - } - - cJSON_Delete(string_item); - return NULL; -} - -CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw) -{ - cJSON *raw_item = cJSON_CreateRaw(raw); - if (add_item_to_object(object, name, raw_item, &global_hooks, false)) - { - return raw_item; - } - - cJSON_Delete(raw_item); - return NULL; -} - -CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name) -{ - cJSON *object_item = cJSON_CreateObject(); - if (add_item_to_object(object, name, object_item, &global_hooks, false)) - { - return object_item; - } - - cJSON_Delete(object_item); - return NULL; -} - -CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name) -{ - cJSON *array = cJSON_CreateArray(); - if (add_item_to_object(object, name, array, &global_hooks, false)) - { - return array; - } - - cJSON_Delete(array); - return NULL; -} - -CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) -{ - if ((parent == NULL) || (item == NULL)) - { - return NULL; - } - - if (item != parent->child) - { - /* not the first element */ - item->prev->next = item->next; - } - if (item->next != NULL) - { - /* not the last element */ - item->next->prev = item->prev; - } - - if (item == parent->child) - { - /* first element */ - parent->child = item->next; - } - else if (item->next == NULL) - { - /* last element */ - parent->child->prev = item->prev; - } - - /* make sure the detached item doesn't point anywhere anymore */ - item->prev = NULL; - item->next = NULL; - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which) -{ - if (which < 0) - { - return NULL; - } - - return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which)); -} - -CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) -{ - cJSON_Delete(cJSON_DetachItemFromArray(array, which)); -} - -CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string) -{ - cJSON *to_detach = cJSON_GetObjectItem(object, string); - - return cJSON_DetachItemViaPointer(object, to_detach); -} - -CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string) -{ - cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string); - - return cJSON_DetachItemViaPointer(object, to_detach); -} - -CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) -{ - cJSON_Delete(cJSON_DetachItemFromObject(object, string)); -} - -CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string) -{ - cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string)); -} - -/* Replace array/object items with new ones. */ -CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) -{ - cJSON *after_inserted = NULL; - - if (which < 0) - { - return false; - } - - after_inserted = get_array_item(array, (size_t)which); - if (after_inserted == NULL) - { - return add_item_to_array(array, newitem); - } - - newitem->next = after_inserted; - newitem->prev = after_inserted->prev; - after_inserted->prev = newitem; - if (after_inserted == array->child) - { - array->child = newitem; - } - else - { - newitem->prev->next = newitem; - } - return true; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement) -{ - if ((parent == NULL) || (replacement == NULL) || (item == NULL)) - { - return false; - } - - if (replacement == item) - { - return true; - } - - replacement->next = item->next; - replacement->prev = item->prev; - - if (replacement->next != NULL) - { - replacement->next->prev = replacement; - } - if (parent->child == item) - { - if (parent->child->prev == parent->child) - { - replacement->prev = replacement; - } - parent->child = replacement; - } - else - { /* - * To find the last item in array quickly, we use prev in array. - * We can't modify the last item's next pointer where this item was the parent's child - */ - if (replacement->prev != NULL) - { - replacement->prev->next = replacement; - } - if (replacement->next == NULL) - { - parent->child->prev = replacement; - } - } - - item->next = NULL; - item->prev = NULL; - cJSON_Delete(item); - - return true; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) -{ - if (which < 0) - { - return false; - } - - return cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem); -} - -static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive) -{ - if ((replacement == NULL) || (string == NULL)) - { - return false; - } - - /* replace the name in the replacement */ - if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL)) - { - cJSON_free(replacement->string); - } - replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); - replacement->type &= ~cJSON_StringIsConst; - - return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); -} - -CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) -{ - return replace_item_in_object(object, string, newitem, false); -} - -CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) -{ - return replace_item_in_object(object, string, newitem, true); -} - -/* Create basic types: */ -CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = cJSON_NULL; - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = cJSON_True; - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = cJSON_False; - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = boolean ? cJSON_True : cJSON_False; - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = cJSON_Number; - item->valuedouble = num; - - /* use saturation in case of overflow */ - if (num >= INT_MAX) - { - item->valueint = INT_MAX; - } - else if (num <= (double)INT_MIN) - { - item->valueint = INT_MIN; - } - else - { - item->valueint = (int)num; - } - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = cJSON_String; - item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); - if(!item->valuestring) - { - cJSON_Delete(item); - return NULL; - } - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if (item != NULL) - { - item->type = cJSON_String | cJSON_IsReference; - item->valuestring = (char*)cast_away_const(string); - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if (item != NULL) { - item->type = cJSON_Object | cJSON_IsReference; - item->child = (cJSON*)cast_away_const(child); - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) { - cJSON *item = cJSON_New_Item(&global_hooks); - if (item != NULL) { - item->type = cJSON_Array | cJSON_IsReference; - item->child = (cJSON*)cast_away_const(child); - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = cJSON_Raw; - item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks); - if(!item->valuestring) - { - cJSON_Delete(item); - return NULL; - } - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type=cJSON_Array; - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if (item) - { - item->type = cJSON_Object; - } - - return item; -} - -/* Create Arrays: */ -CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) -{ - size_t i = 0; - cJSON *n = NULL; - cJSON *p = NULL; - cJSON *a = NULL; - - if ((count < 0) || (numbers == NULL)) - { - return NULL; - } - - a = cJSON_CreateArray(); - - for(i = 0; a && (i < (size_t)count); i++) - { - n = cJSON_CreateNumber(numbers[i]); - if (!n) - { - cJSON_Delete(a); - return NULL; - } - if(!i) - { - a->child = n; - } - else - { - suffix_object(p, n); - } - p = n; - } - - if (a && a->child) { - a->child->prev = n; - } - - return a; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) -{ - size_t i = 0; - cJSON *n = NULL; - cJSON *p = NULL; - cJSON *a = NULL; - - if ((count < 0) || (numbers == NULL)) - { - return NULL; - } - - a = cJSON_CreateArray(); - - for(i = 0; a && (i < (size_t)count); i++) - { - n = cJSON_CreateNumber((double)numbers[i]); - if(!n) - { - cJSON_Delete(a); - return NULL; - } - if(!i) - { - a->child = n; - } - else - { - suffix_object(p, n); - } - p = n; - } - - if (a && a->child) { - a->child->prev = n; - } - - return a; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) -{ - size_t i = 0; - cJSON *n = NULL; - cJSON *p = NULL; - cJSON *a = NULL; - - if ((count < 0) || (numbers == NULL)) - { - return NULL; - } - - a = cJSON_CreateArray(); - - for(i = 0; a && (i < (size_t)count); i++) - { - n = cJSON_CreateNumber(numbers[i]); - if(!n) - { - cJSON_Delete(a); - return NULL; - } - if(!i) - { - a->child = n; - } - else - { - suffix_object(p, n); - } - p = n; - } - - if (a && a->child) { - a->child->prev = n; - } - - return a; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count) -{ - size_t i = 0; - cJSON *n = NULL; - cJSON *p = NULL; - cJSON *a = NULL; - - if ((count < 0) || (strings == NULL)) - { - return NULL; - } - - a = cJSON_CreateArray(); - - for (i = 0; a && (i < (size_t)count); i++) - { - n = cJSON_CreateString(strings[i]); - if(!n) - { - cJSON_Delete(a); - return NULL; - } - if(!i) - { - a->child = n; - } - else - { - suffix_object(p,n); - } - p = n; - } - - if (a && a->child) { - a->child->prev = n; - } - - return a; -} - -/* Duplication */ -CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) -{ - cJSON *newitem = NULL; - cJSON *child = NULL; - cJSON *next = NULL; - cJSON *newchild = NULL; - - /* Bail on bad ptr */ - if (!item) - { - goto fail; - } - /* Create new item */ - newitem = cJSON_New_Item(&global_hooks); - if (!newitem) - { - goto fail; - } - /* Copy over all vars */ - newitem->type = item->type & (~cJSON_IsReference); - newitem->valueint = item->valueint; - newitem->valuedouble = item->valuedouble; - if (item->valuestring) - { - newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks); - if (!newitem->valuestring) - { - goto fail; - } - } - if (item->string) - { - newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks); - if (!newitem->string) - { - goto fail; - } - } - /* If non-recursive, then we're done! */ - if (!recurse) - { - return newitem; - } - /* Walk the ->next chain for the child. */ - child = item->child; - while (child != NULL) - { - newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ - if (!newchild) - { - goto fail; - } - if (next != NULL) - { - /* If newitem->child already set, then crosswire ->prev and ->next and move on */ - next->next = newchild; - newchild->prev = next; - next = newchild; - } - else - { - /* Set newitem->child and move to it */ - newitem->child = newchild; - next = newchild; - } - child = child->next; - } - if (newitem && newitem->child) - { - newitem->child->prev = newchild; - } - - return newitem; - -fail: - if (newitem != NULL) - { - cJSON_Delete(newitem); - } - - return NULL; -} - -static void skip_oneline_comment(char **input) -{ - *input += static_strlen("//"); - - for (; (*input)[0] != '\0'; ++(*input)) - { - if ((*input)[0] == '\n') { - *input += static_strlen("\n"); - return; - } - } -} - -static void skip_multiline_comment(char **input) -{ - *input += static_strlen("/*"); - - for (; (*input)[0] != '\0'; ++(*input)) - { - if (((*input)[0] == '*') && ((*input)[1] == '/')) - { - *input += static_strlen("*/"); - return; - } - } -} - -static void minify_string(char **input, char **output) { - (*output)[0] = (*input)[0]; - *input += static_strlen("\""); - *output += static_strlen("\""); - - - for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) { - (*output)[0] = (*input)[0]; - - if ((*input)[0] == '\"') { - (*output)[0] = '\"'; - *input += static_strlen("\""); - *output += static_strlen("\""); - return; - } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) { - (*output)[1] = (*input)[1]; - *input += static_strlen("\""); - *output += static_strlen("\""); - } - } -} - -CJSON_PUBLIC(void) cJSON_Minify(char *json) -{ - char *into = json; - - if (json == NULL) - { - return; - } - - while (json[0] != '\0') - { - switch (json[0]) - { - case ' ': - case '\t': - case '\r': - case '\n': - json++; - break; - - case '/': - if (json[1] == '/') - { - skip_oneline_comment(&json); - } - else if (json[1] == '*') - { - skip_multiline_comment(&json); - } else { - json++; - } - break; - - case '\"': - minify_string(&json, (char**)&into); - break; - - default: - into[0] = json[0]; - json++; - into++; - } - } - - /* and null-terminate. */ - *into = '\0'; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xFF) == cJSON_Invalid; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xFF) == cJSON_False; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xff) == cJSON_True; -} - - -CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & (cJSON_True | cJSON_False)) != 0; -} -CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xFF) == cJSON_NULL; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xFF) == cJSON_Number; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xFF) == cJSON_String; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xFF) == cJSON_Array; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xFF) == cJSON_Object; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xFF) == cJSON_Raw; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive) -{ - if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) - { - return false; - } - - /* check if type is valid */ - switch (a->type & 0xFF) - { - case cJSON_False: - case cJSON_True: - case cJSON_NULL: - case cJSON_Number: - case cJSON_String: - case cJSON_Raw: - case cJSON_Array: - case cJSON_Object: - break; - - default: - return false; - } - - /* identical objects are equal */ - if (a == b) - { - return true; - } - - switch (a->type & 0xFF) - { - /* in these cases and equal type is enough */ - case cJSON_False: - case cJSON_True: - case cJSON_NULL: - return true; - - case cJSON_Number: - if (compare_double(a->valuedouble, b->valuedouble)) - { - return true; - } - return false; - - case cJSON_String: - case cJSON_Raw: - if ((a->valuestring == NULL) || (b->valuestring == NULL)) - { - return false; - } - if (strcmp(a->valuestring, b->valuestring) == 0) - { - return true; - } - - return false; - - case cJSON_Array: - { - cJSON *a_element = a->child; - cJSON *b_element = b->child; - - for (; (a_element != NULL) && (b_element != NULL);) - { - if (!cJSON_Compare(a_element, b_element, case_sensitive)) - { - return false; - } - - a_element = a_element->next; - b_element = b_element->next; - } - - /* one of the arrays is longer than the other */ - if (a_element != b_element) { - return false; - } - - return true; - } - - case cJSON_Object: - { - cJSON *a_element = NULL; - cJSON *b_element = NULL; - cJSON_ArrayForEach(a_element, a) - { - /* TODO This has O(n^2) runtime, which is horrible! */ - b_element = get_object_item(b, a_element->string, case_sensitive); - if (b_element == NULL) - { - return false; - } - - if (!cJSON_Compare(a_element, b_element, case_sensitive)) - { - return false; - } - } - - /* doing this twice, once on a and b to prevent true comparison if a subset of b - * TODO: Do this the proper way, this is just a fix for now */ - cJSON_ArrayForEach(b_element, b) - { - a_element = get_object_item(a, b_element->string, case_sensitive); - if (a_element == NULL) - { - return false; - } - - if (!cJSON_Compare(b_element, a_element, case_sensitive)) - { - return false; - } - } - - return true; - } - - default: - return false; - } -} - -CJSON_PUBLIC(void *) cJSON_malloc(size_t size) -{ - return global_hooks.allocate(size); -} - -CJSON_PUBLIC(void) cJSON_free(void *object) -{ - global_hooks.deallocate(object); -} diff --git a/APP_Framework/Applications/knowing_app/helmet_detect/cJSON.h b/APP_Framework/Applications/knowing_app/helmet_detect/cJSON.h deleted file mode 100644 index e97e5f4c..00000000 --- a/APP_Framework/Applications/knowing_app/helmet_detect/cJSON.h +++ /dev/null @@ -1,293 +0,0 @@ -/* - Copyright (c) 2009-2017 Dave Gamble and cJSON contributors - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*/ - -#ifndef cJSON__h -#define cJSON__h - -#ifdef __cplusplus -extern "C" -{ -#endif - -#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) -#define __WINDOWS__ -#endif - -#ifdef __WINDOWS__ - -/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options: - -CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols -CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) -CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol - -For *nix builds that support visibility attribute, you can define similar behavior by - -setting default visibility to hidden by adding --fvisibility=hidden (for gcc) -or --xldscope=hidden (for sun cc) -to CFLAGS - -then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does - -*/ - -#define CJSON_CDECL __cdecl -#define CJSON_STDCALL __stdcall - -/* export symbols by default, this is necessary for copy pasting the C and header file */ -#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) -#define CJSON_EXPORT_SYMBOLS -#endif - -#if defined(CJSON_HIDE_SYMBOLS) -#define CJSON_PUBLIC(type) type CJSON_STDCALL -#elif defined(CJSON_EXPORT_SYMBOLS) -#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL -#elif defined(CJSON_IMPORT_SYMBOLS) -#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL -#endif -#else /* !__WINDOWS__ */ -#define CJSON_CDECL -#define CJSON_STDCALL - -#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) -#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type -#else -#define CJSON_PUBLIC(type) type -#endif -#endif - -/* project version */ -#define CJSON_VERSION_MAJOR 1 -#define CJSON_VERSION_MINOR 7 -#define CJSON_VERSION_PATCH 14 - -#include - -/* cJSON Types: */ -#define cJSON_Invalid (0) -#define cJSON_False (1 << 0) -#define cJSON_True (1 << 1) -#define cJSON_NULL (1 << 2) -#define cJSON_Number (1 << 3) -#define cJSON_String (1 << 4) -#define cJSON_Array (1 << 5) -#define cJSON_Object (1 << 6) -#define cJSON_Raw (1 << 7) /* raw json */ - -#define cJSON_IsReference 256 -#define cJSON_StringIsConst 512 - -/* The cJSON structure: */ -typedef struct cJSON -{ - /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ - struct cJSON *next; - struct cJSON *prev; - /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ - struct cJSON *child; - - /* The type of the item, as above. */ - int type; - - /* The item's string, if type==cJSON_String and type == cJSON_Raw */ - char *valuestring; - /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ - int valueint; - /* The item's number, if type==cJSON_Number */ - double valuedouble; - - /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ - char *string; -} cJSON; - -typedef struct cJSON_Hooks -{ - /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */ - void *(CJSON_CDECL *malloc_fn)(size_t sz); - void (CJSON_CDECL *free_fn)(void *ptr); -} cJSON_Hooks; - -typedef int cJSON_bool; - -/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them. - * This is to prevent stack overflows. */ -#ifndef CJSON_NESTING_LIMIT -#define CJSON_NESTING_LIMIT 1000 -#endif - -/* returns the version of cJSON as a string */ -CJSON_PUBLIC(const char*) cJSON_Version(void); - -/* Supply malloc, realloc and free functions to cJSON */ -CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); - -/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ -/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ -CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); -CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length); -/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ -/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */ -CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); -CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated); - -/* Render a cJSON entity to text for transfer/storage. */ -CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); -/* Render a cJSON entity to text for transfer/storage without any formatting. */ -CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); -/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ -CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); -/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ -/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ -CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); -/* Delete a cJSON entity and all subentities. */ -CJSON_PUBLIC(void) cJSON_Delete(cJSON *item); - -/* Returns the number of items in an array (or object). */ -CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); -/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */ -CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); -/* Get item "string" from object. Case insensitive. */ -CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); -CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); -CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string); -/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ -CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); - -/* Check item type and return its value */ -CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item); -CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item); - -/* These functions check the type of an item */ -CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item); - -/* These calls create a cJSON item of the appropriate type. */ -CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); -CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); -CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); -CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); -CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); -CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); -/* raw json */ -CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); -CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); -CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); - -/* Create a string where valuestring references a string so - * it will not be freed by cJSON_Delete */ -CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); -/* Create an object/array that only references it's elements so - * they will not be freed by cJSON_Delete */ -CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); -CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); - -/* These utilities create an Array of count items. - * The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/ -CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); -CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); -CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); -CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count); - -/* Append item to the specified array/object. */ -CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item); -CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); -/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. - * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before - * writing to `item->string` */ -CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); -/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ -CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); -CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); - -/* Remove/Detach items from Arrays/Objects. */ -CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); -CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); -CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); -CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); -CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); -CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); -CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); - -/* Update array items. */ -CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ -CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); -CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); -CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); -CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem); - -/* Duplicate a cJSON item */ -CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); -/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will - * need to be released. With recurse!=0, it will duplicate any children connected to the item. - * The item->next and ->prev pointers are always zero on return from Duplicate. */ -/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal. - * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ -CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); - -/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings. - * The input pointer json cannot point to a read-only address area, such as a string constant, - * but should point to a readable and writable adress area. */ -CJSON_PUBLIC(void) cJSON_Minify(char *json); - -/* Helper functions for creating and adding items to an object at the same time. - * They return the added item or NULL on failure. */ -CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name); -CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name); -CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name); -CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean); -CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number); -CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string); -CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw); -CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name); -CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name); - -/* When assigning an integer value, it needs to be propagated to valuedouble too. */ -#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) -/* helper for the cJSON_SetNumberValue macro */ -CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); -#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) -/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */ -CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring); - -/* Macro for iterating over an array or object */ -#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) - -/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ -CJSON_PUBLIC(void *) cJSON_malloc(size_t size); -CJSON_PUBLIC(void) cJSON_free(void *object); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/APP_Framework/Applications/knowing_app/helmet_detect/helmet_detect.c b/APP_Framework/Applications/knowing_app/helmet_detect/helmet_detect.c index 68956f5b..3ea8e2dd 100644 --- a/APP_Framework/Applications/knowing_app/helmet_detect/helmet_detect.c +++ b/APP_Framework/Applications/knowing_app/helmet_detect/helmet_detect.c @@ -1,6 +1,7 @@ #include - -#include "cJSON.h" +#ifdef LIB_USING_CJSON +#include +#endif #include "region_layer.h" #define ANCHOR_NUM 5 #define STACK_SIZE (128 * 1024) @@ -8,16 +9,16 @@ #define JSON_BUFFER_SIZE (4 * 1024) // params from json -float anchor[ANCHOR_NUM * 2] = {}; -int net_output_shape[3] = {}; -int net_input_size[2] = {}; -int sensor_output_size[2] = {}; -char kmodel_path[127] = ""; -int kmodel_size = 0; -float obj_thresh[20] = {}; -float nms_thresh = 0.0; -char labels[20][32] = {}; -int class_num = 0; +static float anchor[ANCHOR_NUM * 2] = {}; +static int net_output_shape[3] = {}; +static int net_input_size[2] = {}; +static int sensor_output_size[2] = {}; +static char kmodel_path[127] = ""; +static int kmodel_size = 0; +static float obj_thresh[20] = {}; +static float nms_thresh = 0.0; +static char labels[20][32] = {}; +static int class_num = 0; #define THREAD_PRIORITY_HELMET_D (11) static pthread_t helmettid = 0; @@ -140,12 +141,12 @@ static void param_parse() printf("No labels!"); exit(-1); } else { - printf("Got %d labels\n"); + printf("Got %d labels\n", class_num); } for (int i = 0; i < class_num; i++) { json_array_item = cJSON_GetArrayItem(json_item, i); - memcpy(labels[i], json_item->valuestring, strlen(json_item->valuestring)); - printf("%d: %f\n", i, labels[i]); + memcpy(labels[i], json_array_item->valuestring, strlen(json_array_item->valuestring)); + printf("%d: %s\n", i, labels[i]); } // obj_thresh json_item = cJSON_GetObjectItem(json_obj, "obj_thresh"); @@ -154,7 +155,7 @@ static void param_parse() printf("label number and thresh number mismatch! label number : %d, obj thresh number %d", class_num, array_size); exit(-1); } else { - printf("Got %d obj_thresh\n"); + printf("Got %d obj_thresh\n", array_size); } for (int i = 0; i < array_size; i++) { json_array_item = cJSON_GetArrayItem(json_item, i); @@ -317,8 +318,6 @@ static void *thread_helmet_detect_entry(void *parameter) } if (0 != helmet_detect_info.obj_number) { printf("\n"); - } else { - printf("No helmet or head found!\n"); } lcd_draw_picture(0, 0, (uint16_t)sensor_output_size[1], (uint16_t)sensor_output_size[0], (unsigned int *)showbuffer); #endif diff --git a/APP_Framework/Applications/knowing_app/instrusion_detect/Kconfig b/APP_Framework/Applications/knowing_app/instrusion_detect/Kconfig index c8fb4637..ee90a244 100644 --- a/APP_Framework/Applications/knowing_app/instrusion_detect/Kconfig +++ b/APP_Framework/Applications/knowing_app/instrusion_detect/Kconfig @@ -4,4 +4,5 @@ config INSTRUSION_DETECT depends on DRV_USING_OV2640 depends on USING_KPU_POSTPROCESSING depends on USING_YOLOV2 + select LIB_USING_CJSON default n diff --git a/APP_Framework/Applications/knowing_app/instrusion_detect/cJSON.c b/APP_Framework/Applications/knowing_app/instrusion_detect/cJSON.c deleted file mode 100644 index 030311ce..00000000 --- a/APP_Framework/Applications/knowing_app/instrusion_detect/cJSON.c +++ /dev/null @@ -1,3110 +0,0 @@ -/* - Copyright (c) 2009-2017 Dave Gamble and cJSON contributors - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*/ - -/* cJSON */ -/* JSON parser in C. */ - -/* disable warnings about old C89 functions in MSVC */ -#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) -#define _CRT_SECURE_NO_DEPRECATE -#endif - -#ifdef __GNUC__ -#pragma GCC visibility push(default) -#endif -#if defined(_MSC_VER) -#pragma warning (push) -/* disable warning about single line comments in system headers */ -#pragma warning (disable : 4001) -#endif - -#include -#include -#include -#include -#include -#include -#include - -#ifdef ENABLE_LOCALES -#include -#endif - -#if defined(_MSC_VER) -#pragma warning (pop) -#endif -#ifdef __GNUC__ -#pragma GCC visibility pop -#endif - -#include "cJSON.h" - -/* define our own boolean type */ -#ifdef true -#undef true -#endif -#define true ((cJSON_bool)1) - -#ifdef false -#undef false -#endif -#define false ((cJSON_bool)0) - -/* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */ -#ifndef isinf -#define isinf(d) (isnan((d - d)) && !isnan(d)) -#endif -#ifndef isnan -#define isnan(d) (d != d) -#endif - -#ifndef NAN -#ifdef _WIN32 -#define NAN sqrt(-1.0) -#else -#define NAN 0.0/0.0 -#endif -#endif - -typedef struct { - const unsigned char *json; - size_t position; -} error; -static error global_error = { NULL, 0 }; - -CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) -{ - return (const char*) (global_error.json + global_error.position); -} - -CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item) -{ - if (!cJSON_IsString(item)) - { - return NULL; - } - - return item->valuestring; -} - -CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item) -{ - if (!cJSON_IsNumber(item)) - { - return (double) NAN; - } - - return item->valuedouble; -} - -/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 14) - #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. -#endif - -CJSON_PUBLIC(const char*) cJSON_Version(void) -{ - static char version[15]; - sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); - - return version; -} - -/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */ -static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) -{ - if ((string1 == NULL) || (string2 == NULL)) - { - return 1; - } - - if (string1 == string2) - { - return 0; - } - - for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++) - { - if (*string1 == '\0') - { - return 0; - } - } - - return tolower(*string1) - tolower(*string2); -} - -typedef struct internal_hooks -{ - void *(CJSON_CDECL *allocate)(size_t size); - void (CJSON_CDECL *deallocate)(void *pointer); - void *(CJSON_CDECL *reallocate)(void *pointer, size_t size); -} internal_hooks; - -#if defined(_MSC_VER) -/* work around MSVC error C2322: '...' address of dllimport '...' is not static */ -static void * CJSON_CDECL internal_malloc(size_t size) -{ - return malloc(size); -} -static void CJSON_CDECL internal_free(void *pointer) -{ - free(pointer); -} -static void * CJSON_CDECL internal_realloc(void *pointer, size_t size) -{ - return realloc(pointer, size); -} -#else -#define internal_malloc malloc -#define internal_free free -#define internal_realloc realloc -#endif - -/* strlen of character literals resolved at compile time */ -#define static_strlen(string_literal) (sizeof(string_literal) - sizeof("")) - -static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc }; - -static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks) -{ - size_t length = 0; - unsigned char *copy = NULL; - - if (string == NULL) - { - return NULL; - } - - length = strlen((const char*)string) + sizeof(""); - copy = (unsigned char*)hooks->allocate(length); - if (copy == NULL) - { - return NULL; - } - memcpy(copy, string, length); - - return copy; -} - -CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) -{ - if (hooks == NULL) - { - /* Reset hooks */ - global_hooks.allocate = malloc; - global_hooks.deallocate = free; - global_hooks.reallocate = realloc; - return; - } - - global_hooks.allocate = malloc; - if (hooks->malloc_fn != NULL) - { - global_hooks.allocate = hooks->malloc_fn; - } - - global_hooks.deallocate = free; - if (hooks->free_fn != NULL) - { - global_hooks.deallocate = hooks->free_fn; - } - - /* use realloc only if both free and malloc are used */ - global_hooks.reallocate = NULL; - if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free)) - { - global_hooks.reallocate = realloc; - } -} - -/* Internal constructor. */ -static cJSON *cJSON_New_Item(const internal_hooks * const hooks) -{ - cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON)); - if (node) - { - memset(node, '\0', sizeof(cJSON)); - } - - return node; -} - -/* Delete a cJSON structure. */ -CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) -{ - cJSON *next = NULL; - while (item != NULL) - { - next = item->next; - if (!(item->type & cJSON_IsReference) && (item->child != NULL)) - { - cJSON_Delete(item->child); - } - if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) - { - global_hooks.deallocate(item->valuestring); - } - if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) - { - global_hooks.deallocate(item->string); - } - global_hooks.deallocate(item); - item = next; - } -} - -/* get the decimal point character of the current locale */ -static unsigned char get_decimal_point(void) -{ -#ifdef ENABLE_LOCALES - struct lconv *lconv = localeconv(); - return (unsigned char) lconv->decimal_point[0]; -#else - return '.'; -#endif -} - -typedef struct -{ - const unsigned char *content; - size_t length; - size_t offset; - size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */ - internal_hooks hooks; -} parse_buffer; - -/* check if the given size is left to read in a given parse buffer (starting with 1) */ -#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length)) -/* check if the buffer can be accessed at the given index (starting with 0) */ -#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length)) -#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index)) -/* get a pointer to the buffer at the position */ -#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset) - -/* Parse the input text to generate a number, and populate the result into item. */ -static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer) -{ - double number = 0; - unsigned char *after_end = NULL; - unsigned char number_c_string[64]; - unsigned char decimal_point = get_decimal_point(); - size_t i = 0; - - if ((input_buffer == NULL) || (input_buffer->content == NULL)) - { - return false; - } - - /* copy the number into a temporary buffer and replace '.' with the decimal point - * of the current locale (for strtod) - * This also takes care of '\0' not necessarily being available for marking the end of the input */ - for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) - { - switch (buffer_at_offset(input_buffer)[i]) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '+': - case '-': - case 'e': - case 'E': - number_c_string[i] = buffer_at_offset(input_buffer)[i]; - break; - - case '.': - number_c_string[i] = decimal_point; - break; - - default: - goto loop_end; - } - } -loop_end: - number_c_string[i] = '\0'; - - number = strtod((const char*)number_c_string, (char**)&after_end); - if (number_c_string == after_end) - { - return false; /* parse_error */ - } - - item->valuedouble = number; - - /* use saturation in case of overflow */ - if (number >= INT_MAX) - { - item->valueint = INT_MAX; - } - else if (number <= (double)INT_MIN) - { - item->valueint = INT_MIN; - } - else - { - item->valueint = (int)number; - } - - item->type = cJSON_Number; - - input_buffer->offset += (size_t)(after_end - number_c_string); - return true; -} - -/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ -CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) -{ - if (number >= INT_MAX) - { - object->valueint = INT_MAX; - } - else if (number <= (double)INT_MIN) - { - object->valueint = INT_MIN; - } - else - { - object->valueint = (int)number; - } - - return object->valuedouble = number; -} - -CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring) -{ - char *copy = NULL; - /* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */ - if (!(object->type & cJSON_String) || (object->type & cJSON_IsReference)) - { - return NULL; - } - if (strlen(valuestring) <= strlen(object->valuestring)) - { - strcpy(object->valuestring, valuestring); - return object->valuestring; - } - copy = (char*) cJSON_strdup((const unsigned char*)valuestring, &global_hooks); - if (copy == NULL) - { - return NULL; - } - if (object->valuestring != NULL) - { - cJSON_free(object->valuestring); - } - object->valuestring = copy; - - return copy; -} - -typedef struct -{ - unsigned char *buffer; - size_t length; - size_t offset; - size_t depth; /* current nesting depth (for formatted printing) */ - cJSON_bool noalloc; - cJSON_bool format; /* is this print a formatted print */ - internal_hooks hooks; -} printbuffer; - -/* realloc printbuffer if necessary to have at least "needed" bytes more */ -static unsigned char* ensure(printbuffer * const p, size_t needed) -{ - unsigned char *newbuffer = NULL; - size_t newsize = 0; - - if ((p == NULL) || (p->buffer == NULL)) - { - return NULL; - } - - if ((p->length > 0) && (p->offset >= p->length)) - { - /* make sure that offset is valid */ - return NULL; - } - - if (needed > INT_MAX) - { - /* sizes bigger than INT_MAX are currently not supported */ - return NULL; - } - - needed += p->offset + 1; - if (needed <= p->length) - { - return p->buffer + p->offset; - } - - if (p->noalloc) { - return NULL; - } - - /* calculate new buffer size */ - if (needed > (INT_MAX / 2)) - { - /* overflow of int, use INT_MAX if possible */ - if (needed <= INT_MAX) - { - newsize = INT_MAX; - } - else - { - return NULL; - } - } - else - { - newsize = needed * 2; - } - - if (p->hooks.reallocate != NULL) - { - /* reallocate with realloc if available */ - newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize); - if (newbuffer == NULL) - { - p->hooks.deallocate(p->buffer); - p->length = 0; - p->buffer = NULL; - - return NULL; - } - } - else - { - /* otherwise reallocate manually */ - newbuffer = (unsigned char*)p->hooks.allocate(newsize); - if (!newbuffer) - { - p->hooks.deallocate(p->buffer); - p->length = 0; - p->buffer = NULL; - - return NULL; - } - - memcpy(newbuffer, p->buffer, p->offset + 1); - p->hooks.deallocate(p->buffer); - } - p->length = newsize; - p->buffer = newbuffer; - - return newbuffer + p->offset; -} - -/* calculate the new length of the string in a printbuffer and update the offset */ -static void update_offset(printbuffer * const buffer) -{ - const unsigned char *buffer_pointer = NULL; - if ((buffer == NULL) || (buffer->buffer == NULL)) - { - return; - } - buffer_pointer = buffer->buffer + buffer->offset; - - buffer->offset += strlen((const char*)buffer_pointer); -} - -/* securely comparison of floating-point variables */ -static cJSON_bool compare_double(double a, double b) -{ - double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b); - return (fabs(a - b) <= maxVal * DBL_EPSILON); -} - -/* Render the number nicely from the given item into a string. */ -static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer) -{ - unsigned char *output_pointer = NULL; - double d = item->valuedouble; - int length = 0; - size_t i = 0; - unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */ - unsigned char decimal_point = get_decimal_point(); - double test = 0.0; - - if (output_buffer == NULL) - { - return false; - } - - /* This checks for NaN and Infinity */ - if (isnan(d) || isinf(d)) - { - length = sprintf((char*)number_buffer, "null"); - } - else - { - /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ - length = sprintf((char*)number_buffer, "%1.15g", d); - - /* Check whether the original double can be recovered */ - if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d)) - { - /* If not, print with 17 decimal places of precision */ - length = sprintf((char*)number_buffer, "%1.17g", d); - } - } - - /* sprintf failed or buffer overrun occurred */ - if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) - { - return false; - } - - /* reserve appropriate space in the output */ - output_pointer = ensure(output_buffer, (size_t)length + sizeof("")); - if (output_pointer == NULL) - { - return false; - } - - /* copy the printed number to the output and replace locale - * dependent decimal point with '.' */ - for (i = 0; i < ((size_t)length); i++) - { - if (number_buffer[i] == decimal_point) - { - output_pointer[i] = '.'; - continue; - } - - output_pointer[i] = number_buffer[i]; - } - output_pointer[i] = '\0'; - - output_buffer->offset += (size_t)length; - - return true; -} - -/* parse 4 digit hexadecimal number */ -static unsigned parse_hex4(const unsigned char * const input) -{ - unsigned int h = 0; - size_t i = 0; - - for (i = 0; i < 4; i++) - { - /* parse digit */ - if ((input[i] >= '0') && (input[i] <= '9')) - { - h += (unsigned int) input[i] - '0'; - } - else if ((input[i] >= 'A') && (input[i] <= 'F')) - { - h += (unsigned int) 10 + input[i] - 'A'; - } - else if ((input[i] >= 'a') && (input[i] <= 'f')) - { - h += (unsigned int) 10 + input[i] - 'a'; - } - else /* invalid */ - { - return 0; - } - - if (i < 3) - { - /* shift left to make place for the next nibble */ - h = h << 4; - } - } - - return h; -} - -/* converts a UTF-16 literal to UTF-8 - * A literal can be one or two sequences of the form \uXXXX */ -static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer) -{ - long unsigned int codepoint = 0; - unsigned int first_code = 0; - const unsigned char *first_sequence = input_pointer; - unsigned char utf8_length = 0; - unsigned char utf8_position = 0; - unsigned char sequence_length = 0; - unsigned char first_byte_mark = 0; - - if ((input_end - first_sequence) < 6) - { - /* input ends unexpectedly */ - goto fail; - } - - /* get the first utf16 sequence */ - first_code = parse_hex4(first_sequence + 2); - - /* check that the code is valid */ - if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) - { - goto fail; - } - - /* UTF16 surrogate pair */ - if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) - { - const unsigned char *second_sequence = first_sequence + 6; - unsigned int second_code = 0; - sequence_length = 12; /* \uXXXX\uXXXX */ - - if ((input_end - second_sequence) < 6) - { - /* input ends unexpectedly */ - goto fail; - } - - if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) - { - /* missing second half of the surrogate pair */ - goto fail; - } - - /* get the second utf16 sequence */ - second_code = parse_hex4(second_sequence + 2); - /* check that the code is valid */ - if ((second_code < 0xDC00) || (second_code > 0xDFFF)) - { - /* invalid second half of the surrogate pair */ - goto fail; - } - - - /* calculate the unicode codepoint from the surrogate pair */ - codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF)); - } - else - { - sequence_length = 6; /* \uXXXX */ - codepoint = first_code; - } - - /* encode as UTF-8 - * takes at maximum 4 bytes to encode: - * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ - if (codepoint < 0x80) - { - /* normal ascii, encoding 0xxxxxxx */ - utf8_length = 1; - } - else if (codepoint < 0x800) - { - /* two bytes, encoding 110xxxxx 10xxxxxx */ - utf8_length = 2; - first_byte_mark = 0xC0; /* 11000000 */ - } - else if (codepoint < 0x10000) - { - /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ - utf8_length = 3; - first_byte_mark = 0xE0; /* 11100000 */ - } - else if (codepoint <= 0x10FFFF) - { - /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ - utf8_length = 4; - first_byte_mark = 0xF0; /* 11110000 */ - } - else - { - /* invalid unicode codepoint */ - goto fail; - } - - /* encode as utf8 */ - for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) - { - /* 10xxxxxx */ - (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF); - codepoint >>= 6; - } - /* encode first byte */ - if (utf8_length > 1) - { - (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF); - } - else - { - (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F); - } - - *output_pointer += utf8_length; - - return sequence_length; - -fail: - return 0; -} - -/* Parse the input text into an unescaped cinput, and populate item. */ -static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer) -{ - const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; - const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; - unsigned char *output_pointer = NULL; - unsigned char *output = NULL; - - /* not a string */ - if (buffer_at_offset(input_buffer)[0] != '\"') - { - goto fail; - } - - { - /* calculate approximate size of the output (overestimate) */ - size_t allocation_length = 0; - size_t skipped_bytes = 0; - while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) - { - /* is escape sequence */ - if (input_end[0] == '\\') - { - if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) - { - /* prevent buffer overflow when last input character is a backslash */ - goto fail; - } - skipped_bytes++; - input_end++; - } - input_end++; - } - if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) - { - goto fail; /* string ended unexpectedly */ - } - - /* This is at most how much we need for the output */ - allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes; - output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof("")); - if (output == NULL) - { - goto fail; /* allocation failure */ - } - } - - output_pointer = output; - /* loop through the string literal */ - while (input_pointer < input_end) - { - if (*input_pointer != '\\') - { - *output_pointer++ = *input_pointer++; - } - /* escape sequence */ - else - { - unsigned char sequence_length = 2; - if ((input_end - input_pointer) < 1) - { - goto fail; - } - - switch (input_pointer[1]) - { - case 'b': - *output_pointer++ = '\b'; - break; - case 'f': - *output_pointer++ = '\f'; - break; - case 'n': - *output_pointer++ = '\n'; - break; - case 'r': - *output_pointer++ = '\r'; - break; - case 't': - *output_pointer++ = '\t'; - break; - case '\"': - case '\\': - case '/': - *output_pointer++ = input_pointer[1]; - break; - - /* UTF-16 literal */ - case 'u': - sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); - if (sequence_length == 0) - { - /* failed to convert UTF16-literal to UTF-8 */ - goto fail; - } - break; - - default: - goto fail; - } - input_pointer += sequence_length; - } - } - - /* zero terminate the output */ - *output_pointer = '\0'; - - item->type = cJSON_String; - item->valuestring = (char*)output; - - input_buffer->offset = (size_t) (input_end - input_buffer->content); - input_buffer->offset++; - - return true; - -fail: - if (output != NULL) - { - input_buffer->hooks.deallocate(output); - } - - if (input_pointer != NULL) - { - input_buffer->offset = (size_t)(input_pointer - input_buffer->content); - } - - return false; -} - -/* Render the cstring provided to an escaped version that can be printed. */ -static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer) -{ - const unsigned char *input_pointer = NULL; - unsigned char *output = NULL; - unsigned char *output_pointer = NULL; - size_t output_length = 0; - /* numbers of additional characters needed for escaping */ - size_t escape_characters = 0; - - if (output_buffer == NULL) - { - return false; - } - - /* empty string */ - if (input == NULL) - { - output = ensure(output_buffer, sizeof("\"\"")); - if (output == NULL) - { - return false; - } - strcpy((char*)output, "\"\""); - - return true; - } - - /* set "flag" to 1 if something needs to be escaped */ - for (input_pointer = input; *input_pointer; input_pointer++) - { - switch (*input_pointer) - { - case '\"': - case '\\': - case '\b': - case '\f': - case '\n': - case '\r': - case '\t': - /* one character escape sequence */ - escape_characters++; - break; - default: - if (*input_pointer < 32) - { - /* UTF-16 escape sequence uXXXX */ - escape_characters += 5; - } - break; - } - } - output_length = (size_t)(input_pointer - input) + escape_characters; - - output = ensure(output_buffer, output_length + sizeof("\"\"")); - if (output == NULL) - { - return false; - } - - /* no characters have to be escaped */ - if (escape_characters == 0) - { - output[0] = '\"'; - memcpy(output + 1, input, output_length); - output[output_length + 1] = '\"'; - output[output_length + 2] = '\0'; - - return true; - } - - output[0] = '\"'; - output_pointer = output + 1; - /* copy the string */ - for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) - { - if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) - { - /* normal character, copy */ - *output_pointer = *input_pointer; - } - else - { - /* character needs to be escaped */ - *output_pointer++ = '\\'; - switch (*input_pointer) - { - case '\\': - *output_pointer = '\\'; - break; - case '\"': - *output_pointer = '\"'; - break; - case '\b': - *output_pointer = 'b'; - break; - case '\f': - *output_pointer = 'f'; - break; - case '\n': - *output_pointer = 'n'; - break; - case '\r': - *output_pointer = 'r'; - break; - case '\t': - *output_pointer = 't'; - break; - default: - /* escape and print as unicode codepoint */ - sprintf((char*)output_pointer, "u%04x", *input_pointer); - output_pointer += 4; - break; - } - } - } - output[output_length + 1] = '\"'; - output[output_length + 2] = '\0'; - - return true; -} - -/* Invoke print_string_ptr (which is useful) on an item. */ -static cJSON_bool print_string(const cJSON * const item, printbuffer * const p) -{ - return print_string_ptr((unsigned char*)item->valuestring, p); -} - -/* Predeclare these prototypes. */ -static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer); -static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer); -static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer); -static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer); -static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer); -static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer); - -/* Utility to jump whitespace and cr/lf */ -static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) -{ - if ((buffer == NULL) || (buffer->content == NULL)) - { - return NULL; - } - - if (cannot_access_at_index(buffer, 0)) - { - return buffer; - } - - while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) - { - buffer->offset++; - } - - if (buffer->offset == buffer->length) - { - buffer->offset--; - } - - return buffer; -} - -/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */ -static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) -{ - if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) - { - return NULL; - } - - if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) - { - buffer->offset += 3; - } - - return buffer; -} - -CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) -{ - size_t buffer_length; - - if (NULL == value) - { - return NULL; - } - - /* Adding null character size due to require_null_terminated. */ - buffer_length = strlen(value) + sizeof(""); - - return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated); -} - -/* Parse an object - create a new root, and populate. */ -CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated) -{ - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; - cJSON *item = NULL; - - /* reset error position */ - global_error.json = NULL; - global_error.position = 0; - - if (value == NULL || 0 == buffer_length) - { - goto fail; - } - - buffer.content = (const unsigned char*)value; - buffer.length = buffer_length; - buffer.offset = 0; - buffer.hooks = global_hooks; - - item = cJSON_New_Item(&global_hooks); - if (item == NULL) /* memory fail */ - { - goto fail; - } - - if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))) - { - /* parse failure. ep is set. */ - goto fail; - } - - /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ - if (require_null_terminated) - { - buffer_skip_whitespace(&buffer); - if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') - { - goto fail; - } - } - if (return_parse_end) - { - *return_parse_end = (const char*)buffer_at_offset(&buffer); - } - - return item; - -fail: - if (item != NULL) - { - cJSON_Delete(item); - } - - if (value != NULL) - { - error local_error; - local_error.json = (const unsigned char*)value; - local_error.position = 0; - - if (buffer.offset < buffer.length) - { - local_error.position = buffer.offset; - } - else if (buffer.length > 0) - { - local_error.position = buffer.length - 1; - } - - if (return_parse_end != NULL) - { - *return_parse_end = (const char*)local_error.json + local_error.position; - } - - global_error = local_error; - } - - return NULL; -} - -/* Default options for cJSON_Parse */ -CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) -{ - return cJSON_ParseWithOpts(value, 0, 0); -} - -CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length) -{ - return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0); -} - -#define cjson_min(a, b) (((a) < (b)) ? (a) : (b)) - -static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks) -{ - static const size_t default_buffer_size = 256; - printbuffer buffer[1]; - unsigned char *printed = NULL; - - memset(buffer, 0, sizeof(buffer)); - - /* create buffer */ - buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size); - buffer->length = default_buffer_size; - buffer->format = format; - buffer->hooks = *hooks; - if (buffer->buffer == NULL) - { - goto fail; - } - - /* print the value */ - if (!print_value(item, buffer)) - { - goto fail; - } - update_offset(buffer); - - /* check if reallocate is available */ - if (hooks->reallocate != NULL) - { - printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1); - if (printed == NULL) { - goto fail; - } - buffer->buffer = NULL; - } - else /* otherwise copy the JSON over to a new buffer */ - { - printed = (unsigned char*) hooks->allocate(buffer->offset + 1); - if (printed == NULL) - { - goto fail; - } - memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1)); - printed[buffer->offset] = '\0'; /* just to be sure */ - - /* free the buffer */ - hooks->deallocate(buffer->buffer); - } - - return printed; - -fail: - if (buffer->buffer != NULL) - { - hooks->deallocate(buffer->buffer); - } - - if (printed != NULL) - { - hooks->deallocate(printed); - } - - return NULL; -} - -/* Render a cJSON item/entity/structure to text. */ -CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) -{ - return (char*)print(item, true, &global_hooks); -} - -CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) -{ - return (char*)print(item, false, &global_hooks); -} - -CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) -{ - printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; - - if (prebuffer < 0) - { - return NULL; - } - - p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer); - if (!p.buffer) - { - return NULL; - } - - p.length = (size_t)prebuffer; - p.offset = 0; - p.noalloc = false; - p.format = fmt; - p.hooks = global_hooks; - - if (!print_value(item, &p)) - { - global_hooks.deallocate(p.buffer); - return NULL; - } - - return (char*)p.buffer; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) -{ - printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; - - if ((length < 0) || (buffer == NULL)) - { - return false; - } - - p.buffer = (unsigned char*)buffer; - p.length = (size_t)length; - p.offset = 0; - p.noalloc = true; - p.format = format; - p.hooks = global_hooks; - - return print_value(item, &p); -} - -/* Parser core - when encountering text, process appropriately. */ -static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer) -{ - if ((input_buffer == NULL) || (input_buffer->content == NULL)) - { - return false; /* no input */ - } - - /* parse the different types of values */ - /* null */ - if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0)) - { - item->type = cJSON_NULL; - input_buffer->offset += 4; - return true; - } - /* false */ - if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0)) - { - item->type = cJSON_False; - input_buffer->offset += 5; - return true; - } - /* true */ - if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0)) - { - item->type = cJSON_True; - item->valueint = 1; - input_buffer->offset += 4; - return true; - } - /* string */ - if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) - { - return parse_string(item, input_buffer); - } - /* number */ - if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) - { - return parse_number(item, input_buffer); - } - /* array */ - if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) - { - return parse_array(item, input_buffer); - } - /* object */ - if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) - { - return parse_object(item, input_buffer); - } - - return false; -} - -/* Render a value to text. */ -static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer) -{ - unsigned char *output = NULL; - - if ((item == NULL) || (output_buffer == NULL)) - { - return false; - } - - switch ((item->type) & 0xFF) - { - case cJSON_NULL: - output = ensure(output_buffer, 5); - if (output == NULL) - { - return false; - } - strcpy((char*)output, "null"); - return true; - - case cJSON_False: - output = ensure(output_buffer, 6); - if (output == NULL) - { - return false; - } - strcpy((char*)output, "false"); - return true; - - case cJSON_True: - output = ensure(output_buffer, 5); - if (output == NULL) - { - return false; - } - strcpy((char*)output, "true"); - return true; - - case cJSON_Number: - return print_number(item, output_buffer); - - case cJSON_Raw: - { - size_t raw_length = 0; - if (item->valuestring == NULL) - { - return false; - } - - raw_length = strlen(item->valuestring) + sizeof(""); - output = ensure(output_buffer, raw_length); - if (output == NULL) - { - return false; - } - memcpy(output, item->valuestring, raw_length); - return true; - } - - case cJSON_String: - return print_string(item, output_buffer); - - case cJSON_Array: - return print_array(item, output_buffer); - - case cJSON_Object: - return print_object(item, output_buffer); - - default: - return false; - } -} - -/* Build an array from input text. */ -static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer) -{ - cJSON *head = NULL; /* head of the linked list */ - cJSON *current_item = NULL; - - if (input_buffer->depth >= CJSON_NESTING_LIMIT) - { - return false; /* to deeply nested */ - } - input_buffer->depth++; - - if (buffer_at_offset(input_buffer)[0] != '[') - { - /* not an array */ - goto fail; - } - - input_buffer->offset++; - buffer_skip_whitespace(input_buffer); - if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) - { - /* empty array */ - goto success; - } - - /* check if we skipped to the end of the buffer */ - if (cannot_access_at_index(input_buffer, 0)) - { - input_buffer->offset--; - goto fail; - } - - /* step back to character in front of the first element */ - input_buffer->offset--; - /* loop through the comma separated array elements */ - do - { - /* allocate next item */ - cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); - if (new_item == NULL) - { - goto fail; /* allocation failure */ - } - - /* attach next item to list */ - if (head == NULL) - { - /* start the linked list */ - current_item = head = new_item; - } - else - { - /* add to the end and advance */ - current_item->next = new_item; - new_item->prev = current_item; - current_item = new_item; - } - - /* parse next value */ - input_buffer->offset++; - buffer_skip_whitespace(input_buffer); - if (!parse_value(current_item, input_buffer)) - { - goto fail; /* failed to parse value */ - } - buffer_skip_whitespace(input_buffer); - } - while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); - - if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') - { - goto fail; /* expected end of array */ - } - -success: - input_buffer->depth--; - - if (head != NULL) { - head->prev = current_item; - } - - item->type = cJSON_Array; - item->child = head; - - input_buffer->offset++; - - return true; - -fail: - if (head != NULL) - { - cJSON_Delete(head); - } - - return false; -} - -/* Render an array to text */ -static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer) -{ - unsigned char *output_pointer = NULL; - size_t length = 0; - cJSON *current_element = item->child; - - if (output_buffer == NULL) - { - return false; - } - - /* Compose the output array. */ - /* opening square bracket */ - output_pointer = ensure(output_buffer, 1); - if (output_pointer == NULL) - { - return false; - } - - *output_pointer = '['; - output_buffer->offset++; - output_buffer->depth++; - - while (current_element != NULL) - { - if (!print_value(current_element, output_buffer)) - { - return false; - } - update_offset(output_buffer); - if (current_element->next) - { - length = (size_t) (output_buffer->format ? 2 : 1); - output_pointer = ensure(output_buffer, length + 1); - if (output_pointer == NULL) - { - return false; - } - *output_pointer++ = ','; - if(output_buffer->format) - { - *output_pointer++ = ' '; - } - *output_pointer = '\0'; - output_buffer->offset += length; - } - current_element = current_element->next; - } - - output_pointer = ensure(output_buffer, 2); - if (output_pointer == NULL) - { - return false; - } - *output_pointer++ = ']'; - *output_pointer = '\0'; - output_buffer->depth--; - - return true; -} - -/* Build an object from the text. */ -static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer) -{ - cJSON *head = NULL; /* linked list head */ - cJSON *current_item = NULL; - - if (input_buffer->depth >= CJSON_NESTING_LIMIT) - { - return false; /* to deeply nested */ - } - input_buffer->depth++; - - if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) - { - goto fail; /* not an object */ - } - - input_buffer->offset++; - buffer_skip_whitespace(input_buffer); - if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) - { - goto success; /* empty object */ - } - - /* check if we skipped to the end of the buffer */ - if (cannot_access_at_index(input_buffer, 0)) - { - input_buffer->offset--; - goto fail; - } - - /* step back to character in front of the first element */ - input_buffer->offset--; - /* loop through the comma separated array elements */ - do - { - /* allocate next item */ - cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); - if (new_item == NULL) - { - goto fail; /* allocation failure */ - } - - /* attach next item to list */ - if (head == NULL) - { - /* start the linked list */ - current_item = head = new_item; - } - else - { - /* add to the end and advance */ - current_item->next = new_item; - new_item->prev = current_item; - current_item = new_item; - } - - /* parse the name of the child */ - input_buffer->offset++; - buffer_skip_whitespace(input_buffer); - if (!parse_string(current_item, input_buffer)) - { - goto fail; /* failed to parse name */ - } - buffer_skip_whitespace(input_buffer); - - /* swap valuestring and string, because we parsed the name */ - current_item->string = current_item->valuestring; - current_item->valuestring = NULL; - - if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) - { - goto fail; /* invalid object */ - } - - /* parse the value */ - input_buffer->offset++; - buffer_skip_whitespace(input_buffer); - if (!parse_value(current_item, input_buffer)) - { - goto fail; /* failed to parse value */ - } - buffer_skip_whitespace(input_buffer); - } - while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); - - if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) - { - goto fail; /* expected end of object */ - } - -success: - input_buffer->depth--; - - if (head != NULL) { - head->prev = current_item; - } - - item->type = cJSON_Object; - item->child = head; - - input_buffer->offset++; - return true; - -fail: - if (head != NULL) - { - cJSON_Delete(head); - } - - return false; -} - -/* Render an object to text. */ -static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer) -{ - unsigned char *output_pointer = NULL; - size_t length = 0; - cJSON *current_item = item->child; - - if (output_buffer == NULL) - { - return false; - } - - /* Compose the output: */ - length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */ - output_pointer = ensure(output_buffer, length + 1); - if (output_pointer == NULL) - { - return false; - } - - *output_pointer++ = '{'; - output_buffer->depth++; - if (output_buffer->format) - { - *output_pointer++ = '\n'; - } - output_buffer->offset += length; - - while (current_item) - { - if (output_buffer->format) - { - size_t i; - output_pointer = ensure(output_buffer, output_buffer->depth); - if (output_pointer == NULL) - { - return false; - } - for (i = 0; i < output_buffer->depth; i++) - { - *output_pointer++ = '\t'; - } - output_buffer->offset += output_buffer->depth; - } - - /* print key */ - if (!print_string_ptr((unsigned char*)current_item->string, output_buffer)) - { - return false; - } - update_offset(output_buffer); - - length = (size_t) (output_buffer->format ? 2 : 1); - output_pointer = ensure(output_buffer, length); - if (output_pointer == NULL) - { - return false; - } - *output_pointer++ = ':'; - if (output_buffer->format) - { - *output_pointer++ = '\t'; - } - output_buffer->offset += length; - - /* print value */ - if (!print_value(current_item, output_buffer)) - { - return false; - } - update_offset(output_buffer); - - /* print comma if not last */ - length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0)); - output_pointer = ensure(output_buffer, length + 1); - if (output_pointer == NULL) - { - return false; - } - if (current_item->next) - { - *output_pointer++ = ','; - } - - if (output_buffer->format) - { - *output_pointer++ = '\n'; - } - *output_pointer = '\0'; - output_buffer->offset += length; - - current_item = current_item->next; - } - - output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2); - if (output_pointer == NULL) - { - return false; - } - if (output_buffer->format) - { - size_t i; - for (i = 0; i < (output_buffer->depth - 1); i++) - { - *output_pointer++ = '\t'; - } - } - *output_pointer++ = '}'; - *output_pointer = '\0'; - output_buffer->depth--; - - return true; -} - -/* Get Array size/item / object item. */ -CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) -{ - cJSON *child = NULL; - size_t size = 0; - - if (array == NULL) - { - return 0; - } - - child = array->child; - - while(child != NULL) - { - size++; - child = child->next; - } - - /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ - - return (int)size; -} - -static cJSON* get_array_item(const cJSON *array, size_t index) -{ - cJSON *current_child = NULL; - - if (array == NULL) - { - return NULL; - } - - current_child = array->child; - while ((current_child != NULL) && (index > 0)) - { - index--; - current_child = current_child->next; - } - - return current_child; -} - -CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index) -{ - if (index < 0) - { - return NULL; - } - - return get_array_item(array, (size_t)index); -} - -static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive) -{ - cJSON *current_element = NULL; - - if ((object == NULL) || (name == NULL)) - { - return NULL; - } - - current_element = object->child; - if (case_sensitive) - { - while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0)) - { - current_element = current_element->next; - } - } - else - { - while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0)) - { - current_element = current_element->next; - } - } - - if ((current_element == NULL) || (current_element->string == NULL)) { - return NULL; - } - - return current_element; -} - -CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string) -{ - return get_object_item(object, string, false); -} - -CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) -{ - return get_object_item(object, string, true); -} - -CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string) -{ - return cJSON_GetObjectItem(object, string) ? 1 : 0; -} - -/* Utility for array list handling. */ -static void suffix_object(cJSON *prev, cJSON *item) -{ - prev->next = item; - item->prev = prev; -} - -/* Utility for handling references. */ -static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks) -{ - cJSON *reference = NULL; - if (item == NULL) - { - return NULL; - } - - reference = cJSON_New_Item(hooks); - if (reference == NULL) - { - return NULL; - } - - memcpy(reference, item, sizeof(cJSON)); - reference->string = NULL; - reference->type |= cJSON_IsReference; - reference->next = reference->prev = NULL; - return reference; -} - -static cJSON_bool add_item_to_array(cJSON *array, cJSON *item) -{ - cJSON *child = NULL; - - if ((item == NULL) || (array == NULL) || (array == item)) - { - return false; - } - - child = array->child; - /* - * To find the last item in array quickly, we use prev in array - */ - if (child == NULL) - { - /* list is empty, start new one */ - array->child = item; - item->prev = item; - item->next = NULL; - } - else - { - /* append to the end */ - if (child->prev) - { - suffix_object(child->prev, item); - array->child->prev = item; - } - } - - return true; -} - -/* Add item to array/object. */ -CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item) -{ - return add_item_to_array(array, item); -} - -#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) - #pragma GCC diagnostic push -#endif -#ifdef __GNUC__ -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif -/* helper function to cast away const */ -static void* cast_away_const(const void* string) -{ - return (void*)string; -} -#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) - #pragma GCC diagnostic pop -#endif - - -static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key) -{ - char *new_key = NULL; - int new_type = cJSON_Invalid; - - if ((object == NULL) || (string == NULL) || (item == NULL) || (object == item)) - { - return false; - } - - if (constant_key) - { - new_key = (char*)cast_away_const(string); - new_type = item->type | cJSON_StringIsConst; - } - else - { - new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks); - if (new_key == NULL) - { - return false; - } - - new_type = item->type & ~cJSON_StringIsConst; - } - - if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) - { - hooks->deallocate(item->string); - } - - item->string = new_key; - item->type = new_type; - - return add_item_to_array(object, item); -} - -CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) -{ - return add_item_to_object(object, string, item, &global_hooks, false); -} - -/* Add an item to an object with constant string as key */ -CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) -{ - return add_item_to_object(object, string, item, &global_hooks, true); -} - -CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) -{ - if (array == NULL) - { - return false; - } - - return add_item_to_array(array, create_reference(item, &global_hooks)); -} - -CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) -{ - if ((object == NULL) || (string == NULL)) - { - return false; - } - - return add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false); -} - -CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name) -{ - cJSON *null = cJSON_CreateNull(); - if (add_item_to_object(object, name, null, &global_hooks, false)) - { - return null; - } - - cJSON_Delete(null); - return NULL; -} - -CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name) -{ - cJSON *true_item = cJSON_CreateTrue(); - if (add_item_to_object(object, name, true_item, &global_hooks, false)) - { - return true_item; - } - - cJSON_Delete(true_item); - return NULL; -} - -CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name) -{ - cJSON *false_item = cJSON_CreateFalse(); - if (add_item_to_object(object, name, false_item, &global_hooks, false)) - { - return false_item; - } - - cJSON_Delete(false_item); - return NULL; -} - -CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean) -{ - cJSON *bool_item = cJSON_CreateBool(boolean); - if (add_item_to_object(object, name, bool_item, &global_hooks, false)) - { - return bool_item; - } - - cJSON_Delete(bool_item); - return NULL; -} - -CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number) -{ - cJSON *number_item = cJSON_CreateNumber(number); - if (add_item_to_object(object, name, number_item, &global_hooks, false)) - { - return number_item; - } - - cJSON_Delete(number_item); - return NULL; -} - -CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string) -{ - cJSON *string_item = cJSON_CreateString(string); - if (add_item_to_object(object, name, string_item, &global_hooks, false)) - { - return string_item; - } - - cJSON_Delete(string_item); - return NULL; -} - -CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw) -{ - cJSON *raw_item = cJSON_CreateRaw(raw); - if (add_item_to_object(object, name, raw_item, &global_hooks, false)) - { - return raw_item; - } - - cJSON_Delete(raw_item); - return NULL; -} - -CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name) -{ - cJSON *object_item = cJSON_CreateObject(); - if (add_item_to_object(object, name, object_item, &global_hooks, false)) - { - return object_item; - } - - cJSON_Delete(object_item); - return NULL; -} - -CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name) -{ - cJSON *array = cJSON_CreateArray(); - if (add_item_to_object(object, name, array, &global_hooks, false)) - { - return array; - } - - cJSON_Delete(array); - return NULL; -} - -CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) -{ - if ((parent == NULL) || (item == NULL)) - { - return NULL; - } - - if (item != parent->child) - { - /* not the first element */ - item->prev->next = item->next; - } - if (item->next != NULL) - { - /* not the last element */ - item->next->prev = item->prev; - } - - if (item == parent->child) - { - /* first element */ - parent->child = item->next; - } - else if (item->next == NULL) - { - /* last element */ - parent->child->prev = item->prev; - } - - /* make sure the detached item doesn't point anywhere anymore */ - item->prev = NULL; - item->next = NULL; - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which) -{ - if (which < 0) - { - return NULL; - } - - return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which)); -} - -CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) -{ - cJSON_Delete(cJSON_DetachItemFromArray(array, which)); -} - -CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string) -{ - cJSON *to_detach = cJSON_GetObjectItem(object, string); - - return cJSON_DetachItemViaPointer(object, to_detach); -} - -CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string) -{ - cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string); - - return cJSON_DetachItemViaPointer(object, to_detach); -} - -CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) -{ - cJSON_Delete(cJSON_DetachItemFromObject(object, string)); -} - -CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string) -{ - cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string)); -} - -/* Replace array/object items with new ones. */ -CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) -{ - cJSON *after_inserted = NULL; - - if (which < 0) - { - return false; - } - - after_inserted = get_array_item(array, (size_t)which); - if (after_inserted == NULL) - { - return add_item_to_array(array, newitem); - } - - newitem->next = after_inserted; - newitem->prev = after_inserted->prev; - after_inserted->prev = newitem; - if (after_inserted == array->child) - { - array->child = newitem; - } - else - { - newitem->prev->next = newitem; - } - return true; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement) -{ - if ((parent == NULL) || (replacement == NULL) || (item == NULL)) - { - return false; - } - - if (replacement == item) - { - return true; - } - - replacement->next = item->next; - replacement->prev = item->prev; - - if (replacement->next != NULL) - { - replacement->next->prev = replacement; - } - if (parent->child == item) - { - if (parent->child->prev == parent->child) - { - replacement->prev = replacement; - } - parent->child = replacement; - } - else - { /* - * To find the last item in array quickly, we use prev in array. - * We can't modify the last item's next pointer where this item was the parent's child - */ - if (replacement->prev != NULL) - { - replacement->prev->next = replacement; - } - if (replacement->next == NULL) - { - parent->child->prev = replacement; - } - } - - item->next = NULL; - item->prev = NULL; - cJSON_Delete(item); - - return true; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) -{ - if (which < 0) - { - return false; - } - - return cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem); -} - -static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive) -{ - if ((replacement == NULL) || (string == NULL)) - { - return false; - } - - /* replace the name in the replacement */ - if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL)) - { - cJSON_free(replacement->string); - } - replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); - replacement->type &= ~cJSON_StringIsConst; - - return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); -} - -CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) -{ - return replace_item_in_object(object, string, newitem, false); -} - -CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) -{ - return replace_item_in_object(object, string, newitem, true); -} - -/* Create basic types: */ -CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = cJSON_NULL; - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = cJSON_True; - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = cJSON_False; - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = boolean ? cJSON_True : cJSON_False; - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = cJSON_Number; - item->valuedouble = num; - - /* use saturation in case of overflow */ - if (num >= INT_MAX) - { - item->valueint = INT_MAX; - } - else if (num <= (double)INT_MIN) - { - item->valueint = INT_MIN; - } - else - { - item->valueint = (int)num; - } - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = cJSON_String; - item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); - if(!item->valuestring) - { - cJSON_Delete(item); - return NULL; - } - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if (item != NULL) - { - item->type = cJSON_String | cJSON_IsReference; - item->valuestring = (char*)cast_away_const(string); - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if (item != NULL) { - item->type = cJSON_Object | cJSON_IsReference; - item->child = (cJSON*)cast_away_const(child); - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) { - cJSON *item = cJSON_New_Item(&global_hooks); - if (item != NULL) { - item->type = cJSON_Array | cJSON_IsReference; - item->child = (cJSON*)cast_away_const(child); - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = cJSON_Raw; - item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks); - if(!item->valuestring) - { - cJSON_Delete(item); - return NULL; - } - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type=cJSON_Array; - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if (item) - { - item->type = cJSON_Object; - } - - return item; -} - -/* Create Arrays: */ -CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) -{ - size_t i = 0; - cJSON *n = NULL; - cJSON *p = NULL; - cJSON *a = NULL; - - if ((count < 0) || (numbers == NULL)) - { - return NULL; - } - - a = cJSON_CreateArray(); - - for(i = 0; a && (i < (size_t)count); i++) - { - n = cJSON_CreateNumber(numbers[i]); - if (!n) - { - cJSON_Delete(a); - return NULL; - } - if(!i) - { - a->child = n; - } - else - { - suffix_object(p, n); - } - p = n; - } - - if (a && a->child) { - a->child->prev = n; - } - - return a; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) -{ - size_t i = 0; - cJSON *n = NULL; - cJSON *p = NULL; - cJSON *a = NULL; - - if ((count < 0) || (numbers == NULL)) - { - return NULL; - } - - a = cJSON_CreateArray(); - - for(i = 0; a && (i < (size_t)count); i++) - { - n = cJSON_CreateNumber((double)numbers[i]); - if(!n) - { - cJSON_Delete(a); - return NULL; - } - if(!i) - { - a->child = n; - } - else - { - suffix_object(p, n); - } - p = n; - } - - if (a && a->child) { - a->child->prev = n; - } - - return a; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) -{ - size_t i = 0; - cJSON *n = NULL; - cJSON *p = NULL; - cJSON *a = NULL; - - if ((count < 0) || (numbers == NULL)) - { - return NULL; - } - - a = cJSON_CreateArray(); - - for(i = 0; a && (i < (size_t)count); i++) - { - n = cJSON_CreateNumber(numbers[i]); - if(!n) - { - cJSON_Delete(a); - return NULL; - } - if(!i) - { - a->child = n; - } - else - { - suffix_object(p, n); - } - p = n; - } - - if (a && a->child) { - a->child->prev = n; - } - - return a; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count) -{ - size_t i = 0; - cJSON *n = NULL; - cJSON *p = NULL; - cJSON *a = NULL; - - if ((count < 0) || (strings == NULL)) - { - return NULL; - } - - a = cJSON_CreateArray(); - - for (i = 0; a && (i < (size_t)count); i++) - { - n = cJSON_CreateString(strings[i]); - if(!n) - { - cJSON_Delete(a); - return NULL; - } - if(!i) - { - a->child = n; - } - else - { - suffix_object(p,n); - } - p = n; - } - - if (a && a->child) { - a->child->prev = n; - } - - return a; -} - -/* Duplication */ -CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) -{ - cJSON *newitem = NULL; - cJSON *child = NULL; - cJSON *next = NULL; - cJSON *newchild = NULL; - - /* Bail on bad ptr */ - if (!item) - { - goto fail; - } - /* Create new item */ - newitem = cJSON_New_Item(&global_hooks); - if (!newitem) - { - goto fail; - } - /* Copy over all vars */ - newitem->type = item->type & (~cJSON_IsReference); - newitem->valueint = item->valueint; - newitem->valuedouble = item->valuedouble; - if (item->valuestring) - { - newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks); - if (!newitem->valuestring) - { - goto fail; - } - } - if (item->string) - { - newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks); - if (!newitem->string) - { - goto fail; - } - } - /* If non-recursive, then we're done! */ - if (!recurse) - { - return newitem; - } - /* Walk the ->next chain for the child. */ - child = item->child; - while (child != NULL) - { - newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ - if (!newchild) - { - goto fail; - } - if (next != NULL) - { - /* If newitem->child already set, then crosswire ->prev and ->next and move on */ - next->next = newchild; - newchild->prev = next; - next = newchild; - } - else - { - /* Set newitem->child and move to it */ - newitem->child = newchild; - next = newchild; - } - child = child->next; - } - if (newitem && newitem->child) - { - newitem->child->prev = newchild; - } - - return newitem; - -fail: - if (newitem != NULL) - { - cJSON_Delete(newitem); - } - - return NULL; -} - -static void skip_oneline_comment(char **input) -{ - *input += static_strlen("//"); - - for (; (*input)[0] != '\0'; ++(*input)) - { - if ((*input)[0] == '\n') { - *input += static_strlen("\n"); - return; - } - } -} - -static void skip_multiline_comment(char **input) -{ - *input += static_strlen("/*"); - - for (; (*input)[0] != '\0'; ++(*input)) - { - if (((*input)[0] == '*') && ((*input)[1] == '/')) - { - *input += static_strlen("*/"); - return; - } - } -} - -static void minify_string(char **input, char **output) { - (*output)[0] = (*input)[0]; - *input += static_strlen("\""); - *output += static_strlen("\""); - - - for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) { - (*output)[0] = (*input)[0]; - - if ((*input)[0] == '\"') { - (*output)[0] = '\"'; - *input += static_strlen("\""); - *output += static_strlen("\""); - return; - } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) { - (*output)[1] = (*input)[1]; - *input += static_strlen("\""); - *output += static_strlen("\""); - } - } -} - -CJSON_PUBLIC(void) cJSON_Minify(char *json) -{ - char *into = json; - - if (json == NULL) - { - return; - } - - while (json[0] != '\0') - { - switch (json[0]) - { - case ' ': - case '\t': - case '\r': - case '\n': - json++; - break; - - case '/': - if (json[1] == '/') - { - skip_oneline_comment(&json); - } - else if (json[1] == '*') - { - skip_multiline_comment(&json); - } else { - json++; - } - break; - - case '\"': - minify_string(&json, (char**)&into); - break; - - default: - into[0] = json[0]; - json++; - into++; - } - } - - /* and null-terminate. */ - *into = '\0'; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xFF) == cJSON_Invalid; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xFF) == cJSON_False; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xff) == cJSON_True; -} - - -CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & (cJSON_True | cJSON_False)) != 0; -} -CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xFF) == cJSON_NULL; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xFF) == cJSON_Number; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xFF) == cJSON_String; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xFF) == cJSON_Array; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xFF) == cJSON_Object; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xFF) == cJSON_Raw; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive) -{ - if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) - { - return false; - } - - /* check if type is valid */ - switch (a->type & 0xFF) - { - case cJSON_False: - case cJSON_True: - case cJSON_NULL: - case cJSON_Number: - case cJSON_String: - case cJSON_Raw: - case cJSON_Array: - case cJSON_Object: - break; - - default: - return false; - } - - /* identical objects are equal */ - if (a == b) - { - return true; - } - - switch (a->type & 0xFF) - { - /* in these cases and equal type is enough */ - case cJSON_False: - case cJSON_True: - case cJSON_NULL: - return true; - - case cJSON_Number: - if (compare_double(a->valuedouble, b->valuedouble)) - { - return true; - } - return false; - - case cJSON_String: - case cJSON_Raw: - if ((a->valuestring == NULL) || (b->valuestring == NULL)) - { - return false; - } - if (strcmp(a->valuestring, b->valuestring) == 0) - { - return true; - } - - return false; - - case cJSON_Array: - { - cJSON *a_element = a->child; - cJSON *b_element = b->child; - - for (; (a_element != NULL) && (b_element != NULL);) - { - if (!cJSON_Compare(a_element, b_element, case_sensitive)) - { - return false; - } - - a_element = a_element->next; - b_element = b_element->next; - } - - /* one of the arrays is longer than the other */ - if (a_element != b_element) { - return false; - } - - return true; - } - - case cJSON_Object: - { - cJSON *a_element = NULL; - cJSON *b_element = NULL; - cJSON_ArrayForEach(a_element, a) - { - /* TODO This has O(n^2) runtime, which is horrible! */ - b_element = get_object_item(b, a_element->string, case_sensitive); - if (b_element == NULL) - { - return false; - } - - if (!cJSON_Compare(a_element, b_element, case_sensitive)) - { - return false; - } - } - - /* doing this twice, once on a and b to prevent true comparison if a subset of b - * TODO: Do this the proper way, this is just a fix for now */ - cJSON_ArrayForEach(b_element, b) - { - a_element = get_object_item(a, b_element->string, case_sensitive); - if (a_element == NULL) - { - return false; - } - - if (!cJSON_Compare(b_element, a_element, case_sensitive)) - { - return false; - } - } - - return true; - } - - default: - return false; - } -} - -CJSON_PUBLIC(void *) cJSON_malloc(size_t size) -{ - return global_hooks.allocate(size); -} - -CJSON_PUBLIC(void) cJSON_free(void *object) -{ - global_hooks.deallocate(object); -} diff --git a/APP_Framework/Applications/knowing_app/instrusion_detect/cJSON.h b/APP_Framework/Applications/knowing_app/instrusion_detect/cJSON.h deleted file mode 100644 index e97e5f4c..00000000 --- a/APP_Framework/Applications/knowing_app/instrusion_detect/cJSON.h +++ /dev/null @@ -1,293 +0,0 @@ -/* - Copyright (c) 2009-2017 Dave Gamble and cJSON contributors - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*/ - -#ifndef cJSON__h -#define cJSON__h - -#ifdef __cplusplus -extern "C" -{ -#endif - -#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) -#define __WINDOWS__ -#endif - -#ifdef __WINDOWS__ - -/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options: - -CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols -CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) -CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol - -For *nix builds that support visibility attribute, you can define similar behavior by - -setting default visibility to hidden by adding --fvisibility=hidden (for gcc) -or --xldscope=hidden (for sun cc) -to CFLAGS - -then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does - -*/ - -#define CJSON_CDECL __cdecl -#define CJSON_STDCALL __stdcall - -/* export symbols by default, this is necessary for copy pasting the C and header file */ -#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) -#define CJSON_EXPORT_SYMBOLS -#endif - -#if defined(CJSON_HIDE_SYMBOLS) -#define CJSON_PUBLIC(type) type CJSON_STDCALL -#elif defined(CJSON_EXPORT_SYMBOLS) -#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL -#elif defined(CJSON_IMPORT_SYMBOLS) -#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL -#endif -#else /* !__WINDOWS__ */ -#define CJSON_CDECL -#define CJSON_STDCALL - -#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) -#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type -#else -#define CJSON_PUBLIC(type) type -#endif -#endif - -/* project version */ -#define CJSON_VERSION_MAJOR 1 -#define CJSON_VERSION_MINOR 7 -#define CJSON_VERSION_PATCH 14 - -#include - -/* cJSON Types: */ -#define cJSON_Invalid (0) -#define cJSON_False (1 << 0) -#define cJSON_True (1 << 1) -#define cJSON_NULL (1 << 2) -#define cJSON_Number (1 << 3) -#define cJSON_String (1 << 4) -#define cJSON_Array (1 << 5) -#define cJSON_Object (1 << 6) -#define cJSON_Raw (1 << 7) /* raw json */ - -#define cJSON_IsReference 256 -#define cJSON_StringIsConst 512 - -/* The cJSON structure: */ -typedef struct cJSON -{ - /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ - struct cJSON *next; - struct cJSON *prev; - /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ - struct cJSON *child; - - /* The type of the item, as above. */ - int type; - - /* The item's string, if type==cJSON_String and type == cJSON_Raw */ - char *valuestring; - /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ - int valueint; - /* The item's number, if type==cJSON_Number */ - double valuedouble; - - /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ - char *string; -} cJSON; - -typedef struct cJSON_Hooks -{ - /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */ - void *(CJSON_CDECL *malloc_fn)(size_t sz); - void (CJSON_CDECL *free_fn)(void *ptr); -} cJSON_Hooks; - -typedef int cJSON_bool; - -/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them. - * This is to prevent stack overflows. */ -#ifndef CJSON_NESTING_LIMIT -#define CJSON_NESTING_LIMIT 1000 -#endif - -/* returns the version of cJSON as a string */ -CJSON_PUBLIC(const char*) cJSON_Version(void); - -/* Supply malloc, realloc and free functions to cJSON */ -CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); - -/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ -/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ -CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); -CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length); -/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ -/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */ -CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); -CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated); - -/* Render a cJSON entity to text for transfer/storage. */ -CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); -/* Render a cJSON entity to text for transfer/storage without any formatting. */ -CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); -/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ -CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); -/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ -/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ -CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); -/* Delete a cJSON entity and all subentities. */ -CJSON_PUBLIC(void) cJSON_Delete(cJSON *item); - -/* Returns the number of items in an array (or object). */ -CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); -/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */ -CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); -/* Get item "string" from object. Case insensitive. */ -CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); -CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); -CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string); -/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ -CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); - -/* Check item type and return its value */ -CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item); -CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item); - -/* These functions check the type of an item */ -CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item); - -/* These calls create a cJSON item of the appropriate type. */ -CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); -CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); -CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); -CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); -CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); -CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); -/* raw json */ -CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); -CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); -CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); - -/* Create a string where valuestring references a string so - * it will not be freed by cJSON_Delete */ -CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); -/* Create an object/array that only references it's elements so - * they will not be freed by cJSON_Delete */ -CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); -CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); - -/* These utilities create an Array of count items. - * The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/ -CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); -CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); -CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); -CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count); - -/* Append item to the specified array/object. */ -CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item); -CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); -/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. - * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before - * writing to `item->string` */ -CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); -/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ -CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); -CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); - -/* Remove/Detach items from Arrays/Objects. */ -CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); -CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); -CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); -CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); -CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); -CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); -CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); - -/* Update array items. */ -CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ -CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); -CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); -CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); -CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem); - -/* Duplicate a cJSON item */ -CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); -/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will - * need to be released. With recurse!=0, it will duplicate any children connected to the item. - * The item->next and ->prev pointers are always zero on return from Duplicate. */ -/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal. - * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ -CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); - -/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings. - * The input pointer json cannot point to a read-only address area, such as a string constant, - * but should point to a readable and writable adress area. */ -CJSON_PUBLIC(void) cJSON_Minify(char *json); - -/* Helper functions for creating and adding items to an object at the same time. - * They return the added item or NULL on failure. */ -CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name); -CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name); -CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name); -CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean); -CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number); -CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string); -CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw); -CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name); -CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name); - -/* When assigning an integer value, it needs to be propagated to valuedouble too. */ -#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) -/* helper for the cJSON_SetNumberValue macro */ -CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); -#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) -/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */ -CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring); - -/* Macro for iterating over an array or object */ -#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) - -/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ -CJSON_PUBLIC(void *) cJSON_malloc(size_t size); -CJSON_PUBLIC(void) cJSON_free(void *object); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/APP_Framework/Applications/knowing_app/instrusion_detect/human.json b/APP_Framework/Applications/knowing_app/instrusion_detect/human.json index 74d1d096..0331ecc2 100644 --- a/APP_Framework/Applications/knowing_app/instrusion_detect/human.json +++ b/APP_Framework/Applications/knowing_app/instrusion_detect/human.json @@ -27,7 +27,7 @@ "kmodel_path": "/kmodel/human.kmodel", "kmodel_size": 1903016, "obj_thresh": [ - 0.3 + 0.35 ], "labels": [ "human" diff --git a/APP_Framework/Applications/knowing_app/instrusion_detect/instrusion_detect.c b/APP_Framework/Applications/knowing_app/instrusion_detect/instrusion_detect.c index 8fad834c..62929d0a 100644 --- a/APP_Framework/Applications/knowing_app/instrusion_detect/instrusion_detect.c +++ b/APP_Framework/Applications/knowing_app/instrusion_detect/instrusion_detect.c @@ -1,6 +1,7 @@ #include - -#include "cJSON.h" +#ifdef LIB_USING_CJSON +#include +#endif #include "region_layer.h" #define ANCHOR_NUM 5 #define STACK_SIZE (128 * 1024) @@ -8,16 +9,16 @@ #define JSON_BUFFER_SIZE (4 * 1024) // params from json -float anchor[ANCHOR_NUM * 2] = {}; -int net_output_shape[3] = {}; -int net_input_size[2] = {}; -int sensor_output_size[2] = {}; -char kmodel_path[127] = ""; -int kmodel_size = 0; -float obj_thresh[20] = {}; -float nms_thresh = 0.0; -char labels[20][32] = {}; -int class_num = 0; +static float anchor[ANCHOR_NUM * 2] = {}; +static int net_output_shape[3] = {}; +static int net_input_size[2] = {}; +static int sensor_output_size[2] = {}; +static char kmodel_path[127] = ""; +static int kmodel_size = 0; +static float obj_thresh[20] = {}; +static float nms_thresh = 0.0; +static char labels[20][32] = {}; +static int class_num = 0; #define THREAD_PRIORITY_HUMAN_D (11) static pthread_t instrusiontid = 0; @@ -140,12 +141,12 @@ static void param_parse() printf("No labels!"); exit(-1); } else { - printf("Got %d labels\n"); + printf("Got %d labels\n", class_num); } for (int i = 0; i < class_num; i++) { json_array_item = cJSON_GetArrayItem(json_item, i); - memcpy(labels[i], json_item->valuestring, strlen(json_item->valuestring)); - printf("%d: %f\n", i, labels[i]); + memcpy(labels[i], json_array_item->valuestring, strlen(json_array_item->valuestring)); + printf("%d: %s\n", i, labels[i]); } // obj_thresh json_item = cJSON_GetObjectItem(json_obj, "obj_thresh"); @@ -154,7 +155,7 @@ static void param_parse() printf("label number and thresh number mismatch! label number : %d, obj thresh number %d", class_num, array_size); exit(-1); } else { - printf("Got %d obj_thresh\n"); + printf("Got %d obj_thresh\n", array_size); } for (int i = 0; i < array_size; i++) { json_array_item = cJSON_GetArrayItem(json_item, i); @@ -253,7 +254,7 @@ void instrusion_detect() instrusion_detect_rl.threshold = malloc(class_num * sizeof(float)); for (int idx = 0; idx < class_num; idx++) { instrusion_detect_rl.threshold[idx] = obj_thresh[idx]; - ; + } instrusion_detect_rl.nms_value = nms_thresh; result = region_layer_init(&instrusion_detect_rl, net_output_shape[0], net_output_shape[1], net_output_shape[2], net_input_size[1], net_input_size[0]); @@ -310,15 +311,13 @@ static void *thread_instrusion_detect_entry(void *parameter) // draw_edge((uint32_t *)showbuffer, &instrusion_detect_info, instrusion_cnt, 0xF800, // (uint16_t)sensor_output_size[1], // (uint16_t)sensor_output_size[0]); - printf("%d: (%d, %d, %d, %d) cls: %d conf: %f\t", instrusion_cnt, instrusion_detect_info.obj[instrusion_cnt].x1, + printf("%d: (%d, %d, %d, %d) cls: %s conf: %f\t", instrusion_cnt, instrusion_detect_info.obj[instrusion_cnt].x1, instrusion_detect_info.obj[instrusion_cnt].y1, instrusion_detect_info.obj[instrusion_cnt].x2, - instrusion_detect_info.obj[instrusion_cnt].y2, instrusion_detect_info.obj[instrusion_cnt].class_id, + instrusion_detect_info.obj[instrusion_cnt].y2, labels[instrusion_detect_info.obj[instrusion_cnt].class_id], instrusion_detect_info.obj[instrusion_cnt].prob); } if (0 != instrusion_detect_info.obj_number) { printf("\n"); - } else { - printf("No human found!\n"); } lcd_draw_picture(0, 0, (uint16_t)sensor_output_size[1], (uint16_t)sensor_output_size[0], (unsigned int *)showbuffer); #endif From 9a1a407ea6528044228132d55104f46ecd6b68ca Mon Sep 17 00:00:00 2001 From: yangtuo250 <506680965@qq.com> Date: Tue, 10 Aug 2021 18:02:16 +0800 Subject: [PATCH 08/18] feat(knowing app): stm32f4 svc iris demo --- .../Applications/knowing_app/Kconfig | 1 + .../knowing_app/iris_ml_demo/Kconfig | 3 + .../knowing_app/iris_ml_demo/SConscript | 9 + .../knowing_app/iris_ml_demo/SVCModel.h | 78 ++++++ .../knowing_app/iris_ml_demo/iris.csv | 7 + .../knowing_app/iris_ml_demo/iris_ml_demo.c | 59 +++++ .../bsp/stm32f407-atk-coreboard/.config | 6 +- .../bsp/stm32f407-atk-coreboard/.gitignore | 233 +++++++++++++++++- .../bsp/stm32f407-atk-coreboard/rtconfig.h | 5 +- .../bsp/stm32f407-atk-coreboard/rtconfig.py | 2 +- 10 files changed, 388 insertions(+), 15 deletions(-) create mode 100644 APP_Framework/Applications/knowing_app/iris_ml_demo/Kconfig create mode 100644 APP_Framework/Applications/knowing_app/iris_ml_demo/SConscript create mode 100644 APP_Framework/Applications/knowing_app/iris_ml_demo/SVCModel.h create mode 100644 APP_Framework/Applications/knowing_app/iris_ml_demo/iris.csv create mode 100644 APP_Framework/Applications/knowing_app/iris_ml_demo/iris_ml_demo.c diff --git a/APP_Framework/Applications/knowing_app/Kconfig b/APP_Framework/Applications/knowing_app/Kconfig index 8e0305b6..bb8cfa0d 100755 --- a/APP_Framework/Applications/knowing_app/Kconfig +++ b/APP_Framework/Applications/knowing_app/Kconfig @@ -3,4 +3,5 @@ menu "knowing app" source "$APP_DIR/Applications/knowing_app/face_detect/Kconfig" source "$APP_DIR/Applications/knowing_app/instrusion_detect/Kconfig" source "$APP_DIR/Applications/knowing_app/helmet_detect/Kconfig" + source "$APP_DIR/Applications/knowing_app/iris_ml_demo/Kconfig" endmenu diff --git a/APP_Framework/Applications/knowing_app/iris_ml_demo/Kconfig b/APP_Framework/Applications/knowing_app/iris_ml_demo/Kconfig new file mode 100644 index 00000000..ef278670 --- /dev/null +++ b/APP_Framework/Applications/knowing_app/iris_ml_demo/Kconfig @@ -0,0 +1,3 @@ +config IRIS_ML_DEMO + bool "enable apps/iris ml demo" + default n diff --git a/APP_Framework/Applications/knowing_app/iris_ml_demo/SConscript b/APP_Framework/Applications/knowing_app/iris_ml_demo/SConscript new file mode 100644 index 00000000..ef62e745 --- /dev/null +++ b/APP_Framework/Applications/knowing_app/iris_ml_demo/SConscript @@ -0,0 +1,9 @@ +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') + Glob('*.cpp') +CPPPATH = [cwd] + +group = DefineGroup('Applications', src, depend = ['IRIS_ML_DEMO'], LOCAL_CPPPATH = CPPPATH) + +Return('group') diff --git a/APP_Framework/Applications/knowing_app/iris_ml_demo/SVCModel.h b/APP_Framework/Applications/knowing_app/iris_ml_demo/SVCModel.h new file mode 100644 index 00000000..6bf3e1a3 --- /dev/null +++ b/APP_Framework/Applications/knowing_app/iris_ml_demo/SVCModel.h @@ -0,0 +1,78 @@ +/** + * SVC model trained by iris dataset + */ +#include + +/** + * Compute kernel between feature vector and support vector. + * Kernel type: linear + */ +float compute_kernel(float *x, ...) +{ + va_list w; + va_start(w, 4); + float kernel = 0.0; + + for (int i = 0; i < 4; i++) { + kernel += x[i] * va_arg(w, double); + } + + return kernel; +} + +/** + * Predict class for features vector + */ +int predict(float *x) +{ + float kernels[27] = {0}; + float decisions[3] = {0}; + int votes[3] = {0}; + kernels[0] = compute_kernel(x, 5.1, 3.3, 1.7, 0.5); + kernels[1] = compute_kernel(x, 4.8, 3.4, 1.9, 0.2); + kernels[2] = compute_kernel(x, 4.5, 2.3, 1.3, 0.3); + kernels[3] = compute_kernel(x, 6.9, 3.1, 4.9, 1.5); + kernels[4] = compute_kernel(x, 6.3, 3.3, 4.7, 1.6); + kernels[5] = compute_kernel(x, 6.1, 2.9, 4.7, 1.4); + kernels[6] = compute_kernel(x, 5.6, 3.0, 4.5, 1.5); + kernels[7] = compute_kernel(x, 6.2, 2.2, 4.5, 1.5); + kernels[8] = compute_kernel(x, 5.9, 3.2, 4.8, 1.8); + kernels[9] = compute_kernel(x, 6.3, 2.5, 4.9, 1.5); + kernels[10] = compute_kernel(x, 6.8, 2.8, 4.8, 1.4); + kernels[11] = compute_kernel(x, 6.7, 3.0, 5.0, 1.7); + kernels[12] = compute_kernel(x, 6.0, 2.7, 5.1, 1.6); + kernels[13] = compute_kernel(x, 5.4, 3.0, 4.5, 1.5); + kernels[14] = compute_kernel(x, 5.1, 2.5, 3.0, 1.1); + kernels[15] = compute_kernel(x, 4.9, 2.5, 4.5, 1.7); + kernels[16] = compute_kernel(x, 6.5, 3.2, 5.1, 2.0); + kernels[17] = compute_kernel(x, 6.0, 2.2, 5.0, 1.5); + kernels[18] = compute_kernel(x, 6.3, 2.7, 4.9, 1.8); + kernels[19] = compute_kernel(x, 6.2, 2.8, 4.8, 1.8); + kernels[20] = compute_kernel(x, 6.1, 3.0, 4.9, 1.8); + kernels[21] = compute_kernel(x, 7.2, 3.0, 5.8, 1.6); + kernels[22] = compute_kernel(x, 6.3, 2.8, 5.1, 1.5); + kernels[23] = compute_kernel(x, 6.0, 3.0, 4.8, 1.8); + kernels[24] = compute_kernel(x, 6.3, 2.5, 5.0, 1.9); + kernels[25] = compute_kernel(x, 6.5, 3.0, 5.2, 2.0); + kernels[26] = compute_kernel(x, 5.9, 3.0, 5.1, 1.8); + decisions[0] = 1.452844496978 + kernels[0] * 0.67075289031 + kernels[2] * 0.077097563476 + kernels[14] * -0.747850453786; + decisions[1] = 1.507713125178 + kernels[0] * 0.043820415076 + kernels[1] * 0.159872086718 + kernels[15] * -0.203692501794; + decisions[2] = 6.78097118511 + kernels[3] + kernels[4] + kernels[5] + kernels[6] + kernels[7] + kernels[8] + kernels[9] + + kernels[10] * 0.243261886421 + kernels[11] + kernels[12] + kernels[13] - kernels[15] - kernels[16] - + kernels[17] - kernels[18] - kernels[19] - kernels[20] + kernels[21] * -0.437859817863 - kernels[22] - + kernels[23] + kernels[24] * -0.645105347981 + kernels[25] * -0.160296720576 - kernels[26]; + votes[decisions[0] > 0 ? 0 : 1] += 1; + votes[decisions[1] > 0 ? 0 : 2] += 1; + votes[decisions[2] > 0 ? 1 : 2] += 1; + int val = votes[0]; + int idx = 0; + + for (int i = 1; i < 3; i++) { + if (votes[i] > val) { + val = votes[i]; + idx = i; + } + } + + return idx; +} diff --git a/APP_Framework/Applications/knowing_app/iris_ml_demo/iris.csv b/APP_Framework/Applications/knowing_app/iris_ml_demo/iris.csv new file mode 100644 index 00000000..3852bddd --- /dev/null +++ b/APP_Framework/Applications/knowing_app/iris_ml_demo/iris.csv @@ -0,0 +1,7 @@ +5.1,3.5,1.4,0.2 +6.4,3.2,4.5,1.5 +5.8,2.7,5.1,1.9 +7.7,3.8,6.7,2.2 +5.5,2.6,4.4,1.2 +5.1,3.8,1.9,0.4 +5.8,2.7,3.9,1.2 \ No newline at end of file diff --git a/APP_Framework/Applications/knowing_app/iris_ml_demo/iris_ml_demo.c b/APP_Framework/Applications/knowing_app/iris_ml_demo/iris_ml_demo.c new file mode 100644 index 00000000..0e3eca40 --- /dev/null +++ b/APP_Framework/Applications/knowing_app/iris_ml_demo/iris_ml_demo.c @@ -0,0 +1,59 @@ +#include +#include + +#include "SVCModel.h" + +#define FEATURE_NUM 4 +#define CSV_PATH "/csv/iris.csv" +#define CSV_BUFFER_SIZE (1 * 1024) + +static float data[10][FEATURE_NUM] = {}; +static int data_len = 0; + +void simple_CSV_read() +{ + int fin; + int col = 0; + char buffer[CSV_BUFFER_SIZE] = ""; + char *tmp = ""; + char *delim = ",\n "; + + fin = open(CSV_PATH, O_RDONLY); + if (!fin) { + printf("Error open file %s", CSV_PATH); + exit(-1); + } + read(fin, buffer, sizeof(buffer)); + close(fin); + + data_len = 0; + for (tmp = strtok(buffer, delim); tmp && *tmp; col++, tmp = strtok(NULL, delim)) { + if (0 == col % FEATURE_NUM) { + // printf("\n"); + data_len++; + col = 0; + } + data[data_len - 1][col] = atof(tmp); + // printf("%.4f ", data[data_len - 1][col]); + } + // printf("\n"); +} + +void iris_SVC_predict() +{ + int result; + + simple_CSV_read(); + + for (int i = 0; i < data_len; i++) { + result = predict(data[i]); + printf("data %d: ", i + 1); + for (int j = 0; j < FEATURE_NUM; j++) { + printf("%.4f ", data[i][j]); + } + printf("result: %d\n", result); + } +} +#ifdef __RT_THREAD_H__ +MSH_CMD_EXPORT(iris_SVC_predict, iris predict by SVC); +#endif diff --git a/Ubiquitous/RT_Thread/bsp/stm32f407-atk-coreboard/.config b/Ubiquitous/RT_Thread/bsp/stm32f407-atk-coreboard/.config index 9ce8277a..f4caa0c5 100644 --- a/Ubiquitous/RT_Thread/bsp/stm32f407-atk-coreboard/.config +++ b/Ubiquitous/RT_Thread/bsp/stm32f407-atk-coreboard/.config @@ -356,6 +356,7 @@ CONFIG_MAIN_KTASK_STACK_SIZE=1024 # # knowing app # +CONFIG_IRIS_ML_DEMO=y # # sensor app @@ -378,10 +379,13 @@ CONFIG_SUPPORT_SENSOR_FRAMEWORK=y # CONFIG_SUPPORT_CONNECTION_FRAMEWORK is not set CONFIG_SUPPORT_KNOWING_FRAMEWORK=y # CONFIG_USING_TENSORFLOWLITEMICRO is not set +CONFIG_USING_KPU_POSTPROCESSING=y +# CONFIG_USING_YOLOV2 is not set # CONFIG_SUPPORT_CONTROL_FRAMEWORK is not set # -# app lib +# lib # CONFIG_APP_SELECT_NEWLIB=y # CONFIG_APP_SELECT_OTHER_LIB is not set +# CONFIG_LIB_USING_CJSON is not set diff --git a/Ubiquitous/RT_Thread/bsp/stm32f407-atk-coreboard/.gitignore b/Ubiquitous/RT_Thread/bsp/stm32f407-atk-coreboard/.gitignore index 3495bbcc..331082a3 100644 --- a/Ubiquitous/RT_Thread/bsp/stm32f407-atk-coreboard/.gitignore +++ b/Ubiquitous/RT_Thread/bsp/stm32f407-atk-coreboard/.gitignore @@ -1,30 +1,19 @@ -*.pyc +# this *.map *.dblite -*.elf *.bin -*.hex *.axf -*.exe -*.pdb -*.idb -*.ilk *.old *~ *.o -*.obj -*.out *.bak *.dep -*.lib *.i *.d -.DS_Stor* *.uimg GPATH GRTAGS GTAGS -.vscode JLinkLog.txt JLinkSettings.ini DebugConfig/ @@ -32,3 +21,223 @@ RTE/ settings/ *.uvguix* cconfig.h + +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.con diff --git a/Ubiquitous/RT_Thread/bsp/stm32f407-atk-coreboard/rtconfig.h b/Ubiquitous/RT_Thread/bsp/stm32f407-atk-coreboard/rtconfig.h index 65885fbe..4dfc486d 100644 --- a/Ubiquitous/RT_Thread/bsp/stm32f407-atk-coreboard/rtconfig.h +++ b/Ubiquitous/RT_Thread/bsp/stm32f407-atk-coreboard/rtconfig.h @@ -201,6 +201,8 @@ /* knowing app */ +#define IRIS_ML_DEMO + /* sensor app */ @@ -210,8 +212,9 @@ #define ADD_XIUOS_FETURES #define SUPPORT_SENSOR_FRAMEWORK #define SUPPORT_KNOWING_FRAMEWORK +#define USING_KPU_POSTPROCESSING -/* app lib */ +/* lib */ #define APP_SELECT_NEWLIB diff --git a/Ubiquitous/RT_Thread/bsp/stm32f407-atk-coreboard/rtconfig.py b/Ubiquitous/RT_Thread/bsp/stm32f407-atk-coreboard/rtconfig.py index 5ecc68cf..1e094c54 100644 --- a/Ubiquitous/RT_Thread/bsp/stm32f407-atk-coreboard/rtconfig.py +++ b/Ubiquitous/RT_Thread/bsp/stm32f407-atk-coreboard/rtconfig.py @@ -17,7 +17,7 @@ if os.getenv('RTT_ROOT'): # EXEC_PATH is the compiler execute path, for example, CodeSourcery, Keil MDK, IAR if CROSS_TOOL == 'gcc': PLATFORM = 'gcc' - EXEC_PATH = r'/usr/local/Cellar/gcc-arm-none-eabi/20180627/bin' + EXEC_PATH = r'/opt/gcc-arm-none-eabi-7-2018-q2-update/bin' elif CROSS_TOOL == 'keil': PLATFORM = 'armcc' EXEC_PATH = r'C:/Keil_v5' From be3b3b8016e838722bafeb10a3d8d718ca432ce0 Mon Sep 17 00:00:00 2001 From: yangtuo250 <506680965@qq.com> Date: Wed, 11 Aug 2021 17:07:26 +0800 Subject: [PATCH 09/18] feat(knowing app): add stm32f4 iris decision tree classifier demo --- .../DecisionTreeClassifierModel.h | 57 +++++++++++++++++++ .../knowing_app/iris_ml_demo/iris_ml_demo.c | 23 +++++++- 2 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 APP_Framework/Applications/knowing_app/iris_ml_demo/DecisionTreeClassifierModel.h diff --git a/APP_Framework/Applications/knowing_app/iris_ml_demo/DecisionTreeClassifierModel.h b/APP_Framework/Applications/knowing_app/iris_ml_demo/DecisionTreeClassifierModel.h new file mode 100644 index 00000000..0fbf39d5 --- /dev/null +++ b/APP_Framework/Applications/knowing_app/iris_ml_demo/DecisionTreeClassifierModel.h @@ -0,0 +1,57 @@ +#include + +/** + * Predict class for features vector + */ +int predict(float *x) +{ + if (x[2] <= 2.449999988079071) { + return 0; + } + + else { + if (x[3] <= 1.75) { + if (x[2] <= 4.950000047683716) { + if (x[3] <= 1.6500000357627869) { + return 1; + } + + else { + return 2; + } + } + + else { + if (x[3] <= 1.550000011920929) { + return 2; + } + + else { + if (x[2] <= 5.450000047683716) { + return 1; + } + + else { + return 2; + } + } + } + } + + else { + if (x[2] <= 4.8500001430511475) { + if (x[1] <= 3.100000023841858) { + return 2; + } + + else { + return 1; + } + } + + else { + return 2; + } + } + } +} diff --git a/APP_Framework/Applications/knowing_app/iris_ml_demo/iris_ml_demo.c b/APP_Framework/Applications/knowing_app/iris_ml_demo/iris_ml_demo.c index 0e3eca40..d901f18c 100644 --- a/APP_Framework/Applications/knowing_app/iris_ml_demo/iris_ml_demo.c +++ b/APP_Framework/Applications/knowing_app/iris_ml_demo/iris_ml_demo.c @@ -1,8 +1,6 @@ #include #include -#include "SVCModel.h" - #define FEATURE_NUM 4 #define CSV_PATH "/csv/iris.csv" #define CSV_BUFFER_SIZE (1 * 1024) @@ -41,6 +39,7 @@ void simple_CSV_read() void iris_SVC_predict() { +#include "SVCModel.h" int result; simple_CSV_read(); @@ -57,3 +56,23 @@ void iris_SVC_predict() #ifdef __RT_THREAD_H__ MSH_CMD_EXPORT(iris_SVC_predict, iris predict by SVC); #endif + +void iris_DecisonTree_predict() +{ +#include "DecisionTreeClassifierModel.h" + int result; + + simple_CSV_read(); + + for (int i = 0; i < data_len; i++) { + result = predict(data[i]); + printf("data %d: ", i + 1); + for (int j = 0; j < FEATURE_NUM; j++) { + printf("%.4f ", data[i][j]); + } + printf("result: %d\n", result); + } +} +#ifdef __RT_THREAD_H__ +MSH_CMD_EXPORT(iris_DecisonTree_predict, iris predict by decison tree classifier); +#endif From b9d10a7cf17d068874b7410a1cfc58185d4049ed Mon Sep 17 00:00:00 2001 From: yangtuo250 <506680965@qq.com> Date: Thu, 12 Aug 2021 00:02:10 +0800 Subject: [PATCH 10/18] feat(knowing app): stm32f4 logistic regression iris demo --- .../iris_ml_demo/LogisticRegressionModel.h | 41 +++++++++++++++++++ .../knowing_app/iris_ml_demo/iris_ml_demo.c | 20 +++++++++ 2 files changed, 61 insertions(+) create mode 100644 APP_Framework/Applications/knowing_app/iris_ml_demo/LogisticRegressionModel.h diff --git a/APP_Framework/Applications/knowing_app/iris_ml_demo/LogisticRegressionModel.h b/APP_Framework/Applications/knowing_app/iris_ml_demo/LogisticRegressionModel.h new file mode 100644 index 00000000..6d7bbfa5 --- /dev/null +++ b/APP_Framework/Applications/knowing_app/iris_ml_demo/LogisticRegressionModel.h @@ -0,0 +1,41 @@ +#include + +/** + * Compute dot product + */ +float dot(float *x, ...) +{ + va_list w; + va_start(w, 4); + float dot = 0.0; + + for (int i = 0; i < 4; i++) { + const float wi = va_arg(w, double); + dot += x[i] * wi; + } + + return dot; +} + +/** + * Predict class for features vector + */ +int predict(float *x) +{ + float votes[3] = {0.0f}; + votes[0] = dot(x, -0.423405592418, 0.967388282125, -2.517050233286, -1.079182996654) + 9.84868307535428; + votes[1] = dot(x, 0.534517184386, -0.321908835083, -0.206465997471, -0.944448257908) + 2.238120068472271; + votes[2] = dot(x, -0.111111591968, -0.645479447042, 2.723516230758, 2.023631254562) + -12.086803143826813; + // return argmax of votes + int classIdx = 0; + float maxVotes = votes[0]; + + for (int i = 1; i < 3; i++) { + if (votes[i] > maxVotes) { + classIdx = i; + maxVotes = votes[i]; + } + } + + return classIdx; +} \ No newline at end of file diff --git a/APP_Framework/Applications/knowing_app/iris_ml_demo/iris_ml_demo.c b/APP_Framework/Applications/knowing_app/iris_ml_demo/iris_ml_demo.c index d901f18c..001af67e 100644 --- a/APP_Framework/Applications/knowing_app/iris_ml_demo/iris_ml_demo.c +++ b/APP_Framework/Applications/knowing_app/iris_ml_demo/iris_ml_demo.c @@ -76,3 +76,23 @@ void iris_DecisonTree_predict() #ifdef __RT_THREAD_H__ MSH_CMD_EXPORT(iris_DecisonTree_predict, iris predict by decison tree classifier); #endif + +void iris_LogisticRegression_predict() +{ +#include "LogisticRegressionModel.h" + int result; + + simple_CSV_read(); + + for (int i = 0; i < data_len; i++) { + result = predict(data[i]); + printf("data %d: ", i + 1); + for (int j = 0; j < FEATURE_NUM; j++) { + printf("%.4f ", data[i][j]); + } + printf("result: %d\n", result); + } +} +#ifdef __RT_THREAD_H__ +MSH_CMD_EXPORT(iris_LogisticRegression_predict, iris predict by logistic regression); +#endif From 6ad0b192e8e2be8260c5b2bb6c4367352fe33261 Mon Sep 17 00:00:00 2001 From: chunyexixiaoyu <834670833@qq.com> Date: Fri, 13 Aug 2021 14:29:35 +0800 Subject: [PATCH 11/18] Ubiquitous/RT_Thread/: add a interface about k210 dvp image setting. --- .../RT_Thread/bsp/k210/base-drivers/drv_dvp.c | 3 +-- .../drivers/ov2640/ov2640_source/drv_ov2640.c | 17 ++++++++++++++--- .../drivers/ov2640/ov2640_source/drv_ov2640.h | 14 +++++++++++--- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/Ubiquitous/RT_Thread/bsp/k210/base-drivers/drv_dvp.c b/Ubiquitous/RT_Thread/bsp/k210/base-drivers/drv_dvp.c index 41cd834e..6aad225c 100644 --- a/Ubiquitous/RT_Thread/bsp/k210/base-drivers/drv_dvp.c +++ b/Ubiquitous/RT_Thread/bsp/k210/base-drivers/drv_dvp.c @@ -67,8 +67,7 @@ static rt_err_t rt_dvp_init(rt_device_t dev) dvp_set_output_enable(0, 1); dvp_set_output_enable(1, 1); dvp_set_image_format(DVP_CFG_RGB_FORMAT);//////////////// - // dvp_set_image_size(320, 240); - dvp_set_image_size(256, 256); + dvp_set_image_size(320, 240); // default dvp_config_interrupt(DVP_CFG_FINISH_INT_ENABLE, 0); dvp_disable_auto(); plic_set_priority(IRQN_DVP_INTERRUPT, 1); diff --git a/Ubiquitous/RT_Thread/drivers/ov2640/ov2640_source/drv_ov2640.c b/Ubiquitous/RT_Thread/drivers/ov2640/ov2640_source/drv_ov2640.c index de8aa1f6..d694db7a 100644 --- a/Ubiquitous/RT_Thread/drivers/ov2640/ov2640_source/drv_ov2640.c +++ b/Ubiquitous/RT_Thread/drivers/ov2640/ov2640_source/drv_ov2640.c @@ -1467,20 +1467,31 @@ static rt_err_t rt_ov2640_control(rt_device_t dev, int cmd, void *args) { RT_ASSERT(dev != RT_NULL); rt_err_t ret = RT_EOK; - if(cmd < IOCTRL_CAMERA_START_SHOT || cmd > IOCTRL_CAMERA_SET_EXPOSURE) + if(cmd < IOCTRL_CAMERA_SET_DVP_RESO || cmd > IOCTRL_CAMERA_SET_EXPOSURE) { LOG_E("CMD value should be 22 ~29"); return RT_ERROR; - } + } + int value = 0; _ioctl_shoot_para shoot_para = {0}; - + #ifdef BOARD_K210_EVB + _ioctl_set_dvp_reso set_dvp_reso = {0}; + #endif if(IOCTRL_CAMERA_START_SHOT == cmd) { shoot_para = *((_ioctl_shoot_para*)args); ret = rt_ov2640_start_shoot(shoot_para.pdata,shoot_para.length); return ret; } + #ifdef BOARD_K210_EVB + else if(IOCTRL_CAMERA_SET_DVP_RESO == cmd) + { + set_dvp_reso =*((_ioctl_set_dvp_reso*)args); + dvp_set_image_size(set_dvp_reso.width, set_dvp_reso.height); + return RT_EOK; + } + #endif else { value = *((int*)args); diff --git a/Ubiquitous/RT_Thread/drivers/ov2640/ov2640_source/drv_ov2640.h b/Ubiquitous/RT_Thread/drivers/ov2640/ov2640_source/drv_ov2640.h index a6d0934f..573b1f4a 100644 --- a/Ubiquitous/RT_Thread/drivers/ov2640/ov2640_source/drv_ov2640.h +++ b/Ubiquitous/RT_Thread/drivers/ov2640/ov2640_source/drv_ov2640.h @@ -123,9 +123,9 @@ extern "C" { #define OV2640_SENSOR_HISTO_LOW 0x61 #define OV2640_SENSOR_HISTO_HIGH 0x62 - - - +#ifdef BOARD_K210_EVB +#define IOCTRL_CAMERA_SET_DVP_RESO (21) // set dev resolution +#endif #define IOCTRL_CAMERA_START_SHOT (22) // start shoot #define IOCTRL_CAMERA_SET_RESO (23) //set resolution @@ -136,6 +136,14 @@ extern "C" { #define IOCTRL_CAMERA_SET_EFFECT (28) //set effect #define IOCTRL_CAMERA_SET_EXPOSURE (29) //set auto exposure +#ifdef BOARD_K210_EVB +typedef struct +{ + uint32_t width; // width The width of image + uint32_t height; // height The height of image +}_ioctl_set_dvp_reso; +#endif + struct camera_device { From 9a555bc8b503d902ef31088d119e9051531bd52c Mon Sep 17 00:00:00 2001 From: yangtuo250 <506680965@qq.com> Date: Thu, 12 Aug 2021 17:10:04 +0800 Subject: [PATCH 12/18] docs(knowing app): add README for iris_ml_demo --- .../knowing_app/iris_ml_demo/README.md | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 APP_Framework/Applications/knowing_app/iris_ml_demo/README.md diff --git a/APP_Framework/Applications/knowing_app/iris_ml_demo/README.md b/APP_Framework/Applications/knowing_app/iris_ml_demo/README.md new file mode 100644 index 00000000..4ad3c1ef --- /dev/null +++ b/APP_Framework/Applications/knowing_app/iris_ml_demo/README.md @@ -0,0 +1,71 @@ +# Machine learning demo using iris dataset + +### Classification task demo, tested on stm32f4 and k210-based edge devices. Training on iris dataset by *Decision Tree classifier*, *Support Vector Machine classifier* and *Logistic Regression classifier*. + +--- + +## Training + +Model generated by [Sklearn](https://scikit-learn.org/stable/) and converted to C language by [micromlgen](https://forgeplus.trustie.net/projects/yangtuo250/micromlgen). + +### Enviroment preparation + +```shell +pip install scikit-learn +git clone https://git.trustie.net/yangtuo250/micromlgen.git -b C +cd micromlgen && pip install -e . +``` + +### Train it! + +```python +# load iris dataset +from sklearn.datasets import load_iris +X, y = load_iris(return_X_y=True) + +# train SVC classifier and convert +clf = SVC(kernel='linear', gamma=0.001).fit(X, y) +print(port(clf, cplusplus=False, platform=platforms.STM32F4)) + +# train logistic regression classifier and convert +clf = LogisticRegression(max_iter=1000).fit(X, y) +print(port(clf, cplusplus=False, platform=platforms.STM32F4)) + +# train decision tree classifier and convert +clf = DecisionTreeClassifier().fit(X, y) +print(port(clf, cplusplus=False, platform=platforms.STM32F4) +``` +Copy each content generated by print to a single C language file. + +--- + +## Deployment + +### compile and burn + +Use `(scons --)menuconfig` in *bsp folder(Ubiquitous/RT_Thread/bsp/k210(or stm32f407-atk-coreboard))*, open **APP_Framwork --> Applications --> knowing app --> enable apps/iris ml demo** to enable this app. `scons -j(n)` to compile and burn in by *st-flash(for ARM)* or *kflash(for k210)*. + +### testing set + +Copy *iris.csv* to SD card */csv/iris.csv*. + +--- + +## Run + +In serial terminal: +- `iris_SVC_predict` for SVC prediction +- `iris_DecisonTree_predict` for decision tree prediction +- `iris_LogisticRegression_predict` for logistic regression prediction + +Example output: + +```shell +data 1: 5.1000 3.5000 1.4000 0.2000 result: 0 +data 2: 6.4000 3.2000 4.5000 1.5000 result: 1 +data 3: 5.8000 2.7000 5.1000 1.9000 result: 2 +data 4: 7.7000 3.8000 6.7000 2.2000 result: 2 +data 5: 5.5000 2.6000 4.4000 1.2000 result: 1 +data 6: 5.1000 3.8000 1.9000 0.4000 result: 0 +data 7: 5.8000 2.7000 3.9000 1.2000 result: 1 +``` From fc825ea557e25292f8534654a6a86979270e70c8 Mon Sep 17 00:00:00 2001 From: yangtuo250 <506680965@qq.com> Date: Thu, 12 Aug 2021 20:55:53 +0800 Subject: [PATCH 13/18] docs(knowing app): add README for helmet detect --- .../knowing_app/helmet_detect/README.md | 167 ++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 APP_Framework/Applications/knowing_app/helmet_detect/README.md diff --git a/APP_Framework/Applications/knowing_app/helmet_detect/README.md b/APP_Framework/Applications/knowing_app/helmet_detect/README.md new file mode 100644 index 00000000..006427ed --- /dev/null +++ b/APP_Framework/Applications/knowing_app/helmet_detect/README.md @@ -0,0 +1,167 @@ +# Helmet detection demo + +### A helmet and head without helmet object detection task demo. Running MobileNet-yolo on K210-based edge devices. + +--- + +## Training + +### Enviroment preparation + +Model generated by [aXeleRate](https://forgeplus.trustie.net/projects/yangtuo250/aXeleRate) and converted to kmodel by [nncase](https://github.com/kendryte/nncase/tree/v0.1.0-rc5). + +```shell +# master branch for MobileNetv1-yolov2 and unstable branch to test MobileNetv1(v2)-yolov2(v3) +git clone https://git.trustie.net/yangtuo250/aXeleRate.git (-b unstable) +cd aXeleRate +pip install -r requirments.txt && pip install -e . +``` + +### training config setting + +Example [config](https://forgeplus.trustie.net/projects/yangtuo250/aXeleRate/tree/master/configs/detector.json), some hyper-parameters: + +- architecture: backbone, MobileNet7_5 for default, MobileNet1_0(α = 1.0) and above cannot run on K210 because of OOM on feature map in master branch. For unstable branch MobileNetV2_1_0 is OK. + +- input_size: fixed model input size, single integer for height equals to width, otherwise a list([height, width]). +- anchors: yolov2 anchor(for master) or anchor scaled to 1.0(for unstable), can be generate by [darknet](https://github.com/AlexeyAB/darknet). +- labels: labels of all classes. +- train(valid)_image(annot)_folder: path of images and annoations for training and validation. +- saved_folder: path for trainig result storage(models, checkpoints, logs ...). + +Mine config for unstable: +```json +{ + "model": { + "type": "Detector", + "architecture": "MobileNetV2_1_0", + "input_size": [ + 224, + 320 + ], + "anchors": [ + [ + [ + 0.1043, + 0.1560 + ], + [ + 0.0839, + 0.3036 + ], + [ + 0.1109, + 0.3923 + ], + [ + 0.1378, + 0.5244 + ], + [ + 0.2049, + 0.6673 + ] + ] + ], + "labels": [ + "human" + ], + "obj_thresh": 0.5, + "iou_thresh": 0.45, + "coord_scale": 1.0, + "class_scale": 0.0, + "object_scale": 5.0, + "no_object_scale": 3.0 + }, + "weights": { + "full": "", + "backend": "" + }, + "train": { + "actual_epoch": 2000, + "train_image_folder": "mydata/human/Images/train", + "train_annot_folder": "mydata/human/Annotations/train", + "train_times": 2, + "valid_image_folder": "mydata/human/Images/val", + "valid_annot_folder": "mydata/human/Annotations/val", + "valid_times": 1, + "valid_metric": "precision", + "batch_size": 32, + "learning_rate": 2e-5, + "saved_folder": "mydata/human/results", + "first_trainable_layer": "", + "augmentation": true, + "is_only_detect": false, + "validation_freq": 5, + "quantize": false, + "class_weights": [1.0] + }, + "converter": { + "type": [ + "k210" + ] + } +} +``` + +*(For more detailed config usage, please refer to original aXeleRate repo.)* + +### data preparation + +Please refer to [VOC format](https://towardsdatascience.com/coco-data-format-for-object-detection-a4c5eaf518c5), path as config above. + +### train it! + +```shell +python -m aXeleRate.train -c PATH_TO_YOUR_CONFIG +``` + +### model convert + +Please refer to [nncase repo](https://github.com/kendryte/nncase/tree/v0.1.0-rc5). + +--- + +## Deployment + +### compile and burn + +Use `(scons --)menuconfig` in bsp folder *(Ubiquitous/RT_Thread/bsp/k210)*, open: + +- More Drivers --> ov2640 driver +- Board Drivers Config --> Enable LCD on SPI0 +- Board Drivers Config --> Enable SDCARD (spi1(ss0)) +- Board Drivers Config --> Enable DVP(camera) +- RT-Thread Components --> POSIX layer and C standard library --> Enable pthreads APIs +- APP_Framework --> Framework --> support knowing framework --> kpu model postprocessing --> yolov2 region layer +- APP_Framework --> Applications --> knowing app --> enable apps/helmet detect + +`scons -j(n)` to compile and burn in by *kflash*. + +### json config and kmodel + +Copy json config for deployment o SD card */kmodel*. Example config file is *helmet.json* in this directory. Something to be modified: + +- net_input_size: same as *input_size* in training config file, but array only. +- net_output_shape: final feature map size, can be found in **nncase** output. +- sensor_output_size: image height and width from camera, same as *dvp_set_image_size(Ubiquitous/RT_Thread/bsp/k210/base-drivers/drv_dvp.c L70(71))*. +- kmodel_size: kmodel size shown in file system. +- anchors: same as *anchor* in training config file(multi-dimention anchors flatten to 1 dim). +- labels: same as *label* in training config file. +- obj_thresh: array, object threshold of each label. +- nms_thresh: NMS threshold of boxes. + +Copy final kmodel to SD card */kmodel* either. + +--- + +## Run + +In serial terminal, `helmet_detect` to start a detection thread, `helmet_detect_delete` to stop it. Detection results can be found in output. + +--- + +## TODO + +- [ ] Fix LCD real-time result display. +- [ ] Test more object detection backbone and algorithm(like yolox). From 5b785b01053ba37df3a9b69616a4e54e1759ef98 Mon Sep 17 00:00:00 2001 From: yangtuo250 <506680965@qq.com> Date: Fri, 13 Aug 2021 10:28:48 +0800 Subject: [PATCH 14/18] docs(knowing app): add README for instrusion detect --- .../Applications/knowing_app/instrusion_detect/README.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 APP_Framework/Applications/knowing_app/instrusion_detect/README.md diff --git a/APP_Framework/Applications/knowing_app/instrusion_detect/README.md b/APP_Framework/Applications/knowing_app/instrusion_detect/README.md new file mode 100644 index 00000000..61b89af5 --- /dev/null +++ b/APP_Framework/Applications/knowing_app/instrusion_detect/README.md @@ -0,0 +1,5 @@ +# Instrusion detect demo + +### A human object detection task demo. Running MobileNet-yolo on K210-based edge devices. + +***Training, deployment and running, please see helmet_detect*** \ No newline at end of file From 5786b7dffc8dcdf65ceb690c026fe450c59b2cff Mon Sep 17 00:00:00 2001 From: yangtuo250 <506680965@qq.com> Date: Fri, 13 Aug 2021 11:01:46 +0800 Subject: [PATCH 15/18] docs(knowing app): add README for face detect --- .../knowing_app/face_detect/README.md | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 APP_Framework/Applications/knowing_app/face_detect/README.md diff --git a/APP_Framework/Applications/knowing_app/face_detect/README.md b/APP_Framework/Applications/knowing_app/face_detect/README.md new file mode 100644 index 00000000..4e2d36b0 --- /dev/null +++ b/APP_Framework/Applications/knowing_app/face_detect/README.md @@ -0,0 +1,35 @@ +# Face detection demo + +### A face object detection task demo. Running MobileNet-yolo on K210-based edge devices. + +--- + +## Training + +kmodel from [GitHub](https://github.com/kendryte/kendryte-standalone-demo/blob/develop/face_detect/detect.kmodel). + +## Deployment + +### compile and burn + +Use `(scons --)menuconfig` in bsp folder *(Ubiquitous/RT_Thread/bsp/k210)*, open: + +- More Drivers --> ov2640 driver +- Board Drivers Config --> Enable LCD on SPI0 +- Board Drivers Config --> Enable SDCARD (spi1(ss0)) +- Board Drivers Config --> Enable DVP(camera) +- RT-Thread Components --> POSIX layer and C standard library --> Enable pthreads APIs +- APP_Framework --> Framework --> support knowing framework --> kpu model postprocessing --> yolov2 region layer +- APP_Framework --> Applications --> knowing app --> enable apps/face detect + +`scons -j(n)` to compile and burn in by *kflash*. + +### json config and kmodel + +Copy json config for deployment o SD card */kmodel*. Example config file is *detect.json* in this directory. Copy final kmodel to SD card */kmodel* either. + +--- + +## Run + +In serial terminal, `face_detect` to start a detection thread, `face_detect_delete` to stop it. Detection results can be found in output. From 4c1580fab2dc2e68f86d99f149ba5f6d71a3dbb4 Mon Sep 17 00:00:00 2001 From: yangtuo250 <506680965@qq.com> Date: Fri, 13 Aug 2021 11:10:32 +0800 Subject: [PATCH 16/18] docs(knowing framework): add README for YOLOv2 region layer --- .../knowing/kpu-postprocessing/yolov2/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 APP_Framework/Framework/knowing/kpu-postprocessing/yolov2/README.md diff --git a/APP_Framework/Framework/knowing/kpu-postprocessing/yolov2/README.md b/APP_Framework/Framework/knowing/kpu-postprocessing/yolov2/README.md new file mode 100644 index 00000000..e37cab69 --- /dev/null +++ b/APP_Framework/Framework/knowing/kpu-postprocessing/yolov2/README.md @@ -0,0 +1,10 @@ +# KPU(K210) YOLOv2 region layer + +## Introduction + +KPU(k210) accelerate most of CNN network layers, but do not support some of operators of YOLOv2 region layer. Such layers and operators will run on MCU instead. +YOLOv2 region layer accept feature map(shape w\*h\*c) and return final detection boxes. + +## Usage + +Use `(scons --)menuconfig` in bsp folder *(Ubiquitous/RT_Thread/bsp/k210)*, open *APP_Framework --> Framework --> support knowing framework --> kpu model postprocessing --> yolov2 region layer*. \ No newline at end of file From 8593dedd37adf3680516523c6bcf9cabb609d6f2 Mon Sep 17 00:00:00 2001 From: yangtuo250 <506680965@qq.com> Date: Fri, 13 Aug 2021 14:38:06 +0800 Subject: [PATCH 17/18] feat(knowing app): update json config and upload model for 3 k210 apps --- .../knowing_app/face_detect/detect.kmodel | Bin 0 -> 388776 bytes .../knowing_app/helmet_detect/helmet.json | 30 +++++++++--------- .../knowing_app/helmet_detect/helmet.kmodel | Bin 0 -> 2714044 bytes .../knowing_app/instrusion_detect/human.json | 24 +++++++------- .../instrusion_detect/human.kmodel | Bin 0 -> 2713236 bytes 5 files changed, 27 insertions(+), 27 deletions(-) create mode 100644 APP_Framework/Applications/knowing_app/face_detect/detect.kmodel create mode 100644 APP_Framework/Applications/knowing_app/helmet_detect/helmet.kmodel create mode 100644 APP_Framework/Applications/knowing_app/instrusion_detect/human.kmodel diff --git a/APP_Framework/Applications/knowing_app/face_detect/detect.kmodel b/APP_Framework/Applications/knowing_app/face_detect/detect.kmodel new file mode 100644 index 0000000000000000000000000000000000000000..f6134174be6251657c3f762efbc65cd217f19ce7 GIT binary patch literal 388776 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 za6%0ALnx@;&1Q6zrmvkO34Ff^r^&j<`tz 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%0DSoh0+fxYyDhSoI5(u#(kdp4RL7046>7S- z1CFTb4pp!J-_O=Q$EzQers*ba%0sPxi{dEt3-tbe!4d4b?`S&Mk8mr&`A0l8Uq}^SpSo!0N=A;{z%ooWd2||mjYb=5RyDwJ-<)tqQ8go$ZN~~TD@*x z?Ny*H(67Zr-G|lVUb1hwxB5GD=*P%a8^QiB=WB252m7&(hHqU8`V&(tvSm2FhFZSi zFz5?6uXtGp_|h2!SAf0c<}dyDIgpoi)@ND3aJ1f7{oQ%~EA?~N0Dfq!o2vS`pLn^x zc`dZ}y_uRvUITsOZMDBX0_`4ntd?4W`@dyy`Jw9XK=yFWW6y!U=~<-vrK-yGO#VdQEAKO1f9M$pmYxQ6H;2WU7Zu7F+_ktYx zyzc&2p#HtLts`~8-z^4w?{viYXH`=+^V~9k+t~&Hv903&r~eE2-{b$%^6H5s*BuYq`bMe1cxx(Tv5KMa ztTj8(7Vkwuf$WsgfetakZezjWH8mx-MKvUmcli6UsX#wIh`EOEP8yR;NRP*RsfCGb z+#?)+p={RBLSr(2uXDuEuMh6Sw7hX(_dYR3M9`6iMYeZ%Yo2}BFe{ywJo9e%nF8ON z!A4YBhz}3kJD&9xTF6a<%58xYI)AI*X-JVps?qHdqm#*|9+kL;+O-3cK8oag*uq8E?C{z7wG$#9Wc=2dDWQDtj#Pp3KS&2kt+W(y^vCU_ z7{iC6{ypuF_y+GWn%W0c(W{*r`8dImf}SwYg6e=Qbh%ABPkUh# zA}GsfyeO+_HSuOcf6BFzv(psI&JkssD?wVOacZkEcWkGyG=|cw!`4a=R-J1wpfsY^ z;}@E&7K_0ulW}KxQYB$}S)bWrS1WV2ZfzTC%euUQ0-+ANz`LjRTbu@;x-(?+s#rTi zd-@EtC2aJxK$RX6H6=QkD<9Bq#;1c0&4SUjs!^rU%a)D>Ne;!RzKJ`Sr|@ElIE5Q= zVX%L@1PL{IY`F1$c`@13&ufE24y*q@TvWCQ18S%Bj(r|;cGqLHn{(&q@hIae8oRm; zX1CElyO9XBg@SGStZUEplNxy@ZyeCsU5=Q4x-rSQ+xV8S&S2NHxXPg{9Wy<&|9OhM z>oB)yOPNqplRLlZmc|r8@m-dj)vbjT0NuK|upI~u#_}|$MF&{-trpD>zw9n$O6zB$ zjRnzA>2*k6%T_zReX}p?vL*wbem5pj@xZvgJA2fU-N`qUP|JW{>%{P=$-|I1lQb_e1EWqOZs)ZqWYKO^BO#AWIkBkZ8>CAY38Dx5IeuNzlfhKJ zCUaCP7|jN@vyi~eUA*jMbQl`l3wbl|Wx~yFwH3Fw+8b5E0iSSRz#$TJ2iHR@wQX*W zB0YD|T?J=1Fegvi^v;=8ras4L>#71aJ>AV;W@`uXv+b<~Ai0Ezov0=4fnt&K8*Jvy zU9ApHtX#Huce(Ab&x2NxSf@)$cXhetP!DPy5gsGWcCY9&0W*8ZnQ$q+jv&_cn2TuT zV)p)k*&jWvGxuHZV_c^>o5kfKG4+y9#2C{lX>Do$l*LLkgbup^7}S39k3XulhL3?nN;`4?OE?$HKy?h z0os9u{j7^;FlpHB&yCVuku;l(=si96Sf!{%OC&5rJVXU zP;b3pXL)PCVQjaFVM#(qdNJidpRp96AGM}MYl!pUDCeS;cEM&$<9R!sO^Zu36JsO0 zQ~S)gMeHW^EX|v=Ppf=_&)Q>2m_3@_t~e^ACYtqO97F0fUe3*FeD{ev%uY!~megwI z35Q2;YB^E#T2;ZwR+@M2F`kZznAsJceM;Ux0(jbriA7I zd-FiJo#=$P+!i|28)Bjv|G@AbT{OQCP$$+q$Sez63thp|qYxQy_Hn?c+7|24-DVm5 za??<|i^M%HmzCzx_Tsaa=#7E-Lvu{JU2Bdc?7jJBu50W3WvOoe+Q)cbFx>6H*B&+vb%q@5f(^5JLt>ONSZJr)9-sv)Do4RfPCIps z*VSUtTPa#{1G|UQM*5i^$fso^QLjDV-ypCwnIQc#HyOPDfC3FlwJO34TLAPmy5<&nX?$9!9`9Ld{wn zm;;jpi99YFVR$2GIU#uq;uQDs(baqW&&VHIEK$+gxk%haw0PIFSa(hbxBG`p{e8;G z9@H}9*f#IfpoabZpY6K6Wmo}S>ZyZ$G_Hl0Gz9s91_>QMedqz@;5_YR{(~f(cryg?Y^u*-iDh;+})mTK= zPm{&=^I@@DPg+LQ>tPSBejnlQ>F1Jc??u74=vi{)`?IEnS=P3C^7`pcbJGWs!IImo zHgVgEChLvCwl2}6k;9D3+k8lBvkc?T{+2y*)YnnAB#dpoU$eAtmw3d)ZRKI(V9Zju z(cRyU7rJ_kw22EkZfrLtbF5mg3_55_msNeA&ZJ%HpBp;tTaT2}{DRI>?B)dP-t_t) zFK^x1y@?D88@8zXi&_|b%yH$C(uND^b%B>!{^+H+k(XpkLhtQP{z=woW=0Jn=G874 zE%FA^KA@uddz~$bo2^uW^sTeI-EI^%Mh$2lno(nFhc_a0bFSBT&nA)8;}b5Ss6=hQ z^7;3i#0GjXXUZw$y)7GEp%FWe5{;hS-I9Sohc(0cUZcuywL1H_F6o}2a!>oT5lxbq zq>BiJi+;&1WD?H~8QF|rlW9^Ih#48J8+P-VE!q2whSM&-*J=W~AzZ2V3^=`Y*sios zB*sZ*GGj~GRI*>~a@#WJc;fM5=5^6a59q|bg_v=d$u_k;Wn|j1Mza_<(YTJ3EKOtufG1oi}dld1ZoBV-Y{oS@{pUrH? ziG4nY%hiYTCRT3sSe+({p>iR;*X9xIE|iz_e#aZ}U~#ASj=>&=WQ|PZsupf7De_4- zCZxkQ8nF`{sJdUUTa{K9Z6qC>jbcn_P%U^QrhT2Uwn?aoI83YCQ+7gX_kNRilw2Iq?d1Fotj!yu zZQeMRlsV?Ooe1uaX#G5#9ImlOM}54_&=)i_=_QYolw_Xs0}n}aQnb#g`7i?BKNGh$OhmdFwg7Xq< z@^W@>kJIWF7|F?@y%zXgu}f}3fbSVz^i_~Anc)e+CP)q&XO4@Ulht7GJ85AqXohd;Au1T&2C}^JMG4uM$t%VYz7(&MMct_ayqOI4W>2QEQI97ELbaL-A2zVi&~>?kbl6g>iBwRBcUnXRNPAYA}{36lY&Zn;!bSSS+Cf3sPlZGSDl>K4!B_5>CSS| zq7lOn`mDu>UMyidJN6rpA8$78)L6^Pf%-y4hBc_d=5nJ2SI_?3zM`leE-K}1#yGO8WTi7aWy(@k)=P5zUMa2V4 zhl*wq_Jr*eV9zpbQ#smngy7Lryq9vSfCg*W<j z1pXOWG+<;@8lgRL#?wQ(EH29^Cq!4rSzPT2eLJ`gb25D<22%2JU-#&S2JM*SRTnI7 zj~)i2ia$c|nrUa3#P$TV1jq9c;Vz5OYY0-fUd6cLyE3@b&H#!0&ds|!`j4{^qSI)9>cZ@9M_xZmW<}WjC?8~Z1X#d##E|rA>yREOX3@zake*36R@Se zW1DSzVokV@k{i4HoffM@u(f4{lg{jA!oAl?TqNDo->y)eF}L1D8r-hCqdhO-ow?48i*L-k z>89P3JgoEW@{mk4r1cwR=U9mGzzQ*!GU`~TdF=*QYwCV>@32|p@aA0v&aNSShTa`# znY@3B%H>J{`2ctCzV;2yVs|4$5uI31NAjE9{vqogy%&V%m#I+1>0 zf4LkEjCAb~y{pFL1DFus9qa8%t|RVsCQ^`rzBgf8B5?c zbVo9#iX^pUhg?YR3;32uX^?numBH-WNQRL%R38NfNA2E1G%c#T>{j5#NqWN0-mTt2 ztK5{^7B^Y>ZI)bWB3?MyCnZ|klRXy4p3eK?!}pV$vH88;SGRh5x9+tb97vp67Z_Bl za&F_se3!?v)Z3Khy}H{-`T_O(hP&)F8x3AZjKZ^JN7HxwKAUHJ*8snZgIV#JQKdy| zq7JqnpVZ@i)yBLw-q*Zu(6V(93wviGOb|6UPpdM<4y!V=hE!VzgVL3d1ZT{C)bVZD z+G$dT9Q~gAS--!3|J()jSJq_D`OW&0+auWglK0K>0C~vS3n5SHbK%{lQ^!0D2@^9G zX9=S{vgM%HcIaJiB16Tumam>`ogbl_(LuAxp-JtD$m{1s&g9?-EqY3_AWt7%y*oi@ zi8-m$z(<^KoRmo#l4%fZzOS#$_7k`e3=BvPtJ4@a#jQJl=am_DH_PZKjmhSKyg5#g zPBR{`_&ZDin3s46hQVwd0};0sO{rJ0T)DS<{^)_!ZK(`fOyEvi+5*Fi~~+th7Aqm0RdazUpUk?^D$g9NFN6(gFI zF?W}pQ^{s!pPKXVl-=q}>T?iWWe+hgfh$i=(pyd?LRQAZ%`b>NzO>hz$) z?GTh^k+51VZt%izOn|l72ZjkpNEa4Em}D`kQ8SJ*5~}yb`&h}Yk^Nzd=yNfBX_3`p z(14Q_^)A+J-<{(EW{aK8hU^7vTJ1+rhexC-i+upLs7#=KTpv}%R2n;<0zz(#-Ps2j z@FdPH}0#ueb@xq%5 z?sTeXx49=VX+I{@IwNhcE9sbVEN|{ohb_D@STdONkP?&S2sA;e>4;>xXzRu>3p>lP zcps}eGL{oy2C0PXAe1m=$>w%3e8OiPWZJ2I6W`yzS4`8X61n7C8f{qv=3_Ro`?@; zf_}~-5=O>NkV+C>X6-K3DJ^r*Sm>5}9D8ZFr_{Ub@VIDgCQRS4nUW#8iIs=#l1l8c zD(#k#OG&ZHLBSbsbukW3n_$hXNzG#{0R&Y9I32vqK*^x*vDsZdn*-hk#R1;1DH?Wy zqr*CGu;_&RoT|^Qp?pG{(G+fD91_MlBMW2@cbd&=wdCSts}AN|goD82WnZ*CW~0JE zt0_e9P(ga89zvjaUC65DI|z1&2!&lVrS@0@-FC=mEC)3vbUxOROJ~BN;ib97sY`i;~6K10f37@M(+KX+pcKNq9ZsP#fwZ+?356 z>9ne48%Ck5iLu6Q(`K%lGvIPl7t6|M!bXU2eK3!}x)ZcIWy9Pq419F5g&^=gB1{Zu zy$mD8jh&VhWwvJrTrN88OPEk37G zF!eZEqO>w4;woylpVsN30_O0Zve5PruEY#<1H_j?ED`ZduirB0Wo@{RGDLXB6yr#{ zgmD57rz8-OLpp5O#Px}j94=}s8qKKa)?k7o;3B=DAj#ky>!I=+d9{@jNR`2?+sZ#{ z#N|%L78C!0gGpS3$pkT$z zq)E#4Lu?g63;_* z0~2_jz<3TG23^q4%1lyAF+Mk^_c1UpwU3wxn~9VNG;0uP$AFFIj82L*b3xt}WKC_H zhnDPW5%IVPvN{bk2W4Ea<1jPC6*#F5@+4!Uvpxs!^9h|MS~mOjd}kCFqTu*<8@8td z{V3|m>_^4K!8{PyV$(5GqV%Bdph^)7y9LN-_1Ga{Br8oIZgNEw6g)5 zcd-B$0Exr^l9CCE5?Lymlx&x6xyq7UR@onHm-RvL*{?G_^IqR@{^$JCS+d?AvdvBY z`QuGJ`{wTWkKdl8J-?KGZpeG&{mlbED35((EkU2(f4|d_?iU{>mYDGCOL8hR;mc1) z*tP5c?zXaVGE*}gva&b&@f%rmb9STg8`;oq%;3aTDskRk>b<%{v&73 zW*&0ttH1Quz#~m`g?Y#OJ9DUhgYQkB`$8~ZlQlUSFAh&2-Ku<-DE8*5Hgx3JBz8Mb zkIps|iAQQ`oI5DBV^hSJb=K&0hzFokQt2nJOE$rG;3*Cy_QUTwu6iME2+ zJoKTGDlEw96mP2x*B2;^Z*16gMv`h+>)w_QsXRPi{|%1m3187q4GS4|d5>Z^!LXWy zYpC>ub!1O!1S4KHc?C{p>r0V}k7ZqwRVgr4oD(?#a4((EZQM}>AyV~*qCr#A@HyJ^ z*-%A!9c0L{A@i0^VjEW12)87OlHe6@ARI>qqR$v`avF-tG8D=(AzpO^!4)hI(idnt zHUv$fijvIRG(nm&ZPo%+n-UF?H=sB3bm6X1psh{VwJPaS3%VHxnBcU9D6*-xX*o$6 zz*BWOQCAYMuS#J6&eLc~wLCccC4u`?$4pT;@oD!a83adax%D^NE53ET<#LNWi{OGn zug>wS?WS^govKf)dVfxzNRpWO*!quD<<{E5*Oui{hzkXo*lJ9Uwgr}Np7@el6F0jF zM33X4Lk%-AgAu&-BgU21^vzu%T^DQ^6v+SentIZA`}uuttU?xQ|GDmLlB%bs^~1{1 z6jMFWVXfNJ-t0d;cdBIAiOfY-{k14HU3UM^Q1@;$mmpM6o&^cFXxoW4t}ph+hPdUB zqI#0~739V1(_5@Y=1Q60^Gb~-Vd;b4bBn?4(Z>uKNN(eGY`xz!sYPe8|M+Q+!+u*} zIcWtPJDjOWlFEg+ubUM?6?g+hK{_kroT)2l%<%%VSY{=LhieA7E~^ucsHq|c5T&m{ z8!lO7Xpss*D>mFD)l@|tl=gr^0Un8&&@?)hsX8{x_YIb30r%7cgELs$XB`aOKrr}# z#vO{RDns97sG4FUtgL8_DM;Ao;A9(q;y)EZPJ<|nuhJ;I4!$I!Iyuj3Mn)|#D2jw zHoA)Gw?DfeZdJ{0&b4FAjbxoB0IrvrYBJjoM!ys2eNTjqyJW zPp`?khK4u-6j6|tC>v0nZ7Kp&qcxA&0pcZSJb!9=D%aT znsCTB?b>!lrJcWP@UAnribgZ}Muq$E?Cv5xyo(0Tno^K&Rsz1A%!c(xaW46e{QUEs zisZS+&0)j0cBPGjZ*Jba+%$sLeJm>VN`9weKC$!g>YJ{joWY-X zjt;hGQg>8qouhsr zMrQt5JI-B~a1WZ%cy0?z9MZ$QO9MyI;4u z1Kg=Ay+rn^VEDC$T+R=57Av)gc1I~F@|55HbZ&MBQ4;Cuz7eovVze@UE8{xna*Jcl zuP*mcSGziZk!tDObYCTdb^FC{n#lYK|L(T`LR75uY7%#2$@Gp;c%@5Nb~D9_8DbUNwgzu6y)l9X4|U81Kba#zTT?8eEqF*lQb*kA2-i9 zdrA}8xXziuQ~#{!&0N))`(Ff@LZtqnB|(Z@wF;q?+#h5wG%rT8x-v)Pdb=nKGu$ zB9hYL*&-Y+!my<}Hx~7b;i5x~G~7}}6bO=_Ig^WGAg}@!!jtK}meHpg9PSXqpk;_? zB&ua-N^qZ&b=&^;{RPzsA5Z{@shmiwsxs~bQVfM3Rn4gav=mV#XI3kH-v?zuL@-dZ zP(l`NFe;VQ%cRBxmJ%V%AVlq^PV)w1TT=*6+~oM1_SN!7Gl1h^nw6D9+OU;WRKIvi zoo?kX=}@A|;XAVpNik)juutf;aoeU(ldX~ZD$#;_r-Cg`$I5qvst{u~Q{WjnQoHS} zqeLlnMQW4;|03*r8x1*G<#2*+R}!&lr&1QBO8*OUUZ>?q`wxM;^83nIfUG~Ax3_MF zo8``}{nG)ZZFUT%kKW>D-G@@I`$9cNlzP9)HdMN8cZPx({q1)gZkm>r{43U`K#Bv9 zObFF2w#zoP@!g+88h(>L>*ZA2ufLD!j|aCxv}6HXb+Rf6HGDe3nMbek54f_nOzvWp zP|{l$WVKk|s=4j@bZJE(w%5G2d1ZF3o@~*7aV&j(NhD zh_&C!Hn0p&?Z3UVqCZlIk9C)$%Iu}|Up+gRw09~Q<%CG3^46Advo=QFJkYKs>-DEz z_!|~~(Mc7;j8)rCn^&zVV{b5QeD_Vnx{|y1`OE%qrT8zg=X%MRC#mkjf8^NN^Dn0j zPkEi(tl^70CHk2?VXau%FW(t0b(+s4x!G#B3L95AcCTK+&8ymV{7KUPz9$6rvqwji z+&rwkkk`2voiCl)of(NR=4xOwb^C-pn1)V<7ZqDI<8x+UO5-l zMfuu{?}#eM8=8%x*weQ~J(l#QtkF7FZPOM56fOglo`6dn>rSEG(DY>u$HlQDWYAb= z9A$wYh_ue>#vl@Q?a6VhxaMt%2@$j1)dj&Mw2}v>klN;-_$=B5B#-M(DBQB_tfmY9OF0)Nn#pJ zJ6Yc5a1HwU%QpG}IjD zNztWU-v_AYWfwZA=us=JQgd|e2RDaHA6DsQq%&1Xj&55lhpzSeXpy`>X%uccBwO~_ z>gvkcv2ek%uH&usmXx=-x~44kq)}DNRkiAkmE!{Aj~H`Ys-0AY8#Q1di0vOaUE-j# zh2`!YMklIVg4JSf)j`{(y`#-66{sOy*s9bTG>R2rjB4HAqvSDj^+QzITsc8fH*b)3 zub;*dCKAN`rD3&mZH3?TPd21-RaLd3yLYBY)tj|V=I&N)_3{Iv+^#aW$UbP$q*7vX z3v^q-VwLkzg>KLVIUeY>RrfH^zrJFq>Lq-pnP0D=Vwe@z^Jhmnh4?cipA-0vcH0Sg zQk&;&aof}a!K%m()!5vM+9VqCGfiM@w z+Al}BmX^}WDVBDK{z4)nz2R~oAZ0cjr`yd9rMPhI*@w*0GU?=wH`fH?*RHjcSCEt5 z{5w8EtUtsmiFKWO@VD738+z@DmF&`OKYwplTw8M=XaDQvGdYI8=B#(R#Z2=cY}YGF z6@7OJ7#y=4C9lKwiHbDW}+sJ=ATE zJSy<74@Y9^>vgsH&YjgnNx5p=YvitWz8G@1#CZ_;F`2q->@OWI?|!R-J-1VFQ7Pm6 zb*XOB$$hA@LTCb|)360q>e*)C`dyXRCC*WEVgP?;N?}*#i?pGN zibJ$HS`*baf@v@VvCc@fCyzr8|K_4pZ%eyXiyNG=1Pa{SIH|6;D|rtmsvkFXQnUPt zD_c6N?J#++=wQCfmEg?c#L$#9k5q6!YepPdRO$stuYe7LWYt4_Iw&$j4)Y2!EWM!Q z72d4k6i>fGihG8lyF(SRRN_NU&O6x_qV=Sh1ub-mz#;{+HD#*u$L|^_u~ApMfmrRZ zLc2wpl3eF&I;E1h{tDS|(33b+_RYq?IHByR6oefP>l)dzE zC9oBg%Ljrs1gUktu8@?QOV)vziwuGyw0A{b3E}WyBw%_d7Dy}2Ej6T?Y>V15Pf)Bx z72J^85-fv|RMEoo9Ko}^Ajc{gv4t?yESqOET4;f|U9>pKB^=rKu4U#KX9MpUng_Tx zXG%(yXtTg3HK<6&EKWmsxV=uK3-Ign*c#WNbbSh|ORQXFXhYH?^wdSa{A*u-HlCqhQI417_S z^83Zt_aERd&;ei=Y_RfY78u91471)N#v-?xQ?(RMeR6UlOV`}0fIMe@G#X~OKQBCb zu=Qx5TuZmV@oy2vU6J}`Z~_|>sg6eXm4cTjsO9?YzF5U4?@M^_y{{_-G^E~jc?%+) z>DBBTm899$os{vNWST1EZEh|S&YHb;3we5WR^e`{T!`paG@1Y~U9I^9_E zh-ygXZ-=s|Kkj&IX?k4gs*M@|koNWb>ey$Z&z;bL@b+|IE=A5HaT#_`|Komfiuq;> z4Z?rymKY8A++*2{0=>WZsJ%v!g){`xcgh|~ad0}jG39^fR(L%-%D+RE!<}t-gDOd? z*^#h~Rah5P_iR(Y#3oCdr4be*1>FACb79=&;tgzp6Tx!w62%lj7-%Ay$YXZg*!D&uWoR>p3Q zJTajLLc^fk<_71in=J(?{BaTWwua{GuFnTyR|oDA838D?;BW2b3+U$6mD&g zD@hW6>)T$tS`<9b5+swm>nPrhVWds*B;QQB2T9_cm#U-3XkYc_?;S67r=)~}~55>)Sk-kAspgEaO3j^N= z;COqB*vcvpW4oT&eYxBV>{k}uXY2T%@1OO`E@M^O?O|`)vF;aJQ_+0YvGMzx8JIVXH|6DEmaeW@O&PctERSqr21)J z(qZpdq0r1>S1X!!bwu7PUeNpeDQm(}PsJ*JTs$19RXE#&;VSL6xvnl#5^zKu z;cH#Dp}S1p&=?rNR)i&SlxND2l-?I2GoN+yB_P-V9qpa1|HDA%QplwbP!AEDI8zrV z)E`vd(EsUf-{noxjf9Sc3#;t&)Ln9701bpLZ+4j$r_T0@*@X);yX4H{4O-rFp$ z5qgKS2MvAbD^ax;-e0!W$#-Rd!}9yx%R(V%SzTH`GK}S;FN}35d5pa{{+j(eT{VCAJ z*FlNZDQ^U(NS*<`m7yy}pg+OcMH}bgX7zDT={R3fb)|1;)5k&lH1(^(rGXSy)n`|A z3IjgiP|*SXVL+zwg)6(19e6SsOI9}@HiYZdA@AN$h}dv#GWJ^KF1sM=n)B=OwSr%B zUH$WRT!JI~94k=C>$XzlQI(a^IZjS_F3L&VZ@X@nKF^}K&S`vFrola2O}^STV0e-n<0p$7+a+>Zc5Y{oQSSr2s2-gIkn zduNkScixpa;`YH*u#Wh}y1mA3VnhdlftCi&662Q zqIJcC)E)a-ThLUUH_@+3f-W{cZxgPja4so*4*sGU3Z?*ie2tb*R6LAnBZKaHtzf-Fg0B&9MC86|0ouYB7|z8(b4)6}rmMme94u>rZwwp`!vGXX%Q=hJY(exC z)+AM6|KJ0KE4(Cgn10#dL4Qh!Iy@I-nXyS;z%W;Y$w39pJXjkfF?d)mzQC#Y18Ioi z*YbtxhIVuGaQE9FsnPK|TICC5VSh=BT4ARZHm-jdbg@F%0*A{f@fpP_}`x< zG?!R5x*Pk=Uda*Py|6Kj$9U%pa)Z9u=d#qU~g&j2MfM>iDjo?9f z8U7Lk)<#wA-~vZ^d{2`Ed*bBGQeR@zQe8JCn@*SYy3B#NY2SNwPIAh=&e2M}J*l7y zAQ?>-2{Wq=ZY-EeM7cu!X}d{TcF0#yg71oAbiHN@{yqniRYCwEj12;qP^=M_P3t-a zx4fEa>P<%%?Xf)ZD6TAb9G{CFhN)wu#`CahgAn);i&>7^JxQwsC2%#xZV+mvD#u4y z$8>N{O-NQ0iSaLv8ymMf&n>jJZvSterLXCPT>IUYgHvem|6UNb2%P9v28~gP5Z~~g zFS5|pKcg6*Y1Eoup|=TdmZRDwy!-g+jvif%t^1F+l%A6ReDCl0fYYP7x!q+vC@`%B zxt-BC<)WeQiXwDNS{@go?bY51f$oo|L2gi)S=pOl%k)8SN>czYH)$R7GC325PrKGB>uo_+q|qddGOj%vmqBlxxh#mYaFNJq(4?Tw(t?9)~kj zRI5uzXpgR}9O|FD-g3MZdcVH9TrK^Z9i`=#OHr5Sx%JAHniM-I8D;Oy{|j-q;SY%u zdo~|xZ!#y(%5vlKi()LR>1u)fAIiSFY$5)KROO3Rvkox2^Bfm6tMjqZK56dmUc4@i zQh%{*U-vqb)y~|!D67yN4um@s95!DlHdBRU)vI-bUjY(|GI9+qV*d_xueHGxn8*Y^rAy>15g zwN>&4Z8H)0gvT!K+Bz)_$VQ|z3+&M7(p=H-C<6q@T{o(8a`QOtYJ5qDeuk7tvE?!$ zU~Cn;86$V~gkFSJ%#q-+jRm7+A?l_gA)tTr8YYXiniSW2A>)CO?<2Ds}8#o${Y z#LGwoL$EOVM1mB{kSnSSCa3cx1L~Etp$EDKP3LffnI0HH)ipgHm$C2|l)PTKhMJsA zwRbh5&a*x*nhkN-)~gv&piKtV$3`;%R@c)IM{V>g6|-T(I!|#$H%*!2BF1wKEG5{k z3pyJVG&rhB5pp{>RkNr@4wB_~#j{~O1r2%#{s|!sN0doe3VH|A)Y1Z}M7|uf28IL9 zw;b%S;0ajjrBqY{{AZY})2_)~aAKz!%GCOCd&dl#t$wsc)f}U9TRjyvnWOF`KVk)WIWi9)TkW85zCR3pIHiY$TT&uv zg9S7_X1Qc&5dL=~Sf1GI5*eCi?9j{8LrL|k4B%7>VVxCr%G>Pbc7r(@t%@yXzPcDC z{?u{v`eWx|Yio97Z|ivLxEI|b`8NrDE&o$JvI?U29T3=vH(pjsZ+%yUw26bv&Z(l6 zhUdy<`~c98Qasj*A+xN{|sZGnz*06wi^l>iYegF&Q2Q?JiZg46fr1>hy9> z3J0SaIn^vO2`b19q#F?6%G-z+-tg}U>?^go_lK%;LB7zli@d&XP_N`v01sNaP?g9F zbnWMCX2%&3HMgu+vgU%Ztp^8Ev><9`{-}Dz<#^HWHB|nbTLc9=nbT+E4Eh zG?}Wc&JK%!a1gd?(^~}b%m)Wmu{n5^+iWKDWhi{{l1MX{S#bkKYMK}_KGJua)$gcs z;i{u76=ySq+Sh{MWSA?(Z-;6Y4a}S>N^m6S?P%iS_T=0<%7Hwz&XdHWOiQ! zi4@;!G;f!Q0YIN1ey3_w)|uaw+w)Y4?}Y$8(6PWVBtzbnDMmf>8clBsxl~YJpH$>B zt4X@SVt=U+tq<&OACzmj*I`B+E>>p+ayNEp+ge@Z4?Qt0pT&rM3iaZp`$j~h2 zmH_{QNCA+^lXMO6Tz_uG3om&CNt)f@Dx)?_ElZ@Uh$Dky;s9Ml1G`8`C_m-+V%YH_ z(xHl1M9}9*;L`}K8ZV@6-DEl_<9jwiKmk%rR+Wl8&Vy-JR%MJMWXPyhtiS`262w~4 zknsU75FIS%h7&8QBrt+&L1d)j!kmedz-9?eg(4U|lA$V!glUryUCNjOr;)a!i1JT( zsK$zD&?PxE6b`lPpo`K9mJYfpmjaSq^6K&h!lYp2u>~0471aU-pzbOlTH+lHCM>(= z6kFf>zDZbC?=4u(|h zAjGw{O6$k0!83tsvjd|{E!Qgz>(5-5>PclAal+OStEdeSW@$cSH_-Y-La5NJfWZEp zFt%X3FK-#T9ocM~2KsIgg*a1{V44Y*H?=T?@<#LUoL#{vL#`3GM2^2Z6wAQ^3O9k_ z4-5Eiku$eyF(;EV-1>@95@;I&Wpyv-5ueVnrYgLKize+4NqdSF1oW!#UGNQcX-6`S z(ZT7#gEbEe{r1{&Wh{XDV5x?e>P~GAGh^hBm~Zn{8l>p#)eGj&)~!6am3BDlgXL{Q zIN?rZ&Be{-waH=@qzjq<>jNXEf>a}LLRzZ7P#y%+Aw6js)Q6}9@iFD4{AU{gFExHm zFtWL42dNi%_~!{eK6gc-o~zaFw#FsnoBc@kTKCOI{5tbTuC5V)W?AlHrL%Za-YBmY z`R}HOxlI4+g|bM3^rIuMGH*|Hul3^9*U;e6`F`!4u9shx%s<8TG7{S_5X9rhP5qYP z4eIs1=5rgP-cllIqFGBgq&F}N{9lYhfv67xF`TK;7hP3kq-DwB6m`v%eXx8m7V}L} zQhNrd?Np1yWI?{9YASSwOu%Vpc+JGw5Uir$?9o{XR~|S5hYFTy=t&c&pyG$DCW12E z;$l)ZWUixlK$|$CAG_(Alm{`C@T_u)*HS=-o@WioFoa98PSSAtqmrs1s=TfnN#Js1 zOL|%~h8(1ez~Cek5+51bWx7aj|dxAq*DFc9L1EynY!os2j5mK9j!uk!2o5^7yrd^Z0*;H>xwtn4A`$-EQBy zLY+LTh+C09o%mAaT(c6K+wOm|8Xdcv(RY^oC%bX^wcPeRC&f_GzwP$3&({v@Dy+Y) zY+oF34YzJ{H;DUn`s%?da`U~ub=r>x(`@Z+O8Tk!tkc$l%=4^Vs96vqgBSj05lBhs zd0H>TR`2An_EIC)OH0;z$0Yjc_pYbiBh~($+Y~=J0F2>u{p_gw8-DzVcsn>O1Yf5b zKbAG;-DaCT?F>${*wIl8s|=U5{giaEG(S$pul$x?y_bilVf_od6(`PO*fz$c#-z8X z48P5;Z0+}#yCR?Wp+##P%=+zbv+PUa#zfb1)bJA|yyzD|@iW|ne32!qpI{!9A)$m| zUNL|q1edUDwZ+O`x2A}@Qf6-F{$fp&b^>GXtJ8_OYG%ALgI{a#ZA(N8gGYQjlWsg) z<=2~rR$3`@|LHJHw!29N?HJ8^dSlhw;?6fxC!5<}n{|n#F4pdQYh43Yq-~B3IiowR zvdJ_(ytJs%3ag3|soKDL!XvVY=mF45P*`-Ot#mN*IDSyeM27Ym3;7^EFuUU3B7;aPoa3i1pLw`sFLU2=}`--v?cfCQOV1RHo<7fxV+ zSTxQ7=#t|dO&55X5nve6NS)^;(T49JQi>*j7Qho7_|;ej5wz%le@GQiqo)C~d2tdIx{Ga|p-BHZ2xc9z0^5(}nwME9GnNfrv;pE%GcK_CzO| zvG1M^@?qBHxASf#lA|Fn)>~&@x!A_c<0T5FukJc`J!?DP%V=#uBy0GX$R2if zI{XRF^`Zvpw@D;6Cm%C4@O>r8T=gn%Y?1#}n*MH+>Z?A7D5v zF#X+o4^^&t;c%V{Y3%myc+TCUUP%YvT0E=7#Sfhhv(~&U5>;%}g4ax1a>n!ZJ> zghYioMmkKruv|>uFZsK@OKohql=ccqam(j7-VAm3vYt@3+6TL-y96mzu0@A0lWKPB zpyFoPxwm644SWB-DzT4h-i%44Uf*b#w@U8U^n7_`GB=#&3am3M^jmf>>?^}1A!6#` z>Za2_h|fJvVzuA(vxyfsv~vb6zk7CcH!saEd*-x0NM^rIjCc8LUL(^R=yvIbA$3?| zJrzS|_^P-1?2Jq0T1?^-CFkXx{dIe0M#O`HgSlM4> ztH8~`%?0<9ilLO{QdO&jOX z`|X{LhIlI10(V3iI$F1kJYD3a1iO;Oma_R@^K|NL{b!#o`=xgc33?#ES)Q}TRjX{J zE%pkcL7dBemsk_+Ej5+?7PFv~Wssh+({09057MmFb4lKcoa-A~DsNR^5)Q8I_jiNU z`qcE)0SCQIO?7t0!PCEYWt*8m5c$f6 zp9R@=veF9H#d^ZN$80SVohH5&p7e89@1WR1J~>_D`1{kw8nkL}B3>SJ@3|^hKZp{Y ze^FSAKipuyj|)QLTBLkeo2)8=6lS6yZQ>6&!sv0x!xgj0j}YxZyIG?eY8uegN@ufO z&ooXhHP+al4c|=eH~+XS7T?I+2fKM~y-atsB_`mv#h=#nWs|NJRd!`1bLZFV`=_0T z_51A#I;z!gv%i=`Z2li9{dUQvU>)Kz}; z$XVW5OCWf;c-|+pF`=~yL3GX<$$K-=)H-Uumi`537-X9(;irdwq_*3%Q>b-DmKo~h z+a1OsZVC(KU7hR4a-+S~K!T(gWSg2Oek149*W<>1+9`8CL&c5|r};FP2aFT{Xw3>< z8APDsU%aU%hi=R7ZEwUzu^f!Hl)K4 zd=%X%4ioM+j7+e6*+AVbUFtX)dH+Yu=|8MFL0WTS|ovw$|CK2#O z<8{+(Rb~9SDMj&Ia7iPkr$DP}?zwD-3FIV;_Pc5tX}u|x*al^#F$DLjOsOkT#g3)n z11UGFc&6zpuY)M?sU{s!8zC7$_#mGLXwwa$09PWVq1pVXLumR6`W?~&v(aTg@+1iF z5RAG7-dHdxprC=$nV4l-0P4zkYHf2ZV4$gO7$*hag0{?Ws1%YRD$SD>I zK%YmbKCK#p2rZ7-RvB3YQ-vn6Y7fROFVbDTVy^IjV!W69S4V5;_FENFNEH4YM=$+r z>a*q0UAtg9sPYHdrSG>g=l-BZ_RgrI*Wu~^^>d38<*i66Jg*^}$LSVHr?KRAd%{3p zzV(hQ{^B2tp`yf!ySHH9y)%~>bcjX$|keeT1HI@VoC((5AYSo_8<|0gr@OHZv^D=*I6 zEadjG{N>ZKKC6aedga<%=NB{AX^jP~ug2RDR&SB4j;k_fK&}C8DV7t%OPes&wNJ0B z>FF@%DKJ9uk^!%yqbdf7dSnH3pDHAa$Py1u86^bU3%H@>ET_WG8gT$h9%vh?>^me& zb70u|)ZYUCH7_euvZZJ+DSq16Dux0T0Mfr?OXhT+;SG%iAPF`)$ghep1S;Th3)}>;O<&{2&zd1VAiGr_r&Pom#R0PwG+b2Xy^Q52L|GphV%` zY%ogMD8ZFQH7b%yIza;=UWe8$QY&U!b>y9lCqD$+5zjUb>Q zuy)yNY1@{ZB|MU0I9|)e?4(7)+flMj$D!+#CE&z5FyfX8n}^_oSY*WTjG(8v7EX~G z;xpB@92=lhE*YrU5PjcNd-X5##L(4C?Y27r6hN-23>`q^Bgomz%46G{g&YZnCnXE| zOx7h>$hJgJUpsR>^P684SALKUugx*?TjVCne&MP(I;>ny^qL%!zb@mL5OwzCb27aJ zX+aN|f4BHzW#0c9bI6%y8TpaVT3b^6@^d9^=GlHmPxOwWv(?m-A1l_HS$pkst^2P% zUH^m@!<9=C^61sme*!_9xQW>V+fwlO+kA!nlo<*OA$^&2Lyb`jgaT(Mw!{S&&0oJj9bxVVU;l4@InfrLRQN1S-w*fSH7}*|1taHzp7k&;bi_z zSN`ffkvM~VaoYRbt)^zS5BK7-cJSQu{n2XS_pTU>UY>h^yu7sK7lX?OOMllwix(0N z??DTdC(aA+t~d30U5X)W%i20tujgMn#HG$LJ29$1i`6QX3%2lvrNW{rZ{B{j`&vog zoQ%(zi`9if07w|3qOH7i?l1X-xO3gRco~tZux)lueDj~<|46p}5suld27SUH+=9Y$_EPXAk6kIvNS<|Ne}YGC?sFIVtJ6(%^NEoes9bCJ zT8FxKaY+Jt*R_+DG!=;MSPh|Ml*+`rDxzb6lay0#XWWBh?9=<;_Ij)5M;-Ti} zF3hD5r0;*81^Hyix=Zur7Y568Lnz)n`(9VK%QsG&sSoee@Ckiw1;loP@|F5;qjJ4; z^Q?n#qw}>+V|CU|{8t(G;+g#ZX7=GLB-W@G)_+|cjP z{sl&dw6#*=Tq6F=pR!YC@q65W<2Sg7y%bfyaz$|c)3=5BlfGG%CyN*7SKKEx%~@|Z z6ZNI1MJxC}m|Ve@KYX!z6L3&U`hohrLGP+1QB~!E;uS4#t|r{}#pnI%E`Wk9JS_o^H=MiP zX7bp#vcHhfk1$X^I(tXAsVm`tp6l?Ft35rEs^Bv$6#nN^(f8G9Ntq)VtBhdC;y892W$xBT_ZFWTm7=yLF+U1#yn&od-RRPxK6`ZY{C0`+H#fE|^^h(e7FTWLrK?AD z>9WM^@6vbP@C)mBTfeX?k1ABP+6nND;`WA0^}&C5OR7y?ZwZDIA$QO5-|L`F)%tj$ zv%NlosJDY>8~)XiAs5&ArZTP+<+Dp(y%N^nD$MmE(r5Ae-IdMi{)>pLOm<}wnPiu& zmSoVmmO*A{vaeV>TxV7C%}wt%Bj67Yj*lEtxwKlpwmcoz73U=XEq^WAd1Y5=zF^H1 zR{>A9?Xksi*kl7anJtl#sz!%_6kUUm9HOO2zW30b#q?M; z+sp$K7uz6(6>bFAe4*VtFKKzI-;Qk=vVR~B7!vtP@{~+A6{%9ucgYo)&JmzDL#|0e zo=i$}eGNz^&aMQv;vOZshOxqlral&MAJQRAaWxWc#7+vKxM3Jr03Prv!jt{cFwdtt z_@-h3^+kHZ2GB$}H$XH>E=IDOid!TKt@x}kF8BAMrom#f?# zHV)DFiR|jVGmU1Gd;5K~vXm)t7jCpuMQP{D)1~K@sq)s&?hW4nB1XvQJ$(3WZ$13U z%mdQqENyjbC0C~g6;%6|`zw!sN0I;RLbA|A{g9oSb<3of%(cI}R6u;EaL3AzuFB_f zPu%w3|Kz8Y9nZjSwU`qKqG;SLBr8`_2lh+hT{r8$O=gzVFv&ji`d=(=40^~L9J4Xp zzR5loROi^6Ij_!$#}>0rc6G0CEf&E4?vb>h%v?l7r2Y$(0~rl-*gilFYz%4>)@eW_eq{mgUp8xd7p+yA#Bc=ARf z1Uv1G_^od0op`tuL?egIKj{#8sp9(=|2|{X*6rcd6@Q_D;d$ey#P)A)K68aNGVp*} z#d4E@IGkjC^lK&4*N!KvCX<8|`a^MH>hVQI&Qbcyg;V9?GwbBcWYz^+MtTLkbrO9o z_XhT=%tZRN6^FA*=KJ1z(t_Uo8o`wu+!p;xr&L-D7f-2%@mMnMZe106e^W6gqSe)^ zhvv0re5tv!KsY7Rdi@r@uDXn82Z5&&cl;zFQm8tXY zL&56I)EsHfKP(Dvy>#PM;tzUV>c2}E*A1CpQAWRzGg!th#-3xs4X5u#o1=oX5Lp|TGRb4rQX6{XQdej|#L^czVUz3|KQQMK_|}N3 zz=Ey%r3(Khcn0Cd-ow!*x;C}8 zzv4&hm=x0n)YQi#r zL6ZyGeeqvXooE2Szm)>;GD!G2^+ma-8Aw!uR5jI&9WCUY5tu(-{yG@7D|&4TMkZBa zwweYYDfJs51v=ZRUz6;B<_OnsS0)OjqPX-0^l0sX-qWk%72bXulDp&XkAg-LB4ayb zl!oLOx*C_cE%5`a`4<4d=0#1f^Mq<{5o z30yW{Fm{@P-Pmq5oI)D{(fYDTsdc`y0#kzl!3SDWD;g>#C~xi!IrVaqy>JK3fjd`b z^==VGBA?z`x@R}OUT-O`Wx{?pNF1B1rv%yFBk*FesAsPFqs6qLMm=f|7M>wkt>;3T zs?ySWupCjQ7eXqarL^FCS_9+_9-Fg%Mv#zkjQ2$ZL+ZSz@K~jDvr5cfZ3_p8Ruuya z%E_&{7@3k+%D4QrPdK3zt2IWfs5;YCg)}I^A$QH|2*~q%5=Cvs@FAVH=f4W)l!2Fz zenMGQ%LC3m$hAvsO+nMrgm0q@A;5%h(AeUU}Z2 zLl69<=aw5bAC}IWKs*N{M*Lb^Rbc(7(Z;(L?EVJBLt6Gjp4$HVhD^DR16E( zY)aeFOn6q&BjeCti&5PiudlVp*NFz?NFD1g*%b6ya|uZsJZ6Q}dOeZqT#c`EJ^W%x zn2$eF#}r{GE3WE0k^Y*m(T?^Dty*oSc5vO*j0brLyO8&v8kWfn*l^O|3iO%TI^0)y z2C@%!jDMq2NQ;DxZrD4RoDir(jl!l_>*1NJXxEwnU%QX+5F4EhV@Yt8nurDID&-s) z5GxGGwrqr^g6X-2BNCrliv4oz@N~t#i z9zgDl0o!zpp_`}OrZ2rCUhkEB7tQiIyH=7PvxD^}R(AH?Y>@}@FfIqG4Ry_huP@Xk z5nAvtV{l)r>Sdq6OpZ+y_|}1F62=dw8JRaoH<4A?5J(5W7u%hX1Hq>lnsjqE-!Jr8 z%}>(Zu_LYuIwZE54QGF(NwYw9`-rZ3FXfflEl)bW(x_j1xz>n?{Vnwc67~Flv0rOx zYO~l9>NdRyn^$RlV;1@Gd3);ST(DA_xUyN?5|KcCs;PEg@j@T-8Ik$~fNy(9(VhBs zxicHYGw(bU?yeNsm7<{fr7`&(=MlYBZoRwoAWYvq_e8Vb2TF-!ia#@#2g#JF-sI?N z(5d^DyuPnYPIq2=xTF5fWy;!b-;TK|-r2ZxW@^~^c*b2$lfn(PTAvsN$IFeRv(kN| z@fOv-_G+*##;W?(E30o5C@r+`nOw!@hgQeoiD!IW_I>xAqeZNUGlmH)ZOKrcURX=*g`|SPwcFh526(2;gabSEw<^m+X}dm=c9miya%X9q3CRXb_ZQ zwz(Cz`RiuoSE5=DhiG?0A4?h?A@gDmLY1*Qv2GD8M64L=f`kYu35;jej)3qt@Ue?8 zBjPcHAcdl))g8t9bE(Hv)w(aRYLM0H(p=*S(LU>$xLb%i7U^r0!-z~Bx&$zw>VdkU zNk-f1noM;?s$v3grtX-C8q;}5r{k4j^6&v%qv{s*9?%z?X+d-knxdD3m=~k~o3y^& zx{U(=LOEF$b>I7$?kM*h8SpPYT&5x0tapcpamUZ3dak$b8~z^@0)pTDr(yyiQ1!n} z+Gd@jC#uRxy(4)CzHiQXOmsL^p@RVpEYk|KoTW;oRx-PFmF1JB6OHrPSx4>`c<-5L zUI-gvzDWS=d4_#*Wjx)k+0tR|(nhULFjMQ?33+{YTx!~)^5MdXr3A#g02aHVp&hG) z)7~zjR;HY^I$IW*TaovRjThP>rO*CUn+s!=yKH_L9l*WC$<(xCRlfC?*8Woi0(j4co5 z-VCJiakPGQZMAB8mN~;-nON`CZk0xrr=V?Hp9fp+vXs5|joxj}s%ryTjLpeh*o>l) z%K^QjTF<`?t-)Qwc5V4wwFjv2DgA^xNoqoC?N_0UF3%Iax@j$5G3GyFxJ(@$L{q}g zLhJU(F1#PKv*JqBRQFM;6#Dp4%q(TY@PP8@rOsm# zmHR9opg6Ve&mpCwOPh_zO>UbEwu}48eWtGCRvo&Kw6yWta!3~7;pnJ5;B0TLI>KDR zz4HPqNhd|yS7GD}#7IXnSyD5t-!)yB$9anMW!Un%$~1JS6j3*S3rOsitC*T3v+zLm z;B+Yib;!|m7{Yqign|K!5n%0#T9EBC9B?A!*j5!E+!Ihh5CF0TlgP&|qZt*(_^J*C zTML%Ejs$3=X| z*IiI)Z2=RG=^EL1p+dFqSX>mfK9Gf#7nWvuj%gfMZ&}`Qu6r>{pAG0Iq9-pK2vOka z(!QqeE}%7vH~cTCqdOgmTCf{R+jHM##})gmD&Y;M6bbdo#RK@vNHCPBzrV=n*VQ)C zgN zbKs)7-FymVc#&u-8;9rTcK_&*TK(})uc)~iy}xZ1UwLx&X1V=g=UE3AAFbiP>vmVM z*Y-O1I$V}XkG_;xZ0BGzYKh)0Bp3dywvLc%SL^XtxxvQ1b3w`K57C?d>k%0^bKZYg z{*8w^xvJ+6^Y+WEm4BgU+F!pKelnQ5L|oz898&%KaD4dD_k5zXV5TQ4(^spx13|hm z#UbC(MC}>&U-axk#aX;|5dXtrL)t}uKO6W5yX^3*M<4$i2A9j*=x8B%@VyuLdh-si zF73*5{Wls(DdqLvxF-LTFfpk&zDHkM_#3N^{_lwz;pffer*Sww+0NO^(Fm4hTxb$F;M5$ja)sds!;3m6(Rtb0}uHhDTAUU zz@jY`Hu#?N*Z@vi4t$$xRcN%p6hu+Xf*iyexZ1s@05@QdL?Pv{%|NRc+5}D65zIJk zP|)YmgU3fLv#W>xP>1}nRWnjjkR!?vexWxNXo65+x;JMbVQnJ-kE2D2o0nw>=~-fE zW1)nE8djEIAre9gt-`uc0U<2;N*cjev}#gTQ-z|VNh=x;kXJ2V7W5k6a5ZP^hHTg0 zJSvbAj1ZI2y7YC)ZWbD?KYh>qHB^Z=mr=MnxieV)7PyLTn*9%}GIWtWj2aAxm9SVz zP_$d8D!e9^C_QuTyGuZks!f$yZ>G30DBktYaErg&Zv$4m6A5 zpk@WvJZ4W0x-e2_Ax6oR6&bFq9&E`lMOe2T zB~^tD2H@a)MJV2tsQ7U|!El6_6~mFO6yc$4a^jYi0Bl?Wc$@{#*2jRtfP=WWVZtF@ zQhCitLJ_p^kW7E9)UZ;&Y3~q{tY(eOgoU7vn!FE}KwgbaK*vgI21g^<-2u~3lrh?o zU9rI_v<`h2l_^VF3grNiUG+sV1M(5Tcs&o+Hnw9EmR&nsh@r<_z|XN{l7$9qDFj16HDDuZa}=%4hVK33J}fhgB9} zlefkAl)aZktfs&tHw?rGk#er25Om?sqXV3zSGEjt#}+Jh=Q<;TyQFq8(iJI;jm!91 zzM8V_Ite&(Ir*>4SgX6Zlv+!`5q_`aOSF7_s{v?XS7ev8;-I4Yl)dPd=hrOK!u;AU z^mfsfiVM^(-D&`xa1^fpg4Vg5d>3!XZk)q7AN(MPu>hP;vtCww(8sN`NWTYmp=pi{ zYIfMvCx#u`b!eYzw6wcu_+9#q_z1S&T7hrY-0f=!SKU43N3iE{0`Pd1!hxov6*~P3 zDm*XR)ulvcj(jMP(v5zAdoE!T(ce@cSa4Fd#Uor(* zA{^c|>esrqoWxoHbD5^PuB{ah>*@|`j$2%Tr=}RSIk3@V%S&c_!Q2e6lv)}Yi~qq1 zzp#JCK~dDHu9k9twiiw2lHn%+t}ubDAI`+nb|T zf@_xgRz~{|Xxy$Mwojh@Wjg+j+a6Un6L+?##0z&09r6`4IOS*te`8+g!-S45OY-Sr zjprqAILmHjk-B`UZ#fSrbKKqam5-fj_>~bhyr`5{jLpQ~Y4_?0jNI@ISE8#y|tuV@*5@u!Txy4Fjfo| z^goL8j2nT(?{j&{pPXoS&AIW`z-u6vWVft>S~2-n>s;6^-6d88jGc#!Jl~GE?Op1x zzKA>VF|oX5DP<%wxOG0avVg8b^ZY`Zzj4XAagYZOB3D$Pz1%pIYU1*htR^AjF2rvy*qDd20U)o1W++)+(d5?44HQ z6&)vq@7!E&(3Bh5O{fuo03>o=hO<#3CdO;AwxFB))h(3>$)G_uN|y#=txE+vFG*b! z*WaP?R@-$=Efi@78QA0-8WOc4W0N8ym~E5_d9wbofL{E#2sy?*t- zT@>k`sT43a&*J`^@Jonb?ZPqgnA9JX$Q7siMfQ+-Vj1~%1NvPid{8&WVQ0Zur}ERY z#3-je($J%=hLZ|(dS|`nB+B`({_)OYBWQ0UY^Zj22dn6jbP&EM75dE7?A#h3RTs-| zuCS>K4Jn7h?g;O0OZD4WdbFLpd53xZ$dm=m?^p!t4q+P*KIKs0&(wN) zR14;+whVa~%P>SbfqA5^aWK`C!~yuU(weV;f={&tq2$nzAGZV31mzxtty@4ahIb^{ z2_SC+bpk&RoGFvH9jG;joTWzI3U9G$NGrT!@&-q-We?)CsuTMU+=}ONI^nd^V$J4d zRRknB1W%O-O|SzIx3w6MK)@&_Oh98>fU+Us-el-%7{sCu`EY3nkOCfJaIngYbdYOd zMvx>Z5Nd6H*|Ir3f~KQK<6{O#}j1AUP2@ZYy+$*o37)S0&mD0Q08GFRb*O_<%PVl?^WP$;8_{e zQbHa6-c%F*$_5*ua7wU+zSGv6(#uBQgI||ncXg`?ncWs7efgMuY%|bP7gEDe;&v3H z==tyq=2dN7g^t;hj|hPBmEhDf$jR0Vg>DtcU^yH8Zo0%Q$ zwj9rG8is0%2HZ9|L0#76odl?(fU0#WTnv z0E(bZ8>dbFwks!I%zBZ7_V=lG;S;z;_Bouq ze?X1ee?~^n&42ssmFY#N(E#V|${BCHx^7;tW8+?JU+?ZQsFMx@_X&Dq0)}}jJqW3v z8^0nKU(k)^N2(4iyViPjO%M+U_@*Pb)oUe;u$NvByyZrbOdOKR^mT#~?s`P^AZ`8? zG1x7vg9PThj8 z>aePdFo5#Gfk?1yAC1?#)D2cdOo{;Yi3EVG{N#M#3n|T2U{7SWd2hZMX(S3@FH$yR zN2{4NNf(Ed*J|WbsGM<-E(zNq6Xt+Am?)DAB*tts@B@3^nrvIcmyw#1Z08A5RZBB! z3DjC>w>Q$?;U^jn%e`D&o}AtsNAdR>&%k$JckSlfgDK8_>4)yWlFk7{waQNu>~X7A zTzY!NJJ>WRdX6%9bVKW14UDg7SPKj72&rKRdmSV=Zm^I0hJUs$`llR5u-=^H^w2d)dOUg2^gS8WkZScwGA z8Y7jdhpGUnEMICcfj#h~WIc5p3NhC(M_ds6oxp}nh0aQMfU|Ipx+q_jc+NGui;UpR5j%&5Eu<4i?dpz)DQ$k1WCpf1Oh??)Tx`UE?wIPfP-Ami(|yQk>V2%RQn?zZ6v2; z59;L7WJ?(+%=mAReoy@9cIEc^wB~lfH)U7lV49g?fS+s3=NmQcPDw}1t{<(D_1U?> z3arW#Q5|A>Z$nBF(x3I)SqInC;5c@l3?lB}>t`OEf1uctfD;xP;^j@!@9cMEMgP}O zxKM7>U9P&{jLOa5xu`#w|71+~m21Gx$g<*9;WZxLsF>aNz)=Bo8+dEP#y1i~xZVM| zxjqQ4y|6iw4u|c}XYN^pQz1L;9=A~6+*un_`PG|Ct6{U+(C&=uuqDjMcK8bJ2b-^S ziLNMLhPz4Li%NzljufpyATSCrL>QrxC`poMv4hlCuq<$~AYToDEg__OumXlc__1lT zaRS9_)m(6mct}&Ch5-Dc7EqjO`H`&m45=wh5QOW4!KM%G3okK1FvLLsQ$pxUBw8!r z>V&Q%y!TD$9gDg?fPt?k;fb_iFmGztJvcVypphzSf0_nDCI(z>(VZl`bvQ#fnP}xj zZ_NXaKn8LHOR6agooKV;9QF_xcd{BMIKiB0BB>3tDXkRCV=VgFG2^L=1u6!%_aM0x@!W>L57Jhw=Gpk6qBnLrzr`)Fhwvla0kzaj(<y2pY+T_Mc& zt8X<>dxyk~YF4ciYu`9R6qr$Z0^cE|m~}U~oe19zasO|#x7`!PXf+>`7#*%A9K`1P-MBf! z3=q67*9P8WR%#&AcxbgL0FqyV#kO=A;Pe)lL!rNR&+gWe(MT~jU@)RQq{o=n+(@Ro zB;i2_dbyM7n5~~}5;Q%SpeorgLO*=82Rn_U=zl1jiK(dz?jQZa?eV{2{eAqTytdS^ zuC5+b=A)%fp~=;Qo;^=QBkfaM#NA8%Q2su)x{Tbc-9-Ll3QDaS+{k}B+E`C4TFkY6 z{4f8W-Pti`cV~nPUFO?benU6bcV92y;%>g46JA+78OXz`-1PqwMt$yf17n5{Wtf0m zlZW)&e6cY&=(7v>YbQ(5K$%+nWEr>)|F|@N^@H3EX)C}tk?zKyVJg{dMS3j@^Ab5j zVeNM$=<)y6Ge1)n+`;}(NONxWiYu0*=Ku6!)l}qfy7x>5xhV&&%NpB1l{=`3eAdfI z9*#vkXeZ!FoY6&_D{Pr71AJ&ZJ786zayhNWl-?j&opHrPfycVNB0U}>nnTW@;ZYIr z(bkTA$N~pbk^FFva0$?>I(;5k>)IhS`bn?8aT7pMLSjb@4^%@vuaL^+)UOF}1O?5> zfN;7=__w@w|3P)tG=p#UNu%l(xCy6ipcH{92O$yStn3jP#5|%+9AqUlDu}w)UvS&} z@OR*_4rqTkpAW=!vI?V;t#NN@maQ~U*7g|qb5-5y>t}n@KhjtHS%86GsB7}nth((J zJD(;TjK0GRl#vKqBP9kx<9f3|z(|M2GN=~X;YxdxJ3n;%&7ou zhu%)B>k&Q0YFpwtPEp%{bHB#58%l8`iL3)>86erMSxJRUbV>1`Gc1*0Ug_<2E{2q7 zs1W#&eU)Q&L>o>kybi_=zH#aAEKzBbr2i6Nr%aV zgLq>kkov$0sKIS0Hky|k7^ITk(hXTzRXl2BY4T!+>eN-bwG_jwpVQ(mTPT4dzDCpCxHjhgH*9SG zcJ*>9Z@phb8!oE2#-*_;6I)6H=&xL99e9*>lC9sy zCqfWy@M^&>^C)sdui;7Fb+y*3(!oc5nsrno_+EiuF?w@T$R0 zp9`~&TI5|XSGfe6l6Sbdcq&c=^8b5HoT@_Fj(4P-skI;Kbgz)0G^pmqYPOlIsv?>~ z<0~zhsD7D%Qz$P^q!(2=(kjry!^De`CwL)=!mxwhF^^Xpl`d>_Mn)xv^?zu1?!s&$ zf(bfbYx8f&HW4xH-y_%*fCg4YCBH8;ZCMQ%@CFWbHGgbk`9E=%tt!%FS%hd_lqCCE z7ckNVAS>DOvQCFI%n!g>wAEy7G3r~QK76Aq`y15mEYu?A(cS2S%?dYeJIi3loOn@X zqgtF}3d*ckz9x|Z_#D`&z~x58p7rK;VZgl;ujp4X>(iyXisghnTJ;-CH#X1ur#1mH z<)gy-J1)bgPW?^ANw4=guQEh)yGG_+l@`he+e=QjeZK8?kCjommIZTF~UkF24P1vj`qN|YuC0}qH9>x88Fci>fYC9ml( z0h&RO{q-dqhCEU~wO=rq-gTp>jpiL1Yue0tDJuU8P1q-F(wTd)*rL!HcGAPbG`rZJ zss0W*NNoSZ^3LLF(?;^1Ax`|h0{jWKbN~CSWPA<>^youc!YtJ5(E+wB?c_Ev6-P+w`{a;(K$sO$4n#e58+s&UB zx&2*!XPiBIa^Yh@`~5HpW^aOBiNfRi)Y+fd{OqY{Z<;;dt#R~C_08f+!H1DgzKo2R zLpFbB>4+IhNgl;ZO9xyrAI;7m0!lPt1K0MvaA6=t0CiF6N#ivP*~$1dXwBhvPio7p z%Lli^&TvN7m(T_S$n@+2%tPV?LTn}P*vHl{gZG;%GP-{(pNE+U0q^#&u60q#px9<1 z_451T_P!Pj%cE?_S%!eCyWl}ldhnkMWbUmaOTbGe0*2Y){3b&kS?in)wgEiQMZ00l zOD{_KrW=a$P^LvtcqhebM91-J9Tr35sPx)Mup8QCHWV@SR``nuQ#_RZ%a4s?45LV@ zB$iT%t&)SS_2g_^9;@F(xu18p^ zq_bw~QvtXZAJv&xiE!!G^~=WQ!@QUrTz%e|x*WZUsHMgq(&px!rM#+kz!7$TUc3!G zBD^UOKct(;2mGCnPO;pb^VugCrNMCi;1EN?4ueaZk5qun{b4!{zp*F+?aQrH;`xz z*TceGG(%X0L|b7IZV*_uH>INYYHRHZ?QaBDhw*@RsmK{6AZJK)2N-5`mssnY$~VoL z$y*y*b^hdQRYJJzkFn>#TVnx6Lrfn6a|m|EJJ0u3pi7KA5>&kBBsVCQDc(*S_#jy-v|}ls+(0z%H{z$TGeF1A9rGoPBQ=t1Mt-OrzM>;YiMG@n!Redn-9vV1Pcj{ z<3RQbhcl^XaXeHoA(oh~rCq~VkzxRJ1Q@g*EO)id(pF?aiYCAi#03ZqgcR1cK)@?P zP|y>~vu3>Es2$s`=sj3ig-jHVT1|+c1H&@RlGp?sl3+U$1A+xW5CLr1prh|&4sQfu z$1)Nqo5ql?#No-pRH}Wb4byGMc7X$xkf>f)S`(w(sFM1bVXid|y-1RE71;NKjS?o9 zG6ivo7C@wG3^au`*5uA|HEjAcsw|)6kKaTeD)ppSygJ~Ix$^R(YBk`CXblv0rRB6Y z*lYkbGdfCwLmW#h#qeZ4Dq7A>(2t8bH(ALwa$>X;ppAR!AQ~^o)(Z0W&Cs(^fBwEV z$(D`2EiM=<%u~_)!VVFppQpuqOoKTNMm0hn9|U{4o5K!4^(3q1dgi^olhm6|N%g#- zGr*cZge%q2;OW$QJE3rPSYKQ1q%X8UJUFqpSy>eA_>D1kJYAgc+8``HflJ-W?$v)) z)pqi?*>*WrdL9Tjt09k>JH?V%p)&GkWiJ}C`HYG@o#$Q=tl}@|=R){J+f<9^ms5N* zpz-8+*e?u3HLbh=Edn^CLQe?9#ajBv;#VX-VHdz{!F!MkC&$(GjTKDVgS4S3jRi{j>O zW}Ok+^0jITpl;S@`q6j?Xs%d5T5Bs!vGes{wZ;H+kS%N`hL$luJL=f` z$6LKKkzXORggxIb1jku{Kx+-y5lVI&8~3wCfo8u%mZ~+eUj2P}|9GPlT}KOScEm)tz~&?=-rzPP@?c zsIT>)1rWPh8^)1!hfo&p1Fvp}-zb1IW)e*sLa^Si8g67HJ9PEJWks$Gw_2NUZr=Rf zE2vOXivA$k!HU{}I-l)qz<6$d;Zd{z*vJMh#tyX_O3MC(E>*gp%oQ5fEq+tso`6F3 zF(^&(o~hQQ4WU*?*2^8OJFKcJP3<^jl2}@)y-fP6!~&qPz;(gtj3R)gRiU`+QCMk4TI=kOFniX-x>%6~!&uu!V~`K>HZLQ)4JtfQYK+Z>W2`pdZ0_ z+mSKgTB6Klwkm4v6ue?iCY>zP1hCaLqX9`r4e2YW4W^4t*{larj1r^lH6a&=b9F@* zD>DJIy0hI<-dj(f`f=>;?HPlh$04`OdbKQv-|>U@|Z)xK=V>J z6o1q0y~3tPhzj4N^vW*R6LOc%lxM&8X-Mba9^EQ!U%ptm2;68O1jCK@`N^k+@AC%KV;F_U7KA2b0bLPg#t^@M7hEIWP(PM0#?zMqe&zd(e2KZYDOB%nTt|?(4Jy^3$HE5>8)3NC>bNe?VGTDK#_hL z{$%o$R%I+Tom~#_qdfP>Ur{O^wSaAi@2$HlbvBFtPj~y|j*>&v4J5N^x3Y<_caGj1 zAZs`M5O~?%UmQa)GRM-To&CRVhd2ND#BKdxsY}f8x6c@ZqQ)lU|jL5snD6PS6@7+0*4p8{Q8Bkkvj^i*6r zEb|Nb3D6m00q>RijSUhI&nnN3Mfdv4>H%YZEcw%ZihicUvo>t z%DQHk*C=66=#w!PSaYCA*2X=ms`E!_f^QG$gcJcp2|eODJvTu?^5@6^qw#_3iaEp4}7I_l;P z+`rVAZbUa4nxJLn@`gOk?av6`dMT8?^HjXcAKzV?Ip*A#Zm*Q;OZUEP7M@NWynaa} zdQ^#GuZP!%)rTTgLJc?7yB5WK8Ai-2f8D*>t6#r>)bGp8gftk}UU$##<|mr9TLhCLEEC|X;s1JB}16Bfs-hicmm5 zQ>=QN;1v-ah%u@g2y`x-F0neUwFC_atA7BZugw~7Y{!YKajix{1Vnz?>ut6Kkwde# z0N5A{d>2*3cW?`jlD;qRRH`y0?Pv(hLK)L;$1;DomjSpEmJs=77%BZ;zHXZ;JXT1l zr4^`&RIk-J8=NEO0u=*&CSx;aK)PuHpuRr8LGx9mD4L*ip0h|7uSv>E5_)E3+2l^ejajSZ~kSrFAmi;FF;KsM`V`$2Mf|g0?^uE8b z5TZAo@?VvHt6hI2>^A(Y&B?p7nXn^N{as`Mk>78h2z@{8-CX2}_QArMVdDGO?%!y> zB~I+KpOLZsb^+@z>aEU zy1Iqy2&y(e{s5)62XD77FQgx4kP+CS=PDsP_t!b& z(;`z^;cx2<#SU{=Z4AHOwsp!>51})O8Op@5RNKL3YM-1vXw_MgHlfVlS{#6$;|69N zuGO+th;8-2W5w&73o&TCRHo4eemBz?5KLl)KHs^$v#@^!N6^pJqtVC<@V*_@EPq(f33=JEg} zg4xD%l)j;myfassT&|$r9)pnmaNZR1cHz1Da`G%dBY)3TddXPPo^9yR35cbe4Zt9& z@g|F%KNG3U&beJudWXzo?3(&%4=o=-g|)p_w!zA1B2|mX7o?L#fzW1Lh&H~fOCrv< zID2G?nNF~v2inp=OH9uYf~Gq5BX)aOB3Q8CMGrXaOZ)wsfB zvb*hOCO%E$BD<#BtJ1wNUaUFLJ(XJv+8xV@Z5^GpYTbvyX$!}QjQfg8v!#l)WrZ~x zw7y|6L|4LldA{ys>mtz!hQXz&#_Obx(CV(21c$f;Eo7J?Y=Sl5W> zSjjoX4cBpDUFTOdXtz`%wrcw(TbXK3im@&<0jG1^ zW%~7Ar|_zf^!`gfXl@9@KY$~>Ix%x;A&k8ZD*CZRLyqq19KT++cI58sOeeh$o;Z~6 zqn%Q+AYM70_xvG25XiI{k*UIEQ$vxQ#3YuayuQzC!tTf1{dPga?v#y%wBt%j!nege#e0?0ZJ01^TcMXdu0L&1{H$9^`Xj;rQ zw$SHLt!RUi6*D)xXLi;+J4qN#!%hVtD_KUE@f9frii0UP-Ij3RUYxp2BqcHD)Ok4X zXl)>lvrl^L%by_%&3rpjyR!QA1GB>iYD2ejNvWAG035h5V3dL${@YK;D1{kjajt2* zZONJI6d`)*KaoF0+V+B{BzW*$)wps0?yORixS?^iyvQi=)aj%C^GW-o1e62>lpZ|$ z9B8B+y8-X@6@8Cccb{nWt@Tx{u8&Eit}Z`Jjx-^v?3%p(9Yts;mx>83S7F@qg`0I+ zU%3tJ)}VtCT;xZKR^@UmL2%5m{rqjsEZ>C4uy7sXJ)j2hYHNI}j1k?|cxg6L)M_g`aqwH%>yYep}J7N(YBbDmWV)+XKm0k5ZrTslGoZo1*btQWC-hGou!5U zH(1dgoI)q>xj*b=A+^}5_Od6|D$i#n-2R7h3#v@;L zfYU^SQQFRcCYc$+vgzV5>jXI9$Q8S7u#ki>pZ=~K~YQRn1QFJq$)fpW{! zw8E^DO*UJO5PE4yZ4|EaQ#l6Hfv@7!Q^`e(LoyL1oT3KhPTQ8j?i`_3wZPjx*9O{M z8~l6R#LEAn@>rK@5_@gobVFAX5<=vp{ijEIP{3>8ooG(^R!y!hJ7`2#IM7R7$i!{B zq{SXuEtKIZlF#_}Rue<0xBblwjVn8<7C}d`(p%?+57sgb>##2@2Iuc~zWMSaykr6D zf0?e0j}A=I{(<}@Og(a~GeuQ-*}?GAwfu$E)wy9L)UJH#oG_I(n5RQqqOKN|1NF^W zsnh?4WyH0iq0G*ZgJA%AJ7)9UXQBFzxGy#7C5Y3X<5z~O^BZHWdv4jmcIlTJB`e6U zo5pvmt6Y9VecwHQlM2La4|Fa3^JLEAo9l_AA)m5Mepa&#WNCR-K<}+f-VqN?L&#E^5kt3%Hr$1Quw3C`I{T zSKLv>gx50^RHhAn0CjRmX4piw$w{c91;8U2{{|4BQ7VKaGp0HLuo?YUfxb@ zxvrZq8-?OR7?|LCV|mFE)sdpC`FvfO-Rr2-`GjBy3vvB>qIz{Op@_43uWVY$J{S;j zUa+myds8X0X6`B2)gE|mQ=Kltr4xd{m zcuIO7BX4S*j`as2A~Y34Ouo}7&}u#5J8Z>M$aeh&5VRlE#T$BqWN-oRU`7vvaEmeA z)x_*gZv|((2ncZ0dfY%(d4b7=X_zjAL-nh@Z4)eo*J6}qO5CAQP*ew_z& z;8*^V({z~)W}<#c(4xBZ<<(Q8N`1V+tX*C*x76`S7UH62M(3m#u$EST4+0E7_D%FT z9CV=~T`1yxYk9V*^%rJFp0%hi#WDAZ#bf`G>npOn667PpBnl@XLm}@|>)e?X zvcdgK#U09plZ>AB3JZeWogJ zt^`E_ZUo=BmULeODI6rnpV!6^=XeeIX6vVOKRsReEc-^dF@3cclYlF282&wPo3s3ixqmthI|2cZkAj{74&aYWom9^TX zM2VzGF@PipB4Y-?3?}z$PlaT~_Uu%jNyB{^GJsKXBm-J^)kGGxwhJzR&aj|9*+q8J4K7hKMYHPZoc8 zh`7a_mF%_Gmc8d!e;9M_>W%i%tKH0C3kYMq+{#krxqTKrHC6Gftt_)PgAdFds=<6x zH9kJ>Uby;4tnz~;qu{nYhB=JST(3MoaIqESCSxP3mO1gk%>!hu^{TbfiS$EC0cV;S zdcJTm_xNLp@rN-Z7*Jh|r}rJ-R_uyv^@G+E&i&3Fh}jy{o*yyPsv@W8p5aX^s9GRRe?ug0Cfc52cV6B0XUZc6$FMHngw1UkV%+05SMu+g5;Jd z!P8Cy67Z*r2}wdU5e5eY57Q@sEc+mD0nZB05+J5?MG&9>I~p2yaJYlZuWl2&f)cjb^{*)N45briX9u(e?0*kq3d2$Sy{0b5g z@V?tiDVVFx8!iq>w7M^QIM62oS*qTE~dNkhrXy?7!cmItK(d8zw(p)Ck3Uf z8GU}ZS>>bogVy0&QoYyOX-|)uUJ2XaCHab~S_Ga}O08UHgN$c(zjUSfQkQYf-(M4B zYDpD-$4OpgioecRJ%A}ZtAiC_^G)`_8OvG@2DA0smwl(EA1sXCs9$>>cHQbHPb;4Q z@ubwdMQg)B5he`MFm54k_$qP#u7csE$-b~401;s4rc7NHz9tNAu7?R{wLn6&K1G|u znOe0lB_{5i>D|7qXSC;XSkU*U;(@g6Ei8&$W-YiYUKjcrXU~6-I`J=W5pP{NyC<-z zr~kB?e1cfb>Bn~*#K*K>u)htYs+jGftzRP9+gsr^C7^{qu#Mfcs;;+Kyritx)O?&3 zddh)(jg3%D{s0ZN&MlMOwyPkULy_&c4sC}}pP@tH4_W@wAcT1I+X|WjqM|&cC|66W z&$=G5n9;XLI5Yfow62=oO>Hl_Y3EiQmX;bO`GbV1JoCr}$`d|Y6h9=UdFrdC2*Kva zw2yk4*{#=sNPm3*Oq;Sn@FQ(A}g&3t~7U^&3-i)ODf6ir_0Qg@V;k zG_NZJpCR(peuhSr^pjtcx1N2GS`>AK{CYyQPGqFnDSUUUS(OW3=TVfJT#IjG*+8xq z7fRk&TD4CPA11NnnJ@afF7L_ZEw&J?PrzL&3{hRsj z4BqV}V{6RZic94ookO-aKot+RQYx`;8ZX;Srj3k16($rbhl{np>`)s>>sl%KqEvA2 zZ?(P6aID>Gs+9~olHY88Sg;TDWpjt?pp6cQ!(MX>Bj-{Agb&U6$L9XYBrp@VuM5M& zN8L=Zc2~aBI&e1cbi{N#Jp9o3h>UN{{l(X!_J`!n7hHk4{p5YLTh(&C z{dpflPM}xo?$IaK`5v$^Qqyb*$*%?yK+>Z-#@fzb_?39hlLlj)SXWI&SHhX zwRFs#RQD=`ccng^+s2^+i*Ah^U|1flJ^pXFvzPBT+E>zQ-47OPig6M|OT89yg5Nt{ zdK)v0n-|ZpoA}S~upTFl+l&|&uiWjHo5AAmv$M?71;`eTVtSnNF_m)2XZ9@8S z&RZ|ObRT+R*k8r6`;Vd_WyjlnK3y9er5o9+Yr@%026UU<2i&Vi<6Q!t-cN5Vo1?Am z=Eg|6@!?QMGAr(_*NpE&x?ktZnM(<{rYoO2eEp8aYG=Rxy@IANRyyk zP`*5BP`&X^$2Roq7zju8v{%T{?z%r-No}!wZF5K3I5_lE=HViggmHvHE5zDdz;)CE z_BP(#cAzK7OGkvME!~;359X=#v{}&Rz?!U*%4P{dH7Dl(yg1XS)$c73f9Tn32xGl) z4X$FpSn{K0%PlM6`?&Zh_cpNvpTetm~;+-3K*>C5WfEZzOm#IL?MHQyE?gv)wOKodK17JYQ8r=oBV zPsPs9obea49hSX1Weej%C3AI@yBrQveL47-QK=CQ+cn`TyE!EFC0>90rHzBSfUeVp zqpd9TE2N^dx!xVBztFw7@WN~Tz2*1B?oCtV_5|t~iX5bK%+*1-%`1ds* z^j(*X-Ux_+S9W0r(qDo{$jvgg{gwbBh^n#%oh)*6qq(@qkLT9B&12@cON^M@(Rv>j zl5Y5u>7x#FpY@ZalGDZTaJ3>*x9qk-aKEm2fB$7B(Pm4`<=gezLWxx%aO11!^=_;3 z-c$LT;J+mYzff+`1seq6S5}ql)+$+!E^WHH&zGKeYHua|y{@{61%6-WN?#D`y{mJT zD5YSho}a&`k9L^6B%Y6d>9pC;=4huH*XV~o$_@o+tWR!Xu;_eZDRk8sVGvwzkiUG4i`u*LYlPCl2 zd>G%-J24n6AoXRR)U?(upFUwH3l6j2?ZihSja2}x&2jie`3~6{a%@#=l?F~=hOaT) z?%EZom)S({NiGV%B-H0%@b;~%;J43ovCWM;wSqF_*VFXu_s~J%&XM}gq3TL5LOV*+ z5^Kn-pev_L>9wMR7TrnX$E~hqX%Siqt)$kf&=%Ss$R0qeno*j#aE>GFx5ja);ky2TR%KC6)TYl2`3iN^l=c0~Df+0k zVG=ocN7@#AMuC%!2=B$x1NWtV)Bj2v?rA>doKH5q)8QTw8N=13?zj=3!F&I~veg$p z|IVsOX|Ly3V!Y933d(Kar@gwJYu;^1bG0@^#H2IVY#;`fhMUonvt2p8MJe>mGk7E9 zYM=8b3$H)8UI9O5W`V(8_S|#N^-+}BOQRTI0>gj6>XF&|YIs$e{ExM9Lan|)oXh6C zpHDI9!WzRTACkjYyedep^!2bn^UhJ=KEItC9-jY-EWb(&9{dC7%wGP;Jm_o-yUVn? ztCTxqSTg2U=Ki=jXyl)UR zJKJ?-Zn4FP*uU)^BlY)c?7V!#cx~?4l~J(DaMaEi!_IuWQc>K+{l$emRTX*?G(OqY zhoj90u%K$rMp-5I7Lo+Jyxo7vMJo;TKdkNx;k**%b_adW_(`v!`QabDg?*y{&OunI zC>y`nm7m({hn0=d>|d!v>HocQ_?&~4*6IYW)|9H;nX{c4G1pl-g(R$LdsVC|Depk| z)TMFCUM#0K-Uc#-V^`Nc3WRReY*V+Z_a0^u{^Ll;w&`5389ZpwJdr&u(&5eCmm;gO zj^%DzAKbcIlJRPS3savT>Ot|Ps!)M(A2W9>wC&?ET-F+}Z&!1wn7KAJr3qiI zmcnfLuo>2dUadebz#kYKW?BZ8R#&`(|Esm+$^``d<|cBX;_PO}0##d==>buz>-aL* zB>lMcijmd*s#QU|mfmQ*e9LP5TrQ98TAL{53;p<{fs$NPuMD9h<<-tRXrXGN)kS%& zE%@UO8*IXEPZD_lApc7nu?k0Ft}Yo{jj#_}vx_=@ctNLkE*gM0uF@qe!V)l{np`^| za7-O1Yjhikb*(3N@>`Xc7KSgJIC?AdB$0g0j9*cXXC-Fia8#fDI@qk?wr8?*eyeev z+He5309sH>3K}raSH2<*mm!)1B3i)uY)Q66EwSc*3p~d9D~D zB+lz?Rb}y7#lkxajVp@_sD!V(TI*_txBQ5rW5ODu(ETRS4kC>ie1w8g(M9#kj(t2} zrPc|oIa#PFCVuRWjS33WaFV62mueV80ZmMt$$2VkG=t?a+F#})g~cTH zJho?}l{~k;(S-79r84D$W#7(#^c?4aiDcGmMuhTh>KzApp!H*#wL5^6jl?%WkYkq6 zU6H^*vs2yw1G%_R8F=g>P{-}t?RzwrnaJ^Rc{veGGnzB+WZn5V% zDx*g&C6J58avWswHt#jUrg;_j4x-tjhy9*0mCmo5x^UE65o^Hfe*NbtRPnMQyQ@7? zL7p4f2ra|BZ4pTPdn{oHF%=ka{%0=5?QTIG8^KNB-iu}Cu731wy(}I0ft+yYxusi_ z%f>k%p)kLxuv{7P^8oHkzl6@v!QH7qvQJy~`>VA2A|rW-U@~N(U*yCHY(?rTkGV`W zHHiuHbeI;L&6j&rE|l=l3aK- z{bdcNl$+?NFPBUDtXqhV;Ca@Pn3_B?mXYl>qK$8V3Sq6ReX7lH&%tS^NsXd*PzTj&02MHNr7ytS_Qe< zWg5Fbciqn%cx$FNz}Rz#H~bGS>g;jJ8yILb+2tb->Lhw9$eByAzpR-smjywr3CS> zce8e+b%mR!k$uqC)^y#tcAuTxbl7XR-jS(EdG|?L$AQAa(aeJ64XOA(Io8uHv+LtOiat4}&Zv#2-iU%|iMSLiI; zoAzg<$#*In&3>QA{sNxgccZzT-b!+MAuM0rxNiQA^xC*?GY!92-KfT7xJ*eKOjPgO zSPr`~RpUBRao$ry;i`TwNRZ`d;84 zSS=3Seylkbw@JhuIosoq8a2Z{u1^;EkdlQPZ$1O5kfr8B5*`yW>`fa_2ePm~H#ph-%ce?glGt1f1-0i*lr^vC&h{tOZV{LYB z_)3GudD1_$=+635i?bS|6LpR+S<%?PmCGm6=nI`; zqLbkSUMtSKfT_JMv`#~*l7`lmE|G&X`|}2e@tvl_>oDPOXFrqV8_u< zPACC1^GJ~p&AO)7e50wWEUnfoR8~U#is&S#pkMV@RjHgjrm_jrbbV#&jko}&pWt9> zJkS;%3}@;CkO6jT5V?u{YDXdh2!q2tTnVWl-Vf}pmn_*H`tPC>0ciVc&9%CZ;6Npb zQDRyk6_14%G;26OGj1G;ELF&cRU6Qgs#OlPwGDXxkU(sN+>9&PWl5d-^+e=Uo`t^{ zL9Sb-X@hFq$tXo2jd*!Z$rSRy*^E{(^$NQL@U81Fv`lH)zC`cj#dnHm>ACNDe*ZhZ zdgf)h;m9!SY!Qk?PWLdfzMJF@mUjI^YwAKZS#$%XRZt-cLU>vVe7g zf~F^@=#|CUpulx*KJ+^mSgrn=DPvErQ^-44mGNcufD4(Oi(M$6{rHGj2S zj+bodyZW1rilVr?h3(C#aKmAc+^W%5Am~)yo^u%#P8x*0Pj0Kl@ZK8kZ&CQr)mF)^fi?}@#e*dtu{Po@*< zi}=}N{hF}$m%W>G7YE&(+}3xW*!J>-8YUSdeT;s0Gk=r*hRzN7_3hsKD&mS%b zy)KKpN#&{1cfg|VN6Idua#bCM!g9S7lpV#ww=BE|u~%JaAwO43T`h%%rcu1^*C5;x zu(SvU?p6pGY#1h_El6br5mQmo6tlEdP0|sf0Rc!BYZ5z6;`D9ln3$*&w}&fMvVLAp#!)4+R3)ZtZ8JVjyG#^S}$`A{ji?P zjX1stZyXhcI*#J@Mo5uwX}fKz1zJ-X*2A?87b;TAQ#yISR2MOw$rF83Ctr$dkuc9T zPLgV4*kihLYIvFU6FhF6^r+}$Glyx<{vj+U8s^ws??{S`Gu{<3pSV{YQD_Bj zYE#}|S+JNwK`3aCsbW=+<)rv;_iCy4U_dyI`p>pj@NFYe@`1#bBQJIfpeup8cD`QR`Z^rVri zy50=an_uSo^`6c8_8mxTx@gk12Ru;eTdH;SivdJ=&}@SMJjA^b8~`}``0u_`=J&){ zYf|hXd)L}UVOWK{cr_DXt8Z?G=h)d}ch-RPP@bqN(b2Z}Sh#;j)Q0*e^X!q4XE=#$ z=(o?J?8%}%vI`uZD@fbF*67C#YA2=}dm1sBrJO-TUQU)+zWwFht<{Vqw0h`EIpwm0 z{^hPqx0n=@2G{wPPbKSh&@IP9dnGnJrvD|?!>*#aHrkJ_aQC#A4-yF8S!bQgBy zC7P%uRf$_z?eI$Ms1kapJ$5G9D4737^D^3nz2n_y_;uOsJaYfWpG3{extVNn%pub1 z?bu2msHK%>UCnt>xwX%2i>28eQ|b`-6{;bp$EEY;R?lafWwyG!OYR>h+J_a^+s^AN zMm4*>ofC37lojO5p?qa%6&;X z1Rd{YI)N`pO;uCORuheqrjcgoB5pu%Fv`mf=9*7;*f_6cbeXP1;Y>qoz?Z_&psWV1~MY(a@F5t2M&b+;K=7<3v8<3yyWLRVv8^WxIh%fI5aJSs*;Zexs9dv|-fh4-E{LDxb&#Rjol_%oXZ3%)8rmUzH=&nqkQk;D7<-8yQNiCH&LvS!N69 zwptxRF@EGjU8>1~YTS}}ea4`{5o9g00teL&P`4$N4jgn6sp?%(wZX{XhLNM!5+cAtN!0*DV(d@?+f`)f z*$RZ&;*j@frzgO>pZ_>K*@o^47?2%bF%gsZWdr!=!HVfs04tu_?EW5$GJx|G0JtVv zy1**RQ=N#17$_^MAn$1KV8ae!=OlefcGOE8ISX9&YJll&Ht1s#j{L~hx1oI_J}I;$ zG($>N!Rw2+E~)3=AW3SZ>PB799dp5rQMs}1;cRDX^Of5AcgVi{vPc_dmp$6eGIy4X z*h*gU%FXB3`76T?TzuF`HGZmy)?T)@5cS=B#_C`tFIZnk+LPVGSGt|Cg)osyx zt0A_%FZyT<@J5ps$1$~G0Z^T`-j)lhxLStW258BW%fL+3e5WU`|FDD3d1ANXg34<+ zWYxqSS}*_(o6nK8!h@2$n&TB{Df_^#u#NG3Mk#~3hwP{nOV_jq{g0Y-qos{Ed1R7I&gDtJ(zTVqKp5A7C8VA=mGc5UR!!SQ@_Ilr=eT9WINb;JB4#K*fN&b_0iObGY-7d&DYNvA{oBQ z)Z~2InCCBHcDGS=Q#iIU-JF!o7x?S&Ct_9PT9WeAyd$P5i3sc0mbjFA5zm2glo^`k z9n=X4D3s^}(WQhd;|l_1zD!pVy_^D`VZyR`T18$!hkmRr31#@YQ$*dN42 zL7|E|U${)dLY8vjBNDS@d;AWBu_Y=$wYhw0-736zSw`}VW1(cc+-YuVwR}y^+KYQ8 zIO$8b8mS|m(|X!We{mdF>zMVKqQ3NCu%dbgISidGmx?`as|7=Z2kuCFcb_~V8|D99 z>Td5b)K`(fjLNKX#IETUnI&lCCVrOL#s71-8~Qwbat}T=wC4dNNu1EK{mboP2e6bu zgU;Uj{-)QXj`Vlq41VS%a~+&&y%u|V`nuqkaLL&%D>i+l7)IlP4fOA;_`7qEpN>Df z)7`2mtW*7z;P84jYSrvhV0BFF79qo(ZfjDzn`++Dc*dU{Uc;E;l-;_wSz}8N8hO7+ zVrX-MEWMo`_1{>e>6t5Ip1ArZ)JqbWc?8RC0+lnO}{1T zSxYI_mxT^GH57YJme|mN?-tbS~*a96iIJIS%T$vQ+bnwzsQUe6|z7X15#^ zM9kvtf$E{Uk53$|+Z8(xy?zPSKh$^TtW2@CVm;6tGj{P%- zZ1MwmvnURuj#9{Uq@X1KiIkRw8*sN1q0tQXT*VhqMsDTwR0%zLmjL9OX2a8gXW)H7 zXaewv6{EK;i&3!3mP1bTF{oI@f~szE($)yZvt)tCwHfHb7VTyVS6e_+>-vW3GEHRW zB7@b&)rpd9zWMt4C1Zcv6gTzVcre-cvk@mVIj0|MqTV|-*%RA|%_$pQnNSvT@ms5f zj?MO{67`T8Di?6(#}UI0T$Qa-d;%!KPNhLgJ@=E~IQY76)fTK<-*38mh#|t&NS6^}+?S`NYMx)c$i^?z8u3tos@;rT&+38REDN z?Aokp_ngfJsLySqk}15E+s_dYfd`oXT;VQBZY+RG*57rjPJ^-7q_**s2y-I5=iJz- z74_W_)bhe3$=&>pB9GTT{_k_ljB%g-BI6GS-+c$^9vZpebCo;Md2iXip*>+?1?$!- z+lN}rE}XX(_p@8r5+%^5Pyg}V>a&kWt>p=AsEg|tI-7qdE^a-3Bcf+VCtEqWSj-f9 z!k=HTFP-q^)urOK$yz=7N>O-up;owgwE!p#HWaV+@;G(j?eXRG{sOgnZ+zx|=qoD+ z`YzIaT|i4;x8d^7N=vtt(N1Bp^Te=KRg!Oy)!JL9gGYI`QNF!YdAc4poU;&iI>ep*s^Ir?a!(8OS&(dZOt&jQ&nlBxpG)E7aDfb?f{7KhGkvF=YzEn zqpJ|YClB#UIiH*unH~MkoS&~0R_uDHv*O4vGRcp_#_ zULH(s@*2r@R&hida2a9o<7PD{qE*^fCivKCx5Ao9R6X?FhDSlwJ_jvH%-{WQ3Z)F^BSMU8Iy{KqY~dX{GCh_xt1%|&>y2betW`zZYO~N98pT;Sbp~*#t#(;Uf z99a6{`N7VN_L2ndsPJ_dq0$R~GnThp7?K% zbl#?$2Mw>&_kbjUp_+Kq^cj7<9K97Z*P#%wR2YF_Z z=K}{eOzuJX>Zn|nwwwPYBV~|>>CPZs+~&XeYWp4>cv21zdwW^7K3Giga^cYLAHW5l zX6qK&{a)K!IZ_&VuT}HnGc3|WGg`OlX0gu&_P!j0rL~#M@D7ZCIhYJMsd}wmC(Y@k zCQ!f2SmlS}=+?6GeektGGfURIX=BoAP$tJDn2eKJMF^TKn{@@Li@vBK{OZPQovV6H z6#Bq+R*vqJto=4)8({Yp!D@9?o1Sdsef_<1?5q@zo=UDWr6IP)L0^e%tT(*dcLaO* za%%}?#c)Moqn(!gy9%JQ;o_R(JS@B>@Rr&L#?s)wmj8Oz-Pj$=NA;Go+P;Vs?P>!nv8Jst|mAiAkUt#%l!NA8f8>v#z6F=ktGa(w$o6 ziF?`d+O2}`|H%aP!hk6nA=z@;eHHkkUD*=rFkwr4mCTQ4LVGD%e&9&E`CLt8stI3b z562~l_!f+*)~g1U5Z=qb2(D<3?G6iEmo|1?iJ<;(CKsM_%^vpgw!FVOw;A``_aAo$ z=eE_2j+}&Et$82}A^gVz4K z0NaqkTZLfJ4bu;3b9K&}sm7<|t#7^iA1BHv+?+l`z%t1rjv0O!bdLD{Q@M3Q zsmI)Q$mz;t>*!7D)zMOMobPN_jo}yL$2uqfWL|&%ce3N=dVc#y$CI7P?wQZ$?>s=h z_T-;tzrV1Df3!C|Tk6J&Qoa3+di2%s21QU8Hde<{nxifL&Yo2X?{$H+d#~Z6;SFs^vXHI=dbVN<^I5^S* zkV2O$46s=YJ5^mD(&WhT7Qo-~jTbvK71&5rs8^^xn*fR-%T|>*+q= zVg|Gqfc5L@Wm{1_#?6@x8deW5vu|nb+m;?}OO*{3_jQE*b%(4@HpW{o*6TYSOszUs z8z)|i!WX*Hy71fZD6M0^6eh!?Sp1qrR3(>7KYn9fsvPL1*r*;YB#3#_wz@&@w#clt zWrnAn4sG6O-P_(yqiYpw;BD46EawOJar##DFFMJc>awsA*Q0#De+WqEDWWS+K?8kj zC1Wq*vAUw&1}kO}&31ZclxfcWy*gCftj)}rwp4p~o>~(Qs=rdyw|CcfGZpJ3D_m&; z2w3-1HXr+tVZfrI%%f)Cg z)+FKkScRdXVjw$u32dF7K%hBi+Ver>zGw@L(rb01Cq^uUSB61oqQ=aY?IY}-Z6WK# z@grwl9uoTO{-M`a_)&ZI+m4goEH(tN>#XkI2y@c5wX_0+FT7u`u)YlAS)^Z<-d+dk z<+oN#F*hU3$5ej_K&ja?`5WMZWSnA7?$|Ri39Qi>8!m)zs9o)Nz-9BS z??9uCzN$5dZBSCmUw=jQ^k0{{=OV{y13Pu;YlUu@YBLa%(i;Y@Dqn}5a#x8Q&B)=X zBY<5(UxR1Uj1Xq|h~1 zc~YF*YrRBvIN38a$}6Y#70s}KqRiKufgbq4yLNr75MQlFtHK!rx^gxOy$HX}7aT;t z>;tVb6?Z3TFg*lA38}_ko0X#d_Qs}#m3pMU8=~RDtvo~E|T&evxgs^;VWqL7`2(@GPq5HiokXw08d^zJ@Z?uwg){W!AdSUaW z%J?)n4ya7b=xBJo)}ow^U4FEQzxE*fZjm?1YFBR~y-a=;Sh$)Bx3K0LJI(yH0O#Kh zS0KSr9q#W8W_Pg`Qhcm3U#hasgZ;?;(>%l9fga-a>dRcWtVA_SP*~kG>Q-nJ0NmK* zM8~J04iTLLp*D}(aI>@weWEG??5tgYD}kgjq(vXFB!Df!45)AKcmqeqMOp*Sl>m9e zK-WU>4>PtVIlgBpbxCN5-q`8$4%Bf>RUx~5pqhm(uzxAXV4I?K)9Tb?X!&R!;&BzN z?Ldc$Bn&HXy1IlIL_5L^#z5SeGVj4$Qv%Setwa`xE9jv@8t@krs9DfX$jvZR6iXB| z(+G4w@LUuY_zlJjbt4IRE0mc~R?W5{!?V$bBDto4A*&g}&d3XK4A5QbuB{RwSw#U( zeFzIU>XI#YG*obP$KnNpWnCD~1{z%uT*CtX93{D;M-!;w>ij+jB4wY|XBvVlF*fa> zkrj*5s0>aH3p6Gyj1MSDY_&zkvRJsIhZ+y9Q&AUL-qK;773vBh8Vc!5xOk+2wvuNM zRRP>Ku!jVQK(rOp6f9q01YZ*w5e4_LPKmIIG!*SO4RfGzV%Nhkqc6bEsyZRZsnj{0 zE?%(?<*qI;P{2_or~*AAA~A(6MiJ{}b)#sQ@M>yWfZG5cf?S2npRMzTE)-MK zYT8_ZP^H*(MT3Oqw<&!ZH8yRb4f+-1)Ay(ZKOn6dGaYrHlUhUOTPV1nZ56(#78veS zNs}bXJRwDyg66F2ToF@`$wdw+gbjBeWTT1;zi`D#AP%nakWi&c&_B!JuN!0>`fV_Xm= z0^aj>qEH+ys;U9QYy`nPN!zN)^D-WqA{LhGqP(^Z^ifjL8-!lqAwkHPx5*j!2$(dY z!mb=(es9+mA8a5J1+#JsjMg0yU;wbJ;r>y{fYK79@Hya!Hnq znVPK+h`7QrEUz;=QcC^MTlJ7vi)1UnIs`|OAzWUerL1<%q{mXWQWkv9a@9M5%y~-0 zeZG29mjSTwUYMI4+jEu6s!;&MDsG#KUHq`7=^~=rApq6xrUCyi}>66kL_cNj}Fe zEtI<~l%-UTgB$9hImD7*0T&0))#>{CST!t>@Rll}e|RtKuAwbnFkQ7EuHMs=Yq-)p zUsL`&UD5XY*$@BJ_eBC+L-1fQ^0ju|p`%3Kv~liBQ4C&)%9xU{*{H6Ibl4!{qZ(D>7oDx>^b*)-nEIZM6!fajTD#@za)Trqw~bH0IIT^F#UNKp`<&SvlFGMdWgwFPl|FTRi()jgmDQAGsR0 z_C3;`0_N?NKfg^c;PqSZXlfWY8Zj;9-=!qQymzo~Sh?TrmCjld+xHc&Q0@Lqk9 zvvTwT8rF%_>VgPC9G+q`4<9DCW@}=>tgxF}H_dEV>*jA)kqwjVC%N`L4!4Mr^)o|7 zZ*Q(@%qtrZBJTakus)4S*Tb8bf%;S23`gS~Z0FC;n^$|F+DJ?bh*TA7CB1AW6;Oxcc8?E#yfyqwC zg}i2hd)-nTQ-GouF-CQGpjrS**NOjMO146q-V6t{Ob|QDSqj*KCdlkj*;8QBY2k7N zK4JBmh7eIoE3Wh>u2SLwLh(Jw0t+2S>0^oSQWJNB>6wfaI(#9tw?qiGX#2R1cmR)t zR2~+AE-8@dbcgG@+$M$Q|7kTxvN5LJSEWG2t$ zsx(Jb@#?O-x|D}WO7-lGtrrf+`1O;ryXg!t(#7@K)AAD$GTvcYY<|saOb(b*Gn0bv zRkr5z{BHi?JI^k^Gw1xOd8JS97JBgAco1X$k-_cGG@kr^{p5hUqF+E$ zBVDAr6&p^;l2HhQ85<5RdcOqZrl3Ft!)jX=OX0Q1+QXn?ZSzzLxAqaVaeP(p?s9NY zc8um+H+0=5FF2hZ4BnJ3n8jqI8dr8h=A}?ZRih)NJ-B|h51Www$Z^sj*0q6c_SIf5 zC^SObEV?mk))F|W1Di2OmeQo|1bp(y+8=k>Q0>!^%*R|Pwual?)T%QL*90T5bg zhXa2NLBa{9ZS5#`BoKGu8b_*jlY(eDUJd}Y347HP9A$E-Nw})kwJNmBP1OkJjm3R< zm2f~c6&WgkOaL4rWl#oIq1t^?-i%$w@o4U2@6p7Cf9(l&A37z0ZrO{0?j{BT zA+m37Nx-&%%7MaFMaP6@TCj6F6d^iiKqRUI2Ta0YTs4MWn5Dz2ghEu2Rau@gAXJOP zc+8ry(S0bw0*<*WvmF zy)9pXow;Me1KvJuGjM&jB`BN;PzYh6{J>u`Ee-H;?%vM@hL_As9L2$y+72(lnuOpb zJ1E&eJ5jueaO{GL9F-IWG71pYgwr7!n4g}x7!-abo6D&VZb=h1{zDegHyne^E+K+ADt z+1s)R4nB37%!6671dT4$X1Iop+uN)haAa>~q^Kud9?s7!Dgt22#Vt&MRk?$p<`T+F z0ze3YS=p;Po}S8DVHC0E8hoDZB@YB5)q<*SQEFtL00qY+LW@&-x}t~^0rDPAn8bsA z1Ps!Y1i&m`=KA?a!lRt}^VZ%xrVlTB^M<7Fe0!sR>1U~CP+x1DZ zssLPqiy?B!ilw^Fxa`|&ZVGOD-V#8ANGbC!ul0}^yDIWeYj;KY&sh@P@Y!AyJ`=9K z8T}H@6gq||@W?wsMd>66miILH0lm_8Uy37S#Bm?vZ|W|=K|liF^KG^dTOozeC8_M;In<74a!K=(&0 z>{YoMsyU6jclga|_=NGi5Fh*Kcm?)^euJHK`XGJCc~_&1a$&QBk6+Qir;6m%nP&VH zEZMNwXXyMZ%cplYEc->CO2}SVV@&zQrDgI?#br%!m`i<7|tqNi5X=~1k)8Ht# zT5m zLDtv#!MU2hM0nVCx}N>7u1Y4%g`W^_6K(p;K7S(&jyioYCLM(GmtH=O9>T;YxIi&i zdbgbxK0I)jk5N=NH2B(vD50kB`X7wo;>^|jAyEdv^kdc~kmqgw206ZQ^I9Ww&ieUE z2b!OBen(#QS^2UwyEpJ}s(3d}x}$LC`V&)e5dw*OO1_d=%`l@8*I-cK!n#$?gv(YF zW;k$FRVpy-F+44Aae#EN)8GydN@Lmjxuw}OX6h=upKzYDA$SI9CzhCk1+pRAO`3@S zeWCiiZ}KA0@mMHwDGbJg*40ux7lXk7g5Vf@4lJE+`87Ky+~7jS_Bq4H^nyo1{XpXY z51LrYd30iS1=hyc)X^B$Wv{?v$_(h1^(oEKf_D&*+Oz{8z>^jREv*3dTOl-9B`$Da zPI>aFpBo#O35F*>l_g1f?sZaNAE^}RJJhhqsUZ%2tdskZ-!ZE?7)@6DSLH__C~i8{ ztkTYn_3G9m{PeIToap3lb2zJZjGqOYjGFRdH7Ut^kke4?1hdPW{h~gH zajd-NB*h4cx}1t{fz1@ouiNsap2IMmv9RUveD;AIL{Ni@udyNv0yV3_s5jkyEx8B= z&80da@9I)Xv?nViXVMi=_4J%6Fmu zps!LfZQ>er9v^=o?=x#k2ncT=AyR~T65F}{uLz{cxo`~L9Ph?M&UVwH4)<0;5T_Aa z2DcQyo`~IOqRc*F8Ho+IIG5gQnpgvjC$&oMziTj-8(>2 zC4BG@3jJwy?YKQU-2euoKqAoA0$4=MQ3BWIzP;RsgObAV6i&?hS-nkg4KItmXOMxj z&usM&DUm6vb6K`2mzI}V&>eUxbDe2YtQ0u5l(wOph#oC*lFaw`7z|pCt_KPhwPy(uslgPnvkZ6`G*zlLYnOfIiA+AB` zJ({k=TgcU_`>v9}e53-36sNUjOmalPkWxm@xT|Fdy&rdPY@E8in8yW;Mub|L#zcRw zLuw$$T}hMmlAV1Y+LR-?ElzpL$^mtx>ts=~9kKAtMv?!Ix%ZBeqq^3`t9ul%F~&q= zz~r1HFh~LkNuw}PlT*)h&bg~Yg|6zZ?&|L9oa6N5tdTUz0YxO4C~`8`WCITO8iO-9 z;d;CM?z(TiwchXF_j|q8=+oY3pHul%oqhKC_7MWZBT^uwk6{L_2e)pa9^!o}Ya>l? zy^Ox^UIz;LUEN$u^VKk+W@6)ema=CYw$6@J8`~ z8YcJRminB{x%dFw4%fE!%}eE&&ll_(ZD|rA{S^g1$cT%L6h^h2k;^vGdT}3k0OeBs z21y&lhsn2g-kaJ)nDusjJNT6H5^RIjU^LqsTqbY?HYrWLKrjIbmPnw=$%YbMV887d zbSgGNl0n;;rulAPi)SOLHVsBKgPrDnYt6RZ`BsmGsZrp#%tE;AQ)3Ek?Wj{nH-Wd8}$Q&^2dR5XlMu7 zqlNYRGLhJ&08XJ^+{{5pC+Uz|>=O5oTee+gP@5BI1-R0HWEtW)jTRI>pX_~M2p=<; z<9apg(31vQO|nvawKGJ19*=NQ_Cq$8)jD9cEGYZIYOFMns%$$>~uIJ zq^JX?6X9lc2gGJ=w`RcTwBh~m?bGE`S~uxA)rP{sjS9Li9)?}s7WFU_GI7oGq-{gk+|sovPtZ!<8Ia%;-w z&VDbUkv7S;Y#!h4*K1l9*E$IoX+s%GG}L0$_y@Nd?4yI5sE}#U=ix5*9Gcn`Aen<0zNtf&1w*EkrL)!1|SIg1zoY^h)V(r`LwHpULMOcU_ zgOt_X_WC<*^RYW!+uC|fn;Z>myF^Z0XPbunAkB_gN)dbbxaUx;A7+aU!|NTssJwA~ z()+kef4k$(L5uaCsIRFkRW$e;v^sH2;o6eM^O3z~d(Y!^D~IbXdsLFPCWteYW%a`` zfz!NOoYfpx$2&Ym@G*5TD&4{LkKsP4o3qPSZ;Kpy30_I~V0({Q+SD9oTTNnymUcbj zNvc_8ytN7K0p=MMwM|RUdfE_Ja|TS3`N7_Cj3mW&}L+a?*Sg(o3 zmN|BW1gW7~x2l_iZd`3) z;+quL6J!IaU{*X;@^G=b(8M%2=U?a*}5JLHR9sKoA*UG37cq_Z!% z1=zy+O`UdP{g9|n{`iohU4c2B1CX`}(oo_%R7npdl3VoJ!GLm9FWs{0@t$yRqZQ(E zlwCbqzni+-taKVSv5u`={~b=q4cp!t)%4&7<#*FcS%z|uGDrPBz0K%TKHv+5I6y~{sre@c6pa&T*`9%+R?a{)jE~-zN>~j`3Kp@^W zYi!V#e_(J3ZSgAxA=urhv^Lx}WXjkXt!tvCy%Q;K^0s6pqODkLjc2XG$mNH2apKk}wZe<2JVC`XI2T&1zD44K~bp4McDD5s(?dh^qQg z3jHbvB2|_Nb*1=0i5hZ7Tai77K3HAIBs+%}fuFlu}xU zV^AwHSWP6wh)LUkEda0ReyzRF9@Q%_@g@uOUm8SX*Jb5;jr}22yIt)=O-d20hf%75 zRRuMBAxKe;Q)c5flTOylcC^QF!Y`*a4x)*vL8F!1#&eK8N-5ukkieO>}c>g~&Y z#*Ayb%@T*f`G~ZC&8mUGAmj-))+725WOl&q?AkU`>(C8wHyJIX+Cfe)QMXCy!PZfQ z%c#uwH4@naO>1S!dYfOVg@*}k(mAABv&Ycax;2BXm9khpkco)8e{* z*3zwJ9QcBTxWSUL(=L<7W>NLkYgUVQEIBiJz0Gd%+11U~-Z^CeMWs%AN1T;*`ny)H z7du|P7PS#CHk$0s&9G*gw$Rk}6I-&MJ%K46ge;-#&;n4C zuZ2;&73)Xsx(1cOsWo@2ZQE7t28|jha-D4&BH6n`6O}`_a}Nn?I>ja7<~j2s9s%NCMhARfW{t!kRRLM*j&<@LlX?IaABGi5z4I|}gHfV-6$Huy3$}rl z^aEX?NsKp%cl4PR+E%?&Z4&EM#_ipjZ3;Q?0Xh5ako7HrCheRS76B*}6Izp;HX0xn zLEFiu2DGNNu+GD)Wm>vhf$4Ne22pKV+78*6iEniFb)puBMq`&bEGSBe-0H3nEZ;_2 ztR1La2f<1Xxx|(j3YZ#{EyiY@{j(w>|F!_R^n9=2_V4rjr4P;^&VM1urGK77{(c1T z-g^b&%K!sUBj0@*?4%b2;snT{Rf6f0fPd^lltR!8qk=Ck{uh6#OplD%K_9z8@W9=m z|I-7)*HDl*Dv{7yzzs5F%nbUgl!9-jV0-`CBq06*SiDRCi=mNA&o&}*C6u?`F5tfb z`I65Bwp#(|y9M`u2JQP|$QOTx@^>PF`(B57H~m)d^)kSxt`jzI1iJ%^g5!QD-~9n{ z=mEf+UlHg-P;c)Gi1{**#jN0yZb0r$0kaqEO{2)2`#|1wUU=vC0PpJ+%$7iZwG(+X z2J%1uA-L-p;N2f1jT*q5Pw)=~lz(nQ{%{&_&ndyD@5A=rNC-Y}0c?&4^^bs^>`Ua~ z#{geFB`|e>{9uc5=jo`Ty)LVF@F7p9k;HQG`slo0)R|r4;0LniYMd;f3+x!E8 z`gPE&uM}KbJI{-+AzSVP`M|FQ-y=YNffe3xDc~0*vfc*z)ds=LlYoDH5lQX<{lK_T zGXr?*JIJbM0DmY$R=oh&bsTx|5a1`HP;uX|Mq5OM7fo=`pT|Yk@P#A}wI!hscM21bt%)IdC6f@fyMS z5wP!cAgS8^-FSykvJ&J53+bAZ1=&9!ppkg{8p|O^wrL0oU(A-dYXqw*5fB)r0(-^TItO;CD6%E8T$8&j{Xl8?e6# z`Qmo4lOzROmjGQp!Asu(oLVJtOasF8yYEuK7hXipH-df7FNE=nV7tq{BfQNA`Y*2# zto{+~@5M97#n*wnazgNE5bU};1>dVZzng=C_CG^;*IP*9HYlI$7XHNp$MM^X1l09V z{_Lz^sD0M0YjVeP4r&zXJNBoq|a1d>79n>w96l+5N&@m%w$t>O*8@ z?YhMbf?pg1`~*W@*b4Q2><~2l5oF|QL17Z?cBYUAe+TtH8WFmF3*~=*TwqxR^0m(+ zG8f37ZWXSp^;a)d1Yhn3?0g0}b_3`w9t84+AeSb;M0%zHw|tCzSi8=*E+WTk*Y`cU zp!^zaXRuRn@2>#A`mNwZt)AprL3|AC_x&Ade+%UAoSB?YLKaD)p40`q7kgFq5zp`9FOF=K6M%s=6cBPRA*8^79 z3PiQ@aLZMKYXV^R>93K0eGF*5OK|)o?CjAh4_e z%pFEv{0h*yQ82I_@LO*oTiyb^_7GC0!2W0N3I6^r)X(o0tbG;qnFGi|t$+LLV*+LE zdG0-kd{h9v;10ob?Y?^a`@*x^06&@#JQ0ENuEPRDt$*xTKukf9KlmqdcNogwy-aYn zcHHOwEV!Hp`CsoL|8T=~rsRT+wf<|*yU4G<2e`O|oc<-?RS~4=dBChj&^-w44RXku zO;CU3je_6a0_Y4P;x@p?zCvVALis~Dvc3uIt3ttbH-Y{q2ZSd(;C{u8!htnV{#jnI z@e(MPye}yH3*@601eev`A7^;sU;YlbPcC@*V<^A&1Ef3%a%Z1l{|xM3;WOl$gJ8c> zg^&p7?^q{%r(qd9hgS;xwf^D6GlJu_`{#GR61;Z<*me1l3z5sZp@*T}OHzWK zcL2Bl8o}>?a?P)iW3~JDL`YzM0PHT!3(6luIT;n~Z3nzzvtWKL;O;$0&&_}nI|Pfh z_crqX#t&XS$caDiU~2pGo!PfDHB@xSrfaxI{PV*#{MSXsXKL8}#2?l*$Z z{pa6mczpLyp#Mge!GHh#`#sO|E8%~C_%DQRRGR!WgiZR|3=H#3q%0C$| zd-KXJ6~=eMM!&=W@fjvxy2Yn^uP^VBSV*eo+zd9@X_Xuef? z;5)poTGUJ9H+Ar0TimQNm=KM|sd27%p@`GiWe$Fq#d%NgP#UHYX84hu3d= zw6nVnVzdZ^ft>W@Hk*`}LAt+&yIpFe;mWm=XJ6TWjz8r)8izCpYF=Zpo0<7wlJ_U( zGs7p3^dP6$(2OUF?L=$=idMR(iu`%59QN`){e$v>yTv239s_^nnaf-)# z&o~1E<`%xy3gp61M_Lgv1R=UKsDU@yC3fHhHS;>PQyuDie3Acd|8>h<1cvbhJ?llS zR(2T^;gg{hk>`g4cCT(i*(q(k2f0s%-0DWI5Sg`>fQ{uTGm0wonr9G$jW*)Fgo(Gf z45ZJ(7tXpcsU$59@utgo$bks6_f{UJP;jT+o#tas zt2<+VcnGog$WunEQG-B^G^0$~a})AtM^~d*ZS(VEX4awFt1cmN@-Xgo2g}Gz;?05q z5o=Ca;vbH6BJIXToyn#{|895i&ftky-|aFP-v^lwO>T^@Cny+x-_<|HN7)xxN=8Nb zjPVW?sY7GDE|7FjTyNr+B%L@$Vvbw+eh#&`Rxu3kcQjh1$dKtF14NO8QlT)nHS3i!dy6VQ8?qPXacB@*94J7#p5XRv?LT}Oc@giBj1~Fjh!i~CU4zPd zkgHmIn+-nh1h3X&78H_CAx4!=m*A7uZV06UZbWN@=YUY-j)?$2(VgxxL{>YFBGH8x zb}L~0;>EHsA9Tm4IPXa&c^#0eiBcN zAAdhS!Cx!e?0(_MS~R4Homvx+bxB$au8vHkajKSaPuCDAyK@y6}h}=bIb5XIe+bUGX1SCo!iV4PCG^; zgu$uSz2yMXnGo-h8f>-}AOjU!6*i6z&+=p8wjiaV!+Zpv3W;`@cOV<}Fh8f&g!wsA zYBX&!Sotoy!EA7%P5f<|h+>~qd489S|72P((d!VIR;Jg9wPIccWNAJu9XZQK>4ktq zit~zXu*gsByn?qtc$;UGE%K=t>r4O1ZQ=d?$&86G4fA@7)IP?ii3g#%uACJP9$8(spSR->mLY4f~8$K4yx!wQ`M& zm*{&9PCe@3Su#NmONaOeSEndZtV#Pk;*2$*un@<|d(4zswcKduP2wh4UNkVstJGfW z&I^h0A4ms~2jz`A2ADO|Cb;j#e7m#DAla%ILX-+f5FfB0qwyiul$o`>&UckRY8|-0 zSA@t!n_x{q@3v1mWqz&IVhriX8hi*E>Y*}NIgswV!TE72MxO=AjX(cUYGZg z%64Th(xVs>%bt_ch}Ukn(OTyp=lNsRca&SyHbfHsG$P)lTh7~e$Z?fez6NQT_^PB7 ztA-G@P6o?xWc*KaXMc0Zt)j^dJZkg>e#w~-RNN`IcItY0vA)$HYHW7$cS@Rf1nfTk z$cq6-NHt{ZLpo6i48?sE?})_g^^fY1M|gd5Smg5QkUkg0#lKHN2f`jrxJ4Bke}WxP z*CT6W{}MB5zsKjA<5PAFH+LE2yc!7eRn2mmZ^c=C$kY?(z0RU4Z=9+ z`W;$7Z!<2VJj31q&xXd6r(?^${sz9=-&EJ#a4md4|LE)G`={ai-cQ!mT>yMCD%gmE zepBnRy|wYoWv>YCt&OjaZ595-4fyefl_MIk+xS<(Y;Bx+;PMq8{tfVl>zB{f{6Z_1 z3-|pK>YZA<;y3%?JKgiaijGTRd$CQzH{hG{()KHb-~Iu7hyVRQ>eAbw{GH_&{p901 z@IP6WMQh{wzkG=lr=a|;CzprshxXRKu;R`y0B`?(-GysmyHDLDysrf1#SetTH$nY> z{8I4oLD2h*D`Zzd{revjuCMu(UgB0XzYOD^qD`=M4D2sEQ#WS<{hM^1=`N7_zF(L6 z9oYXvRd>_}`j5pcZx_LS9KBvxs`=+$t^f9~UWNM4=Ict=f!*KUUU6w{{Pe|Yp}yv) z_|{i~drrglPkvjth=Km(^>s%Nfc^tc=%@!-t`=NZ^K)&C2yU#6*M9%8;J$01e02HB zEgrxnN1dWJ{?A-q_m}N}pNN)y@-sLN`P0kti_q@szY8za#@)X-B|MD+Ca)E$=fF;M z_B&&>@#mXcmwkR5_D^udvNaYc7k1Y1wQ=pI$z_$@P_B4oWoPZUjxlv}wdo+`MqZCt#=iLh!Ge|Ka3K%i4Yo^}qjd-B;fNG<;e&x&!ptQ32fncEwi( z&-1XoZ*N{+Y&u2i^SguoCn` zpVzr=1o?2kaQ#=%-u6Xd!Ugg^rtX`0C_i?;;Nsf2_>67&uQJf?OZ$+Mwc~svBZ$@f zGS7D{KUxQR>o+TIx)1ELtLh|g0Y3P9f%y$M{wMyqylDa2+jOb$v%dmvJF)Dy?}Gh6 zQTRR%^4~5jzw;Ozcc@Q@)~t~kiWBR*;LIBG5goL*K7Cjoo@?&^bp9%w}r2*f_mpm$mKP^ zUE|$#Z`eTAwya3h&I9o$!OMRK+}*hRCpEvo=KeZ*6wXurs^tgEV4vN(GL?h<*!c66 zk9`c~_cSek?^D2Azpg`Wg5!)F6pVchcDGz1++Mr??>;Ylx#kZT4PLZlh2y${|4$gFIj&1)quB^1o_&1_m7W|8)|;LWnb3~{S4#} zH!d4`0%VDxuCWc|@2Q30CPgm&kNUcw?S%HuT_hX}K>5)Xf^Ys4^mcC9n%eXC$~(gD znxE&3TkG!m2KN8cW0wpa2mPtvt@uFz_UrV|g==d4#B-tLct6PJ-Vsbb0OhycxAF(= zpugo0f~K0^;@8Jl-hUR(M-L`Q{1mqH&KV(z!*&k6|E(1@Kh4vkx``;*xt6V1{1M2` z?=HLYVz9e&qi~H9^j~L%)>dfuPfc}rci(0lq`|IYuWjGD?hd->l?L2IM@onKp&jMch z?K;h?V7KCe;PeDwbLa9mZio86zel*s2Kd{rmV5i4-FE--IW3&0%2Rds9)k83{wTP- zb{>BC&_yqQ3FV=S>xkNYzWpk}b(h2bzPPDwrv$cl?0(^UzXg3?!;05ye*ITd!rROs zlZ86|r%?a()pcLj`Y)ll?nkxbT)6t;AKwdl@}jzimqGvXhZoP){8M*tT>eDOkN3?o zVQ;N}P-yDd>!2L2YmXH6=g_Z~g|CPGYq(_PGq1q@`~ngD;aadaZWlgP^B2AQrQqj( z1N`P=VX1cA&%ZC&aTVCzyiEAwHqd(-R(|m{?C-S)h2sWj$M>>uxaRL3-?glA1j?_J z)V*nQvL+9$WGN`x7v%L9oDBrVf**5uK!O!^ait+&L z$GvmQ_Sfcfa^i3Gp@8-)gOxBmxHHihe=?W!sav50#H@Xem{Oo>@k$bXnak^s<(Y8sZJRBUF zB9d~_>3XRpC?8qsbY@ll$NiiPw~j(OvTc6T6Qj?QC$Yf%tCbTLOC> z6H4n)>#YUfFVe474jjrXQCe|=8N6`z&CwB~Y@$u`T-!voH0(FZKa z9-9dpVSSl&t3PT#QZQ269oc+dJHk27;j|~G3szqVu#DY#R86$OO4+K}sCa$YnCWLj zkx&{J>5_O{mPtxO*qHZ;`D|XKoiqk^&F6wdM47o=+gu7>`sREKqxUb9HTOfH5`f1uV?UxE0hc~ekz#A&ESKfs5kEN zMH$Q=jD_6ZgfGpY3yd#jWYbYk(3gT74i4HK&6NqrCF+bhJh`b7=QM}h_-VgCmhmzg zZ-%lsLLBG9cjEqRI_OJ>IU*dEGcj&zmp?FC@?uUl7@CSQ?n<tai+c#rBmQ^P#N;FmVQfO$2X+61d zG3LY3)C`_2xkdt`jrZdzt1oIkE62V#6;GUL_tC!J~~W3kg* z`SEE*fg35t2Z~y6Bt$1EQ^<>@FxErMl^u>@*I0OjE}EDG z%N(${3%D#8O2o@{b1I&ay7J@RcZ#8)!k^pgrA%>WUt(l`T4vEESy#lSF^8yFz=x-z zI9WJY$ti58L#T|QFq^*H%}zG?KI)9U{jgXJP`|5o-ebTW{XLs{f^>z zOVHwq$tI{Mq)<47*}dz6fs$xuhu54t?v9SMqguG}r=LJdtrc{*+<~i1nE6s$2F;)oSL5V8%ff-Cx&H>2Cnj~dA0{*ka%QHw%|^e#K&#= zXt;>ow(!6I{61U9s#FJ@%$X(_NOmYb*ZaEKH9rpOsTe(p2U|3ep&qOiq$*eml ziqM$Riw0(*rNF$JnzmHEZgbo>>i|y7XGYb2Lk`b-IA4C$7;oeXbXmbwRU{Q=fk+HzRaDCMr~x$O%Ze=SRRRFGpS(a6PZ4Cz*Z(QvwnB(rWXM8W`vE>2|BJ0lv9P*`TH`i&7N+W?-X*dCCL{Da= zXxyJjdtJ#TmMfDskHem@n(~e^<#zd4)K~76F<$F;U0fiT@&wnZwLnR|pCr5=XCmox z#GPqIgNwlu?Tx7V%4o{$jg(z8$xsqS;SEwF; z4%hyjC^)GQ8IERSxxo+(b1MEuoMQr(;aS>iYzz8cExzW`YOnJY2O@^izM-J>z&Y*E z(i5-%z3?2$E1we*($k&g8YrAl+z zGiI~byunWD8+Pf=+fS+{c8|?X&JOJix6-f*`jk!ogvzlx)Y2P!cG|X(IG_JQBwGkc z&avCgo{WtOWnU>oTc0>|?uq*I)U%Ff^vNRwTl>4SV-BX{!0e+Z+X4fohc={L&o$cZ zbjCOS0_(*X+DF_nqZ=jOO3hg9zje)IwOpn?__n%8;1kE;D-yaWqGN1pLpCMuco`6&~p0Sf|(ighb<7ES3 zM^^q+!oC#`?}`MoXJbXuwBNliPNS}gzKolZM&(J%8*i#grARzYq=No5<4VX1xv(|l zca50k*i^m}G)*d8o_;-vo9&5F#|%t$6s(H}n-gY&<0iNzJmjy=x*`_i(Mo^|a0;2s zDf=)Hb8$i7BeHoL)4Q#)NXDHAr^C`x01p%PNN8G(er) z91(LG#l&Ooxln`%KHeqLhCPw|0NVzcbqtY`ZC^h+!wa_u^M?kf(icjcBe$1C)Rv42l+_!zv0dV7j$wj>Sxh#;_{Ot%(2D0bPcuoEIAFsnPq{)P z3eA|qKYzp#v=*kC%qst(hJ~okN%)%e^+wm!P%6;PP`IbwrlyMDPc3zGrpE~%lTTLI z39Wx3fuqTBg^R3)0;=OXD#x-1tr0qqorYwu1`f!OV$_zspIAxL^AnI9yO(hBfHgVn${^|Zf1HmSSVx(B^&OGT+Kw~ zx)E{Cl&!jm!QeKsOjM>@SvMWj+Ni8QoIr;WWiabKNBMhFy-s>kJOf`o$4$m;G(D1} zq?95SjHL*ym~o7-$+APwMp>_;#L>p-f`2Al@I*+GWCHp^PT>i%z5;=oLJfp7;!|1t z*da@bV%+J8Vl}Jn?n|m82Q%edh6@|xjBhXvU&rwh8(@nu&c(%pj<7@i6y0B9;t_w; z6HmmMozavf=8Jup=Y}~VLWgAW=vlGX%i&}6P*^={#lvd?-rU5?`b^4~BJ^P*X*U=4Cj*ja?a_(hur-%mG)pbb$!IL$biyTK;>ql=HW_YN zblVtNfgPsd1I}gI`-@Znau{X(eIw)SfGd6$(=c3Jj8RmP%Pq35NNWLaKU03BBTN$-ehbf z081hg9$d#3Kq8ft>rLEIZWlaJRS`BZ+;LBM9R%>WsGT)p= zD}J-P8p_8yHSXD;Sca#n1vfKNg?Q~qbHEo#45^Aqf7Zjr7u#b&2bSItFb(^O&<9Mi zkFzhJ17VMDmMMhX+x7YWSeSMn^T@`>M=9TnWnb4w6df5IoUPYS8TIjgNR7~&uzQ`P zmV$3ty{n|Hq@&ehFBgs!i@o{X>2lF~-t8@jw9ghNE#!WWP3Mv&Q;|tB)vF3KXp9~U z_U7zI)FGQPb#gdU3CHp|Ca4M&PN^wpB|)VMCFfT45y`?FWvqN!QO$6Vg@3p-@OE4_ zgy&eCqcvF^Zj$0G=}uRxe46j-%JfP!k6RZSiCq(&L?P;-C(rrf6SmP80)_x)oNhnZ zGlebayNIn*2PVz%bv-w4AGP<9d3x{rs1H)YtkTK7E_W<>IE;Jea0mBhD4lAtc#b|O z3ai#9U5{2xOl~9&FDgrJsg-il>TtxY;DT6asnsr;Y={mxSfA@45zSgpxso}%Yj0}1 zX+NG*jAW|=6gu&r@ihx?7A@G;5SQ6oqHvPeh1C%&Ah3c=Wr|j@P7FXLmStVa#UTRUC3<&6d0+ z(%af=qk!Jlic#gs)|p+|Bxg|u9f1YCA|A&*xI^_dqcF54eLemw^?rxn>mtcV&)RL<0E@D?mK{l)AaIuAh%;YSq!LCUk{>% z6y@t;0!H?TXBH@l24|InL?AOtWkhMrbYQ+T%@%!;@$9})bohxulOLTcnwz`@T0BXG0j&-P%zuT3b^`;vClBzy9Bq|Fc_Q;t+JtC&JGBl$7T(Ob@|F+3iK zB=P~HJnVJvz!)RG*EoL6JI=loqWuX?EaeV4jjmaga7O)!C?r1$a8`SdyMnl5WG2Zm zzPvZe$QTzzrn1q3g+BsLe&*=JX1;JgIO+F z;O27~pDZ`)zo%o%wbfFp?QnbiMxQStFkR-H4myb z7?mlvi)677<26tgoMkviTAk1;W6s9IreW-)&413H8ed)79f-vxR&Ob<@SV@ zggM5fEn%Oin;FW@!$J{eTJJ8WbUViTQD=Z_tq}WVwxyWEZB@+?x0UvrauWo$F)y;D zlHM4kmF`m6_c==^O#z)og-;u+sumBd7nvy%PNqxxl%uFqxZ>JJq#ygx9Vr33>6%UGYw(Sj2XU}-3wEetr-)oQ16MFVoIIa zVc#QhKGG8DDpoR6);DcPMf*w=p399?rsIVM zUY%`b=yVV=o1pLZ5em$p)2s~_JqJQ@l2t+iOa0Wb@%iUfCizslZ}{{ zjvAYZrKO|!Xe!G3nZVw`1_f>lMLkm?bty}XRo_h8P{z-CLtJmSO0e7hl+mDiFV zwiWhTqj+z6#$RaCjhuhp+be&%LrbP}%BP*4ld2ylOlLIXuMOu(g(GQuRejz%AzNg! zqdrS8U-Vc#5x1rD=|U#GS#C=@E0vuinM~drp3&Mp?YTFtbDm5Vowa(1Om@oa8J$+B3u)K9)||RPxyuob z8^feQ&Y9rwK-aKM>M0mVSHc?`v{op{*t)wM|GnQ;U-tO9J?1&TlU4fNkngTC?(rMl zYL`1JUwYF0Nv6%Q#_wrmC*72kuAszc2@EME+-!P8oTZ~X>Bw+K=DoCGx@Zi@`U9} z=+iUtgNcZ#>e0(BLqy21Gx$tgs(*ONGcOPM@oXiu=s?O)70o3_0A2FCtsjZ8P4?QJw#Dc!vGjI-kWqv8=JZaknm2OcKH9C{zq zcl%FWik;b`(!J02bhck>3f{dGrp=G5KOT`DKeOmqdOW{6GO5-LavIMOwQ51fjT&ry zC#d(PeCPfk89ns$i_=HPIk6N$mBki)F)|nbh*KyI{nUIo`jN2_8zyB{k<;1~kJAU^ zgS)m7lKG7~-H!{ynMi2fGGR>ar3=K8>DnR95bLInaXNf4`cU424hJmj2M#M7L*>a} zJ|I58`t5FxZM?oWpLSn(wQTmB-^bBfrrK4>U$SfVuy)PBHElbs#=G`gg3mdqUF9)4 z7OxIYl(AgU5T)?gW~syaoVof7jU^qM-)m=G@y6GEljHM|u)@$c%-QHFk+T@zPjuL? z#Enu@NE`}@*F`96h%kn^ZkhZzgKoei1-zO@LxtucJEuyQsD8^hBV)@81sGPx`RT(7 zZq=|?J!YTCPmE|n^X|Bj>r0gUq%)j|+d=^)%N_!U7@>EMXAK>rR@u0n9ZB@TVsnTF zraXSjOvsy$ac(s2o9MLH>lx`B>#^jD8qAn9dtElIuge*Lj-94yVvNRfQ|0wh!>Qp+nHkRS*gn0Q?dAICbLFAu+HQGvVy#6*IXLtDEVp;c zZBzAQ*xOExk;GFI!I!N8V0(Gj94E1}>XKKjc0zym{K}sW`O<^IA(D6Pbpb1 zjph>}$_ZTQQ=k|ViHr6t9$T#6?UaPWa)o2qw zM`ya~3q(N~u@JeKy!otJo*Ftfhf8zA7Q7PefF!Vwp$@j7Ntg9+XLEXwC%xu;WW?`L zb>rfa!aA>XpPAbq3?{_X<%Z%|X|I_m^`W6H7;* zZup%}|NL92kvYX(-D&-{{!&ZNE=AY)-mT+q@6rF*`IE>*&c0`uD`H7mD3A-&EurZd zEqM!gN9U7WSVi`5 zX*!W4U0*7mDdy3a;`b*js}l|jvw!9ct~@YyA5k63EDh>o-Xp5S?9$u`qm|Uc|0kX%@LGOUCe%eQblZ@$z z!CH|&_~NmWeU;U0XnBS4_U)v`mTcv8u+NOIQ}sC{!0Y&VVIq)g9=5!YZr^XhQ*3hN zj98QJ*DuAi#`Jpg!6y_uA5IlQY`8_1@L;n^l*(k&22|Z|rpNY#Vkh$Y#jrQECKSX* zAb?lRS;Iw`mxF9xhpD zPg1FbQ%Vy<;X=-oNcz&d3RE?a4d`)ODm84XE<_zZGI#K==mkZYlZFqVXh_%_H zOjVQ!z4)Tc`y4)=V^4=8y{4f}$4(A&XL&RJ?HKDWO0#0H&pS8r<9rXj*t?s-)opYVOq{)hI}sb0-plDOdEkKiR@_Hx>vD3nvFN(B8zf2>PiIZ`skjyVxi&pc!@5v z#J;)GuF4F`1dlF655(7&OsS~9IFt?_m(8}jBK(GNBnC(xQUdlN=j0GQN112(-);9*`LvZ+%6+&|1zC3Gkm=y%Z@j!crYJ4vP!K$pCcqUeQKGD4OE zA#v(5(pfR!LG4as;5?R35$d$)vxVRo>w0Wq$U}xkZF8f*BanEm!YV`}WwB{it>`Ex zE&FgvJ5@TGw#^pyMfy}@_a1EzButI`Vf((Zs*Tm$KN*@yMSmf#PL@oi6T9>Fa%XR4 zo}PBwcdF;ACh5N6{4PcsI^E8W_~s;}xz8UjWZZhaH%F12>3>l4-a(R_=b7iMR@%6@ z3rQ>K6q2ZuqZ1uSf&}3)7+}2ZY45wby1dV&9&dqx89;C(NP-lX z6tzpa6*pEJtI+CnioMm%eVV@~CVDbD^LxMdd7j_XfUn?fORNlMd((UHy?5koU%6gb zk8H;(g@EeRtVli>P@X2NqX4MhxD-+nMITAPEYUn{P(6OO^hpwPwtO3?F^uui{>v9D zAGPou4I!HSeBJ129_E?C{mfyWEVUjiki`Zsa2_JKu%{u3Je;8K@1we2O~W~(F6Mt~ zra47rgskQagYU2i3xKgasra)J*2mZ_#;!tf1uWz_0YVs#ClDL&!p@A=Su`ypVm6EU zKJOSQDFcLf6g_gEX~5_mN$9dT8J9?fXXCyv=wZ$)>%QnhB`1^af;9sAz>1yb-6?cPTtzD%{(MH;EL5wiZbvr9w74o%7|)}>OjhG|``u4wiPk8?yT>eT-n1s`?G z&^L`M)|%I(uPnGC6n|%7H5IB?mSe0u$?;w@u=S!FYUapN_-d*_1!@=L{2{ZFOBJY9 zuV*^hWm|%>;j(k8;GGv;y6hRTG`$wNw2}@k_a>#LpKEG?A%!XSI~Fli68!S`#-3)b ztu}i=cI%w9X5h=r*1uk;v#a^cJ)!zeaEn_`LWxbsq88cn9oyKOLQtVTbTI6u$2uiV z#!e2I@bS^6+vS)thaqos<6*Iv*;E$?JsC_iEc&Ttn$St#>BS~?*#>>wYln;OuYc@W z_!6Wn1=!HINk~uWf&cbetJVo-)iPG03}5kijlz4?)MM#sH!;=z7W&+st0tB$ zu+5Dz)+_0~)H;5+D{V3PzpY*tnW;T+IV59ig1Ww*|9G|JT3TaHaNF*U;`xun^zrlD zTp4Z%I=L!}Y z9>OkFF>&ca2;@!rnK^i2N<8;EBHHB^I^V17YJL4t?ZXF)&?!lv~7w+2?+`x%ON0K{bL%Z}R8N_k?@X zruF5AOJ7izhw9dI{@mSUrmP6Jmc&vI&M-off8yMFM_j+OBHWbU&)%rNdV(CU$u^PH z3Y3>=3jA#IHLhXH+pg<*#c{wNBsCl@z*3PUn@kEXn;cyV$Yeu`Gm1jH1d>Jeae=n1 zY}Cj=D22K#*o0;CoGJ;B<`ghntAYT{| zJZ1_)K^7H=*P9aONi5F`wxrZ~P1CED9Op}xWE|m4bAihiS(%U3KoS*PGBpYH8DEG=1ZK|D{u`#&f9dQpWq4pT)+RVEG4G* zW1KVAUthEfMgm-?nohAyq!l=DD#rSAsn=Ohp%mHKjRHyImR|a#KX1x}MqIydBG) zniK`H(w#3wM{H{*o$7Rdfah4~Q~w|DObO#El8=>tRPzp}h{Mwzgpch`IqI9JWLQFL z9N>do=In+xBI@lJQ)oYLJ}tTjaNi%9Z3?GeWzQ>>6>}wXXX(j$dW`?ri~n3ado{_h zF+MDX9N4p8VRH~W|DnCil!I5c4|gigWPIsGR?wg0(DC!Zuh>j)wkX%traLyjN7<_3 zMH?rNH($x_YAoeSV(Y2NyjK1O*CvFa# z2hHzy-;!D$Y8xBvBo23w=se*!JWUWd*E zcW;hN>V0gXb&p7GH1YN39}GV9F0J*Y&#Bro$4}y)o6rCw7QMS8EJ{a|^ z^V`_xC*7M7s=y`^a{R3lhXk?W&fN8~DGSH;e(~2x_vK72(ktq>$)i1@=p2-X$o-25 zz#(&X##89=?z}$(I#8cDBio1EM_uO`Ehw);)3rC7c*(x(kcm&$3ioq9c~`%jwh4U; z54p0K_Y=~^Q?d06r^BY1{$bhM*>Q||LjD_Gq*D7Aqgm;r1uv-4Xk<|Aq&wQ0RR56# zK(U82gPxDta`oW8la>HhSF2)M?0I1YSX#1W&>DvY7DUkRHdl~G&V9Lnlshpdp#f{0 zi@Qe(UMQUP-{kztQe$fHlQ|*kS@G$Is}?9{pwOwq^n#rE!5&AIlyiwS7`PKXcothm zDzl5vZc=|L64x8@12wYpjR*yn2j@(n8<+cH^DM-)KfAGoG*ZLWj8&=B6DJq0G=X~6 zPHFGWwl5uN?}tb2!Xh{I(nz+p{t$(!X<@K!Ib`rd3Y%)@bq74`)A%# z5XhT*^C|hywTHhi2mZSB#bo>#eW!X^`vd)VqF36@r@s$abulc;_r7X>7`&Kk=I1Bg zQmSP@4K1F%@5g4s^A|50=c_N3BYrp`KiI8>nRf12t@rl^#&2_F_n5F)Xs$FaHo3Zp zTs__{{a!Go+gw}ok${_3O-XRK1m%^g6uU{k^4jk1Wq%+JQOEl2@#Go1hk)8=k~|>C zHlltH>PF5-{DKc|jtjoI?Jg}a*K4_!8@HQ*k?bM?%8!@s$2&z@aTycPG? z8D^8+OosA|9n@u3YLqvV8=}Y$6kTC8)O-ATFbx+F(XAJj`!gln>tt;(D2m?IK4Kvp zK5IGAo~5uOXr@8e&d~M6Kqx<47}nr#&@89P8%4enDYA4K z$DuT{c*iyq`w5A)fwt6vbMr1wa9P%2 z$~Oc(-+Weh+~*cb*)C(Rb>Ja;*xS#Z!y>V>#J7J=ojKYavs|%r?N(7P6YuYz*#wTz z;kg)E+$(JH&YM@->$dW;>4NEvvErJqlpLA`+P)c z$BfGLF9$;M=}8!Uztom-cb8q)DfZ>oPjiXxUtkjSC@h=HG+(__kA8kSpJ2H;J#J?{ z*a}|>)q@igwz)f!hEB`BJI8S$y0+TjC*FF-$z&Ecpv)bBr|u-L3Bn~?3t$)WuZg`) zdF*?b`MceX?{aUC{%r7&Q7`)f>+0rMG<)nbt|1azyYOMae>>;#I|t~^*-F43l9L^rsC zNQj)VM$Ih+DZ9ZfRyq{kF~8ML({6z;85n*KqvUj7&wv>r=dU-6qRwtguFL{|i5?ap zk7H<}nyk-Otsb7U>{+T4uFD5Z&U&3eySCUY=?u7TJh+);>wVrn@4$E(xj-%!dEJTqT(=BzTwB>UCe>d4GjKv2FWY-n%( zBT|eOZzmV$^t1P|#xeyLj?Aviyf}Ala%j-s4#{i4;*3>6+nrvZraQ9O6uLqNUgnSu z&@pqPL^v)!u7bP9nn;u$Q5>oWbYsi$OfD&ww8C|QH2r15DwkK37{d13Qb5TE6mJND zg+>)`MzBH=l>br?(~*q2DnY7WzKU>IqRhj!AY_=gcPpV47#(1Bb*AZlF5tedJp;yp)h zS_U{9G&KSHE&2n7xC7VozcP$389F|sfS(e$hjWHBdJRvnHhMYqcED4qxNig4Kt-3BN z^xNgI#(=L_uwhD*TD!Ye-V3tX_2J1J(v;1VY7xuRwO!e|o+7(3V`OhUDW{Ex z717Lr<*-hATbJd_s~@SQg~?5af#4a#Ld#Fa>t$w6qA+K!lgLnVzRkV-x8n{}bKLMZ zT2?zd(=OF9T8XNHa+wVE`Yjcl=DQco*DPYmg3_x;kyuzbG!KmZ8N^E4du9-K6*TaN z-8f>Du%2-0&yrrZv9itY6|PeR8B`9-y5+xhVW{&6n0l@mrCj@Lt+U?FrJYTM65!;k zEAlofjm!_>FV6mC6P*LLn+YOq2Wtm;lalP}Da2e)m0`K$oLz$j&yb!wRI-J!k<3^> zEp_P)ab@yIT9}mnjJbSSR-05|qJPUuQ%jz_u_Dc@X&g>lYdt46;?m8bH-eu)hUjs|(%hLq>Z|d5=dI8B5S=R)Q~JjEa>dX6 z($!6{2q2)8dn0D01!Z z;!x21y(jFwYyW+({%-gJ`^AgDd4I^dbaLm~+v}e$)Iwjd<`eXy$&!(dc58pc8h%E8 zRoRQmg*o*H+kuYuW&Y`<^vCRPL|zn?!9y$_R{lVHe(FTz8y~BAwVGsJ4Wk3k3OoAE z;s)NTXMQcTu{*JT{qJWV%s}Cn027zQI@9l*Jv;rGy$9Ex<0f3bjL%l+KTEvpr5N@%e<5|Z^iv2G$L2A|%hAHkn4VgT zM&h>#D4Q#~Ik7nNx~lvHuQsvAlB@+X>-F5f`_%|qlu_o^+`FN1;vPkX+3}UFiGBV+ zfB9+-U;p&;keDCbGMhm3$#s&YGLjikw~kxQ}ulMYGmH0W3#h8 zW$1a$VCH}39&?g~8LrU1zJ{wNXM>g~LoXX68zbLYeS=N%A?i|ZP*~<-x6Vo1jj2S+ zz|S;Bs|k@@Tg{Kai&vHozPa}8Pgha=+?9bLt@(zNC6$Mp`JhehlWHKj=mF22$J$51Rjg7a;x1<(E zTFd;s^@kXMc|oLv^97KB+qptYYRhnC-9%Zttg)hsOG3i4O`XkIniXvjH~eOnnEh`Q z6C1HnytJPAC! zn2YxFOZ^~Myl!mkS&k92NnVPMrgNs$;fqI{9C(fy=kTzqX6sv|5`}}Afgm)O$sCx? zF_v`ebTi1s5EL?VktuZ*JR+s&K91D-Fer<0$6FGsxTOZ8Di50zsJb9zDtXN-EiJK> zG)wD}w9V*do>A)fnRwphbdO4tYq1FZ61rq=+^wosJD)h`zBP9RlHct6van;e&{v*XV%J44Y0 zP*APLBJ3sLf0@j&i(}D%6bYS;PQRFJV$Xi8_hZrP(s?PVpZ-#l_?ObbIdy}6w?AL| zsXH;2Zg+EsLPHWxJB^5%YA)LOX(u`D32^Tyuy`Z!wpC)5&#%FYyI)-5BFpbnmslGf z;Z^j$Q7zj~Co}I&*!n7nUR=Bd2^aX)*}#%O=j3czzIj5P4SXpo=)?F=K0CZNm^0Ux z`ZJl_1fRFATX-QT$!&CLWmP9#TVDDhf6@IDsdWlR#U_&xfBYro<4*VFT~jgp@|(hu zm!CSaJ|UZ7#*eAniJjunBhaY)Y2D8now%s)pHR;{ zI$L8kGJ9oh=xTPB9J@PpgISjP1lb?_E$S)Y7^wSg4s+cahpTGcQrLraKFmo z2^|JI+P;R+wW_-}5`x+(wv2)@b8J#A;1a`Zuq2YBdzCF2c5%XY)grlg&C56n_M_gN85iF%&!8e{HEy`wE)(64?Sz)PS8n1xSdZSDScw;?N>6j%B~sPtg(g`D@G0MmuMl56>1Yo`+mg7|#OFo=$+vSDF<(N8OEP-V;TZ-eEg`4Z8peZh&>)9+{RQ{|YrZ=LD zzrj^_b&2Df%+-vyxqSY_dF+YGI5y2zR^l2uf8i!xDup{(&Y zHS2g%prH8*4FdXXE+>*Y6BcWf1YH@9B-ZkIxkv2cwZV^YyHOe?o_#P)%;Be4i|Vcg z$olbYuuvl+m4q3}*h|T)1r&a(Hop*BFVm6h>9mlKPmWeEFC59$+0_N=@`&}E_hbRG z)!IsSHFO&pbIy;f_pRa&g_-3~m(`H~94}TQF}jef8)16wVvxw2W6^Vkxt@2Jne0@m zE7xXDE4}Z7`RP(=^aOew+OITx%9+3p1}x2Qtaw+2ZDlXBrnm z|4UxUXM!K(I!EIg{&latNY5JOr)}f?==1oapD{b+(){suZ0QL?$y}&B6o|Ezmj*9s z!=tZF+t}JpuaXW#?&P!=_|s$RDCq|KxAIA`3Auz24y=Fq(q%nfxG)*=19|q`B8h@M z6M@0KDb7+B($_}}8AIF9jXdot%wDmaOEixft9}xegllc?(%z|-$K_xHo!Eb6Yc;xZ zrGK2Bt{+rQ@tNP%bE_ePI?*kSf3{Uj#lU%uaabaOuzDL~lNT^UqOj86K4qT9N3 zZ+VHh#&dv2njUe}uZ9K}ghCU#F4eU9<7{;Q^QF$dmQPi7}`KiA{Pym7c;mY*Su z7a!Hck%chD4Sy*i^Y2}2%e_)6KiDj9DBs(Af#2G}>O#!^dP+YJeEH;3h%0gY%yZ2; zO25@LrjN*3el#+k3+_sggj{@0T_nmdJU2T;YLt&+SI($cS8XsNh zQ>Ciloy4-pTvoo{E$8*cE^J8ze8Wn)9SHWbf~?=s7D?8C&hYg1G33OZTx zsYSlgc2)*1ox!C}yUI7*jxg$X0q#Q0i6nwcPGx2=`2N+WV#3UqTU8sq1jR>Jszt;VJ;z95zNLxMO)C> z&~XhYvg%1(1g0di=l_-HXnaK{aZ*eZ4phjiGN9->GDBlbhmv~aXSYi%k*jpfQboWE zKyVUm9f2<^N)iOLDQq6YunWZGd>P#DrZcSP>L>`uh*UvRQ9WN4!TKKt<2GF=`JC?d zSYF4I2KZhY2fXEpW)+^M=3M)s$4;}_eblZSy9=Ulch#j6U>Bq+Y`GXJBQoy^8skaL zZP&@8Y+=z_Ve$oJ-pi{zEs6qLG7Ar-n&6r(-RHBqCTl4Z^z10Qkzp(v1mPQKwkgkO zcO^1U%X*oLeUHNhU_ff7qY~Sqcs~V=hZLN0)PBAK7flp}+QnsEF|xd6b-@F%Wv$BO zd$EL7A%7!2@zb;Np^W;j}e)`VS#OyeX0K^ErAvlUF?brdLe zh$Bk^`a5aYlPLs2B@p2@*CRgPosbdT*UG(`Qqmxsp=_SnQ>X?A-V|iMSSnY4wQZ0Z zkGEt)ubR$d;Z?8?H9!Ce5iwlcnOJTmV7mgWBe>ARYKQB|`J+5tw!k;n`0p6}`qgDT z+B{hJ3jO@h%0!z@44#is1?7X$!S)0_QDw&TQ=Le}9&8Q#dfbxtw=QumnY(*GKQ@$| z5^KXBEUM7NY%|+T0V?P$sSaW&N$IZ`bD~Kl!RI9?=*kj@U-I$yD zqUnDNG`cI2D)o;cuYW;aU&ifca1n@5g9te_Z;3UMqfEmoVit2uqEjQ>2lOk#kvJ-sj@obt7Ss<<)#HqrR~+ z5n`pwWvkPhWvhk7S`$>xgvq{{4L>4Q@_K3pO)M_xe(FR>*Gf@ghM}Ik`vXQy(njda zQcnBc+8Y=2@lI;MJk1G)G`jtUSW=KunU61NCRAm#<%!hneLJk4 zWnY_JK+Vs*bCu4(uC;dMUdY{#5ySmWY+2VsL%X z*Uhe4fx>p3@Z;zL3gAg8urnEMFU)3yZXz7@0|OfEZZtGOZzaHq$T{7Nv7Xa^jylV&s3_8@Ko2Kci(WdTEUX*&tMJ-Hg1BFLsY!5f z@Z3C`N6r;`D|NhQnvH1GlaaS^h_rn4^h1GSU|=bPvFkVm?uq96->vFpyT#91mDGSa$&pMItEgO}_&AQ2O?pHGkIZ!8v86Ujt3@nHv9s&|NTF*SB(VB$}%j9Yq3 zN4=6gx4zpI>GGYK(n=p0?{?IiW25?#-<@wW?P7_mq6b-avnjUo|9pCEybvgy%m3`z z65}3h@3CosH-N4GId`ef$0lc>4W{}-O>{|3aM=9-(ZnM=sei&`aJYC-EoW+*&}_XK zi1oPk&AYnWu>Xik8?7!AwmFyp1y--MgEtk1FmIQYWdF;qe-m~tfL?Np9pSGY8H%Ku zt5#z7Y&Sb5u%OdVspdK`h9%n>K{~w;>Mh^OsM0LPIQw*4b{zkkoc9-z;;K8eK6{5E z^TW`Pw?ws#;cHG%uHx31JxbraQh;}sV8?Qk}^AvKkYOlTaCh2&Q}IDIAWDjB4;=(@0;s)(dGcOieNWmO%( zTUtscNtUw8&1jD~HzJN9$)x^Pd$Qb1)x35ZC|1RVi#+wM(aPK*3HOb1TRNsMvH8QR zzE?!!+W9gJ4X^KK}V^^(&2Wp<7U@E046E>&PjV6>Exh`>04M* z6LOS57Xx|pQD>!=df2Ndlno;87mBqhmMnK*Q0*|T-Y;T>*a5zIB?XT0MjCg!Xgv;Z z-*X6vic)*jG{BM+;Z(aCPmI&$)ya`z^{e^XgxW0gsTKKc9^~!!|FIms-Q3(Jfa@8L zeLVH}C95wf=xYnjK)O{-A&iM+;>Vkon2Krc>+aRnmbsWZ+6>B;bhJXLnFhQA_u-6R zsX^rCSni-Gsn=8G6oA3&jS8qu-dL|=y?xV=a!!9Fw@jkrlApkZno$Y&Te0_y3vMjWh2+Pi>NwXs?I`?bht0qIJZwTAyibTv zJ$)6@>j;1x#7Z=4X|}dk!xXI z6dY3ZL;$a1pmv#AnP+pPG)sKdmUD8rCi978jx$K^v{(XDwI>RSRPl7ia6Jnm6u%JIgu z=(j-kpfkXO1qs8!epjk4@C=}y{SSp40G7Zw+poNH7IY)DpcE(kW~45gvqL0Y^M)f#mcUZ6Tf zn|}m=7mifeLM<2g`b8A)0v%BVXWeWBJoV#qs*QS{15k`tDcV-*YfBYnE~Ei z%(CpP#Lz1x+x~Vod4_4CX@p(vFqwSq{BZs&2gY(^Mw&Zvt9E~Yf9Jv2X7a6(ts5pL zX0u=@7n$vyolVdmP<%T0_F8dXvZ?iP@}m3ARs1{48_@EJw+CnT7N$0ksE{tY~Y<3J@`T)sV+v?@a8vbA2@K~_M9^{ zj4x)q=5!3EHyD5=qo1CEYN5&S^|a8A@05SPo9Puk3U5!(&OtMw4Up5WI2Cy;wOdUe z=SUI+nAM^;G?P&NUfCC7pAin`tC41)y{MHKGBJL>IWm1<1^e6C&h)2?tqb8|)+-Ds zrXA0y_V+f?T8^Lle)npW+{|<;{qmfc9#wq&)f2*|P-ihs>b`ovX~zo}%PFn7{=zp1 z>EWWV`9tz*ZPWOw<*Hx$4+{giY^s)x1*Hg-5vD51BbAN#!uAyNt{V{f(9lMNVQbYw zK!E*%I&-(5D|D^t+)~hGGGp@#{IjXexYn3$en~=S32`;;r6b7?mK!Z)Bx`;xz3mvE z&Pn6Dk?Q7^EYP6h$L-nOZUfrgvfgzSSijODcZZ?;cy;TvncDy;s_ydmo!V8m@jUdi zZ>sq#KgWRSs8tdxKN5IqG=MFyWfw~3dXj2zpHYX7YUJSiiX=UrS}#xl)S%g$%{_P65I8@}}>N zEgmnQ?_J(`@F&|3vsjkm>*{F1WsKZnKr2<9;KEF-?qWMhj z_HFXx?Q;CVa!P%B93jJBzCNBm$7dT*zV(%?avQ43PcI!mE0HF9`8+@jJ)plmZH;yT zD73X)P5)Icx|2%**IuG9dA@6+Y0GIBW8@{OxUzdT{{iGHs1Vp0A6M7NpkCr{+S1mJXvCn(yK4CE5_0*wRe`0 z3#E$!hTi#P%2n7WL*uWapId+mYiwKYUuhJOx}(n5np^a0RrFn(h6l@kTeOCik)b zaes04_JpoO06sZtsh5apGJyYw`S`+ji{&fDoBTo%Z|Q|FRqZA5e)&e>FMEXdjB>cF zmVUVMBRiW|v*w*)cUkpbE6ElcmDZ4LGPLEU=}3(#UI*|>U4%cX?zIGMo$6y?Ls@}0 z<P@yx@&RUg`$FK!H zd&-iA>aEB-x4Sk$IGy{9QgZ;~>=3#~N*jeTAw3^Ep{Sk2aG{je>%1eu>r182A#a|i zz${zV(d&q8PV4spYi+GHI#?DEw7M25X`YnKmQ@RlDaLsGd|K)M`za)S&71_9BzS@W z@IEQezO+{~kUj4!$k&4F451Y(Vv994X05W`rijUj!$8y$TpK@L3lJ8=c%@Z|x$O2` z=pY|ULO%+wxOpa%8MhCRrJJ=s4(N64QC{~FOZpS#HPya-e1c60PhLX;gnlvSejx-> zT}I5hs~B@HkR^|qSiP9vzB`?KIMZ07L$4U5H^f}k09bJ9a4DrdTnvid=#i{FdHKr4 zx2AljWR>6X%3wEAtqi}pyO|3=g-})W5iw$>o@$Hwb-SH;6bp&7XHMuRkUZ_bu)nhe zjDE$k{N44`*OEEoBEGqA-`|kax8Z*O4pMj?xJOj1@)6~F@)Wy;53kRvA($sWM znVT+d;%#caP&N|&eIm7$Y~%pDCn;Q$a|JPb$C@sV(KIzlx6P~@yL7H!p@|Aajv$Rhy8 zEVrr2>KUu)R7T+w0SF9gm1H;7nl5C3^bkU`7R+9@>^ouq^73AtysK0iITcJf`b6FY`nH^Ix{Mb9yD*l;21?yZ$%7(MRiiBzgUOZ5X|5oo1V( zQ?VyDWBt_&<7woWvL2nOu-8tXEFT%*7G)k_>8|b_|LhfO;KC2y!q_wHOTtHAV$yGq zed<`|)hyC+$TR+b{_zV>M&0iZ&ED2t3kDC>Wp?RHpLy!euNEeViQmdeug^qHeB}gK z8pG1NOa}h1tI-s54-aqu$8dan`O@9e;DvvXzE+Ridv4CXHSy;|Rzd_f-z5IUrE9K*re@*j#ok^9j4T-*T?>78@vUdlr z&D}aFk5@iCYbRT=LjhV_q*51@8h`?joj3gKT$=cJY^DQFdC<@`_6%=JgUR9HoO4Pw zlOtww!dQ6DKYd?n>D=nAr>%7PQfJ>;3%`(ruDf`YK%z0JRfyPBpO7U9#8)UA9VeBm)PMSF5^<{m_N@VgJtg}OqENeV zDkl5@hntszOUBY~z{!QA(kl2(inBorUdB%O)x?Xi)VD_fIkD)C&wu9G(l|9wh?gcX@N( zf)Y=ai%M98RdC~AxG*pae80Z297!&Uon^*<04`GJ!2_TYr_{wE;48$zmBs=oF)#lT z7PiN?H$VYe!3aR3eMMWre@|l509)Jssid z;e+*yGuzyR`W;7Oe^hA{_mt7$nY8P#g8uN(WXKLczmTuKE&YoT*jN+M;?2%(?+J`X zzIF8vpE1KNDQoOD&IZ_R?vK@j=V#BkFTL}37&Bw!)~#?nv6+y5yV10-tNZ`(-TKw@ zg*WKU8IbdNv9I4W(xvv8*vZL9*Zu*w9J0D}HZyU4Ro0sF?$I9m*;}z1*7ec7C2NIr4Iop3W~Ob(2NXVMjO#{fjD_A zRPuqS-y!VG+c`~>X1Yk0y7;bFB%^_)l33vO>uZt}c&lrJb&zt0wdodKcN*bT_iElPEHCc?CvxtTQv4E94YQW1-dlEE&f z9sULN_dUMLTH{{Mh;-^z9Zz>?lK?v}f*zLDE-MLG+nXW`1*;}Z71vcA&>Lldxhh(i z0p3x-xb$c(M45zMBs@iA552iW1S~63S7Vhurkca$h?1mAgxS16> z9R@HSL5yb1@?zz+tD7knVGMhtCwUu-{}EY6I(VU2HRC!!&}3!LeZtr3_~6Ddvh-)nE?6zinW@PG%qV8>1u$>1m+`Jw+F+m(#BStd^R8<~o1p^Jp9a}>FFsP-ed&DVPc12WF=j+N&;VV#vHF~Ng+sy_VZOgM zhdcYep5WV*d$4UK=_GjHY}R z6NzOx{H&MWVZ- z0$DjN(xlH6^vBGKAU1IWsWIs?)7V~vN)>AEtGZIBa5gKZ+QVoCi-aBFHUg;C2C*=q z-*U`9mpdd;;e12#r=#Hb8X+LF!HVFxOTLd+vxRIh>e_-9PcAqF4nrJ5N|*A|T*;S7 z7N$*EqpE4rbV!~f0FDnNXmPMpH+Zqy)%!s z0;r?n^|KYufW*{PHeFc>n6O=Jmbg_)8*-fA7G)`$mP_TB5AHuCW0yTCZK5$X26S4a z=w+cL#5C<7|J!v7EjX4a)CYDMQ{CbL`MA9Tf4w|nIFPDk zNTSFHf7#?XyGYgiQrj_@Ca(=d*eh2)@;py~ggqW5sK>%8wfvAfxIVn?wP zKZ(7uB}-PLtWHrZAPE8lK!7OId%eB)(|hmd+}_*FotZnmp;rO~3qVq$C`zI%tE}xP zk1botlh}^qIO`4e)gOQXFf;d@_x=68-_M6pLRQR#Qpyv`s0K-d6&rbi)=)u0;y9r( z;6Yn?pRV@zUHN2oX6|PTtG82Mx`UC)va8yau8-akZI;DHgWEa!2l3Gb9?rktJ#um3 z8$+`h-B*oFxM!%;oUfNPpCjMAA@7|z@$*Xf3*13!KfNAYy}UB*Z29w-eP3N0>$*a| zR|gD}b6lqle?^wmeyl#&f4Hx8zLW^P=HKgR=U&-GzG8-MckG*&{zLoa#12_p$z`|e zK2Z5lrs~@%0{obiE-pJTrc&H~qSjseOvQ zqhH^;9!TYj@jxUv{G+ugqaM)uZ|JQn5vf&Kw!*Z>zkqiGu5B>-6kKGM%C_E?8xkV`|Rk)9mXraajoF zT}~S$%I7rJE7POkMHFpQ9;=j08(E{{&!f#Qp%MfJLa|(`y0~CL(>zpWY2cWl2tSl2 zkq8)q&y2Xd)oPiIBRKZeZW#+Gf;W$_2QS;X5O@@(T7Vx2wZgN~OqfM{?Wom3FMHRw zgB-9nU(FN`&^rRtG-0>1s+5-LJ}OO<(3_^y%6jPR-vewpX#uL%&8V%b#;9 z*|Ih97q?+C5*ocF5(z?CZu$@D#~wZ$ivyG2PF+|gL}esrgn>bj&>MHen& zuj_b^j(a4YX(nuub-_%6_ZB<26M0Ta;&g0W*)Ua7bC^3!Q$Y4VS zrVv0G1=%c$$d(p)Dr2B(q}0+glF-IZ6~0DgicRyZQxzJycZe+mNJ#8iGRVBn8bZZn zQ#i-~K&uR&+hFlD@_I5iw$&ZQ6)gRU)Gu0!m9pG|gY490zwOiW`C=I0_yk4BUPGen zksmZOaWi%v73+KbsF8@}swpHnS=S^SUI=C3PJg-+NX4<*xmw3n8b`}(CLdOU+68V6 zD`caKo_^NfkBc^d`22D{uU)BNVn{HgWlywe$Z|MGx*I26I(>saSq{f37^bXz>MYxTcl{8UUGeN1+3ewannX=*p>A zH}|>{CN1wD2qV%k-=NIbiSj>e0irXA z%P4Go*{Xxgsiz~iq{q{F@R(!l-9FLlk@;nEZ?&O={K-lxAI;3qtk}ZlU_V$8g$1ZULQ#X6AjXbZ2jj~x|Gt|yE)b_9MIp= zqw8~0p;s}sZtJJ`!{w}SD-o&GZ;<-KyPs)Hs~%Si)K*?SAMOrEW^i%;KmiAc%O4|X zG8jC^YRfIdl2~-f`T9O^;w(rP!HOME$c?seR?o2U6fm2(v0gtM$%pH!{1}P=p36Nk08+ZjrXkzWmw-X z_90)kOQlBG1d0T+08p|l8>2Xo>n%4 zK?>fi0CEe<-=~|J|K@FFqi7}ih1UyVIsI~Yvg|jE9H)_b48N~Z?=ocD^P<=hGz=?- z8`V&I$Y#l~cwDcTtumBFFjZ0992{|k#+W`4mLg@kWT>D=qQs~iG=MZUp(i>a8j5Co zP`Omg-y`$&qF4W#HnEUQTywBiS#9;nM~T{Q=GN@GNH4{23H7XF6&!21IqKK0>fjdB z8C5Rtr%E-6a&izZqA>8TRDcQLGCB?0Q5Dpr61Dsl5=OE!FsnyhA%8(HH`NSjMcKXN z(L$?V11Nrf77jJ@qTSSldO)0 zz9D#9ln=Dyo8`hmNWG_QcfG<%fY2`YBi5Yqrg>X!ewMdmS)r{-Rcq>h= z)mFkQ(vFBmO{0w_GSN4tOWQD9D@e-(mde_2Dou9LR0)CeV+^@EgElfd1n{rqj06-o zK>a8_A7%SLHzBgDO?ahmh6Z<)D1<$%D!YJB=J{oKLthp zh^#s#tuR0h^Eiix9w3F6;#DMMrG`Xxj>%-dFQsSy?%s3f18q)aK$@S+Vt^!q9Qy4W z<>WuG%SAs$BlIf|p)Al1twKY?ppYXMB)Bd2uoZd$3iA1+k1NW%i0fZs2>Rp8%^A7C z*uB9a^(crz2x~H>DMS*|=_Fjlx<8DVK*4nj375fMxb~VEU+~b7Ld1naH;y|pZ6oHgs?L8O=2*j#K{aJ>cAw@6m+mB^S z5Jfh#>XTHIp53a;yG-FTPgR{~wcIYG&r-RGKbF*IkR9{0Gu$55-uV6eZ0g{5Q)J*6-jqfzQVMZsP7sRegD^q}@1s zGgG*zvsGt=?jAEGnE!?AONlRURO!+O%J$f6PXldN#a}MLUh@%s8SmWL~a_jZ8a-^Rg`AV3=wARjdJx)RYZ zBcF=DJ4&i+fB&EyZa%xk&-_{HUNh^@-Cjn9$b0VHnQ({xp6& zkO}_3v%sCugt|!$-&k5YRH5dDP04@;BmKqs4wh3(!Sdno*Gq-+;N8?n zlU^@0+FS7l#ZJO?BOcZ^5-w1uw+GM6&(43RtE0s65IeFt;0;;+^vatFVP$G-CRxb7 z)*=7A%~6QunaWeCymx1@fJB40zx|TX`6vP&r2LdrxlB*Yr7-Uv=cx&xewA~Y zMi=Gkx$lKbL%H+)$NiyzA31fhrT_HqE`)r16x6e#sp(pj3sCP^|{{LZz0rH7D-qnQvwA@>gn2BsX~}+Pk-*8SCI}q0OiN zz?b{Q-lN>RdDUZ-!nb!9PhH3+7m_^=tor5R7Kp?7X1|vi_bV!cZwq#uq$g+Gza!GMFQl|AwcES&uDUnfCbQpWO5xTE;OLpMfISevq|PGKwrgm%!93_m<<}5BR^|J$<=(>mI)@X zf~UEk06C}jwub}k_XQg@Iyum<7O4b}cv?Yj9;#qN5UfFurIl!o_BXMVjv=vhD+WbO zFdyJ_`ajYnS2C0}(28ilhFF`VA(R&u_^g0v^WBzh#5umq4#O@G6M8$DuS+tkOa4?* z*&4oE zo`@i9MWz?dagHJ-x2{LCn2)F z5MKfOZe4}J3zDHT4&YRZn?Cxoh<%$Nc|n9JDl1`3{OkdBKwQ+;oWc}~lB%{mU)FH7 zQb5bd9@9zB>MMBQa6`GCm>P2Si$6BL7&uVh(vN!X-SjOTfUKpoFgG#qd*hwEi5Kd@ zZyw)xH1d*OqzBNITVo)+_RCim(XmY8ac(6%cJvqU(6~rgPyF=I)3&%&aMKzX@wD5&{f17fLJgB(#wMu%#oOzWN)Nrlw_|UA> zn=^LFKKn(v0MoL;*BL%tjNN*R!t zZ%OtA${Ed^zW&?M7HIS;Y|K3t%^JN+z8T-&zz?YpA6;HTZnin`#NAdJ!_xny`uqDG zpX(>U7MO5rg`ylQ*R{pzgKTMG{fDoX9O?`hOVUIYGjPJhaHGtixsb>=NmZmd14k6Y z=E>TTY+O`fjkD-1UI3c`A!3m>*W+by=ad;WDd~WDFVZ$E(R@}d2`tCeN$|(D2E*;A z|3LmH@R3_l44u`?pM%I|x*eu1>MBQ7e4xriG%}-{j^Te^QduU*g4ly)8hI*f(GDdr zYQe~nQlVrEymW(O*?f_gb(L^8d5=20EwpXD_nt5qN}n^WXa9~u4Nq*gcW5)n9j~20VMxMh*0$+!{8qWOta6deplaE z7I++k2TeB(H}qVnNO`W4hZ$UeX(t}t24i)HU;;CI{7xbZJs4S0Pf^7jmQ z?z4F*zA-WJKfv)iM_dU~YVd2xouy<88U>l4(N{y%wDS|NON^8+=%+IjU`Kc1j&5M1 z>3-@D;wxl2lliCG0@z0@%_9woV-*J4-HxsMZ*A1|B6Tf9RUy`?c{0fXkJU z@@MQV=pZmhOP(BU+l|*Sq zbK_l1?)-mpY4fF_71~AlihG8rTKB#(>6WYIt`{=(IdVH>9Fqs}jf{yA?Nf`BR={AW zF|2F(WYlk<*>qS-$c4viJt)mT2ql<-l{&OsDY!>UtPMu+1N2&27`>oRk>SXr`KO|) zN>s1d#h+nzClT5nz&-9LLO|U5AQg})Xf(H)37ebZ1#LPtX(!gI3k^;I`=zS31jcvw zjpK*&imh!kJe}MVEux^+Jwi>*rxeoViI+9TAR;uVz7?s1$L$I!d-ViMMq=r=J*6Cg z1uy4Po()RNXESl37LXLDq~!&;CE)eyL(kZWMqV1lepSfEu)*JE4`!4jgtl$E}&0=ri> z{t{a%I$;c`>#C%KAt%%F8sR;rl5SvI9@4kMpP&PSV^9kCkNWocX|pjJrG=&?H16=# zY|=g>B!*?!69LN@8}#KfG%F9bI`QcB9f%>5E6pLl#l%aof;S~h?;CR!IAj~yl&EKsddER`56q*UZwDG8XS`Q#a2BL&eXrt)4O zkZRz$AX8pS2s@3ma*Z*myxqFlJR2}x0zl}4B{y%!67C2%QX6oWfb!%{$XVQ!HHO|D z+t6+o04h)_K4P+F!okgFey~#E^UmW?)4)>UYU*#Y#U9<}T5R3LfB6v~qog|t>m#}N z$5|k_xtFtEQxjBK$DF$te}7{So#vdfd?N{QOgM7?gZc8l?qk%$YUT5ViTst=7^oMP z&xH#I|B>43%2`9DTAh4%zC2U*O&_-kxy&08umO#fd)Xm&G_D5{3tI|bYMm*6v3MRz zIE@5ptf?$FOy#kjU-X$9v0by;$LoPFPYJJdGwxAJ?dvJ|HX45a4&<*-D&iK%UeO-j zd-^kR8?-7iOHvxSKC8wTD&2rT625W-sa5+G$X~sNN-@puROUN1>{bF`wpy*e?NynH ziWS;s^|#9_s}*_9a;egrgYm7oT)Av2jpUevR)=%hVWsSD8-!XlgDFD0mn*$h+>v8| z#yeY1U4<^m*~^*Dv%#79P%cYl$US+c5@&0NghxFR2aH@6{I39S$eefmpg)b~+#C~~ zydjf6xjb!0#tF@7{orWb8lj~wJfSmvO8G$j@bq)$}W;P%u;c$f`t0_)+ zP0~tA-;g)4dZA_bD628)2X3&*eJZP+&Rj2O-VnH0)c`x9XP*q8D*Gv;p3byNO({g* zXQQ!ZerOri1E8Qc=`d?MPhE1Cn%)XQo3?UYTgfy>cy<*If4`REX!Hj4{QQESfqoBu z5^_&OGZW;v3Y?#V)UUB?-P0(L9F$%bR}vwHIY0T2VY7LhV037@@|%}e?2BM*5=nWWhNs&ossPZr{DK>J1w4Ezm%;UomHa1In zhpRc^>cUSm^Zi>Vs84)mF?SPNXt!pz;2+H-OkBV+c(c58^VpoDYuN3?qx}JI%nXlW z{%U;j7@(-3muro`R_0R#R{gzKXf{?jcb3nj=uu{n;vLE=&t{HvYkqcaqM)9Fiau%c zLWDpAj6MzSZX^qT1aeAkmHcVTkJy((p^`k7rMfo%#qvDS7wMhDy!g9B!gvi-3ZA;rFjqWQ#1gjK3nCvK0Yl+`eWfc1iF4-g`?5f0 zAEeM(=noYvRb^EpXmiEcH|~4EVi4hc{Oo??vh>>ZS2k*9tG0ZKdX!zb`nty>t6cHo zt!=V156|h`wY-8p`u!(9_L1!i(bH$RzBi$IBZ_r2GQQHy{;LIHwB~u254xw0JPMxb z#%>1kWo2T{)rCZ2eydkF5NE2%ZyOYXfkV1T4v{9(*t9;>!@|sR|AIgb@4g`W-7#S) za?&Q$@|9-(fV!p@Z=bya)`OORPt8XGHu}mg*Pl$}?rY2$%yo&uHzjAFI9~;83cIeH z4`z}l2UjmoAHJR|JjjP;w?~3?JzSC`D>q)LYPtOL{oC78_CjPw&NMzC)ePegzxNnFI%V{k0Q2 z6#uY$n15!H-^+s`2L5PtV);3CJ@E&RtcQGkm!=9s@Grd=m9^5*+Ei1T`3?b%`Y{p& z%86_B$=|3CUf+H%Y)jlRqCeCByT;Wj_Mofu_3%$JiM(LV#s z2@Fdg&N?FG6t~~ROGbG_mrLN^N$^QU6oIso z2P*k4s>>LR0EM7a)~;pv3vA#uf& z--WM6$DTufKfu`YAZtA2$45e1*Vrtb|$F{bkQvWd)o2B64}DR-va?59^}3c%RV zwL3zWbggH7o(TLL+#8BTlD*R4;7mtILT48KQrMmR?n~`Jqcwd9T9eLlQoP)5_R~LE zp}z+y-?alHx$Mw8=6IRYk2&u74Lx-AOg;9zHE(&o8;U4EZxq50@gsMK*HW+Y#JYygBn7n9|?qj1LfoV0=#B34VFk=(2? zXs{?y=3;4hHk<={@wgo7Ue2M|Yc+Q)8z%W+2J3@}Fkce2hP>cYz}y?ePZG?L1{F$F zOnfS#%~DXPbf;UyU-T(-M#8rk2kai^4I-Lzw^}%ho#T7@;$G++WYC7eAWWmltn2yf zF-MrOB}7iR@S9Fc+Xdt0SbjZQEJPKEj;#BjzOB?KiN)9kpGBN7yu9EtcGY5)t>LV& z4pc7fpuDv7p&-_`3l%%3~rDVy_8C~CTtj7Pil3N%q6k{EPGgb)l&*3Z#?_*vDn0J>gy+x&4as6U_OqN zKF(vl2Qggt_0L*4gk-|X#_Gqvq#3$D0dlq&ipJ(P9x!LV9Z4&<@4Q1JXBS^?x>SF6 zB&xM@}Za;u$NAJrN||kZ-uCIYxa*v{x9y0;!>gi z`QNS`@Wk-vFN${R`th+1jNkjbZri?$VGR&7)H}C>?_De%@M&m%uE2j*nrMdSOV1rI zAH4bL^ZcKM{=I~YuyCnga4kMphz8ioe?0%P+}n@s zS?K7GGTZUdRlkynA{0LJ2FPxZG%2q&7P*ZmK_P0vt+2j$c-j=_YDdvEu2M-AGX+<= z!Py2|Kwro>@j9T$7`YH7yATD#2>Wc1QMU?!VvQLU4m=q_Vv2Qv#Tp(fuSx}uk!7Q9 zlo~>`6l)*}h!5IjeIn9zv|riN4a4lV=u)^sYB}?w4e3DKYT+SF&C7LB^j2Uj&paCg z7*wHSRt1RMnrLYBs z%quKM8z!j#(yP0JAU(>c6n~?p)-TJQ(;iP-Ejc5qhaU7jo%(nL`naO0vS9*P1cuCs?+!?u`9QCpL=oX*}c8LuH4LJHb-v1y)^K_#pPcQ zU3+(PVfz0$j2c2SRQ$=p(HrgUQaU&1o2aGr({WCZ$KR=C;_BZT7i>hmNQdOZN&tU( z@X6xLK>oei!II;y{>EwUKfgWcDT8;++jLFYn|(Xc_eCeRH+ zF(iDn^}^od&k4dGF$-&{MWSJc(rX9H;pRfvENgLpYjBV*gY+pcBAZFO0nPK_C$7h~ zF5Hvjhs&u*n%x*+Ist!lcAZVRx`lD~tBrxdEJo6LJiFe`WtIX>AfSmab;0irf53%J zkes9FvCL8T;U_GBzoyui^BD9)1_EjFIu4G$bXq%+%(irF#SA(WHNX(SgN;m$R zaA<{Pb;m{%k*HRo7gb~#Tqwjm^I*8i5wUYRU~oxD6JEvhEH%;rXyr_$kvd4w3$hOI;4;{Br8aS>rq`$-L?SnM zCS_xVs9|LuLwvfD*v+lF87!W~VM^7%FLMI;bw=XKSuIk_VEPgbOLZolhSqc%T+2{- z6A=_W_N0Ch5o7sfhlk5Dfa*8J>{Qkw1*C>ki~l{qlw;yeZ)m1C&!*pQKHA$##Zmo| zJc&FTHr3VO)pkwYr?Z(}$tlDD0ncgAEeK=}cn z*z4IUQ8|A#UybI_6{Our_o5womf&}#>g;RLWS&)MZoTTiW*$G=N*22Z2@|S@v#}am z?fqj^J|(k+oP#9x&t-`;JctrV7!jO+CGG7204C8Etz`m`y$V>tCXzPd%q>;fd?B93 zgRH_Bat_ZEmGPcpWwm@7d?iavhA>dsHr6!zBbYs-tfGMhjh7l=I|v9xpz{Q@}L-Z5@UpXlfdk zGC^xl2eBxi|AZJnxM4g7fl2corIjJC@_Y@f8ztep%T!$w3#iH%K+dX0wn`VZvXzMe zlKaMugHbK*PlfCsk6q8baweLI?>NxAUg=i$D0#)){!e>f?xxaTQv^hM_2%Wl7m&Hq zay+87HNT0vfBP?)WLE5+8oH&$z3zXM_}Kf8k{>Qa&+}kW^48yfV{h@i0!VC3fV+Cw-+r>}5P@zF{5;>6LXo^4Bl5rZzs!*yzVF2?-s z@h`lKqtLCm_@i~~p`)m^In?-0E$Msy6G;v3KKsnoOxtP&W*O;_DknyFnB*H9e+X`Q zL77}`KKRD&Vnq8Ee4lnR((JomPEg^H@_2BHOr6Ve z?{8b;YP?7?H|e2pl&=J6Uxd{%=}`kEGcWc9G9oFFD`{3*xD98tJoBVpyxifT#nK?T ziENI6eM6wXmZFxvCxrNmK!cfI+h%>zUD9h(81$Su_w_}1*{@Za?z3$sdlW0=G z{6L(Pr~Ruy;n`-Ar9d7A$S_FQMpIrs-GCJ@QLw#?%=8Lsi6^7Nwx;kt0muQ^n%V+F zC&dxbxFA*p+DHioqly7@8>=E_6O~lD+!BF`2_*LLo;{FImZ|M)+D>35!|!f{AHdS>pv@ zGZ-$hR6NeB1(_?z)(lBONG>swN6o4OgO55W?lD$Q=HZxFOxW^lk&c4f6T{hblBN`T zu!OKx?Wx^Uyv(ivW{kHMMABZ5Q?iR8T52UK6)DBAE8v4=YZQztF4*LJcq}FuiM$%r z2_%{Yp00itYpyn#oRoE>V-wWl`gny-a`_%J7 zKXG7PR04gmBsEua84l!R-DW;1FBZ_K^(KA;l46+>ouLZ|-qmg6dy-Ab-ud z3zf^S+?#Fd*MiH*;>M=Z;OGS@JH9;9F&Tnrj_y);b-(RH=^CAhmsI&J>#H>M?(ls# z6x%Gr&WWWH{>#(nN}rt+ix0+0 zc|RWyaoESCUu!}M&?FpYk?h52@8)K5{ml=QH^2JbC)BNnyJyBq1}tQ$0(oe@HC=Jf zvH80@>x=Xnln{=lXxOy8p`Vc%;mXQ96dhNpsJ4?wS+XdPR%z5Ll z_^E6+BG!7F!6+Cjpp1>4UhLk2gOS+CVQu)$wEayB5Wj$8CUbrxs=71o=*?5Rj-782 z6O#L!608Uxq@k2|CK9z@kjOq3z8NpifLGRZlENM7z<;dCyI#oV?Zoy|*?-&k5*AFh zmfaaAnYo5MU3MiWHbKvjsE{4XVH%=0&jgLBZAhXCsUA00S43d<_JqRoI(^NjR#p`~ zP#d!A03#GtO6kB|CvIJ;4b`R4>UY@w4^z<;lUU;YXx(&4SO?d-g1*`p;nXUbsHnjT z<@@z6u2K!c$Og&Nx-uPjJyiWk&>W@vbZ1!BG~n-A|>dwNQ;0lBS?}?06RCUVjRVSKc}b! z@cW1vfnhUXIK*3mXs{AsdFUJpDk2PrwPlH|h8ATBq;v#>1WghdOrTIDM~RXqDkiH) z2q%aD1|xw5=@Cu_d==nPhDG29YI7WroPIOyKO>Oo^C!Td>o?(f=>^EDej|@o>kIj> z&9}za8qR? z=Nu^r;T19}?(}tgP{grSta#+)kggAsX&g$RhqU>_#;T~K+svvQf@gUDKkxp~y1ZX5 z_m~O)75e*C8-t%|e17aysnq_FC-Qbem+ay-`pVgJuMU={8y`FYU_OD_=glZ_a;zj!{#iLG=-C`tQLfEwMV_rYh;0g%y zKe5xLk;)MpnXK~4Y?`GqY_H(;rC6$&MM2T# z*&X&=nCDJ?12roT!@=e#^N#FAp2e)F+*dQC* zqc5cQlvk#Mo36oR%*(xg)p-hI=6iQzv8f_f$~N;W3;o5U{uEOZuFPIHQhDFCWV87F z&84V-6V>NnwooIuDVAQ3C#k1Rf6e+z{58N&1U^sG6Y1?s^$tc*j%V4>}`M zOdsdA1MR$p%O0^H!k+*={@F>($^n(IDwOK2>kG|fmsV`nDQ^0DXtb`t zpS-oG`A4`|7Vu3YMq8gpgHYwDzS%yNS>vK`J?7tM&0D$YXd*{^t4zjQc@14(%seZF zJ(Yjw;=&lfEiLo#bYmGXk|7kt52@$I-(%y+eI8_29;cd00szGsILgB^JJ>}BS|aaW z$G4%`H^d7JQF&wN<(GizhFG#!>mk8b8dWqv5ejnj{|E@&euqgKm8>cF;c9ZJgTVnc zkEBFzYo;EbGvk36+b4!w143PR=U-4JlXr^S4P(SaE|u4qZdl{(eCA5hNx}Y*dw;<& zb{iq`%A9s=8Cgll2d)wRwRu)Paeg-V^Elz6ME!mma83bhq36Z}Pj9TQCPDi1Mt6Hb zFQT5Svv?!7iBo_MTgD(Y1y<4Hm$!UI6)z~k0th`MAAFQX;}6=YU2G+z_A)i<`16S9 zE2f}R=O5c$^^Std9zH-QYlwc@FkhVBCz!@QoIYr_QkC{< zhf3$Bc8h59z|(6O?g>vgN-eKKh1t2@k%U^0`tGEPdkZpBWcwh zh_Rbjp2RzEzFJu2UBtEYth56!%9H6DcroB00(2E>e4WCw*q3t#QlhZ2XpJa8bSJ5j zQ9O=mNp(_>S?h4No2!BloRo?=pJsTOT=FyC09d63@)zp)nz$x#Jdb~G#Zq;C7RP|U zEcgnVND6%RrIPEtIazp|%#>R7376=_EihrN`n`W($ z%mL6Cl!}lqg7x`dS{L!l#^xnAB1zs=N}eiUT%9S{t0-RpeY72+#BBuvV>&Ys3a*Tu zw47sQIBd}_Q^l`Dr805t;&sa>tyUUgp9Ns@?mJZA z#n`Ja<(f#+@jsxPH`pVc1UyZT5^j?F_BR|j^+C%0~RyM7>4uO|!3 zi}kBzO*eovoHgD+C6?Wa0Hk_{Zmyr4N(_I&%>CPPBpiR z-}nyS%EUEVqXfDkW$A%#ciZL}B(FPbIoY56gUaj}4J0)Zlq=LJE*(@8$D#_?yav<} zr5_ZTDy~$^SdIlWzv*>KQFyGvlK~Cb*fdaCJ`=HHQE)tL<|zw_2lxz8G=T#Qtg6Aq4))AHy*mI6>n#A<6GW6q;b{K_89K1)UD`% zFjWqx?(4H?O5ozJFMftjp_}ASphPz#1ct$de(zzixXouH>xkUziOHJ(j4!p8oE=WD zmFM$Q)|I|zb^WMN_AUFsM}MW4TsE5+75Ga0Mgj_j}yC@Hy2Qb23 z&aiuN)n}(33V-F)WKAnClra#drIH>NMNHcaP@gk@1sGqhTvPRCPG?q8OhY|Zx()#U z5NL|?K&gb5%N1%3Z^jqVq?e4it=a-d=w(x|SGyZ3&a^?=3z_t^$`^U@LYng>vqlmG z#^$0KfdWq5Tbc6LR3-52_c>75K+g@E7`!jm9Dx^)EoFn*Wa`U03lGtZ##S6{wBGxXiPH1Y<7E z!cysX<~Bz7r5qWQ;}Lky%0`#dU_M*qr7cf9kaIP@1C#-NZ%wm!Q&pt0&Xb8OmJOw5 zhD0>xSK98-;|x|;9Q5MeR{ggYtL?r@a)Pgkm}vX2Bc&byhQ*}JYz}t{L^NK#K)65} z8m`G?U!qHQjHc|$%r^`)P#eSNIHAIFk>ot=;}d0dv0kq&dsJdfSE|dE`KGtH?<**s zL!TBS$|;NKvE_@~u~AKVaz5D1%XT-c03~7z(Ia|R^%4quq5BzzPB9@6E2S%@B-uH( zPf_&3zbujB>H5u~&`S_9@MjzS{I4?cuN_IOu4lgd=-0s@Q7nt`+=XQA^7{DmnDf12 zZ**`byi^j>pIiR%xpROG(m3|-J zO0K~M_z6!PKwk@!@oP!pK0O;cZb69NSqxdL<`)-|V?l2Rx=VT6AKt~bVb|)NxjgD` z!^vWr_MGONlgoFS%)|neTh?$?FNHr}P7hl__GI;$A9pT}j#e8<{q_4{r$|6j$cI;r zI@l?T6`~rh=H0MArC64;Mo}@a%)Hg2xd6kSNp--4URfIKRIt8?dY-VW#M>T#i?`x`%1m-Lz8NFAgwQ!=?e z=J6921J2iR1e)9PQs5+;XjB|he}nWmzBQRA^EdM6<_?6}I-AX1TJLVjl6~{AAU>SFTW;)Dv*#;f=F>bGn=-to*Fq-hU-=U+O>`k-F2;U7{M+!SB=QR4scM?g)?0Z>XnoLO@M}7&* z#U~$^(Dax`%c8|{BCf_23jG9pEA;7TydDfe3~V#c=&YC$z{6S@ZR5yFQ&5+1ylgmr zD7!(QgV)+r-WdjPjbvG566GbZu)sn%UAz#XKL48r~=;h1TRWvl_nF zbg(fgIBy477o@n*B@>+ca50m-ln#kX zH|wL$wpk$?;*C}@nK~0DwuE3t0!&cNSVRguKhZS>WuA>352^kf72MfT)>yZ+rz)He zFg|=34JZMqqLToE0^DfF=dsLVmD*0*(LeND9xoG^hUFAH=wvv)G5+-_waFi&#g^Yo zV0ofe;G&3tCvFD3^4hnhGHUnpj>g8*P;{xfDQ<%RWPaFKXjjZ^Fy5syU|Cy~yrBF* zr4|Gz^m`0dU`?~?J)jjtHZIN?iL{m}Sjlb}poydWf>GzzISur9nl9x3r|7+-zrMVeNGo+2gfkOR}xNAZ8K_AVDIdfzG*du3L3;&N)@x%CW0D2XvzwIS^m~ zgBT={8c`ONEz2IS$DSQ)f_KmHdad3F$l` zrUWM_Pr-(qooO32pZhut6Y12dR9gba%obb)5bOepvz-vM5~}QC3?xSM5vQ=qYfsZT@45L6XYLS;BFs9 zinqefaYiV4B5>NIL2K+fR6LPZDm0r4_-m|CjJKhrkD)H&K|Fro%tM>({D!$qpn6o{ z(;hWX!Wyy&KCWud@mOxgVQV2AWK|S)3ZY9#5v*O?zKe;4cees`*o;`y>`LtA$KAi+ zgxCsHZ4n|n8{9o0)QmE-$S{^mBE%LBpDElB65}t`#PS4wi>V~02IV)Z(61)1)Q#=8 zn<>m5@9wPa_h`H@d7rs8SX%MN`~A<2;jz1Qh_wp}R^RnYAU=V(GLXR~tEAKIwNu%) znfQz3ppkmIp)?($7!;kW&8Xpo5)ECt{%V!7srB?k?T4f&BR*aGc5^2t5#c`%RyW7_ zi-SAZy5(cn#L3i}x-va+9O}tjvGnldIsHSQ_P>lANdtWjRU-}yy4%Wem-t)Lbz;7@ zUBGt*bE7hri}QC`IkC*;mzJGa0TPLu*>7vbxU=;d$Rr z>$0W!xP06pDxHx*2n& zY6)GRG*jUHmwX{75VMkfR9eVa%5V#(#E!Xj^+)zt@qYc%8WPxW^yM^`jPIq+G3i(3 zA1iOvcXH3;A?M+dzyHGnP4%lVv-l`@fo+0ZT(0xo zQ=3~)T>?(M@2Jo#rwMO4tv_eo1Elsa!gL=w2nl~zk$!A7&cNMU24(4IkAtlMcKqZA zt6RgGKNze3a`VGW7o9{QP1xL%hhm3sTq-AfUDm4RKaFwmq&S3woN=xNrRPAs%S~Sn z_TZNflz|R*pqp_kxkUuh(C(cvG`=u?`-WF39h#x8ro}(@iCKTH%&;x(&b&%m;%(~L zI)8IeWju6IMvZD7&dqRjbr~MaJwOG;>&OKlcYk448cSY;iv{2l7Qz8HT64mZ>C<+6 zNt#OEXi4q=mrkEj2J`s;pzQN3Hl6s$m^9-JmVBi0ES^zA;WDuvAC+F$bnE3hSTgrNLB_7NmtlJ5%%Fs)Uxw+U84CIG+qG;tEU7a#VQl%>XdyrWVfCjhi zE&BMuc&j(^jzUz4*u&-5OKE=F~9|zRV70@bU}mks3AIgh!XlhaQ?L zU~w*I0<0jR!bO9sELjnrqu3hjN0Rq0u#KjqO#ujCrBwMvYK-IaJMQ90f6Y3c&I6A9 z?@^jU#e}7#i%iYuo8&cXH{})7UBwMcy<5ZNnjZdgVHL1E=kxkR#C2MN1#ZeW6+72U zIlFHbu+D_gnqFvsT`TB&O`fh)$-hpC&y@*A1%XaBaNv>=y8?&GlNTqK+L)BV^!M&Q z$o?DeZ5f==8e&oBsA2!P+JDdE`ssdPPF-D}oY~XJsX3`4F3X$z=JFVf%*H*qBso>B5xCd)+PeHNP}yMGkd%?{pK?e`;ULPRCW-)EwYJ;!pwj*pT4q=b`<6*!vCK}7^4!7~8DMzUH{fz*7_sa!9^ko8bnC3(EK($E|V zQj_3D+n~VL0Wuw!uqmh_i!#7cZIFzHX6%w_yYk0ALOK!(V@aek(7UN+sv~eYYR*K{ z2YkW+00TxItRzjB4vu;dJl@^%8D+Oq+OM@0;=9^ za~Yzpg4YI1a%XlVML-xm@L-oUONaioRydz-7#d2j{H9T+SYHAq3dvP)K+mfKk?IS1 z$)A(j=3r4@53^+|r8G$kM=6oCN(GCA+@T|0(G`$jcFPLOeO5j$a7dC!C@U>is^8-E z>nkp_-EZUCRZvLIFhK z-R0kAi0O@9B@8RTd;A5{@LEoAr?|c%UMJ-F-AI~I0A}pnr6uYVcuaT3JC`=2IS1pf zE9lhb%17<6q2J>Qm*)gwUs+~46K5O)F8{1su`dw={>iWfzB)i$0%!my%!T&s&`yW* zRm6Og_YII-42s#4on{{u8#-i#(`#~8I@3+`(K!eyOy089kCM}DsheFAq}A)Zm4>sV zm^xofB3G)*ki)jKAJKl}!9zW0qJ(5Okw2HO(r>Q#CFvx_V8@s4)P~FRCGj{3#(-2s zn5}GO3B7n*Ni3aj4v?E)n(?mHF6j41mpXq0;O1}4L;EZ+V+eCTnH*eN`sF$iI~K?P zqvF2y-Y-HFF?W}qrKT?bcmHe|z=fz^dsI9!{}$cbQpq0*znpV&4L+1a_QxfB>~iaF zH`NNVoxT4j8xQ}DG!Unm-$}gLv*F*Mh1Ld7l!<4oNIraHA{4vy>F|%IuFcB+RS%7> zX428#sqlZEC>=gWJl|>>J++8MXWq{czt2^g><@OV!TKr_as?=Kw~zoz5pDRvu~$C( zJBjJvUw`vWhW|xY{yWcQCLTDGr9Q)^en+JyGI4LP_yEMsC5cc=`=)#^G&7%tUT$Vm z5zRld&KK@oUOso~&w}s0v{|nQ8_I)3Bevc#v-wEekvgnQZKk(meIu!lwKO1RB6#~MiX`d41A5p}t88Pk`Z9WO&REsb-T zDeAFIkXJ^t%b!2J_f@c0G>$EPb!|HJ;8eF2jvsWB=>L z{wSPy`RUK@J<@_pyVs`S-0lUl`^`T(&Bb3Qy4#6I688)EYnii5mK8=nzcM1hk)`;1 zt*0XPQ!jQl4sTNG=4~W?zj~7|XD+?-Sny@q9y|TvU*?w24!^cV-(Y`l@NKKT@W%3+ zkj(v;qbr^BSASo*@h8zOefb8;m1j4y4;#)f0*t4 zG5)(BI(#@%m1}ePCAD<W z2X8)_7V&3Ff2PA}`^9_W44?_)KPx5ff5^<+*6c_fWAK;aexIFPdMfrFLD8-KV6%Na zRTzG{A*^z5K7Kg!zF&VSQGPXhof{^|%#z=KqirTRwKdmiY#heFl_Y0fG$$rk2Vp}R zj}sYyXMbIJxVroEn|zS)>+R?-SX=?i)oKjemVi1uY)+-D`5i;9Ro)zgz$iD8IMFG? zKi@H0!=*5HYP-RhQ(OA2nT7xvWi7OFK5J=J%&on|zOr^$$yzZqY(7>`*Uq)%Va^7Q zN>M-1Z&le%+Yi@N(Xa=RzXASRf4K>rJKPr^hPSN~iU= zfQDshxBbmP`SIxs`=uZXRPw6ont3C3IkvEThn}FFB`*q(OZP9^L$kfo$Tk~^l&I_1 zelz}=-}&=vin440LF7>CtDGon&4-wx)9tQmFCihd7B-b^q<0(hA^@m#n>}&OwBEq} zIv#%usZ@SdjWlM&X`yA-H`V@n|4co^w69${;scF2G*;^%hp7!flYYFu{{k!`{G718 z-JV~o3aQ~t-*zzhk!fQqsJO(FP$FJPAh}{~EdWMB9VCNQ0t4a1fe2s%f#RtW?h}m) zC0aA}TKu=Li+Nsj@bR zgUJ+Ktf?dgVkLAQYb?iEA@E}j*du;#jD|6&}LN*r7Hx6c5Nb$_k(&@A$2bb{3=|NgVjN3_F^Ky(S$wn5>JdFW5v}GM^1MF zJLQHvPiwq;EN8uF&93+3z1H$n4&`smw$@fC_)nlpDN|hO6}ifslAPpVcQ5x_vqy`S zzLGSI;#|>nI<=a*LxV`<3L`V$R4l+S(+LK+G$Re6RxAkLWQ7BDXLwoD5HyB8pNRm+Eg zHm6fu1Z+L@VgL^qt>J@yrc+DwoooZykZ?sB8?VYdKvQUbgCqD3P-X=MK{WqXXwO*z zK)F@xtD#|5+AOcDD;1Z9GXSq;^{ZfM9oE&r+=OT55u(8G=|i*)fOY5VfM1dU^#m5M zJ^kdoBY5Azs;!CsbPEMy$>r-Xwmh65${#*o7xV=Vgw2nxu5aAINShKLb=BzM@wevL zhm40+e#w{L^Iz#FktRmHu0HKc*kJhPtuFbi-i zLY!|>Ln0S<)J#1^XB@)1G@u?j>>#j(W)8%_l_=}sfL-0HQ4F;1y}tLBA;RE z*3R&`&fV6A`$cpvGQ9R||F~0G3C-PnZ@rvlmWeNp)F0EI!_Ty~`)@UyBY=aHjk>G7A5p5CenNCbpecW?t?lA^*!COzf~$j<#A@eW$RD= zLEE}i^0&T;=J4mn3dqQ}J}3=K+Nni!xJfQIce`41rO{n{o)DkE3^bi?_Hr3sS}>B7 z<90^};^>El!=%-tCqL!9%XhcwvR*AE{b_;JEJE@ThHC8zmvlY8peK-x5?g=-1()}P zQupx5rpwc(XfiiOE~b2EE!bJLAe=bkT|YkNT}-K z1hc~@nHX8IIMB%93#aj(AhH=1iPdOlZC&3H2%`WSK*d}oD>5S(P^5{)cs>Oyjx{z+DqRIK*gdQj zq(;w#>MKRpW1$++6)uCFX&g zW+)SA8?o!;h)xGS4@kRQ`8e7tcuKj@h=Sq7)LO@?rQn;x`{0hFjSPo3b~&Gz(#?AO+NQWU;i>{9?x=|#*r;Q`r?A2 z&F=0ghXu(3pF{K_Y8rjR?&WUD9Hp=7lwOyAr%-;=GY zePC5z-F`!PgTJa4riX9Vx?`ue7W&jYdhw~>ovTJ)D%-ztv{d?mw{ulOD`y-(D$x@& zp0UF;a`dOQno|DcUki}*{NKNnneY4wc)GQ(P3m9yIr{_*iwEh&Pf)PK?7U@Fw&VT# zgR}gVOp6CNwc+*J7`CFEFaFl0?SsEO#$!@aHr^;N!!mX3g>>^fp^Y~R|6wtAAvr9T z*Ry?LwK0nhU&}o3-pS|xb>{Wr5_k4oIHg6SSf+Qdm|t8bfA}No;{tnJsNq2Ff!b8* zvK+kyyJ@NWjP#QJr1-TJ35kC_k*3J%Bw8W9@ZPob<+Cx z{5h2jOs^_2+b`G90-DBWF-rFN%yNk|yyX-d6q&%K$B9e)d_OR>rpaVfrPkz}Q7&O@ zFQe}nu-a6@_5IrljM|0IMyoNjMJr7k*KoMWq~Of658N_BC}j*_6l~i z43~2(KK;7Z&Kcd5J{jrvSQdsxf2olf2n@uOW3Xym&`s>+v4IJ#bq!>}=dY!*^KB2A z=h0lbXE^VoaOmI5@nBKOwXdbk*r4|T2K=ruIK;;D_*({~@unL<#Z~@qY zzeICKX8K-GG5l&@Xk(>9$l?HVUhK*}Fona5j~M6+X9(Q+5Agc!+1v&Fpwtgx6GKl} zaX|s8mzSFm%L;0fzE|!e+T7jQbt>m!&Ji+AhUyH{QIp=~a?e=z>#q}N`r~{XuS~Ex zXJy)^C{V{8?*^B1 za8Ax-iti6-83x$doAxLQ_FQpNLJSBl>NK&DbZEWR{le;v>QWpM+R5x_F{`P7tlW)j zRh*%Y6~RuumUK9Ueak*ItG=MSj+a%zOij|B^6V8Ny8=c!Ex1!96ho>ocBXN`5EK|Q z^a15vNEG|&$@QruZmt&&6&*(PnG%y?N38`WZE2sy@3y#va9%7s(K;J=xyV-;sfW|a z0&PGcnelC|6~C6qr>@v32(Fd8Y^oWb#u4;iIw~U7o3y*oWs3353ECIC90FG8U9jZL z@u5hoz}{ua8WniO$`_JJBWyK_uD~*pBfh-Lmxx}F(u#(u3tmwIC$?#!+~t%^c{Ef< zok|5l{yN|BU8`AE^UYP zS0ndg&+P5M!e>UjVN?BRBX>3Tq^M0{%h!cjvTfQsVY8P>{`RNM>FkQyu2RL`^6AqK z0P8;;xmbO>)BC(`YErQJfb!y6b4PA6BQ?Ioh{Z3HK(V@ZR=~r%4RU#aEjRi>wAa4K zP3PO@j4BM5zI))+?#_p)S`Vp)7(mdLct3r6vJ?F&lc_xS(Qv2NqRC5Vn80g`owo-d zY_gW`Zyd{PE->tUmVH2;_6G5K6k!WUi63+X%z zD%kVpD^PWf*IEJtcXO+boiSw~3nUgxez{a{hZaVA>RXG6kuo*9*uoNDZt@qotXeim z=*7|uLUH6}Rt-;H>j+5D3T1H=cKP*r5l2 zS-W?E>?c#)8aenJAH1DTcxRUAEZeyXqhd#Y6<*yA#C5+Qd8>E*(2+uC&KC9oRXV zo41(Jxlt7@$S^lPc0M+LQtkHHG5hBY+qo}13l@U$Qsq?tYGcvL5bz^e^y-J{*2tAB zzfM-OmOlng=t=R_RzB44&qba^v}5uGUI-q>evR+KXEwv~YSk|_IBlx1W79D1 z1H+FBf@w!b>#fg%(~2ti0ls9FdrPM_>1f{BZjO^k_?t^l?F!T=`Y5_Vzf@ilm3C2o zd^ge}j(1njO@YQqMod^s%;hf*(Ql=*FBK~nbM8VGXyE;kNBh!dewJVT{jPj=6F$fe zQ%eiuJ)P~(cP_v7mCK_Ge`I*ic5nZWv5(WS@-)5HC(?!HfqeY=3mv-|tD%x&exbf% z|Lm|XJfk<585WM7-{O~FvR2-DC!@4lW}E%FR*HG*?B`qJ_yy+r{EZjux)MrY-)4Ks zWI1FWIISD-hPiEnI`Zpz^fIMfN}afVzplS_G365zTxWIu>%w!{} zu*($-6jzg>Jg=LGjMpTir2z0mR)r{6;z&McyC89*x7taQIl{jlE{kh0LiK`lvGn}WOH=cR#B*z zQ(d$y8(}p@_D!MIYk&fYV{l#p&w4v$~tIXMS?Zej3fPQYFG|1RZf1DfLnaqAu_7`wD8eaxN z3ZR#9^Qf$?7s|s^K$*E86mwY^jTco*y1rJ^rodL+)*sCj7X-mvmwoUOrzn2$m1GKz z&;&jSJ;BIgs`oH>MwaUI^Cw`4Nbra1b?&bt>M{ti1e8Yd8r21MuUvu%h%gehO>U6{ zVJ%NzI?#nDW?XC6Rg!u4ZKDm9>->cT_TmTu*-oumPM>;m$CGuhi5* zzKokaN2>Y8!f_=1P^#c3`-S4V>zhf~s{x0SMB9b)GGQ-*b%Na`>T~8LrMA9vIV{=G zdcTKTuh6Pde5{p9`_1{E4G*U`iW;#~e3EL{b>~~FS1$Yh*Fi1xNU!W+mUt2qr^8S3 z2jz776Q(J(W$jw0@Cr+vWBYfjN19K*+jx(<{Mo>#ax)?YK4XQr#5qZp2_ zO+;pPHA~UrO}Qi%V0_Ke@Tz=+Vo~y16^sYl{}72~MurT1VUqLiLY8fANLg zN$&rWHtwV|pO%-lw-=bR&04drvyOW(UItT*zS#aI`{VX~xqP;P%NB&Cj3cP-l3=X; z8aXF)IyaeKGpN~2CGB;z>k)9ZZW?3`myXTa8Fxd!QO@kMmw}%>*e#dcUio27$^j8& z6%9Z;QM-h5au=?X?h8q-B%hwcVt!@T~gM)!jM{$ zv0HLp!(rWrY9OFbD(m1pvR;9k3Lh<*-uc{gu~l@eRw-*RbyonXoanY;dLT=|XoOD< zg=}e2dHMd+I+Z2n-8}=Wo6_H0fb1O^n-5vR=v(l-lXZ#Nl00PoI5bDJw#(JoS-XXMI26#;OZWkX)8=ilfW zS0~S6&8KRr(>;N7n!DHMx)0%(R?g8C;skNg=B~~dj~n4KDb1=txEthCiWNKs~AXc1%VX3}JF+ZPEa{prC>m z6z0c)wzJOxfn1b54~}qjAn77tFD%dP7TU)A`C#>pJn8NVq09MNYfzVR<#@$xUFGJQ z9@Deu^wq+JWZ3uBvt4rN3?!JG-IikAO8=a`1ns1Kvs76W|KMcNZ+qQ+sJ-SuN=qDh zZL71uZh|F}p996~m?cJcOn`6VS0(ei)`g4Vv7gKzf)rj9Dyf_icK@zKoksCHtD#g( z&;_6${d_>zL&)NLdN)zIezMd0Rp@%rqf6#AErd6|tg0dOQ*Xy@8 zH){XuDx_EfrOZn?yJpYSA`B?+`;V0hy0+U`GzzV?%|W3q>(wo-bdX#dZ;?L0+SSes zIi;O7DrpK-xZFufNw{)}={S>Hy=>EnDyON8u_e^2C1SuTfW2zT9dlrQOd#tRiKJ!| z08evjx}A3?ze1rCNb0;#fZZ1RR5b1oZ8yUhnP=-hk-fub-r!PDO1KWnIeVNzYU&175;Rrn*{sje6F zwCC6W!7X!mtbM3IgVbe6@7u+?!2jz9DIgWm!0irY0JUt9voDk!&xwsNzP+DVju^_30AE6JaguI;>5D_{c)B6E`!Z@r*#&>4*F< zV{u#+EaN#@YoSXlFSoco7d<6pbS;8G%k}AQ-ou6+vzW%#k0nWBe(yf7*hwx~4iakZ z?4_J^Hs3TR{<3@>|I=u_ls=!2KU|<6t*P~l2D{pHk9<*k=T#6S0Y}&-K*6rf>(#Vu zfPyy7PMYB76UpUvu_-LYP0V`#6Em{>U!H5OL2IqIdyF){a%Vb;9XX<{G>TOvDqN6g z^;xTlwOi!aSLZMl=qRauXKU3#OQhn$pbBZui@;K>K9OSd;~E(}{!(RC?Y zm?oE4JXN}J82G8EVx*z=M(RS-nQ8|`FcCYA^ubg-Og1w$( zh>>XTZ3DSN#grl!(J|e_I@$)gZNC|JgDDkRjBewofZIQA4=-GlAz+=>@ZIJa9m7JP zcHBWyN5=4_$5@K1`YANFa%W7gP|ZEuKC*Uo=z&Ys$CFB>-sYr|Lu8vXD^RQ&8L%~o9q1pKI+KFz>K}sqPWdLVs3t? zp8MgkTQLi;vz>Duw0V5V(B{KJ%Tevn)IWwk%SR@6Ppas-Q}k=WKJwbL!k4>9d$3UY zkrYPF;Y&-I5xpKA|8I`5UV0J_ZMO8fdaiV!DXR?d09Nc5E&V4m@^Ly&vjz0R!mpDv zQ6&vZ%%lOSf|{SrmoRPDID>WH<*oS*J;C9la}T8EL0rH~<&#pO{(k#s3r|_2^7ys! zldThV)wFu7_^_`>x!Opy46MZa`Pj^2LuOO^80WMyFmQby!^uMj6>+uu@8D%S-b zWhgdBY<-om17Kz=AH$;TefSf!aQq49%D;*9m)H!mv2kY5fijU2d!FJjKV8c*aASs? z7x$URIzs8g>JGORZ?Yv-5Rl~>cxXuWhDH^T z`G0NEvwSRdXezR`vAqZ zw&vsvP2htbyC}|>b`nQQsixS)loq{#%GscQwEtf7c<7o1kEZKTv5KQ7V@=JobfNWs za0+q0vOp9PN&iC07pf54;06?4Wv_o{G0g%8TT7^ z#xmBkcR4O~^rGSXs?b4_k3%XqY_L3tPjI8ypYDyZkxogxkl7`r$YVR~!eRz+mhFqv zw*L8Kwm$|t1MYUGh z%O5Q?+ALp@RO+P0Nm)&d*uuq%S$j~=m-Ge;5t7cF$sH4B^d4BlNDM^g#S8tdp@;X2 zZIfdZ5tMv8YAzS40MbfMplC0!8PH*9V(+xi%k_mL7C*q3MNr@e7=?Zgz_~JZx3hak zY+WwUb#a1G7Qin^O+(kShC$GI5aT%6iL?cINCXV%ObESH5!|Qf!8@HQ-SAst6JgCa z`o1p$8+ffFB$#l3v1zBHJ4)ZK$D=6ZT28VBYfZSw77BZu1&D{~`v|2}H3zG1d6Tm0 zPAd{#EB2IT?nfPu;dB&^0VoosmmyFVM0sJ6WhDjFdwEp^qox$F00jjpO%ocUqM`*9 zqHgg`mTPs&B3Yz3+ZGrG3?u9;1&Z{b1mN%v!-{DYucESTQaTLTEVCkU06j}^Wk~{t zcd+Cpy+xJhU<%;F;96ZkF>;i$0dov|s)V3nHti`g`2VX`uSpj^2XG0M9s-PB>U~-m z0QH|)qfiE6b2U{0Mj8!h&~?}?_5N91$Aqr7A{Pgihe~afQmIm(WSGq#fp$V-1mkX3 zEJB1!1RxQEW+{bv=JuOUGOG&{02v0yi_`!s#^(ble&A-Ww}jKw9yAtbxF=-XdDVY= zb+I00^d}2sYCUb2xlSuuskrc~$osFQrtgar53C;VZ@Gx9Jm@4T3sfxN0r2HuwbnWoh*NC8rR7moI9t?k{$7d^cYetYG41} z!NtjTGJ2xf%w^WSsqdX3Mrh0)ecfWBx2LXT#!`)2RQ^i0(pJXZG{=;uDse=;hK?ss zHy`?L{vUtyO03s-Y!(E^!8y3s4{shN8AD)l?t_h$@b|ZCUtHpA%lFn}Q!y_1Ae!G+ z*Q>RkRw_*&Ok*huW#%yPhu*TmVsMTV4R)i9ppAtkO0~_2D;T;wkTcB| z+O95h;O znV@*2$$;uy#o3I2cX^~&V~C=d_HZUm0rj$5^;UJX&!L+drLthI9A_d@J&gg-Bq2+> zBYnpSacRq`>SfOBDymj1*{1J&Q*eA!GQ8?xM&gx-01%w_ zIXzo9RmX5?)T3-1bBdr}WuQQ2AsKVIE-ar)RKO5`hq=B7pW4(D+v-D`s=`O3ARJ6cIp#C!V7H#1m1vQKr{I&q^mU_I~KGdJDZ6KD4NH@gBpoO9$GhWt?w=)1hvx?qLurYUCMLG$_2?;?l$ zg>%7?9y8?C$7>hCPpq2w6YPJsy^@>XIyTJS0fRuqdf9m8_)Kc~f5*N%$gkCY;h*#6 z(3=&I!M=}nm&0q9W5bV^TFjeab8LtqQ|wwfTwC8qOJpEqJ>&9)x3c#!#tf%tZ`2Aes}QWLiNQgsZuzEVTr7-O5S zTos~V3hTneH^HB5O%<;ZD|^SOV`xcpSiYu;N zJRfRz+}m`yFuy{598=!#iaS8%ymJY1!EAhEQmQ6EDnO>cuM}?!r{HpFk2SP^TQ_LkCJTm{#T-1UEY3a(2qjll5 zN9+!i_2F(f*)45u_|=s+;_8hxA9TlS!~I-?i)q=T*Yqiq^C>lG@L+j=Ix z;ZdoBXvSEhttn=!Ho7BdXzjvPn!5)cyU9tCToL$H?MVnRBHXJ>=8E~~vA2|4jVk5G z7Alv%9%>)Trg|0-7tznvO2+PtbonBb%^zOJA}W(vo0!Uo7mcFEh|lhtNH4a7++~$d zP7{kbI0A+6>kHB2&E&1p%B|#sH-^pa=$9xZBVAfF#aI5n2ZUdxf84@|uSPDhA6|jG z()Ou(JNteMOqr^Jn@X~8X0kwAU5W%NGkPCSXyJdF?rNc}(J%f1+dw(3#Pzqb@pQ0M z$(?zoCD+gI1ij$VKrgQ<8#JQltxd~{mvSVcY};P zL2<_x`w9F2Nu*jE0M9D5KY)gtVg*I^sB+uPXRclg-PIWM|T=tx~mrCf9tJ7@L5^#VJ%k zw9GQH&IB^i8`9;BvvY7N+a&K#(@`TX{a3Y~CMSAIj;XRgAvq?MPMY`DruzpMmTL=& z@|(cq^Jz?N!4I_Vw9>!!?t6hWPgoLwV}F1B`2JEFFTX|>hHJSp8BXH}RaD4Q3BJF$ zn%G^_`?7U0a5rYWC@9s6NMY7QwVh0AYnXf_#0AqfH=Wr}>kx z_Q7jHczMYpv^nX#Bo9sV748$5ILLvmv2Q+&+zx2yZEiwYblc$LHN-U%&MOmDr6SiT zx#FIzadpSfY6RLf?jLgsl|*X5Sg$VBriYu>+C}B1GV*bJ(e`R_^92@v+S7XC%$=j| z%}l{6x26H|HDi^+-2g08w$uk)G|1g5R8M3u?_BRJf7Y(MH=;9&QUu$(&_5GOCwG1o*DPvu>l)Q?>&WtBtQ~) z6VgfN&ACf?-}~L~-rxQI{lstlu-0CC?R})v_S$Is@$Mnjg=6LQ0<~`Q8Z}8IDBb{YSNhc-FOjaq)s{Am2tr4z`TA>?ej=^<#Od&2+v{ zIe(0M?IR5qoA%dN`0M;vJU&>+FoTWH9uZbV2xX4#Q}rr#Ca}cQ&WkCTkAbxRraTu_A~f|-tUO1n*t91fj;8` zMY)fj(G>bv&mcN#bMeJccRb&1cxnF3i}J~-*wm?gAsFvvCdNIMb&tpVXW*5bkM$c) zpAH^P@TJ}(!Jl3%Kswn8TgB^4B)YfdYzGb(Q@KZuZcFP6{rdC!xpD8d!4qvm+TyOn zsI>6*0l5}GZ++9t&GL%9*77Mr8OM0KFP--;y5xJqbSdUj<(&%yCufE$9&)cTHcqXfG-b`E!YZQEzmnGTuK!nfC-?Dk>Rn_MFRI zrnU4?x~#)ri}l7&!Getw(s23=+)-G5FcHdV@+3t*m2w}q^Lx!nd2V#(Y$R}K8jkkd zAZfEEZr7=y;)ANvja?DPguyOWLJ2~K+cPu>r@c0uO+U(^u zdx`Wx&sJ3ISU=F_LI)ZRHlKj?g;$C%cJ#T(D_hjAm(PzcsAd&`xj-XX*nF0|&v(*K zJ8dV}6R90&e8S^8((Z|;SF-PVf#=QBw>#Sq+Ph)zb5!b01#b7vx>IFx8|CU6YFC)8 zo(icA?yR3=Crf`lF?H$S*z?oV{+7l=Ij_~JT^DHcu1<+x--GuL4ej(q`&FakSAcsq zrs8ak&O!SOgXacNJdstHJwrQ5GHpK4oe;!TRsOGD^sU_qF->v}?=;8+dw0 z7KgJYx}Z!(@}8#dUX5Tkb-o2sLr@iM) zA#0h~-8I(3?~E+Q1j9&aO8{kTcdV&mXhGhYx0b{7mv_#K~9(QDFD6IgN?vWesbXX9y~3*+Ej zIx^%ZgPF=)GG5?j+jFV?Vwf4NC}${b+@Erg&5&LoFvZ2ZY(C8F3z57jQ_95`?My+J zPXb4rRVX`g7_1Q?YWzWeG{wW7xS@)TbEF21@mU};ghUmQ+++{ui+BgK(_A7@na|mZ z@_Y$W0mf{H{oEl-d9PY84H2#@jE|Wf$wr*9-V!7eVI!=AOAM9DX8)04Qhpjp&if0_ zAU_#okKw^ggf0{dUPlleWlT{jm{z|snov%LS$9+97-JIqT8Qw0A{E+@^B=_K?}^13 z?f~ynXLEjvJv{2s8dbkcCJfF`=XlJiCiEWdUxA2&u|<7_gBC1&jr9}hVZJ@dr~ z!^lUnPx<(l+?74t0%dm)$2dnpk1~-=h4W6uG9feodE!QFis0k=y(1||vREkUqKkaH zcZg++L~$?-qwAA}!2&tN(6`}|&hHWg2ELkv3xtBL*5XuK~LA?O5~^!YhYjFP7~BmoHk zu<#HBP<_QHT`En*_J!GGE@%w~*x(Qw9_Q;lBT0TC5Qm6ju{7xl%@C1DutZK3vJnc> zGW#o#HzYxa;>pZ(tQ;%>X9XYQB7P>7obX2%4#&NC&gYMXX*%YH-LX!f*EpXE?B(J# zS%K-_V1lH=u*)Avc#@E)Wf&+7eMBk>44u9N`&OzDGseR>?}v3!Uf!AXp-DdB3=vkc z$fP1^_ulBd!{OkQOrU%=)LG$xaeRJ+2_+1B$0~!`=wx=z+^1Kd>5atvN7*FRbIOgqS}s`lZY5E=_`@bDm8@Asc%qAJpQ9FjxJ zA|BOg_& zU-IqgLHGjXOW>7WxTX(9)uS`+S6tzPf!=_YCoUWhVq5}OC&ad4&3+wml$-b!?vFD* zx4&2Nb}ox|b|k0qjP2aM zxIaG5Lk@$orAjg{LsQNuhI?`@YB67lxJT!cWtn$85MgmL*y-|l zV4MYaXvdX>W+6uX@ZW!-0`c~lNS>T#h?fGPvpkAyzZbU zoSUFR^J7o#8IGOo^CU|pNy=w=eBU_PUSixHcNeqRIMg}2JbtOSeloAQOq0>no^i?+ z-&0NyX>m6>T{)aT73YkwIa05;OyW7^nRxP068N!TcgRkAXks!CYd5XwAP^%aJ(uHM zsVM0f862H-pN?!7*w3E!*-n@S_Qqm9cM&fqpBdVpv!O#-^5m5BNor`M zHGMS04#W$}{kS4kI#WKH^gWTihiO0lsH7Cgm$r%mB9Xc;EysVL$EqM#B%mjW$<#}Y@X!#Odw0RA?ICSnkiw~xzi5UQ5?%& zN|4!d3FdUuQP|TBcUt7QEs~2s@GzeDOtbzF4wrxn9bvo$W|pRC2w6m;4s<*SS*0K) zQ$fPyVI69T_<&afXJ8igcqF8Gf+q~wNW|^tDs!1V{vSKwuH)xJdxB9j%roY~z$_3? zJ2T{PHcC$sm6R*W&{m7L#PXSBE}NsvMq=0v8%iJ*WPtUBU0Ey#sp?rS?uC^;kPX`I z$TAV&3M`cJu*IwkjTK1P))wJn6Y>4H)}p7~G-cTro{zV?nedcj0fPl>FyV&B~7@M)} zBnB=LJCif*Iw$wkFHM6xMn(Fi;sH%h%{HsoE7?nrrTK4GBReAb8| zMHrKD$-1G-2Y+G3Aset79Z$M=O^*i`$BL6B1=Gx3=PKwYyAL|u?SrSyz?469p;m?>}ad0V)|%dS01f7Wz%aoJ#ZFrAJO zSPq*%pF<<8H22e-)_2TfcN8+xKuZwI!Ak#%x;;yAn@MKt&!f-HU8DH`ASFJbBJClS>#kU#w$asmaUeumt>1n`Hw zqB}npgr#@=2@$Ucd1s4g)p?N5{ua?R)*wrN@I6uMH^A?zZqc{8q5R~qD5tDLmTs9u z4h@3-8|y^N3*djwEmDs{z30jz^#RbY)Yp7<71*zMRdm;zfNg(7W^GXZ>oG)J2j!n_ z5k2q=&?7AJ!DYbpv&iq4f&RIhL~9NMVtbJl8NerW$cxtlzBPxez7^~a@W@Llz(4;G z8T~2X6K4=X2j$FTBF7A1Ul>`Egnru&B4hVJ`HzFh(>H?t=6@isRI2trMD{HMwEqkF zLSUm`t9u=DVu-z)+Bul^Hh7y`WS+ai}0>_clsl^=uM#!HBP56D-d zB6S;}QY6~%0Q~rZ=$h}r_b~M{BvCz%z{f~uwV#gfBV%fiH>?sJAA|Z|7LnK}$UnG4 zv||d&fBOq$JP%m+IF^l zt`&eqmB>`Bf9s!-za;=){wp$Z8`!n0MBfQOf7+iwe%}c4>x-g$4S=rCks~GON6p`m z3x5WD`ySCRwn4pnZV-L_`ydCt6utN`$UnJT^sVamcjgbsncaZTe;;Xi6#V_{64Leu z@bgJT^kUV|pB_ip6rgT>?d|n&-W?Ow9KHd{JD(N3`cl>YRb=UFP#*m`!n_Uo)-KWJ zzk>eO*OB{f0R4{Fk&Y+8|BDOA^aUuts1!vq6TPvadkCxPo?1S=; zkBLq#fOmj4>? zmx#!@6zsYmM{Gfmj|P#SRL`e#c2V6&pkMJPGiR^NaiO-Oy@*scPCt{Yu?-iLqLMK5#aRrIi z18({qVy)hX)SuOyub#Ibm5|sVv~$gIQMnoF1)D`rszE<=v&dgPUp{{vd2JH#y^3ht zOK=>QW<}rhLjQ2i_p0@SY10CBBt*z^z(?Lg-X@^lU;1igN1>h-sk!zRKse97{|VraP9yiNg7)sd zyGC67z3=#=sIV5!>r)pI`3E4At3@wg2Y9G}+;trA*SCtk{!6I${hLKEZiagCpCkR% z=fv92koSHM<>I?U$9Dpbe1Ukb0RC%>sL&30^Xo`v2VmK&Y zfc}ka7Cn^)`8UrX{l5Z#ldD8uRNMdaN1{hxhVrjnFFJlR$d8;xaz(&_i%5eR@MQ;b z^#@@8o~K_U+To<&73z6SWirJ{42tM$(! zT>|v)gBxngj`YtZMa*mLd=?^ki3f%~+IzjuB4_bQ%0_@1!zCIpV|zdpZ*>+@>( z-#`2}{_(%@PydZ@IsCi)|F-{s;ek*s5(>j#rWQdewMeyt|NgiUB*Y+y0D=JjePaXi z?>|vpwF?L$LPGzm166q`BAWXzgr^~V;9P{y)BpbWzyA5INPrv1|J0{9Sn(s$@s)SZ ze=yT15lqVGvx8{{_8tf@bu~OGj1+^V^ApxX0%N5TrP09=p^_MiM<*h2A(8MTVl(lC z01IRyNO+h0!!Nprw7#MJl{w+yDC}5nz)XS@7iY8Y2hmf&-UmO5txQGysgd)jF3KOD? zey_O!LlL)mxjv8%1q3ccz?73eAn-viH~-pnNyw$hXjw@0Z5}XgHO&{Cg6b<2L%VTc zZWq%=qVEn#zkt*G!=5OSLZVcPN-Sn^!PEY5M=Tp-1QWTT1XyZo5Iy#FPTD*D1Ep^0Cl zvRT+ko643``Cv9IWTJ5NJxTs&;tAn|YlWQ=ICcm!dD)*A=v$sX7$0M_f+SuH#q)7m zAW0)Nof<6~MotJ%q*A$*Ff;YubYY?}A`BJtxkx;khVN%M-P5e-ZEBkl#-@gMzMn+K z{5O*V>9*lvXJkSs%U3BV50%iA4+ssrUWtkk&HODF=RTZ$afMXqYCiwYfw{%Wqr%A& zl}*?aKEcn!Y}PEjPnh?YAppEn2y8oVwrdTum_snzQ#T-AtGoBwb$9PVcNzKwIhnyD z7wyn=U_T@XD0u{WYHEawWs=BKOuj&(q`!-YgfG*%$!TF~@@Pe(?EemOi}*X8Z9n|u zZ5p9I_C#D8--j&Bf4T^He}jUvkoB-O-XnN@0Zx6Zltp~|e|^YQIJs+?U=Lp8H~CNj z;}mo}?NUbBZ+5ODjFhqC2EBN{}WnaUT0d?J+AjcD4C#^23; z0jv>1sJ-ONL(nlK1o<$xZbSV5GO+sIwQ*YnM@UHZ$3?~&VKEg9qwM4jNg>JtAKgpy zTSrbrjvsOn!ad?ezc)2qVufIIVc4ci3a|k{pC_z~%cVkyPwskt;m(rKZwNV%RfqnW z9DQaO^1*2lbx;?94YcqRWHOm6`M6M098KllxRMgyF|hX0UPKaoChi*x7KL=!!yy}0>`BOpZiogD9tL?e*^LMOB7xYxgL?$A-;K!wT%9~Tndy-eAo z`wDJEOkSW868KO!nlIDu2az#U9xFs6g2Q?|98ZN4LI_wc(?m*wbOe_BGiURoLOH;) z@kBTv1cF>B;w_`v9*>U+W2NJzPyQ)#uCfiyxQ%J{zNEG(n%$G|-DHn_H zKNlCiyJewQv7=W^BW~4w3NbpP(hDfL|0Ur)$%A^CQ~vbbDuJp^{B|nBgjj*+-4NOy z9~LI~Fx7BjEFvr}mKpKadzz3ImD~bH4McTEg`-cV2w_|FXe##LHy)4`l_q^NxP*uJ8-OJEr7-Mle|)b0k8^yiiPM zljc@yFVds#*TMD(9;Q`b+vN06Q7C2u@tiC^g=D6mUOYU&{vC-D$#B>e#|2k#D6Dlo zDY{=^j~&XG21^2@aSP@Tz25Rq0SNEnCMy~cGEV)?T_UnNuIg3SzEd3+o%*ea{WYMr zw&w3Y0JJUE9hw4MkJo`83`(Lk7RmWK~ zSJnRbMQG>Rqf73(1mjAz@v5J`0)Cf%f62Ag@eIFB^xKtC{*9j^YpUa_MRN_i3CbIP zBpO@_^=JPm>Z!)3{`_Q3(_gCfc8jcIVE2Ssbln=j)>6$Ay@1z0P^*6s{QdT`+8@nB zf3)*gaU$sV#>>bH*Mq+N-Zewj_!Pq$DT+5)&LQM=&{z(WUWseZ8gxWASg z0r_0pk~=)$=Lz+aFRRCuJtO+~9Ow&w5WV$)oQA zzC5vH3;Ct6^vJU{|M)4$wQtlU?gc;mH1f&U0QcNm`{C<=sh`v!Z$tUBHWOZUd zMiBfya;5f@>bP#rFKX6&0{-{kQRA+jcSl}FemDsII2Nj{y$Z@Vf3NlzJ3-&DP}h?J zy=O-B2Qk!dyIA}7_dqZILtXR*u$vjEOSFJ|*SP3UcYxhLuU&#w;{;E>U9*A&J$_@& zYt{2|#a&k&y&Z6pu6eTte&;8DRI~3NP=58^C9fR-{T;Qnzxx^ZyK@G4ekW|?( z_`!c5r#67ynp0Ol_cQP_8>l-X0l&X{v-SiGwwB(oPPFwZuwS#ePG9}qnBLk4?0^m1 zYfpU>%1^Gi`tqkB!}!?tPq2IW@wz9g-`l>&>xf6epK@VI z%mLPkYQB0u9Pjo+b;p$8_czaqh+lxc?}4jcJpsq{;mdWRH=&)tyEU~>fZf*~tKD=3 z#Od>!T#;*YLeAB!pVV}+j;?un`@sv0)9V!wf6LBX#ay- zMW+sd|3Ck|R`edU|E0OEr5aa#`%HR_v%04d~W>nH8o!Ve)L|=>vr(-Zfo5)s^8~dep~bSK4@<(QAfT2{r%1xqQ6zI zNB8pDx2kccvD7s&E%=q)Q|oyS^i$%RFM7Z~nylOWRgf{00 z#cS`V#>>lHb@exZ{gs_H@!x`+91!g&g1r0st1njLL$b!&8`EH~QPnQgL3?wU$h;A7 zL0$7M1O%3Tx=VDU3;KEM-$cXJ-{alI+Sac?`EBtfOKt&wxLUNk8u$G8vzi-wL7(`Q zs9p_d@2dUVVX!~)tmp?}XlEbHb9@f6aQLcMnxUU#t83U+(AVEr_goqL6zc1ml~DeE zPu)9Cz`nnTc2}P-`g5X3wuAo=Bhpmm@++cetNk>7SbO6#kWZ`;EsTLYmls`#fIrKJ zSAX|sAfGbUyd;HsZ*IDZzYKOyuB!doAfWQgn%|rPy=Z;i6DL59yhD>6d&z@apdGFE>eCPsS*m`03Go<|C)d<`dlSgZ zoZ$$h=KiA{EPly@h{}R<6m$u*z&(0+y8I;EA;aJX7WE9|FW3-o6Jm3(>W3hZ_#0! z*sa(A9n<#@5F;K|*=qK*|DmsfcH?_O22{yu#v7u3qMr-9m9hRCd-WEr4Cio?PdX&U z2p-KzvxB|ZHqNH*NjY|ib#_^Y2l41eb%hqa&LLaWN38xZt1<2KV5U~K-vO&G6gpHd z8?|<+TDi`iDBft)r2G|@dJ4aM-jpQWR> zVeH%(wTmUez+NSzx+Blyk-oTA++0N5pWrq}zm=j1Si*mB zz)_!fxA)@tuJ(H`8})Xpp0M{NFqh4}g=;XoNfqXCI7XBwhEX~Y-8I0usiwB9#x5VS ze_EpW*tRli*?fw&HhPJq>3*X_iId<%Ynpeu^~=*oUY%HXzuVIHz@)KzNN1OhnLKif z(atNAMsEOkvV4svh}Ho+A?fTn<8uhq1`*b$COT zo5x*2U8~k%^-JCDXqz=G;>dYuzf#Vja`)9yY+50Q4- zf(sPeVz#+yC6Pw`ZZ%%`IZCM=Osh`i$+j4*I@*Bw&?qEUA!)>9HS45)t(J6>Du=#% z^P=7qw3~o40P|Sw?$~giC4!^}_OGEXO& zh<5S=a$6^s?@M%heOobRS0=bZqGiKgS|NQ+pwJf>6J zrEqwg9eNW9-$FAj-NE%GR-z@Fszch{=vVban6O2vb4U7h0l8MO7uD+sYgCB=2boz# z28&Ju>zi^hEyh8Me_OwD$m=$G(A|v~3yDk+)}~?|77r)aNMS!6)8=lqaV;)Mm%;t0 zA*C|~G%mZ<&{i~|6pp)Xjtk0ms|y<0uJjnc6X;?na@6LMh>LpJ;0S@9UEc86mGGwbEmMcJwy*2R`)zY8_DJ+SbH?tj zFpbM3gfHnoOafJiE$d)bD&1|cT#?@2+F!434=Oj|CZA2=F*paHgP&UDGv-#ofZR;2yN*ys4eZ zdr`?nrL^5_)@p3uwIYOD<_irP6l%9RU!ct<1Fxo0b&GiitJrAJ8%c|c@v*4w5o1w5 zMA~@ZIMGf<9T&8iH(H*7)n*-*bPtAaCkbmukAFs8i^(tMtv(Ow*`5^Z-DW9a%LO?s zNT6O)ozrDfF9#^gXls13)22^S+Y%nPM_Wi=pp1;&7_p7mX9lf19qz$7s(;KrkPf=K zy3?|)PM#mqv>&BYJFJrqW1e#_Pb)6a-2@_bEob~Wc$@F*hQM~ZR*%Bj&(&J z%X(d6Eas`Q?#MgOceay*TipdE#xmY9iPIeK>ISOJJb}3J7Dn!5-BPuy-OhHly9P?b zIeovIa87%}kpLFfb4g3!N;3wu6FB`{u~KQ@pOW!OX-pT=#yqIl?oyeo!zF5nM*<$x z8Kp7Q+N{Cebo8fjo!)7eT6Tms%M$V)gFEPCBSdr`J)($k{^KsYSvQ-XVvYUXTxAtc zb&Gv`D8|uDVS5nw7h{@tyf!(n2+|6&eqCsP#O}9b)SJ9Yi)EgA5;PvCn8t(LNGS z_tGuq#I#G5S1|+Y_iDSMnf^Qc&VyZ@huWmxRj}oZ$&6b3yF3H29!0NrFK2L|{uP#S za^D?a|HMNV= z^!Jp0+_YGJ*ej80qG1=snlTGj-yK(uYVkoM5EwkQgSs~BKorZ`2k7aULyu)!*6O)! zgO=4!)Q&g2VZpfK>P*_bx=Ft?_H-)9_x79ZPv0>@Z#4GKE;J=^Hr%f^ccVa1-F*Lj z!`@AB=B*LyE1ktQS6M$*+@p)zI&G0%^{2C0Drxadrclpj%4AeK?A;!h)8kGs1gEA# zn5msKuI#X*Y+GMHX7g0kkcFI6`7zSpPf)myGI^aA-U;&+Z~+o#l(xF8owz~gCHm=B z)~)pF%R#GA;_Oq9h?k79tlAYfhHVZS)0%MF!Sg)nLJc8Uh71=XLnT9YpgwRIyarP! z8epxC6oujT~^q9}Xsd5{Gh6y<&N%XO}Nk{Z% z9cFYuqm&s*rZibz{oT5!h(wo-0iYurda>9fevQt6}})nvNs$y9dEmlN z9BA52W=v|2m!x`#oeKq?RfKwD^4$unu1{}qrf|D<*o>;k7NWXVmP6F7x+8w&fejAU zn;&;~SYr(#+8J`iQOw}5eAB71Ma=fW0Tig~ZRwnzRa-p07;bIkGQ5wsGG-zw54qC3 zP5MxpH%zvca8&K_x6zhX9icKhqL@8uAC=QOt%K7r-R8KtIYhm94`*g9zV5Wkh-!@{ z7X}RYe3*vtFcvk-9HiCa!=)%@@##4t8fkFgcC)`dVKSk?V}7c~Y!!TNEf!OI0{ZPZ z&D#=T8xsm>9is-w+_};QTmsrin=F(onjmMrKcZ@LKE$XC17m$ul)}P$Z86c86bvCnG^uAVetf0o*_h*y9S%TAmD;6oca7X*n>}NwSzLYIbeC#0Jd;SDJX* z(1&etEcgm0xoOgh$-|ls#_4olXQTExwP9F~>c~iJswi8~>X$ek>-k`{ZL3ONkWpQS zmq{OPKjvdXtLt&Mtj}fN;!dQrN&PlTpLGL2=*E@0<=9S#)WL3>RydudfIHXCn|lLM zOlOOj9&t?-+%5w!5?YIS`JzCH1h=TJmtv^+vhkK#JR8L30&v#f(TBR5JE>{bPhj*eA3uny-YyS$t5waX}UcPbd9`kft?VzFajJppN7&1B!h9+T-I z@2y+>C~IeAJr-Pc;oY9lvcKCvO_od}Zha0l+~ zwa{O&#WaOOJG&l>PY#+GYV}~Bx6f@_d-&N#M>ww;P?*+l90;m4e#xMiY0^fA#o=A` zTMIsZnX?zwTOB705vN1d*0*<TipOtZYLBgndXzG3%LhM5-U zNJ}=>8AHOGXAQA#nV{-$zt-yBeoohk)6%Z3QHS<6Nze!>FtVh|YBA{z0rk+vX0zEo z*CMkFe}Z8Q$)O%>4C`B)befe;&c^IA!2J(MSb}TSYK=jm7@5-n%SoZbsNl*DPm<}v zk~$Zz@K7P|PE*eyqi!(`Q)Sr*)fdZ1^(J4FB4{E9h#?2u4Rmg+(q!f)EZ(-Fs*mM_ zn8B{=#~rR=8}76wD0SGP>EDHQ`hq}WUBTVwjo~O`De6!|pGKcDn|g7a?n6~Ui^JVw zatC)!nYnQkMZ0<9goHKO?7Q)LH{-UZaBYFLE0u~4sg-p1y40!;m$$7=+v(LOa*wKX zMpR2=Lq(CMMQQpz!C!A%1il-8muIcs!DiQ$X+CKn@Vv9V0t zCTlcPc2`PHay&2_sd-7mFmBW8)n>V`OQUEdhE(TlT~2j}+3e89TbQ)PYqTuF(1u9R zRxM`kxS%wk)9of>Ry@$hYV&Q~7I~Zg_NMkQ(8Tb~wnQHna=Xt>8R;(6n`HYviNOB5 z)Y_B*-@0|16?Lj?ajTYV_1au5iI%QHzl&25xOrHjwsCHW@xw=rKFCc6L))GCID>2H zZjFn@86{gGQ;mAw>P?tJ4)K86{z#VHhP(T*&=B8;(wi-_NFT+QEcFNmHXjEJB27QYT^&2sI$TXNz z$^ynvHnl@(H5r@fGQoyOyQR@ZjP*vfRv__FNXfjF*2?bmD>!zU!6~_Aq`Sjjx$+%j ze_vny_$FIsfYHhCx31;Cvh0r~aYHtI`&{Q#+#VKR_AXKj579cMUXI?b?CryB(p(^R zbLh2*275p|Kw8X&oFOrI{TlUH=R?~9iSP7S9LlIMyV3g0WHg|BxERVcH1Kbd?e2KL z=78TMR;GX*M4a=^by<8xeQ>DZM!c~=D}33l%MN;HaVOk2^fMQO(Owu5MHRBb%TX8OGdNAMr(?XkDZ?Q&uzA29wT*clra^LTsDYj)+-Lj!9|O%44F z{VkiPMRhIX&^)OgQxVo11F1goLA?EtAs=pj#JkXGR%=Ju!4PDX8suSXvC!Y=G`+6^ObTa9p1RyTlwoWfBAvFuBH;BwxOQ(v~1i*xzoMtWRnBf z@`_AmDKrdb_1kx`wopc)V zD}9}%kYzL>UJ=|xX%8mEqq74!V;t$-9^2ls*W7O#(Dvm}%$#x4yIt_IyS`Twin3n1 zGegV{xlvD-GiFOsU0y!2KXt%m%Jdo=dwb$Qt~DCcXN}L#$1GZ%yU2Ls0aeWHak*&5 z(oqPv_4ztnE?Hh>zgyyWnOy^tp@+VvKvg|XqK9?>n@4|{VHE1NOKDmA+$Pm-OVcSA z?&+{jGF?%9pS=fluse5zb-UH*jujQ9J|XAf#lV%`uEZn|(2}(+_c422_E@i#HO8Ax z^UNb+9oDneIZDIjtHAR;yp!*v#gQ)aFXOT~&Z+UZJ3ZYcHQKz5vnKhVHuYcwpE5Kt zEYq)4SOTXwNO0c@G-KU*rq^P_T3ce)F#zBU7(TiDl|R( zIfGV_Oy8u;M!Vq7V6n;|B?shYw^RP_PUfsiTR^Tc40MUTZJ5K)YqM&njZwQ!p$@{! za5iV$jOi+tek*M0wKux7&4{6C5Hp%ko7{o*x~1l9(ZR z7Ufv9RZTcgCVF*K&3&iQ?tt6VGsT*Mn0b)wrJtZ6`=*vLtt0xhyR8i_- zAzSL<2yUF3wz$0eHywPz(`)*+$`SQ01FxLdRE~J^D!(@y?ZfiBag%|{0BcxuQQkZ4 zXF3Dzm`B?%r8|9u z!pj+nj3xh6Rpdt}n6!C^#?Gs!3UEs!fj z;j?+@fZOD;s&ygCN*SH>W2mta-KUQwjCj!!mGz>s-fX}$pgTZ&QH_ZUuD5r@Nf^VL z`>|GD;q4-nq(ZOPk+jKXu=dF?=iRA@+;67B=+!MU4TFdK{B9egCozNBiu#PUW)psn z$vH7h?b(gnBUu%80Pk}byf(w+i>Lejo=4s1Y+93_fcG0SGtg~9jZ}L$6<2c>2Io+R z3-zFA>fuzzwJz;o6@8oV4c)KSyoMO1}9#$(@DG7NxF_%9P667!zIWD{dwhaO)uX6;-c26-<#6b3sd@V;kmm@80EY zUe>*bYEOSF*Mu9_u{JMGD!oyiR;uF-c~76UU)dRmr5;Kf#s+LfKlg!;j`@ueG#*i> z?o#LVHkRy`IMW(RLSZVRi3yBF43H()Rq#t}HiZ#=d!yHQLie;Ak?Ux@gYM%j;V!gk zg*^cSmt{yi^xV>HoE@0YTy94oHgr%Pbv~Nua=I>sDWX-q7MLORTe4jZ zhLp`pIj%+~Ru6@AB9(AJD!RH7*-_^6$HEd+J$_%_rtk^X?)$R48Qn6aSWuPEc zu1=Pn*xa`d88#ETTrp8>@B}n8>+_^KB!n%2`>tQvv(vg!(c;ksw{PlSuOz0130M(o z!b)x;nDuqZ>*c((IVp>sCsE_Z;AESG$vCO~+by2r!2u-l#EO6kmYZUJN4tG5x$CwW zlrX7uodcAH-6Y;7Hjn5x>UDOr4cpKaZd0GImBXHTo6TUDv^Pa3gFTz9iX%OZc)s4+ z*LHM1fRBpLS4f*I;cRX+wh&2km!I^sw-`DHho}y*I%Z0o>acCS@mzC#UpvA;17i&bPDMd z((2>iiHV7v%FHj{_p#Iq^u=rw9zGOX`ET8y>Elxwj(n~@?YWCiiB@#{>Cx+P35F5U z(i+GuEbq@YRP>-)f7qE*o{?%IKDU!dpu`G&v##csKgDI-<<9ZaunazTH9^oTH z3ScKx`ti5oke#l8>f}y6@4{}>9Y?zSzA%p!Q-l8ET!+;`br2XCRQ2~yT;(=`zJ|Ow zlWI)v?aR?k_mWv5)cJ?%KtPYE;hz9h)R<;XEFBlRYDbt$rL(W7a%l_7fq+BlnlE(7 zP$k_;l*nx~P%KeQ+GLGf^)1=SK>o%PvySYafvxHohy`6$gv3lYFKSut6rQzNWuqS< zKW?mNNs!>PZkDPjgs-KOoGr3`SdXQ6rogXe)FD{OC-&7eUkU}yw2|Gn?_`YHidH}3 z%mi+O6b@|^bC{U839c6_n;yTR2@n?*`HGZt2h=v)42Yb~8a%lgEQ3>|E-Y0%-e#vz zu=~K7LY~(v$|BdYJNAjjYTR_WN|7n(ZQS5weHLOdtudE~I$DBv@Q_D#bP{6ktl7TA zi3MJ+lnQzg)Nj+WriJ|#4kv59c1qG$B`J!O7B;ny32zC>HKAIK!Vt&b%SeWG@FyH0 z>G4(?QU&m6b!9rP`?b+3KbZH7rbuTN7D*5v>uSF9+Jpuh5D97>@)AsuRjCP)D@jkw zADlNN5GHYhpTNeLqYb&40VEbU4=&?O0Sw96TvkaN9PN6AEQDz=nz<24f65_|d@}PG zASx@(($kbJ8|ea3%AD}B%ywgqrhZzQ@6Z(6%Z!tB+^(52j#(Hhe!h<=#Y#;CQ6+36 z7wnw-a*5x<)K)IheOI8uuJe33eYS;pIHiI3!A#B^@f63@7eiL2wO>kNjUi0KlEOKE zEZ5iaP~eCCPVd#RS;NK_^aZs_t zh!Z_Z;Juq~Fo8J|Y19xQaLa%nft3O|wP5NTQWo-syUUxl18+ck=2Wj&>lK5Uj}lS3 z%O>$KWzD0p{6b!O=tI%1d}2Z&k;xNjo9F!U9WIx3GOIaN6?~hx zxUAw5#Dr_=2;!!(T`^Uybo;YcoMckrNWteKrVe3(oC(TqS<+uZbPt;DE^R%E^4`W= zM$gsB6)BE{d?C>3%vf#|U^(R(!m-C!cXkjFC(>*AcA;6Lu~_S*6C3 zU$N^ES_Zds-l}jFzTdhiMwV$^j!7Ok^uKR3>goz9IIETfpd(S8Fz8;IMe<8KlzfRN z(OQrBh4BmkrAPF9T>yo9|-dqK#KUPYOCkqfdaz0JR z?xnIidY;PfyhT4Z%i+;lIFwHcIO)_<@HlhTRD7?ks)=a2TDW-SQty0jT*XZoXVde)WI+=9yfmC)p@Q3`IBcM$cOf&c2FK-j&2? zb+=a|f(V^e1#+dE?u6jA>=dI`Ly+?ujPP7hO~huG6vRmqUgE%E<&%w= z2Lj1RydG4JR+Y%YVq&zo3(M;2Y17`*a=%hgxHn6EPzJfzyHMIR$_)syNNNbmxEje{ z$rmNCumxpsaE0kKL*m0ScU8$=&w?;5#dAZtlcY*eN&t+PG%Hhan4#!`iM*7f-v@bX ztE#XADE&iGX|R?RvIH}AcsW&<&4S+-ZUt$O;6sF-m`qmbuy{_>&&YCju$69?Nwg}b zI&O`JOGZa^d()$~R^m(QP^2>6kuM39#bktvTHk+2_tPomw}Taq*+jp86Q}&26sjgj zB3+kKZq{1jSknVHo4t58=R!vWE$@&u5E>?|ZWofe;rz2EEm}Qa+sE<51o&Pd)l{Th z*3w$BV0}|2vny-H1w}?uz_yv!eak7jn)2O5qwIc2L02xf=8fGUQ zD!_A!pAY$Vx13RkmDNJQ#swKp&vhww)A(%7&Er-E)UX(!9yhuibGSteULkXy(lDWX zNhJ|fj;x<8Ge0^4*xPDMAcdL0KktRhj8^KEe#uqGE{PAL6O);K@V0YlN||{0^-8{@ zxk9m5zXtUgCp6 zK9^y!o6(c`*0kLWVVm<4sbTnDY9hT2UrRJcZuHS0#|_rx>&fN+uvnV_or7yeBl+c* ze+E53EpMzBh_mqAj@nt|j(@8@Gc&bxtE4@dD3sbC3@?Tjx(WG>HxW;Hspbdn{4vjv zNO|u3>C+X<^fE&5TI&8c$2u7fmdkD`KJL!*&)hzy$dZZLkA_6PxV%q`g2Y))l};AK z4#()4EtsOrNOeYVQHBxwdIX%7tO+}=A}E?-@ica%d6H=Gswfkx%*vRE&0!L!3M}Um zph$+*>7*xH4y0O*qT-R2Iw{q7UJ8M4B;yeXt}wI&8KNzb5)D)lJf(m#3)XTZiq)73 z=8%N&DT7paUrg&|niMHO3UNFy!<+&LQ;#+Ag2;Geoo56NAZ;RP(gZ6zG6d1fmZM5I zE!l|ddl^&L%7W-nG!JkPN#zh!l=7Mh9AJvBuxV3Qy_S~|T`;=crhb58{IVI|cV;g{ z=C_Q~CzbX21I!gje<^1Eq8_~D%-$B(HL5%mhH+LK&D>l%FOl^fX zC(@-~3ZN78P`Et%0JL)qxsYwNF0iBui>rM*~)t2vmbUg z?_YmX&HwVXHIyqST^6m_!E6XN1pYNZ>27ps_20D7t8 zkr;a8=^F~+sLu+a>#Y}T=U*pR1pcEEht=vrZq4ai*4r)ApbYl|(;nitu zhx&i8m_CPBYeoA|HViu5MKxEmGF>iTVd{u*qKGPfZ!KO|MQEK!=3n-3dV!4VpULq~ z$!OR`()^y7*{h^=*x7HCo4njTvx!yto?V=vlbQ5@CoF_#AW)RsHNy!R^F+Qi5?-xh zg;h9`tbQuT(~ZtP`8#(oh4N^tjaJxvGNH`9*GYa;XxnD(g-4u9ra?vI^ZC-6&qXV* zZ@i4{qGCdi3nUpVR)v(jy$TgL$(`0a>az%wrP4W^%8Bd@2Y8&z_-f*xq|!_^DoL#` zN*Dmq^=m{thAGgt>s=eVb-r)k)bgABWKWR%6AN;^V+OmyU54Aen_Ark%Z}c}BMdyZ zoD7FIADSJ}#0w?#(xzrWA4a2)2z^~?jb@nor4=)cit(+&YBlXtO{2tvCsoH!Em769 zSB^_J_P(fF0b{YiBIVFgIuQbZL%Vy5YWDQGwHM>KwDfrJgU)scLysFm?Kli513eY6dg8EHiA$al>RvduH7IVUSaCq zvXzR(U|u8XLfR=HcqLp|1W2V~0$j}Fi|#(oMYSXV%{YW*ECmQ#mopHTc1v2)1~?(> z>Zx4RYuGc=LN4XXDr9Fw0VgCSY8pzhn3}HolE6>v&;kTHYID>LEADG+p`Pa{8dgvd zUA$m0d9EUhPo$~;r)`_L#PpL=TnR%z&5GNuOtfBWdrU2GGG5Gz!2Z4moc;> z+3DvlOa2!MJP85%eZN)&OJ;$t>MXLwg%Y<}eO%gX#mfYrf%H9#t6VgBxiwkni zee6u-Je@_Au5K+YX{|LGX(v>D&^R(pD7LTyvdubt_M|VEQpHWoJ#XAcO3T*BW00|smKEP ztPo1!Qmd&}N*(L=wn2^jns* zGCn8N-SGuG-?9a0oL+0AK;otF@EKzXja#)B1L&e6IJJR2bZYj>9|57@ae>YeVi@JP%g3m1H|MpC zzzsyIpI@I6y>}N7H5y!u>V22l1kr(LA|4f>Z`vwQq>*^0geh5RCC^y-Wtkx(V5|zs zw9~+55tDhQF`ghpWYJ!Qv}I0y1~m=LhNKSrWw3xs=Y%!BX79i+paA#%R~PSe(e%8s z!Rrg40z=GZY?sJZsfu@1lP@+6_MtL2`B82oe2rW%Q7fef1RL9{nQayGNhJ!FW*K}0 ze}!1Kx6l)3iRFCRd*mkt3+-Rp4Az#(6_3^pjT%B^&&e0Gl2rDN!>^_&dJl_k~w zwTBih@c7pjkmmZ9CJ`*{$V#g0w$uXHCX`l@S5o!073uwo!7ti*%Y-#oeSS<&l=B!b zu%7i=BZpu#dY$e`>4x1x!$<4Dp^sZ zJP?#P1By!4sK}k@X-Y7^sv&j*Hb<#vW~wAAa8FH8WQq8#g)E$vuj`&6k+%)$8#Hrz z-AFE7llixincud@!}=v&6OIEZl30;0uC$t6yV|@>#DF#6nv_d48nB*ZAa*Njb0UL= zX#5i2u3NLG8~B2KBci@exeG$hYA&VfV%m1z*t)8lR0*lr%iO0se1qH=pR9IUR23xG zDl0~{q<~-P(XGwfsi!KeUWIWeCsbZ!Lq6S^sW6X>*44vjm)FvHYF%A99JdMI2rgV% z$vs6w`^0oLn3b76W-mYjVY~g+L8;C*0(tr2s2pIx)bB>(?t7uJ4Ls9ui2I48CwVZN z$yPrWv&VnWTPa;Arc3m7ASDZ>ifGq{frx0~b2v6FSa>jGzZ+mc$e@|7flo%~RkTI4 zLpe^uCnjLAnLK3_-+BvUYKBPJnkmDRbA%y?uFY_=^+R*X@D$lpL4LaJ_X_`uK;!No z0S*Ay#DcT3tpdF`1b_qiTGB+cTj>oPsQYq^#SXCNjB2DLxN`M3DEf4*s9*!d*n?Nf zMb(F;0-G5$?-To1v`{R@PZAmX zuJ*hbI~6!q?XGFZFJL0azoRFl=_2%?DbJO1Aqu`@e1U7B3;6#KYMTtJurReYq+^2Z$t5#8 zp}@DDSOpW*A4ad3|8$w*4L>6zh9@+}?06N9Pe_5}1h${4^$6=pT^S^wj_VeaG|clf zSR%wkSbv@>uAZRABK{A17e2S={`~<{NWzV?y+&Ffw;}3>M&op{wNrozyft^oZKGd@ za~n}heESeiX2}nFD2AK zflp0)u>rsl9eX1XoP%o$gyz+RQZ0!&q$3*j2U(?3T|6uvc3@(}b#Cn?gpD=HZ1=+y z)<;Q;x`Pd+e2&Gi`eg@l1(V?TSYvap9jPi;NJ%TAjKtzxhfi%Dlf<^;&!!Wtc+F8l z(*!U#;0GB&4V%rQguAJRjr=+71>MNC2jU`x8#x|YDs5dC(p9C+$m_)&Alx8G@ped< zJ@MV-L6lC*PNjIz5$(Br0D7ByAgvS?&j5A~@CeiJi5=cE)Ihwy`u!5|LO(!IT01iy!$?G0Td#F=N zw-_x$gB~g(%R|3QrR!=$c%W9WZ)to_h1da^QE)q+38zR_ByQw2d6*J$nq<;t5N6fp zE_eTd0iH#drdbk>g1rHN0a0A10+8PkRF5ub)lL)iu-i$$dN!L=nbC6cN4-$$9isAb zV+0OCF_KmxGg1?4ygGJN6#aYZ_nuf^YJDtla{~8%(Moj8X73~0n&QDchLKx zHl9BPzj|dn^%i&{V$weqNtYpR4n3R#>f9aXl^^4KFI)*Y z?L0d!)~~MIs@7Lyn;q@N@=uZ&{~-vfxpbY-bx;2M1X%owBqrfEw+2pOkq{y;Z`bh- zRlM@FEs3Y(m-+?1t9%VDq?fBW%|la>VjC`mrKUe^{C<2USifF{&h_~lgx%oNjhWRo z1z1s`99Z)MuKr4KluUgTYCz1<0)OeTY_WZQqQ*F(rCaro8e2)6?wL0(Z|-DkiX&`~ zEMwUG1h={+)WV(mdyxXOKb)k1d8EMwmyN^A^T|u^2)uIQ00$cen|Y4hi+$DjG+E& zaL$r2O#k#+rf)Va$d9efwvSlnAjQ9*BfP9I*i^P zm-0xYA-&CiD?n)KcCuBV%9S4`jhZ!sL$CsZZV#vgNDH#M74?T2^ zHD}^^x4Bd-GsQ+xq@)*F!*h;F%X*8EL3Xw3dypqaI-W$Kwipu*2)(f2C00Ec6Mygc9qxt?DZfDmz;oq0`V-CqGgLR3^P zCDLZKeIU45teMq((OcInr;I8&#mm+3OnM@wb?}ucQBvELYAOS~e-d#`U(Ya2rgpMM z&I{Zu;_&v@QRl)28tJro{N;X29Irpt<}KEmDvOS*x)#uM8W0z>M>*lz%lH_9mI(q< zl2!ocBSsbohq)karvt3M884tSR3ing`wcQ_6ii`aaV!0*TqMe`HU@#`QKW7e^RvzD zj|ea6#3hk&taPiAcz&>WHzIF_8_;(j1e*^SOgH}`hG(?}0oA<_=UB8}RaYxu7eKlV z>eKagJ0Y!yzBt!TS4m0H=!{53m9r@z6Ia}dT{aC8v@=VMlhEMg2FCUwZ;Js6qe|~E z3bk}u;fiu+k5vonILv%G+w-b#5|uRF_U)wG@>GpKU(U?SP4tAd#)XZQxmXVKlX%EG2?KVKAX+TZZ1_BN2#$n$#)Bt1kG-yC)3Id zOXptB-yV7sK$_j)A2{(Zt)EUq^x>hipAg)V-uGsw7>`DxhtBMkD5xu>-&%QkD_?hR z&J3@=&A(2ZExt~-StI-7Lg(3{@IjTYCQF>)YWan%EU|jh zfz!aC$1T8htq#SqBSF{gG381TDsD?9H8CsrJ)eqa8fi?PuM`y1f|zquy-XYL+HN;) z-79!(29etHDQM{u;MwdtDPmae8cVONd5!WCHh-|`7n9kFEn-fs-Y3CGJJE$*OUAc* zfM)k+k)Np70%o0T@L@Y(j~F$b^_0MZ(N1e0%gcF5tB;$CP6ROm-gO2fVNJ(~!hn`U zq`4N#(XAF`nf#1mbehr_74WKdosOY1bS0|=`R}GL)P@?OQ6L6vJJPmi<}E@mpGMj3 zZtjAA97hKBYV1t)2P{|M-wE}wo8pP-C@VzzJIm3HbgZtG&N_|qhf|Tuk@upwkX%Wx zR>yC@F%rLID$XuC(7vF?q-#X&X2e9YWAK5><|zx8@z>aTwD z$}JC6LSvo3{#F~b`)S|1pV0ZX`|!pRRlG*mbL{JHXR@GABW~zojJlPYNycie2gxmG zeI)<)rRMok@%hs-+vRY+2JNG0!R(GP}0pUB_=PIMfpZtReixAr&2tJ)-JA9s(Jz8W<3C8hiMFLKB zD}$2^CmIpjVPrpPwUbQe0nNxtWlL!2k}M*o3ko3}o5C=h)EFdh^=PN=OQ069g4SH= z`;dl+`C`FA2p<$a8XN@XYFP)KorX-&tXd(xDk0T84ZNCJ5VKI6Wf@L;i3x#Ls**rD zf=ZLN#*!6~B?t@xE(YgiloB!E?A5pqLuToL$g^~lk&?K?Co2NW16Ec9R87YOi#&%8 zu>{a50#Bx0tgy{eimjJIM&yBR@|eQ4a^jJx>4E&qB*q~=hlkgrtl1nN-<_IW!SNws z<*tJ|jo>zvdns0RGth;EKdDU*@~NO=#VU+B65nMFaE%SIxn8}8-wGCh;CWAln(dxo z&}Zzdm@Wmdv}Weg=Vfk9r}hu?Qr{Ia3{jR+em=S(KiOCP(0HNXOoKmJInQK^*lAca z_G@QSZFoV6bK#$f%`8O6#^saDl>@y=4RX0q{HsFV^BjPGMd=bWqrgJ!@^|}lDvR<1 z8JEM@&QUH{)Gy0xTZ8%?*?YlBvFW8k{kc%KIR!U~Va2J1B|e)g0~4#R&)aGXcOx`E zY%lr1*5OYo2*KAaG>OvXhS;Jr9a>Nt)iUfcx~$hYb_K}Jn_V2{gsMpKXq~B*iYg@A z2+zAxI%A|^n4)acUc`Vj1O^ZbDY>-_>wU~s4S1Y~W&4Wed#bUeFr1a;({MQ*&Zsoc zf*xuBkx0RuNMl7H+7JY(PUnhto)+~UH)47kl>m|gOERdTyh~zLBr8-i8ds4p1q9{83+`+jUKmsu)l%v$C64akIV^hGR)f%t;y{H-JWU zvVv|C*_3OaX7Y-$K|WhdGLw+Vb~+1IdbJMmsDPJTk#P9>4!19-?fI(T%>l_}{ss(K zx*EA@$QKl`T)dBR+119JWj2W=Q;pI$P9|~1Vtw%{gQyOe^}M13qbg9J^8&Hpna;ik zjaIHURaRx)X|3c5O4jEo3zn+c9rOpWS*m1+oPQh$|D;m2y(bV0)*^mmS@#9qJo*IM2?)W0#OYd!_Dw)*^d0Alg$pt<% zkt%#ISY2{`xKwfXtl4sa^1J$tt7Lk-pK(VRy@Pz`sQAQud?lX~^k7kXUMepKq~hjA z7n_KF_yYQxk&SUz)SGN3-)qhU34f&7D9Wui@{2xRzF2m@f;n@o8yziUZM<7u&7Q{t z#+#jGGB;>OX9KGe55b#4pAAptmSo|^2Mq|j)cQ2&YPseZ+q))b_S5O_m^#I1kz*cZ-`+-TBMyG1ZS@N(S{$rT7JGz+*+I`eiNkUfHVo;JS>0P&73i(?iSuRKQ~oO?@-znaQRa~ zv4@)77P$~1)2r=KW|`vbX1lh~>QhY$Wc%`%Jte7`L6UqWICQ7tztO3(*)cU0PE)N# z{iu0Wg6s<1R~Ir@a^9q|csU(BD(WE-T8z%rCWAs>GV__k>UYzDlc*}rFV>POi5t;wBe@n1(}=+>sBVI=^@Gr*WYM9z>eDw-CGpA& zbS0647d{*&JDNZUIrnS3+QaT zG$WF~-L8+ESw8LG{Hon}b)YDl{Rbc^AgYYl4=45N3#CErIy$~5ZO(8NZtC(1ww0ud zYPf-3F!uN%c=eTh{~wBG3fUVxS|o+qRJx=G5)5=kL)_?fQp&O1{%SdPd22S|n4nEg z6wQx~z|?f14g*ALNKtBz|2VN$xP1<*_vm2jfFJJ{HmY2Xc7dNNfeLjo?0N}k6=*c2 zI4<`3KhA6-{^LIGQs9YC(~Y{q}v>00ny{WL|$Ifvw~3CTI*%R=_oh^+RhDp`AvMZ zRwrq(WaOBQs#NL2B!# z?lfD`K}3WY-=vjdq>H>2@%BYk6cWH=p6b-+jnO4KuaV3cn%fu|yJ|J_dr|z4Ecc8f+YC_L(hg zdE9kLX)cdPn}S|m6jR#4Afb^Pbr^tG^OsxEI^Pq7baG0B4RE4Cn1r|vsAoNTw*Q}l>rXw>Qd_99AJ9fbfA@K z-OGADT>ZCzVctl{@l5sxgV5G^KLme}&_lMasN)1aj7GE_d$79R>&nbXuckEK7&lU} zsuf;jN*|Qb9GVMrE~^hE5Lol9x8^01Rch&mXzS~!_1Lh^bmT~3rCb}6=g`pFBKpQA zD}MNVt`ojfcJhbvQLA7(MQrBlZ8%@BnGzype2}|DHCLc)ap}m20+qjSB)-CLcg_kl z#StiKNW}!2tfU_$%pyhP<0f6tLV)l9Quc9W%gi)SLpv;s-pey;Mq6jpiYll<{KNIx zXge54Hh|7xWb8s=iCz%ax5U;pGIojYV;j5I%cI=5cL224h+`esy(p$pK+rV5B)19mb2_!mAIN3F4J}_Jbw3hswbC-YcxFGnxH92 zTNsN%=G^oW*`43^bd2FsZ(hyZw%EI9Uq3dI8F(Prg=MQ$htZfm&NVH6N@tQ$^EkWHcn9DUACLsQN1;6vwq3aZX1#)dol(Ynt79 zYbOI1G1h4*Ijm{a6<{{YIx3Vf=upfq`j81qaW~YSsn($Expalur0#Lu<=9?b#?Z5Q zfBLM!v_f%XN4;J`aV+(D$3#ETk22MKDgQarwW{OD#SCN1mhbLrv!x;P+nHc#GH-I)r0YF} zByU~pt`62V4lR*OOpB#E1am|rv#agDZnDQ`%5j=4v^N!adQ@LR^8NSS$^~kn*7^0p zh_qD5tz_gLBwPs+)<_!bB}(7Fld==lt4}!E$3YELY|FjF-jvOtwW(6xS5}DXDDRB3 z_1cu%V!LX4S4&OG{GhE;rBL|-jAp}yt6uk|$=m*aEmS4KP2lBryM0SrNxD3}k0AVw zW}VGkOVP#;T<5-5+O~ERU6l;5Okro`ye3w*)=;ysbSN=-9pCTFrrJa272dX1;_<}EMB2ZHleqj`Wb$6%r8^*=bg+VcM8`T5w)F79nr4^$LmVjh6#TJ3#BdB25 zS2+g;RlDoexvhI(6>IwwBKh3g@p*_{WodmpF#%-`ZQ3r7Dpy*H`c~B4u{^efOA-6R zbZ|<_0I{I`phH{cL+@BAh<$@Ur`xvJws;XNaFxDiEs9%jy+l8b0~us^*pCgl`0*@3pis(aEsNO=Xl^~0c8+g zt*jK~p7}U%A(#uMP}A0Zd#zHD1dN7_Vy?@zC6LHx<3V6F;rMO0No$o#V!a~Piv%gO z3)NmVq7<7ph&m!<`N?U@0UK!DE?a`F(37ZAeU8;uF)yMd%FTkWm$Zi5Y+SgvQ+JfS zZVt?bjMAiIlnZof*Wl@#{Oi#n6?97iORLSzYbj0Un5o_#&_1U%AyE4-RTw+ZFnZqi z(5y)$_HRuKa#q2|w=NoHM9UBsG{x!Ikc{CR({$*uR)HQcf1U#u@K>5Og55w8LiB^1!rb9$wr8qamjoOC8JYO~uzFl4*aw|H$gpESJdi-mzXBRd8%*^Mt(1S`(dbPtS(BPu+Gz4T^q35NdCVh9P9(^cr8a~z8aW-Y?W_B-lrvMzEuZ?TTRS)Mq#&f1{v7T;`E&Ny zd~zyW${c^BN9|+S_7=g81#9r*N%qZ$xNc0MzILh|y0kGZah-&_xH^d)~N^ z(0apSB2$zqZ@!p|KN3!%_LE!kz(mPv4S%s@758_{)5{yclc@|78*fDlv{QNcI}UZ~ zoc-qg{`qG=I*5$~7H>Se5GhLZhe-C3oz|U5j#M4p{@0`3k@d%LYj1br4@gakoW0q= zH+PyBtADip$=^_4yCx?88C~$vQIew5XLrB*wEX6!#9tWt$;#@fC*N9myU_#zD!JFk zZTE1C+22$b(3RLst^dk$vbi!Iy>@bNe6mDn|LfjH&9BfX0L(Vl{2;48V!XChS#npS zj~E*-2Ltcrf;ay0gZqClwAI^5u7s^52){85*1znAqSTr(JD(FCf}uqNUS9mB_w(7_ zd$Z++^djDf{YNw!zX5ox#}iQiO_j3mjcSYv#wyK6<$;$ak4pcdgvsurEFmOuCyV}< z@-Pme%k?U>Qll$Z=WW8ck=DbVcf}G?kS(h5if$+2O0MKG=WgLXJKCB43s&TGI zW1?cax}Q+XQ+1}Im|)e(>ROI#>4=OV2*pbZ0df*`nKDpW1ZH^|hz}e_Ymj8!AQe`_ zaE)<910-`<9Kbw%h$?zwftH0OsmrBHJVsL+GGfX=_RqDFz;gg6EuS|jxzWud%o7Wm zx`EP~a0j`b=%7q7V+)g1Y-LM zyhC!*B=7T?g>!EX3aPf}rSQ=i(1-nun%tUD$x z3u}o1vPPzsYpU&&mC(#3W;2Cg%B_8oGj^8NE{ajuy6k*^{2ar1(;h!Lvey1-c>Q(( zp5Ht#z1VFPkCyFOuFANXhB``~iVCY8ucQdx`l zqmVu{)BHyUOxq7SK4IQl-wY7Q=?h+=bcfqd1 z$FF5$Zc=Q9t%$yCOp#|PRo0gxOI&aGVD=2LHR$N`&XL!hEN+=;5)s*Xg3G_#<+t@h zAfBwj0~A4LGXHJ1h{NAbFU!5|GT%Kj0Eq_|mIYF~G!l(PBf%Ptw|S0LN*P1-t43C& zhS--{?NVA6nQE|5QtJk@rU0#~W$_w#Hd}}fvXX^H5bH6vkpKdwFtU>aU>eJ%43WXO zLdm`bSF$3)bMZzMMVL077eSd1&;O1o;#%3Dp;{fWQH?I{W0D=WI87{(af~u3-Cr`O zIt$CbCG(OsERHQ^ArbU=QW?vpCRWXg(- zI)!9TwD=;(p`@#vu#l+NT>E-=HLo#7J*zcQb|M8DfD%A<1Drnl9R|@P(UAeifEQ*9 zn#q;Jgaq_w=edFd_yiDdQPWkYN->^E7t__oMa-gnWERiHbj{5*i&=d&Um{AAAP2&( zwPL92d9#!v5*ag@|8c<%IEw{Y@2m{92`U+*K#cco8TSJh;DQ^KWrQ zqNb(Nkb^){Vk*u^*ff@i)Sl}|6&d0sqEn_N1tv{p10XqV38c#TEZ%;JrTlY5gNZ7v zVGy$Wv?o*~TAIFG(-Ay_R;6_9=|whW5+qMCEj#LNwnS=NvA?mB;9!aT=yVhpT4>v z|9AL$&L=P9Sz=~b`)@`P8}ysYyJfPxDiqjvx}s5niND6E%|r8P_VV0*`GxKbiN-!s ziC+BCS!i`q8G9TI!m&j?Y{tA>cN$}EhD@#+uPjtZc<3*P$edzUN+%-i6}fXENCw=N zg(MzcoTxB*F>scc55H>1h=g_S8L^U2XPMi;UOLqUbi62Gl=;g&v^|UXmr9ZBW8%dM)x9iOF3wHr6RJ{INpr)w0H_{vd%>2O=1@i91egHgpnQ&-@W$d|AO(O&vY^bqCNF2i20pXLL>DT-A?PmR+qNb(|PKV zpJ#+S|M8(rFBq8p<&~y-@yty(cltx{b{4<=H2s9_$Irfe1#Vq9BIVpm=)~^xlV)g< z_=Wa&s56K9d}wrk}@{nJ3&=hh1nVgnZOLJ-8VQwAl8+8YFa_?Dc#vB47M4 zN{(X_kRjlo_}5=t3s>4N7=To}TC->B>xo*>{J+-PW$WUGa&f0vsqzrvfo_UOUM6w zhuYe?ZSFXK))CU(>kFOx#s8n8_lmOXJkK<%y&T4t99mW+l}L#ZBodKPh05vVocB3r z=bZD|C+ARgPUQp?a%KQX5Try&lqg%0EytGaaocXYlkGLrGi&BzrdRh`bHVv_g9}_> zEns8s`v32H-{)b6qv=F%`g$ic1VwcTJAQGdxKNCpdp_$bolLxQGJmu3tt zw)o$aLSehO62Xzf+iBIJ-TuvV<2q4UkuRGY1i>hQYJ4wdOB#1_qne5j5XbK?-r{|Q z`Hgnw{6aPUnI_m96r#Sy^SmO~%3A^`eUSOA9_418LyCAfOq z-giH1!AITZ>NvM?X`Nr56?3C!NeeiR1!@bq zQa=PXi4u{o=Z^f6wEzx~C@lW(ae&e*GLU?Ms&M^ozAH-?^as2!;F^C!od=-+nr|2g zC`d~w3lb|J9hmdwWw6cr&^cc?uIP@HKD3;l335p_T7`)>!bQn(=ND@YO(8GVRu)-g z$(vj;dd72#S8M4C$HRY?`opJKcD@Yg00R?CT0G zOblMi&V2r5E1pei7bZ8R*|LAL@fqv;2Z1&<&Jk7J*uv&IF(>pHg%uO2{PeX0VpIdT zS7h<%TGQ>%B_s(YKHF&y=;p$UzvnK8=1PkY_QBR~XA~*(Y#iYI%QGQDIzeSmULNN{ zMIr1<nUM=9_T9{GFe z!=TOqJTQA2e94=ccgle6!W4?o17f53-S~=>ZLpW7p-Nf4P=HZ_2wjmayd~>A6+Ajl zPS(rR`g-$|35g~rwX>$7M)fkII=Z4)82e0xSOGmK3+j+>W3aM<%BV`F!PQ}OO}SI7 zXiZ-vrQtAYpv6c`Q-5Y>qAWdu90Uo^WQbEuMC^+cl+a4 z2FcJKU(aT0f^esiZ-&%i&t;GdgROH*LUG@zTlYJXsDm_xrdo|N`RA6>7C5o zdTX&Tby=Nahiij=7`bD)uKGH;$YL(V?ga0}W>@Zi4(*R+7v@U0)NZipo*s&#{hBtj z760tj!F-AGZdvswhyLNey#M+xQM>o^oga9Rcp}W(vGVc2nDO3(S;Z%y{jFu)aHY(P)&ODLke(Ebods{k7T=Cb8S%mxh4+*za+T zZ#u2}i4k|1+-dwk9$g)=*Qr>GxP5Sbx|QsCYCH5E^P>6@*{&`G!@ofG|AV}8R{(e} zX~^9BJG1noD{YYKehx~Gl_5*Lzw*!CDub00l>oby)Nj3%0qFDGqvwC;Jzn0j(d7EE z_0?PZp|)bSAFy9&NqOkvh^oxzw6B!cF8`8lz$<@%ST=#`qb^v$ns9!>hc z>YhSQzf=e>ArAu1^N&@;rtIzGdMz_mVHMxHM z=~-EQ@}rb}9|Toj6_&zwbutYhvCZ&v%Jf?|d7rY&2>$ikqYf9-v?FyjSU6!ml3e zpL(f{U(^?Ot@n3+_|wF-jkHJZrMJpI&O~G5bgH(>brx#zRndL*-KBl5ngaZJ_zwZr z3g`%!?aCY}dK65iO4(_?t&?;cgZYIywyJgyKGT(bZ%{HqIkJ(sUw4sj9zk?YO?L-N zZNzd!r-v0(LQIjfrl!+4o>YmlyV$O0-{+OAhnlAWs!wR>vJQ9}lxDJ`?z(U4XjxY{ zOZI}3XJOSYI%^hQ+7YN20CvMpPH$Dl5L>|CpaP=yOM;)50tm5G3KT=Bbx15mXv$xz zn5C{x!MSP{R^xhWlhA6#;H)ZBs!cIY!Oj;nQ^VvMVFXfIK<9@PxW$TqqQK@sJAXz4 zCYK~A)JL&dziL)HcV?7>7CaF1tqY?wvK#dD6PEB^4AqJK)8mI_iEp-a!klUwspUC9 zEf>WRkftcUY|ST*w)2}vT(zniSOZ5xedJP6P7clS*KgcuhwcpW4r#2|13a!Ke0sE9 zn#Wg?X^R95nH|96BJtw7Q~_vN{l&F)?2r3o;@0$~O8vxS3>d9iKuIjQM)VC1S*jQG{#*5(M!y?d*k^x0e4FQyAJB|jJPhAW&0CIk zr~PFJHw`BeI6&=Eh7i_Dw|k6{aZ-DNnMwrUvO>|H zx19&v@$OwGN-H*twdiz~lDhuC^>Pu~=xxT*k&>Az@@=upw-9s$l z=OE!X{s|>c$W;0x5|qag_dr_<6|xOJz~-UQX=w~?yyQR$C%`5_+%6d_ig?N8s1htU zd8U@fY>5H7n*v|xjg?mjGhdP^;Cf)$e3CU@*GY=%2~HkN&16xo0=O)0WBH(o`0;4b3j*HCzVMbHMt|+N?^hWfYszXn?i!N3z*Epy_fgTSrVrt`#Oy z1>UYM%g;AOg2^&+Udib^kre?AwaCZ<&%{8Py&~r=1mVeo2mrWxv|)lUQa&XK1-bw^ zohp%I^}4*^@ESl&JS~={6W~e+R7WMQNQ2`r-a|@>l){#(xg2%o@@dxnc0~-_xHAgO zL)OcioWGbmE$8f7wg)U(+vr1efvijCv|8kUiLZYB+fOmMzmIz1_j8lDX3M!MY+uC& zGt=JH=KmUaIa)G%iz~9B*F;~@9e(Q8u#eQ(Y)J7oxax_i{cfTEv){Jl2LS1uUc%cI zu5oFDhi+l^{MpT&$1nLu7rPfEBq>!2i`F7eyta0@;j8?E7IH~S@|xw2M~1fPdYcJ* z;jsSNiZ*x`Q_qJ;>OljmYmy)>$@85^Y+$IWI z4yVKoaV{J$N7X`wAF?d`0zn7@8`&oVNRidy-w5~fCA5g6i-Kj~JlRGjDlH*Ko6NVB z^ETQa42rH2oVl`=PB~tzaSmKA4w#ZvR^Klc=zLrN|HV-Hm9+Df*(sqXE7c((za4*u zP1~1Q4$Wl)%jH}iLF=)wDY1|{Yk0xCBH`9lF#2!8vHSzLXot}9BH~lycE@L>PEiep z9s`5{%gnKy3qoH9WLzk!eAn=0qLpq(D_ITumn1^RYIP_wf&;BkqNO9%O0uN;GaY!< zDr=H~;_IZ`sbZf|hWA0>h^4~*S|$?dp(H9+lK?7N37DC0`b<$NuI+yZ-LL3(e{)l8 zqWt5(B2JbGHrFrQltY8_P`opObAj{0Pvlu1S(W2$yj+d*+a)nCDbGC|NDw>NK=0PQ zhdXNiohwk~!`@6u*~PbVZ=BHn?sae9lVBH%&pRWdISphmi{;lo_YNpyZcUoJPhF`1 z{f|_9DLu-AbB*R4ygcTa7R+avyNI?^oG*R*^4WCzNuzUyMPK%>Fig2wNJVZW4GJ{7 zI67V8g8M3a`QnXt;KPW8*S5Djfl!{@Ft5o0c<)%D)5x`r{SALQ%)0bw z?m9FEOgqH6%$-&1dUtjD^9)colNV>=^uVYsaHKBZ+H2bY7|_Nhb@Xh zP;bHb-(1@sIe*xiHv3a963z*QRBt8$pu74y{B3-etQBvLzZH<<~|#RNuc{2)66p0CD=1qRFo`-aqi8xqiN{viNw zWa5-lh=VRDX}b^wot*>7&&pioQPES-P$%|`rU#a(LXX?S6Zt`^t2k0H;)=fRW@)ed z%4u1kilq^8Hu|Bf&&8_xTIQ(S%Pnx8&jK<4B@0`#xhv-T_P7!(f$`ITpL$D_m~o2cH10)Zo+n@ZR;^(UyU7uDs>4`(Q1 zXqsu9i@_Zo2r9K&zA|r+$?EF*M&aX~FPCgVJ>g`Lg}cgIuEFVhN9co(NGUc}eVi%p z=%Cio1)dV8zS}Zaz=CX#6R`^Fn~MOmh#2eQ6w+UZF)mhIBY+y^$E{_WY|uXfwBmJ% zs%1tB>^!p}cb_-{&Xix_%ZM(p*BDdD;Mb#(<22KTrdsUny|y<;#qoTf^ea5xS2!vz z$}n+xQ%XttT)(IaBy$kt$fdZgQgZ1AX#eCQe8`j1`37IN5Yf>g&isN?=@H>Y2XOqH zBB6~W_7VcAnQJLoCF>cDUM?~*a2L;Yt!_wVQ=oCBrSJYpd#r-;f9`OEKdw5785HWrzslfQ31|Vr`vKW^&`- zyP`@Ip{Afy8YJ;-0$!lOf7v8&4=|U-`+O#xju#v)2G4rx{X8B8vTt|A# z|83^$U3GC6Y&l8;CdI0t<1szSkI(Gyq#9n_DQ^0Ur#}^`!QeCRUHw8%F3b=LR~)97 zEq@A$mojVfNG+9{`xJZ%PvLU5bQtaH?-1XlmtSzj?-a}RrRU2A+MbDvnuv^;IJy_t z>+n2#yBH_KlGz0u`w>w}PM%9Fas@=ed1LYO@MSB>dgh3-+AMs2kqD-qK&&S!dbg-- z1Vo$kE*~el2_#MdU*l{l-1G~B-5Zzig}?+oX;c=D#Bn*;AdE}-F9nNH@;GYU^{y4S z>d=lXL+HMY@$C#Y6D4Cibp(Kd3T_sEDdF==8*pfFX;%#2+~9wdwe+WpXa8P(C6NxGXRGa@U!UV{Rjg14?ymas zEB#f~#irSiLf9Y@2tX&U@iJJVOvh_IINJQ5dJkOr*4-zLP&Z z*{=ql7m=q0kJ4P0*-XdR@7`WT>6u%rb?4M|u?Lor*o})&DQZiR%B{5*$>0_lrPDK> zJZp2(r>(95rhGwst?U%6x6!N@L}ah^xF3{0H$j6Qwr}TRje6akUCm$IQvKWO-L>F& z=}4)?s8Orl0${QqS1twn*tb2kYl?ZSQMY*G-i=6;xS#msQntOBt+qh=>KqTi!0pmo zr7H9{oXp6lx|ZaPppV>ijD*HYW#!j-o>iINuyUE2_dt!`;2lxH{va} za+YBV3_RY&=%!gbEv<8TE#LCYl|oqnXo?@!?m~&I)G|7r*T#v<^-5ZA*~xu+{lQA^ zwH6r31>SgN3)lpto-ur_{#$GOs%KisXS<$je3kCumGDhx`*-=|*E@YGc(Z@`FQc&w z_3x-aMprPsgU0NA7)3|%b5%uV)-8ZsW6U+=`oVQMv?9Ufzn86T&+%Gmymcf@#`#)b z|8bO`2`=jw|L)6Hkyh_X zN0ep1W4MZBJs?z`t!5@SzGWRP)A{9EB$hxjxm!}weax+%Oa761{(rm{`hI0Fb;WN{ z{K@%TkngI$@oC=fl&R6WQih z;5d0l6i(~@y!fpF3eN#*VfteA(HT90!h_s$&!)~PFLdcy#@@U+uhPedPIzqdl!C5X zFXWD-s_xoD6Mv)D_I*RfW}P$3>S77P|LFV_usd5Fc((_9LO)+VF?G4f&e1v2pfJ9` zfL|lnk`~GU=8HGsInobkjH*!3Wfhx-t2xIK zvelZVhin{-!S67{>x%L)CZCscYCaEJRVN860}T~PDpJkr1f}Ba0TrhtF2?8%wJd}6 zzm0-Q<9n=A%1A}ft1E$eS{bOSIG$^9CD5;=`e`ha%vE_(Kr;yNnMzWWYwP)2fdL% z#>5bOnF5qjhTP?xbV$;8Ptg;qj6OvNZyG{A;t;?+mIt5=C;IDTMVD~iridB1g4br% zV*jHdvYKY2zH~=RGx$*vK0em~cI&BXY$Y1c+lwVikkop`z&THT5e+h^1VDF^RtPGI z`?&)hbMQ9Oj3vuiE-Ntg2vlPUaYq2yPb!?khoMs5Eg6t<+bDx{ccXJ>(DTb@MK# zm6l}11V`>jR&O0#XSDW9D{kef!&vsIS={7K{cZ>!4D>8y%qpZtO|Cj5iv! z9Y%`fV0boJW{E~UYZJjkV@VP7e>kG1`g(us{_52a*2wh@DBB-jt6ysK7kuH`syX&1 z$e9hN{ze<`W#{uib>c1l(aSCPR}4d&eear7&pF}VKOe~LYu_p9;uZlz1z%bfZZJpS z&P9Ap%Z)cOBdd@m+dm=raOZ6{lqyZHrSOq&cs{2*t)Td>Q=YP}E2$csn!YM?Wh z+YDWMlys1dvSA<2{lrcU>WvZ1&b0l?EmW+#3*sAUw~&SyF8l75KdDYOxhw36)68G< zz20J$dR!Q!7K=-fc-6gSPZ_5QPPW1S16} zP#--6KXFskVG@0xNY|sYbCNSMsfueW^J}v1nDm=Cw`7$XBoMS;fr#Asc#fH@BD4>E>?;R^VWPzxGusIQa3`vf1lDk?4hubd$UQ@y^S0xHeYU zNuzixHN$^&KLjAD8{lz0Ub=DZ0%sw+m_O9_vX3u%|KL{-n%8gsTyLrD_+s%-%`o7M z9K<*1)!O@+{Kt0f59S!Gv*_|9qtAVm^n@*=D>DLxU)1E`s;rV)Jw6j7_gly-KcA z35PGKEGT?gF`=!b4odpYS$uODQ*wc4+l;5yDc@YoZaS67PSST{;tw9L$#@sg=%O@# z-CR%F7`7{imh&ZhF;o z`jcy--UdZ=;B7M-%-TdL+k|=MJ7k%72!c?Xcsr2fLUoK{X8hBVIWR}R1=>sLOu9U~KsLpVS4%A@O4{^HsYV+?Js*I#iGslgw(@If9oqsoPm+GmO9VP%vMm9S@6d@? zjG^&AX*83ORl2^#?HEv{wDZP!DG%cM8+APHc9>#F@Vz<{TS2ErmG9v}Eezhe%?L8i z5~+049O?4uL5_su+kWF#G5>Y=iz&D-_ZJ^zqCXpUt_U$XF_u9{wqHUve-d5iJ!NA3 zy?avFE>i1kmlY6ZV%oa8$&mM@^@em1|bMLPJeDtNySy}fCuKJ_d!e`d4+z)=v zoZU^&;ZKG8XFM@=sSvE+ya>J9J#E~Ne2%&8go0!D*DJ*K34Mzw{RBpDbo58*FVlsA zUN6;UH{Sb2xlSzAM~n6ct8bw%>QtaiAGz^d|5560&^IfiSFgPKJEPOYA1wC0qi|8( zo`QpXN`G01;||W;s=8cr{|>Rs#m%o6`?=0;u6zXq`GyY?PwvvchaiewSe2&6tBrbS zAYkVwVw76TebL+(=ZOYR1F>CwJ&8>*3UugYtMti@MoHYW9gsK4+i`8BTZ49~ys@`c-6sehq~SS1qYYEFFJ3DR4W@#mf^r>anF&#rdyGr+6iiPhQO~tEXe* z^6JJ%fNBZz<#}Lto?# zm<&>(Yg2P~q=Xw9k!5No+x_#XxjdQtv|C$zcv>I%@}u*tjd6%6zO1~T2)g{hmC62h zzB}Je_inmxIZN+)q8Xs^Mi+7ol$g zNz(211}GX=05cC#`E<@$qghWUs0K09OrBQy>&Xi|kflQ_^CfAC-WlKtP@Z1S7S9i? z{>OYoJzAdPK#6bf@z7Y23YUOv1&81LWn81?LwWPO>J283i{QH^~6gLu?h)% zC}nTS^xFA;dhUw!ho4&pc#%n?V}6(0p`{+jKDVDsLl^Zg&_W@=6h~bUx z_{~v7sjs%tRUjOWw2_|e1W(1w{I97AN>i?aCL>g9OBup1o$Z#1Tsjm^i`F15iS2#? zY3YdrF#m))k!{J!UG$W|8rGYUl6nsZfv`Yv3-9Cyex%S)N^&?@tSPfe5i?NR3PIT$ zVuVU<_nj@H{&jzj7A^t$fZ`VY2|$PH#5dIxacfSanK)`odr!;8W_f zdp8@gfJ39xRY0F25=mxEVgps!0iZB9H;>zm%VFHw)e zcqupcCcC1bdG(P26C{qyYSQ6&w78Ms_c)NT@F#ZF7 z8XFH=re1)@9+c?{hbh`{S3!B{nt;6y_&GykoI|TB=oMrlQ5}IgZRre(8!&7&87A6g zGdcnk2gwyVlSjYqR1V^P0ADwE)H1G1vL}vdA}A z7Mn#Ivd(ZjLr=p2`{L=uM~lgGdmTY2jIwjp=F*-}PdnNuOw0Nax^dys8ZtF2rOn(=+E-84+*fkb z96h%h-ws@@UiaksKNzk*Le1upL^^)%MJ^U7S|M%N%z7^ef*&8o_ZU!8@h{Pdo2eT} zG}^4Dj~RjCLK2SmrPimt;w+*iys*~-9W#&61VIWYyJ}-#hk%_M>$Lf(l;)|SkVwRn zd+8RK&o6G!h15!F`15V`(QT6%1jS|^S*xRxtDFVm3ao$~6i}ogr6DegIY_}-M}qCi zxpb-+)f%|8hhT~b-a(p6Ne0-5tR*)yuU-GCh^>q@sRo!vL*MdSi?>zDY+M3$e4a0+sxS_TODseP51Cl6kt9QN$4h>E|m)h%894R#Ac zXYRgTDhvWObaGTYZe_|@k0DJ_n(%_VIF;Rb)-#8%M+^Kg*?s5gp$DYn{iE~@4C5~O zhkv`|)AP+H!$;1}y^Q(^YxYa-QOubg;|NWVoteh9v(-$0q6r&QQbavz4yZ3o2j+3* zpuh%{wO>t9?pHbhO%+*CZT)NaEH%fo#}}91h~?QvZDV@&M({86GEsYtv1%`inCbYz@IlKGkSMEqc2k_TP6T# zVx^C-(;R(*8uenF($IV$lmjv5IE7|XInXuj;_8-Gj4hT4uT$jU8^QkVNxE8WFZK*3 zC!2E3@P?0Pa=bfBGpb%?RoH2ia3d)Pu|%7?*x`XCsCT(v9@#TIin-7N4z-gWjqY0&C)Al() zACNzS3hCda;&Vz;i37B{Y@aY?xYs%$wo>}{b~j~;UMkXjn~90yI7sR zN~|!UBV>qr-neuS9@Oyp1uDsHkK;tW;l}E|{_^`qmpsJrD zz6Mwq>hWLf9K65?e+a=PE;O*#&QJf^31Ib|3i$1X?ApPLNtXQ`IRy|z2Qa7^xb{1L z`e$Fr_fyN2$m|m-$@^Xah2;~?wQ4A~*>olO^z7~SXVXuA0SE?vZ-g`Nrv5~${A_+T zk$V!aDK$)Z(OWue?rk*cR5ec)#_Up0%VbOOntp0gbT8MsZyM&KNHczOSw0tQ!*+m} zjlJW~6Qg+NYxrd?tC<--CwDyW8B~2EVF!`j;+Ku*{&UYG)Lw#P-ZLS)b?6O;&(Xh4 zZymjP;}RSpJ-INHQk!$9&v{&Xr$Mqa(1AQxJ73(Z?CI3V22vJ5ZIa2x*mVC7?k!#| ziy3`_!~Y6C;w7@zuD0?E`QU6rv^KxWSZ8-$mk8HBS(Vt|hq`x$=0Mc4EwVSR)L$S{ zaB8?4`g$lU?x*z?|6_JqK1`^~;ld_(EVYS9sz6>fbdgTm-(1u!n$`Y6BY~VnTY5yZ z{h|vV(!n?dk9q~Nu8?*33r#(NY_{QJ^V&Yl9 zujZw56P00|%v_4u6uce9ce8PTJtbZ#w3?rgP4I?gKu(Em&h1Rw=ME+k#7~WUy9?+n z48=-Vp(1rE7IjOVU&7%)N3ccT#s-k)vb>M=s~DkMK)V*_mMun|D+xM|wdo8=C-NLA zvXoz5Q+TtI2Lo6lMQGHgH8|g^?ZuVHZUV##V>HJwXfu|OTVk4JYB_PJ^x)MR19r5I zm=03{HE0p&$|bxb3H}{QW8!72>_%xcq~wMs44gJ!<@l{&1qsEPCOMO8kw6g4KfA+- zc!n!5m0kXiYCMbM2%g0_plIUARMjZ>Q(4A9wJ8P;;knbexsG5=tz03IdYD*{S2@)y zVKqk1Vp?!eWg66`l4nk@T)tbd_g+wb57YiHIl6)6^N?xGupK+dt;z2sEl0U^fwoU2 zoxgDOB}x%jW(#oq^1P5>Ol|dUc)=U5y-je-sr7o1rb*1oPQfkk%k{U@v-EI)TJf!N>G&Gp5SzZEMXbiu9=&-4nrzXic z;H@*u$ZRCp!lEfy1GQk4a^>+NUX++FpT^@w?9+yjkPJjdFck*2W{ToyRIWpa3PYVT z8!1x7;Vztw=x`$HWO8OplPy3M0Rnn&l>=Y(I%hWM5NP@_m1V{7mLP*bXhC(DG~=pk zl6H^a^Lf>_fCH-rN)|xrXDArK4OmA(s#?BDV^skLOA^IHFh&eDbsnb>7I*Dv(EJl`tovyh0^S$;T08m}bC{9)LKFI+)7=5j${yN+K_-WrU1! z`800ILm*7mL3@|STc;tY36kigv>OT`ahZ)YD__oY8x_7O!-w9?Aj>N5*@t-E!PsI; z{!;$`vC< z!M;W4bM(-W7u{u@Qqw-opCC=!$bnM7^)G2$e@5HU zr8JDV$EhN*;CPpC;M275HJlz~^tqA}^;7P2rDNjQ;0+kH2q-JFUn1hn_jO@?l~{%E$){48 zP`W)o_(6KQN-fH@%Ug3ut;kM?#_;5Tf`HVD5;plaZLp=QMuXr8oBGZ19PT)tqM74C zv`)@!558E(ohuKcJQpaPdIw?>aA0n^`OV+%6so-2H3%9jh1u=Z-BX-8C;Ynp8p!O_ z<7}yuNf9pkz4nE+`PY?#&|0OP+L$*$q$iwWDByT&Tl{Y5?hsbkR>)teF0EvE)Tu?? zLTo9Li8G4QGJI;S9vn{}q6wK7fGW zq087&(53yM0E{YJ63)V(C;w4fS}g0n5^1>Fs5&;as3@GhX=BbrW;P$X{5EbP#F~@q)SqKXI|&IVO9?vT&7aU#Spc! zkjv8XakeFRBgwWb@??3WkgUjm+5|KhAwjW_Q_HO9Zh$*6ge^nxkZ*x;45|L6qUG!A z9%)DC6!po)|_C&fYqTI=3!T)zC@y6a~KH)~C-8yg;`Y^a}p zO|*#{K35IclOi{-)Z7W&wH(`h?y^|fRX)@G=C(4(-A#zJ6F1#QA;?R;)0*{hH)loK zSJ&249Da6bnAytv>@de^Yf(t;VL-9rJ>Ra@jq1^t?vj`7#P-`+A)szl=F9h{Vf&b^K2acG;Luj+sxCu@iHH44+@Pk;s zvvek9Odeaz5cE?Le{~B^Chv$T=W}oiv6q8AqVfyVLC-8)xZ9EYd)6E&m-XpgjF<<9 zWzy^H=H3cEGl$BxNj%EUGU> zV|HyZ%T1BZW*9^Wlt0ltkRk}Bw}m-SkG4Z{S?CBIlmYb?9d;bOV4`_*&Z#G0jwdh` z436@B35*qEY+eFNb-G+zDgdfGY~e(OH#mF4pi{3d

Kk`7wS=kziH_91K!S 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