From a4d26881cbe71c28993fac96f786120fe60c18f5 Mon Sep 17 00:00:00 2001 From: Syoyo Fujita Date: Sun, 20 Dec 2015 20:27:54 +0900 Subject: [PATCH] Initial commit. --- .clang-format | 7 + Makefile | 5 + README.md | 78 + examples/glview/README.md | 23 + examples/glview/glview.cc | 460 +++ examples/glview/premake4.lua | 36 + examples/glview/shader.frag | 6 + examples/glview/shader.vert | 12 + examples/glview/trackball.cc | 292 ++ examples/glview/trackball.h | 75 + images/glview_duck.png | Bin 0 -> 262861 bytes picojson.h | 1039 ++++++ stb_image.h | 6509 ++++++++++++++++++++++++++++++++++ test.cc | 314 ++ tiny_gltf_loader.h | 1262 +++++++ 15 files changed, 10118 insertions(+) create mode 100644 .clang-format create mode 100644 Makefile create mode 100644 README.md create mode 100644 examples/glview/README.md create mode 100644 examples/glview/glview.cc create mode 100644 examples/glview/premake4.lua create mode 100644 examples/glview/shader.frag create mode 100644 examples/glview/shader.vert create mode 100644 examples/glview/trackball.cc create mode 100644 examples/glview/trackball.h create mode 100644 images/glview_duck.png create mode 100644 picojson.h create mode 100644 stb_image.h create mode 100644 test.cc create mode 100644 tiny_gltf_loader.h diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..a94a2c4 --- /dev/null +++ b/.clang-format @@ -0,0 +1,7 @@ +--- +BasedOnStyle: LLVM +IndentWidth: 2 +TabWidth: 2 +UseTab: Never +BreakBeforeBraces: Attach +Standard: Cpp03 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..60c922a --- /dev/null +++ b/Makefile @@ -0,0 +1,5 @@ +all: + clang++ -Wall -Werror -g -O0 -o loader_test test.cc && ./loader_test face3d.gltf + +beautify: + ~/local/clang+llvm-3.6.0-x86_64-apple-darwin/bin/clang-format -i tiny_gltf_loader.h diff --git a/README.md b/README.md new file mode 100644 index 0000000..89ad73e --- /dev/null +++ b/README.md @@ -0,0 +1,78 @@ +# Tiny glTF loader, header only C++ glTF parsing library. + +`TinyGLTFLoader` is a header only C++ glTF https://github.com/KhronosGroup/glTF parsing library + +![](images/glview_duck.png) + +## Features + +* Portable C++. C++-98 with STL dependency only. +* Moderate parsing time and memory consumption. +* glTF specification v1.0.0 +* Buffers + * [x] Parse BASE64 encoded embedded buffer fata(DataURI). + * [x] Load `.bin` file. +* Image(Using stb_image) + * [x] Parse BASE64 encoded embedded image fata(DataURI). + * [x] Load external image file. + * [x] PNG(8bit only) + * [x] JPEG(8bit only) + * [x] BMP + * [x] GIF + +## Limitation + +Currently, TinyGLTFLoader only loads nodes and geometry(mesh/buffer) data. + +## Examples + +* [glview](examples/glview) : Simple glTF geometry viewer. + +## TODOs + +* [ ] Support multiple scenes in `.gltf` +* [ ] Parse `animation`, `program`, `sampler`, `shader`, `technique`, `texture` +* [ ] Compression/decompression(Open3DGC, etc) +* [ ] Support `extensions` and `extras` property +* [ ] Load `.gltf` from memory. +* [ ] HDR image +* [ ] Binary glTF. + +## License + +TinyGLTFLoader is licensed under 2-clause BSD. + +TinyGLTFLoader uses the following third party libraries. + +* picojson.h : Copyright 2009-2010 Cybozu Labs, Inc. Copyright 2011-2014 Kazuho Oku +* base64 : Copyright (C) 2004-2008 René Nyffenegger +* stb_image.h : v2.08 - public domain image loader - http://nothings.org/stb_image.h + + +## Build and example + +Copy `stb_image.h`, picojson.h` and `tiny_gltf_loader.h` to your project. + +``` +// Define these only in *one* .cc file. +#define TINYGLTF_LOADER_IMPLEMENTATION +#define STB_IMAGE_IMPLEMENTATION +#include "tiny_gltf_loader.h" + +using namespace tinygltf; + +Scene scene; +TinyGLTFLoader loader; +std::string err; + +bool ret = loader.LoadFromFile(scene, err, argv[1]); +if (!err.empty()) { + printf("Err: %s\n", err.c_str()); +} + +if (!ret) { + printf("Failed to parse glTF\n"); + return -1; +} +``` + diff --git a/examples/glview/README.md b/examples/glview/README.md new file mode 100644 index 0000000..b248bcf --- /dev/null +++ b/examples/glview/README.md @@ -0,0 +1,23 @@ +Simple OpenGL viewer for glTF geometry. + +## Requirements + +* premake4 : Requires recent `premake4` for macosx and linux, `premake5` for windows. +* GLEW +* glfw3 + +### MacOSX and Linux + + > premake4 gmake + $ make + +### Windows(not tested) + + > premake5.exe vs2013 + Open .sln in Visual Studio 2013 + +## TODO + +* [ ] Texture +* [ ] Shader +* [ ] Animation diff --git a/examples/glview/glview.cc b/examples/glview/glview.cc new file mode 100644 index 0000000..42a0b08 --- /dev/null +++ b/examples/glview/glview.cc @@ -0,0 +1,460 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef __APPLE__ +#include +#else +#include +#endif + +#include + +#include "trackball.h" + +#define TINYGLTF_LOADER_IMPLEMENTATION +#define STB_IMAGE_IMPLEMENTATION +#include "tiny_gltf_loader.h" + +#define BUFFER_OFFSET(i) ((char *)NULL + (i)) + +#define CAM_Z (3.0f) +int width = 768; +int height = 768; + +double prevMouseX, prevMouseY; +bool mouseLeftPressed; +bool mouseMiddlePressed; +bool mouseRightPressed; +float curr_quat[4]; +float prev_quat[4]; +float eye[3], lookat[3], up[3]; + +GLFWwindow* window; + +typedef struct +{ + GLuint vb; +} GLBufferState; + +typedef struct +{ + std::map attribs; +} GLProgramState; + +std::map gBufferState; +GLProgramState gGLProgramState; + +void CheckErrors(std::string desc) { + GLenum e = glGetError(); + if (e != GL_NO_ERROR) { + fprintf(stderr, "OpenGL error in \"%s\": %d (%d)\n", desc.c_str(), e, e); + exit(20); + } +} + +bool LoadShader(GLenum shaderType, // GL_VERTEX_SHADER or GL_FRAGMENT_SHADER(or + // maybe GL_COMPUTE_SHADER) + GLuint &shader, const char *shaderSourceFilename) { + GLint val = 0; + + // free old shader/program + if (shader != 0) { + glDeleteShader(shader); + } + + std::vector srcbuf; + FILE *fp = fopen(shaderSourceFilename, "rb"); + if (!fp) { + fprintf(stderr, "failed to load shader: %s\n", shaderSourceFilename); + return false; + } + fseek(fp, 0, SEEK_END); + size_t len = ftell(fp); + rewind(fp); + srcbuf.resize(len + 1); + len = fread(&srcbuf.at(0), 1, len, fp); + srcbuf[len] = 0; + fclose(fp); + + const GLchar* srcs[1]; + srcs[0] = &srcbuf.at(0); + + shader = glCreateShader(shaderType); + glShaderSource(shader, 1, srcs, NULL); + glCompileShader(shader); + glGetShaderiv(shader, GL_COMPILE_STATUS, &val); + if (val != GL_TRUE) { + char log[4096]; + GLsizei msglen; + glGetShaderInfoLog(shader, 4096, &msglen, log); + printf("%s\n", log); + // assert(val == GL_TRUE && "failed to compile shader"); + printf("ERR: Failed to load or compile shader [ %s ]\n", + shaderSourceFilename); + return false; + } + + printf("Load shader [ %s ] OK\n", shaderSourceFilename); + return true; +} + +bool LinkShader(GLuint &prog, GLuint &vertShader, GLuint &fragShader) { + GLint val = 0; + + if (prog != 0) { + glDeleteProgram(prog); + } + + prog = glCreateProgram(); + + glAttachShader(prog, vertShader); + glAttachShader(prog, fragShader); + glLinkProgram(prog); + + glGetProgramiv(prog, GL_LINK_STATUS, &val); + assert(val == GL_TRUE && "failed to link shader"); + + printf("Link shader OK\n"); + + return true; +} + +void reshapeFunc(GLFWwindow* window, int w, int h) +{ + glViewport(0, 0, w, h); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(45.0, (float)w / (float)h, 0.1f, 1000.0f); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + width = w; + height = h; +} + +void keyboardFunc(GLFWwindow *window, int key, int scancode, int action, int mods) { + if(action == GLFW_PRESS || action == GLFW_REPEAT){ + // Close window + if(key == GLFW_KEY_Q || key == GLFW_KEY_ESCAPE) glfwSetWindowShouldClose(window, GL_TRUE); + } +} + +void clickFunc(GLFWwindow* window, int button, int action, int mods){ + double x, y; + glfwGetCursorPos(window,&x, &y); + + if(button == GLFW_MOUSE_BUTTON_LEFT){ + mouseLeftPressed = true; + if(action == GLFW_PRESS){ + int id = -1; + //int id = ui.Proc(x, y); + if (id < 0) { // outside of UI + trackball(prev_quat, 0.0, 0.0, 0.0, 0.0); + } + } else if(action == GLFW_RELEASE){ + mouseLeftPressed = false; + } + } + if(button == GLFW_MOUSE_BUTTON_RIGHT){ + if(action == GLFW_PRESS){ + mouseRightPressed = true; + } else if(action == GLFW_RELEASE){ + mouseRightPressed = false; + } + } + if(button == GLFW_MOUSE_BUTTON_MIDDLE){ + if(action == GLFW_PRESS){ + mouseMiddlePressed = true; + } else if(action == GLFW_RELEASE){ + mouseMiddlePressed = false; + } + } +} + +void motionFunc(GLFWwindow* window, double mouse_x, double mouse_y){ + float rotScale = 1.0f; + float transScale = 2.0f; + + if(mouseLeftPressed){ + trackball(prev_quat, + rotScale * (2.0f * prevMouseX - width) / (float)width, + rotScale * (height - 2.0f * prevMouseY) / (float)height, + rotScale * (2.0f * mouse_x - width) / (float)width, + rotScale * (height - 2.0f * mouse_y) / (float)height); + + add_quats(prev_quat, curr_quat, curr_quat); + } else if (mouseMiddlePressed) { + eye[0] += -transScale * (mouse_x - prevMouseX) / (float)width; + lookat[0] += -transScale * (mouse_x - prevMouseX) / (float)width; + eye[1] += transScale * (mouse_y - prevMouseY) / (float)height; + lookat[1] += transScale * (mouse_y - prevMouseY) / (float)height; + } else if (mouseRightPressed) { + eye[2] += transScale * (mouse_y - prevMouseY) / (float)height; + lookat[2] += transScale * (mouse_y - prevMouseY) / (float)height; + } + + // Update mouse point + prevMouseX = mouse_x; + prevMouseY = mouse_y; +} + +static void SetupGLState(Scene& scene, GLuint progId) +{ + std::map::const_iterator it(scene.bufferViews.begin()); + std::map::const_iterator itEnd(scene.bufferViews.end()); + + for (; it != itEnd; it++) { + const BufferView& bufferView = it->second; + if (bufferView.target == 0) { + continue; // Unsupported bufferView. + } + + const Buffer& buffer = scene.buffers[bufferView.buffer]; + GLBufferState state; + glGenBuffers(1, &state.vb); + glBindBuffer(bufferView.target, state.vb); + glBufferData(bufferView.target, bufferView.byteLength, &buffer.data.at(0) + bufferView.byteOffset, GL_STATIC_DRAW); + glBindBuffer(bufferView.target, 0); + + gBufferState[it->first] = state; + } + + glUseProgram(progId); + GLint vtloc = glGetAttribLocation(progId, "in_vertex"); + GLint nrmloc = glGetAttribLocation(progId, "in_normal"); + gGLProgramState.attribs["POSITION"] = vtloc; + gGLProgramState.attribs["NORMAL"] = nrmloc; + +}; + +void DrawMesh(Scene& scene, const Mesh& mesh) +{ + for (size_t i = 0; i < mesh.primitives.size(); i++) { + const Primitive& primitive = mesh.primitives[i]; + + if (primitive.indices.empty()) return; + + std::map::const_iterator it(primitive.attributes.begin()); + std::map::const_iterator itEnd(primitive.attributes.end()); + + for (; it != itEnd; it++) { + const Accessor& accessor = scene.accessors[it->second]; + glBindBuffer(GL_ARRAY_BUFFER, gBufferState[accessor.bufferView].vb); + CheckErrors("bind buffer"); + int count = 1; + if (accessor.type == TINYGLTF_TYPE_SCALAR) { + count = 1; + } else if (accessor.type == TINYGLTF_TYPE_VEC2) { + count = 2; + } else if (accessor.type == TINYGLTF_TYPE_VEC3) { + count = 3; + } else if (accessor.type == TINYGLTF_TYPE_VEC4) { + count = 4; + } + // it->first would be "POSITION", "NORMAL", ... + if ( (it->first.compare("POSITION") == 0) || + (it->first.compare("NORMAL") == 0)) { + glVertexAttribPointer(gGLProgramState.attribs[it->first], count, accessor.componentType, GL_FALSE, accessor.byteStride, BUFFER_OFFSET(accessor.byteOffset)); + CheckErrors("vertex attrib pointer"); + glEnableVertexAttribArray(gGLProgramState.attribs[it->first]); + CheckErrors("enable vertex attrib array"); + } + } + + const Accessor& indexAccessor = scene.accessors[primitive.indices]; + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gBufferState[indexAccessor.bufferView].vb); + CheckErrors("bind buffer"); + int mode = -1; + if (primitive.mode == TINYGLTF_MODE_TRIANGLES) { + mode = GL_TRIANGLES; + } else if (primitive.mode == TINYGLTF_MODE_TRIANGLE_STRIP) { + mode = GL_TRIANGLE_STRIP; + } else if (primitive.mode == TINYGLTF_MODE_TRIANGLE_FAN) { + mode = GL_TRIANGLE_FAN; + } else if (primitive.mode == TINYGLTF_MODE_POINTS) { + mode = GL_POINTS; + } else if (primitive.mode == TINYGLTF_MODE_LINE) { + mode = GL_LINES; + } else if (primitive.mode == TINYGLTF_MODE_LINE_LOOP) { + mode = GL_LINE_LOOP; + }; + glDrawElements(mode, indexAccessor.count, indexAccessor.componentType, BUFFER_OFFSET(indexAccessor.byteOffset)); + CheckErrors("draw elements"); + + { + std::map::const_iterator it(primitive.attributes.begin()); + std::map::const_iterator itEnd(primitive.attributes.end()); + + for (; it != itEnd; it++) { + if ( (it->first.compare("POSITION") == 0) || + (it->first.compare("NORMAL") == 0)) { + glDisableVertexAttribArray(gGLProgramState.attribs[it->first]); + } + } + } + } + +} + +void DrawScene(Scene& scene) +{ + std::map::const_iterator it(scene.meshes.begin()); + std::map::const_iterator itEnd(scene.meshes.end()); + + for (; it != itEnd; it++) { + DrawMesh(scene, it->second); + } +} + + +static void Init() { + trackball(curr_quat, 0, 0, 0, 0); + + eye[0] = 0.0f; + eye[1] = 0.0f; + eye[2] = CAM_Z; + + lookat[0] = 0.0f; + lookat[1] = 0.0f; + lookat[2] = 0.0f; + + up[0] = 0.0f; + up[1] = 1.0f; + up[2] = 0.0f; +} + +int main(int argc, char **argv) +{ + if (argc < 2) { + std::cout << "glview input.gltf \n" << std::endl; + return 0; + } + + float scale = 1.0f; + if (argc > 2) { + scale = atof(argv[2]); + } + + Scene scene; + TinyGLTFLoader loader; + std::string err; + + bool ret = loader.LoadFromFile(scene, err, argv[1]); + if (!err.empty()) { + printf("ERR: %s\n", err.c_str()); + } + if (!ret) { + printf("Failed to load .glTF : %s\n", argv[1]); + exit(-1); + } + + Init(); + + if(!glfwInit()){ + std::cerr << "Failed to initialize GLFW." << std::endl; + return -1; + } + + window = glfwCreateWindow(width, height, "Simple glTF geometry viewer", NULL, NULL); + if(window == NULL){ + std::cerr << "Failed to open GLFW window. " << std::endl; + glfwTerminate(); + return 1; + } + + glfwGetWindowSize(window, &width, &height); + + glfwMakeContextCurrent(window); + + // Callback + glfwSetWindowSizeCallback(window, reshapeFunc); + glfwSetKeyCallback(window, keyboardFunc); + glfwSetMouseButtonCallback(window, clickFunc); + glfwSetCursorPosCallback(window, motionFunc); + + glewExperimental = true; + if (glewInit() != GLEW_OK) { + std::cerr << "Failed to initialize GLEW." << std::endl; + return -1; + } + + reshapeFunc(window, width, height); + + GLuint vertId = 0, fragId = 0, progId = 0; + if (false == LoadShader(GL_VERTEX_SHADER, vertId, "shader.vert")) { + return -1; + } + CheckErrors("load vert shader"); + + if (false == LoadShader(GL_FRAGMENT_SHADER, fragId, "shader.frag")) { + return -1; + } + CheckErrors("load frag shader"); + + if (false == LinkShader(progId, vertId, fragId)) { + return -1; + } + + CheckErrors("link"); + + { + GLint vtxLoc = glGetAttribLocation(progId, "in_vertex"); + if (vtxLoc < 0) { + printf("vertex loc not found.\n"); + exit(-1); + } + + GLint tnLoc = glGetAttribLocation(progId, "in_normal"); + if (tnLoc < 0) { + printf("normal loc not found.\n"); + exit(-1); + } + } + + glUseProgram(progId); + CheckErrors("useProgram"); + + SetupGLState(scene, progId); + CheckErrors("SetupGLState"); + + while(glfwWindowShouldClose(window) == GL_FALSE) { + glfwPollEvents(); + glClearColor(0.1f, 0.2f, 0.3f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glEnable(GL_DEPTH_TEST); + + GLfloat mat[4][4]; + build_rotmatrix(mat, curr_quat); + + // camera(define it in projection matrix) + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + gluLookAt(eye[0], eye[1], eye[2], lookat[0], lookat[1], lookat[2], up[0], up[1], up[2]); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glMultMatrixf(&mat[0][0]); + + glScalef(scale, scale, scale); + + DrawScene(scene); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + + glFlush(); + + glfwSwapBuffers(window); + } + + glfwTerminate(); +} diff --git a/examples/glview/premake4.lua b/examples/glview/premake4.lua new file mode 100644 index 0000000..afcfa97 --- /dev/null +++ b/examples/glview/premake4.lua @@ -0,0 +1,36 @@ +solution "glview" + -- location ( "build" ) + configurations { "Debug", "Release" } + platforms {"native", "x64", "x32"} + + project "glview" + + kind "ConsoleApp" + language "C++" + files { "glview.cc", "trackball.cc" } + includedirs { "./" } + includedirs { "../../" } + + configuration { "linux" } + linkoptions { "`pkg-config --libs glfw3`" } + links { "GL", "GLU", "m", "GLEW" } + + configuration { "windows" } + links { "glfw3", "gdi32", "winmm", "user32", "GLEW", "glu32","opengl32", "kernel32" } + defines { "_CRT_SECURE_NO_WARNINGS" } + + configuration { "macosx" } + includedirs { "/usr/local/include" } + buildoptions { "-Wno-deprecated-declarations" } + libdirs { "/usr/local/lib" } + links { "glfw3", "GLEW" } + linkoptions { "-framework OpenGL", "-framework Cocoa", "-framework IOKit", "-framework CoreVideo" } + + configuration "Debug" + defines { "DEBUG" } + flags { "Symbols", "ExtraWarnings"} + + configuration "Release" + defines { "NDEBUG" } + flags { "Optimize", "ExtraWarnings"} + diff --git a/examples/glview/shader.frag b/examples/glview/shader.frag new file mode 100644 index 0000000..bd2fc49 --- /dev/null +++ b/examples/glview/shader.frag @@ -0,0 +1,6 @@ +varying vec3 normal; + +void main(void) +{ + gl_FragColor = vec4(0.5 * normalize(normal) + 0.5, 1.0); +} diff --git a/examples/glview/shader.vert b/examples/glview/shader.vert new file mode 100644 index 0000000..a21fa30 --- /dev/null +++ b/examples/glview/shader.vert @@ -0,0 +1,12 @@ +attribute vec3 in_vertex; +attribute vec3 in_normal; + +varying vec3 normal; + +void main(void) +{ + vec4 p = gl_ModelViewProjectionMatrix * vec4(in_vertex, 1); + gl_Position = p; + vec4 nn = gl_ModelViewMatrixInverseTranspose * vec4(normalize(in_normal), 0); + normal = nn.xyz; +} diff --git a/examples/glview/trackball.cc b/examples/glview/trackball.cc new file mode 100644 index 0000000..86ff3b3 --- /dev/null +++ b/examples/glview/trackball.cc @@ -0,0 +1,292 @@ +/* + * (c) Copyright 1993, 1994, Silicon Graphics, Inc. + * ALL RIGHTS RESERVED + * Permission to use, copy, modify, and distribute this software for + * any purpose and without fee is hereby granted, provided that the above + * copyright notice appear in all copies and that both the copyright notice + * and this permission notice appear in supporting documentation, and that + * the name of Silicon Graphics, Inc. not be used in advertising + * or publicity pertaining to distribution of the software without specific, + * written prior permission. + * + * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" + * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR + * FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON + * GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT, + * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY + * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION, + * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF + * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN + * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE + * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE. + * + * US Government Users Restricted Rights + * Use, duplication, or disclosure by the Government is subject to + * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph + * (c)(1)(ii) of the Rights in Technical Data and Computer Software + * clause at DFARS 252.227-7013 and/or in similar or successor + * clauses in the FAR or the DOD or NASA FAR Supplement. + * Unpublished-- rights reserved under the copyright laws of the + * United States. Contractor/manufacturer is Silicon Graphics, + * Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311. + * + * OpenGL(TM) is a trademark of Silicon Graphics, Inc. + */ +/* + * Trackball code: + * + * Implementation of a virtual trackball. + * Implemented by Gavin Bell, lots of ideas from Thant Tessman and + * the August '88 issue of Siggraph's "Computer Graphics," pp. 121-129. + * + * Vector manip code: + * + * Original code from: + * David M. Ciemiewicz, Mark Grossman, Henry Moreton, and Paul Haeberli + * + * Much mucking with by: + * Gavin Bell + */ +#include +#include "trackball.h" + +/* + * This size should really be based on the distance from the center of + * rotation to the point on the object underneath the mouse. That + * point would then track the mouse as closely as possible. This is a + * simple example, though, so that is left as an Exercise for the + * Programmer. + */ +#define TRACKBALLSIZE (0.8) + +/* + * Local function prototypes (not defined in trackball.h) + */ +static float tb_project_to_sphere(float, float, float); +static void normalize_quat(float[4]); + +static void vzero(float *v) { + v[0] = 0.0; + v[1] = 0.0; + v[2] = 0.0; +} + +static void vset(float *v, float x, float y, float z) { + v[0] = x; + v[1] = y; + v[2] = z; +} + +static void vsub(const float *src1, const float *src2, float *dst) { + dst[0] = src1[0] - src2[0]; + dst[1] = src1[1] - src2[1]; + dst[2] = src1[2] - src2[2]; +} + +static void vcopy(const float *v1, float *v2) { + register int i; + for (i = 0; i < 3; i++) + v2[i] = v1[i]; +} + +static void vcross(const float *v1, const float *v2, float *cross) { + float temp[3]; + + temp[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]); + temp[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]); + temp[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]); + vcopy(temp, cross); +} + +static float vlength(const float *v) { + return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); +} + +static void vscale(float *v, float div) { + v[0] *= div; + v[1] *= div; + v[2] *= div; +} + +static void vnormal(float *v) { vscale(v, 1.0 / vlength(v)); } + +static float vdot(const float *v1, const float *v2) { + return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]; +} + +static void vadd(const float *src1, const float *src2, float *dst) { + dst[0] = src1[0] + src2[0]; + dst[1] = src1[1] + src2[1]; + dst[2] = src1[2] + src2[2]; +} + +/* + * Ok, simulate a track-ball. Project the points onto the virtual + * trackball, then figure out the axis of rotation, which is the cross + * product of P1 P2 and O P1 (O is the center of the ball, 0,0,0) + * Note: This is a deformed trackball-- is a trackball in the center, + * but is deformed into a hyperbolic sheet of rotation away from the + * center. This particular function was chosen after trying out + * several variations. + * + * It is assumed that the arguments to this routine are in the range + * (-1.0 ... 1.0) + */ +void trackball(float q[4], float p1x, float p1y, float p2x, float p2y) { + float a[3]; /* Axis of rotation */ + float phi; /* how much to rotate about axis */ + float p1[3], p2[3], d[3]; + float t; + + if (p1x == p2x && p1y == p2y) { + /* Zero rotation */ + vzero(q); + q[3] = 1.0; + return; + } + + /* + * First, figure out z-coordinates for projection of P1 and P2 to + * deformed sphere + */ + vset(p1, p1x, p1y, tb_project_to_sphere(TRACKBALLSIZE, p1x, p1y)); + vset(p2, p2x, p2y, tb_project_to_sphere(TRACKBALLSIZE, p2x, p2y)); + + /* + * Now, we want the cross product of P1 and P2 + */ + vcross(p2, p1, a); + + /* + * Figure out how much to rotate around that axis. + */ + vsub(p1, p2, d); + t = vlength(d) / (2.0 * TRACKBALLSIZE); + + /* + * Avoid problems with out-of-control values... + */ + if (t > 1.0) + t = 1.0; + if (t < -1.0) + t = -1.0; + phi = 2.0 * asin(t); + + axis_to_quat(a, phi, q); +} + +/* + * Given an axis and angle, compute quaternion. + */ +void axis_to_quat(float a[3], float phi, float q[4]) { + vnormal(a); + vcopy(a, q); + vscale(q, sin(phi / 2.0)); + q[3] = cos(phi / 2.0); +} + +/* + * Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet + * if we are away from the center of the sphere. + */ +static float tb_project_to_sphere(float r, float x, float y) { + float d, t, z; + + d = sqrt(x * x + y * y); + if (d < r * 0.70710678118654752440) { /* Inside sphere */ + z = sqrt(r * r - d * d); + } else { /* On hyperbola */ + t = r / 1.41421356237309504880; + z = t * t / d; + } + return z; +} + +/* + * Given two rotations, e1 and e2, expressed as quaternion rotations, + * figure out the equivalent single rotation and stuff it into dest. + * + * This routine also normalizes the result every RENORMCOUNT times it is + * called, to keep error from creeping in. + * + * NOTE: This routine is written so that q1 or q2 may be the same + * as dest (or each other). + */ + +#define RENORMCOUNT 97 + +void add_quats(float q1[4], float q2[4], float dest[4]) { + static int count = 0; + float t1[4], t2[4], t3[4]; + float tf[4]; + + vcopy(q1, t1); + vscale(t1, q2[3]); + + vcopy(q2, t2); + vscale(t2, q1[3]); + + vcross(q2, q1, t3); + vadd(t1, t2, tf); + vadd(t3, tf, tf); + tf[3] = q1[3] * q2[3] - vdot(q1, q2); + + dest[0] = tf[0]; + dest[1] = tf[1]; + dest[2] = tf[2]; + dest[3] = tf[3]; + + if (++count > RENORMCOUNT) { + count = 0; + normalize_quat(dest); + } +} + +/* + * Quaternions always obey: a^2 + b^2 + c^2 + d^2 = 1.0 + * If they don't add up to 1.0, dividing by their magnitued will + * renormalize them. + * + * Note: See the following for more information on quaternions: + * + * - Shoemake, K., Animating rotation with quaternion curves, Computer + * Graphics 19, No 3 (Proc. SIGGRAPH'85), 245-254, 1985. + * - Pletinckx, D., Quaternion calculus as a basic tool in computer + * graphics, The Visual Computer 5, 2-13, 1989. + */ +static void normalize_quat(float q[4]) { + int i; + float mag; + + mag = (q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]); + for (i = 0; i < 4; i++) + q[i] /= mag; +} + +/* + * Build a rotation matrix, given a quaternion rotation. + * + */ +void build_rotmatrix(float m[4][4], const float q[4]) { + m[0][0] = 1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2]); + m[0][1] = 2.0 * (q[0] * q[1] - q[2] * q[3]); + m[0][2] = 2.0 * (q[2] * q[0] + q[1] * q[3]); + m[0][3] = 0.0; + + m[1][0] = 2.0 * (q[0] * q[1] + q[2] * q[3]); + m[1][1] = 1.0 - 2.0 * (q[2] * q[2] + q[0] * q[0]); + m[1][2] = 2.0 * (q[1] * q[2] - q[0] * q[3]); + m[1][3] = 0.0; + + m[2][0] = 2.0 * (q[2] * q[0] - q[1] * q[3]); + m[2][1] = 2.0 * (q[1] * q[2] + q[0] * q[3]); + m[2][2] = 1.0 - 2.0 * (q[1] * q[1] + q[0] * q[0]); + m[2][3] = 0.0; + + m[3][0] = 0.0; + m[3][1] = 0.0; + m[3][2] = 0.0; + m[3][3] = 1.0; +} diff --git a/examples/glview/trackball.h b/examples/glview/trackball.h new file mode 100644 index 0000000..b1f9437 --- /dev/null +++ b/examples/glview/trackball.h @@ -0,0 +1,75 @@ +/* + * (c) Copyright 1993, 1994, Silicon Graphics, Inc. + * ALL RIGHTS RESERVED + * Permission to use, copy, modify, and distribute this software for + * any purpose and without fee is hereby granted, provided that the above + * copyright notice appear in all copies and that both the copyright notice + * and this permission notice appear in supporting documentation, and that + * the name of Silicon Graphics, Inc. not be used in advertising + * or publicity pertaining to distribution of the software without specific, + * written prior permission. + * + * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" + * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR + * FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON + * GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT, + * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY + * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION, + * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF + * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN + * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE + * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE. + * + * US Government Users Restricted Rights + * Use, duplication, or disclosure by the Government is subject to + * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph + * (c)(1)(ii) of the Rights in Technical Data and Computer Software + * clause at DFARS 252.227-7013 and/or in similar or successor + * clauses in the FAR or the DOD or NASA FAR Supplement. + * Unpublished-- rights reserved under the copyright laws of the + * United States. Contractor/manufacturer is Silicon Graphics, + * Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311. + * + * OpenGL(TM) is a trademark of Silicon Graphics, Inc. + */ +/* + * trackball.h + * A virtual trackball implementation + * Written by Gavin Bell for Silicon Graphics, November 1988. + */ + +/* + * Pass the x and y coordinates of the last and current positions of + * the mouse, scaled so they are from (-1.0 ... 1.0). + * + * The resulting rotation is returned as a quaternion rotation in the + * first paramater. + */ +void trackball(float q[4], float p1x, float p1y, float p2x, float p2y); + +void negate_quat(float *q, float *qn); + +/* + * Given two quaternions, add them together to get a third quaternion. + * Adding quaternions to get a compound rotation is analagous to adding + * translations to get a compound translation. When incrementally + * adding rotations, the first argument here should be the new + * rotation, the second and third the total rotation (which will be + * over-written with the resulting new total rotation). + */ +void add_quats(float *q1, float *q2, float *dest); + +/* + * A useful function, builds a rotation matrix in Matrix based on + * given quaternion. + */ +void build_rotmatrix(float m[4][4], const float q[4]); + +/* + * This function computes a quaternion based on an axis (defined by + * the given vector) and an angle about which to rotate. The angle is + * expressed in radians. The result is put into the third argument. + */ +void axis_to_quat(float a[3], float phi, float q[4]); diff --git a/images/glview_duck.png b/images/glview_duck.png new file mode 100644 index 0000000000000000000000000000000000000000..0d58e31dc3f45d580b1ab95a3e7f911f0b8578df GIT binary patch literal 262861 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 <=Kjj#^PG6_YH_$1!kz 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 nMu!yr=l&OI@N1T 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%0A_K&qhH>n*LHbHti+ z-;~WW`vYdJlHYlf=5CjHmCG0(@!_BSo%kKTtAm=TN?|3_Pw%b*Ss8a1g~NIr2iyt^ zvB{HP=iV;83)b%k{kq8hvD*lJ|M`0$lT*-6SbjLbbXZ?rI}m%^L~YZb>#>}CsO>yx zlz)4S6sgEm5|W4{pF#d}rQ}p*MOB(<7T^2*JtJOcuLNpg6h?(6y0ElyT(>T-qd@UC zGAalSN`As7x18)(pJ~q3Y{XjXR&VB~cXJE^NP2CWEoJuqnY!h${B$G_Tc_oh;$yXN zS;o3kdzj-b?>uxOI<55^UV2L}QEim1_p@Oo2v{F74RwIZ) z;d=mjII~4dl|e~3EdwKqY(S^{VlwlW5xbbHSjAjBX7S8wF!nMH&imDiAi3+)p~eXq z{l18PWFU&qk`Miy00zn2{KX4{^O6~CwU^A*(v^;u-ruOQtVJK0iObF>rHxIwU2FVTeKJEDRC+CepZc!XW$aIlw9&W(f^ zo)-n!*1{|WWnOqLU?vkAsuhd@2jTew9E8GFC=?7Wa|JdYg}1@HeH0R_6{pW5*F2f` zJxPQLHsf501(oPZ#SFyGL%j3ywA2JP{q<K8GIO)?DBBggbWIkta60*Ti8WD6D~04TTX*C;O=B41Bn(u3P!QlWWmIW*=!Uu^&4 zcGkQmo7dxs%vFnqQ%Cv#ypc;2X`J3HZ1Vf%EP1HOUwUOiFTcENa=sUjjBo)x)cp!7 zv0H!|Y*J6w*g=H%9608Hg803^S9k&PUE&?{U^;WcFs`xbWFA3; z@6RD><<$CVbgpR^n>40DnFL$9JFnD0CgM)qTF>OA`H%E+`uJUfd?0N*AU)~q{x9Ed z#_wNuv~b!}I@J~nXbtjQ*cg!Ik5*xEf6ItJ>43Ciy{u!9m0I z?Tp&Lwq-Jy8pZhsY#L$j8@rFRs&J0NdzE_uUVtTrc^Lh-tJr@EZ6zxmLeFPz5yX2i zmcgBDWN(?^em=hEyNOXx~Ymbo7fUk$)JcRRUmK47RspHdB}JoAB} zfLTXyZRI<%zKSY+TEGJjim(rOPGU^j#7Yp|Mrv@W3^m7{=k|ovSp5dL`X|r9^yUGJ zantdamH&0U907fMueINLaYA};nqafx4448~e*;|W27qM}UPN!8m%e>^oBer%cS9xZ z4}_I32#uvGFguG-Bu6grrI6d-seK58-|zg$l6cMHr@&K;yZOL@WOKkVLCr0?P~=9a#1(`pz^0WiRcr1XQQ>A0t=+uB&dgE!M<`da?vr5 zS~>W{?!QFg^URh%d(_2t&Rn;&309u7HlTjTCA*(I?$hPL2~qhG@%{R!{g(u+2$NAG z|1p!#2p>`m7CgK8Ju1A++qE30vkd$gaS=1zY8a@uxd*n{MMX_3U5#HgqS)S5&mMn| zoQm=k3)-!J^s&n&z4qXn|D-k8a~!&lJ)eU*%6~X_rVoz@2dfsh7EnHUADIcd;=!Rx z&%_EC5;_#bdaa%jnEN|~NogTg#-fD2cmDGos|1b&kqNdew2%hV=Y_p@+Y)i;;4N9e z*N5Od@pB|zRemKy|6z$br(~kywh7MC5#C! zFK{V2%bfXr3C4y;Yoot}ZMgPssR)f1-+}Rtj<1JKJ3n|l;b4Xc3S$MIl}y&`u^gny zBWlUHZs^oU(SPhvR8T7)7NY?b1XaFoWlBMJnRS)an=A+W{SKQ*lU3}UL0u>yIcj(C z9nn1e{y((I^?|lPBMg3%5}5vWGKv5*u{HR^I7}7$QhWir66;W3hewRog#U;?ckaTq zJtmWm1P+=My@?OvIOzhhXMVXdBgx~`e4b$-#I+~yPf)WiRe>0k7tk(=i+qmNbUWbI zK*!KNsB?m;i1Jh%OEB$8rB0<2eRTQuBVQ)^)wLq{S5bSTJuBf0FkNYJ0Ubtpfq7>zTH9SOXBwo|T?`h#c&4!)Q~ldf@E2|Bv*ak8aHqE6ZXstpY{O_Or6i zB!7+!nd?08(eVU#+*>Ki>H7GJl0_Gx;|$h5-Y5GE(YIVco+H zB3SKem%fw115=$&Svbt+0#}UQQeV%H3j7~5GykN0_>gRlEz8Ifk?SIYA~ZBjV%}@gG^`A0sj%Y{XBC?|Aa>ugV-KEt z+z7`$HG*-hV)u+T^1K{s>Xi$J35AwQIPdjibNz<v zfAADAKBC%)97s7bHUbm~?%%g!hRdBNSXLPY3T5G2)a++sPsE~1v;R2Ymq`dT7$E^&CzrFybS`t+apcz@?%uW?LxLu*HhR`IcSU6giQ>FY zo%2l#6hBxRK)(Qf4)kbvMve6Tw{za@ANd^96A(GiwG{pken`!&qz^IGBGWkwPMv(x zY5o1rzX$Trm=}f(4ACr&?kb%i3!dGsNKW}3e> z(N1>GZ#CHost?9>LapX-?&%tui72pyqGS!0!reYR{ESv)5kB^{8-0->dHSY3%)%?p z-Bedbs&e`$%@eH9lGGoAy!EH#p>fKywjb>(0(pc!y4QhM z{H7frBOD2}z#t+KyL|*7*#^Z^#CLV>Rd9OV+IN8siex+UGN-;^<>)4?4TaxSYgY-8 z!)K)UScAzES5k&6rTeV339p-qb#s91D<%t{A7Rm%yw)kwijIW&KJf2647K5S_>k=A zqnBw&9ProQgmk31k)b8O46os~h^_E(T24Jv;dz4U;roc{(5mRs3%d$laSEvzh^cYn z;oI~@!U14EC`=3118Om3I=|KTe-jybP-8DhY1*1QFt%SVV~Lkdj(s@1neJ|BnIQDv1^!Mh&xJ7BH*fVOOd3 ze+CAW=qihDJafqGWStGgU}pM5Smd!Zx=7JYn4y-Rd8*>Uv~`m;Kcm#mr8T+2kA@4% zD4Zj%Otz6m-LUW{L?Wlh1GCkQ{JmMJ6n>4iWeVSj*KmU*`@5EO0nU06$A%J`8Ge4d zxo&QAg|*+>suiE1Lnd~d^zHeH&i7G|MXdE%smWpFdmYe3m{ZrAzz{>Db4T~tE&Uz5 zO#7>f!|*uH(h%#aCsD@*xo7Pv%gmPZeB~6^}I#cc*TLopCEX+P5n5SGj%u*M_dKhrUNU)$0$p^OFnnGKf5<-lb#n((p|y z+|4V(*5|ub>PJMCBN{^Xc5{QUGkIiyyx%$WB;{I_;#hMCiun4E59rLXr}dT=PZ?{ zV;%-kHR8;Aqn?LJ{Qi;IpARiJj#&psTkbyiE^A%`?pzE($`b1#@_pqwjyJJO>z9T; z^~7@w-$jxQh-&$7(U&^6ayC&q|!XqgZD}qdc^TMZeH7YjgoaeQ=sj!L2xgG8(wlVv3X@G}AyAyRP2lsS-l=m~mgL#GE2`Ub}#L9GclBW1efk_9;`igF5E$X_vm!3!mw>-o4*o z9v}z3?gN>wO_^j`&vdR;0h!pl{H*km$w$L)k!Ygn)LPE;kMaRFh-n{^?yVM9+gRc4w#wMx6)eVzJxMX^abI zBfE%>RnP=x7uTDO@BD2}$49Z!DDFriq?`nmNx>QZsRrWloZ`niZHUQTX$e3$!EKXa z5RR8Jv^}AFcd#wA5Dv&ROL^4?!v|%+TDfnC9stp{GF|_9#~p>crUzjjiH6HCaIN>+ zB6smh7YW@_M(p)UC>%n8@689FEP1Ffm*I`_-k=hwrrUgI?UwE>fX6(?79LuX5yJ(~ z7Vr^Lhv0(ML=8hnBp4~QA=t%5_2j?&2W8-I^p1;ZWFiIN|4xk$;BAm5u0pmd9nw8V zT7w}r<{MxubC25cU`9Mv=)=^t@7q1bvYqXF#W)nFxbBhU$nd`j{m-{v`_Zn>2z+~7 zD72Guj~@ed^vqSpLv)3nzTrYT;~YBjKIzgon;!Fsub&M5QV z8!Wq?+TQgOUHM7yK|BWYzGa#yX%~I4H8KHB;Vu0_K(v1v1R@^)s>oPPjPpAxg3afy z#|5sDa@PV{|6+>xDuxM97u72NvK+3c=kr=Yqd)?XLR&tqK!MT~!In&LO-zwsu;Zaj z*Y6(xILN58w{+o`Y^Q~~)yW|&LQ1J?lTU|P(?#GpwkQ_Dbg%i{A8uS+3TN2AP6+Hr zl}4&Enm^tDZFX(_D3`i5+K`^PrJN$dfdV~I&$Y3hPlhQ&ojB;?h|m$2#V{#Jn>h%a zG-r&?tMw;Y&e`OW>S-wY*ea85Qy0ATQ8~5wn+OF;cX_9ocKM#V2oYa%b})Kflu}*mrwCt{*V8$ zn>vS!RL1#Dr}L~FkQpaPrh|9a9I2EdC=Iu#5@WJq2wX+qQ``aU{N2Xaz^p9_eVw&M5!$MtrAvnB+OHKuV?tp<(>J2x+-Q ztg`qn9lRso%NM^_Rm0jJ2BolCJdH?;(t&VKuS`fAHme)&S~BzrBEW{_4H(eDV{50% zJoY!tGx#X5(HA7L!}|ItQbev`K-*PWq(L;{sBD zlk^k%Vk$@r!Xz26tJ|L}p=m}FEQRlkreLFQ7NX|7hYwLZnye|n3Y%Wp#@B9Xr~70N zwZ|Qpw$H(V7EI=`4QF*!3k6pn0$nv)el5@Eg(?tU{o(8Vs-$A6Rce31%*iN!-eFko z^ZHeYn+D-)oy)W*Bw;p2)u6byJXFYD>WLszTR5uO}CrN`7Rq zSMIhhz4A=rptvQyQ*$+Nx3<u09ITrv3}b2aYR<-^L?xflhf4Im%I6lG~vISX|a zO4JhCq$!b1!+Ii;4^dC#RX$gpFT=`06H+)UHDtVQ8}>^9pEf@UoeN%ff!}VoZ|)=A z)_mGzuFQqFi}mXOTMhkBkYPE6SefIbZ}kWlrg2Mw+ixPt;+(BsvgR6ddb;OD?m~Z) zy?7{r;!H;9yR~-j_%+J&kKzlAK+e!G@3+tG z&q}Ag>ni0VTZ|l2p*dcy3m*e{Fg7sVEVOW)clcD-ZOw(YC=+9!pOx9TQ9(xUq(%A4 z8QxyZuoO+dE_?$sV>0_b%DbYpeP2;f-i*$jdq!{~ft>3h4{BZlG|NOpcvfVbV@21#(i{*tJ*qF&es{Zt8_xVzH09vE$k923bSrdQ{ z-Q?8^g6FxY_7XUs&{oPnhEV>_Ma{@0^LSo=9($Z1VP*DI#=xWo%C786(F|h9J=6V7 z9;9s-8~o){{d|;p0ZJ6P3x2D$(Dl>F0`nFaSxlA49104BCYafCu4{ajEA=~)b_%M1i{TLM)zgIKtJDhOdAi6UtDqoF zQOE*~XwraJ0^!kdy|am_2A-aes;^MlT0@)qq+c2Bl8jFPSYZZ*k{iV<=+h2GZOf`? z!o|mgssY>mY?yLtpks`pf;VDl+-vB&q+4+I-`aO;;a8rv58kpikKVwxwqH`Td#jC# zYh?7w-epW7+hKnDWwu6STy^aouO+10UY~f`W%2Z)2b&|OhbKtVcE5>Pl-CM`b%dW# z*k->&H*jC>cb?X`RD`;SP=--bFg``C3NCR9aj^}Pgz3^cE3Snn^eOmok$cfPwO=I= z#_hBMUn^3<+#SmUreG?&^fuS&0-cN9(3YzqGg^CAVG2j@EPbA+g@npSMiJ?6FQPXI z0^i|hUCruFn@>j$Mce}iR=z$av+Q90;0^#GElLnuCayYxA;6>o| z+ITn&l=Iyi7nv_VYu7i}%cquEiz_;D+i2U~4F>bdLN)YM8S$%VjTH(X4evpJEBL>c z63*Dm?j-$6PDxH%KqInB_i%q{4p+dG(WQ`|f1i9@J2v#jur1-zkMCcUtBFEdNG*SB z$LdGxQd;KX1?f4Y)Bw#l(DK`_9jQ2K0Ye%?rm=mLY4`>;uPvmkgeceeEzL(V{?aTN z8(&(!paCx^boKf70WPj9y==v1(w04#jc5?3leqFQVGv1%M{lil|G9^v4)~ck;&(w} zu(8!NVw!9BdcY?Jo-pH|CPcsN3~9R!pu~i}=ja;2Ovm8$-$54bK8nY>ysnRGqTRdW zRXe+h2~}6zovt#tE-u!p}w=R3~+ z6$J1zcWZHJ56aTC_7BAYe%8Z}-@&mIF;`y(W@>2dl!{W+{0CSc$NoBWKNKm&$0-+=RRi~#vg#2 zXyXa8g&jFLF=*sVoojwph;|n|IMZ-=kccVWYp}|@l!Zo&2-0khJC%O(;}2YId^Qs` z(EC1}Kz>r-*V48fw6@*IbD5yzcf{OkKP$75w!>@i6ZE!1izI?^=Nn4ev~RAg%p!2ZhHe| z#}cRjo<}>}$*JxuUVG!iWT1~UmP%8B-IX^h@7(68DlBI`-O{bb8WxEq?jx`tk+KZF z%j6JKV|xgHs6OcyP@1$)O~kJW7lbcr@aUeBA2FdCJ0G}bU zlQ7QzdV{eUvy5%y6?M@YOViU%>Yk$(*j;}|Hr}JL3=FKjheUOtV{g+aB()zq z;sb2SZIP)jwbM;9EAwU-whWd!WMK%vEhOmGpCwP|(22))OJyfjV}puc z-~RK`THvTD_@3?vTf55iSZ9J^mkeXwG|#mCagx$Q%Q3R;p%~)+W#gAD(-m$7$1$o@ zgE>N}QXU3YrXmuSoWZr?{(KA6%s)KbOLi-*3+;@QXCb{!LBQV6=Q4&YwCt?SvvE9H z;qs;7xW)By9+=!#NeBx|6PHt+k{bf7XQu44h4A5fo9c~NqJ>KeNF$OVnzi) zbf!BrSH|9~q-6BE6Zl@!Uy>X&KL`8n`hP;+;R;2wbI@cHHC4iwv6D5qU633M+HUTrtffneTq9~a;8j^p3I~rCwWo#N~n^q zb?Ai9%apJrz%OaBD`N1N&o8ry_PMN=MWnmwl^xG{Ev=5C8g4_+3$?hn*&vSfkYpc$ z6(aJV=3NW+XqX0@V4RdT)+o!^z|N6$bo@}zEXre;r)C*Uv&o=~>=$dYZHFnD`1$984{sU=yO=o46GaJa^T1$Y%WSKOn z5yW{@jac}~KT>`aNEz7bD&~aba@}=u6o~OA-{pJKwL0^CD~d);C@RmIT>x0v>Od=# z2Ii>;$t>a57R-m}7mhEyvK}d}Xw8WW*8&`Rg=V}6PG3!0I*q@tk6n&Um5VXcZ0_S! zuYJH^NwugIHKqSX&nj8<;ZT-!J7+nBkkM%~iJjoZvBA$&JLxk%ol9%`#n;jI@~$cq zL+T_WrC%rZ-LFzCTVqL1LfDqbE(umH3p{085C+y`bB%{t%tkbP=?0+;Rcg+h_%*Hyw1#(7O6u z{w6tkz2C?mEYm-6Shq~0%T|q6ipAuUytbaP9{2D0BkuYoSaar_CE>OCV*}PbK#HxU z;E0oHQ8;DSL!7fhi>77S-1ESD0gG?dJiB<87GcqP8zSQdotL8V{1v;}2o2muoetdF zi9}KyT!P)ex{I1vLe{lfpYiqQ|4`4kHBGT*&UVY((X&~uQ3b<|)Ac}$cU2Ue0Yj6P zEk8OJPPc?XVw3DNgL{!<0fGq8k^{VzLkNA%$K!XBDX$zB)8_trgIsXV=F-m2{hBn4%YNt>z} z_ZsCxcnFlZhP|?L!eXHKr8b{8qTjA3wO;$k?_W}Q1;Qv}zKMq7XZ-~2_PZCH4(#L~B#@B;{LX!2iW?o~I<$W}*0MUj<0@Ucrv^iMeXTDn5+QsnbdJAQr6w ziQs2rwk!mhM0OoPeC=X{&N5Lg% zVNtUn^Q%_+mhFk0>MAQ0Oz=)MwznY{xd=Hi$XPT^LPuelQ3{w30W{!Qx>MzO%%PldU5K0n((__xZ zz3){9#en0pD0VgBopcQW>og)0+fL5rgrY8@_~iVj=|~jB#npQc%mVH>PHl zs$G@}R6qv+MfX^htw6!=54x}8jMVn)8qxA2^Z)G;O{ImvJ^p|N1;nIp~_=?^{9v^!V#jO;U6m-i`%!fmq&01!& z#p*nTj<=;wvtI%lCf19t=TV5wf*i@Djn!8g(Fz7P_Ng{!4SbHKs8Le1G8?gVH>ou1 z*Z0+AsZ`e6Pxd!MdEmx{1f2G}Hx~cfO8+|OfDm0j+i&7y?xQrFleuxgv2=Kf0O2?= zc|JQz;WU)H&@FKZO#Jle{Q};Yugd^?9SZlrYLF)MC+9pQ2z^;0e9Xga||#3+peK+)XS{U_%IbEZD=>$ zD=C<(sLy#6tb_hq+7h0Q`gOW(3ijJltE!l4aOsaYV?k@%y8wYQF{nY2p-6+EXe_0g zu}hX(gB;AWB^OpZtz)Cr0_bi@qC|936lr!sbS6_&KqE)k5mttGx3i+4eK`KxX9L03 z^+baa9i) zoZD1ZE1@O6SThE+TIo$PQHv`$9TQlRN;N)ZRq4cf5N!S?pFc5pv^6!s&(d4ylNF!Z zhQ!@`^_-}H$1Rbh|NiWL#9e55)b<-*H1XtnG|8jD){EYinY-2NoLHPDkGso-jswc~ zsU2s#pVc6GCTg1rd4KerG=Cc2(aQDQ{ikien`No{q!YO^WnF8|izvle_hA5BDL1P1 z)i+G&kuT2?JKynH>s#yld4AvL zzV<#>?0p@jL0M(tI+^1I6FHOwn6-Gi~ zz7dTsif2`6l9mY4A;P|jtgKb!+!E9@O|{sbMr@U*M^%Jg3M zmts#Ao9Iac&yQ~9EMhA_HpJ_!Y)d}=hH3%A6jxv9O<=|>wECV9oFQD~E`(y}r0D}q zCLXzzoeajLf(CKKyLWbmKE*m_%Q*Ak3sf^p=-qy3i0UOy*R3QCRjmt~2umd_R{l$r zMeAj^bTj5aM}C=X-ntJv(q#Y|RKpR76W1W5sK5?r^fK1SK?n*0c=M@Z+O4+b3MZXu3yYS~9;Op^F$gm>-zl^H) z2rkkF1z`S?U#Ma4)1$i%)89EsM&run9GaoVBun53OU>kk`=9zBu|0GTBt5jUF-Put zq$&m8?~qP6^fJ&rC9jTgqOkY(Q|E139GK3Z04jRM=0@osv0FANXmz&-46V#sfX6>lm*|I<2_n3Z8#PRhhxkBc ze9jsC^*}5_#qL6f+7v18^>a)m(||1nz2~a?#EqdWY&ym#ijN$3&ret1H%rAf{OO$V ziK7An0bIY zn-ZNO!#5s2jVy!Y0hiwRxxEvpH;#F70_9_wxi1S~#2m6f?qwnPd@CSdB2znS}r#Nb%eXcm++?61k?C2>A zCrv-$L+j}IODwJT<{(%(VeLFlf>{D6R2*MLd>a?@b~U+LUk` zDSO#Iun|C_LkfEP^jM#CNIr0opm9pYlrd%Ex1O0^8=teabB6nAgcn(YQ8RDmheF?Gsz=-E@f680KZdCA-y7g6vKy}tarlGET6S!U4=sQF!%$ys*@e7MkHJYX z*$}Pryx_a}aDa`x(pV}Mc|Tx5y}C#-K3_t~MzFZm?yzB?n{@)ffprCF$ zUwkrA^^1ry%;=c38FvgTUJpEntam4p^}W&2Pz_09ELrLo7K@W-AJU3-yZxs(zxYap z?4}WiB{sHN@RVYa5EeD$8JBmrJ|#cu78EB?4qYIAk)lZv0Au6^rY=+U6vV| zUb$6fH{4WLFFT|g<~ORb$d+DxeOUGFW=o*B@K};v8Xd|FI~^0!1MnYv75ZzgNcpwN z1^|rUdG@fzEuN)lD+PvEJ1#ly>YPbZe&#mOZWZYI2mn`%CQkMgS9w@V%GwFDe4J=n z7mx1YpsZd2SXXi3^Z8co7j$*@!9Thb$zTUDH(k3i>}c2^*BMp9U1y^ z2y}6V7P7p322U!#6%x~b>DPdRq_z3to-4jG5F=u=ndJIW$a~d?8=$q$RJxF$`B=v_ zvo#<2n=*vry@Y^PR&EBwfS?`#$^@Te&q8LAXH?glls012eFiZHc~Vc+@jbi%j#PQ; zu6F-1LqlIE0x3iseY{s{pZBcTwEVr~#6*jBo#f}eXNJ(p<Y6YXqYoMzqrQMVWV9K$w+RH(MRjP^I2V=;%YjzO|?i%+*D-%Mw`!u%P44$ zmTKV1tZYE#Gb-M-AE~+5U%B5^LlZ*P^yK`INw@kx!vARMrp(>g_-|ZSwc@xxe$`Yy zba=p=yR~U4<7;(@S?sOJu~0BESL$AX3)mTBAELPXI7jvI0T{#w64#1m$_r2z?tR)9E(O^E zaTTRCJWlG=Saa=An={rv@?{qv7%d`#l?LHsaFCzhYj(I!3LWq}gtlA`i|H>t)r*Gj zC}T#IiRLH0Z5qJPTAuNXtTgBUJ2LCSYmge4+E%K{Y`0108&lBcuM}LIk$4>;-z7f| zyFpf{+7ocPcKc-1=}}6g=*a-|6S>)DqdNO}9NQihDD+Kl>|Y^Z3Ry*4+X;kEAwO>Q zJ-B{)bi7V)x8WT2Sm92YUh9M8rFP`)eMhgV5O?9q&Z+PJjH7WG?O#g$MCY}ipHCdj z%#+SvbXE1;oIwG-nS|j+WQZ6K)c{4CbFEgIC=M-gRJP$AT{yEoVdLbXQBHJ@pX~4* zFL=~k;e^b|t2V$p$8m2pLi>|mvAKQq!!O3sBbw-tXcmhKUZ@VMzgA<(?Gx)175W*0HrS@CGTdyw`?Ss%RWF*bK)5(5b2bi8hughuidh-3gVqLlS1PCol_Il!)L;{1IukCXFL4D zkw37ZL(>N=CbB>P26t!%ceTCI@;1Ry&-*a(8Xj?i14_PArbe@#AzxR;0SCnHPJ!0- zX(7jhrYVobIOt}qoEU3SM*aO=D?Eajjg9)^ub6i08oB@Yj*(Q{uL(%F(T!jX)6C=H zmd?0tx-iB<{kOl{FD26O=sao)l7#;z9&vewD;;@emsY_n)`OL;BKDpg-|TEC5i)=r zQwyF{KKJnNv}+n6mu1`8zn+MB8@(X%h}zi_I!`+tp&0Fa(GJ}E#|bLsI&~oqEIWZ( z0oCrydmhVWykZLm&5oIGUi)wk9_bnCem+sGPJM-$%9x$_3i3fQNyA@PfzV3Fzr*UG zYBQqk1QRgws{g%3Ia1{d{ZIzi6$2g0A04)4gnghr@wJ#T- zbBha!BwX*8M%E^I6yo2{)>pV-9R2E=5ma7-UVrNO6RR&2pFfWO;OC~@Jf@jJ_N-}1 zPS(Y`OlL_&Yw^hU^%xg1w zEZj&^R;p*Oa484A=q0)TkRhMb@%@u3`3_zG0(srYok?!r9N4QtBg5%Q=jm_m{ODJI zx&88?!Thldj`-y*W)3^f0=15{TaVHLfO*8^_NA>_VZqAG%t0 z;EjZh%g@ec0N+=wF_;$rAh4!oa!7oZO6U^_xSD|Rat1pU*qaZZpg&8e)OjiY@*KgR zYnHf5N5o;Z`Y#gL(z27g8|HAV|FY2LJawpu*_kMw!H)FCWY@0P*u=v&dctDtR>9k` z_`(JOjYk%v9A7Iu*_GeLeKPE6z!eZjCiV!*;MXbJ{X^Henfe1dza!ObtzlF&os{Le zgV%&w=4v!}q#MUmtAjENY)*`$#?-(*)YW-^6_?JK@+MMb{j8B5)Ku;EnL+4DIekxv zLU}E&;&njNLe>)dEfO2!d#7T9dOiba6?AjhW9Qz1y2TxDaYHmWTRMpN!=8Kyiix^q z7(0gxji%tybrp$6=k7FkLrb}XbB}{EayK zOE~l6F6}hO#E){pFRxW=&3!u%ht8=7>@{&L)5!9lN^Aj$=0~W+uSHJw0#4D*uA^Q# zC{IH_jhn*2%C;u)8>Mml-NOJls*;XLf%%i9nKSp~Lqar8{$aaIpnx}^QT~)mxkfQKqS3+&?=WgyoMqnq14aLm8%~WKXIyz_iIZ$S+>m; zIALQc#&gs2;s63Ob!X-z9~0=Ejs-MLRWR{zm_`#zjnC*QyQD@0+M`FDfKJ653%=xJ zwol~p5iEt`g_@;Hl0|;2(C9Hf*T9VpDI~En{7Nqb!EVPJfSHb|!V}ctkWYPL>X!J+ zHM=PJX|!3`KyTZDSreTwlST zIYo+-+w);5Esl8bf-V+3x#z@=7ApHDlZI0h6XZEv=zcbh>F$RDSa0Yu6Q|a`qQE>G zJv)nG+VzGk*P7CGcz=j%jes4^r&oy3nYfV8yecCQu&?%+34?3gF0I*(Pxp~uCg4y( zF4iG?@MeU8#2=2351|%u8;7ExpH&gNHYlFI3MWqtJHMtzv8g_uQ;&KI(0eyD-JJP@28go zn!P!XTR8+Y&tMxm%?Nj$@DHmd%l@q$u~csU9S!nMHp9{d&D3A1B|3sN!z0ghS+x%x zY&Rl*AHPkX5HNihlo8nLznWLWgQM@9)Wi6L-XWb=$B5G`OAs{9Z}787A6VE!8v108 zQ{9-a#Nc%nuP$-lPq7AVGWfkz@`P6nGK!(w%sC1Jixuk@SIu&=@C*<$GB528=ns*s z1Y&s)#m#%ze5vAeEH91zB>%2j#QfFI%-6X(-DrM&MxKK1m6(y{scsI* zSFezmn@zz(AKbBjf1#~?A0WRmh~Og{@tfb_4(l;A9tBp;)Jox5tqye5{_e_i@@uJ; zoG#W=(=bP0Y$R0fF8t93@C>RU@xXsyu>Sey>$~>VP6=L2A4jUJ1%Unh<=%}x#CY$^ zaE~FUWO8&7ft8459^z^}~VC=RVf>Jwto;b{z5Xh)NAcS&>-76~# zkzhM`XL zpG;sMv@U8OKoFj=M}1|{HsC~6h#&(c{$mD7e$a*>4sy5vuk}*|Gn%}EXkCUNzSjt| zM9Qn~Ya{xL%wIEMB#$TKl6iWXqrw7wE!O7;!*}m^&p*(~Q4q2br+5xYRpJKT<0CV@ z&COK|{D~snY_Nae4NyX>DdR_ROVv~yGrEKdzm4_mA!i1fjkAHS46jOOfK1PICPrOW z%y?oE<>Ei{5dCtan(&|KZlDjcAa8wA+R5COqrt;b|CPYa3(c=e&t;L>oU#^7ao;gU zb7#Av$|i%#?^rzQGEKj=Rk~@K#8n#liU zvx8J1^k9ii- zp~Pgkt^v_rjC~L_A#Z>P)XK6|jVe$jF_iCKAI2xUA@|8&=EFIpC8g&wFDH@ za?*QmBJ2D_r)`Wek?`h|6Z1yRuOb(p2YB46>PY+2^t@yBZS2;jm)k7Ud5FEBDY>%Y z8ZK|(-z2u1PKM#XE%YRUsVe7iX7X@$ZjZ4`s47JtZV5LzZEMQLk`-1(#G8=_nIr`q-i+68zL8^(XIgw zHvH)BQO??e7;sX9_ecgnzJ4(s2k$ zTdwu2C80h_b5j@beaAlMfV?I1AE5&a7>LB=`Z*}+0J-_=Bumg1}1Q#m>y zzyXVmTz%X0mKT)g;0m zv>+)l z3b8&qO>lfE_a(FX+oTkxOy$4w@~EQ1TB_GxEhE2>w? zd~ozo`t|fguFeVpKnm6_^Y&~=e4mq0E+sQ`Yo?{za1^RuyvhEgRp;8f7+E z(Diy+nBKN7R^g%G056gLpYYYH8K}vNPtiRNXdJlRQIkY-eSy(c>q=KFt`A(PK7)1A2 z<)^Z*S60@QmTTSNFL~OJyPNJG3@EU7jD=CuE{o1#O(E8?PB&oY&O0@M2_z8CF;X0& zwb!}xC%-qvnz_APIly23D2?lB7pjvdR@qWzxSkat)CdH&%a_T{XMSC5pe_UiPP~6V z<0b5@Jig~7mvS|%H|61Ka4!T>$zt}n9Nb#`b1XKs4)Ir&qe}5rW&3ywYkSTuR{837 zD#BxPG9Svmt0ma+OvCc^S)Zo4n?B@|9JkO%6Oi?#7k6pPi1+Hm^Q=UUiMk{>(et&B zVYZU|Z>;7__hsG-fPH4tcZCNQlGZ4D#{qh^XANgs%$0g24>jp#DLn5P}#1vlMualT6>6 z8Tqz}VbcKHEwS>e%BVzrfkRx{w_I9)t=bH`=wZ@x|0eF^(K5@2X2;t2Ng8Ao!eI+* zD>ls76zvY}a%FxO8*-&L4vv4TF&LX}H1U>cR_GMqA7HQ3O4Jz?65=-k2I{N6YjUa@ zTErFfCHfhY7{XZ(O~mviLkv*WuYTeYdefzQO z9_Fv_fRp;jI==h;eNS?R+eYxD|3#-jZF4FNuY!LfUtQ0+!s=b9fm*`^x%peE5xS z9>BDU*xA#G7s`{e)A1*CPCn_W0A-yc1B>{{2g&y3$9oW5pLOwx3ViX&E&b=G)z?K- z9v+vBoU*0fTj;e8v3jCzCA=)j!=+}@C(-Qy*ynGXeC+zLB5+f)8TeRFr7!jP{2_Er zazB`**0plIi)B46gV(x>Z>N1Vlqy|@;n>moItqZ0mcfgB;3cOfi~l-(`%lr1(NvxR z7vI|MVe1g@u)fWSMO+WARfOEPaSu|g*&aw-g47l$M_2_C+b16UK>J)mys~QAOK6;# z@^CFO(8E;V*TFdUdV3Vv;LVlATVk2s7}E9)Z5oID!Ol;sYcDsim%d_}s5Y(nh&BKy zkXr|$(d*3NAtB3Gh4YjeyrSyT|xK#K8+kFs9mlQ&dtb&&L@GCz7V+J z>UNjSK%cg@lPq829keCUhHm|*=5D6mX^2|Z)N(kMeXAv^6Y9ZXV@f%L`UAn@Om?U8 zy}aX};kmt=A=(b{);n9XLa#c$fnE8;aRc}CE(z)u6I4?=sWMbn5jwfkj>14O8-aJh zrr$^0;OAD*vicjw(<`RhRU>heez`Q_+bXMheXG^X<3c*G=I!nlLWE1FAs>QpdC}?6 zdb!{iZYZ(6ZR7}4Uz>s|uRt*w)U^OMq909M*65SXl|ZgeO5-TL;%8T$w+sRIJ#1jY z9ka*jZ{t$6p1|hV-7e3(8EZR|uNO)fB4n^%=sy)z*K*z(7GCvAN=wr-i=tb{M=Io+ z;lxG~u-1qu*MNRJYM1pmrPU0fr$abhg|+0C&kmp#>F3rP7^t{nauk9HgQEzYgNG4Z zRMcyGvD|eQAzinZ{@2CxNI1PhP(1gAsD`&HVsb_s<;SfV4+zQ+dYRWhObp@ac><|K zP_Ufm319q*x1T0JE5Qu2S(<^`8yT9T6+BHET^1*aJqUTx&L%jjoJPOu^STYiP3p_U z<~F#rO{)8PYFddm)xz}7Mq5@IT#X^#lFcY!6k@M-maOtX(iV6 zE=AH{+TESkcUN=rRAm0E!vszJUnea89+cw8gxP}BO?s3K2xs4TSG7f4W7sh-Fl7-| za5U6L)pj{NjbQ^iPG5)-fV1Ao=HcTNB;K2iaQ?o;jWc7 zOAdoZw8>5-52aoW$&+a9TD(9h;Sf z#g+*LHO;V;eGz7;$4UiUjw~seK#0L5a67LQ(%kGV7iFZML&@jQYy5NsZ#&@;K6Q#m zbnaUJ**eI;w5hqMtvx>PK_rw-{;8O#{QR(q?!Y3`|9P&n^H zIVZW0Ppc^j?^_w+{;b{LNRWNeC!87~70zm5HLB5R-ObNBrzFhj{T4m-kas!6OzhDaS|c8p##Ma^qSr38o27NN{!;jKlareS zw_#-CQe*U_#Rm(oop0qS%@FbOrxPZ8>5!w)Q@?a<9lxo(uU%dXbBRDXQt{cLRL4i2 z2eg`M@Ap<(Z~K6}+{A>qR=n-YY?n$>8m4gK>SCc5*N0*FRd$cR>N4{wP{UF=p?|3d ztU8`bgIBa#2Ba6|;N6hTC!dqMgoX9UW;Z}?St_QUYG@TutKwcg|Z%0`fLFAO6toRdE1d;ROKdg8B5*-swb(6Ul zs3m&8y%%wDd!&cosQ6pa{oD-Vi~FAY^esiihZ(`fX|JcWb+G+KDiygDvg&D&M8$p# ztdW=rW8g{O?B*_Z17hwD(9xtPBmZ)MDCq9yc8*FwkG5G z_uALdv?qC`PQjQ4Cjf2MePWbRPlA<`1+Up6VD`$Ht<*8Hn++bFZRVkXUSjsr)+eU& zb*V-0Ap3?=%BC^e@l%!lji+qN#!CZwUC37%tIbkgUF%Jr{Cy4La9w_1DbqTh&Qh_x zj3xQDKqq9S?#BkH7Z23yNA5THWOKkE4~=XO4v=7GoZ_lD?of1?`c+|YXB9ODC^>@DGe^o5ZU$T-Y2EH{%~hNIPevlIbb1H zNQcWo5PBOEiO*p^7r4L3&o|SjcLQJKhp~%#&j1rWg0z|fd9KI`mb_@4n$J^VT4M8l z`FEe?7BH8ul&sSH-+&Qaz%`;1Y-y8OISD}2h)UG6e@xIdcWlO!>!-K|fXiIe#Kvz= z0rK%+^2l>vtT6Gy6qZ9d4gS4RZHX@<-NJZ7xznr1iH$gq>i&o2`cJ)}XW;^m-3SiK z7FTq?TC?w+v6?_)LuJYK3*E67W>pbzUEzs{xjq#JdaIL~!2H6TD)e1lgP(`}VWe-? zzu#1=k8xkn)x{EwJkgkCto6+NiCDY^ChhBej0L3kNq5J*(*uvvFrrDK3dSSIOsBt0 zsuTCzyYmadNwPk>O+42(XnIIKOGBOyi-RE0AH2mRs$&t#hji#JfkgB@S%wlIQ?4xe zo?peyQhr5;VJ6F0b78A5s=UlOiAkvmwoP)Up3nq*zlv-o|IHJ5y%Y36MCa_yt=G4Z zfqUDUqYwm82Gd5HZu>rkync-&#yy*cT)D^Mo5s*A0ps>o=QgIkr6}c(@Qtezz3^k` z{9_SuT(sy?Li5p(!Eqkwle4bYlTiqE71lq}7t=o4sh=%Nyq-KY_7Z3MLwuya{l(P% zd8zyCZv-OdxevP08OXgS9_S=a+|)RwwkI^cFx%93bWRqVar zlp5rGuD+tKU5Tv;>uG9#$mz*#g~mMRO2GlXt|p8ws{p0=FbB~!X8smqZaN$c#lPb} z_mma2SKK(1JfGz9=IKfE7LZ@PQaim3fGGtbz5`C-_^0s-VB_l!rOZvi#_+;dr&z7) zOJ_m_Qy%a*E|0to86Ul*Pn!IA^0@egQNoGM*e47Eqm3)`7SS(1b1cZjYL66`ES6(k z17BP0WwwRm^t|sIv3)zv_`H41^M}WI zhr`|9H_yURrE5o%RF4v_*^b$+<(7^N*{+ZGd;&rKHn%cuTZOD(!!K(E3DdNcxam+9 z`32Va_OLS8U>MwNZvLpLXxCQzj;RIEKTksD8Zl{~Ff5FB+ zNAD=Nbcfo!?dlTiP$Gy@8Ec z*ZVb?*Kko4Kq8VM&V}gdWDgv2 z^P_#F52yI zX7l!7mn1pmGJQkdw+C-fvyAM|wdtDoX19BPpPq_?CaqTE*yfZ8OK9ik7WrzwAGaGY zDhIGdzfy(^CVA_hg;Vmi;GM~j%o{MiY*wpCO49N+U6rqMKA|?2TPRENVQaByJfE&- zUB2pjj*F|qqy{+R=BF9(A)@hX(=v3ot!duUk5c#b-OquwbQ-8%k#|oW((g4I2f)V_weaRxvQ)svBRXx6cs}kf8T9 zLX9J@g$=q-mH-?k=_1Mta+e)F0$a5`W!Mm-Cy{0Yo7KU}-rG?K+tdA(rx%>>39QaQ zv4T(>|9?tt*-Yfqcw!dzyTFOh!N-kL)av$B^337%;^pZSln_tq!qt#mxrqRll(4rp zHym1WL1@4ww={PHrqIM)-3V}E{`9k%oq=pu=JZIA7?tbu;@wui=@mHjl+|fyvB6(nD@tX(n%Yj*;NyOb zQgLg%GF=v)8{O_`T8SLC062k*hjwisCDyuVg&Bfug%lzfPphy(Y?|Evt5yk*o`Q_FoNP( zdR43nCVaE(rHe9?RKy8AXqhL z`xTBs$GKC!{jC}bbV$?QzY>-Q_70** zfeZa%ve6(EQp()Kif4wq;Ndkh9no99hd-O($F1cdS5`T;nbF@r&?bDPXyPK)8Iv)Z zY?#R^vpKEBzaRgU7Em=e{zm6PL_F52OSSN7H!1TFub#%^xf9GW5u)Fx!np-rfiJbf z#K$c4C}qyS_PE@a^QW;92%o(z>Z3OvAc#F3{_vWdia4u> z=t}9p8M3IW*U6)iuHnzYOUeN1bGUFKFmTdmqPkgkIT)!yYc038gA2%nh8R)? z=IgWh;)qG&FWUl%k?7ci)FXt#w@6OC;V_ z-!eQG7}Y&gj@%->f0}yt`(qf>-_PYb{K~J%I>ap$!j~Yz5*7PRi|7xX zF?oj$P34X(lC;QrLbCOHPSe^d`%zSf(5QsPM1@6sr`fSWT}xq?j-u#Q`NsLbsV>{RY;M<70LvX z#aO~+ZLPd~Tr`PJnGFVAF8bJKq?5uH05i*OO|a^NLQ7u_$@7G5!7^U3n*6WL)f@ZyYwpJQSsW{3!V{aHgND%-+jRfATxQ^R>~gbve53 ze7xl~iN-`l5pC71?VP@g{`WDnlGxV_FSW!I^G0gzcb>81YKr`OkJ9k@=n&Z-uY7SG zkEJ-MLF=7kqwnVCCM~tE$n-xMy!7y&3|=eY^2+_9T`Ysj^BQ#Lr3?MwG|{mx#^csc zI(h|eDN)7Hr{gTb@kdr%dcs^LV0OP?!weYNH+;uFQ~kw}<#9!Kf!mkpAowLNL3H47#~1&=UVkhG%E6Eo)EM@*@S zBH-&!-B>AV=FzBRtshoN`Q#epd_=31kPG4+()d?patLB~2De*U*06n62si_)6LbI< zTtP=YatdW5UScv5`@$j-^ClV&dS&-1CfN!^EdfByIe0rZ-JIDXXE2BDGjtkfDWXa(mwY=C&D(_+5dAxeI!Z&Au4 z3$I=(g)g}=5jS80OT)&v%>@7(NtMtGzr;}Lr}qPPVkc65S%7utPkB_fk8+p+cx zPU?T@{aVhp>T9h{4MmE0%?F1Y8tL&71V%a)4h&&j~ca z-8b{i+RWZufql!kF>zv~O{gX6tg=;05@9b$Gn^DZBkG$pOg8#S4J1vX;OCi3B=3-u z@r!Q0N>%`T9zrb^D|X@gEiq%cO!`~G3NhT3v(hhKjh`FcXwTo#%Pm01(0k%+J~UwT zY=z}INyb(yj+f46{FVO)z4?Q_Y~D&_na|f>(Yw)%T#eUj^iHgc=MTX#aJIzz@AM%! zI9aI;<3>4+A3p)CZ1h5 zo2Y2jQF(+Z>xaDkW`K`Ko6pOf#_3u=?QBcnSW22s9#%#iwnzl^SF!+I%odf0bR($m zF6i#F(!SwbgP%<>rDWi?{h*dq<@-tueH*Kdt_A<&fpO5vS7qKfDVJ`!Zl+&4b*txY ziCp37(IhN8iG#JJV0Hd6QeJw@qxk52qQl%=`~1g1?vi=qk`b$7{?@o2UL=Wnliu)N z_o}=RugxUW-OtCS-+A@4KwJfaoJudM4-yv+()Obsf)!V!y$U9H-)eFBy@{|Y+6Bz1 zW&C_OGA1#QL&SJ(26v>~rn0=F$PPP-9%RIV$7GNR9q=p!njnN%*lgbx!eTg`0lj2R z7Y&#$EZZ1j)MRkj8NhuGHHEj560X@%*8QMiH|~;ROEHE}=+8B6#8|p7d~@kRxR*}C z!TSUEO`yF)$bbSHbGiSG-h~Jsor7(}m3>@;++Fr7>OGH_(0lrfr5`?Ba5^IhYHiP> z`sz14%g{X^1D-LU%rO6BNust25j|<?ADn;qy69e%WYuV$!(v zgKM+?|gccl(et4M0fm8m%aMO z#w|W^2+|09ulP+PvpvI9ra+{z(9>x-Dm~NjDWveQNdhNZl|P~uoI}hCBvQfzcofu` z-`tSwoQ4{b`TA`rh=xCla}P8OuNime2VsBpXqr9y`%|YSj$cfER|99DinBy;;5AkS z(psBqkp{aku_Q_qK>3w9Dv-$EsPj;mhc&RZ*ka0xQ5s}_*yGJt;(25~M)GZJr@eB< z)i(The&?Fs<;!vl@{q~8Y?D|n-9Q(E5ZeOaJIFp#nrzvbtOm11&Y^U`rVJ<_g-l*Z zx?W`(!1*ww##iL9LvD^ydN7jkIEbU^8D*LOGGlyT+1##qLi5qu-<%X5Nr5u?{1@`X zzH_2M4EriW*uXXcmp<ussU(Q(5T5O845scJ227S2pmHZHjSazzZPRi0cpY1FDZx%q? zeF4DXZi3rmOT{5YqxkIAJ=Saxi#}S|RD~*v_OBOBMC`UoP0R?MJN?3Qle++}t4E@R%rl@M<$^`c=eC!wBv*>y2;}W8LX|j3A zp6}U;X89OqwfsYmrKzw_10JuD@{y6y!y*CB5sAMVCK<}hWN%Gw&TU7;XWvQJtUfo8 z+4Thp^iwoyQ+BOCtNeWjx&?4QraB9U^`T=z+ne7YblXG<^)2b+8Ll7v41M|PQXPpw z0AJv_FqTRtFJOC-kFbLYJunGC3s$GcHj7p1a^r`#Gf|f1(ai*8bm39)5tiw|t<`VL zlfJke>l;9S-RCV)?QR?nc_f9hEf`SkUN7@DJE+OhXn~dbBb{IO6_Hb|FgP?Mej{+$ zQQs*LqQA77pft6Lr`#?`+=y&mUK@EtIg)VR(lF@LKahx^oZmIq=jGUciNcGYg4HxX z##vLWuUj(t<#>_rRfDE)3*mBwO%sl*-D?k}Ae0PmiDStq172gCD5nm8j;OLr2Ubqv zr9c9NQ=xW!8WC5YX1dv{op~6?cVEhEy;BbLL-4YmRR1zPnW3tJrvI>G5*f5}+NZdf zD*jlm3}SvkevMSV(7oM?SFSx z_>{qxsLoZ`t6gWQ!;llMiQc;sk<;B-@QIq+Tm*xDV znv35blkli9;xWL44sewF&Kgv>&el>Ddq`Bm8-NKXGFuM-dN4u!-vR*?K6DeCa`#`c1m!FbCOb&Q`TOKZ+kJOXI9zl<)^#kI@zcLyu zFOlS!kgWp6dq|yvQU(O(2eVB2@Q3%4N>#u9%Huw+Sz>rsT3MPeW7I@!I+uK(BXanC z;r=he$0ChQ&L!sP^U8%mn<&q(Rs=I1OTX+d`G)W6Aas1OcZ8eEHGISYI6n?G0FFgF z^)M-fmB*;ZI(xui=wTzP=EiFy8*({!mIbet`X?ejRw2yg#vzIqs}i3&bx+iC)SKRf z=*heZc2+9*t3+ZG{JB)a0^PL4>Y~M~iP0!f9%%tSs6JAja&wtG) z1RD1UFb02@{2WFd4Rc5@r$zsBBqrp3af9ua*1#zD1@qVGHolAvw_h{SvZ!4hEd{=pweb(TRYn->MV8?fl?2V}XBQ+JZmAO{ktxP|6P})Si!Y_*JTdb-`Cmu zJg-1>s8(n625S%_D2H@5;77;}Y}h}2jJHC)r@az`1@k*b2e*Fp8`&XFtf80xd=Hzf_^spH3FJF0Kb7xeXYJcJqs#j= zxiz~f`N)DscDFfVb0-a^#hb&Vz@=7cUT(3EHa<)&iQ%AtFa26QVh{C8fbTUMH1n;r z#7yZL+Hb2W+{McVh7coZt9&wG&4w1a@QXk2sc0yy)(S0Y7&g6UYB6j}{xsP8!Je_> z>f^40w2{=XIx(x-aq8hFzKtu{)}44j-RkRR*k9Mk(N9TsE%ekn3K2+>^LgDhaVcz1 zCSs$J$7ARm+vv)+;QZ2wDk1m044ilyiKg8a#CqO^Cep!zhD$5E#s@JabJDn6B`yW@= z*d7NLZJVY^n#OLNhE3Agw%x|IC$??dwmGqFHJsSCd8hAv?w9);&e>Xft+m-Hd-J$b z9ezc~-7cmv%yw~p#zIgSzis?obJL5xPHHUimvg4RvkH;|d}P6qd+Q}JZhkYi0_^o} zF=9HM(Lm-abzQ_Zad;MgkrmhE{EP5qd-3NAc(A>E{YMt$;WKa)cDwC%E{6eg#?r3q zGDhMC!?V>tF|e5g6;0~l+~P`xs;$C>BM6A^95Ug;EiPNN+rZEJC{y2vcY4vTd zWh05B&G4OUutgbaRHEqJm~PGPXIGee~q zT_6L$?%R%iZ4u81Tt^tXjJK=uX_4;_2D-F!hNm!PFQ{fw(34LJarP6dJNJgxtp_x zzivGA@!36*dGDOu*8cSrA2PcR0vI~}9g~K?`AROkMi246Io7&U;htvt>YGa3u6IBx zGZgXuXp&zQsy3L>E`VHyrOB;~x>-;e$L8HNA(3GR85-YQ87(I{74`S?{NiX-Rka`- zqKp$YLtJax5A{{YcUvl!ziWn|}U-UNsmOY)7jVb07wwsq_84ZDrz09U!q>b9wT{iE=47|NV--G|Q zH%~a#BrD(zpA^sKwfE&sGS}VCT9ysVUgpaQZ1eu+qyBG9hq)ODO2;tdFUGdiF0i#! z=~%3I{i-oF{J4mcL8lD9quGG9gM>}2yL3}Wg zQIp~w+2~=Yl;bNx^Jr#U=YjR)NSvclSkD~Wl#%lK<*pldX$;|&rF35h%WJL+0_T7Y zd~lAj?FRxXlL`W?^(CN1Z; z&G~x^QuV@iL}D0ROnOc;mbGD{nL$4sPvi$bVey8q+x%WsP4||y8WNj-&V6B`LWMg* zw>+$2GUZ_3iQc&KDq*81H-J5h>ck2j#d-}P?05~UekligM4blmI`$+Z)QhuK>{jwl zxgLd9LEWW(D8_%`RA9n$+tCej)Iv2!6E{v6<;99XJWo32>B_x<#zE`*Uy0{~6H!MB z%TDCx?>V-NnvXs#?|zk_5nS$dEAvz^YJrUrio5JQ&wV+XpFnCw3TOvhKgSZJdt8=j z)85$eus%iY>3ELmko){g9IJQ#5{I*p(-)81Zubqyx5t8H*6{|;eLj?wPMIc066)tx zg2v(Aph#5}c1ObR>@Z+56eh~A1{^dKllN50 z7({VLW%_NIz%{PwG;($SlG$BP-}ODbE?0XV5S0sSeHc)8k-FH;n~WQhGZ9b>P+kKmFMxi>o%{yVy-hE7M=IiVP%2MmJvb= z(5qmRu+T{p-eu_ubC2udHSQjX=`eln^%v)jP10O{SyN6(8{IT~rg^!I8~*4c9@%a3 zRam?`5AoMn9HGy}e-%wE_l9ZHbtyDQElV6V>phh&#V-r6l^hth;sHh!wCuY}a8`tc zxFX2kUinMmhPuUDsbaZeBU>vIA^~+JKz%Dt&Rh~JUfL)$E$B2W1@ayG3;t1L3+D~>Ilf+nTo@E z=z6a6LMJZr-yiU}|Mv&7cbtU5gjDx=NUTL?7TAR`Ddvu=A!)7;0sYCd&}GDc6zI1g zp&-L=MshvnM9@K~-2sqc%mlf3><*_QEYCgjpT19L{(EF*WY_=0ysqBbmDBz$NCzuT6+0kcgO z)oG8aE2nEZ+AFdG+LFyOzLGZs7)*@}@0{aLqj*7(#;bTptd#hx$0PtB|0c}ku|Crk zdZ)6KtDJ7lMdKRS>JBYmg>?pU%V5{Fi@t}_FM$S=%&BYEC-W}hzjj`Ndr zUgo{kJkI5~$vGC8e(?~L-d5plr2io_GImJ_2wz+HkP0F_dE|z7SQ6 zak*uBfPISOvMrs~#6`tEQ?yxrYxz;O4D}_FM(;ZIB`+d=Yg!eN!j>8j=eh>NcEl0E zJE#ZWV+5N``q%edW#9c)*_^yB6PeFK8ji%EvLyWbUeIV>cJ4W{Iu?r#R=)B_iT|op zJ~Y#B$DN|QBMUM{&8gwzB{Iv7lcES3ZZeyq*yefLtINi{Qm6GKu?_I#T-CwUK+ zmT-6dqYF)4EaArz@>~YFZSLtj9C^Kv*7L%pJw-2bM-$JtPgQ83Imr!2^37pWcS*3> z;P#To(>mgp)#)B_q5&zq$NIAxMfJ&-A*4F>&YC%5`^07z`mMG(22b`V-rv2Ao}{wh zF@7P4@*kn)Rzy%K)}W&b7*1UY2RY`U$z*T+$s$7w#hqlFeq$q59W8+JZ-BH}ta7ek zs&yb)v9jTInIVNN@8BTl(Uxx{$XZ!IEJC7bE420;CImR@oSo&E1Zj=~SJwMs@G9x> z=LCcO?h<&qj{cVamBz18nmWw>p*FN1<|;e5sOFma$R<)dOQGk_i7~Q6!Ctj!VNB}& zl~spd$9#efO~d$;{63B3}UV72nq^L5GXwbIlVw z2dj=0qmRJ~rWr6xE(hvlb4xWY!0a_B#+pe2zeiF)+jDh4Z5<;|e`-n^u=& zlx_ZQR(@t~c{SyDMb18AtcU=j>x58@(JBwMvb&7)-FByMY!m4K1373TneOg?7vff< z&IPtw2Si;mYqVZ$MgEq`snoOk&V(2g@L;lmG|(E5KVK=U7{$+Ot! z`~^%gJbCaT%)Z?blkQgA{EI3YPt1&;m99n#Pagyq?0K$x=Xl-Kz!O?uCJ;J1ie{-i zr^UpC~xO46Ow4SIp zCt4J?=f~fqUfoC_*=Zu8q8qu@Baz-DaT1q3XQFQ%1G^c^MMw3#e^}Wac|0U~^t%Oi zu#K!&5r%YN7M2d!31QP{(aulKG8tdE*5I#Tj||cz$C=L(V>c@zkxfy$Zk?R|fM|S( zL;hL>po7iqT)Lvf7?tslszU0QuqG^yV&gQWcw`aL06i-|7DPaOJo1jrh5G3Ga6_ym z+em|DByYa}7o{o&-LWZQ&DNzbI$dew$>QnIM-oVS4^@|yw;}e4Svs_pa zDHs~mYKa{NI3Lh9{uzw+(m8Pn!+&$k#JuKEMsH2MgyECWcnTl~UW9xphwPwGztrI) z^L1Bj1LVyFonz@23W%#jQt%_Lu!mWfI6&JvM9u}3J5f}$Ib|B6$n_ykI~}W=Hy=NC z%i({4SY^q%tfgi@9PYc8cpVn7x0S&Yn1E^UFx6O|4)O?njPFnJZ^IOp@fP%Bnlr(x z+ABHIi(@`MZ8#E;+LBxe5PCr3<=zh@!x4d}%K7ef`J^Kq{Fq?coE#Kg4yD1NB_RaK1pE)*sgN?Fh--5AS6N#Zc zy<`4h9+6{`b`Ogh7lTlVo>|C#lhpQ5&9R>v87J)t#@bbd4TS^WRL z(U-j;^0zdW*aFt%D{-=`3zsB+S&ktl|DZ5ek`2L&Ju?L8di>rK>=rfPnbMi<+7O<$ z<>~I3D)Wkj?T7jJ7rTkVD=iZFI?Q0%v@AaM*WZH=PO_LHZ!G^1|hyyhbA+df708*&mQoE8+ zZoa5kWu>P&waUTw?(9*bPMx1ju5BN zWZd_jmPrRuB#BM&2A06{%t=#v8xzx?Vn>Cv=?(rsT8;~avG>6LGRl$c`-di)%d^iJ z)H*p|$mB_@z4(rpVY6G6kpY_qCJ+Nits}5t@wx0cIbGc!t$0MAuCGHkF2?q45Ffz< zMCU&syM?ef9|EjGTm@rN?p^fO*?;r8;V{U($R9aB!<@N-en~G_!h6z4S0SsW9IkRx z2OFy$`Y+ae<>EA#UcF~R)7Z2m$=IZCM>upWyH7{3p*YGF@#lD#!_EEHKU6+B`dKfr+d zRr5v>4Ao-w@tm@oAF$>JRpi-w_h;0tLBoswo9Gk7M#uls!@ggj)2X|xvT=guIl|~?zWjb2> zyb}NY(ZW}4+l>$MjHOsdy!&L}053P3B0e5&DpFZAa_Q`Li`^`r{k5oFP_U-=ADWdI zw9_?~iv~)yd^RX9v-}}0TmLD zAUElEFbtMb9!2ldsPoy@>M`%9HR$c zicp4XR8Wnoy`1er@cf#>R%6fD%qd1F34y8sm-WY7eUS_DKwfwXqs@%#g>y@^(e*pZ zsjU23xTa~oE!bvv^kf96C0&P3<6(fN{t(Wu6C;AVYihMSiW8^d_R~tvR=thG!zTwBmkVs()`&U9(ce1F+#omXd(l=f$(+@e_R3F4tA9N3xD@{8-hp@DMg)b-**{h)$n2ycgv*1n?g zA#Eqs;-W);yKf-fYN0{PW7!JJSW4hN$BW#DT{L#6LO!KmkelsPnklA*ENU9u1AFZs zS-(~h{`rtFW|GAI6K?sgrz%4>$*OPUmXt%oIuu%klg0Xg?D$axsKsL8Kb!b=j;D_RUWIQ?qc;dBIM(BWlU5{MjNp{=>gGI%DuYUU z!JCcFC+F<<1Hz|z)N-Gln|9jW>nCutn@>S=z@(j23b0Q*d!U2!c1&lPCh873cDp;4L@5FooN#c zg=H9xd9E6@%kmIfXz_Ho^U7_~vwi0-I@Y|qzBPY5++uWHReyE26ob~z!e;;0oP6NQ zBkE|ld3*7GQoUdpI3oL2p6>AA`Db5SrivZ??8WUy-7w}nF?Gv!aXu@(;i@oN-4Hp> z`f+&EqOF@SFej{5A*E7eIcOnLau(;?1l^Nu zpeTx1OsXCKyb#|Hclf~omfd0cwNt4|H1cUtLL&IdsB}uYbYrAGI5Y@Q&0?JuiC4l- z1d-xU!}kqDD|BB~Ywxux?*0Kn+w)x^?`V-|nlR}j?&bQH%3sY$er!4EIfg}0wJtlh z)yA7yYQX+=RV}XcUi$+t6DuVqKpTW@OMEdx*WQ|br%l1%meYm0!#4Dv?_{l0!5Z65 z3XLnPEQOFaXI_*TXB_P8XYH~>DaynG-}I)Bx?FZHn4Y>i4?uy7FF1VRf;DWKBtTO`E6S`?~?hx2u3Mficxkwz>TRBrFcM6c-3k>7tviQ z!y6Q2*V-9+IJ_wKl^dp-yNX&UBmUOEV=DUl+!)gy&!N0$sdW(b`MjuC=A=w;W09oR zSx)B-x6{+sCg%UWa}GJX#q z^-9UvTyMKqSk&S#`aMGjGgprL{Al~FvF zYFpIj$BlSl5yhwb^r5`(N%QPP#@1gQX^;G$kem9$8P~H$Tnwzt>Auur2b@}m0XKOB zxNo$0E2{k|^o55LQ%X4K7`(CFd5fT&F~xoX>}`D6Xq^V@qMB+iJq8plc?S19s?24q zEm`87P~fqM`w6skEld;y0xU7oO{DjxfO!e6Vy{WTG@dBWT|h{GflR`elAABzIUY~* z;C9~Gvt2#+LXs}W7m`!C9pg`sS1%bA!s$+JaD@6yL-EruN>EEa70(fR?IdTt_q%tA z)X{FY`bb@gN<5_eT~6IBAPs{ldJN_1+#<($ty|V;jDO&$cFz|+ZVQqBA<#CB{@uhA z1I-_XW}NTi>LL651oZ3FCBz03K-rx^qt$nKOAWhTWO}2j zOaO1WRjnb?fawUwx(GZ=eOqbyw^D2jMpP6g7 zPD)Q$Q$Zb3X$7x!?NJzcEBJh_|t)>xv0GipfB6CfDI zF>m@v9BgAq!2ZM27K_A`Ubos zbGJas24zb~%uL)`fII_s=Zcykz%C+$!IX)#`N_34Wd9HjbgE}SPY_wsJLtsKuz*Lq z&@A~=d9$$L7_o!(i}H96(i(R;RaA<+#VU|Rd4JMyKUZUrCo7R0`gvu-N*#a)IXuQs zhgM*GV$_rGFnvmUTSge+K^!vk`x_&4j2YS?lIK1l{nH)a{RHaTj5|J`6n|+^-6S9^ zGXc6?xwdZw&%-SuIx-``ir`Fx?};X<(DYBivw-!EBDagKMcXVDQOuu;TJ;3hTe|jx zWZ7tHh=;q*L}FP!@97JY>nDzndy;wg9E`pfD&D&%Zl3EWEH8wOpwdSrO(S>`^X2o9 z*brsy>-8^PF53aK;wrfQgRCi5B2DA3%hoUGVOL-gw37N(!5*B*FhzOzBrna9)qo5i zb&Nffjmq?qA1U!5Kdy((xd(Hp!&+8 zi%>0RKb#JMkgg_Q%PA%UCC-~x15M^UyffXG^VAKVoHM7k(E*ZR%Y0-w#H#9gh8hvV zIKbhw+OCXFH^cmx0|q`2B8`+gxDm0+_E2+Eqy4()jE%o{^=r7L8!8JI18}hsY(#FP zaKh|<+B<`&jS*8G@!h};lX^=+{#lh^AR;_1^iB$r@bqlz?T{1})kSJ7Hu=-tryq`2 zgXLkWOB{PZScK|lVuVkyw86w~ImcdSe{^7((j5iH;@(YORXuH(uea1#BhhBR)-aVRa12Mz3{wx7s^?IH-6B zw05A|kqWLiXl0&j@sO+69)o^*Uv#xPJ|Ay9X(e$VZ#{fWOffOHkPy~pN*^0OzGZ`5 zKib2A3lgzO#NS^Zi{s6>(EljOx3Fln=f%S@X7)~S6sMGTPJO;N^uGN2LCE){LFiZl zb3WWn%?T+6@es!QHngczg*}{{ylZ@tUTqcONphcZvM#gp!uD{PM{^-$Y_X8Z)PHD5 zob%#hpuQ2*-JoD9BL~g*>~S9`k!jRe2AtK_(|AnZmTfhFngrHv@TMt`H4J<8ID21L z7{Iqno0;;Rwej8DI(KebyU-5pByd;l5l3djkUdQEmU76IKRXrwBxWP*@qwNDtj-gLe&v>dTmqJd7 zO*FP~DfIVzDJ_Rs`nTo)7CCc-M5-EWTf6M&fr}qAfQTsrM<;R>1*CkEV|mKf_RbLU?)6bh|2pTxy2^6vNHy@?4Qz2!jbdW;(gg(tiB`htq z4c|w8bSOFdnL56q(K#%J-J;5a=J1-`k7Db|zwV)I`lxTdL`s1^z9o3k0&Ezv_`=adRr59q4cr!Lh1^pf=vR-hKIQ+A7@Wq0-{7`J;U zxDdmuSZ|(akkDPcw&0GEe~Pdr9U@(sz&_;w&LR zU*3W@Bg{CQ(zQ>yGhSm7Fym(_nh3l(2pJmAtYD+dtv=}&!|2`jTUjDT?^&lbL+G%k zTKFICunNRly5f^i?HTUCY4{5q^s*X!Ue;#qRuIQ@Mk2m+)YvN*e?^=_KB_#EWYSx| z<-i3dE*yxw@$zYHy0!<}i$~D_yRE*p!+AP9qbMoXA7grsqoP$e3iuC2eTiC3xfO|e z3XZ^(SL$zu^Kv-A4s;9dixYpe9) z2h)&~;pT9+6w$xXLuHo`3lW3nO@Y_ET4tLF`R&4>rYjiZZT@&Maie{cuHeBkNWX*j zb3lQiatcBXQp32C672;q-!=YjdXe{A<8-YC;}~VktTW!5i_sOg9vUF^Es++Di5_k$ zzB%w?!Tb}9?#?jlSHoS$=EGIPDUYxyOAekR zX9%Z-&yKl_Am1N0Z*nN{m^d%GtFwepWIl(6)5*_%UxiSxsDzxyzp=B@)NK&BzX*P= zeo-}pXVk!eY+*ygBdv|W)Cb-&2K6UiSuyP3sKaq!02b^a22aux3n~U3eSu&BC%RdM zuvYf_eDu5IKq$f0^?AHPp-O|k=jl5Sk8G*6oWl<>24^vKw`hfsO6SFL+a}qKS1q0G z`R0v}D5UdRNvMAXF$%tYoY4l|hOQpX4gO%*ro>B5+AT{>@=&={o_-9Ah{_wM$B;P&{I%4en9>Bk~0F>6Gb+}G{}z*I?%a>xr2o%GD=d@ZwqODUx?AWZBgFI6~5<)&}mR_a}1|sz~ zxXy&b3xHq>5qw$gBjxxOQ!@UhGrv9p!Xxd-C_5i$=90A@k1Evj;k;dCP4# zo|8AW1kWElN4QA1qyBrL?SC&+-TcQ3{&6qESLb!=4rHB0;IK7l%5+lNGIb~ii(V4? zeE`88soqg{0cMSUF6(@isIQE5Cr~52G5xS!jQq;AZ*mtV)zg&9&}}Td-L*k_FR3%p zLQus+V$AB&wEg{s@9y@G^$VO2L8!Yc_J;46# z#2sPXUNCFJTJa_9ufXNXpE5;v?!nRG{J+uimFZu!^v2r- zI2djUO?0Ph7JR-z|52DhYH;U!^clpDw1Q{MM0}0SB7AHZ^ru|;(46|6KD-V=(E>+n zSs%3?9pH*LTOYTyK5{l?iw>Z!XtIPs8;# zTxanao$Wmiu^kTNqL5(O{H<1O^R+Jh)z^Q~wgJGkCy(2_9!B7_8O#<%e5`a-&p7yVm%OoV%ddPJUh6(AnCu$g zJ?|_)sJ&3j6vINBVJ=LSAaVS7DW}{ARNeUo4weO0KsM1>*9X05h9`o75;GJI>vs*} zaVq?Q?X#Eb()ni4>`6AB?&i{@>Ma>XQ`Yq7t&X`S?*pvt&eQO&KftK7;qF*pmEZqn zzC;ILbZzHn#_qEY=O8#OnOME?9cWt4h0dRE~S1f)_sp1Unzup?^RZnIweU-^b|M|GSqXlty5oS zx6DwNlWpr#SprevO)RYp>V~A;59iz%W@2zLK=RQqse4v0-P=RToo0#3p|Q5tt2w<2 zhBS#b!Zb}z1>Hio5tJnwZ-7dYhvd$q&kpLx0tTnc7KI1s@T7{q@QShoak(BrpJ zA8J$?2yW^t0spB4A~n<26$Hc*a<z#EOPOLXEUfT2w2v zSMmmRWbvs$0h8;!PP6ARZSH(^ZGfGi^lxm=+%uTpOG<3{uyh-WuAH8;ZQ9{~qHrF0U>W_mPv4POPpv1gl5XManU z`Iz)=(-zSE42|^6+z*l_LS*2+luu>9gVYWy+qz-n4TzG-LdK5l(?GuWwG4<=Y`@qCWDc+8~QCOA8QHr!o`g2%&lfi>CuxvAYtaq;zS zxI4|)`z^bp59vO&IF#ej~(H!gFg$kb^2n-doc0OK&XhG`8i>M=Rf$Evst4_bz0vLlpQ=bYfW zneoZIxZ3XCkOlIEhF_?Wk|qGNwDBMIgDypTlxua*%2jejrMRD?xsNJO)ON(VV<}>} z)Uz}la!z=hIAN|rqnxbgqj<+JgQ^D`B}Z^guCh!{QLRCr*bEui^*`^h7p?ahft8ZV zo7Z2BzBPK(8)5;prr*H$gJ)ob_ZdzJ&$dRxhCg-G>(bA{!Xdve6h2A=;R{IB|bO9upMerjEgtmV!X7Q>{jUR$e223 z0IDcL{}#6yJ1Cl}GQhGspAagDr0O(w`3u(n(wi9#s=$d?6}kD*D9~4`s5dv#Ud%Ncc{$wsBGnL1T^wG1sd*;qfK$ShKqgctC z2Atq*nCDh1Fo||#BZ3nntb99qtf+UAsJzOrs zN2m+jurq)=-=;FwY)_<>pJJ0-qg_!xBC^{8>Ht6wJ#5jG-+*Vl@%VEFd5}nm8ixs5 z6FTZ6k$7lScX~M&m}pmG8#`vFF*{2MBSFehk#Bt3ZPL$xXI7-H>lO{>_I%8hVDCT-F}_B21E57 z+iSYiu4cJ4nGs;Nca7Bdey;5EK5K4f5TaO9ZKum2pQVMna{H%Wu6?vblWJ36c$0^? z<~#wKIu>IocN_7qNudIgTfUAOb^ppuUF>V3_gHRYItF)Dcx^*WVKDnQskTeZ3YImvfzl)|w~J3D34~!sFzKh8HOs!o6ES9I@;L98vFLw$E+uHjD~k4Nqry zTsH1zyxsCN7^vCqV(HYdjnYln`I zCg=Poem*0DR&Q*3ff~GM@KX?nsz2gU-?1Ikuc75Y8D-=~67EM%#CayhBQuqqj#$`M z9gP{2Lc28J6@Xrwkrim&oZ3Kq{L(t6rMhyerpbE-Y6tK|42Bm#m8m`m!Hx9%FpCJLz0RUv}Pu~?IpTE%QQk( zRsC$c>6CH)v3&I?k@UV@ zNbSccsRj!E{ZPK$t-(NiQ5ah|AH%o$w3p@wkJ+Pa zuLU`&JBc$_i?fl7pH-=A9QTbeC+4X+%o6b=-fztnms3%h>^3VIQjPsNm2FHVmj@`q zz7#hoCAhameM{_2o)Q;7+UM8B8H-dh1Fc^BUhe~e*iGmb#C*_QOCig~4e>-x9l4&q zrf+b0V){Js?_^I&iz5CS9_HgbtU7L^u#05e^y^0Y(*xNpaW&VN>Ge~NM(ba5L#^;X z1?%N=njOD7co?61G*)PMh$0X!TPNw+Zs%w<-<4@#*l9J?jxJ<_&wid=c-$QE60*e8 z=DN-!q!$@v=~Ke*+2&>%b-AVphG0bS3y$bG9B`?15q2M-$gSK=4dfoll-sIQ48o2b zTvfe_lSL~HzOQLG%Whm@c|9D>JAb?#!F9g6=iB2&|7+w%{%ho}i!Z-}N20l-k0&8( z`{m6e9}_4?`(nyC?$p0}HNpj-%3XUooj?6`r+(P|!gFCa_+`)XP9`v9H?`pJt_W*N z!IJQtRS$}TrE%CFr@ly}BGO)?JT&fKtW&mvqKFAgEV&XgpZq(WmVFG{j71l4ugY-S zQy@2dXvWF_!!hM^)`}<(Qw^xjvyymdl*+4hTQFT~#nf5Khx&d7_kbB?Za=?W-4*=r z%j)g$#UjZXw^Kc}t?_{z6B*?)%Rwv40t<^%VdVkVYZa||C(px=Ts~qwmUv{&)F+~D zceaQtgKo4R)9lyFR&+Q&w^DEH3(=KYCU3;PFk-zlEK8gS_7PSGU!o!1&j9$24iXY9 z`{AOZkOly)py6V#o{G7YLY9#q+|l`GTt&Esy5=4(m*z^zoX`CpHF5uR(i z9x+FW+a@m)Jy53CGe^j*TRYzh$(@F&Ia-N@MV#9|j#|aC9+-5NO`(bn*fUPmeQ)Hj za^mUOAVx$#94fO>F69soHK>O8c&UeqcbVffn&d9rPf27q-T>ArC=WafT;RzF48=A4 z2QHl5I176lc4H4;#5yuM#6J|Iq`$2iTW>Lj>x*tF|M@JuPGS9B&n`|)MX#WZa`op* zP4UOlr7$sbd>DgmZMZb=WwL~{y2Y~Cn3;3iE*aE0KsxP^rjz8%paI!m&U$;Io9(kd zZPTvPZVxPOQh^Pp=eWDJ^YejHf2y9pQu9E|P&>`J;_wrQa;)WaU*m+`;-^`%X~j5) z?SOR)2*(RAnq>G5xCP+k+GT8q^)FLR22Ncq2pUKY^aiqZa}lhq+ z+c0#tE?I~HsrcY|8VM1UTv897b(+SW;ff?6=X^8VuS)3K6?FNV1LTEFMrWf}Q+jcj zZY50;)e0Y{*Wrd|+?wbb?>b}Y6Kq3X7h%Q0%u(j!jFk5{v_tKlooMCZ$VCR8LCZ?c zeL8cSx6VHHoX8;AXyS_n7M(l?jVeAO4kHR*+uf#}{uwsq_v=iR?DZ#rj>~f|9iP`F zXyo5xY4`qDpDstZ1o;@Jv72YHQs`$6VR=2|UU~9a=a~YP6?E7h$B~H3hklkK6tpk% z6e82@GgI4ADejJjqq0 zEFAHOZ`dnHQstJju)P5M>-Kx{dZ-!lBN@#D%_gQdWMNg z-W=GeOEeVHb-Wvt_bXKn)**1^SWOI>z{afq^8)yehV?^F-=*jDjnu5yW`c&DTFhBV z?Py6Ss*;zVzO^2!%zER{y|wLotMK_9ogQY^X7Ui4w9ZNRAQ9KLar4Icl-=KwM*Pj5 zeo^JAzgBo(Koz=S2NrZY-&-dWuZ_M2>)L0=iQPFf>eL%!I_ZA3-kP~%b-jYLzrO!I z_Dh=~*B((A$#sDJmFO#Qh~JxLVbEklao0gWtf%iicH=f_u4CwKBFc^OO4YFAW(oZW z*J>o<`~9GR>VZfo1u=EW6&GDIL9*5Sd1!kMtge> z`q2-~>oI-4|FA7&?&ZZ(?Wy~WLhj;qVZ-&gcfY*?Jt=;pohTw(+1N4S%MAqH7Id@d9iuk9bge8V8pIV=_2DFyO`pX}D z>LPfZ?{~N#bWLxMhJ#ZL<#4p797oyML_Z9$DAkHgzX<(`jlR)(Q%c(Pi|MVwc=kU) z5wZqU8ytI$wP`&i*J!xv2Mi59V!CBi1YR)sXFBaSr^$s+_5lZ?bvyqOKrl@1eJnf)(Q4t2P@HTV2McSuT~4Yx|`@Xlhn^Wq|k3B z&5^GbDMXi!?DVTsdB?@$_gNZ(ahxA*9bn5C@9+nO@LKGmh z=WU_*=Bq>IuZr&%w&(zD(psqe7iuG20nVyz3@>w*k0PfT715xG>mrwPq%NbtqSAX*r|)69{d*PK%W&f1jklE$w&^Cvxq zG3*=%%f>G!m|Zex2P;EiF853f_mN+DmarVitz!+IMSs=Z6S_SfVb?n{%+&fA*dzbw zsaV^#O6TeJZM>s#P^U4UVZmOTH?yb3aWl0EKg<0^a2h!iy3=aIX^N1)Vds!L_rTH+ zKVYdRnPfr3xd5&B<kx2wwg-C06^Vbath$}+wm)HV0p%pt7nd={n)`1h2+hp5Ih;x8a*bOuRk3?fYmHI;E?E$82@@>= z8@;bfV)R>@5!UpE8XrAnc&{%_cLyozC@~r!$N8-z)u&&Sv{vC~T0MZNv^Q#AL(XfJ zj%DyuKSa3l3CD63nH;s1W7^2v`@o=77$?vfDQ63-uH-iN9zN zO|}?RJEpk|Oeu+7b_2~MYfNHg|AG@2iYf}tn^bd@|6@_RBMbQpAe{k<71slJU7H(< zE9y{gQ1O;yr%?UWP}sH-o24{i0Z)T#;E@3MNw+CBM_ME%qSTHsq>xx zX}%+ge|usJV|7xl<$Lya107}YvU=z+5q)FBvUZ!2>Iq`;^bPgf^z=<~tSo}?1|g^Tpvsz_TaRW%1b+qRO}Jxw84?rFMI}Y zS{;Pnr9CHcc984Tpk#b#PMyPtN;7>v(PotU9Z-D~@*_+0E1ZW^xrwEvQ7;6Nr3Ygs zJwRrrAFLd3Fy=Q^>8gQdUCf(p)SU@*uo(!~FSoArvv{3lG}E`*2aY3H$Se)fw}}<% zEIIxnd|F@3^171w5Vs2;ZEd=Zk4vk-AdhcNOTk7=`t-Ho$vpG4Ztgm~l3v&1vUY=Y zE=>$|+FAb0BwPxw@=sl6R>UxdL9dB5AlPfJ!7`NQaC%>DRaF;`$1;bI%RuwIsWHpH@2ti9+$pE3)wY9 zJXjODns^epD)qt#Zf`})f1U4b!9MzVU)wP0?R?p^a~luWDSLaZZE8QJvAl*}E@%@)$f;@;xF6*TB?zyt+S z4meeLeS#T;y%huuOxL_fJ!!9m3N%^rcYYHoV!tM)3oX$wX!4|ReDC9OkGp#Dy63SG zP(g;4)Er$ON|Zud%X;AIwg9khb01l^o9!nP$?rTNZ0JJg@>TTMk0KUjs8T(vd(}33 zh0?sC({SWVwvSox)F=Bu5ZZldCrb4vKO|XX&di~{FSh7TL~(ophNyS7*h=_0yhqi` zJe6_5R~RC-o7adm{k=+1^Qgb2xFQBk<(djMm1*I)G8F^5PgCE@in)v~DbL2AJp>k9 z)S5#821AJ}Yesv-`Ms@YHqGfH68Rm~f#5t$L7f%fnwZgMjjn*hpt4L9?~O#AWv#A{ zO+Hr~nLarY?qA_P?(Wo|Jr9^*GN^yww@@$UpErMlT6Ns)+_r7m=L%}=$CYSt z3AK70>xZMrX5E)e`>ru4fr#W~+WtHu?me7EE_2jD+>`cj_w%T=z;XMu(Kz_d?#Qo} zTJ%YP(6x1wdE@8QrnlvqT*lX&FMe^Ezv-IjkVb!fEh>VveC5?tU)`&3d;rq%`TT~7 zwlKcVaAbet<|pktG~W$W<9Fg*N|r$G9hZAs!eRAy!o!+7CJ#h*DvZr$NDkqzp#5Q1 zM)8NzT@l$!Z!%Z#mGfSNEb&Z6L5uqqQsCmNYHXPZzm(RES-TsDl?wyd(*)!>vL?Pt zzt5*bJ2UX8$ zebI>dpaer$9)|_8Xf22HxIk{ec)bdf+Wx$P*`YbOR~`j%e^?6WG-8Y9@kYinyDU6; zZeZl`O#qT}d2IzZkL^_;RS?V7m87FefX809-&sK1?6jVT7DG_3#NPGzk+Abc@(${% z$n^aJMmo$aL4AR@cedq|i*H^DW-aT&TEHXq6Q}^jbd^WRx>Q+I4WvqMD&ykJlIk4r zY$h(1BP&RLHcY@b)?0b7ZH#~=eWN4Hm|RC!Y}kWrBe+-&lJ+N$MU$3N{JF!Kyq%HG zSWS}oDNd4xCb0UZLeA?paiEb_@*`OD;NlDGamx!NLn7cowtsh_?<{>TBfLLFI{ zusi(iKs4!J%baCYQjy1{>7%j-eKE0S@^nOmyWnHyNu8xD&jgRO-6Mkt* zDtRj5f1VS8hC)+&1l&g9TbW);%7wrivy!;b)>#ZdL;X-_-K&L4&Rc^eC&#}b$9yo8 z%KG#3gNXDUUCx>JA3RzE)9?pHY$l4H$u|3z%R@Zw_3R#2AIf=70sCvUpp|c$c6q@u zZyk!;3i-`YjsZ^q15ZCVQdEN}BAA<`K-0b9t3@ToK5n$uz?Ck67U%vPN-T1I<;(ocSn%$u<*S1O z9+^+p_HW9U?;X3}&rYWmZ@OBFGS$bxUtqZMH&jc)Pi+8+0N=$~3OR}t(SHNs%)j;+ zeKkbk3a`CgSX&BBDAw=WB%LNa@u?Z>qN9`Q0q?Jx=jc*n9z@BPv)f~Fw&swTu}a^G zpXu414UHbs1a`kBl2M7+vn%+@>Ufn(nSy{&s(?w!cRh8{Wm%yeP()rF;!@|v`SJDO zU#ihJwun8+Q?+(5Ozcs9H2P*$&c|_}x!zeKOzNS_?-JrlD{-nX$q*43F>6RKp?KU& z8{mJ9gTlEh;osS9MoaE5|B+=VvOER*$2~?(ckw$lTbj5X++&AE5#O~cc z)3EsbgKcDtB2;b_2pg|VXxi)2dK`I@2UJ3>;eKSNw=(>Zw(0xXnr5o=x%tnkT4_11 zr2>eHEX33(@tA6x$16i<2g4^zf=Zy>fz(~N52~k^sMpPS7IC>}tklC|u-1hXMpb)o z$n#Tw=<9jNXp{EfRjK)LP0-eGfrB`w;#p#cYN!&SQ*p~(?aCf35}DWvBY1EUgr#ujhU>otps1Mu6B4*DWi3;uVsCz;$t993c9*>?NU@})= z&#FM{0w4duJ%l_Uga;0{)sTIDiH)j9tJR(;jCeqWH&8zUSG8kT_`aHU=-<8?U3~y= zBJL|LBU0^cs_p8jC!o|1%0ws!*}d}}rXQO9TK~$UCWCB`n~5m}RW_}#>kE+bHLy0B zjiN1|hS-MTRi0T2XQUGmFRT>F8y7OG{@PjihX&Rtg!?Y=uqv^V82WU`PNkOnjc-vlv+~(VHZyqwvlw)Kuc^$**_XKes-8F{2J4}Kp>n>rFZVM8GMv5{%8L93Rt<>*m!gX?o;CEKn|5gEpyPFX^eQjvzU)chY zMrut{Gd{R1mI49sMsbfd^^$!V@a~DX)CRAd$gc>`lHW~QLbSfQXt28qs4SIl>xii! zVBpFxvdgJ652&>LF40a688OL8DpfQqnH8~D<2pc)|*wjJY6(a zAs~8iBm|E4%bg9XVXvU$3Wr~g#wt_TRNi7CW-;r-JdglN85Pa^UZY_C|tIENuGnIcy;Tqug{UBlXPq6B^YjLDC(?BtivRf zGeJ2n@LY?b0@FbWiJP9NMGGItpM*lj7)IYU{^0fJJKvrA0Iqb?eU@|d=jm*GG#J3l zw(cPjI9{e7n<9H{MI^t51VcEIV2Qff<0|B^dfDO|bkZ1sNADwUn%E0AlCM7y%6)S`0j{vdnj0feU zU`5(J(`t=DHij&YD^1&DkfUaipjINyptCAKAv2m}9WCl|{@>wms+5eHK~Ixvv*u#Y ziJ5QcLYEYAMdCXBz4CR(PJ`uor2U(t*#j>sF?58|>?#F4%`FZL_e3j-$~YLI1}l|n z?%y(s73 zK4COTnVe6SH#;7U>YBJgr=>+UQ+!JVJPmY8+>w_>z2uTevOOE&vV1T3N_N$50XRBc zQuL7LGo`T<(+IWUl~;Mm&v3%q#n zKbJ5!fM&CF)N5F~^MswiG|^XjFITgFTu~_*cbCED7(0GS*f?$fYFp|Px%s_j8G>2h zp=?^L{~QS?ibB3Yiv#(HkF>(WL*SmKVPEr3iDcos%erFSZRQ1ps<+`)Ug%s; zD$j0R4~Kvj1weG&ob1Z&Tw|O`{K%Y><0XEt@F=vWn^~8Tbm|g9_2f9`s3cakJI7wA z_cJOMK@ohBRvO)V5QpG=$y5V(FnD0je7M(#N5ojwdW_nY9VSbO)eJ?xn(>?q?_2kvVMrN+)JKC{c+78 zbc?Y6K%o9)+D^*8()wE#{re+4EtW4Ucn?pL%(-jdavc??f@R(SP!(AB@q=h1Xb>aVF0> zP+Gd=OH4(eP@h{F-$hek3C<}wrK+gO{<%#p$i5Vz3K3HAOWK<*HHwjeVav;LZzlgl z5j9j>$~Caq7_~AzZ?L=kE?PO05&G#C#^XgE89J8asS{LE1(kytsx}riiATfxAYo%4 z4R%!E#%oYZS-7dePWZ!Z@Xy-jXOAmZLdUWRVo$NcCvDb+J9NymO~gMOpCC0Q5qT7>mwkxS8gXHzj-oJe;uRK?@~Bi3WpcGT6={({wfl6(## zi!@@G-lvsA%QJ%ct)7_SKH6R3%M9w6CXNl{T;2^X{!c+$MwZPctFr?yXj)z3G-tSh zPokGTbvY5hi@-6s9@Y2n+KQR-)OiE1rhG_}4{*?m`fTPXRrI=Hve2)R3AKX+6*q1n zAOMLgU)FXrqCex!5Rrs9l%kQRNCd{3MvXg>`_BCvl+2^}n+?vH>bOW5_vZoGtRDHb z5^W@40IBBMmUIO>YjhSFU)mN{6_xV?*|T{KU&TFoNd)U0X%#(0jjl0)slSTJBqt~U zc6qUSLt5a#LHMZP`~pPOXgiBZVA(7ERcL_@y{-sow}D04@rPwtVLH*s3pSfrsZ;;Z!twwN2XEP6Bk7FU{NGX}__?y!Ot%yRLYWtSIP5G-rkIs9%tu zp$FL@v$;);Hp$}Zh1DwfcHag;LLIF9sm@Na&|6fzl>LwC#Q`K*2m?UqdKJp>6p!#Y zvnbvk`D@lcs#1Sw`({!lu(uilMK|8w`b zYC00|s+az~P!%x4I2p2ux~BNPWg06!MT$STKhn+-&^%|KX5skU=@Mh6B3>S9<3_^q z)rLVfAJoUIm#-=QT%EEd98}^|qZI4Y*%xd(sX5~*`&DqR9pB&nTePuPcd*O+-JoPs z=2MaSohU`%GVxR0EA>6CG83;3k63RTVB+uvikYzCcQnl56Dcbqv@)w{kz`DN*h%@E z!L9AEcQDBKk^CKY|C=N)PkAn8r0=HVUxi*idj6r$30&Oxevjt$kBB~@qon^Iqvt#^Fh*!YlEQg8lPv?xKz#Wd( zJ1Bwqr}@C^5-T6-Jwm_=CZnoggti1_C62H9R|g5xKYzQ}^<5bI?bh8ibQswk9|RqM z5E-lp!lgYTn{B3_vCyNP`xIWP6nXu`$IJ^3^Gl1k=MdJd(kq4R8_7UjISLaB_y2hZ zNd9x$gjKn8!E3I}kQ9cHDyfIUh;clY)6i0UxBB3)kkD#1nn`TvW~>^Y$51LDkXhQ} zkSL)q$1V$}*-RDkt9aK57=hkiu5-#SYDjwU`cp6mim2`OUUx%w(d&dXN5GXC%5WSA z)BNquUE;h*asG1Tj4{{deCncsQ?t=xyyzS=yJ%*-&+lo#&ZlNR%x%M`q0FEIxG$6R zg(K*T0-Jsej7!uE`3}=JxBzalUs=mrH576sQ-kqlQ;BJLxVCJYw4pbe^D+zJi~3;n zKS~VX&ayc=-&!r6)0%+WOa9zO94pzdgQ|`uPe}4_TpsGW$*?^-S3HXAVhTZWWhT1u zhtpMk>rLw zA^z=$d*FZzn0oD{Frch%`tM>0Q*J%m3e{;{uD6f>Pee5~*Wv~{FPWmG*eD)32JI$s z$8KyDVy9(B_VngJNgCgu4|JE{klMB(h<90zKRR1P|+%u z??b{+B}clg5B~lYB};=%bGDh|_JcflCUMm>EyZ z9Co>*sHN`|)U32Y+3&&hRZ692TV8pyLJM9C&}ELkrtziX$?M&@u|Svm7-yf(eXSxV zG0r9A_?LCO4ZhgF?C`;Ne;OMlQtuP&#rwN^FBHG}Qcr}Xt zI}%UraW~Gce*D3!MJ1F=X#8MFiwmC!+_|3X5%;aQ+zK}OwacWRqs_>VdrBf(@%#GSpOI`*=|OCI5s)~{1pt-d4D4d|*p{#VF&9r< zJ2!5OP@F-`hVn^sW`Qy7$$Fmjl|v)QbW8g(@Usf0WGQu;)9OTy1?z^M)orBYUH+ta zNsstd_)C~tR?A)&So>4oKG(h&*?#Mv!JG3*geT%_70F08Kia0Uj7$IFH}4Eb3=QtL zYzK8~->h?yU=MhuUrx(=o*%nj!RuGt;-$Vmc|-nY@aOS3F)IU#edBvrdD?tzfxC8V zJ${2aWt)%5fM)m`5TT2O60jcPgj4-mNHo9>Bk)KZUVcYgwgIaLNuxb~$-0ROs&!|b zvRQ7$-sAq#Bh3?x>5XfI@LUQ^gi@3ftRNDOe3(D4Kl4k7`TA{)u@S>MqN9>NSpuBS zA}d?7EvnYKjtVGIFAmpAG=h@_ovaOaCKcQ(QIJ-W{eZ2nQFSJtc%Ec}?(G7oj&I{m z;s!$CTOqN37vPNDZ`8+dKQV-~&NEL^^g+H9C;%`%hSub9k8>C|HE=arjhIq>zFA72 zP*9Lc6KkJ~?@#7%jy-M5j}_cv-o4`8)Yjt>4{oMW%@I6ipdlRJmonRc3Rkzan6<$mhdbTmt@k$FAwAt(uzfc?Vc$8%pL}29%Ky ze8ko4dMTtZ+BMZA-TQ~?;V&eTKTUY2JIsF^!ux|GNhNmE?>zWJ>s5K>gy~+d?DigIi!YJywFCO=YFJGOD4|`cr%w^Rc)6(*oQ(Mt`S&igZ^m@A0-ZaiYIZtou zFay|YGF5o-6}>6^#)i=(^Lst)7thTB4MjWlWdcm<&pmnuO5_gllRT|d({a3PKtWA)ytAiru#TCaa>v3+8hFDP>J@gF2Z||WK-ng+s`XD#9mGFhYOQuhC z;>TRf^`8&`y2~C%;v=Q#%xlaGhJOmDzgsQe_4FHm_4}RqdT+FKxC5Tb7_j#PLoMo<5+e zKk>zMh~(p_+2f;0H49G2^DN_MA^J6p$N%y~Z0W`J?};&P`ej;oSg5k(H=*NXLlVlO z-Ese0aQ`S@(cHUy^KpIfdFuL9P~s3MLbeN%l<$XYdb;aWOFFJSV#*JV&y59YvoF`r z`z0@f>ga=X38`1Hf8mC{}_*^Ag>`_|nIA)(v6T^&z*R}5JWaY>^FPd&(HRLnc7-^x&_5zFY3KB7}v z2Ox~T$!A%W*NpekaB-Jk@C!p`*7`WWMBX5yHYv}R zb6I=b>xvbl)^l1lC*OPX!pR>RL#kBMeBZPA)2Pb`=I+F@X6uP^Q4e^+qw6-P?HD|y zD`^qdq2&Lx`$bynAxOTfP2Aw!+d7)U1}E&o}7m_L{tUb zW^1CmuI4aLdfS{$ysa+UL6WxpfHhXR)H|>3ag6wzaJ|9ZjWPe-+Q*hj;=t`phgt={ ze<1-Ezy4{U8E*sXgn3ULZPrWz_ZQX621)=oTE}$(1wHy#;_YvjIao8C-_0H-1M8Xk zcapv~-&oLK9)8jetH3+nSCV5Stev-z!>FoNNk_SL30| zTX@7Bw5G8d$ocV+X5IPyq>;d4-CvFQ*j$I0#d53@uh?gINV@V%6qx+1c87EjKRb5q z_A=kSkN5p`{*|$UX}nm;u&DWo+A#h3el}oWzcwf!&`U}(H*X1{P129px%zuja7<*H zt!}VG)+|rR;-oAFpahFxCylxlA8<*b>AP2@DtQ1A5I)135<9*s$D`76j<0otWYn!G zx2Aqrv<4pPJVImv7(2NQCB=cGIr?Wu>>Rzq(4D-{)w0Mj@AjFf=%Y0q5wBebtAU6U z#^Zp+683R@+JR4V&ye1nM9z`s|8LHyve>b+a*Ul>&< z>BmwX^7-G{y8m~!v2Xp7#d%K+ZPt`bV26!@pUngfPFi5T9UJwX$%o3Ne%?WL3R=nD z1k_=It2=q|i{cconpMe!$=wMA)eAR80vJ`XZ!B&1F6js9@s7St;`Hy&E0f@*^@Vor(_#>QyLBq~ZyH?xhe=QVnm_8gmC6?&;81_B(GS z0=BkU|HN8Nr&OpMQ`Pc(DpwYh1$UgVB_@-vik+8FRJ>-g2#y*dnq6uRyp3s|dLA%& zfT-10FL+%guM|u*cw0<^2%HRjHUZ1_-7zzg_-nzcL@X0g8AVR4)beNfBpxLf7YL78 z!C!B2i49MDTlceL95QDSj()e>XBN5T>S48#{v_WQr6jv)`BBvJW}GL@e@Z*t+$@b@ zKEVn^f<;KSvd}6UQaF6(!35Hq!`;pqN&^OO+J-qg6lPZ;Fbn`44a}NGM_{2h=qsXQ zTUG9>Ps1j@_rYZ%QFTfy<8Xh$$bTi;Ckhu0UZNpbr}&61&M=9=r|Ab5ln}-5PCGP{ zQPxgbJ>H|be>3Zqoz6SIC)Z!`vFI_rnqzI=9wxfgvqlt~d$@)%0#OW?@4aXJY$ zpzUM^J%$qvE@rg$jyVsDFTcIDFrcVPsD`3em0VhVY{MLuGJw`pgiDeMmXUfS;p^u6 zeo~!n>8USjaTTZGWB}LNx%f3!W!~CQ+i!0-9M3wtRLts%RVG*ytm&kOkGY{raP>w$ zXt(Zcs_TA+h61Ais(|YA9p}U?AmbAQLqpgt2q19+6%(8XE9Za7`4G<~$=R<2vDHaj zRw{eeTX${_W#mku6b(3n*)JK?NrQ(^Bzbw%iVsCS=Sm#1jdQPc>kj}1GK6gnWK1Vk zEtKOXw$b~NSb#h_o#N`039s4}8C|YDF-_|4?z>^g`BKr***;A_XPe#L_)$bNjc9bS zQ2vW+@frBCg82X7Omoynx|N2Yd-;K{F@Z<*DMj$GgJLI!n@8DzsWt^QE};715V6Ch z9C>I-M*}$KU~)?APg@R;xvxg8d4xu^yRF3$R@<8NFTx9tJw?KIxHx@Xq(-c&>V=Gk zR@uFZZ!{(BykUuUumSzO^I8{Z?zVT@B0IU5K&;dks!wz!77}<2e}QDO5|{-niHvo{ zYNx;G!P>m*SKqGb`0plmH%%q#JYOzLSD#1=7Ec<3d@n>{7p`9%!HT3_`{CE>c5?(gv+h_u6%PWE7|C`^gproE(hO=AN$zL z*ZVjxg~9TdX6705@@7`13uE;&u&k$Hw%4q;hP%|LM$TAIzITMwSMUwQ@gAmP^#Z)~ zigVt5A*^HKA6~0+GWMDD>^*5X+opfg2iOujH>l~W=5S9QBM!5<$obV^>qh~MtBsnl z4f2~X6#U0J#3r4a<3hy_K0xE+ABpmBH$%gDtkhLYN!N=%pstN4{ZJK2f4UfLCNP;B4OY_x3 z`;Gr(Qu@mC^eUWB_-{{v^WWEM=7u{7|5^vJZkdqloL9>ID#v-%>pTXHj~61uB+pbO zs(pArKvcE%=e{LJzusKp%D+;wS|CXr$baudhq7SGg8KJe)qByoQ&S}e=D#QHZJhcn zxP2H&*~1BB$+oWS4X8^qOR*tlU=O{{6-#GiqD&IL=#ZYZbpmUt!A%lY4L)Ne{=5w! zvp^XcST!o2akF;gR%L15wFY$z&6{KXXtFW$`Ev5eq$S9A^5#YSE5CzN<7OGGt4>Tu z|FL+Crl^-2c5v!ZW&S?3q_CzrQXWZvE2Tw{(ji6|>lPXZ8(E}mt{+pto1nLm|tg?ULYpy)kEH{@PBci3Dlkmca97aeiZ zc=p<$Dg6Lbg&ip;eX`EP^+Gw{k}iiVzKrjZHE5CgL>|F!ZH`BqmP6Yve@TFM5_E=+i@XV$Wh=KvKTam3S$F^Ue4Ruo{Hc!^ z){T}OI71fyk0Gn?hij2vI@_z0E*r2sO@U%^V9472_0y!E%QZZ3e3V=wNQTWiuX0@!1Rf!ph!ciL1$QYlStrid)(@CQ98 z8-B=dVj*dw>R_c!J9}7DI0P*~+%6S9?oaWQ6%?+DRQvg^_R6|Y;G5iQaFC@)VEQOO zI2d0z)NJHW*BG76gf52ko=nxM*hfjP?`Q*z+>Jq#Hp{-#s?=cjxP0f-A&Z~W1$vVb z81<}6_o*3jknECPMul-kKw##+xtd~@WRy@$jvX>p89rKG#lg$`?#ef^B3D69%YD5} zg8kGX{Wqjp$wYswLaeK@7a*3zE}bhQN|27!DK`{_AOo(yOvq zg^?JL7LT7wyn9_1WN~h+^lP<<_V@x!>y)&X1HUZK|C7tb{p!Wo;aE~2UmK-oE57ta zotca-toLsi`{#>xi}NhfHmwx=4#BT>&~ajt)Zv-Gljn)`F`{hz)Xmbs*!FfasLP6i z#aBljlDIL|@uM7%CHDIt0-=0vp7TWVY_#j`JYq+56q~h|I!%n$z~e*JzhU1mQv3Af zXP@MIbb^RR;*E5clOG$r2a)6XVBY+AH^ds}C~piR{XT-Vjia9{Y6B1UN4Qo+#jkQC zS*(U5D6Q02PSH4m5|4Cuekd@-U6C|0oslSbZ`_KFh1p9quu;}CtynAU1*}y}KSJ39^`to0hB+lf#0#-krTGg5@z+A*s;amL<~_LP-+qa6pl*1u z4;bfs()Nr%El&Zuaa}4YU87X%9{3F6{7$c@NVnn;I9!G zRom;qF$H#eP*&1&y%>OqeP8vSB-{?hrUHM!=oA31aw@7kp)fS5vnNSRUiH7iWnFW&@q zCMloXU;3E%`PaYJ|L0K}wf?8I&kyaG!QdlP3c~SHzzt_Ad5I#WSifa(*8E_y?k|iY zuN3DkC`CiT+klYcKvXN;xe}fUXEL4P{?7QZTSU{KWkDnEkgQlF=ao>2wMx;eZvgdh zH!s0$W@@J>`MeK>HcGUK7u#vS{G*ZD!^%EV5WDf}4!mLq0eV^He-WUxT&pQMbl@l{ zjH<=a2V&GMvUW64C{W5F+$4__{#G&7uoU>(@|;;}%<%>ursSBWyKy-$BtiGtA)cY1AY*(J0dvOSd&z;Ds=QofarTZDV*x#^2yL`0bNd=Q6eKvr?_s=3@RW zec#L`z=J0m7d&i$+2R9=5xn%36TrP3IJsRbOHMF8`we~aA*6+=B8;4NtAtzh&h+*D zsP5>rGd==^1j{i%bmtpv8}l4C&w5RAlxf+V2;k9nJ~buOkm8Qv%+H!<*HR{*+d4EaG!aHBGKe%IZAFcM|GbhV)c{Ex)@EZZII+M%A8!410rGNDfp1 zUahEo5Cq0F5gTc)`zGC=cvd~HkKO;qdSvSeyEBzBjC6UEW%EYGIL=vAwf`WWmvMP* zJ|0=pjLPZGsY(zicvigW%a^=?r{8+Qk^O^p4dE=p@})W=T9mI}fzbH?*CepD&hx&d z?4@#YH(>ef!?wN}ZVz1fgFE99Zp`RUKEg+;_ttGe3_EK5s?&g()S>o}k{SH@hD;d% z*eCqij}P}dy7!+lj^8^qpYAKZNC17?udy1e`Y=)VIq+%hN`8ASy}Kc1q|Xo(VKAX2 zVfy23mNV&bt2dyvxpO9>o(E7B3`GICzVWrpYH+ytXqbNlbu?5bv-n*g3mVy-pyYoG zX3EVQ%!Nd<6%pwc+oFd=&`lQ4ZTc${Uom-}+H8D#uiFhrpo^NaBOVS{58$y)C#^xg zovYh?Zp@dKsvd++Dm!nl8fck>*#c(TT{Z10zKJiCbOpBquZr90J+@eM%(Lu#-T64g zKo^ZQ&94)d!iGtcCqRxDji5jj0sk?{-mdvA^`H-XB|OODJTem4$mYX6g_LD@-k2u* zFU6%uVA<4OZLsjTzI(dwz48ah6j!-g1cjY5>XzabE zb8(MwLPtVu84$@|N)sY&53*aN-nB|7;lID+n%8qx4Iwr-bx9P$sB}TBmM^VLCsgbj zf0-fWKrVA7U}gIKsZK6YWgp%sfzlDC>qy(@t${Q>;GCdT$(!X-mYcpSU{IHLw$ z-?VJ<8#gU60UAYGAbh0b&B-B5ER7^gDng!fZYQzELW0BM5RN|?_64oa(zDN~BdmE< zIpVL;xzq+*A#aU42oAGEG6InIEcVmJ>k5AV$P8FI@~sY)MlpsemV~f>#!fAlwdbrPiVV|c0V^^2}e`8`tldU~>*b-CbcJ^yxBxh(^Yt2tC zAv~iZ*8<>;n&ep+AdTwf=0tM2<#Wl?^FIFbNhS-!FP4J^bi5l`&d0mEI=9z4NTe2v z8hZBoiB8QdARl+zoTD9iGOf{NRbsJ){j^ETR`FcWP|jS0d}St|8d=YLwC39?$6dGA z4+5etd)3Cav1eaHZ~J!VyxDm}f%hV!m(GRgn#vXL&jM?F3_o>~gB3YVK5hK_%qK$y zF#s*avMD4*&QV{qg)oGseU0@u8>XmyeJp>%)cuH!v#g@yku#CYIBvzkE!WU-4&UbO zG)(#q(#?QZSty=5zgC-SY4Aq+4~w)ZgU4S+9D=I^u*_5!^PY1C9Q|!9YS2`R?H26~ zlZw}5x4;~ic@g_+9@r3QKLp$N=*ELWke z?%1CPm)1B2?#X!Y)Mf$&S4`2&SkZ2X^8;YzWcpo`Jsrr$?a%@izJfWw1`Q|AzAnzq z#lEdy&mQX;GX2s|Ud=9}A4a7*QC23~2>}J#+nOS3-R7+p%2E?V)(*;Gje})M3Q?1V zw%oMd-ihoE0h*kEiH3k0J+acA1ff6@Lwvrn5j%4ouylMpZ99 zhUH=kFs^Ht7jCCDeu3$LRqr+W?~50aN}xvK`3m%Y(=iF~%~%1`fvX}hsB&|(-p;&i zT2S(R;l`0K%Sz=$z8=d)t{TrS@*OTN8PhB+n|%Oj;T1qUR$I_2?u_r_VD?E;lJ|K0 z(kze9q*L9uzI3)YW-Th|J5T=e0oaJrC%h3iyVT-~h@a-&#&1H|9=wR;9@JMeK33-< zPq)$oU5Rab*JKV8BD=J1b%0{AW<=oplDcL1>n`A}NsY7Xwn*#4r&I-ei7%`xO7i13 zPeBKRaKa9)6?^@Ee59H6m)c>t5D7;G@{$pbe=afmohZsw1cW%H0GB6H_R0X(ig-o)4l`(VxR--C&v;)Ay7s?;UTYV6&|X{;7})-vC4 z%4A4Dc$?&6n^xbZX}a*&tQo`uyj4<*P45!C%$?Jn!VA_57*qrqwjarIb?_J2 znmZ?V(+d0#cv*vFY<}uyA%81v(^daF-L=q4S}-jXX#Zv7NC_UgX7Zp2)-+xvHo?Dq zuygY+(L+6w_>2@@#6<6x)$NAKm78+)BiHsf#38|TJ zZ0lFOy9E`^DQ<~6)bu6rNmhJyU_FR7K6>!D(HsydWMxY z7Xl~^dP9*BL8tk=AKZ!ZY9zb==#S!qQL0Wt*m&rxiZgQSx#r(Mj`tYsV82`ce-;1- zf~vv{M}sP#t9y&7eU*V~M8`UM1GI8+*=bfREPQ<~`r5qni;o(VabFHlrR!S)6p27- zoQMk3-QY*3XUQ>quTKZoev7nLY369S*SH~0dR?n!PZ&GeZAGZY=EAx}<((waopw#& zj%(PZG4_uHv}b39!lWEGIvV%e4he9<(l*?G_*}1G?O1kO$6`+X!aK=+{bb=GkalI!=xpn*78AW&1NO%_JekIoZ`V zl8ocM-VNeL)#zj$ZpU#&0Jj;Z`8S8SaNO0X$d3K|YpRS+;BK^5$Y9pr!ozCPXl%Jrhvze($Q>SolPPwG=R0+tL0#Jv@bbJr`_$3u zGNlrA*9*;KP5Y^);zHi!_6BoU6=nfeOpmmWqEE>Dv5##5AhZx|IaR9_%gv*v-tYCc z0!qk667u881{OBEFOJq6q`Bb;D3+Rke}9g(;FUl* z>y+&6xPlof7cX~}EuGIouRWyH@$wrDY%67$|IoKHbyrs9!u6AFDNREjY&PL?Xd^;t z{w#&k*-5%OBcx4bzJ4i*$GOPK-*9GeT@XsCH{a=GR`lAY8@b_KxKin;VS>O^rQgcO zCLZ`YR&TQ_j|={A$af0sUKHc9xsJo_RpB}@c#*+{t^Eb0v^}!1$ZIgM{3b^ z8-w!Sb^P2Q?Zno^|1lgR#@Zt6(9uC(=rk)h4FF9kbNKt)k^8?M^mIA!pbpz_k0?bV zji)+uDK}p-N&X?I^X_JR-fX5tmD8=Tl(Sq&5YwEXvZf<)Wngh3&a%_Cq>@u#2pFjT zP63NC*cA&}KP?>XXet&{+!s&ekhr8eZzBtZN1WDBp|6#Oi9*li!s_Lzq`rW3o z>~$)Z_?iudR-4gkPDDIq4FQN{k3fOYQ@8s5HB#9~Ve+QCd-2d2sR#yq!`#JWYlUMV zm%d=~aPpi-(S0Li|3+L1G1a5DZyGbHpAPiL@Y3@4wr$nx?XE8-NBYe2hfwyC8p}vQ z5%LyfpoB!bKqeJG9ub4i$M_)Fb^ONb@lX=E+Px=xgDuRF+sixDPsF~QZ5|T=Eq}Sm ztINlp9W87FKB{%6V!W@>WnD156;PG#9e`ZJj6EM-=KX4QU{H{#ZE20Wn#yH&xWzfS z>=_X)*~L}}ZjZx=gogjyCKFnX_vjk3A7y3bG&IhbNK_Cv;&G*8$TqM~09vPVV$ZME z4{O--rVQ*$O0H&l0j-`mmSw_zCJvW6TzQEGKv=-{nT11(5oa-RZ28$F6V`6vz*w6xC){D%nxyWahC$9 zCV}#&=d{5e($<+6th&|Hncr`)`XJT$U(3Fc4rc5pzPvHj9_r!SWX4swR)rphTedM) z@|)(T=V+NQ3}@8Q2(ZL_W|Jf|HyHTvBr=Snd4iS?**feup0lh)*aeN*3-Ukj2rvW@2 zgL;N3f}C;GckALdb=l{iO=-lcyss0G=_j>21ec7`kq2Gq!$<8uU>%+R*WL*Um7R!R6bocNBu+;+vjh z-Ozqj*;d4Vk(ugL&TYnuY`lyDnnp}~P~hrGVvLgXkBF95i))-wzNJa#VK z8`VzgGTu4km|JP6FWqioXYH}q0fa%7K>0>7D{^wc6VOEl3<=hy!THox^CjkG_o)aw z>fIjh;r-_~nqU&yxG)Q_RFps62W)KDQv_LAkFb&-CWUAr7kgB1rUwWG0A9n24_%sS zz^1S3*bowxPO-~2Z6Ejm)W9rjgD>PK{<~jIkk_ZGC++DikJ@SL%Gv(C*tdiK3d7u;6$_2GcV4>1GpR+t1~r0tQqBp;;Or;+5Crocmv-xE*7 z)L}s;C#BLbkGnwAW6oej=F+Do&BKGj<<&b8A>$BU9g4DRND%p5o@j{9{o4q#-P}{x zg!TCZ%a&^d9`KV$!n!itF|LGE(1U(wy?@P7Agin&1}#)OQHRa zawBVWe2t&OAI~9VeI`d;vOQkt$!fqda+^@lcp?O{+rZ-QK6VLg3q^SW+=^_I3py_R zHlt&jhX_?q)z@$K9FuRl@#&g0KX&_zpos!pd_|HV!p;Xxag&U(chZGuT))ol1y_-( zHOrDNy@SSjzOqmg^xNf#`o{oFZo|YYDn$VaB8bZJPl0a$26}b&d^WV@MdGnFu1P+FD*jlFKPqT) zsXrs>yM;bS6ip*g;wv`lh__Jj}1zt&Me8jvcJA&&Xt;BR54Bo`7o~dJ~%ol^fYIhWEn|=SAi+0wXPRGAk@Be6e>xZWM z?|+yQM7nE$k|H^}yF&z|yCp`qba$u3Bm@!ZMuY)lqr2PD-CZ}=`+I->f&H-aI?qR( zDyI53|IqhwVEPv;QM$*B#RL=Qg7h_)C-Iyt`EQ9X#Ig#j!9}Ao+AB{pHd$A_d+o04=xW?WKk)zJ!Px8lQu8!#fkRd zT`Z$xJ9W$F&saIycE(Bkj;^DNuuXchE9h4Fdv;IVtGpowutw7>I?951q! zWj(af<1-AHPsOvhP&2OJc-MLx`ny_QlZk0@r3Ja7%(3fVwG8aIaa`g4NxIh>YhHcv z0;*=smAT19O71jwcD=mPVAs<)a`neF7>`OIz?u-)O|SYD3kr{9KQJ$j51Agk8FLl@ zwbitfy9P86toL>m5=2G6S=)YYk99OBKqH+Adme-4e1Z<<6F?_8xy0@yEPjlUy>1}5 z4f7-^brdjKj^b0e2+jx>^RsRk;$V09Turd$81n8t8&(erAve5heuf{v-MkO3PC_%* zXiiVzOyj(A5{@hIt^NuAyj9))Sk-xb`+-s6KgC1jk zt2D_A?IG{PirN)D{HFWPp^Ki%LR4v+F4Ts@MX|K^Q*>d3%t5Qko7U2QQgFcqOonni zH%?*ff&Ab&@Qpd3i0w4#>C{AOtP^>)$7 zyE%%o&P^6yss1Xr@>u%wsJW+Tw}dKYgO{z+*{^<{_NoEM7M7;=C0Q4y_IG8`PrUb9 zIMzG2snpln64U_xFK7W)-)J%K5ujUl$V{dvR-?8G>YY&E?zle^dDI>>?a^hwjr#PU ztx{U$`9No>)mICR8aDT1`Hwkv^am7quGw;vpP8G3!aD1pbnlNGvLk+n9fGQ-1(WYcYcUJz9X3 zhVp49TrZ>J8)|`Oaw&1&9>cd zwBs36)?ao#xmdMKl?KXv_SZqj8cqCEw#XJ0FkZTKq<*j#ljOb4h%svFkgOSlZLU$ z!LYn&^Fq+Hg%{HgF%z_ucO716bq4qh1*Jp%M#4M4xPbHn6C8|NL9@0UJN#*X^ADOW}w|3aJHetnb0eeN!du$u~~ z8gFb<-gyAWJ+{WE6eyDa>R_jsBo>#_9N2ham1@Z9t%`dfmnVnT3`09~;F$ z13CQC4^v5hn8et7S}rFAYFy|`sWYr^8iiE+ou;C5JO99d&4EiLKs@1Yhk@Z%u7%_u zLmy-5xd04-37VBBCtvH)^NlK_06`$ao?r*==LrT3V`m{)@I0yMaJ_xkXCjYt|=R+npKe37;O&t$2EXU&+K2R-JRjprSr#~a8y*Z zzp0u(AbZqgmSrmMwLNJvhgMaR`opG*1MFK*2f2G&N;7KU%>wm#J7?P~cB z2-P+Sr{Nc333wPF6Pe?`2BH#ZLBVR!2()uH0uk1odnSZ8E=hSRuiY+;2#s#Uk*f_{br0l_zI zHn`li?MM{vOTS4X1^us*b2)o|sOAfB4FeSHj7|pA`2(HG(fl2eP?=NAdjz*^F?)8$ znK+_}X~BNHkm`F3(jRm>GjCPcNqp%XEUaRpVg3mt1ATowc(9|h4VBKfu(teDiZmRd z{V3M~{9?l8{WtdUN{zHGHt8QcHd*7z$iZ}rY0WprLhZE4AM~Q{pAIE%XM;8mtM4#g z61vLr=F8~orT-H84{a{|JRUN7{o2L6sGrKZZaS_k58C<$Ig$$`7!Loe@|Wp6-V!x; z*utER-L6bNf`}6|z7{VzAgpK>Q5S5N-Qn?ypSt-8jTN|o7)9FuK&-qQ|Mgg^$~764 zDJjFC6}5~w1CAwz!Zd0$qk5khM#CyEeD=jZJ@u}j-aI-CC1?#pJ-g?-55^(;%;=oY z>BaUF*p51x*!hlsDCuX|4U zM9RP17{?QczwPLGWvK`y!V*X0b8z`!5YydL-w{gFKOD&o9V5Nw5|go>oQ5H1Ebe zH7USm;YLxsXI{k^W}|8+_AU#YC#2-AZjP&d^v&LVVs>h@y?gU534zCeD4MLHFb;MJ z5xf^H&vaRs9IxWtYiK+8a%2`;2YrnMX!QLW*>F$(Czuo1MRcRDFi5lbvgs|E(9l_Fd?{)oNnz5TDOJFU1jpMZWwj=!&b< z+*V^KrIKH7CM2iL3P#{Sd&yS7e|M85&t9hP9CUYL0RBC`<#$h|AD|(Yw^oK{8&CH{&3LmYHsxHpt~?9*_{oc6mI-*F>)Cfi*r$|CxC@_CQ5^Km3-XEkK|g`d5|dHTOMT(|iA z=7p{K(jX59if%GwH^L%u)7~+gsKy$6!uVaLyYsDm9wEWz8H$mR1+44CGi>1rBgFO3 zU1hAz?7wErFENGGa7rBPNPk1&e}A}pfrXBVN@ROy4{)}c(Q9EM5Y)}Y}y^=6YWE9Y`U$01iQP6d*LTRSzquivJi?rNv-_;J! z7!rUQR*v0~L)oBn(o?9JD$fY_>h%&@t##Cehy_b^F5lg_LvMY8u4s%y0Q`$gSqsz* zqBLq%v-5kDh2pV4d=RC~{!O^W1qB2sZv`dHa_l2$TASXcGaBMQRW>e*#vvJJ7&HG$ zK13xRhC&3cy!Z{Q4RS zJIUZd5{*gB=OVLaxwUvNm^CbVP`r`Y3*n@L_cV7(w^62u zepKlCE3wTvqjxlI;?#4c>Zq(E07cN89+77!xr5NciRodt+=qa4sn67>PtsoDQNza- z%cXw|ty!2Hbg)0(8OgGjgzWpjkNTU#m7)>Vb0A{wy-0S^KKi+3CkFhG&J53g76Y;- zRax6i-h0J=G&;sfA~w%y{mcvKVM<|!pUeLfNyh+?v?BIVC|r zes~N!%tjQH^YS{uw5 z#S*FVEgOuqHXi`6KZtsnhF+viUf7AN>jSX}*v1?V=^+0+qFs-qkI6;8JpZyJ%?&}E zgaRE)aXj*h!zotJjBb|uyF^>fgm6Eek7OtN>Q6|R_Y?6E+LhJjn)reg(D*UqZ68lB z65ebqlt?iJQ*l*IPQbmKPD<6U6+joX89gG5`29t z$>k$wSeO!7@q)xuhjv;D{BAjECll}7R|z|Y93fevNdx6M8=l-YW_=p@G_|| zE6&ukx{A*t85PAD@YmtH)%oZo#Uy#S2#n@)2^J*~dMi9xgc{~kZb;UNgkPk~2D~HK zW=IClhLZU`zG37Pt?IN79`Zpt&wsso?Hsga`n1`+dYU9^`eS29?8O)@`!9lJ8orJ% z=|?Uf%tOzt|It5>p?v@KBGuDeFsWi5YwM>CBL|AZ=9}h{j?LqilX7&jN$k;EJzjCf zL(fokB+G0=_KgxcQ#J@;^Ldbx?Hpb&KqS?(-9EcIkp?>h=x=0ya?&~&|0?xRE~5_; z;XNQy<*5uwS{hl%UQ=QCZo)=~U3Df+pvK-kA zA$$4mW%83UiafG$wKn`)m$%;7cyY)sm7NdtKKK?{j%&i-RRKhTGG6xlr@KCuu)`8- ztzt-<;ZULZFRE?)}^YcjD&%Q3aIRp>Fz@UZi zSn&29m}KBE@7hCq+(POnHBH9SbyOK?I)4v7*(!y5UXINMv6B?%M(fLH#gTRam86v) zK`>1(>URP`ifr_Itrqmhl&ei6>(z2`8YeakLB{wjf_6gy_4Of*x36K*`nV>Y!BI)N z*#ev_^bP}DCt#BAhyM=<1OIciALm31UZiS=0uqt&!xT4@lA4d++b;wc>^grNf655d zgv1R~mFhSx)zl!s)X$k%AK1cM6lcI7cnRestH+pflX-lkzuh&jVarb$;@3G+c6F@2xL;F1bK4BY%YYZ9Fknn_PCo1t>NG;lA-j~#t?o#2UN z`Wxwbxb_QS#n9aquJfdEB+i!Bo`e}E8O-?F^t^_d*|Li#vNl#?Gc((jry$~qpLMT$!=7|$V;gM6kR zfN~5Q3*J$)QllE z`a5^Z$|#K*T?04c;Mrg$_6!ylJg~Rl%5MsRb)~Z6Xh+FEiyb9A9&qe7!kF7V)M?uF zZl^3#>a|4fEwhG$RRt?dB7x2K)s`G#9FU926KM<~heDN8-CCM`Xo2$Ac1yN1>q-DZ_FTb}C8rf~+TCB9v`1tAGL_ko=lA;L zO7_Cco%X^tOk>bi++b6J=>hPFkt3ktf!(LF%epQ&&YP9EM&GcdXEY?uZJWenT@d7^ zV|bWq)!|8oZY6K`5ncjiX*Fb61+{8uk!2x#d|mSKk5wupR;&Ft;)WyryBj!YLBW+& zO=FLvNa;zw`WU#e>4Hq@43qLCa%XQoQn7b;{WM5W$_H9}#uvIX>+QvG-;HP2Q$etZ zMAUQoV53pEGiOeFr!ykIne^QOcj%sN2>0ecc=K-oF$}u6n~#I0Gfp?vjX${uE5ost z(_|8`oi#fOAJK3b@zc~-ZnOu?{u7(eWI=aVx(~&pOdPNqAqo1i{}hNH8_f$g(oVmA zXnI~#Z-3k~y>9MBF;1f$gg3xRCOFO9h9q1d5m(L0t>*VJR*s0b?mX8xfhc!>pO9I? z-$AK_o)UdOPKz-CiN< z<+}#EeKc|;@2(rb)mPw7Ue0$Iy5PfLgtm>k4GB+h-VePV3V&xZs4_pH5y0!>P$~Z^ z=iRULI0s-IVkNfB_cZi@r(xxH?-s7*YsL043wnutvn$59XgC(r`n?+2LB|1MBZlMDbpWK6eB`fkL%H% zlT&m+jtL!O=4B!oW}S$Bemd;DAq%`ciiM}8tAId0tRV0GoMQacwBH6Yt zweMd0{|vgXZ+5N;x!)4l)Djp9d9afpn=>NT%uMvv#)2C`?IzK44W3Q%b}SdR{VOnM zdeW8W+0v;|o@Nao9qcoE%0@HVb3z9{mKCZ=9HkajeweqDv>wIxSk26vfOH3;&Hn5` z^0>bGNcnCb5BgV|Lc$5wk-{7^dZH^El|RssC{l2;x3lLGv6CGP1?#N$G26FG)FWHr~F#h=OM;XY2QpaSblJpGhyPGS1t5)EoW zoN*%7M`i?I77Hm-eSc6C{5x~~ix9Auf~qA}>7a_ogr6;%Wqr(g=vw5~IH)-M!&eHx7drd8d7GN`&Ynqai=9Pd7hPnFR zZY5VM()^XMz?;J(lhju{{KQ6O7GXB)6Qcz;P`}e%^n}y%di!IzDBjA)oG}EW!;6NVQ>_xQyt2K&endv<^l$)M*e)2H(n7iaKk?Oc0+e1H2P{y+Eq=p}f8Q}mG4ut^jpA}%Ho(8>wg z(IJ`JFF0BZi4NO4L48C;x`C^8GhbnM?5ppjF0G%^;^pc|K?aW7>7v^!LT+}|!<1#q zI4T)UIf0srG(ecG!W#nziE6w7o`^85a3c3q9*$bvQ^MbL?cXxYx4yX*cD^0TR`Wu3 z$Io0UEpTn9^o#eMv**zzL-E>l#Wsjz4~H&oQu*RLx9QbX)0bB3(kVSu0U$%V>YI}9 z^Sz*(lS1M@;#M>0NguG#`FGfQIhCN;i<-X<&hwFE5ZBpTCCs>6cwgP;;7#r+#8?y1 z$ueF#$%DH2&`I?w$?qy(Pvbb!!tAcoylXuzPP?idPy=W5sDyWKhQ6n88-5#O@1Fdhnf`yFTB3(2;c`AsrKZt5 z-EA~KpfbH|-;I6Ngbf@R{-)_1e?!;=`Z&#$Xfv`He=VJGUeT$^vVtqOXLN%jK1WPT ztTEWv>sQ=CfLfavk^veQ>arDlMXR5s-8d<+`HGjAOicCN(Z-(@*_C)yENaWqua$`mOkk*_Udsx+CaS4V)6H%HS=VZZ+lyBt&$RVhKNw6-hV}dX{MjGn3h|l z5goI)HaHD;r|-12su+>Ps+J8?K5R^%*xFJ^A3b8`3Vb=Mbu%X)JjKH8yp}`$!?|yF zzSW}0j2=7Kby^z*!iW82mux$E!&c4YRxkUCF$~!zoaPdf`g&ga*IEOYj|BfS%DlhI z&j22?`hJq8Hs&b`_}KM+hKOxDs#k|YB5ZyZK&g6}CR#JdC&-8!U~#+=8zcIe_j+vsYp|;S-A+w;6=j}t80l9&~nf~fjpY3*`sn;c}$Gw&C-6qsTK8{lersW?*Q76|cFK4Om3uY43h$xxL8ZmojQIN{e7}cn~3qCpX zn{~xbHWVCMdcClu=~eMLvMhQ(Q3N8z7A400#c}n5jcw&%$LqUQNN+2D{Kr1@mL4No6huztQp}0ECADtJ(6Qy!nSe+>U!22DDRI$)rzpe-= z!-A!u-s4u}zs?KxVNnJYnT&9+7y~xX@_L&9PfjeB+yF`VcLGdN6=EF}w!(2rx05Vt zX{$nOi}#a6QCx4j%dx6(@;F`{HWsQF?VhmUUNyudzUrwOCN;F7Zu_ML0LGK+?Q|ih z`=UuUM%QvOL|iqh<#GMnbAP27P4Ds(mlma$oh;75sC)Y4oUX>) z;cS25JYT6E$IXpZIF@v0%TF)iH;8Y%{Zb;W&~!J5Ajvw!PXCYWz}sdvfD$pmKXJS? z(%(&;j$M2R(py4-I5P6EzT*LJ4#y7H++ zJrV^=>bTUIJ&Fs?`f=k99z;WmhaN$?>`n=)uNffIzV`n!9a_Z2fG z(Pt>l=(juJG&GjjgzKyyKsK3|7K0psW?+-&*yBu_B7;kg6J@!EYeEWtrVrRMbm6c7 zuCTmqNe3!2;u`bjK5?%?SNe;aRM<}f#xvWy69Bm%@v6%ck+Fa{@hQ<-{qc%HO4or! z0XO0ryf+r~$wq0W9nlC0@lh%zkkgjEmIA=6KbZ9SA561iWnAm82Ze*~&t(&yo7lhI ze58}^tUdo0-mHf@xM#AI*g``8edSb+zc#suV$8zLA!nM*uB#-6mVHztPPdd!PLdRMR`H5~;v^ zX*`+1vTS;$+kq$nWDANB=HP|CUG=7kZjB924+V$k{M!%Mn6D7+vNplkc4{Xc~) ze%u)3_oN{&Y0A?R9>we;d^K$7gmBw>#lURJX(UEQ3k%B?>~7Q>Vs`n_^JFYe5M$R| z&P-BfdY8epg>WhJHxNJzwv~M)l`T85l8Mx|hVFBx?Bw(fUD!?_4jyOH%Ksc;epi-v z0cUdkkT>T`7ezea^TUydEdcu&O8E96VKrBP;576+a-gRp z8Xl0^v8AH<@Rapy>o}w~@Z?j{E4PN>H;Q-k!)oUGGGE>Q`P909;SRdv)f>DKP?6et zJ3ma9g#!TOCa4eW)j`UxX&vneobp|}Z~iw^=;=5%`5e?z(X zqs)C|8W9|wm&a#ri{^6I$S_p)uq*zov2^oSkgz0)O2lcyDG9RDCZuuxJQT<4u3a0c z_DjQ-vw=|DMFwC*?bx|^(jXDaUlGSg53^42scu5ZZc7ghUx_vSDBTc)8hLsUKoYgC*xRfGyTi zWe;VQ$AmV)Dk%&16!PgeQe*5ILbN2Y*+71$Vx-*n70P1*3#9q@3uEZ$D0r0qY}^{Y zY+h93_Sm}dE#_{l&L5guhx;7d!?JG4hcq^(ciUYnUw4Rzo?TVXDe{Qmsz`UkTZWxK zG+uZ7XxebB;*!O^e(%Bz<<^|_^eJM z|LGHba0dOem|*3Z+a-LJXiXY&II$XV)KGu$?QfRvjp0yXtt1Z5pFoDTr;vVXkk(x^@eJK@67hZ__v1{VyG z!v_kx#4wEjN~0b%AZZ+^J$69C+Cex(!xkfiJa8 zHGrnGYL(?GGHkK4fK|l)p-p_)!PF$a8%7kdTc+wnvt}t)GR?%HYSb{1>Abr1+fIq< zUGO-Zi<(ig{vb10E^$e8c8)XqcN9OM`(MKbmTp2amz}$%VRJjm-u(Nh2m%5HGxuVo zG;vFtL!5}LmifkBig3>kMkVOi$CMs$073gzAt?RoTORz1Ld4&#*?FGW{z5b{A?CF2 zD+AEGscO&?RPfiD)=W!GbbJ)mZCTWJcr2uV$efYXH& zLanfVj}dMcEy{FdzqM-aSO1bQ$fRp-Yz9Rwvs~b88uF~|`Q*wf-$)Lw1UZ#0HvP@d zX2FWmGCA8_up(8ws3;ar`3_-)6J`o-^#*-S$Dl`q7WX7P)rleU_rpz(F|Ij}CZPNB zE^MuV(f+YttyREIiree2AyxO_K)^z}hN5w!^+E4eE$+bsvZ7H~ztqu;5Y0n?01TSe zGUmIbE=K+=7KnWB!KlCN{vsUp<=1WrV79Fj>Jk!1uU#yrt)e*2D&q6D1>f1rMA#)c zE&eP-6$|S@!NE5)~6ciFSKS?*1f)V zkTNB?YOdi?V<)TvnoDgnb)-^(pAf6?Uzf?6;G5KD%B=Pt0SCQ3+9iDxTf81kRMj}z zfu$w}Ilc(Bkc6tgh)6bt$Z_uz-6hCf66pPeSCimDT5Q@8#)=jd2c+eg^eeX2qVUVr zAZD-&of}P4f<}C-{a5#%Eh?B1wwY*EAB0i<`;EWZ%!JRJSTm{qNX( zPwy;@%LhyPN;4~D&u4)IfK2Ng$< zhjoYKgwZP$9QoT-8wGO;Rob#XiNQz29(|cXd1B}ruV|`wzV=lWz6=jo8c)XCEkarF zjKnzfbKOR=8#o_dy1zFlo$tJ{J*cm&4U>M}5-0LI?Zp=!E;c_Of$uis1HQe;jn&tp z>TBYwd_jH>T4aN%q|A`Zpbm1`9z}3oq9EXyCePhPpz?=b8Jlz zd`*qy%cMw4Ek(c5&4&l}4p{%ELlTw~K0JhDdfo_&db{-<^K5!2u|uMP;z* zGM$eWzVF9U7eL7qq+>do21-3Xb>r@}?y9NVJL+JrQ}KKkzh%p2ib5EFbG1M7Q0(^K zF0});oN2DJ=~`XY1LGkm(-sQf76R#bK1zgH?5pbfZf)sD6Z;Kn1tuEN+(C^o#-omy z#Z96s6@C(Yz7sL+Mp>f^z5~}vO?jSGo^26~x9GdkEyb$39;B7Td_%*xzf1=DYMIMy zs2lw?um5{^W(a(ao<{vP!GS^91UEkI+hv8yNHaP2b9<-8qV`-a$56 zRDYh3F)>?i1?Lb6f;molSCiINgbTV~^1)-cQ6*MSkfT%%xqkbh;VZ$47YZyc4y`j% zEK`A~nPGt#0cpD?;m?7BmCeb!=q(s0whhonRK(3a_Odf4L=drtO)-Eo{M^+ER@-~& z1yA?ypjl$;?aM;LL#8NtpQ^z4SQLuf{Eztrhx%&{?kMauOq0vdk}bV zdn$kjs;Ow|Wa${B>huC`%-rWT@H7uI@YnNFxli|AI+~rcJ~V|A*34K8SF$jjiFJI% zmS91+h`6V#+Wz(CLRuFq8)dtV(KmgRjRgJ~^*c)lVQj#|6*P5iKf^2(?Qh*Y5dWS> zXK+ievVqmNH*5U4{e`Mqs%DqL8M)kt7MyA8blQcYs_*b}6Dze3Ak4Z+5)KXE!}!&M zdgqKRXW9{^_(7k3p_Co(l`lzUE)M~M+fT>O{j0fr62mWa$N{Z@+2!R>ki_4|@AQ!V zJoS|Z&1ufk!s0wE;B!BQ#H`-}bUfpnPJk@@l~0ovE}E}J7dDN2ac8PkTmLl3#3$}QS z44KnT;|@@&f$}`XT^4C=e-;==8#{ATOuJde<8ewlQXlEi?Pe=J?SEQ5&2VxK2YAfDfOBW5)y?i$Eka2tB}Ul!C6 ztck4sze+Y-9Ob33(oeM|BIX$f9<$eC7TeZUjn1>ReC#eyRp0=LflDj540l}#8A3O= z7Nj}-Q)Q_-so<+A>&Nh0zV|vBj8+y|Y0>4%1(82yGBhb4eXPqdkorSE*`5xgVNGCwP&dcqxCig^QWPvO;`T zdCUzdNbqy+apb3>YS@DOa-G3hZKPuvxDF5g3C#Uj;=bcEdKkz_4L*C%geQRkCsPrBL zo>Z(q5+`1sTplhypQwwf|Klwg-PKBfoTD9S86TC^)4HNP9e1u*2i>a`u(hVFCt2HT zhQH2n==8gj7ci@HuiB8p)~PIc4xag%Xx?LT*0nWofelqIZQSD@ zws&;DAGnqQrtxgdBOCO!)65!C7mHV&Otm1NBvT6lYr5P{y4<(1U~{D2B$-}SR$T#( z;jDXs6YDL;Ho6mKU+sHS`23XeESEcaw(zzn%QHHK(&CQs;;A&m6#|C(=|wZeV(a4k zUZ!e|J*@i-10veQET>wDWKNA6(#Z`k0a%rQg{!E|y;ZHejG*k1K@ zXQeufxlR*a*hcFs=PK4`J?=>S?|N|25U9#I&z=w+{i{tl=3g9DsfPOz{V0+diEfMq|?s zW1*otUS}4B>EFHTAMc}&m;lipPR~lI{-7oNiL+8;jVrxN58eRCEm&D$<$4arG*>^A z5U8I-#BVyek#P9ZmF*DJ7)jX#)4O>CKo!dXdv(CZDR8fb1)+@9C1}s=yTIL0(Wwkl z;-Xw!YTDk*UBq7pY|mVMDVDtT@jIQ^j(vz8zlR;}x4=5OsauL9^YrOWXX)?0o>^n> z9kvmedTP;BZI@ zJOC#)k-!Txf9SY#1=2DvMr$N~>95rNX9u^U%V!7o1>9drJf(DMYm1e=(4WEo(VxML zz`I*lh2UI)k2b9_lMf0xR7_2I$760zn}xo3Z)S`0jBbC)RYH)ug1M+&WSF=t$o_=B zBKJYc7cpAsOW77-n3WL5^_3VhltqQyHQ>K}E&Iph6Vs_iI9FdmWDJ29%KWUTjp{eQ z&)6R>zJ)opMw-4WKjtI;jmAt4y1x?kc#L(w#*IB%=H+m+)gSugwW7VcUMg;#IVQ|7 z1L{fk4I(A2yAxE7O(u|R33~(oL7TjlB?gK~afo7Y!V32s<E-_7-ze@<>&0qE?}X zH`WD8dtCB8IRvB}Vx7Lt|6$5uqV3qk*_f6CZJSc&sxO7 zC`x=|QtmaLnqFVCSVUZz>*;YJ?%_eyX<;1t0cS{V+Nq3Yt2sH^lw zX@bOe*?pWOeo$-956aJPOXiDPJq55Ont?81{1ebKkJuY5&60m@8}*j*4skZe7L(esN0>8)K#2` z%(+mf(O2xqqt}7VeKVI>LU~UAT7EsW`J8g~Nmsm>YSQ(pyz=_%2G%N$PU9;MA6+Bo z?|sr>p{REMlldbrm@#NL=+aaCzKZ?0>LxBFs_kg+^71EM(0QE>peS@Wz1aG%pSkq9 zgjB8L9&dlIR?Azzkr(hxBv>Qd|Np^L6lLkHE4MCI4!g-W=9h`f2Vz z5q4PL*RA#Kh4=G#S_nPa;|1nKt_re4;#U{?Z387uKBwsG$l4K_Tv@QLG3gSLI?Es4 zF*um2Tpg3HGEWn}#`kQTa7_~W=Od1b!9P2FEEQveC6^2ctiCQ=MBfP+`WJ)fm?koZ5hC@-ECs#;m%QPjv3b9(iPLg z&Nt{}{_6?C-$MVwT6zX(`kMebWk*=sJe*atdLC0yerrYm%HS+H(S|PwME`l6x4k%^}m%lr9_ejf8)@t$0-DyW#fN35Ps}k?4H|?J}w{4)>`T> z4RvYz+%Me|=r#{`p&{bgJi(O^oIJKKN~m0TqBzd} zz?HJ)tx|8D7`18}J-Pj@!b7Fqx=9ouVb%I&+Z8hZ8DybiOS~tA^AOM+_$G@8;E*;d zL^tUkD8ELZgmm=u-zdjR|J3E{mt|5AXzwruv#3+*jka=M;IA!a$FoTe09U*QfEiMw z8;=d-4*$B6z-YO!`Fgd%od@`wjTt1M#Q8Ld!s1>)#_@9x`~0%TwSkZrv{!DR>+giNxYXh3UcK9oh>AdD@n^ zcmNXNuDbg_5cm{80v;S5E>4P*f|7JaY}4PK9tAoc=6C!KU0wg+YEX`o8{Ph%d`PJuA~1r7wI-&pXp5V~ZG2 zA4;TBZX!R2W=Qj<;lG5S6qUA>!VExfS} z0rjGTPX9W}^~|qYNlXiLs9xL6C8gN9=GQQ^^l)~4YV!HDJ+|ET>Ztt(e2bx|8kj%& zpsV`n?^);QY-?XM`Hye6-?l@SF@9CqyZr#?F7KS$Cuw+cZ0*|GT)xv6Dh*1oqp^|V zZ$*^|7#CW!Wp6lj!5ilQT&St;_@~NOm_Uvz*$~Kz=?}&NGw_&%$h@_N+hSD-=IsAI z|PtS%^r)YY1h-Jie_)$L~ zt71RE7EBJKNo>r@|I~9~)Sa@wn(y#kc+9BNFDu^=tGaZEywdi;{3k;1wO_;;yUR^e}fr%iK@Hr)zE@+qY{&joKe{ySof zh{r~ALt|gt#8j#W)E~bk?ln9+ta5?g5LTPbrl5q`ZQ}$+|9idu=6N}(j>jE9#(f_S z04bkJbb#tA4WNhkn9aF3V+5Hs_if-q-}0oot;l@bGC^=h`r2cE=^4D{T$ocNlzEGr zgzDcuyB;_iQ*z{$nby&uM zi;a@Eh@EoT*H~b^?1I)$=9>b3P#wTIJP_Lz#VE}{!d7}V6 zWxJATd2W$s=w`GD`9>SK>5cWr-gxneau)Z^DGS1_Xfu*?oi`Y&rI>f}**pt00DY6^tJ#F}$psavl<(`okfKfO=V$-c z`>g!!wzBYL(p$3z7kYl+#BT8j|0rQ)R(0jOLxRG=C~`NPxQnZZAk><8F6;IaOtBex zaLuctOSUZ{Q3X5`U~J?phF}YuN>sPU-rs-y7$i`!CFyci#Ct^Tev+t#%z!;!t00v#CT& zV_pj;Xte2z<*-9~!Yyp}TqTeb9AqbvmPz3=qstq{xyFAsuii}2NY_aVX;yB#7dxvip0{o2Wn-m9$2uRTy&N@A`rcxZovIMed& zns&# z*9)DV{pS5RQ6wMd;km-Eu28GnRnvdR(8GE^?~4q%CobfVLHmx*(}i9nBmg}nU*5)0 zWsa>$3zG2aDVmQEA#H0Wk5U_Q7HIA_CM>~+Twh35J@`3mbr=7476&S@r%NOVo1}7I zI8sYfZ&uS2D^Ei_$BaIvO!gHDzA>En+Oc*Qr zLqmMk0(am$vSxnHZ9>pgp!R5zpE(PWgwn)U4CGx-HMXbt7D3^*D9QSbCLS2F4& zg(bs2*8G*P=0E(#ebXm*2jFV*?&Z(VW-$#O^uJMtn2Zd=v~Vr%c9$CX%NMmR-=)h1Dir_k#o`tl%(sbAtTmKr6#jvluO(ugSy@|gu2)Xh z`{ux<)P&yfE%-gHkmvz-MiS>^C3&Io=+(=XyCtWcGZ4PuELKLNx=0U&%5}VmJ)Hdb zsjkkic~kp<>H6^(Hv;J<_T@~$D}~`AXZ_VNW^s$vlXwaz*;n6eeBZbFbLFd6Odt3? z#-yLqdewbrcf|?SI4DSY6qsG^oA4!>4uZA77H!%1ELS~XlpfKl_m=j5>fXB(HX7?y zR312RWAMx)8+gj>+Ukx&C6;z_olW8Fwzgyag-suC_MXd?ADMb_uQrKI9lKmr$PaAI z?~1ciy2lXHgAS+tU(-(rGtZtlTXlSeHqD!c+SZe|RrI&TDbH{G67BkQkM@w#?#xr# zj0#B3a50YX2v|uBt3J(M@~jz{-_~lAZ;DoG)4O_{lRO3{o&0OwDu!cF&}~)P#m>AH z721P;roa4n()!iSPv(zMuj7-opy|7GKBNM-FQ77johvu?Tum5ba-hh<&gprj5{W)M zfxsVHpw>Xg=`vke>CnQH=k&A^CD~h_3(58sQrN`tT}Xa)IA-R39@qVZ`;J32E?!rw zY(B;~%m1{IY(!W~0x=4_vY@^xW`Z3PT>fBvgopS{&l$&Pq*UWn(i>fyMrZDS6+bUo zS5N{hO+k-7F)WAqS$8}THrbwuI`7jQTu|^GPe1a7NeybGQW8*NsGb`CNVn<9U;n<_JT~bO z>QTjhXIx3Vcy;c-fD&Yu52oI16zn&}qdV2hFQ?`Hp+ssnpRbFEnAJt^q+SH+-3T5G z7@)DY;mc z31JT>zKuR4IZ|L`Ii#R$Jo8`&A@?oo`8^uR$%g0D1UlziSNhyb!c?4T<^d7xFx89b zY36v$S%L;H=AUsF*nbE&i+VGjkf<%fGYwA)g6h9;=L z%@LCPrpH-QJ|Ng|<-Skb_bi&7xj&Y!VGJcQ4XxXI1}q}*xTo}wvdaRNRS&O}@0ju5 z_{$n_5{p1vD8F-0$`WgnA$6Cd_##YH+Kz7BSNorz^dNPW>SPSoj;HIERe3@I2Cn)axU{m(Va zM2ymNL|{qo3z1w&^oZ&hrh1zD=Cd>Y^a#r7YCdk3+sRWoN-tdrzY27*BaeQ1$V&;v zBp?B|t|pC!%a0x{RvoPC6!e3C*U0~8nIMUI!t%C#5@{z0bUw}EhT7oFFcZ`OozClG zu6(DM35Wb|g!Gi+AnfZE1k^>JPOWIUoQGAlN2Bw8Q@`7qB<^;JEz&tb)1GjB6%v@C zh4xAn!c(2zv`ERNejFiwK7x@gva6j6Jq8?yh8~Y_uTm0u{ZeZ-?#^zFAhap5r4@>l z(aO%s@w2ymU%+j~E0)Q37s`2AWp{G$!RCzo8Ai1sfULpES_+fw5})j~H2oy%%55cYpj@43&#TA&bwvIC;vNd`jw5 z+zSnM&5scQEQFjAF?Dp^${hQ7gPlxPbWhz_qf*J7z9#73sF-#Q&~QQjlGq0JeGe|7 z*^Gl0wA{8|vHp$FS_|h=+_sO|)CeikaH@)L-KGDLk83n9c1MP;Y~R4n%cNqy zcUG1$Te>>0WJ;US(1LGf;I@y-x_=0+m}hT%e6zBvBN&<(&{|l7a4lxm|7Nnh6H3!~ zQ5rY7`H92nS{G8Xf5(DvZ`AiXyaGCeY~$ADO83*q2t(m>CjNsWWH62J;fBTg<`;ga z^Hs4D6@pDr(mCSfXq|F}obuEbq3McanC|X#O!pWTsZG#EIj@R-zb?y!M(mo>@ zffWE`Sf>COU-EO_hv}G3bzH_-!aX@SUE*CD-da3Pb4e)D55S9pAD1NWfK10WsFCdX z-$?eH`@8cSH7)$yYTPx`d&A0x<6R)ks*1sOB6Q9!VX5BN)>$h3SB{OpiEe#wgjlrg zTOwYQ53cg*mSo7BaohFrui25l3v>|^VtpfZ*I=>tP)t-u9Ac_ZPLMgBl;q#9*lL={ zL(P4&Bw7XSMr{~d`m=d$YB2O zQHt_Av)2Gqt8aVf-+}ND+ZtRwMXEGxwl3MBh#&)DE>Eh%=SH?zDQDjef+;@NIJSw}9e(L96688N+q^<5BON8#=o5cM!gn=gjix7|8kMop;0$17B z-wBEcNox@jzH1l3t@BD^retv}G)7KW>k=si3`F2D_Pv)=&>nuz3)KCXp*{Eqqmu7K z;7*R<+-o_TuQ`dQvh zzQXv9ugUQmQj(i&+Bp5>f)k*w{VJR1kI#5;GM8q#`?~@xL)>Fs=JKGWzB=@41khyjC&C{zEA*8SD&9ms$+M=u0rc#4c@1rAqbfXHBQs|M8!^nM! zY;Le#A+X_)(Z*+VS~HT7Rg*4R3!neD_a?7U+ljR8QlE@w^Kr9X3nIAL{$i!>PLZM2 zzpD47pB;q>XzonV@vV1B49Wxk`2eU^?oU@v2tI|}UBSb?k>nWBJR7wWX)I7~nk|S9 z`mM4W8xWeP4GS4o%JQU7w)&I=+Ga8dE2oJ-((J`xC>S5^bXFvUz9{l4kC0s1n3T>p zSO4ssiTyrnS5X93#Ym2jVKf%QShdr%4YHIORA{-1FI`!V0Di(FuZnAt=cfGrI^q46ETb-#uqZ4dBe z$ARY0`0pSn+(=WF_`z;tDOz%9JOZz>|U@qY+*MCU~e^%N&@}ZXN4OpM#~Qt ze$kCpFA&K4EJ#6#zNDlHw*2`r%=Wcjd|{~Mk+?VW7=F~*FI>c_or98=(m7yU@n8Jk zrPp_Gg;cZ~Cx*HVGXF*C72UzY??2Ci$23uK3ZG}SIHr+nQ6!eN3&`Z2VhrWJ6E#)k ztyqm`Q0Y+L1!tCi@oyJwxZy0;J%k%@dHp6cUKJh8hL`YwzQ3lO_h6M))1FjQ0bPm^ z)`t&LwPgJ3xvayxR_`cz-=L}8>V94bJX-i3MZ|ShQ*Oq`<2{Ie^=pegl7+PR+fRcDyHU z>(PLlMN&ED<0WDr>*pce*8Rt9wqKZABZwZHR{M&`W=~JWjR|kI zrN+k4aI=vfCj|(NwU>BZLhxPZ<9z@F@xL=(ICT&bXF0s}r%Jd40=rL=E-<&`v@}_J z+)KJBH3@)hfc)K>W?tC-L6p^a^NZ1qrY}=L+r%1Qbg)%}3IYkPt~-HYjE<+-IamhJT>>8#}V)MeNEXEQ!u0_3_FzO#TKL!gZAybtzuBAs6(3W=UP zJUo%L|I_o5FBiUf)HS2ULYiN-xX&wGLQyVb13s1e=28Z<9Ni+gkd^=2H&FO3xt%6Y zv;K2;o-fmfz=Vx;{;o}|I-vL1P7IYS06(o4)48BA0(V6^d1S5H%BIh;S@W)I7|oBj zo_?n%F<|LB`!h9&KBVovDHtslJ~gn;L1ZEg}fSh zamNh)&MgkRlcQ_RuG4wHJ9IMKZOhZ;VVHZ4g?PhNz5Zi|!doEo5bE_F7OywA(efu*wkiz#zv z(M5*^h^5=CG+FY}f}s5tzDrJfwzcJ3_ZdYRLZ!EM1^vSa%ca#9g7*Dr%ENZ|@Qr@` ztH$-Q(f{?xKoI~)M~GZ`b1P7k$Sb^u4Z7Y!+*;~KRvZ?Q9DxN3cD>j*UlX9vB0ge^ z^W?$%r|UeT(ttVk<$$H_mw@}vlnfeROPe}&KRoYUP5sW_@%<@dLl;|>5MXm#zt+K6j`X(&Cl~BF;mH8G6;Es2?5z8r1duKT zsr($NlT4*=f*6_lJ7RvY0B8N@&gugv7Owf!>gSRwx5R?mzDsm{$=nDJzkIiemQHHe z6xIzuu$pBFa1na%z+vGbu{Gk`&?;!&u(Nj=i)i*--4&WBb$9NJ|4_X=$fHgW{P;!2 zpnhJ?&#TkGN$a75T+E@;WG2S!mPx{W+x3;ZWS@nD@OXC91A?kGPM<}>nZWLZ&W`8g zmHB37TeU37MslSc^fu)nI@gWEEsKB8^|APu=goc1L7`ij-WE3{y_YfKzGGQWgJt>O zxWJ3$9FA^B)3aI2Mk5JpA<2Iv2Y>Fd>=c3OLjcjx^b3Dz-bY zVM}`b#{TT-g5{@rz}ja~_6`cM-3r6OK#r@5>QjojXr_8_33f$N46%`I=Rg%>%{x4s zSnKwcV^P3yZGfG zQ#`1~Dtkdatt<(8TEa7&^TjIjVcs0uv93cq^33THR6(s6nt88Zc0PK zNBAYNj-SR`J2X-aW>ff6D--iQ^$-t29}+Zo{bD+7KE9!2!{UCoH^vCI(x@(!qO^)| zaGm>3hOoRBY8+hL8OmCYouS9snqosYTgi)M&+dU`T|{4E2DBV*l>MrCZ$)5{ks$Xd zw{Uo>fA9v!l9N?cZ?87h7SbkCc;2D+)|mr2&*C3+@Qrtn46-r0w~<*+r?)xLB#SxD zJLq$ebT&t)W>%azChqzAVx8Ao;lqr)_Hw85l-%KZewi79V+<`|!}t!A$$cZ_rP+Mz zaJ%{yxF=$oLdIJp?&@nBTC51V(*ZE}GlDVFOs8#{S*+8UGRpmz zp%j1Ebcty-TPcfEJjy4||HNuEEFAt;-~3v*@{Q^S9703Fz4%w7ber*`;g{(3^`^=1 zdK54Euf7nVACGkC&OT=)GQ9UkwbIDm2I>1Q(A!I4WtAZ@fBMz+(zZ%?7k}{u zX9oRB+z0+(b2`RQpWK7QT1+=KPMx*k>xxWik-_bE_Zohsv5s#g&rL)NBQM8hXoDI< z&0W8zp0SzJ1(Sp^y5N(2X1$jAw$irE4PRM{?418ZPCo6i+0F&#)5}rh{>HCgZe|Fx z1s(Bl3mXp5D<`uUIv-vHE8QJ+^{=FfJLXUX3^ulh4>kP0>An7J^e%z3;>-Kram1Cv z+i(;7H6ny^)rv*6`{)I4nVmXV|1UIeLigInOrj3;XX@NM>JdjVuA(P)%wqnbI@)t* zJL6WgXyRVIiYUshFx@H2EQFieSzmbA=7(*@F7U~(P4g^&$Ji}8o|D3N6pkCtE=4Sk z2rr4EPenEQ)U^U&zaJn6ohZ2TI#y_NF%BLbd9EsT!n#@M2fc2SBF@+?Q|VteFw<#F z^oPn0qRv}b+XhG0uW^Ad@A=$D7^Cuk_9Q$V2bWqNd=)- zgS)vx$TIMTa>kp^ru}N_+ixd@K7tPExoKn0#YN{0vzuSx&pMptw1li|HrFP>c3pDL z4WAz3&fIHWsj9RanMZZ?{3AvP?H{lqV?}lt23&@c2LF|PVvB-@A9(KixeyVgUrs+M*v>CD{@ z0*md-S9+pfX4ZoKGP&-|SO+v_g%Yp+q4Z@A89(b-f%n-+R8K!elcxPlX0FG?(*2%; zHlg9=!>nFrdkxJh{{Y@_vG*4eN5?uZ%@{G<8;2hzf008>2&U(=9*Y83EPurij%V`q ze*WA>hqW2D1W{(^<+N{tgpB85t2i;uh_6N!Ns?x9%N}iYELy6BdMTH*dS>v|XL-U)&|BaD zidB(fjqNcX@mi1xkhYlR(Jw`!S*z%qn)syQhJ%03o;vo5ffvU#pZt1IffUXXb?ud} zoBMAfm}3k~j7h$a%W?R};+OC0Ohy^lOZE!HT=+EdI2q*Chcb)ezj(R#rB}VHzbM9} z<#WZFN3e3)v;vf-(pnSnA8`Pf=)@Ze23S zcs$$I#R!fO{1;?JfddP6)vp%plv5F~p>Ne|=XGXD?yEbieytMK$sPgQi}5YWoc3Dx%)OGl`6v~DF>~G$YGUOR)#N$qRQ)zYm;&HEIQW^+dcyK z$Xd%d92!A~8eWMebE{V_$HEO~{1$)W=UccFd{$A`vuoErU(fzsHKpZXUQaKjxi+R_ ztT5oY#9eB@GS|QGtpgU%6WiqFKPQ8NkPTs@n$3-mL448ruYUJ1Y|O)+;ac4^>+lnS zbHMdYpN+v0i4Pk;x|DvK77<`7H}&95gqj$$>HAWewRt89P`?|LR#boPoxNV{oiwEF zluYn;g!T_?wlAj>CO=1r7+`imZ zyD4Y1;Ct!h?~!@?v3l;d(1pdz&<1C!%dhA=wGfqLaD|0Susp1z zT&|w-v#hOd%*+A$2Nty;FJ?;o5^H!)TZbZx1#ws4Qiiy=5jWHNW(?*xn+j5Ane1&Y zVl^WSqPU98ODs2}EGHEmW-C~F(KgvrWj8-_?R|uP(68y%?x)ez<$z7%C?I=OcJ62w zEh-fAv01s$_L{QHDH_`e{WPCf^c7}bd zbv49Msdp;7`{!ljtdV&1=iX)t2Mihfq5#Q{m7-*@y5k--y$$I{aF*@ZIDkms99D+k z@5JAV(Y}woo?HlYI=gO#j53|pR#+1b52)MvAC&QYNAFShee@Y6jTz8w;ipNW1#4OrB$)S^JDw~F zi#_aqOHVoeMp9*(J2B%;lkqCimT}>b!Y^$pyV1qOmB4$&EP}y4v|Mp*)uDB9F_=jgy!$A<(?P(l25)_^er*x1RMA-UcNi3 zB1M+YdmJ|n6p#(ZX!-$KzO0@zPq&)U(It;y18VL3wtL>_iSDm0o?otZZPD~yGbLnP zQ7S1)__@$}{(Iua{by9epx<9aG=c4j@i$!Yst#Z8_2K4~;75rdgu{lIVkvJW4ktdN zV~8;MloH4KqGCxXfRjk5=hG9(M=!K{u4P}UG+}|D0v^JF@Ngx&kUpF`-_K7quBXVo zuioXW^_@%30v_b*U-FitT=z4KXP=_IIop=v};G~ z8y_8M8)5U3#tW*5Js0CeK1UNdK%LU<4+bmW=kj=mo^Uyz4la)=n13INT^;i8!tNhJ ze!zB38MH(UV;msQ?Jz-H5OltcTnmm`i;IeZ_&-KcbG`lDC&}=fI%RS?HaiOF5o$rP zB{S&xHip0m4A)mcACY*T3jXL9GAqQbt$~;RM-vR=l1S&K=G2siIlpUDGIYh;eHPm6 z?83HRm7rGl^Xn%X_31+5rVV$^28c{gR*^*YE`0DZ&wY37pclBdHhrdl0FT%LII)6PdxbZkfz@(@Bju5e63BnK;`gB?rW{2)`~ zEBEqPPIKj_LJGaf-}*M=&G7T*K!-zqrHJrCACms%PV9t!%>q`I>katoW+9am34x1_ zL}znvV34D-YP>QK|Bk*-{$nh3$@;b&M+eHoZhfBufp-45@=L(wWT&EFk#UtQ)6e_k zR7g3c#xGu(D#H}yXN*MyMJjZ8cDT_5)0>Q=irrzB+bSG(RWg-3jRw zFUe0Tv>k<~@=%mDe=C}PCmCB6i^YDp9B+w$c7L87`HKY?aul~Il0H`PK2J40ICY%nhc9OTRV(W8`8#FFom<>4E$ zw~mw1zV>*8Il)#AzbXW?_)pa8%c}2CF;caLdX0=?*11_a70zm0z;xyJ0v38?MDMY2 zA|*|=H1CBCyUZ;#7p{H>1Y$|OVhFCn$L__$MAR5?{o*@Y1@%!7GtgU}m2U|E_bT|2 z?LOnya?ueYo%M5f@Ur^LoV`>Ra-f-2`=Gocdi_MYG?$QN5Um}-Ozkj#l&M$wv zYB8n+wh|PX{lU^dKG|_d0Om0;ZcOJ{J++vDm&*~Fd^v!*0niFFo|-RIYZ(wh7QSF} zD)bM*m&Gw@`whlP#Xp83y^=uPHdxP|_dA-ZC@m1%wLM7*$aKrtIg%K<^XCcTdv7OI z0Jv))Vw?7%g%Y;)5kfEznYa)-eG5Si=oefxtC2pJDQd9_fCahw2R zoM#YkVc4;?yBOQ`VJe%jz|LlLF9i_8!Eu2@$Tzj3lN!s8F5)teGSkI0HAQ3$QAWES z7dGBv3c!?uR6*B;CFk`(c%M@(9h*&N?w^=DZuDU(EW}gX4w&$*{l;it;3FMgPL(3x zcd97ZGmz^lV;LTptI`0s_-*l|k4jI)o?yG>pMDM=xwot&wkNp%^ z^hKaEh!nY{s05ZpwDzxf`|W1}uhLI%r6<;6iRl94vxuCGEkO6+C0n3Vmz;7h#K|2- z>JAeCSAt0=sGx*@0bPTv2gYY>WHv06nZR3}CXWk#C*hSVE*gm&3MAzL%Im}wJ9wen z3bK20x*aSP9ZoXsdd-7)^^7y?)!pm}Ma0Rvke4-(hsc=JO6tz}g>wdeS*9SeD_>_N zq2m+YTbx-5OF+jL`X;7o?nr^|N5MHS>&6>by4UU%A{U>8xNGWENAUAA7WZX{spm=E z109-#{5vs&^V#^Z^z+B-El0g=0|tx3VifV@=QG%^y|+^Gec0EugQr*H#{W+19xbuE zn6%c7-hb~r2$p|Iu3r+$Gf)4_9#3T=;5Ey2Xn>GpN`4Z8w4|KLQ!C5Vfrb9t^L6Q_ z$PYnypI!(eUkIA+Y99&(jS7o> z2f)Nkh09J2fMOk=8!oUskiI}D&u?Gz;GZ&FL^9RzJKLD-3^dvNr>umI0-87D$wwy+ zkdg~Yr#l~~PaJ`g>{g~R)?|@{Z6f0C9SdPI;Z!2CCd@m^(}*{6)le?lv7nQm>Ru$z zxf~~H7$W4e2F~SISTXg}*%~P;XrQthKrXS|-NhSYJ5Xc-&+S_+1EARvcqqoJgl=G@ zJt?qwJ)$SW3eI8FS+$8BCzHdCMdq1kE|LU2x>fjh-rO=iO!Z{)|*?1H`eZXsGIn17q0@4 zIzimg(l8Ijs!*M<{6<_$C$}J=@=^xEL++w*u$FE4UCA@C9%YB^RLI{q%c_?Zv~?L- z!E}*7d_JlaXlq1?YnA?5MLWA$Mt;8f3DZpkK0 zPAOoBx-((Q?tzfTTnt-j(6Im#Kud^Z$l?>@a0<*^%&ea@VNn)U4JIhyY+SZGj0W_b zgyQs4Dh3BV$sBj!upITZ#y}hR-YW}wk@YLxBK^EX!r4?Zge6b>o&J0t0T3e+s4~LY zur%f?K6`^JcFWv;pw$mzQ1Y#|)aBmGHH$x56mmWQ({^5#X(IIw8oy9@m`A&n=TwUw zQ5>CD2iGFjh1(jx=6$9C);G-MWvExo>cRC6Bl-<2hO|A=c|2BXNUds&K>mIj z3T%)+-MmEE)sMrMO<=7iM*3oR3=NcKH&q=Al`G2&D_fOWtl;p-s{;Rdbjho+)N|M^ z8)VrCEl9d8`-4z$sLY{+8X=VV4F5gk&bVf#3+h|d8&=7W8ne)UW7e%=Q)hS~Xb}w( z@w@H1)!zMmW^5u=>(c$$EdoJP`R~2&0glINGFFR74<{(E?^k`@KC+ zk>Z(=(rLn%0J2o<}K}c(WU@Gs?OhW@8O`dzN#_x~ITa-iB zT|tU#sM~FR(=Tb_%rtL)lh;$pZ?8^=`LtXZgv=a_xeRXGbY@e)!^kx@5aXgnUS`A7RzT~8Cy8ruh+ zZuF()hn7WrwGiRGH|V7hA#R^-p;uwNMb@ISKE~1e&6k$)v31n8N$t`yg~iW0wu%&~ z-Jhiw@L}YldQ+_RUvEMUThy)=f~dv1f+v(wl)S-;C`oiH|JwxtK{w$w@SpW;CR#U9 z{1nSs6Gx$lRglJLe=t9M?A8F+AW4OH3G+%hQuwUE05BZw(R8BAYCphG8SqO~vReK*s82d#a_*L&9U-N_uG~DDI>1ZDvKi+ZD>j3%!D!L~bG>u*sum z(qoY9Hg9i*zXddqrui9_H-+nH93C%?^DVo)AM00Pv3GN!7O1i5@QP0!y!J6c8yOUZd?b&11JI>IpT+I?T@CjQ8?lI9q zEq*=;>$TkYH>Lyc2#>2wUqOY%j$ep@shZN7qOFLnunGZHbZ>ngSN+kMsD#_j2B0Gr zjxfamG4(B(qzwvN*DD2fgn>}-{GC-1N@^}4iQyqa zSD&~c6weQgG0~yOyG{1V9fxa*Y18rC@Rlq0@HTkFU@+0<53-ZucbC*P`3++-`Lx?O z1*507Iliq_&td>d=M{!Si5$5X!2@goXj$s%Tqj1u)E~8cd6Wb%uF%p1MSg(amZ!d6 zds)ev>rs8|`{uSUrQY*m4@CaJwCcnoueTFcdMfMFJ-zZF;cFZD82}np9MjC=oBUU9 zj49N8>fYyVU=(LbbG{=9!UjB=iA@u6Zrt~1qR z4=(*GfSv@0=ksPapl7yE0BpV7H+A8UIfQ(($c67Y|KA^8Q4AKq+@&l;6Ky?pOwF2~ zP?{SQJWi;ZW9$BYsU#{l9Fb?^EF?FeRNIYKKfE zk0WHF-79I|Q+-`9C|@CYdIuEJ6_&?rJykLyM?=d&E409dg)}CDz#|-m<~?NEcJL1W zwDR0qwwrNpyk4UTP{Bfm{5B-qVaCrNX-IMo7)C_&paiWU{lO01@_z^)i|x&Ko5MsM z4hw#`i)^;0u<$J1#~ft@d4B?V7FQydhbVJ;uyMH*$s>rl$GaX>r1*S?mibq8)LR_; z7z^j<+e8}ujRE=RuuTnBu7jtc>3&s4OE3FzvF2$!R9Iv{WAi*oMiS%V6{A~Lz5M|d zZw9;2YQfKRQb&>Q9Ll!K<2~J0d`8!7GFSl{PnE}wZ^kWUEZ-p4_q*`+yKG>FF!~%O z2q4`9#{JMJ>3v)DctUjdr)St=oO+_k8m=F{LI{L-S+6Qux>&7HQB|At1rhMa%0Mrw z=A^NevrhOuuF|)pwwxTC=okoKAm~|+;i|plQdv?jsgOGIJQR!A zAg@*xQ1*1spFYCocXMXuXQYKfxb3N2=rgY67T6B{i@7t@3k`=`bbTU35EF%*8n?O} zEObE1Z?%aD+7%QjFCr1QxwiWj(q2Pat3aKz930~~)OJZk*)ZoPm0VL`J5W~omaBlw zJu(6DLrzfotGLAFhQ~MM%b4`O;-@CP)mK62g*5TY@QDx$`;b^(W7XtQZ-`SZ*YaPE za%Wtroi~Q==6=2_SucJr!W$b-T|8=%aD4`}{o6Y-?X9OiQGt6tY8sTFTj%d} zZI8AiPxiYM{;MRMFGm&vnBRXw_)*Z&lZ7Kwc>b6W;4fBScc+y6yKh|?0|_AfBq;Sg zQmEubH+B`~ABx~`B^nxNV6!am+q_d&$9{F@YmmH#Y%68^MU@)4EjuB7AQeZKEA)7n zxc2T-mg6PwN6keZa|+i9Jhjrms&2l%kXz@>jGRA>&4*6k(<#jgLv4c>`rWde)YU&A zPFFg-weaT6XF$$w2e`ZoF4;-qB^CQmmQMu(w%$)ME7Bw_2EM%ap)f_0Hli}2mYKg5 zn5o~~xr))(>VxR?y#oz$9^wmZz-jWQ{fLwNLvhGsef&e6lR-$0%!eg~_j6!1|5X6Q}`6|8GE&H^*C1T4ALEjC;e-Cp(S@+fT6OS(k_-8hJJv zJ%;WW(yFNY_U~AkBp)c0XskKV2qz#)UE|o)EPbkRlwDn)Bbd3y1ib2^YJ#cr_qg^N z1|4tHr@>=3M}IApq7Pcu$0KWvAj!!QwO&6Nn(g9wH>MT!stY<7)@AK!`01ig>wnQK z)9J-NoAVPd946X)?!T4gwr;vw9$6vg1V}npS`OazWw+I4j?H7E@YIx@Pw@HkW|w4v z`?8$x-0DkXs;{cT5?%zump>?TgRGxNh;C1XjABP=Za*C#76pXGJZy;h$*frQj%J5| z@aA_zV?L2P;;KG^u=$IyH887Q%ja}>(<)T*I-~q9n_P2_G+!i9L)%it>`W?;s$n*YNZ;j$wIL@nlTDe`E_xe3OiCEq*gJ~FX4XPw=GxccW zU^gUl2xL~+;ph`ilZs}v7GakGF0u{UiT$;0g=}g?CVZQLbgvROoR-*`mO|aX96A|7 z*Eov{T1&lcWmYlrZyFE%437{Jpt;%V0rUoK8|^aL#!W7dkJ8oSuP5{Mdn7><=aNb9 zL)RidG&&b_m(r*kW6J0aryPAH*BUbdQw?$$I$iAf#poy;%ySuS65w}+pMRm*%WVi+ z6Kg$J6#j!TOY^r;_vr+(!}O#gboc*w0r0LRTCHg|(hzl$S-AZx_#9|gmnPay8r4p-g#|3aqH=?$$2p*Hja_}M z1VtIgrJ}{bv4{l=mjN-yNs-g+rge%q?Qm@NcUwYOk7ZAcl`v_~Z}8J>{sLPeio|18 zHrwDdrP@1)V_)~0Sv1kMK!MZ`&q-XdNwc~~Lc1nfWv`2s-}TUqjFTPf9svGaLodig z@4|{aDpAhIhMALweU)58wZdq|*hqNn(phj{qxmbok2g`-cQ4xa zTMEL#m!fRm50Nf(7PDlvwmja;@rZA0SKEu%DYnSH$O`kmiE0ytGs5X>%T7be(2To{ z6s6j#>9*3>_CbKZL*g4eG)BP~b&y^+90P~3ph4Rfa|e?1RB~ab3?ffIG@>iiCv0f* zuYw=7&dN6TyV}r&C$B6B$LwYm#|g!g&a#1GTUQP=u=oQ>NYve5rnlxm2EupS zG-GJ5;C8qy%*SWhpr-}_qif1L_+PYZboeREIEjdF(ivk^NnAYJSjscE-^OfVzHO^3 zB^-MKz8FqYZUE!ROFXaFE+c1_5NM^Qq$KJGOj#dImV@M&LWZr@#KrToz{E2C-CR7* zE;+nBnf5Ro>XUmDa_V{N6Y-Hv2ja*4hM^*!u_f`tKmhPg%e~*>u2&T3A4+)k?67BS z@--1hV^_jH+WS|RXc_#W#1HXgvhi?U+V+7Br3Ve#sh~%)BhJSSeyR!avlwCPjz|93 z*uNF&u;HqN#vfKTap(kl{kEdHL?8Am_df6=LwoI_72@$^on**!ErZ_>o^ce>il{Zd z35nCa;s<*hT;M_x3qePB|DH5r0XP#+p@hrxXf(z*I*mfLA~I?rNznbf_w-Pu`M_Z7 z$MrD;-Oa#GNu11p7mjc|<&!{3#MPN1*1&z%E9#pB{=X6(GeG{_L!8@i1b@sd5ZhR0UvWIN} zk7%VYlXDwFdEpwRHKx40?oiAXg zjaqTmlk?Sxd>_kZtcp;_E_)Sc<(+M?rNol_t1nIC=MfeU@$1^NI9cM^8Z28`&Kv3A znYP!F1kO*QmaQNF&uoA&!SbH|Xl-IG`Y2&rqmf}^Kp!=b{faJ}(_*f@JIa!vh|U2! zl0RWw-!^$an_tqH;JLi}2bi4ax|b*1qv(6hX14HX(ox^DEVMnd#O_`f;FlUmn^Ao) z1(Np*F|Ejz-fI(J1_9%}k~}~t!i^XsaamfbHl>mAx%E4ci^G11TPvJr+Mh)W)|^8t zHpCykBLj_jv;;wbrinfS`|z-L1&s0;vk>6bjoaQ!g%vHD)m~M*2f%8v|Jm*X@?hr&*w;^mR?;l_p3N1=~fd2khp9{d$t{OqIWDj z6x%arAr$GH9qwcf7r6b~1{$_(xyY-^?Ry805^(I^#7ihreIewR`Kq!GdqGA650m75 z4a}ZEaANunISniX&HV@TKE^Ay4G{4QX+KO@&GEUPGGYKMizw%Om@LGuflYc;Uw~G_C4{|5nVUEfgFSgrp z#9|*mS>kN01#G_+YI~!(d}3#(S3%&Q-THzmb}yyEi=1f9+QWX37v6`W%idF#rPFVf zEEZ{(EM0$n{H4A>+K|e5U4N4JD9R{KmmHvM%}8{@>VUqQ{`cE}E{mjk+v!!bR{KgV z#&w}o;sGty>|6Dn2)p#(zw0RZcYvcARpu!Kl_k0sS;0ibGK}XPE@bLoqnog~! zkfVFxDNuc}JHi25iB!JRh8G{IbUX3$Jewcp#7cq?@TbZ`>!p%uTN;o_CNP-asl{ry z9c-Lyd$;vE_k(ZALxzS=&unZ2!~3Jc{Yjt;&D`?)C9cg5y^oCR~#Y z^mo#_!Ja1BSSU2%>0UL#l2f9~1;zJfL7TNbFS#c`U)k^QZVyx)$>;w8k6p4L1z|C; z3zq*wjG)Sznc3FSkA)9mj|V(k@@lBnNliAFijkquOY4B}&aHRKVxuB#n1^=zB;JEA zZ$r#+C`cwVvJA~dhc439u=N=n$1vviG4Xib+o!~q`Q}BA?2*3u*~5_`*}WWWz0V`M zEj6cYdV(F=*phxajrpz*zI(c(6NyjmqK8L(djs;^THae}8L_0?#c+}LDm-@z{w+}s zi|I#*;W)4(;HRjv~7kT!m2~@_$U|302!PO~fD79d3hk%6GK6G~KGlW;k z>Vwi6Tx>05h115W*ClFiq2D75EM7E>Zq@55X1*ilb#d_bH8i=%(5Emn&f6UpxBjmW zZ_`9#&0jRVoCPp6O4 zTXbX>zgy%B3%I(@qg&pN#J$V>dPZi6t+<}8Pl_eRb7-gZ6KQGK@2T2t<5V2Ek&}j_ z{UlJR%gc6XLL{OGli;r7JKl?aqb9S>%ROy)eR02&J;j#{gu>D1;UD&?K`IY=wSz*K zkKv(AKN&`JChC?2ml_>7?PMm4$F#=8Ys_VvLo+Kpf|z#5#3RYY*PhKDY=ynQH;s=+!i)IFOx_6YOXW#d1anmMPhpQ5( zKsh`%f^kx*3VA!hnFQ5(hhZ-Lkt8}ozS&yNxv$lTa=MX1RWBIIwk(m7WN#%A`(080 zz3n#M=2$=gO^ZR2k0{FHlH@HB{HS|9Kk2H8kIoB65eDmPwVlOz9i~lmY@IZ0s}19UL5(cm7VW_BGL%SN(@kpED|miTkzCh$ zLeR>>6g%6eMy=huw3#UUga=$0xM$I`Bw39DxtV29ktI)FbbSe~iMno@cQEE>E7CvjuYAsN(To4awRKIr*TAMYQ&oi<8zHtQU0n)tdz1fTW>aY&C zVX^K@Qf){-Bcbp4DS4%KN#$8$zQBXg zsSOdKPzdp8*4F`9;`1(*f=mJ0$#Ft|!u34u=u*u6HfDz8xGGy$orV>NFj9juq);U& zW7sxc#Okt06nkAy7_EgA7{9DF^oYGi$iKkV%uG`{<KQrzVSbhoW{=vsXqbqnvbHn{m-W2$TKL1>q#&o`H z!CvZXG|7o23lSY8Z6l)F9-T+%)5FX}Psxs2{=mx!`54wZf}7&$NJa?(AV+@;AbKdH z`UzERMnqBHvG4rxWaB)r`a{jl^A26&$+D%)%-p+L38&}Nv^9rIPMd&Aj04}N0?OY= zU&ra)n4Ose{)epZ@P@OGx>ch0h(20~5vv z5^eO}>!_pO@ve2(`tEoCg=anIoPGA$d;hA;8N?M!*K|sni&92(X~dT-=AC+JI6VOm@&68A+w?6A1plQ&x~G{&??y7p5#1M46|;FKjJ$Df@4`(q`c>->ziJ|?IUDm|AWmz=leG*x9~zE;0WRx%yh9d1sneau z0`h9aMjJai*fR!$bScd8wW!aPnzF}z_A)0{Kr8i(T7&uhOF-V_ValY53!UjiNxDb` z{?d9^I#+%kp}_?ztX&;l)ad(q^G2ALk}IBiW872a^5(ep#&$=Apaltw(%XV`oIxie z-K3wYJQuGCWo2Y00$?j6uPLnS|KbJXjA7FAtfU>kS*m`^^M0lQDgu!0G~e6{#Y;%; zbeOX-nr56ez%caXq`azk>Pr4zC9(fS>m6=$Yd zDkn5&+||q~>JJ`t?NbD>gezMJj)+?Yx>7CzuJi(ZS<;GEqM%kELo*h#4PnX6!ri=mD{^%3jrI@4Un<`T-_Gl74v1~14mi7{lVz>Mnr6N9x z-#Fy9Q*UKLublu+BCm~SF1dJC&-I&YN$`TccIK6^N!?c{oWJxU{Ee#&X?6qqRA%Oq zDFo`ePGIglM7ncISU>aOMH$v+GhzF#$^}=;oR=Q_@jig@AN^GyVS|UlinBrYa~v+T ztG_0x(nT`Uy+wJ_tA_{U*iLxEmF$)e*q|TN*Nnx!9t1Ityb%mHXIhni+xwPY2L9Vz zg?E-3$V+k(XznRBkWU{jJil7t7zVtQM29*r=l3aeeyHS6CEwX)V6CT4CNo6mk?R(p zri^%NLiDVTUeuxo%b?oQE%Rr_+#AESRO#w<`WE%&+QXSTh5Xsw5t1O z>pspp@l=Rl8hA%VzYBrehTzRH2GcBRaRiGADH)~6o-UssH11$ZD7of!KS9h4)hK%r zs$${{c^}ZbHkMw9i6zCI4u^@6_I%^^XCIL<=RI)c=tvtO_N((kUH+F2_PmN@C6AHB zes||{bC>%zD~mHrAqo)dEgD)rr>S4mpM+FyOXJ0kO5&kO;hwls6}dYnV$1tIK?`yH zJ$x^bEdqk*h|ze|i+7zs3Cm+Mk=AHRZv}7eU}gf#-|2N|e;1oy=P}cYiU%FIz=p-f z&5MHM?LmrlusB1|w4{Qzsm1eb^yQaCWEvCCxjV%a^Vbt@7#OHr1sgx94WZ5T#3*lV z$7OcxQ~3&QDyr5A5f_^u&FBxZ_1oCSh<0yA8(23CWaP9|aZU+XymFYqDHY?V3*5l_ zJI497qwg3uyMj@gB$NjHBJgF~>Jb)A><>dRXXC4KKivxt%Uh4lC{v^oQY6*4I`7DZ z4PvgnD3YiGPxZRJW#GeMy@zHM4t$#XI>^SjsV_pGJjxqbF6%&!E%4Y4Vr@Ze;lo9C8bkrnaz|)bEg!Nxbdf(O@BDfA zsIy~A02>HOOZ#5n3}@>7DTDFO6_R{t3-?a~Zq=4W0j5r2Fet!@0^U04 z0l*xCuA3<2W3+K}Wm2>gxS57aB!-SSH9vX$H?<8-gC~-v1F0qh_sYl`kKTp$UFxR=>u5MzO9pAOPO+m=-m3#yE&C*!M5;!KXyx%T9>;PUnN zfuY`ut;SFmp_iNJ-$R&sDBhN*;X|&?XztA1%Ensbh`3bXD~vU;eQkirgFC{e@Dp9R za9lvrHpz;2Yelt?8QA;bnt;Z0b!;9BhVm11ho8+8xUw?XbB?{XseXMyAGnpoB zK`=%m(MTFhK_#yEjvr)TK94%9pdQinFRJ|UA~G;z8h)Z=KPPz=RkONbxCtsRjQ+!y zBV={Ec&A_D<@SYVTFyIUfGP;wjY02cIJ?Q{Efd<}V(-Rc4kf%Qe+E5DFUQ7N6DzZr zKP;CnZLc-HH?|Gi#FmXsG+%`41+Q+>sKd|RE>xL2&~vo`m-!3lFcBXf=Y_=MyqIoC zv3Y@-7jx*%1eYz@hNl!bBE)sK9Dg*Ik2+_(ofxyv+HkfcVh$s+zHO(nDL;RbtVR0#GlVWMJrO5nf z@}CbclBxb-UM#zxS#K!V`TIed3LS*K}5lW$Yw?8;seSLy#yY+g|{+AgJ!7Q&r z{dm5~Ts~8%qw*L%az-COOW@lv5ChHKuQB zhB!9j4n@tVJ+{Ks$5$FuZF^-zC}CWX5RNcwKdKL2(x#X)qCjd=SSqjz{1QjCM) z{{MBo8qBtfwuj8RK!k1pR9*6h`h|Mi)z9>AL@{(=VS2v+y6;(Wo*7Bko#_2xFv6;| zIWX&Kcawc{_LDcM8Rl=$#1zy`kLBuK40cRWY|mik{R#X=g6wC_dE;+dliQ*p!6Bbz zQ82<&!>AHp{crBPvdVhnF|ax${3`rh;wD|8WPAutCjeVwNtAUf_yY}-o&##$zC|ii zGIfK7HHxicP4sB9`$CcafRgTjm}09s{!M6fWDJVMXH1*|%mJO+@_Mz<&Y2M)O@A3k zt)7?0@bqNI=(CL}!k<>KM539e zm*dV@EPB9eo^=i{BA*b)+%NBy#s|2-GBk3KxF0CuVjfHq!|dm|TJ`rgAfSf^%cl4B z`kkcw{-A#%Ks=N0JsM>WD=xaoKZD%0vsi(&%DxvfgwZjfPo|s?h)Lsxmv2Uc@^md% zT2N^z6-fS9`)Tk{ZXzo(Cj;i8+Z?A#{0s}iCZ{|$qY!esTNaCnB8fVZ#lJFFBFYq* zGwce7a^-ei5z-|_PD&;BW4?2y@OGZt;ZI+lwYR%jez7+G@H?{Xve#&X z4)e8X?_-OR1d?qdPFpIwZ>h!ad|B(o4yHjI53Td-#;VdviBv|;Rq=LWskxN+QR5i_ zD`pkUZJQO9o->|;Cs1`$H2YamPYi5g@y8bTKQF>rGeNR9ZFk6n%ZFX3*}pcj1mSZd z_q>3JGtGB>SMl!|N-K~pL4U<4U7U;1S4+Z(n%m8)_%OtSf6bxu2m9j{H_WlJh`2qE zeaj@aDh#y-%JUnNO@JB0ROp`0FttRVzq+2vom}<3)UBOBXv7hiBZ`5D(=lVdUj0fdYtTaVW=Nb=@zPIhg z!W&smEw?6Q?wOYY4v^^|GYMBVy#=G1OM-X|-Af$;8$7C4XrY_A`&DL(q9NoLj>E&= z%%=_2OXWpml{|GFN=scWxhivg(7v-YHhn>~1Ysw8`yR7iQer#0^t$7;81Ln?P%+Rb zj?867F9dVx>Jh?u-9OF3%AiNK(<3GB3q_llC3l>~PPSHV#kQQT2fQ|&y$u*F>^rk@ z1t9rwgF?PT6{;`xJTII`@}ai{k%9ZNG%&KE3EmzpqU zwu&ldsub8)GMoo;%pJcZR)Q^}9F}-*xiHrb1*fZoT+O69kTq9-3&cbqA%gk~z)}(R zJA!9V{i&Ce(LW$nuEnjbJR|RvXHpAmw}%Qr>$29S|3|&>7P%}u>8nq8RqU?qc{TV# zZ6)c078T5`o%jTEg%mHPr~ver)wirRpEzt;e|VH)W|0vPa$62D;OyhXs9w1=+hyvg zxdzHv)7-o zz>AX2z5US9)(P0&t{Z5^^1%1aRd-}Vg>PVQQGaP_2l#66Yb1AH9jmk{-t!BM{Nz1a zNv-*I0lF-On~Z=zWqwU+Pqdq9t>C;5_Fy|_Sq46p!85^WYK7RY;qN|Izu99`As6jl z{_KPKH0BAyNA{4Bvl1$gj-|G)F~7xmbe!eKHQ(-W%{Q1nE!o^}he{q7qb!I%H+QBF zL77ogIXj|StG~3@!p6y9bmiUQN(!66S2c~{_3cOjh?_#4&S^c80@*C&&Z-*6yOZ1jwVz?Qx4v%%Z%~FZR@$1s! zJz$)FSO=f06tG3%srIH6uv3P|vRbn#h;EF_=F;h9#J(;=bbysKX1)#K*VCUhdFDI) zE}AOWWHqiIwZ$tMs}|ab9RIXb-mBf>q0Wn_ z`}vL82vWJUKT6L-AEoDf?gArPs4bug^9U*Mey{5c;w(mgF6d-Gx{rjh5f`w8&4j#0 z)jF+Br?|7#MzK*Om)p5F7y7Er=?10?s1duo>BnHp~&!09nbNij0H65cu2;&}) zdDbCbu$Ry=i0QuElWrkwLc!Ke`+c3Ho#R`_7rtt z{O_XE;~`ayYV)rpk8SS9;uh~W+V-kr8 z7LzaPH>0|{)+>3KC=Cx2B);&Cz&~a4^yh|thKyH|Ra82F4BVbRswY3w1)?j8s~%t4s-OlB!IK_xzb!70f5tr1AtaulauP4KTh|x^+;aC@Hjys}NlM z%@jPMEC3Sx(2c(1IUm8;kSDCFIp|~Q=z_UBaF`4otb_^onrzSMksSfI{%!)ht&CkA zT$vceEH5kTWIguI8I}eTZ$DsN9L28@96W0Ewk@*$pnCf+ zdSru#V*?v{kzn}*cV+h#!ae5|1b~L)PmLevEKF*zyCN@FQ{kI(W-V5FMX9-Q} zrKiDKoie`cNSDFkfjw3Q_f#{@J@LF9A&+;$ z0&Pd-?{w?FTx9<9ws z^(8-0ZqYNE$k~IMn^JKc6rZe1UDWpMSPz-koexqYW{1w-iAr>TR>ba4_p0s3>A7*C z6zbLtk5MzYTw4&`K7UK^^9UE@|6|Y^Q*AhHaAd4-?uTTrSLPURB`@Qs06okq89>sQYxZ(yBdyMm1{%FNvv#a8+ zQ<;OP1Hoq#T)Ml~_@a$3Wz=m$e{@6Uu;VCAel>$&>#N^+@)HOfmnqq3&)oO-=)6Dn zcWxD;gHt=wBg-#YnLta&Q7g;=LBe$guUgA>>KEoML=Wc{mE6Q!q#q38!5PzRA5TBq zLuF`Rz39Qgmfg-x%ItMLx^TAHGf&DcY(lDb63ju?UcT{!Ehm>;F@u9JM+_(=N6u<3!h-f@_1!r#vf-v?i>sDlbD z7tpt185VNHSNGdYR{t*CZ~8jFT0JkRD0$mj+^`(rA7R&1T+hDm0WD=(yWHq^_Eoo^ ztVvXs-%odW=bT8s-S2aKeApI$F46*zHfW*PQ9yzeLIEG zHo;u|zTwTJM~sHUO)EIu4rZ|?S35l75FoDnHbdo? z-sF^&Y1Q#o!XlY`o;sgEcBr#^=v@`8=)46>lQ=t3=A;lq4+C@H-)iOI2d}{Sh63w5 zpfVjUO|vznoeFkk1#j}WOQk5EShokRmpPh;cG(GYV1-)_XazIVyuTfX;C(w!N(-cU|L%dI=f zZa&YmzzwOJai|_5JdBfl8F*|5Erkn%astb2r|9t7wx-r2>H$;&kw@+c!kDc3rwSsN zI9WBEI(sR+yyJH_0)SM8YkVp1{|(q>zTzD70`BwBz+!*`m*5J!dFL;kWrx@WFJ*Kh z-4fUZ7*#v!#iS0x&@Tz!R22(yJPT;Z4YW#NuiLOxT?IAGYzroOhfadNh<#+=#rbK` zIc)nQmjPni-{J0yA4`)2T%YvTE3}zLP+1u`92qux4plNz>`ODZ=NEE$b}pmr?a=r%7dOHtTg<`dZ{kwuf7H zwt}ljD@)e@OTIFqutUIgVqKkSY<4h|Pxy*~Sax0q&YZ25F~b3dy}7R<-?88RjUTdm zxcYv091bC6+FMI;c!t@u#8|K)`$uNa`5E1X}_}?cQ z!|{ysY_*!R)=?a&$K!*3kGWeY>o*ho8fC{vEX~wc7OgDK?-A{%khiusK0HmXe=jZk zA?@@#C+*8FuEB3Z-Xlz&=C*1>W<0G%gWFz;zC+#<{8o&9kt9KS(Jf{kA2)TXa|~tl z%QwOEy057&Zj9ulG>tZW*bW&kvSbrwKI{rpNdXwE=9#D5ShM{G0X0$?Bi}l|U>8`y z48h_X*;`m~Ucv{1&V?T!y&6)>t5o|Z9m}4rVdEsy{O(zgyba_LuxHx&=(u_==Xx${ z+^x0UT|C?wwvn+HcvwzxG_Uc!iVTjAq1A#TqTszyuPhZ!3uFb_4OyTS(E!}!#PIwRU{v|{01`79wsqLsFBw9kHe(#RZ0S^Fj!jeTNe z)i3Y=R+viCVZ7-Rav@>v!>~G2vX)c-eobqwAtKxdKHdJOwD;Wp`+UyFvqKkP2*XQGE{ zkpI>Y!GY^a^ws1X1mV zyD_`g<7Sy#7EMqIVBzjC9Hs=WHR+Eh_z4}~tWb8anc7r*c!RkSS67cafYbA2ehnrZ zuCld{Z>k;-``Cq0aUH^p3#X`a|M)x&B5kze+)iccC!-zK5}3m)_Ba^6{zq0f<=ebP zK{H33)~g;`p=JUbdKy}`TUYYtmar^dN1|N~!sU8JU!g1agxseR=05k#5Dkue=3HKQ+0`!HOpbX)9b@;h8DkIc*F}nG!CNtDaCq^fn%fq*o z2#$?(%&eCeB08a8hb;BFy8wS>I8usnF~$}hhMzR2vP&q%__~s%0b4ya_gvH#H~8sD z0n7@$Zr}?B7N68L%lu#%ZeFn7D;wW!HQiaXYV=Igb`KiHTq6fes@4B(jF6cmzU>dR zKkB@rJ3wJHGMjLgz(pcbnSCO$x9OvXY>JVV6nq1o=a#eZ9J&AdjXdO#ngqJp@h{ z(Cx;hs#!Qv%FKMc2xTBCqs_&>IUIRjJvq_n?2@7>^4{puN`bhttMyxtX6R&AGKm&l z$HMdU@e+c|0|35`gC**p18(Ua`mlX5@Qnt1Nu-BteZ*R^-DAQgN#ywf%}d8#!+FWr z6IzIa@86j3+e~#I$J_1g3pue`P>vfA(;Ix7*}1=2i|wizm#^Xt>Cg?(HZU3xwTHTy z)?26KAnXFyJ2Onjs?+|4Wfaz}pD^z1x7+}tzqsA7(~8d2RZY4QrAeL<;c*T5lL{rh z$1miLL-^)ZmE3l7FF8X>itG1-c8ig`k;QY3x0Uz9!h;;=>5N$`zhNthCf)%g8jDJk z#%j~Tw0nXt7P&jC^j4Z~>pCf=vcv5({V395IV5}Jih>C$Q_YaEt#5uN_~mIXIek4d z40!~Y#-qPu6$=wl z5Z`XZR~MI;Q{J%eXVmQt$*iaE*=^I8HK@!3c`up7cLd24keK+d{AdFzjGVrkzB?6- z*lMNsa>I)$c1E^>7ty&2-nq$)BP^=v1x4h@0UV{#uDe9a0`6(TUbhxpj_YW$ZLEd| zdIDLe3&Y>Lgh%?q(Iuyb^&3ZS889w47O4+W+~U&8e}pV@HS-@zpfE*`+_duzhXt~{ z0E=WLT$HDo&dfPppQ2YF7DO_BQA^x|i3NsU42&?zEK_ggaN+B@Aho>Kd;xunrEiz} zaFfzozWk$AM4(B$&`tKSCSgpdc(U^rYnobR5R-&l=|qZDLg9^vQ<)e~9ybMDT_N^L z0Pc6vZ}}_RWA#;{Z7%hJZ-{F91mUz;jr#($!&RRaLSOd(@}v5VJ81K-TJb8u|KxJ0 zYxBB`FKjft#^J(Z@TjuHe9eZ4oR8&m@of>`OPc&yNQV^1@JGMk@uZuq=vABFN@qrM zf*FMs$3M#K7O4;)3AJOyGd*e$9_5p@R^?SxKMB3;=A5~wTg+XZhBjTrLdQTDtaght z+XUZGy5F}IXUxP+77ZI~0Q^;^S>3xKI{WhtPsvm(%*#jS(f)DsvY>c$%TNGF!e0;zGDVkSS5VU8F*k&R~?B#gPelO>v658@gDaGdd zp1EesfKN^|c<d5IEskX@%>hBD?cBt##P}a%cnb3lH30pBd1}m7F9nc z6Ut&Llm;8$HLv`@`}}r5M^LKUi!Qp5%v8#_G5D{$^k=T4T^f50=kq6+H~@l?`mioA zS{w<zdV#YK+yA$6ODWBufD&9pTY`k>u9@9n55yph)Vm`SIPlPYn@~R^Jj<#tnlyU8wf0j zPMi4ATTdA&Km^P8Fufq`*NQQN=fl5np7^bGJ^x`*xE6Fwq2*V6tQ9EWnSIGyI{9iJQ4(xcCVB<}TS}Om@Q1&G=S%6zaO)}jp3zg;9Zrs+ML73R ziS=P-KCCKt`Jf=omq!Sr+w|K;8U($z#GXjnk zz~EwM#w#KZ@f{`0u6xQRn)%xuhAYzGp=S?IR}Xnz1{Ob6bLR+Rn-RWr{~_C<{DqtD zy=t>dKEut}?Gv@e6z*32I3lxczzFpk)c=E(ThJ9($c?<}?}VbajYL@7PzS$^dIEZ_ z)1T$IEeHg5YYFdPPNOx9rF!3z<1a;xPCpuOc&3+ytXDNmR@mBx;82G{JU$tjBd*kc zrQY2x3}Oo`4{|fkhJlzzcU2<4DIw%RA18*F97fE1=bxJ@l_vLc6iuq}tgP7YTk z?#W`?=>*_av41n}Z*}(OiWzohxw0D30giDN1@AKS7 zpz8O3`oC=8L8kZYD1&jo>2=549N%3++i4HEkotQe*T(2Ahwtj60hp_GSfA4Qt(mRE zX+ns?U0wy#&qEHqUL3Dg)XuCb48B)>hcS|T)LIi#WlQ;Qrd~qO`gH)NdDp<6hZw8% zkLu%*Vig|U&QBP6KN7^DfKVQuM6-Z6*2I;uH(3oqf z{$z46>Cs$IR2j*aukj)$K_h;fhM{*A0Rh2W&C*XxYi)_>vKkiSbGw!7H|L#q8h+d? z@l#M8`Mq6@5>S8^aD#ze@3OW!sD`mD!+>k=M%_jHMo$NyhqV!eqIQFQg?GJ@`+?IX(4$M-IkmJ$GwLqh2@pw8-YZ7HWSB<@vF9 zH-?GX%W0K$*itHJ)#)7k{oMVlb`_0#iD;NY*vEfc<_gKgUr#C>7Cz`e5?%i3<9y*~ zH@^5rSEfJmCEwdIILLalDKY2h1dro>UG12N;JflN^*SIgt8V3KXt%loZ69up=xJ~q6c;86RDT+`LY#Z5DPS}T92lnt#a4>Qi}g4iqy8c#6WQ1U}Z&HQhjC|i>$|BiTH@&FO(3uD{e8QABmUI2o zevvs_u-g5nNNs7IYvuv+0>^=Di zSBgz$AY~BDY;T;6^Vx- z)1arK-lFgswbydSAraW^P3x3i2X6_vV)Nu5I=6DNI^34DL5z&qclETN5+k0W#n4La zt})=e)RrG{pFk{I+U8^MJvdTMOOZ?VhVz!}x-1s0NsKsvd=JR*EI8x^VJqc(?CwLG zjK@2khm*P~4%*2GHX+BjBE3$7gV9fxzuDR>_g$v@MD}U3DNXI5-xG6Zo-WuESK(6` zb~)v*&mbG|lHw4%H)TrYC%Hb;%5{GBw-iSXl2xmp{v5r9ED$@I#O*9mxdJU&f`KX$ zB|eQkce7%{Xylvuyd}W(oqV}}%TqYMTo=K||f)=WFx0q}PumJLalYo*+BQB`Q88)BQ&=L^7|4>9CbFgjy)3Z?Hx_GQ3KOmHwiUF4SNJQH`xoBs zC|6F`H@s(q{4Do%hr_vr)lC>qTgQFCD94&l`TXx=QY;pRm0qXL>#2??R-r$o6jS3+ zpZOr+?0=R#EVB}2NLezy`xza=Fj(|$@Qy2jbpvd3#R$F`*o-igF=r>7mY6jf_s|7w zR@B_Nlt0G+-><6eq>!v=OGk}2J1HAdP_`9k;9k>GT1>5ZN?q(_PqkaqyGqe7QHxaO zwN!C!VG42>$>FzMSVRgbN84mmKa+8&9TkAqDdShFen;cDZ2?P?sO;2{^$MYK$fX7S)<1;ws~WlFch0B8!ID_<+f zRSqewK3018V)2rT47Ma~MeEm+rB;h4*;Cg@$gXyJC;>wB(Qo6d8NPXTZ(C4uH~uf- zz|B>#!@bmz2Ys}GVU}Up%m@nmx+x55OAmcvX+-^?$&?ZKH`Sz|_l?w)+4I{^!8G3$ zWOl3wv**4MLG4B5x}kX7H1fpKw4zgQsrMt!)6_CLhy6U4u^zSIeBPQP2`KV&m>zlG zc5CQl`jBuZpXju|jfz7ljTN@doaX+&SparYeWzP1&cD;K)ByB;{B-+k^H%dUN$tPp9KBFpc;pt_w^)CI79JL;EcicA385`$fusj z#HeIOZ!xUvaIgWBJ%lxm-w_2EaQ*zkVl%;ZU(ZB7QsQZHa*a(Hl{vA6>*67@YbOjVWl=L<<5r)%eL=YF)y-YB$=P6uGNbuMMd7;osw9Y zP>D_mQn(C?zHalN;4=5$OJFFsj#@auVguJsaH&ZzbxwKvlfcX#NN#5ML5-u`G2&~X z^g!+7=b_BL1IJ_Jr-~#cqP89At+!QiK_Rz$fk$4!`>H4~@}Eg7efqp)cfZ|cA?WB~ zkz}d${`5j~z-vj5p^4@eAIIiaHAC3t3e2gG73-ck#J^6aakNdKeJW-k;8N%-YQu4y z;$#c&V;PblVBDc)JSj{&t-sf+hJ1pV3CM7XTfRjdnH`nkPoI35ADgMBHEGD>$}pTq z0t)Dz8Fp&-ZE=71Q5)Fc%ICEl(yC$q3;yw{H5=_4QRgIpwMzm-*;DdWTC@X) zmEmQoU0hh{qR$?6*Q5SJ`0*zz_c0zRLj7d-sAZqd*NZ?+{r2Q3pyZBTEFk2msF#GZ z2OZV5v&I?+bINMu+YILpvdl1FiJX2h_`7XSr>QP;QT~}f?rk=dFL7_Pf{czeOg1%* z4^8P5w)~M}Dlfgq)9%8`n98*#r??-6=y^JEqB`1@QzGkXO?>$nnRr%@(W19W=Is^Per?rlVegpUmJj2?YFY{ zTsd@M&hY7Fk{4`3Koi5>PyjVM8gZC6RqWgURJM=FVZIA?zB->5@t+iA_jo{a_M`I>P2b=*x1d+_I^rc+3H>a4qd>8IC=Hw)I_p)`yXU+@!!m(F3!)uo(38 znp>n*Gv-e`7~B^0*K z?9F|cL_c@8jH?)>#%>?;I?YI-z(=R-Bs-=#4rNg?hGmhTOYgbnrCB%>S08B8gW-6H zj9H}fJ69p!S*9f8gw3;+#^(KWASl21MECuJY!!<{!1 zZ7*-@hI;jk!N>dtu6^VYw!bf0Qn-h0fDq(ZW(^fVoQRDfp!B`N%aA6Ut0(5oX{tlc z4Oe22OEv8H5Q8&CwF*OX~ccL>vqgt7l6^Vl6EBSPD+R zms*_((p`9z)9xlq?@34=^BlA{Ikf^$FNS5b`saQ>n)nK3>$0O&S{C3|4$Z>2JjB~) z4QO1N_VZ>cgNk8ZUv|TI2P|f0{?54GwJZ=FXOcI>WBXv+!wGE}%59g!mgI+a)WEsN zg=4y0bFX?u{>mc-O_8rQV;MF~d)dbn>!C2BMzGaAj{c!x%=(`4UeJJ%frb_~u`> z5HA5XC*L$PK)MoQL*Z1?!=sk`UH*mIjG`me7h0s(|5tHz2p|N5x~? zV@clG`RSnS7mpsS#^N?NzjM^w!y4|= zXCXB?;Sc$B`Md`F!J(Om2wQItA(N2l4oNo3wqEEyIw1OZ>aA#KC3fMh}Byd;s$&@QpW13=# z{9?$BLU4-dS++>VR1@4jmfqTAV z{l%FeCrg~xOTGZ)1+09==}%Xa^R`uM(ULMM4`V{jMH{$FFx|vd9eloJR4Z!}#W2KdCC~`c2uimP(p7LuD>ZO4X5CrT7wx z`ICyW6#u1Lk3=T#yPAyEzt+CH`Q$=-6ynN5{FXM-&$Bw7KM`8f)a+8sUO_nYgiNfdsc@?2h+mW3qF#U45ZINB7$uEyR;>diEF zE4_5NJ_*?ho(vE6VmMLr>>`e#`&|&HN*e~FR_LHNs<%C^>u1x_#v`8st}h#R!iVry zCQ^El8PZaCsJv>8R|O{1Y0uEr7JeCZ+F!2PtZFLJlG<`h^lfBpV%gnu?UQ~9is)uC zi2}>qBcew3=dR0+3%mS%-{^Dl%malDb1bZhwq$x?dz<6jT-%l1%6}0=0CT=-AM!n& zZW8Jrtd6D+-|K#45`Bz|jf)8s8sP&>UwG;c-a-t%GKfum_d=MTO3#}OeY~MtP6aM@ z5e57js(^z;9ZtfT*^pEy??N^wxCeGBPKvnFR3RA1h|+c#Jy1DnUWxNmxaSId2yY#F z^gIzfN+12vsjj$D(Q$Q^n5K6faZ3UB#rK-;Z+*}iwmz?VBP|puynlTV{3W!L8=KFL z?Mj3)FS5wh5ilp(SlW0y6%vlqRu6Y?s|QKZN7oRl{kk>Lo}4}litDb%5xY4Sj$zK7 z+Jh+*SlYgF<}*TU8$1m4ID}~Cb`K;8o)+2)?}0MU37c800!aNf;~UCO3!{8=o*YOr zKsXikr0a49e~RYgy<$cJ$on{PN`H!Hl(;H?c^3vKZqdJ3{W!vKwlbyG&8U9S%lg!? zw#6~dNa?W7snM-oirZmxMy_Wo5LOP01@fMKz7O!K^LcP;Vr>f-_G#Unl4npf;Ug$k_@JZjf%dq7bT4>L%P7mkLb z`)6KDqoXtZ(Mo|%1Q1$L$SQ9)+qK%T*T2p~2JYuXY#6wP!kmu$lIB*qj2zSiwh6+Y zuLaR**x!U)=k+>(Hz%}>5TQ4RApmL}mI0EQT_Qy>!et6{)2G$u&Lrv9Q{ZAJE?8t} z1syC4-VVEdx@bXVDrm-%GM3)gQ3u6vw$ApeTzc!nMO?CJYQa5gA2sw|RLpp3AY3o5 z#Cwa5|ARs7nREt}C5dHCP1$hmy&;a{x{?ccv?+h2-(U197|ot$uX(l!$ZoyMYi~(T z{x(ErU&%sVnf|<_c3|Nfzxr;;bW<4d&=%h(-};$~^Xs6@bKno$A9tp9a*zlK^K!mG z_Cq1(%3Pak`A0#AX?ggM6tV-8UvXDp5+W3ux7P zvK3<=&ORIynYDi`189rv7Jga>6b@?1a3DtaY(6=^(lm z6is~CeQ=kNiFA-$8+^kUjHmY>th3Xjsg=Q;~nS3x>uYCD^ue9<4GI8%Abp?_F(a zrYcQpffvq35`YxY*SqnZudu@Ugr&w|)^E`>AE!JZjq8);cy(z0Q;*uFY=YhdL59@_SoSkMaT+O~;F`A}AdA2Mr=^bSnIUcMSH2YcleAQGrZdb{4c@Rk0{0bn?I5Bp`I;dYJeY z1J$1yZ!hLy4mD)r2-sH=I*$?z6mpAqKU-6Lk^vaT3J6Ow({ifEpwg7C2J85M zSZqoPe9Ja!Es_X-^^^?8`kZWdx`Wp7Bzt)!)<}h7Oy<^UC)M_GQ>*EagBf4`_;Inx z7g@jxoN(gn#J1C21s3gB-~CM_=kZ zEeQXD%Atto)D$<3JlOdqRrBuv2CBARO!1aQ598KXyC`m?|6c_Urx9sZZw72Z?KIfQ zmvp(k=K2@9K(U2iw35))GJ}x%4M=jvhP~Rw2-0$XO19p;k7zXCfs11T+|3r$alhF&7 zQX==brnw|~f9HZS9lC``eI$)#U82oqru78#>W>}axbOh zI9l=&5#&W~AwBw42G=e{JcuG-*JUOvz>hb5_3uo%&&Y`?R-%Xd3C*1o+XkwO(-QtD zM-pM_Bdn+{_O0kq>{7KP@N#--@6uoM;Hp2c??FK)V?|_005G@yal4Lz7DEGdu7I z^sw4xRp1MwujTYf+gr^TqL$U?IEH)~?WR!Qi(D~A5_>bYLzdZx{ThLbX5%iAk${+d z_Nq4s&dgb{2AGwdWl11@8ojWskq?n+fn^6%-t4#_M#>-VD$7xtuIj9TG`!RB;OA|> zu9IgJ!_oyiKj~Xm3GrNJ&uS=kSMN{;!al0wn*PgA32tojpU!`oD2dNz2iJSfmN_&* zMMcSi7vh69q9jyd-Y^fMN#$m6q|);+^jm^(e_#5Rl0w}I`*U~Ixv*KQc;l4b!)5!} z#97xpty)3N0xW{=mZSC(6YsnuKv6cHXQMVX$DC=P9f{6xRk5Hx=&Z>H3UnEVQDE~e zlS|uED!vnikLk_^%RP9QyJjo!VDh}=wPJu0EUDnTZ#y%;x}A0UM#vS)#Vd%L35@5u zUsPN7k)dDaQrArMsO|NgVPLA;XLTyim^`aqFGj^G@M~> zDk?6=)wxaXHa}s?_%Kz4$yr!qT4EjK>W5C6sOd8MFD+7xwXQA5S$9xQ$VLMSfI-m?`sH zv;yxgN#y!d@7b0%3VpAAuZIzDC~BITtQI9jZdW+3HIGo7+8MZb-|lsMaZ%K2@_s)! z3M-N~6*{pJ#OL)sNUCYME!+tUDDZk$5S=g-rcf{}m5$bSWsO5aNRzbobLsaP9WZt> zT=cmmYQtyy2;A=N$93u9QekzeF1&fqvn>iK8p{$^pAdFEeB#Kt`ae{2Iq52APE!}X zvuA5_SLPNPQa8BHkvh^^8P5?vuYV!UIZ2AHAwZbgrLV2!d;Kb5+h(^UawyZhs<2kO zi|T?^7<66hj#n&{=s`P8neyV@>Hb6%`x^TAVCVS`HWkxQtaUx-P-fGROom*ua7tZw zQmm(s&gJ31f(iL#nml*w0Cs(ZYLJya;+&#g5ZR4nZ%vgscp@V)^@F^-QF5uC!4QG5 zkc_G&y?<;wb8TB>R%cLOVLoR1hqL|r%qx?DNNvBXP%Lwi<)Jd^Su-(^5P4oKfZxR- zTN@-xgbp#fLh^k37S50;i-T5O^~_6vL8~Qt>?!xm{yN9kJ_;<`l`QxLo6g8=m68k# zM!1xqQ&9*ZEk{ zVni9jgEd1WGwniMVGeBtNNTkf!Nbzs4rk?6U&|(4cVczLPhp5memHYh1qfqq3z;FXvjhSZ zMDI#Q+wAeGs3kmSgHBtoDWyd=qS7LV@^GV6G@!s<0g3g;V0W?)Z}~d@5Q+^PykL zmNn>rxHhagFF7RX{q(pp`28egpPTId(GJe zL12L2@u6%s`6ze{CLZLr-0czhugJ|1_{B)f^kUs9S*iNQX#!6>&KJ4xYUe=vtkAk` zzfPim!zJ$HX?axh@JG(B;P*FJABg@%BKN|{DLr{wQ^0>O1ifvao+O*=>pgHz3)}k#59GB1cFkv<{i>e*`-KGI`ozdH;_G zc*ckx9hga0kCWGmILYN;ahia)>OODt6$X@!nVgabE&a~ge)ZeN4}q53XVu@fd~rNh zXb31sN>Scy4CiW`?(7u6+wD{@l7>`2Z)!Z(e=Q!OyOwRHlxjC^QanBeOBF0$|f{QZ`6QION<&Rd5N>N%55OExCexW?97`H z7!t7=za_U7iK`u&eL5$A zSm`!|*Eu3lBS!Fk!MI<4>N{AUeBC_Q&PlG1QS-;T9+e>ep%-m)Pg^4bh8J_er`VEO zFvqw(^5gSh5I1f`4bM3~P#H~-EwJ2mr+>JhjS*{@6eqr=59`*6ASlQO7NFoRdd7K} zTPKjM&FaaDWJS{5^65}n@qPAC55W=h9EtM?=68Ul@V1BM3a7j)osdSxbzd}V*JR|| z!%h5b=qBTmdA9;x2Vv8<_IgQ_JO6O+nYR@22GSSO@VZrPOfhkyTNO4`p7l z8IPZ<3Hdif{MYxXe*zin$+~l)MHsI<#4rEkLp;ZlBd+dvd#J!n|d3u}W75l1r5R@aKk;p~)>6%AO&pRVUc9YhV3zIif608s?eADZ zucJld!#2SpN?qe$41e;Cuka<+obqcvo7L3%=TwoJna5-z9o!qUCF)VH|NYx*#;*D@ z3xlYM^O3XvsCz>D>H}CS0Sp?@veK+E8A!NX0QJ$y#XTh;_x;8~yu4(rt@qU634sp# zz`w2p_Mpzc+&|v=K6$B(5Zu~!@=U&7w?C-=T;_(ww{UtQ-zrk?er>W??7G0bIaQ>7 z=elpY1jn&s-hev^B;1z}{~QUo2AUgD%Z8`Ov7c@D873Zbth{n_;BZ_(&^)nCrlk-D z|5%^NKT6*mS|pVxjOf4(aa;jJj>LO}tuW*JqqB72N_H5}P}# zqylBHT}_=U8c@A`Qp+Oh9fP>)n@}6?le(L<99niMz9z?juXRgb-pIN01d8t8dPpt5 z)P$cnCgZ~EAqjKjG!N8*X>Xr`{Q+|5fJCNuK~LMMtrWd?_uwhl_f4)DGKXZaf~v+^ zY!HuV+-aIIHSOF>(~t@i=DQ@v!iS?ZrTCW7SBTOe?3)43{Js000|uZhWo!v&$fVt0 zgCRndQ`$^UgYtsZgebFzH9@PsEa~Fol7cnynBO+Mrl0%u0ulX<=fa9T!uoxN$;DH8 zVITwPYXJjO**AK5g%31JG-a&D2z z$kABz6oW5>V*Kr(uX*w4&>m#*SkxE(w1L48Dq;R`Shw`^<7-XeY|*Gan?r2rLV)O6xjNl554{I4{88w+_!Co^J1LGAEP6-euWGGzy}k}JPgzI2x@t@D0f zRP$E7r9Axzd}q2<@lXt`nYONVv;&h{&Om^b2iqw;dsnQ^y>ixuwjI>3 zoW1!!sPDNsZNlaPot>M_a6=dDJ~bU8r~H@dM3N}Mq`VKDwg?~=QZS0 z>>Ojku3WMGa~zrn5W+syW}(c+rOm-evXja4b+DOuLu1u!bPfiOLSHtVx~+Gb=KfY+ zX+%sOc;NPkUWaAg^$*)^jq_+t@hU(n;iFy2Ngl+k8L?c0B+HU)0ZWt)95!C{SGPo6g9>#S*AHjY{wA86nhGbo1S zDqb3uX&7}dy{_6{VNE)D35x81hcd+MJ0bP0bUzQ-IlqVxR_Tk`_wP1RNRuV4WxskW zFgmqWdN9z?D6U^6VfEV;QPajIk;Q{(qemlLeZ6Iu`nh2s%1(20d;=?G_OFFn@!$@^XEv9&c{hp833lj19O#gJA`6U&0PHocqIvV}hsT#N^ z``*=-dl3VCS;Jm!52F4aucGI3UIdt*&gzxX-#YCUkBN}UKEX6*G_AHFcOKd`heY>e zT&{DSkJwe7iF>+%%KB(^GZySNcorf-T#EHq#Y+;=U5>&m-$JZmqhD!B@8Z(&nJP?Z zwuBlRNpdTslA&k7;~Kx|R{mCK9iQ{Ua%|c4(ewQ?lyCh8@U;!$7>aOH!>2`$wi;X6 z`BLx1z=7EA+jA@~zn70pgV64(%7Pe6Qj*S}#F+RXxM`yho?F?5yAFbZIHMuh}P`kZ$cT z#7WezTD+#P&HAyg^XUQUbTuDmPF?2mL`xrq+1PV()TuZ;9hh^4onueVwqgC>oD_c6 zL_(XUb?!_$QE=0c=QL%yVCyvBh?Exeka$%wbgBk1=iIF#^c`YHCEv+`_K}3~j35+m zp2Yb2^zR^g{TB&vx54BrjmT>FJ|undJbY7Oxm7R_->J_2L-b;leKPuT}>bu7Mey z;18tXAdsd+v@2XWlLbb=T?D}();oWzrZCg%WU2V&-SYUXK|~{4eYX zgZ(|HH5UQ_sy`4*&c9u1KuJBOg%-;n4jXN1S7N0aC;fsgo(po7sTM=8kA`J3_xDII z4|MrQ71V+Y~A1hp}Vpq`(6P&eBGs)k6seK1j){ zE%^NgLzD}Top7YKT|2G9WzTLPyi2p`h91NN(z-tpg}lAOnM@|FRt5VdEVwHs07F#tBqLaJnpSA?Ls0 z!AYWf&(MT0*!ydyWdnK*v3f{y+`_+JvyAnZ$udOIdF4c_3X|+Q(R63=(DM;-K|C7Q zD(DAND`EgvW2#fpgF(=eKGuS$aQA%Y3y+1eDW49L^e+BJV-9-b0=5xfWo=BQMda3> z`-O`{BM|C&7oN{bx>XC`bXQv&D?IO7$Rd(FIoMqy&d!U_Z5`-8_3#chtgbJe&ap?= z5;v-8MYBW8fljTE`yCqAsWO91b-%gLm2e3tv?VN|iMaaG#+p7)E7_*Bmu0{tQdjmwLGb@w%a80o=PPYSKugmvV6v% zhqc1=NVcMVc~JG_1D`8Op8#xP1E!mBj6dt4>HgJUAw#z`lG$2~30#pMtH5W920&5Et4=7q7cX^C3CXu5JXRr5x(0?w_rt#Fw z57)0fsMc@rJ-Mj$1|fn!+GWL}R778d8J*w0k>OsSg--+$R$H7O8scmX#%HIFI@j-Heqa{J)@*qlTYG=r=V5 zX9mqZSfE|^=z2D{8B=W4{4=A@r+K)gLA7v>wh8;ZEpnxu(p*;#bSl`ksT~78vptD$SB z-bPCoQMix*!z5A30^Ko?PciH#*^8c3=8#S{1Ab#-JCN+_WfBl8c0~tO`Kv2 z+A1Y+4>{Jg!ldsV>T0nFauVEM!reo!7gXMCQ?YW|U>AWb*Zl&^F0<%7XhP%lG?LUjvq-=Xi*tT)sS)VpHX?51Ha162t0JZoNO(e0aYN`ZIA zvQ4v(!YpU{HBJ0OA}Y+@lKlL3+kX8Zy*9V2b^^juk5*QfyA5Zf(tOWM$7)j!F3owy)ZJ!)tU<6}nPhYg#pk_RGqbpaITTP2R`-73* z%r(_AZQmHnmUYdN@mA?3!GXNY{OD^N*h7}L z&U{u9=VTWnJ0Cr6j2k3$ude@aoY@? zLlc^U_w0U0X@R|1Q9f0QGY90S0S{NQbkdF&Pj{V0GfbynV)#;T=v4!Ha%-WBI;D_BGkz`t>&13nh^p9sfPe{)as z7MKKhR=VH_Xu(srup`C(1GOjq?mfoT7^caG>uApJeWB)Xa85pN0Sf2`SgsHMm?smp z7~`rKnPa~Hnr6R+udq{c^RdLjqKE{8Ae6)0#QU zgv({q9p8)xufLjd8VPzGB8MJRNd06hYJHq}N$D{sXrB_V!!K zw9}pV0IriCCS2!Wx6+RBR<*DL5kMHwLf*kOSSG+wCi|#2&aSSF(|uB$B!!o zKmz%S<9*WhW1FJT&pM7W^!sCE!ks{|I@W}f9b@scL}*0N0Z)UJvh;yK)D4*EIEvG2 zWxCaS3nfgq+wxGn*gAzb?@>w2qQ2)Y-E^-n2emAPb{^%n(tub48|+_slQR<&(vGM5 zlAFNla?+(gWAG$3V)X%HtuDGla@DB|gMs)aOAMIb*u`tEfBqP9hZCnxTT-OupU7|w z%E(vpM@^SYPX_N+%J!U-Q=V2dQ{zT9mc5aD|JiKjMyFWdi~NQTkDEsrSwp(6^}Ekg zXwDp@Beo%j6?x}|1ut^8jsrQroRzuxoVl}=>o|l6=M1x_W<~s(R(kSw5Ledt!fbW? zRV~fDsrj`rc|~|ohQ&L^=fa<2_eFJA79illMxK+T#YL@`dB~$_*)538WJr!k3%*LA zvO@#D#<-!6NsimXGo5+l#Y* z=6>?+B~y=0yUR*)uGR^HxplQ|yZ)&eHRm}|Q?+a?>Gr51$n$|VE6!g_yUr*@Z7+RX z-m_S&>V3bI3K|}Uk@sVmN=L4e=o!5xmU;kJ1oP=nP<19^W-bL(DGj87V>*F9&!{rj zb8)$hRBI)EfZpI5_>M!cAW#ILi~O&f%J3(U&~{dC8O>R zE!~~0dz^1BpQ*mokJGxwmvoLBS>Egaxn;-jAc%n$wfeMf>OQ5+$VYqCb{5%VlotH@ ztK=M(=v4(gLLjqiOOBjtmzB zwLRL-mo0#<5Fapjgl!OXJ*ndQq)I;*#tyywY}u(BRwAWtM?yNE+SC@%ilr*2O zCoDK=a=xNo1nRR1BDCcxu35nWTQ^dFow`DO7^#R0dD-y#j^39Sqt7>n?tDSF7Cdk9 zp_?|bjHSneCpvvgpiB=ZWM^2TLTZ8$9cZ57E{i=YDwHvUtIY$UbmVAZR*IUR+MXkJ ziW&JsTU#QWf#XJE!(%g{M|>A5ei8Z<#6EFY1Jnm!lp(CS3Cj#s;J@yX42}k`vwECH zVvj>qQwzgNm`WY782IuPy5Y731RJidzvBmjVp+D*J*6{U)t|vn^7Be`TW%&XcK$vbQrgW`AIXlBRghi_eX}P~ zPU@vf)<_m@`|+EfO(34lXEN=+SdTuiFpDN(KM5dt2A$QnUqW8$mn*_b4)q-iT#qsuL@qe^YF;^;I?bc(@4jlQ8^4@ojsEgk)P#LR_s9YtMhEtS*YO%j8A4 z!=qiM{+1{vO5b0Jl0?UE?)ru5SKRH4`@DNT$WLt4gKYD4uGL#c zam>zu!wtc()Nan2XX-ASOS2#!XYRDqnQZ5hR+Wq%wYYwC0VagqwUYM76_GFD8mL`2 zbtra2+JYwtpL(_99J-warhj*W(WunbR)Ib4%AosH_D4hHL!I8e=Yin{8xP%0)&!FL zRbhJ^a&w6XUHHV*z#i^C!RXr25dIqoZZBY4U$aZK@f7Fu)3Ka@b~<`Q1aRtGY?QuT zZnp&FAOFpg(RJE*>6dB*xh)IkNpML+!LY)k54|_;7JHOisIJhm=u(T=LmTj?fv`Pt z!l#Uk8?n8evqx{VeDo?!QyzF%0XaHw6hF%HRlCL-4~OGlYsm-t z!voo5E5P9h#j5Yz7afNS_*C`5aM*x1++-ifJoOoHXdyiavQ%_4X<|Ipdolx4dI zM#aSlPJEHG78xB^f!SDAFxUN%Z<7h7R5)5*LTn&M)2EF^F61r!=H6RVuz6#STW&p^ z#nX}vsqZEKz?JUOAhMjH)IRH?as1Q>;vd$3JxSkEFk<|P3%akp+PNF_WR^ln>i;8&i_{l8PJA&>b+6EuDNt38AESg3a6<;31=9@5-@1U;gQ6Nie z%+ekS(dnp_Om(F5s-2pWB>tNt>gi<#${_XtU+*`L zK@R81L!kF7pBkS2^C*0B;GZFU$b&q53~d(HJ&o%&BYeZ5#hhNG?9;wOd3|MP^eFm z$BbfMl5bz_V0!5Ku9Vo}g%o+!nZ*;j1jICZQ&%2TbjpvlNIFf-d@-ck=ZIJ_Nho@G zVNEvNCEEyk{%Pmn>M0+cC7PPm39~htQ|fi>(cbGd85-x}%Iwk2uXUd415VI;*TDca*SSp5djBoj(8CJLEw0!0=s%uoud918%7~yvy2a6W2;b}eOF(5fm;giu-TGLv=skvlii2OeN zyc$hPFGt-Y=%rxW+}|$dEPbNA>7yP_+8hU+F#U>P(z)yn%uUaGnkS_8?(E>^42Dnl znD~gHB+S-In^jxHHxSA*8942)vR>U9w(cZ~o8n5Zuh{C#I;HF=*fesy&duz#^2i0DnkwM49% zEuBpR&F?qHbxt1(Kl6`mA0cgi@5ij>vfWk-albxk50dn7x%)HV#5<`PCnmNfNkj%D zzgkuUmp=EUR>(>w0^-#6C~Zn~O_BG{x4)Xbyh7vK(&$y^nZ%+9Bk!LPUj&xF2_|-= z@a7ke6UASUaAq&p8H}Q!lUVO%<($^R z&R2bM4d;~sh(_(pwEAFe#~EkAmFfH7w<)_|@$REF0sY!B^~+&GNK#ozMC*FPy7NKs zED{a-pVk2O11C>@S_+^n%|y3vo$k2<=+B`lI@wN- z>3r}w5KQ{XhmH(HO#bc6n=UojwOko32>&@OD3jNDRH~cd`=4Q5-G^6m4V`#Y39uwA zilUnW8i(1DD(ZdZai;>n5^vHZaZ}#@6Ra#QJ(VpL*ydI36v7^h=krWVk3uJ`Q0uY#QZJ^aN`t#9(;t}(Ql6qm6KPtp>4 z60Z&TQ0kC5`CgI}yW(OJ_@#CrkUU~s>$$BT)i;`z-%Miz+?V;Dn*uMA9~t(11xm;+ zR44;dA2mlA$o=#LlX~T>mzg;YD3a7Cfc%|n`|GTeVwl7NfECJK+b%!*3WJDN^bKQy zMAhD&VXR^I37uR7iS9?EaWtH}6vV00^iEbU>+xK+)w%X3j~B1&DT9u4wVetEnn*j} zSp-@MY-3JZ#fhtxIaer8rVAGfY<$pu?JRg|IvFxdSrl=_pl;t56i+&Sn|sa%1O6Tb zTgAtJEiB1@`qAZ?1XvxTWqyRV@$bq{aw+j`y1d5PY0I>Sd-A5Y=HQRm)Dv0%y9=Nq zzx)+`pm)&d=q(-INZ2Zam3rn(2fmhSB`~K^@`}Fky5j(#fpAUh`0V6|#5F#a*{m@M z4*SIN`r%6&jM{O=M?kW^M0O$1(TyYeRDmj|*M~gzd_UHwlQyw)KJzAhM6>WehHx;C z%7O>;g=h*W$~mHq+K`FFNj!8r{aioG{)vF8rd%j{fLm*{k;Uru} z1u{VXBodvn&_0i>@S6+G)~o0kl!~k;Q9DJ?JV!zk?^X(bdp}DcU+CKfpRp3xIA#&K z|I>uFzf;s`Pr=`R9a_M1q8Zqm>yz`6{OywA%d%y5`a+g=(bQ^23)U^-OW35Xv%z>} z;)j@L8l@lS!`9zbsXSe=7}SMMv#T2ydnY)kj(@;j$hb`h3NqKXJG##qovd53S;zfe z6pSAAdx-zRDVQo9Re!9jnsA!W;c|JsotRF)^~p(kg1sI+R$_qB_1J`Fa3+v-9j6>2 z<)mAiYtuYqIGFczA+aB`ACaIH@;}Bf>0>Jf z-#_t)@|00*blqBhx$AQmt&j%|^Nx zBIxbkNeif%mWu~+)GXir;NtyMJFqP$W(f6%l$>n{$=gI72+f@r|J@-S zEQlb?>-9L(Zsw@>DMes}88}ThR#gPDbib!`dYOB^g9J$Nkiy(P9@wVA=(1Qbas=nU zvg^?VcL5TxT|O>9eK?~KJAJD5;14-Bc&cKLqm=BDJ^E7g?b8$H8>CKmdYyxKa2m}u zFDKF127CxWA#j^67(tY5oBb&q*PgfOzUbc>8A9Se`SJ$^@s~fSsqP+&y7P`mDtrmA zYfoI5hG4+##$z&M1+%|7p6xq&n(gm^O)RvBRh=6#hTARmv}PiLKxAsCNU(o~LQ(Ug zlU6qT&`g@DzC&@?ct6Nz*ce*4{$wiwIY{|;LG(vxm#bj`FPd#vLRu4R<=>W7rj@N- z@R6}&(d=G@3wY5A1WKi;V*{=om4On<|Be`yBBiojN)5EA)$K0Cw3IF7$MKA!`kh}> zZV*`f$QM0EtKToem)>Ds=%>4}(87yw!*q+}R*lwuJDtuD^wXwxXDW$Z?7-$1b_K+1 zv|ag*&easPbM^X(I!a}d~yw@Lh_6xUXt_s@S(mr;kpEpgZY(|@gL zi0F|UmqGAtc!vBrvKP2_<^Mrg-QcPm5Gpd6cbaj7T+*oreZ(r)Fu<6>BCFj-1HO2H z&`Z3&@dipBPk+e?KKGz5r%XJm04ohtvUG=X0vii9r@YOH)oC=-eYK)S`M7AwlSFYr zPezff#nV4p68a2o>T0QsFOws(7i29L=1vbIhm|c!pRkyekXLQw-cYAb#W@|D?^jo^ z&L5Y{*jeAp(_f$5d~KqRefLiD%;g^bk)MTM-}wlQ;wyN>ZlR0RQ{+g~YOKZiOpawFFdxEB&nF@j^oof;R z-9gi@)+EQknml02SxzL;l0}M$p|NPG;j>i;$$TJ!W*SQZTO(_dcqV#m*;h^Pz$aws@!WqztPA>XuzR8_du6v9nE#%YW>9P1naP%J)F z+url`{zn)TXHjULQ3)dwd=z|{)K~dje+kGsDHQc)&Yinv9mk5zXq3;qF^!>by6YLO zP%EXR@xVId&QE_VR8Z=8IJf(%uP8?ch8F)$XAW~{%xm%uX+T4)6x4)~)t)dGZgj?Q zlxg;%(?CmTSfpb|MvKRd&(Sr>tco%P_ef-KEgDUMosl#=It#7FLLj8`B45#|pJx^2 zIM(=GFxg;x&Cy?EIr(SZ=fvlv`8BrLV%@|Y^qht{p{FUWc(ek4{Xi9_qplrfujvT1 z`BojZ60gS-463MC38^JiDm#u=xrj13=8}EH5?i^|`{q0fCzkDs`KHo0tLY602{hP<- zFH5fk-gYI3c?&==mhMF~F8}Kc%FWTjoqV69e-lGTNCQ0=cxCX)db{)r4Yk;D zdIwdvbQeUtY?gRRe5-6@TQ-pv`L&X)7#v-ZrYKl6=2#&+6cZ~E?H`Jj?Ky04fk3rSLD1d4Z6ChRWZ>?gP^eC zcN6(iD;K=PC`9N_*o&O^zO$d_tOCAQ4B@Y0;~&o)$Ia{D}mXEY;6~_`)yQ6wD%}(q>K$ z2>X!v^Umg*VH&h74yamPv-ixxRG^^IvqfMbWz=fM6lsgE{xyDeg^Y>0dHGqFYn}Sx zoN*OvZ{w=J;-1~?XK5BW>Kx}hbb@0}^023*f!}g6)-j0a4)BNVh?o6W3967F&w82a z1w{NjJp}$j!WxI-HGZBEi;?NeZhEzx;zqQz4(p-y>HZfIGkZINsTi{EPpKYu_*{e# zU$Zvm4d(;>dF(hUZ*s08$6x#OoYLYScWnmf$l(W{HV_o)@0U^?w)v1%&d0l5S>M;! zO5PvYmS@dAI!o;g3Wyes0L<=>(bgi0S}F8!w;t4TTDagC8=C~uhh`z~d}=@U6XfTA z92){^*P9~AYb&UpgMc?SKxTMXkb8vA8Jz8>v6g#9`ZB-CNJxPOPf`i_&Z|7IGlG8j z-URw7d?)5Dr!>f=AV!BUa~_k!sJ(ENl9R!&HHDuU7g>yxrcp#)qbo5}QQAd8pQ*mp z-8x`o?((f)b&x|cSVJv3WfXeY!C)vX|3Y*1{pnY|S57>pY+a-ke^?bfWM3V1BfrNi zOG}IWo&|>{W|a_BE&^y`0YQ8OC8P9p~;jB}i4s{IxRePEneY8~| z6R7Kv9l1LrX~c>+n-tFd@aqwIXYj2D@-1Hg zk4_~1l5&so=#A3u1zdm!OR!hN&Te56%YD5PZY=V5sBu+rWZ@3+9q3w;?m5f$BZ*E1 zfz5RHL^N;KAd1nO85vSev>Yv4hcEaZ{+q-9CsQXWAS>)I?zB6{ly?cKJ6GQa?eE){ zHLhVLJ2sJr#^=lJW$O0=f+i*U6HX-}XBthqWy{ls?0=s8AXt-2o(}{V9BW2{G-a}0 zbZ2Yq=!LC_13!LHusM>hLD_2VOm5{{wA(2j_2NTB&}m5Q-x`-BP*cPsI9Xe5C_NU- zM{I$fx3?|duD1>!Cf3IWXpTf}?Kz-ny)@#Z+lQgC#)q$Y^ zJlx;{j2DH5_%sqbL(sDr4LE*uGRu~opr){(^e~+XImB2z?T5(vly(37uKAe!E;yds z-1l$Fnw|^JV%L-U$GG6lnHT8e}r~3W2X-^~>7tL*YW>eF(&*8YJtzcH~I#S7( z%d-x97z(X`kqLwBy7D5Tq10CBPb~3dUg`U%1ZfzsI4sRJD0&eJVZGGV)4|naCspX@ zeTBUU@?qo*Ak(82=Gkf2>%*l zN22N&1yx2ujX{UJ1rcYdqroqe%1f?%HFbl?+x4i@rr%9%6>)!zNQVWVvWN2f;%?cNYd%+I1v47qxGP~9tBYl(x?U*!b$dM!OJIe70sVYO zRT7=HjZQ9zL74a}Zaee^HdehrApC%m1wWE3ZR%N7&(~)jM`Cob(jgI@mc0#XH1I0H zPLjDvADalao3DCy4utxSy~TvQ+!~Wu9uYtBZbO?>525U8OjBrcG5^euXK6Xc??46fZT97+%-}&SHw;=v_((7w=GrwlvFGjUpjqrxV3lZ+*|gnUltT`D%K#Z zQ1OuPe&eE6Ndmr_N``CewQSKuhZhvLBfF_VhU605=h!hfWc@t4M%Jmz9|I*}` z?Z<`@t`oam2=2QQ>xye}Vec>L$741Hs|@$M3NQ92DkMYj;Cf`Jp=9F{r%<_TDp|?fCs0rCQMaVmN8;n(n-#usNck35` zv_ZlLumeJj#XB;Ta2Tc$ns!EdVLIEI*&uYom{dX2pns|N{2H(1p;zhDXF{1IdV{iV zCS2Id{`rqo!NPnSq2F}@&-jdfH%_05p=3#j?DI8k8d+jfBW2g0#m9Bcfj0d6=f zE4CeFGSor`oGZtVn);D!y06B{?p|i;CLAPqN%jSw>^Ve%pu}mV?lW^|@$Au-+_nJC z3$3EDN`th?L&iqq1<9qlm6x_1G)`-K)CZm4#^C&KCfipsL_G?A^L@o>rc-Hq?)nhV zg2Gj-!84+^e;zfv@^DrQN)^*w$yDU0|8GsSbP0rX2r;(8SKeK&vR3l$n>>n^KgD~< zv<1PTvXT=2?$BtfAA#0gxuN{yn+KqkFN(8{zakQ>UC$kI31t|XwW31V*O3W)~LHFd57%AoK*#Y=1E{f6=ybpm1o7Yv0j2E3^&T@1pSO!&2_@ zOb-ZU<1}RKy}@FWq>42h1|Y`f_cQ${Wa6+P@`e*{SPwRujnl19A2%4j%4U7+If=l} zzsVzvb64E{SEUF4T#T?^HZGnhPZ)XS^@R{0swYYV{ak7p_MSnzj3z>&g4Tp;$f0u1 ztcGa;_s=lCvo63uUUQtsJl-p8`oOCGC>h~C>h`hpBI-q5U}4)AC2LZfzfDudAIjIi zM_-G9Tf^4p`%)VAb;Jd51F6vcBE4zI;VlQS9?gsIUx`HA^>Utj?hmp>6~Xsiy}uXp z$(iEV9#pUvGwro(%&VQhAib8IMH{h60NTv2V}{y9hcM1jD33}6My%@gTI^8!@h8+0 zHw}_m!R*(DCw`!Ju${#%EhN+6yHv{{5NiNue{uC@ zmGU~pDxx&RZWT0-Tnvl(%=^}ssBt9@U+e1Io5&GSO z0v%>6pBg(qQDJ9V7#Q0tMd`cgZPwBPAxL!lB$umD+ew41V3&AHDSlLgo$smt^|htV zUCS}F6qA%ZtB1oS(IJ0huE>6pS2)?6@kPsSM?Q`P6Aqri zeNjj#7m$E;bco5=C`f;nc)wa{8oPoqpxk6=Kpax``}U27h_sbHnaPk2?YGCtbilBt z6*(@cj&>sO5DE|57oN6(T=+ZolEEgVwcc2*3m9A*uAkplQqqGjMsC8mhgwUZo3e>> z8u0WEd9AFSVy>IAs%uZ)=%wc;D-QeF@6^IB&$PLpwR(;d$rx$pYr4m>9`%>7&-T4z z*sf27z&{SIkM<28O$a&ogv#b)O`RtGMn6hhpEZ!8CI~3VLa@)bu@@ttm7H3 zI@5l_N5dRV4CwZ!3P^GqHa`A$cVfpyQ^W36Nk*;o%e}L))CVRO6 zZK^j5v%-`p{HSKf7YYn5%0F}Y%ZGqL;YCb^bQ5v-lw9Vf-=`gZjIzfjw9lUxl&;np z+o1#irbRmO+NXlfM#18a=W)Wn+K)y3{;8QToppWF2@VW0)26pK9Fp-indYo&x2kXVaC;I!#@5_sqtsygPImJb z;@A3iml}=@>v!qdxmJv|0t$M4#KabRO+eHoQM2pCHSFlK@GY`92K1zxk>bz#j%_l5 z3+=dl>OFe6zIe(al0`7(!mt!PB>{8UN8nyu?SI{a2Pu_4RoCom8t;KnI>m2P?aG&?_(Gy;T|Il`-t!R38s&X;at# z`n{&|>SOzZDxV?yWP+amezj^@)B3G$rj({sHntWQl#a9aC+KfZM;U`hE5gBbwx9VR zgEM|w99M#7s%1g)ENK3O6_$53?==ry{4GIy9dpbJu<5%<%7+Acsv>^4sD+mPL~Z=axS=$o;mZWF6X0rhl1) z+4sK%kx6Nt@|QnyWHG7dU0UMFaMU#q(>Ci(5nJqZ*+>yFkTO?}(3NO=L9xs{2h1ds zp*>}*+B0qmXw>Vd8A?7as8JP^S7q5D{COYoSZG<4zN)I$yIJ3cCBo<_7ss}- ztKiP`$3VW&gZ|S)x-35OiKAjDejPZt{Rz0C`3Im~xCkaOlb6)%DIE)`$sqXy&F?ld zMCgo`0=>Dd!oPJ>7B3i9P%g>rM7ZgNYkSkqe3%IoYGy}E(@rn!>=5nXh=^E=?Av07 zhTIB|V%#udG~j|n_?%buGMqzZ!r^7Bfiuj}2iCYKi=|^ooTvMbEQ-<9#0e;SqadL<8yyZ5nv?=LXvp&;j6>Rl%+rOeAk8y38qYBpPiS zS7~2O33M0daqP5KKs|DxeR46f8Ont3iu7xZSb=K|!E-=x=Om~51ED3!r~c2ng25Di zD#@rbaH>l3==cEqZnFVe^BNzqo!n{Ot(H>nb9_%#$(!lYo?qR#!i^6$_~vy&Wk}{U zLSK@qIPIJGIiv&&(PL-e(BsoSu=8hO`SS(>;4bs{YskyDS*X{dd0lcCq-G_r65&G1 zDXP3B()~CX6_V%CH@>x54Nqq|==y<}JIJ95pr8IlF;yoiE}G9z4bE)SRQqHZ_h7_$ z#%;uvVs~9h>G_3VxzG{&S9CY%uZ1or@{t{K%@A3!36{{QHCD2QE9yWXvBW<&ZmawYJ0y>`|7cFPu zeGR2z-nuRiYXF-^*KK7rHOz6_Tj1rDQT48LCHHC2B~`=?!88+5b(~KI-wB@QrIBL2 z@9&sbx+b4SHeD?%Jj5U~aZ(4+YuxPLGb>M~TlEN@b|6VV_0yFR-)H*Mfu*-o(!ee} zo37i=dzcTldYIPP@nMun*<7(r23mL$ zSC~-L-wTxoZCbVe!eF|A4GNI^rbYqTar zbDi4lIX!Y(eK&;NB@RliOAs)BKt@f<%<{$WO(T%f$W?kjILi3L&@s};FTw3(irDnn zMXRFbir;s^#^u-SheJ=ad_=$Aw7kICaz}}`>Xdt>e)lId4SH!)!!EUi^<}`V?TN?9 zGvy#50(+6hCi1w*yGc13Ob9gTPM`A)BNpOw{-w~-IiF)vFg!RJDYar(cr5DZ9`kqnHUROyU15J-}^x5wX!-> z+GN{f)o>D%xalRUC8i0FxFEfv@Po>Vpt0t~4BhXt$Dom}y0EX|g^Pw;dT$&g-JhWh znQM2R4ZQmokvo~3IVmPT#ji4TKXz4PtYDc_M7(tbl(>jPVmw^pP{1Q-{FgR>jjSml zlePS7(ObZV`Jb^(SMK0a8TDjX*FB~F#}p5=puo_UF3mP{meugrfV08d@i@?ubYt7h zXUmsGKASAYrtVjf;2WE|9Fn^^gKSKhigTcCln>M25(b2>WP$e^98O<4)LsS2`~uoY zwCNkPtebX9(EdZh`Jx2X+RbYgD(xH+zP9iZzQlcyk0Vz!2JG#xG1l~6nY3R=YHouR zJ0R8iVh|Vkxxd)znl+OtM4(|Hxo+ix&dB>TZ4J>zDhuz55NMH)RwV7`cU+K}7&~UO z1Q9nrKvEm6&GhDb3GsD`>xb@jbrMUL? zNIy(GpV9yFomadtS>0R@Xe9uPUW;l^)(AYnf{Pfs>1VJ87Xz)`qF(a4@2IgcAl;g} z*^~|Dg6~({4eJzRPH#QXHTn|cU#y7|qx-)tmh7LybvYbD{sL0PYWFRcOxs$fxmRB4 zO18A^)^60sd;eu3jF|l_uF8Y`1&2W+PV+i(k6L4~GL?q1*k8C7K{>Sv^c6q<+u3d% zut?`uhNZXMckR%q5ez(P*Uib2iv5GQZeFNSPCp$K|rK|yIMs_7Z zpPpSrpIQ5Xh#{wI(`pGkEqQTdhJNkO*tXz4nIhfPD+-@?HO9-3nDe&oJ)fh)G^nM7 z13&mBvl1Y+7~_1}h%>15p>3vpq{u$m^(4qcA)CN9(#+n=Pt+b%R2QMPf#ae3EW%I= zREGVq8~8nQX<28t4SOxh)A$sg>M1^@6&^~3tl@eyr7YPQH_AO(RU2m)P9_Qb=^$U? z$oI2BJ%&P#r(;k>bP>9-5cj@Z-fcml;oWjM$Ut1%W-p<~fsV~U=_!$N^rV+5mZgE( z@a|PaE)fWKW|2Cc<%eXAg9Vg){yD`;mp)HPNHM^Os8#D)csDtye9KMPidg*l>!_{S zX)-RJB^4+Wi8({jsD3aPt6B0+Pqs@g-9?4L#EQa=r9Sa7KF#??&8!uh+$j=wt=~3~ z#%FHl5D!drLdteKLgXF#U;r~)A{K~I5>(KSIlnPV;>H=vF2C(BoBAg2RdW|H+wDO_ zGW{^RnVC+Iipdl)u-DS9qU=G-acq+#$T$5^&10twL0}t92oNdakRhe}LNb0$2lgh= z^3eSE%QrYHd?v4^L#DIdJP^G2@LlV+{njJDEde&g8k8u3O^UpL*z**pl2N>vF=h(g z(7JCGFTDS?GKM!y9M^wxbeYeWF$$l~FyC?@WQ+D^FDvuEcoa{_ohae)Uh#fdUl281 zLsVEt`KyQV?EZD93y!{V-I1g_E_iz)8UqydpJ90y)Y$1T~C_-g=A6Ac^xoN_2w zm=Ql%ZY~rq3=EQ}#D0bk5Tipe_G+dIF2tEB%6pv54s#BC%Z|L_h9N6$k+oJ_HiPB% zs(J{U7LbOJabK#=`;Pi0p@AWyUTPJE1*YHL-*TMD6LfdW-VKhl&4w8L((v<#YZ${d zICiR^{RHv3(b7#Q1bm=Knrh$G4)>umuESct} zi9%%~um^U20uCt02SuY#B4~Wn{Rr*i<>#AFYYdmPJ*k-HMlk>e^TO^wa@sJM_i;g< z5KYg5uF>5=_LIR$T@fEF<6 z3I-IoVhpYG&;>jwhS#fUne6r$UPsckU>w6sO`b@wCychaCpZb29>k;!G>tTist|6|>45*^jRf)i%?(pE$5X^Id|1|{KHn{xWcEk?(oK}ux}>QO zSlls@SQe()(-Q_-UfXP@rQGP;O(55ZBdkt*e)g$yv)RPDnzKASkNsI*2-&b>ZPqkb z+582+VW+yT%DDX^zjtfi6lCa3|2xr##-Hv=wC)_aUHF>C&z2vU2zQyFSGD9jj>gos zv=QSLork45R=Hh(+760;bUpL6IM)|yHv8y?Zr14~>f7%?bfPQ2Yj>uecVKiB6HL!E z02^=0!S#)YG`w8v(Kw`%9 zk}-`F4u$WBMuTky5o zckxEr58XVYFAee6ej!73Zy~-d*M;F`4!CDT5+?y|qg0~b$#a=8L@xBjX(n<%4 zb(35?(I{ut4VN7s^bCJ0uT|sqnso$Wxg4XT6k*t^T5|D5gUlT-U#6M~$Zl9l2|s0u zOfa(?(JFUvADNXXyI*~~dF4z0@NSA=KpVsB{?sydOt4%FMmxXqw>bv;oZ#D7+VIcw60&z01wC+P9pfjC1$0A0!{SI6%@t_3Eqsk9ga-3gx{-c z36z~KfTK$%`W5qs+&)TusD1Rphgjsa5!KQa9iu?zftO8%x_wM3%VUJ@s#FQ&+ewv~ zY!y@@Hk&)N8m>;W$X{;6UG4aFW|3c>v(eB7$$x{)qoA7b43DMoX(vzHO4Q9bBum zY?zA9)Imab3RZW^Y5agJsySq1hWWI?RmXIt&%8Z4@x{U0srAN(7qEaa&;j7fYpMw( zdPS%SZ8M9jw=Rp{XHlxDC-4Sa$_X3yku%#tYVas z0Xl|bxM=U?gk4bZ63v}?9|F<)TPArrMQE{3l#}s1g_L7`II3ly+E5qXi`{+((&N?; z*VUN4XDE%OiRPg17(0R~syg7L#_)6^5&uxz=WzQ)nNe}Mxp++}-=M0Seq6_nR5=r%(B%(%em zY9-GC(@F_x?lzhLG0b#2|E<)GVdnJ?nwhsWp6GoaJGo}Q;C^Dy=~l@J7IPt5z7>UF zrpXhFe>1MdUmbbgB&3>=$Z**G7H}Gc`E2SP5>yRd=Ds(>};gfhIkMxWG{w zx5@QF!O?P>MduHq40AUqBA@Y|gu6Xb=!yz~{lK*vh~jQ|r4y}$hIlt}KS{W6;5a77 z;G_}Q&zvxZ`tPo$)Xvp`(luZ9C(y_zwukDyc>cst^VR<6WjgsPZB{Q9$>9>pMSI4e zf6qYIYT+R(A{B73_n`GmKM{>a=dWr2XLFIZ69oc1?oCQHlG?S7lNM@v%UHB`Savjz4zp8l*X&C$jkdM9bb~7S zZMq!b%cw^0;aidTm@Ilihk#`SKJjujEp4U8z%lX>jkj$lu9I%Wq!f)Jvot~apMCq@ zH=k=-Qktd+;6kfa!x0B^|M2!rNqL}6tdBX)2H#-p|n>oi$vai9J;mB!()H3_d)^Y@G*X#A~(2Ip7*?g?Lfv+i2Swv z;xZ5f{CRn*@VxgU7fwOxRR4-tvL=CtrS93He9Fl_9Xw8iHpIP%RJUpT@xb%2Vx1NL zn#=T3pNTRJS{nieT@as})_Byo)o-|8Nst86ubV@3}f7u`bI z$;B*HaLe&Nx_2yF57otGb?I;%%+URoXqD?vVK`}+b#Nst>yDqIT{;|hjc%~s--_xm zBE+GQC~G@~?aLfB%%a$TK}7ab?$EDTOb=BKko&R>1oxN9?=k$&xA`0qlj(D zWh{WJt^JJ_f<_~0qQgXylY>bJ0q0`x_yHuAB!N z$x~D_+fkLJet!>o>DM?@IA9oBW&DOWhw?|;XPh4yK-ZUETn}sEbzPY{O6H}|(7ptb ze{_qW^mpX&cX|`QBV`2}2q1ZY(^|MWJjtj2H<2BY=`Fq_>ZtM0UH9CXC5E4o66H>4 z=AsqPR*R;@4X5W2TJfkkPI#pypDdRJH`w#ldZ;YVSg29vHcoN2Zt;=HD-)3Ue9xg8 z>x*9xX>Zs^vx7GhoBaqb{c&-gz{!n_&w^k|dNI7bx4E%l& z23uJV(X~1u<-o2W%}?Re&&d~fVlg;|O?S%w``}1c_(MpPX7*x~ujGnw%xT!wyHq=bV48kZH{lV1b$2$0M~mJ`>fPn?dtyfd=14%;?f1{!Q%zLKIR zwnV{G}u?fsOO_Rn%@eehG%-lAS4@yL*9$2Wj zw1*W1(m`u+&+GdnV%v7B9Skc}QrdJ`84PZQ<fr9%twaD0{~b*3#@rer6Ar|k(dGjQywB{2etJXD2JQF@*UduKDp)v(}kgOn7m67 z+xR`LYe|do3UwVr-r{9fwuqSX<#*HNtGh>(lf$WE!4xW9&G$7kln&NZu21TI>)mr{ zd7V z*PhL5R+wa?*9dR`GPc|NAnGtd#&;BZi3KTIhsx=0bQmHX*(n&W6cIb0#h@Wh>4 z=80?#iznN{`8O>3{;zyNVr5|}Lh(4C`3gG9n94V>CXTF(0(2ljxI`BsL|yy!v|x@ zr4CVh-;1oHE$ku$x+|jgKetEUIpLD$6TItWw{3Q}$tj*@_QM&3II%w65Ku_$#R9A2 zmNEpyvBfP&8*_yuFK)Yt%eCAdbW;0etDbtE5hb^6tSfuXHqnd+L^HChag7j zH3>)mi_K|H>?o!lN9wd55v`2ee`^WmY^g3qVgeeb;Z?Klvg55vL4p@=-d)*0Zd4j> zHoW3wxK2}D!1OT~iln2RZ(D;q*Txx1?~3F+%y+rn)|7PdI3B**Y2(dRPa0c(K?P5G z738+Q=p8>^~gOI%xtFQ0>0ZTveJ?8@e zp076r)f((be|`gbv}~`sKkKBOGuEMJK43(Ax;(TMk~or@9Kef{Y!G-ujWy$al+hOq zn(@BMkGxSK7m36eH|KO`v^E+3ewY2;Xz|``nZKQ&IB~p1A{>O2fk_gz2RTWp1ttj< zqD~IO9h0LfvuN+c@mvOE#~pxmB+FO39@SLA?a%eRt4m6bc*n-VRWwnzEds}(y`<$? zPOX1GDyPalG1YiYU7wJc=24UZb^E|2W&416}xx+Cet z6TMM$#J>uyJc{Y4ywNTSI-surqHr!=HAo(hY4S#bq1wu|j)TXgP@3#lZ)_sb6|UKg zzkIdOiHH3;uKd+6i+cHbK1o8wdcSpC;j-YOg0{nlnvWHiR*0K*9{*O@@Xo3+d>mWbrJN>A`;H!x13o7t_f=9_C-PY>!b5=z_c zDhEOuuUO&JY?7CV{}~5K048I4MMlQIoBYoK(}1X^$fg{MtKjC2v~W_g+>ZpDpw`3U z*qIgXIMCsglxC1HA>2qk(5%J`pl4Ngq~&!Ce_guJoj4RrkaQ#9Iz|GZ;XiMsdr$CD zoVQ$6r8b;-8yOFhF{8IY^vQ^W`gWA6ZYwjPQe-Fa-Qmcyoe|b+ zHP#hP9H`@NeMa3~#o?~_Bp28rj^-HJMymmC=Hz{E4ufHrRCTSaw_=s8N}tA7UKPkB z)5;%+K0H1S$H~VNNoYxz6R+)1e8UN>SR8-J{YEN3ybKWrxwvyM( zPKZ8(2Y2mYGnkyxY_>w+FZ5~9wmA>S_sk@1r0^OJJ8|MSYR){&Y`Yao zLjy;D!$vH zIi7EP4h}re)z@&;BEL4n69k@Pdri6MbdEgckB}igX--2l!{(Tqkv&JBK}RdduO;7< z`igp&6l{*CAW%rFEl$=^httQM6d~iUoYwc~X%8PX5ZJk%?VPj6q+L!xKfLp8|9+R@ z-b8y(H6pLj8^$qp5EapVH{azo-rE^XUk&9p-pf7#;qT~^;MO@(C`Xop{w}`V!l8TJ z6RIamYg2ge8y4_Q{rO*9Sku=LiE{oIPagRjF@IuSA}(E38su&Wie+hQ$Zrx?^L96+ z?|N39xbT<5_GM#C^vA6j! zUMxDMx}G_>W3l9w6@SyU6;>0@+5X{1WS@SGdygCjOR0I7T9#@9E@t@(8d{ow8(5_G z>7l&AZQIJimE`l66muHv2nMj@dbp^Q@%NffnevW)O6lF3ozjyLQ>V{4C*9R|6J1dqvVb_r)f!No%iDn2I%g+gn?j&5fqM0l>XP_r^{feE201Ef!}x=j zZpOZ|&*j$d@tnWciODU_#{tYHuN)keSxgXJ??Q@Maf&{OJm99E6FiQ8z2+O^wsc%H%3(8XT4M~>Twk>74HEfUrypEw+!8JH3Gc;>7BxJ*#ln8&m9V#*zB8H9 z0BBt=x`psKWfGf|!AM$-(3(qHrB+g)PYq!E2&%&qR;d5Z@!&!65;WxAsxzK0A69Vq zmt`Iid&PBknkV>jJCrlq3b(-zOhc{Rkf`Dq6rEkE56bt`DS9#lL$e)54w~Y2mA28? zK?jWTbmzX3HQ_M4rpMU{+i{OOn2qzwbg1WrM$bBn`OZNWA<0o1hs`5^+!SB)rNfh+A-zyH;^9mCWYY3Nn>dtGGRgLz@K zZc+(isRjnL-tTpwD!EkSq2(ag54C?X;Qt!%iX1o3)B^ZEc&>@&QieI%hPv?j-Y>wc(!2gbkYj0WM4a3%h5j-3bENlqsz1ei-Oh z+4?-m<CHLeA@$LN?lw*=U)+IpE#Q zzKI5R&Z66t7b9ly9p!hU32Z^(TNLzfI+=7-*3Htx8XPE(9oZERNMaZ6DOh)W+Nfvf zbf9g4u#-Rf0@tC-N6@ODhCRu7o!5Qb`ZA=nwomIi__Zx1`5)OP5~#e}>9%XOHdZ-A zrDoao+xT$VF09u+M^9Q_+LcUA$fx2=nuv1ZpsH?(Rf29Al(%84)wc5CZ2i#539%DV zTIi3dy{L>}1U$!@6jOA^NY9Wz?8qdo2~`gEJ~=#ZKbu_81PBXHY)*4{C&VmqN7P=r zcAtKZOK+Ve5Y|`{)FW^KnO~{W@MJVpBL!c5i1L&=!&xenPRjJ7rf_U|&8WNm?JG@{ z)Z};;7RZdft8MQhYguP_?0re@fK-RQWXCht6TXg9C)&Lb?MCF29;4x7+P{N4gmM8} z)7*jh0R%=nyNPYnQ9-vuSUk&r4O|)x+H z(WWmG$9Jm}JhFw#x?Q(01H%0^eNGA8mYhRK#pgagqy#pYrNg6^80-T~_=wJ)PEAoe zK<5mpn6K0&W3Va>?K(WZ%dRp%VUWvhi5|&AtBgFLFBDa8z3Eaed zHNp^I*VJUiI`znKB%S>jr|r#UQZ6p1pAzN#jrL3c%wnS9(I)#Fd!Ak$O+d;6dv$@=E5t*!j(ZtN z%MYT;zgC<#)H;Tiuugd+5dMfIcp}h<$0?)&9l(N^${Qd^oKF4;riZ)Z*k|hv@wdBi zu(@7pOeG&(+GfTGE0xF7obPCphP<`gvoR>1{!`(zTbOzC(1%5}e7E@9!#p!~yZ}R) z`^*81avxd8H13(jN-+kAi=Ns%dC;!(i_!!oRmLQEUz+&UoA3i&)fi_MLfOY3Yc@61 zlLwNww7s^=*Yp^!mXf_sFO+7zz8`$&>rC9Lnd_jQ-1El27paJ}@Y#w_^*Q5(mNY`P zvg@FmlJ=P}4Q+$OEylH0CElqOvU=3wIPS})ON8d;A@{sVj6qA)Hw|!y?(Y6b{NYsY zf@~eUpZZDDPTVil&$sjCfgc^f9DPQXUiL((x+{J!tI~$YCmLH7waH z^z>4sq+5LIMkYKh`S>&}vGFsbQlO5v;IP=2_QuoE^B0xv;PuV4vLC)@aktmUYmx_U zE+pjl8L|8up0!}P)kFpbN@Lw4cIUcxd#Wo@By{ZMlYyevH2Ar-uW>tF`*cgG>E?$< z%47HRLfsr**hDA7=d;lVPVc0TR;#UCyVjHA_J@U`fjYs{pDF^?&MTeknXI32r5+PMkUjRk5h%MCcA|a z?BF<=NcZfL(jB%!&VEgirp0%GjK^MI10oulJ6}yZtyd;w4;I!|H3RJ+$Zt5>*Q6On z%5DXT{iSxrIVdV8rE=<qZywtr-5JXxxZv5Z{v~P)8{&Cs70| zPs6*hbfnj%s>5Tfp$0|V_pD;%kp@f#Ca$Y4TAF33v9kSnQZT}64D~`>v9elzK6^Z} zaJ^N$z$%ybVyYe*XOX!E2Gm?a6H7t2iGoCqBfNIOT3$Var(?HjH+v5l#Jz8?e0lX_ zh%pzxg(2HBm5l8xhHU%$K9{<%$+TV|JJ-RzJ&I5H8ECShZ$Uda7M_3m%C_L1L#)MSgE+>O>df z=;l)d_bjGYY5BU2+7;wuj&M*K3wwIetCHrM=KGFc{K;!PDP-JZLqD%SqIKkF>M7*K{@Jjp7CyY-C)sk~~-S!#1*)9ZDA2 zbBn8g>)33y{woJMO!!vTm_`Iw3l^y>c`X`J1Xq_{505n1L647d_HK)z!EMBTSoi6J zuyAJJV()G5-+_Z|Uk$bc&z--Ogq1d@!*bDN-g2v5n?b1Oa*Rr@r!)*Ma+7x(uj^S$ z*IjtD%FGZ=V<0N7|qoRFMr!mi~vGj64*mgh!% z0YbNj8bP(6{R&|vV@w4rCp~-8yg--XtwZqF3I*;ONo8(?AAPt;in?q8o+p5!l=9MmxbV$T8sc_dO7m5EDT$T<*>527Tq{ zi3P7l6lID?bpwOy>-Sz*jdpCr*P~Zs{K&WMFVsP#*rcfCB&L7<{n_dwbr}5?c(W-^ zr?<*Jki3fx%er>4bft^HlEX6g+N0F`B_kEiL|^;l(prhAF?yrtBje+4-gXU&Aj4VF zcIuf`U++ICfvHm8Y@qFB8rFHM${}oaeByu*O{F@9%9C!V`8$03wMgEkfF2VQ&R=ZgKxoo(gnPtc}Nw~^iUOTfnxR+ z>`T-OmW@^7+z_uQl~!w)8OJ&M7Pe{QJDIF`ex+nhi9xGO^HOHvNTFFs-IlQMiC9~m zT)B@6dd;r<2}KRV<&)cKh&)jsh7>8ZZRljc!H5^JyZgP{<7?iunI(p6Uf&W+`o%xo zfm0~_)Q%c{gIMXp$&GlC&qrdJ2U$fi*nOT#^h8!pJF#I`E7oH-N3w~o$NG-5&X3pZ zU0=teL&~$`X2IE&+FT#iLI6a@;L2`_73|p!yISqU+{_KqE=Zyl!!E|Chc8;pp5Cb@ z#(h>iRLraAsPbFXq+q&|%GW8mH8o58pqj>~tOZ!BG^Bz&rxg259#F9Zpp!vzMxg0pd+)s3ZId8#)_ zcNAc5A^L>`hBqW=y-h;p{6Dv#cK_yp&G&fO2eu{YU2SP*S{SH#6IarHqrPieR_Lqr z=R22+)#oe)ngrHc(}a=ioMaWpS1NQ5iZkESHJJxWG*m2cDxRjN0gdaw4t*GRbdf5Q zNt~*h60D6w4VBvUd`-0Tx!x#+ilQI&bO9fO2RSr;X{1$g(RvN7BO+TQFGn{%oUz?5 zojoC@pIh`5T?4P#2%K+}>i&$*2AWqdYN144Ryml{&t&HO(fHJ~wEx1M?#ChPHOuV% z+p%^LQ}xf()tTUFTJ$@K|9-~XA~LH_8a6EXyp|B${6j4g)|1Zq;!dSfV0gu~dpC?`gJ`AvCM2;Eh8=#A@N^LHwO!&5h@lvLj$M8yxL( zm#sH;UPQ2$DVK@1s)tYizsAxZQOMk!veA%Gy8R;9~ytu?!`#C0_6l0*f3_ z$3Ffu3*7m>P$bI3kn;l8Z^){6cM7+6Xv4t6fFJxnk47jW*$cD;KeB}AythHl;XmE^;B6m{CZhYCdi0!cA`iC@bk`gi?uopN_T z@@p}>?^AhHIB|Bpo#t^#67;9HWX?1jDTV`SETn+Mc9HP)0oXzdyQTB_o=zy>CL8{?9itAJ4F(aW3lp zf))chj8ghvKayf?!HN$hzB|MJ`M6dMjY_vmLl7na`H#o@EBayckTPL-`X3+L=c3QP zd)#V&$C3Yd{4XpVJ=WI*|M39ypGal2(9doJE@=J7H!*+mqbXGULiykHwWOfkzlIS2 zy!=1^Bl@44qAC1^$M;`^VEKz;Vx?T7Ad~-n!~cuSE;NPwB*y>y?*7-a{{IXA|8(Jz zVlCHJ&D#Hci%2D6_X%xeG@w@KfGs8o6CV8^Xv_i8Jgqq@s#E)~n@7f>G3vEK6t(o< zxU&mJLwed{e1`o$AHulbgGNl#A)xEvzd-F@BZDLX)CONuSj_b^DC|D@PvmGa?b}zh zG85SQJg?UD7=GpdUv$w2`B^-e*7Pzdb@9{1f&KKYBKjWq-?Sv*74_Y>zEGm@*v&); zwmdwfAM~xU} z`99z0d*GaVFyS@5l^8xDg3q6&@ak5hQj*hSjfVN65{tElfHgnO)mp&mNB~9Bgp1bS%0)5?TW}K&S$oNw0o1@QmN4On%AF$X6$T%ZH-4> zd>V(Dt@%M3s#i!Y;_U+m;ltu4oR85kYc!}rAYT1-JVgIHc80=&EsXw%-iP_wii=l7 zpM}xwCuT+Vjy9hN_Wz(07{?=9*9i>R4Kl4v3U=4H+Fo{O19#&b8|`CoUG^56(?vRhSZ|4^LRLR*Z46^WOH%Q4f{}uMGec+2qSFHSq ziT*L^hJ{8kN$m@Z*=bS&G);g=&$Y@Crjpmi%^Tdm#GBd`;n5ZiJ|cExQU%wCf2;f} z;a85BzHGb@cbn3ndFP@@+xBtK#=6gK+mTlz(Zllh_fC9F#q5|~Q+FV*$+CH{`)JJ- znc>KJG96omlbj)uIjXu-U0z$_G0y3y-4!>PS(^TeGsT# zY)*uaJAmqH?l<5h*0`FEPs;5qJKHFD;7d$v-PZWbw+EZ04(u=gNx%PPL5uB<_v1yY z-bD^t*}BslGugFWUIJX-V^z@j0JLPFA%>A#U$cVT5?^8@z4s?>SVoI|eHjg{;?K9E z-~VBn@%V`6^}3&K==B2Q-eRZroALX4gXQ}{u_XFC$GCK6W zrkqI}K;$^-vKOCt)`T}ll-PMVs4uTgsnPmP`?vhvG2+u_&Dwc1{yaaUc3}mV8@6(6 z&vIlyuS1;m9f7~yM|o@8VI6xFemaIOT1Iq-qj9TWMp-Fnd5=p6Fz>VrKzPO2M1faU zeSgcvO}vw}{3Vn{=k)jKvDJiU4YDJ3X#t&n+EB>W$ex6tN48xSL9(Vw>f)fXwdZX% zv4m{AraG^})~k3;wF&NRFmyqZj@>|(bXj(4LNV1C>n#_}24c8E;WtkkEIOl4$b&kA zK8l15r(_u8_c>yhvCF#? z_E+@hARkK!JgsZiCk5$$k-f!h+Z!D|$WgJ>^P$^a$LKPms>)ua#EjrRwEmRw+D()6 zHi>=*k|cGJ^F`lTlZ4H`aMcD+%+&{Kq#MGxB&5=RhC&c=lI~YRk+64l@G9zt1550l z+P8yJH#QcT^CZ1*rjszpxno5V4%$nDuIZhfwP{kERvXIa(KUZ+pP0(;i_%2k>1m{X zIGr<6z?i+<<<~$Otg{e(XSx#Lwx9(l%ZX~t=ke~NlJAe{YTJR0uW^0&(^c-cKzU%l zIuWyM^zbWwm7Knh%nOA?mFWB(WN%ka39Er(%`D*r!(94*Tu)FI;4&Sop*k_rW)IK6Xa)6u9-(B zT~O82+}r-A_W>@{ert=57k*r7U}wSPL;J+CYAj527Qx(GAtjYBR!;;tP5he;UYk`C zX#OEtvE>qh0(2Y;B(pLFa2Thr0$k5YI!C6{sIfU)tCEniqE<=5mEJ9B?{_WD+lA#O zws#L{-CL3F3g>dQ_1}#zmFGPk@PoaR7an=$$_{QotIwnSI$7OHX=T56x?UaZ-uy15 zdzUsHQ$5Hrp-W1LI3EFGcrSV%rljry2P;g?tYzRc+u6R>OAKx{S89;LUzgO2dxoQw zb!wmZ%VFIO8J8}|X{#ZTtz+H=Sx(X~1)}9ulu?XZ>^s=G%zo&+@=B6m#;A zt?jlgeuhi1LrS@{gi31f?ns$Qi3KYfC}t@Op!WnG*1O0YI1BzIJ*A*uR87fQtx0%Nys}+$0|pYdIF6g z2dA*Ptp?7AZ)_bgKf<1@I>`&uAuFw_sT*sX;AyfMcts6(p#ib_KBi~ZG=-Nkg==+L zuCmi1A?k@ZKTb@PM6e|}^e7+A z-Y5=^DK-~ajwYkOiG6dGc+8Wxt-sC*$+{g5YXf4(uY`O1H2^(x6Znn^iuQ6aY|%Xm z0U#4CWHd~*7?H2tww7|)Y=7f6Pu(dmW^x^=N*9D2IQb%=Z&nn|{IIK?XDb%&N6MDI z=TY%6b0TMY9IJHo!&(I6!L*Lqy`K$C0l^p-M{>aj)P8T{o@-S3qo_bimHcv&M|l-< z0D-Hp$B2OfdLnbut8?CSaTT%@kfRspZR?tkDPPH8jv5_%Igk@Br-gDOkeu8CQlL&^ zIxazByqpS8B$4-~^rs3CV?YDT-A8CK`nEOk=oUM+WBy9&LGDF6Z9F$AFf-k|y&B;N zT+@u&!P*u`8wQUweG4Q6SKd)lqC**`UcCvyIYTKvIce#7WNYKPW}kM<<*xZ#7x>od zYHWoT^C{ErBXfdHV|geC>f=%p_l`~-U0I(+S62*x4Ri^-r^5B^NGa(UE}-gh6BQ4{ zioI~E`}zHF97D}JZuC}+d$p;jc$;7t7IL2{#LH*5{gG1j}b1^7wR>21Ye_n z1=MCPdGq^~wA`ai`)JrmL5zl2C0{sd5~jldT!NoA8m7x;-L|He4oCX*ISge^8JHSZ z3x&_eZEj(Y*YAN$1ardG4`7v-D>8tY#-g|Hza8_fqyYuF(4=Dn<8}T!@bA}B|5SU! z3~REm6LDkKAyE3k7p-FxB7_US*>Ppa8uco~Zzb4t1?tU0loM~NgN$f#XI^--8=^*< zvaF*JUM#-wkEc%2gkP-MiZ6IOJi#=c&T#kY1JRO4o`pBQ+b1ivLIOYogj=>|f=F## z|G}PjGUU9ex)AH_qywrM+9djsyR8E}I$=QIgo*(F=S5|vnqb%x^ROi^Vh|BZ{L~yq z*V!&3jbja_$5wzoTTQZ$EVfi6G*ZReRqTYS@u&>)1q`>YW~7%!aatbA6Z%1vwrh2d z7W(G*;JvCMe#~*zfi!R4Gf#2xbrQ&kd>0FEs$s27hgw0bt6dT4#9=!AmOID|E|w3R zFU3S=o`37kJ{68e@Tk#Ew{xmgWvw);!i`Syp7Yil*^~R8P^cskv}Cmq2j`mA88pkp{=-jCfL_B zvGgL0zbStM zUhclOZtMQz!K;x1grZCUtW!kxUO$>8-?EQOuL7KRY7w2p;Jif;BUNu6uVk~B+6pA| zG>b z979s_KP4+r+?C-#P3A`^=fcT6zZ*5yg5UAvk|a_ee}U-={;d6I7Ru}-P22Sp;1Sxn zzWxjj;n+}Q*&-_`_k*vp%vBN^mYYsbwf1&RcaUzqkgA6VC_^vh$fs_C{4{2bMU(F@;ti>Dyd<*3l`~V0vi%+2>`+1k@M{U>p<~Cyyh}@_#Bkzhb=qjpgre+7B*Bu zrF4-J+zz_RuPOZ8@(5DC+~~VDFP>3afRq_ja36ukiY#H~eMc@TG+C6rpMH8r>%^KG z^r!o=yyS9i`29NzwkmO31<2|8cn<+ z4?g2OXnv+z;eu4(eq8FVsW?E&1)mbmE6=qSzDvJxp#+AIV4Ab@3R#dUt!Vi$xk}G} zKN@ni%G5%db*nE2Y*Om3p>No6=2}EfGN=TkLuPwB*iSc#tLSn|v{+#|n*N~lt7A~& zq9l(V=MtSQMlMsOD-u)fOWHz70I><}wA>LD*qPyA71hJ3Or=BAeQT7SqYvOAayK== ztw(>#Q9111V#xquW*e(eK}@(GDg?(Hy0*2T>_qcF6#>6Yr9nzhNXdh1+Uw-PxGv`k z5|CJ5`A=p;Z59h6vT-W0kXxeOIs5`3(v+=8eAQMx9YuSzMLEu`c^7m8@EwF~Ra1DydmzGr~*D3#d*qiS28V zq~oD#yHkA77)Ww(ZJN*Pv9+{vv~<(t{nS`#!KW|6+S;O&=4l&DTv&iU5@}Z>@Ay~t*SKfl=?frhQcw^Yd=YK0 zUNgXNpVKLNphRe3PSpy`39w&6;v1~{+XxttNOck|JnnHX1q@Vk{CBXRBTI$By`dR7 z4wL0META}-hbgf`@0%#-5z@>DQANHGJu+^;C!QbQBg$j#5^?%}pViJ3m@FdG(GCCt ztZ&FtM^rsF2P}x_)5)mA7L~I~X^qKvAvX4vCc!s{XY-AuydE6obkq;Db2B@&NMtop zo=>=`hdO3gxz}3D+~tm_#rt5dYuMO|8A3=%)R@;Gd{7Qeq1^MwyEHvxA)TuzZy
TcmmyUQ|P zeMt7NwQ);Fd`0ijhb>~nBNd;BgJ?Q@1|2F8n=_l=$!MVtXwm#F@wvvnEQ_^7)&8qz z5pQ<&gJTAUw}_mfnpFi<$or3b^QgMoGLp9TE~lBrSJ!ac9y}{;FSDEO7Oo46@el>% z?d!`r!G=PwghaK+0Qtn%=VL7uVw7+&Al~8}ew#>@Wt%wRU>wY(*7;y|;x40+ah~ zTr*+#J)-nObb8mrP%oyhH<17KZVk4=oQ)-tO|<*LBx=P#OGy+}z>XEJ8t3qDLqUjg z)UjMS25e*P%@;;s5f9d=*`xEDXLg^_ya|xIb!b(U(g0Zpf=q;h z{`6zQJ82opr!X=1!7$;#fGG26#%=i&vKEzlX0|^!rB<+n8Im;tP=U9@Uv^#9eH~x( zeF^>^MrbDGOmiFP1!Pf$I(EM_XveH%xh|zUll*;%5(-SimkN0oc05AO-m-d5*0dGi zSCATa?N2jn@*y?I(AnJmvuX$z4kfBku|B=$ET%I4z@!NW6?84nTT_4i8lF*88-a~G z@6q!g*l#&|ny1#q)bRoLK0TewbyE=LXrR32wzZT%@HzMdkCzn9o^1{y`ZYN{qV*>} zo1$UpvwmT8(i$A>~};#C_Mrz zh?}j?%EmJ}Z0xt0ar^`Mnnt^!|5JKaxh<0C;a)3eyXswW=%Gec5MRvctGP#fdU2d4 zj~lGxHZ#uf@ZI2+DXbXOafvy5D2vTl~Q1YN#Y(`L;hH zT()6zIFl}Xv~}&33XWZT*Z1KVCL~E%J~c1uY2+xso-N&&?Zs$LQnKX#n4_;O>WfrO zCk$m<-I3bhMuzqV8&$&5em!e-o#G{U7V)tVaaD}W?0%7YRUS-0Y1Z`RrY(j7*s~d~ zq;MI=;yxixt)c{7LwMtFyf!wf_RD5GB7B;%ytM5o{Rwm5dV9;C`GcUK`u>Q$*qV5M z7QC*Lkh>VvGk%LpwEhE+!hk$6Ypqmmc2#B(X;O~z7425Rp1Z`%Hgfltl zrn8@ges0M*JWgL$5DdOtvr!QHBevD`UrDOqMTjp+R0Y@X%3S35AX^V3J+1F($nP!q z&o2mYxzfhr-$-<$PA{5n52Jo;+gZc47?ou+x811ED`>GeOFfizOBlZ@jBm?X{i163 z+Av;i!R*RLz1VHkb4};@qSaR1IktIhZGsyZ3T@`1v)HMNl*6hc)1=l2J*{Hhru{oo ze|ZRzyhZL#lys2VBJ{;F&dJfS4eSpFBMTvmR3+@AtBsx`F}8DaFA&PB2VSbm4sCG? zbGo!fWwMFK7-AESBCmD)R(&!u)9SJA_bQ{mj332qKJW`nQ6uHAJ?1Zw>i_HAxF1G8 a8ioF&%Gj^{`f~&D_2Y@t#~D9_{QO_!f^lL1 literal 0 HcmV?d00001 diff --git a/picojson.h b/picojson.h new file mode 100644 index 0000000..045dc53 --- /dev/null +++ b/picojson.h @@ -0,0 +1,1039 @@ +/* + * Copyright 2009-2010 Cybozu Labs, Inc. + * Copyright 2011-2014 Kazuho Oku + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef picojson_h +#define picojson_h + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// for isnan/isinf +#if __cplusplus>=201103L +# include +#else +extern "C" { +# ifdef _MSC_VER +# include +# elif defined(__INTEL_COMPILER) +# include +# else +# include +# endif +} +#endif + +#ifndef PICOJSON_USE_RVALUE_REFERENCE +# if (defined(__cpp_rvalue_references) && __cpp_rvalue_references >= 200610) || (defined(_MSC_VER) && _MSC_VER >= 1600) +# define PICOJSON_USE_RVALUE_REFERENCE 1 +# else +# define PICOJSON_USE_RVALUE_REFERENCE 0 +# endif +#endif//PICOJSON_USE_RVALUE_REFERENCE + + +// experimental support for int64_t (see README.mkdn for detail) +#ifdef PICOJSON_USE_INT64 +# define __STDC_FORMAT_MACROS +# include +# include +#endif + +// to disable the use of localeconv(3), set PICOJSON_USE_LOCALE to 0 +#ifndef PICOJSON_USE_LOCALE +# define PICOJSON_USE_LOCALE 1 +#endif +#if PICOJSON_USE_LOCALE +extern "C" { +# include +} +#endif + +#ifndef PICOJSON_ASSERT +# define PICOJSON_ASSERT(e) do { if (! (e)) throw std::runtime_error(#e); } while (0) +#endif + +#ifdef _MSC_VER + #define SNPRINTF _snprintf_s + #pragma warning(push) + #pragma warning(disable : 4244) // conversion from int to char + #pragma warning(disable : 4127) // conditional expression is constant + #pragma warning(disable : 4702) // unreachable code +#else + #define SNPRINTF snprintf +#endif + +namespace picojson { + + enum { + null_type, + boolean_type, + number_type, + string_type, + array_type, + object_type +#ifdef PICOJSON_USE_INT64 + , int64_type +#endif + }; + + enum { + INDENT_WIDTH = 2 + }; + + struct null {}; + + class value { + public: + typedef std::vector array; + typedef std::map object; + union _storage { + bool boolean_; + double number_; +#ifdef PICOJSON_USE_INT64 + int64_t int64_; +#endif + std::string* string_; + array* array_; + object* object_; + }; + protected: + int type_; + _storage u_; + public: + value(); + value(int type, bool); + explicit value(bool b); +#ifdef PICOJSON_USE_INT64 + explicit value(int64_t i); +#endif + explicit value(double n); + explicit value(const std::string& s); + explicit value(const array& a); + explicit value(const object& o); + explicit value(const char* s); + value(const char* s, size_t len); + ~value(); + value(const value& x); + value& operator=(const value& x); +#if PICOJSON_USE_RVALUE_REFERENCE + value(value&& x)throw(); + value& operator=(value&& x)throw(); +#endif + void swap(value& x)throw(); + template bool is() const; + template const T& get() const; + template T& get(); + bool evaluate_as_boolean() const; + const value& get(size_t idx) const; + const value& get(const std::string& key) const; + value& get(size_t idx); + value& get(const std::string& key); + + bool contains(size_t idx) const; + bool contains(const std::string& key) const; + std::string to_str() const; + template void serialize(Iter os, bool prettify = false) const; + std::string serialize(bool prettify = false) const; + private: + template value(const T*); // intentionally defined to block implicit conversion of pointer to bool + template static void _indent(Iter os, int indent); + template void _serialize(Iter os, int indent) const; + std::string _serialize(int indent) const; + }; + + typedef value::array array; + typedef value::object object; + + inline value::value() : type_(null_type) {} + + inline value::value(int type, bool) : type_(type) { + switch (type) { +#define INIT(p, v) case p##type: u_.p = v; break + INIT(boolean_, false); + INIT(number_, 0.0); +#ifdef PICOJSON_USE_INT64 + INIT(int64_, 0); +#endif + INIT(string_, new std::string()); + INIT(array_, new array()); + INIT(object_, new object()); +#undef INIT + default: break; + } + } + + inline value::value(bool b) : type_(boolean_type) { + u_.boolean_ = b; + } + +#ifdef PICOJSON_USE_INT64 + inline value::value(int64_t i) : type_(int64_type) { + u_.int64_ = i; + } +#endif + + inline value::value(double n) : type_(number_type) { + if ( +#ifdef _MSC_VER + ! _finite(n) +#elif __cplusplus>=201103L || !(defined(isnan) && defined(isinf)) + std::isnan(n) || std::isinf(n) +#else + isnan(n) || isinf(n) +#endif + ) { + throw std::overflow_error(""); + } + u_.number_ = n; + } + + inline value::value(const std::string& s) : type_(string_type) { + u_.string_ = new std::string(s); + } + + inline value::value(const array& a) : type_(array_type) { + u_.array_ = new array(a); + } + + inline value::value(const object& o) : type_(object_type) { + u_.object_ = new object(o); + } + + inline value::value(const char* s) : type_(string_type) { + u_.string_ = new std::string(s); + } + + inline value::value(const char* s, size_t len) : type_(string_type) { + u_.string_ = new std::string(s, len); + } + + inline value::~value() { + switch (type_) { +#define DEINIT(p) case p##type: delete u_.p; break + DEINIT(string_); + DEINIT(array_); + DEINIT(object_); +#undef DEINIT + default: break; + } + } + + inline value::value(const value& x) : type_(x.type_) { + switch (type_) { +#define INIT(p, v) case p##type: u_.p = v; break + INIT(string_, new std::string(*x.u_.string_)); + INIT(array_, new array(*x.u_.array_)); + INIT(object_, new object(*x.u_.object_)); +#undef INIT + default: + u_ = x.u_; + break; + } + } + + inline value& value::operator=(const value& x) { + if (this != &x) { + value t(x); + swap(t); + } + return *this; + } + +#if PICOJSON_USE_RVALUE_REFERENCE + inline value::value(value&& x)throw() : type_(null_type) { + swap(x); + } + inline value& value::operator=(value&& x)throw() { + swap(x); + return *this; + } +#endif + inline void value::swap(value& x)throw() { + std::swap(type_, x.type_); + std::swap(u_, x.u_); + } + +#define IS(ctype, jtype) \ + template <> inline bool value::is() const { \ + return type_ == jtype##_type; \ + } + IS(null, null) + IS(bool, boolean) +#ifdef PICOJSON_USE_INT64 + IS(int64_t, int64) +#endif + IS(std::string, string) + IS(array, array) + IS(object, object) +#undef IS + template <> inline bool value::is() const { + return type_ == number_type +#ifdef PICOJSON_USE_INT64 + || type_ == int64_type +#endif + ; + } + +#define GET(ctype, var) \ + template <> inline const ctype& value::get() const { \ + PICOJSON_ASSERT("type mismatch! call is() before get()" \ + && is()); \ + return var; \ + } \ + template <> inline ctype& value::get() { \ + PICOJSON_ASSERT("type mismatch! call is() before get()" \ + && is()); \ + return var; \ + } + GET(bool, u_.boolean_) + GET(std::string, *u_.string_) + GET(array, *u_.array_) + GET(object, *u_.object_) +#ifdef PICOJSON_USE_INT64 + GET(double, (type_ == int64_type && (const_cast(this)->type_ = number_type, const_cast(this)->u_.number_ = u_.int64_), u_.number_)) + GET(int64_t, u_.int64_) +#else + GET(double, u_.number_) +#endif +#undef GET + + inline bool value::evaluate_as_boolean() const { + switch (type_) { + case null_type: + return false; + case boolean_type: + return u_.boolean_; + case number_type: + return u_.number_ != 0; +#ifdef PICOJSON_USE_INT64 + case int64_type: + return u_.int64_ != 0; +#endif + case string_type: + return ! u_.string_->empty(); + default: + return true; + } + } + + inline const value& value::get(size_t idx) const { + static value s_null; + PICOJSON_ASSERT(is()); + return idx < u_.array_->size() ? (*u_.array_)[idx] : s_null; + } + + inline value& value::get(size_t idx) { + static value s_null; + PICOJSON_ASSERT(is()); + return idx < u_.array_->size() ? (*u_.array_)[idx] : s_null; + } + + inline const value& value::get(const std::string& key) const { + static value s_null; + PICOJSON_ASSERT(is()); + object::const_iterator i = u_.object_->find(key); + return i != u_.object_->end() ? i->second : s_null; + } + + inline value& value::get(const std::string& key) { + static value s_null; + PICOJSON_ASSERT(is()); + object::iterator i = u_.object_->find(key); + return i != u_.object_->end() ? i->second : s_null; + } + + inline bool value::contains(size_t idx) const { + PICOJSON_ASSERT(is()); + return idx < u_.array_->size(); + } + + inline bool value::contains(const std::string& key) const { + PICOJSON_ASSERT(is()); + object::const_iterator i = u_.object_->find(key); + return i != u_.object_->end(); + } + + inline std::string value::to_str() const { + switch (type_) { + case null_type: return "null"; + case boolean_type: return u_.boolean_ ? "true" : "false"; +#ifdef PICOJSON_USE_INT64 + case int64_type: { + char buf[sizeof("-9223372036854775808")]; + SNPRINTF(buf, sizeof(buf), "%" PRId64, u_.int64_); + return buf; + } +#endif + case number_type: { + char buf[256]; + double tmp; + SNPRINTF(buf, sizeof(buf), fabs(u_.number_) < (1ULL << 53) && modf(u_.number_, &tmp) == 0 ? "%.f" : "%.17g", u_.number_); +#if PICOJSON_USE_LOCALE + char *decimal_point = localeconv()->decimal_point; + if (strcmp(decimal_point, ".") != 0) { + size_t decimal_point_len = strlen(decimal_point); + for (char *p = buf; *p != '\0'; ++p) { + if (strncmp(p, decimal_point, decimal_point_len) == 0) { + return std::string(buf, p) + "." + (p + decimal_point_len); + } + } + } +#endif + return buf; + } + case string_type: return *u_.string_; + case array_type: return "array"; + case object_type: return "object"; + default: PICOJSON_ASSERT(0); +#ifdef _MSC_VER + __assume(0); +#endif + } + return std::string(); + } + + template void copy(const std::string& s, Iter oi) { + std::copy(s.begin(), s.end(), oi); + } + + template void serialize_str(const std::string& s, Iter oi) { + *oi++ = '"'; + for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) { + switch (*i) { +#define MAP(val, sym) case val: copy(sym, oi); break + MAP('"', "\\\""); + MAP('\\', "\\\\"); + MAP('/', "\\/"); + MAP('\b', "\\b"); + MAP('\f', "\\f"); + MAP('\n', "\\n"); + MAP('\r', "\\r"); + MAP('\t', "\\t"); +#undef MAP + default: + if (static_cast(*i) < 0x20 || *i == 0x7f) { + char buf[7]; + SNPRINTF(buf, sizeof(buf), "\\u%04x", *i & 0xff); + copy(buf, buf + 6, oi); + } else { + *oi++ = *i; + } + break; + } + } + *oi++ = '"'; + } + + template void value::serialize(Iter oi, bool prettify) const { + return _serialize(oi, prettify ? 0 : -1); + } + + inline std::string value::serialize(bool prettify) const { + return _serialize(prettify ? 0 : -1); + } + + template void value::_indent(Iter oi, int indent) { + *oi++ = '\n'; + for (int i = 0; i < indent * INDENT_WIDTH; ++i) { + *oi++ = ' '; + } + } + + template void value::_serialize(Iter oi, int indent) const { + switch (type_) { + case string_type: + serialize_str(*u_.string_, oi); + break; + case array_type: { + *oi++ = '['; + if (indent != -1) { + ++indent; + } + for (array::const_iterator i = u_.array_->begin(); + i != u_.array_->end(); + ++i) { + if (i != u_.array_->begin()) { + *oi++ = ','; + } + if (indent != -1) { + _indent(oi, indent); + } + i->_serialize(oi, indent); + } + if (indent != -1) { + --indent; + if (! u_.array_->empty()) { + _indent(oi, indent); + } + } + *oi++ = ']'; + break; + } + case object_type: { + *oi++ = '{'; + if (indent != -1) { + ++indent; + } + for (object::const_iterator i = u_.object_->begin(); + i != u_.object_->end(); + ++i) { + if (i != u_.object_->begin()) { + *oi++ = ','; + } + if (indent != -1) { + _indent(oi, indent); + } + serialize_str(i->first, oi); + *oi++ = ':'; + if (indent != -1) { + *oi++ = ' '; + } + i->second._serialize(oi, indent); + } + if (indent != -1) { + --indent; + if (! u_.object_->empty()) { + _indent(oi, indent); + } + } + *oi++ = '}'; + break; + } + default: + copy(to_str(), oi); + break; + } + if (indent == 0) { + *oi++ = '\n'; + } + } + + inline std::string value::_serialize(int indent) const { + std::string s; + _serialize(std::back_inserter(s), indent); + return s; + } + + template class input { + protected: + Iter cur_, end_; + int last_ch_; + bool ungot_; + int line_; + public: + input(const Iter& first, const Iter& last) : cur_(first), end_(last), last_ch_(-1), ungot_(false), line_(1) {} + int getc() { + if (ungot_) { + ungot_ = false; + return last_ch_; + } + if (cur_ == end_) { + last_ch_ = -1; + return -1; + } + if (last_ch_ == '\n') { + line_++; + } + last_ch_ = *cur_ & 0xff; + ++cur_; + return last_ch_; + } + void ungetc() { + if (last_ch_ != -1) { + PICOJSON_ASSERT(! ungot_); + ungot_ = true; + } + } + Iter cur() const { return cur_; } + int line() const { return line_; } + void skip_ws() { + while (1) { + int ch = getc(); + if (! (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')) { + ungetc(); + break; + } + } + } + bool expect(int expect) { + skip_ws(); + if (getc() != expect) { + ungetc(); + return false; + } + return true; + } + bool match(const std::string& pattern) { + for (std::string::const_iterator pi(pattern.begin()); + pi != pattern.end(); + ++pi) { + if (getc() != *pi) { + ungetc(); + return false; + } + } + return true; + } + }; + + template inline int _parse_quadhex(input &in) { + int uni_ch = 0, hex; + for (int i = 0; i < 4; i++) { + if ((hex = in.getc()) == -1) { + return -1; + } + if ('0' <= hex && hex <= '9') { + hex -= '0'; + } else if ('A' <= hex && hex <= 'F') { + hex -= 'A' - 0xa; + } else if ('a' <= hex && hex <= 'f') { + hex -= 'a' - 0xa; + } else { + in.ungetc(); + return -1; + } + uni_ch = uni_ch * 16 + hex; + } + return uni_ch; + } + + template inline bool _parse_codepoint(String& out, input& in) { + int uni_ch; + if ((uni_ch = _parse_quadhex(in)) == -1) { + return false; + } + if (0xd800 <= uni_ch && uni_ch <= 0xdfff) { + if (0xdc00 <= uni_ch) { + // a second 16-bit of a surrogate pair appeared + return false; + } + // first 16-bit of surrogate pair, get the next one + if (in.getc() != '\\' || in.getc() != 'u') { + in.ungetc(); + return false; + } + int second = _parse_quadhex(in); + if (! (0xdc00 <= second && second <= 0xdfff)) { + return false; + } + uni_ch = ((uni_ch - 0xd800) << 10) | ((second - 0xdc00) & 0x3ff); + uni_ch += 0x10000; + } + if (uni_ch < 0x80) { + out.push_back(uni_ch); + } else { + if (uni_ch < 0x800) { + out.push_back(0xc0 | (uni_ch >> 6)); + } else { + if (uni_ch < 0x10000) { + out.push_back(0xe0 | (uni_ch >> 12)); + } else { + out.push_back(0xf0 | (uni_ch >> 18)); + out.push_back(0x80 | ((uni_ch >> 12) & 0x3f)); + } + out.push_back(0x80 | ((uni_ch >> 6) & 0x3f)); + } + out.push_back(0x80 | (uni_ch & 0x3f)); + } + return true; + } + + template inline bool _parse_string(String& out, input& in) { + while (1) { + int ch = in.getc(); + if (ch < ' ') { + in.ungetc(); + return false; + } else if (ch == '"') { + return true; + } else if (ch == '\\') { + if ((ch = in.getc()) == -1) { + return false; + } + switch (ch) { +#define MAP(sym, val) case sym: out.push_back(val); break + MAP('"', '\"'); + MAP('\\', '\\'); + MAP('/', '/'); + MAP('b', '\b'); + MAP('f', '\f'); + MAP('n', '\n'); + MAP('r', '\r'); + MAP('t', '\t'); +#undef MAP + case 'u': + if (! _parse_codepoint(out, in)) { + return false; + } + break; + default: + return false; + } + } else { + out.push_back(ch); + } + } + return false; + } + + template inline bool _parse_array(Context& ctx, input& in) { + if (! ctx.parse_array_start()) { + return false; + } + size_t idx = 0; + if (in.expect(']')) { + return ctx.parse_array_stop(idx); + } + do { + if (! ctx.parse_array_item(in, idx)) { + return false; + } + idx++; + } while (in.expect(',')); + return in.expect(']') && ctx.parse_array_stop(idx); + } + + template inline bool _parse_object(Context& ctx, input& in) { + if (! ctx.parse_object_start()) { + return false; + } + if (in.expect('}')) { + return true; + } + do { + std::string key; + if (! in.expect('"') + || ! _parse_string(key, in) + || ! in.expect(':')) { + return false; + } + if (! ctx.parse_object_item(in, key)) { + return false; + } + } while (in.expect(',')); + return in.expect('}'); + } + + template inline std::string _parse_number(input& in) { + std::string num_str; + while (1) { + int ch = in.getc(); + if (('0' <= ch && ch <= '9') || ch == '+' || ch == '-' + || ch == 'e' || ch == 'E') { + num_str.push_back(ch); + } else if (ch == '.') { +#if PICOJSON_USE_LOCALE + num_str += localeconv()->decimal_point; +#else + num_str.push_back('.'); +#endif + } else { + in.ungetc(); + break; + } + } + return num_str; + } + + template inline bool _parse(Context& ctx, input& in) { + in.skip_ws(); + int ch = in.getc(); + switch (ch) { +#define IS(ch, text, op) case ch: \ + if (in.match(text) && op) { \ + return true; \ + } else { \ + return false; \ + } + IS('n', "ull", ctx.set_null()); + IS('f', "alse", ctx.set_bool(false)); + IS('t', "rue", ctx.set_bool(true)); +#undef IS + case '"': + return ctx.parse_string(in); + case '[': + return _parse_array(ctx, in); + case '{': + return _parse_object(ctx, in); + default: + if (('0' <= ch && ch <= '9') || ch == '-') { + double f; + char *endp; + in.ungetc(); + std::string num_str = _parse_number(in); + if (num_str.empty()) { + return false; + } +#ifdef PICOJSON_USE_INT64 + { + errno = 0; + intmax_t ival = strtoimax(num_str.c_str(), &endp, 10); + if (errno == 0 + && std::numeric_limits::min() <= ival + && ival <= std::numeric_limits::max() + && endp == num_str.c_str() + num_str.size()) { + ctx.set_int64(ival); + return true; + } + } +#endif + f = strtod(num_str.c_str(), &endp); + if (endp == num_str.c_str() + num_str.size()) { + ctx.set_number(f); + return true; + } + return false; + } + break; + } + in.ungetc(); + return false; + } + + class deny_parse_context { + public: + bool set_null() { return false; } + bool set_bool(bool) { return false; } +#ifdef PICOJSON_USE_INT64 + bool set_int64(int64_t) { return false; } +#endif + bool set_number(double) { return false; } + template bool parse_string(input&) { return false; } + bool parse_array_start() { return false; } + template bool parse_array_item(input&, size_t) { + return false; + } + bool parse_array_stop(size_t) { return false; } + bool parse_object_start() { return false; } + template bool parse_object_item(input&, const std::string&) { + return false; + } + }; + + class default_parse_context { + protected: + value* out_; + public: + default_parse_context(value* out) : out_(out) {} + bool set_null() { + *out_ = value(); + return true; + } + bool set_bool(bool b) { + *out_ = value(b); + return true; + } +#ifdef PICOJSON_USE_INT64 + bool set_int64(int64_t i) { + *out_ = value(i); + return true; + } +#endif + bool set_number(double f) { + *out_ = value(f); + return true; + } + template bool parse_string(input& in) { + *out_ = value(string_type, false); + return _parse_string(out_->get(), in); + } + bool parse_array_start() { + *out_ = value(array_type, false); + return true; + } + template bool parse_array_item(input& in, size_t) { + array& a = out_->get(); + a.push_back(value()); + default_parse_context ctx(&a.back()); + return _parse(ctx, in); + } + bool parse_array_stop(size_t) { return true; } + bool parse_object_start() { + *out_ = value(object_type, false); + return true; + } + template bool parse_object_item(input& in, const std::string& key) { + object& o = out_->get(); + default_parse_context ctx(&o[key]); + return _parse(ctx, in); + } + private: + default_parse_context(const default_parse_context&); + default_parse_context& operator=(const default_parse_context&); + }; + + class null_parse_context { + public: + struct dummy_str { + void push_back(int) {} + }; + public: + null_parse_context() {} + bool set_null() { return true; } + bool set_bool(bool) { return true; } +#ifdef PICOJSON_USE_INT64 + bool set_int64(int64_t) { return true; } +#endif + bool set_number(double) { return true; } + template bool parse_string(input& in) { + dummy_str s; + return _parse_string(s, in); + } + bool parse_array_start() { return true; } + template bool parse_array_item(input& in, size_t) { + return _parse(*this, in); + } + bool parse_array_stop(size_t) { return true; } + bool parse_object_start() { return true; } + template bool parse_object_item(input& in, const std::string&) { + return _parse(*this, in); + } + private: + null_parse_context(const null_parse_context&); + null_parse_context& operator=(const null_parse_context&); + }; + + // obsolete, use the version below + template inline std::string parse(value& out, Iter& pos, const Iter& last) { + std::string err; + pos = parse(out, pos, last, &err); + return err; + } + + template inline Iter _parse(Context& ctx, const Iter& first, const Iter& last, std::string* err) { + input in(first, last); + if (! _parse(ctx, in) && err != NULL) { + char buf[64]; + SNPRINTF(buf, sizeof(buf), "syntax error at line %d near: ", in.line()); + *err = buf; + while (1) { + int ch = in.getc(); + if (ch == -1 || ch == '\n') { + break; + } else if (ch >= ' ') { + err->push_back(ch); + } + } + } + return in.cur(); + } + + template inline Iter parse(value& out, const Iter& first, const Iter& last, std::string* err) { + default_parse_context ctx(&out); + return _parse(ctx, first, last, err); + } + + inline std::string parse(value& out, const std::string& s) { + std::string err; + parse(out, s.begin(), s.end(), &err); + return err; + } + + inline std::string parse(value& out, std::istream& is) { + std::string err; + parse(out, std::istreambuf_iterator(is.rdbuf()), + std::istreambuf_iterator(), &err); + return err; + } + + template struct last_error_t { + static std::string s; + }; + template std::string last_error_t::s; + + inline void set_last_error(const std::string& s) { + last_error_t::s = s; + } + + inline const std::string& get_last_error() { + return last_error_t::s; + } + + inline bool operator==(const value& x, const value& y) { + if (x.is()) + return y.is(); +#define PICOJSON_CMP(type) \ + if (x.is()) \ + return y.is() && x.get() == y.get() + PICOJSON_CMP(bool); + PICOJSON_CMP(double); + PICOJSON_CMP(std::string); + PICOJSON_CMP(array); + PICOJSON_CMP(object); +#undef PICOJSON_CMP + PICOJSON_ASSERT(0); +#ifdef _MSC_VER + __assume(0); +#endif + return false; + } + + inline bool operator!=(const value& x, const value& y) { + return ! (x == y); + } +} + +#if !PICOJSON_USE_RVALUE_REFERENCE +namespace std { + template<> inline void swap(picojson::value& x, picojson::value& y) + { + x.swap(y); + } +} +#endif + +inline std::istream& operator>>(std::istream& is, picojson::value& x) +{ + picojson::set_last_error(std::string()); + std::string err = picojson::parse(x, is); + if (! err.empty()) { + picojson::set_last_error(err); + is.setstate(std::ios::failbit); + } + return is; +} + +inline std::ostream& operator<<(std::ostream& os, const picojson::value& x) +{ + x.serialize(std::ostream_iterator(os)); + return os; +} +#ifdef _MSC_VER + #pragma warning(pop) +#endif + +#endif diff --git a/stb_image.h b/stb_image.h new file mode 100644 index 0000000..0a9de39 --- /dev/null +++ b/stb_image.h @@ -0,0 +1,6509 @@ +/* stb_image - v2.08 - public domain image loader - http://nothings.org/stb_image.h + no warranty implied; use at your own risk + + Do this: + #define STB_IMAGE_IMPLEMENTATION + before you include this file in *one* C or C++ file to create the implementation. + + // i.e. it should look like this: + #include ... + #include ... + #include ... + #define STB_IMAGE_IMPLEMENTATION + #include "stb_image.h" + + You can #define STBI_ASSERT(x) before the #include to avoid using assert.h. + And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free + + + QUICK NOTES: + Primarily of interest to game developers and other people who can + avoid problematic images and only need the trivial interface + + JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) + PNG 1/2/4/8-bit-per-channel (16 bpc not supported) + + TGA (not sure what subset, if a subset) + BMP non-1bpp, non-RLE + PSD (composited view only, no extra channels, 8/16 bit-per-channel) + + GIF (*comp always reports as 4-channel) + HDR (radiance rgbE format) + PIC (Softimage PIC) + PNM (PPM and PGM binary only) + + Animated GIF still needs a proper API, but here's one way to do it: + http://gist.github.com/urraka/685d9a6340b26b830d49 + + - decode from memory or through FILE (define STBI_NO_STDIO to remove code) + - decode from arbitrary I/O callbacks + - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON) + + Full documentation under "DOCUMENTATION" below. + + + Revision 2.00 release notes: + + - Progressive JPEG is now supported. + + - PPM and PGM binary formats are now supported, thanks to Ken Miller. + + - x86 platforms now make use of SSE2 SIMD instructions for + JPEG decoding, and ARM platforms can use NEON SIMD if requested. + This work was done by Fabian "ryg" Giesen. SSE2 is used by + default, but NEON must be enabled explicitly; see docs. + + With other JPEG optimizations included in this version, we see + 2x speedup on a JPEG on an x86 machine, and a 1.5x speedup + on a JPEG on an ARM machine, relative to previous versions of this + library. The same results will not obtain for all JPGs and for all + x86/ARM machines. (Note that progressive JPEGs are significantly + slower to decode than regular JPEGs.) This doesn't mean that this + is the fastest JPEG decoder in the land; rather, it brings it + closer to parity with standard libraries. If you want the fastest + decode, look elsewhere. (See "Philosophy" section of docs below.) + + See final bullet items below for more info on SIMD. + + - Added STBI_MALLOC, STBI_REALLOC, and STBI_FREE macros for replacing + the memory allocator. Unlike other STBI libraries, these macros don't + support a context parameter, so if you need to pass a context in to + the allocator, you'll have to store it in a global or a thread-local + variable. + + - Split existing STBI_NO_HDR flag into two flags, STBI_NO_HDR and + STBI_NO_LINEAR. + STBI_NO_HDR: suppress implementation of .hdr reader format + STBI_NO_LINEAR: suppress high-dynamic-range light-linear float API + + - You can suppress implementation of any of the decoders to reduce + your code footprint by #defining one or more of the following + symbols before creating the implementation. + + STBI_NO_JPEG + STBI_NO_PNG + STBI_NO_BMP + STBI_NO_PSD + STBI_NO_TGA + STBI_NO_GIF + STBI_NO_HDR + STBI_NO_PIC + STBI_NO_PNM (.ppm and .pgm) + + - You can request *only* certain decoders and suppress all other ones + (this will be more forward-compatible, as addition of new decoders + doesn't require you to disable them explicitly): + + STBI_ONLY_JPEG + STBI_ONLY_PNG + STBI_ONLY_BMP + STBI_ONLY_PSD + STBI_ONLY_TGA + STBI_ONLY_GIF + STBI_ONLY_HDR + STBI_ONLY_PIC + STBI_ONLY_PNM (.ppm and .pgm) + + Note that you can define multiples of these, and you will get all + of them ("only x" and "only y" is interpreted to mean "only x&y"). + + - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still + want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB + + - Compilation of all SIMD code can be suppressed with + #define STBI_NO_SIMD + It should not be necessary to disable SIMD unless you have issues + compiling (e.g. using an x86 compiler which doesn't support SSE + intrinsics or that doesn't support the method used to detect + SSE2 support at run-time), and even those can be reported as + bugs so I can refine the built-in compile-time checking to be + smarter. + + - The old STBI_SIMD system which allowed installing a user-defined + IDCT etc. has been removed. If you need this, don't upgrade. My + assumption is that almost nobody was doing this, and those who + were will find the built-in SIMD more satisfactory anyway. + + - RGB values computed for JPEG images are slightly different from + previous versions of stb_image. (This is due to using less + integer precision in SIMD.) The C code has been adjusted so + that the same RGB values will be computed regardless of whether + SIMD support is available, so your app should always produce + consistent results. But these results are slightly different from + previous versions. (Specifically, about 3% of available YCbCr values + will compute different RGB results from pre-1.49 versions by +-1; + most of the deviating values are one smaller in the G channel.) + + - If you must produce consistent results with previous versions of + stb_image, #define STBI_JPEG_OLD and you will get the same results + you used to; however, you will not get the SIMD speedups for + the YCbCr-to-RGB conversion step (although you should still see + significant JPEG speedup from the other changes). + + Please note that STBI_JPEG_OLD is a temporary feature; it will be + removed in future versions of the library. It is only intended for + near-term back-compatibility use. + + + Latest revision history: + 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA + 2.07 (2015-09-13) partial animated GIF support + limited 16-bit PSD support + minor bugs, code cleanup, and compiler warnings + 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value + 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning + 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit + 2.03 (2015-04-12) additional corruption checking + stbi_set_flip_vertically_on_load + fix NEON support; fix mingw support + 2.02 (2015-01-19) fix incorrect assert, fix warning + 2.01 (2015-01-17) fix various warnings + 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG + 2.00 (2014-12-25) optimize JPEG, including x86 SSE2 & ARM NEON SIMD + progressive JPEG + PGM/PPM support + STBI_MALLOC,STBI_REALLOC,STBI_FREE + STBI_NO_*, STBI_ONLY_* + GIF bugfix + 1.48 (2014-12-14) fix incorrectly-named assert() + 1.47 (2014-12-14) 1/2/4-bit PNG support (both grayscale and paletted) + optimize PNG + fix bug in interlaced PNG with user-specified channel count + + See end of file for full revision history. + + + ============================ Contributors ========================= + + Image formats Bug fixes & warning fixes + Sean Barrett (jpeg, png, bmp) Marc LeBlanc + Nicolas Schulz (hdr, psd) Christpher Lloyd + Jonathan Dummer (tga) Dave Moore + Jean-Marc Lienher (gif) Won Chun + Tom Seddon (pic) the Horde3D community + Thatcher Ulrich (psd) Janez Zemva + Ken Miller (pgm, ppm) Jonathan Blow + urraka@github (animated gif) Laurent Gomila + Aruelien Pocheville + Ryamond Barbiero + David Woo + Extensions, features Martin Golini + Jetro Lauha (stbi_info) Roy Eltham + Martin "SpartanJ" Golini (stbi_info) Luke Graham + James "moose2000" Brown (iPhone PNG) Thomas Ruf + Ben "Disch" Wenger (io callbacks) John Bartholomew + Omar Cornut (1/2/4-bit PNG) Ken Hamada + Nicolas Guillemot (vertical flip) Cort Stratton + Richard Mitton (16-bit PSD) Blazej Dariusz Roszkowski + Thibault Reuille + Paul Du Bois + Guillaume George + Jerry Jansson + Hayaki Saito + Johan Duparc + Ronny Chevalier + Optimizations & bugfixes Michal Cichon + Fabian "ryg" Giesen Tero Hanninen + Arseny Kapoulkine Sergio Gonzalez + Cass Everitt + Engin Manap + If your name should be here but Martins Mozeiko + isn't, let Sean know. Joseph Thomson + Phil Jordan + Nathan Reed + Michaelangel007@github + Nick Verigakis + +LICENSE + +This software is in the public domain. Where that dedication is not +recognized, you are granted a perpetual, irrevocable license to copy, +distribute, and modify this file as you see fit. + +*/ + +#ifndef STBI_INCLUDE_STB_IMAGE_H +#define STBI_INCLUDE_STB_IMAGE_H + +// DOCUMENTATION +// +// Limitations: +// - no 16-bit-per-channel PNG +// - no 12-bit-per-channel JPEG +// - no JPEGs with arithmetic coding +// - no 1-bit BMP +// - GIF always returns *comp=4 +// +// Basic usage (see HDR discussion below for HDR usage): +// int x,y,n; +// unsigned char *data = stbi_load(filename, &x, &y, &n, 0); +// // ... process data if not NULL ... +// // ... x = width, y = height, n = # 8-bit components per pixel ... +// // ... replace '0' with '1'..'4' to force that many components per pixel +// // ... but 'n' will always be the number that it would have been if you said 0 +// stbi_image_free(data) +// +// Standard parameters: +// int *x -- outputs image width in pixels +// int *y -- outputs image height in pixels +// int *comp -- outputs # of image components in image file +// int req_comp -- if non-zero, # of image components requested in result +// +// The return value from an image loader is an 'unsigned char *' which points +// to the pixel data, or NULL on an allocation failure or if the image is +// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels, +// with each pixel consisting of N interleaved 8-bit components; the first +// pixel pointed to is top-left-most in the image. There is no padding between +// image scanlines or between pixels, regardless of format. The number of +// components N is 'req_comp' if req_comp is non-zero, or *comp otherwise. +// If req_comp is non-zero, *comp has the number of components that _would_ +// have been output otherwise. E.g. if you set req_comp to 4, you will always +// get RGBA output, but you can check *comp to see if it's trivially opaque +// because e.g. there were only 3 channels in the source image. +// +// An output image with N components has the following components interleaved +// in this order in each pixel: +// +// N=#comp components +// 1 grey +// 2 grey, alpha +// 3 red, green, blue +// 4 red, green, blue, alpha +// +// If image loading fails for any reason, the return value will be NULL, +// and *x, *y, *comp will be unchanged. The function stbi_failure_reason() +// can be queried for an extremely brief, end-user unfriendly explanation +// of why the load failed. Define STBI_NO_FAILURE_STRINGS to avoid +// compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly +// more user-friendly ones. +// +// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. +// +// =========================================================================== +// +// Philosophy +// +// stb libraries are designed with the following priorities: +// +// 1. easy to use +// 2. easy to maintain +// 3. good performance +// +// Sometimes I let "good performance" creep up in priority over "easy to maintain", +// and for best performance I may provide less-easy-to-use APIs that give higher +// performance, in addition to the easy to use ones. Nevertheless, it's important +// to keep in mind that from the standpoint of you, a client of this library, +// all you care about is #1 and #3, and stb libraries do not emphasize #3 above all. +// +// Some secondary priorities arise directly from the first two, some of which +// make more explicit reasons why performance can't be emphasized. +// +// - Portable ("ease of use") +// - Small footprint ("easy to maintain") +// - No dependencies ("ease of use") +// +// =========================================================================== +// +// I/O callbacks +// +// I/O callbacks allow you to read from arbitrary sources, like packaged +// files or some other source. Data read from callbacks are processed +// through a small internal buffer (currently 128 bytes) to try to reduce +// overhead. +// +// The three functions you must define are "read" (reads some bytes of data), +// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). +// +// =========================================================================== +// +// SIMD support +// +// The JPEG decoder will try to automatically use SIMD kernels on x86 when +// supported by the compiler. For ARM Neon support, you must explicitly +// request it. +// +// (The old do-it-yourself SIMD API is no longer supported in the current +// code.) +// +// On x86, SSE2 will automatically be used when available based on a run-time +// test; if not, the generic C versions are used as a fall-back. On ARM targets, +// the typical path is to have separate builds for NEON and non-NEON devices +// (at least this is true for iOS and Android). Therefore, the NEON support is +// toggled by a build flag: define STBI_NEON to get NEON loops. +// +// The output of the JPEG decoder is slightly different from versions where +// SIMD support was introduced (that is, for versions before 1.49). The +// difference is only +-1 in the 8-bit RGB channels, and only on a small +// fraction of pixels. You can force the pre-1.49 behavior by defining +// STBI_JPEG_OLD, but this will disable some of the SIMD decoding path +// and hence cost some performance. +// +// If for some reason you do not want to use any of SIMD code, or if +// you have issues compiling it, you can disable it entirely by +// defining STBI_NO_SIMD. +// +// =========================================================================== +// +// HDR image support (disable by defining STBI_NO_HDR) +// +// stb_image now supports loading HDR images in general, and currently +// the Radiance .HDR file format, although the support is provided +// generically. You can still load any file through the existing interface; +// if you attempt to load an HDR file, it will be automatically remapped to +// LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; +// both of these constants can be reconfigured through this interface: +// +// stbi_hdr_to_ldr_gamma(2.2f); +// stbi_hdr_to_ldr_scale(1.0f); +// +// (note, do not use _inverse_ constants; stbi_image will invert them +// appropriately). +// +// Additionally, there is a new, parallel interface for loading files as +// (linear) floats to preserve the full dynamic range: +// +// float *data = stbi_loadf(filename, &x, &y, &n, 0); +// +// If you load LDR images through this interface, those images will +// be promoted to floating point values, run through the inverse of +// constants corresponding to the above: +// +// stbi_ldr_to_hdr_scale(1.0f); +// stbi_ldr_to_hdr_gamma(2.2f); +// +// Finally, given a filename (or an open file or memory block--see header +// file for details) containing image data, you can query for the "most +// appropriate" interface to use (that is, whether the image is HDR or +// not), using: +// +// stbi_is_hdr(char *filename); +// +// =========================================================================== +// +// iPhone PNG support: +// +// By default we convert iphone-formatted PNGs back to RGB, even though +// they are internally encoded differently. You can disable this conversion +// by by calling stbi_convert_iphone_png_to_rgb(0), in which case +// you will always just get the native iphone "format" through (which +// is BGR stored in RGB). +// +// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per +// pixel to remove any premultiplied alpha *only* if the image file explicitly +// says there's premultiplied data (currently only happens in iPhone images, +// and only if iPhone convert-to-rgb processing is on). +// + + +#ifndef STBI_NO_STDIO +#include +#endif // STBI_NO_STDIO + +#define STBI_VERSION 1 + +enum +{ + STBI_default = 0, // only used for req_comp + + STBI_grey = 1, + STBI_grey_alpha = 2, + STBI_rgb = 3, + STBI_rgb_alpha = 4 +}; + +typedef unsigned char stbi_uc; + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef STB_IMAGE_STATIC +#define STBIDEF static +#else +#define STBIDEF extern +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// PRIMARY API - works on images of any type +// + +// +// load image by filename, open file, or memory buffer +// + +typedef struct +{ + int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read + void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative + int (*eof) (void *user); // returns nonzero if we are at end of file/data +} stbi_io_callbacks; + +STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *comp, int req_comp); +STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *comp, int req_comp); +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *comp, int req_comp); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +// for stbi_load_from_file, file pointer is left pointing immediately after image +#endif + +#ifndef STBI_NO_LINEAR + STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *comp, int req_comp); + STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); + STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp); + + #ifndef STBI_NO_STDIO + STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); + #endif +#endif + +#ifndef STBI_NO_HDR + STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); + STBIDEF void stbi_hdr_to_ldr_scale(float scale); +#endif + +#ifndef STBI_NO_LINEAR + STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); + STBIDEF void stbi_ldr_to_hdr_scale(float scale); +#endif // STBI_NO_HDR + +// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename); +STBIDEF int stbi_is_hdr_from_file(FILE *f); +#endif // STBI_NO_STDIO + + +// get a VERY brief reason for failure +// NOT THREADSAFE +STBIDEF const char *stbi_failure_reason (void); + +// free the loaded image -- this is just free() +STBIDEF void stbi_image_free (void *retval_from_stbi_load); + +// get image dimensions & components without fully decoding +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); + +#endif + + + +// for image formats that explicitly notate that they have premultiplied alpha, +// we just return the colors as stored in the file. set this flag to force +// unpremultiplication. results are undefined if the unpremultiply overflow. +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); + +// indicate whether we should process iphone images back to canonical format, +// or just pass them through "as-is" +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); + +// flip the image vertically, so the first pixel in the output array is the bottom left +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); + +// ZLIB client - used by PNG, available for other purposes + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); +STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + +STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + + +#ifdef __cplusplus +} +#endif + +// +// +//// end header file ///////////////////////////////////////////////////// +#endif // STBI_INCLUDE_STB_IMAGE_H + +#ifdef STB_IMAGE_IMPLEMENTATION + +#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \ + || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \ + || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \ + || defined(STBI_ONLY_ZLIB) + #ifndef STBI_ONLY_JPEG + #define STBI_NO_JPEG + #endif + #ifndef STBI_ONLY_PNG + #define STBI_NO_PNG + #endif + #ifndef STBI_ONLY_BMP + #define STBI_NO_BMP + #endif + #ifndef STBI_ONLY_PSD + #define STBI_NO_PSD + #endif + #ifndef STBI_ONLY_TGA + #define STBI_NO_TGA + #endif + #ifndef STBI_ONLY_GIF + #define STBI_NO_GIF + #endif + #ifndef STBI_ONLY_HDR + #define STBI_NO_HDR + #endif + #ifndef STBI_ONLY_PIC + #define STBI_NO_PIC + #endif + #ifndef STBI_ONLY_PNM + #define STBI_NO_PNM + #endif +#endif + +#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB) +#define STBI_NO_ZLIB +#endif + + +#include +#include // ptrdiff_t on osx +#include +#include + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +#include // ldexp +#endif + +#ifndef STBI_NO_STDIO +#include +#endif + +#ifndef STBI_ASSERT +#include +#define STBI_ASSERT(x) assert(x) +#endif + + +#ifndef _MSC_VER + #ifdef __cplusplus + #define stbi_inline inline + #else + #define stbi_inline + #endif +#else + #define stbi_inline __forceinline +#endif + + +#ifdef _MSC_VER +typedef unsigned short stbi__uint16; +typedef signed short stbi__int16; +typedef unsigned int stbi__uint32; +typedef signed int stbi__int32; +#else +#include +typedef uint16_t stbi__uint16; +typedef int16_t stbi__int16; +typedef uint32_t stbi__uint32; +typedef int32_t stbi__int32; +#endif + +// should produce compiler error if size is wrong +typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; + +#ifdef _MSC_VER +#define STBI_NOTUSED(v) (void)(v) +#else +#define STBI_NOTUSED(v) (void)sizeof(v) +#endif + +#ifdef _MSC_VER +#define STBI_HAS_LROTL +#endif + +#ifdef STBI_HAS_LROTL + #define stbi_lrot(x,y) _lrotl(x,y) +#else + #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) +#endif + +#if defined(STBI_MALLOC) && defined(STBI_FREE) && defined(STBI_REALLOC) +// ok +#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) +// ok +#else +#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC." +#endif + +#ifndef STBI_MALLOC +#define STBI_MALLOC(sz) malloc(sz) +#define STBI_REALLOC(p,sz) realloc(p,sz) +#define STBI_FREE(p) free(p) +#endif + +// x86/x64 detection +#if defined(__x86_64__) || defined(_M_X64) +#define STBI__X64_TARGET +#elif defined(__i386) || defined(_M_IX86) +#define STBI__X86_TARGET +#endif + +#if defined(__GNUC__) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) +// NOTE: not clear do we actually need this for the 64-bit path? +// gcc doesn't support sse2 intrinsics unless you compile with -msse2, +// (but compiling with -msse2 allows the compiler to use SSE2 everywhere; +// this is just broken and gcc are jerks for not fixing it properly +// http://www.virtualdub.org/blog/pivot/entry.php?id=363 ) +#define STBI_NO_SIMD +#endif + +#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD) +// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET +// +// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the +// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant. +// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not +// simultaneously enabling "-mstackrealign". +// +// See https://github.com/nothings/stb/issues/81 for more information. +// +// So default to no SSE2 on 32-bit MinGW. If you've read this far and added +// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2. +#define STBI_NO_SIMD +#endif + +#if !defined(STBI_NO_SIMD) && defined(STBI__X86_TARGET) +#define STBI_SSE2 +#include + +#ifdef _MSC_VER + +#if _MSC_VER >= 1400 // not VC6 +#include // __cpuid +static int stbi__cpuid3(void) +{ + int info[4]; + __cpuid(info,1); + return info[3]; +} +#else +static int stbi__cpuid3(void) +{ + int res; + __asm { + mov eax,1 + cpuid + mov res,edx + } + return res; +} +#endif + +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name + +static int stbi__sse2_available() +{ + int info3 = stbi__cpuid3(); + return ((info3 >> 26) & 1) != 0; +} +#else // assume GCC-style if not VC++ +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) + +static int stbi__sse2_available() +{ +#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 408 // GCC 4.8 or later + // GCC 4.8+ has a nice way to do this + return __builtin_cpu_supports("sse2"); +#else + // portable way to do this, preferably without using GCC inline ASM? + // just bail for now. + return 0; +#endif +} +#endif +#endif + +// ARM NEON +#if defined(STBI_NO_SIMD) && defined(STBI_NEON) +#undef STBI_NEON +#endif + +#ifdef STBI_NEON +#include +// assume GCC or Clang on ARM targets +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) +#endif + +#ifndef STBI_SIMD_ALIGN +#define STBI_SIMD_ALIGN(type, name) type name +#endif + +/////////////////////////////////////////////// +// +// stbi__context struct and start_xxx functions + +// stbi__context structure is our basic context used by all images, so it +// contains all the IO context, plus some basic image information +typedef struct +{ + stbi__uint32 img_x, img_y; + int img_n, img_out_n; + + stbi_io_callbacks io; + void *io_user_data; + + int read_from_callbacks; + int buflen; + stbi_uc buffer_start[128]; + + stbi_uc *img_buffer, *img_buffer_end; + stbi_uc *img_buffer_original, *img_buffer_original_end; +} stbi__context; + + +static void stbi__refill_buffer(stbi__context *s); + +// initialize a memory-decode context +static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) +{ + s->io.read = NULL; + s->read_from_callbacks = 0; + s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; + s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len; +} + +// initialize a callback-based context +static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user) +{ + s->io = *c; + s->io_user_data = user; + s->buflen = sizeof(s->buffer_start); + s->read_from_callbacks = 1; + s->img_buffer_original = s->buffer_start; + stbi__refill_buffer(s); + s->img_buffer_original_end = s->img_buffer_end; +} + +#ifndef STBI_NO_STDIO + +static int stbi__stdio_read(void *user, char *data, int size) +{ + return (int) fread(data,1,size,(FILE*) user); +} + +static void stbi__stdio_skip(void *user, int n) +{ + fseek((FILE*) user, n, SEEK_CUR); +} + +static int stbi__stdio_eof(void *user) +{ + return feof((FILE*) user); +} + +static stbi_io_callbacks stbi__stdio_callbacks = +{ + stbi__stdio_read, + stbi__stdio_skip, + stbi__stdio_eof, +}; + +static void stbi__start_file(stbi__context *s, FILE *f) +{ + stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f); +} + +//static void stop_file(stbi__context *s) { } + +#endif // !STBI_NO_STDIO + +static void stbi__rewind(stbi__context *s) +{ + // conceptually rewind SHOULD rewind to the beginning of the stream, + // but we just rewind to the beginning of the initial buffer, because + // we only use it after doing 'test', which only ever looks at at most 92 bytes + s->img_buffer = s->img_buffer_original; + s->img_buffer_end = s->img_buffer_original_end; +} + +#ifndef STBI_NO_JPEG +static int stbi__jpeg_test(stbi__context *s); +static stbi_uc *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNG +static int stbi__png_test(stbi__context *s); +static stbi_uc *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_BMP +static int stbi__bmp_test(stbi__context *s); +static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_TGA +static int stbi__tga_test(stbi__context *s); +static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s); +static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_HDR +static int stbi__hdr_test(stbi__context *s); +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_test(stbi__context *s); +static stbi_uc *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_GIF +static int stbi__gif_test(stbi__context *s); +static stbi_uc *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNM +static int stbi__pnm_test(stbi__context *s); +static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +// this is not threadsafe +static const char *stbi__g_failure_reason; + +STBIDEF const char *stbi_failure_reason(void) +{ + return stbi__g_failure_reason; +} + +static int stbi__err(const char *str) +{ + stbi__g_failure_reason = str; + return 0; +} + +static void *stbi__malloc(size_t size) +{ + return STBI_MALLOC(size); +} + +// stbi__err - error +// stbi__errpf - error returning pointer to float +// stbi__errpuc - error returning pointer to unsigned char + +#ifdef STBI_NO_FAILURE_STRINGS + #define stbi__err(x,y) 0 +#elif defined(STBI_FAILURE_USERMSG) + #define stbi__err(x,y) stbi__err(y) +#else + #define stbi__err(x,y) stbi__err(x) +#endif + +#define stbi__errpf(x,y) ((float *)(size_t) (stbi__err(x,y)?NULL:NULL)) +#define stbi__errpuc(x,y) ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL)) + +STBIDEF void stbi_image_free(void *retval_from_stbi_load) +{ + STBI_FREE(retval_from_stbi_load); +} + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); +#endif + +#ifndef STBI_NO_HDR +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); +#endif + +static int stbi__vertically_flip_on_load = 0; + +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load = flag_true_if_should_flip; +} + +static unsigned char *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + #ifndef STBI_NO_JPEG + if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp); + #endif + #ifndef STBI_NO_PNG + if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp); + #endif + #ifndef STBI_NO_BMP + if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp); + #endif + #ifndef STBI_NO_GIF + if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp); + #endif + #ifndef STBI_NO_PSD + if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp); + #endif + #ifndef STBI_NO_PIC + if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp); + #endif + #ifndef STBI_NO_PNM + if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp); + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + float *hdr = stbi__hdr_load(s, x,y,comp,req_comp); + return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); + } + #endif + + #ifndef STBI_NO_TGA + // test tga last because it's a crappy test! + if (stbi__tga_test(s)) + return stbi__tga_load(s,x,y,comp,req_comp); + #endif + + return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); +} + +static unsigned char *stbi__load_flip(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *result = stbi__load_main(s, x, y, comp, req_comp); + + if (stbi__vertically_flip_on_load && result != NULL) { + int w = *x, h = *y; + int depth = req_comp ? req_comp : *comp; + int row,col,z; + stbi_uc temp; + + // @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once + for (row = 0; row < (h>>1); row++) { + for (col = 0; col < w; col++) { + for (z = 0; z < depth; z++) { + temp = result[(row * w + col) * depth + z]; + result[(row * w + col) * depth + z] = result[((h - row - 1) * w + col) * depth + z]; + result[((h - row - 1) * w + col) * depth + z] = temp; + } + } + } + } + + return result; +} + +#ifndef STBI_NO_HDR +static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) +{ + if (stbi__vertically_flip_on_load && result != NULL) { + int w = *x, h = *y; + int depth = req_comp ? req_comp : *comp; + int row,col,z; + float temp; + + // @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once + for (row = 0; row < (h>>1); row++) { + for (col = 0; col < w; col++) { + for (z = 0; z < depth; z++) { + temp = result[(row * w + col) * depth + z]; + result[(row * w + col) * depth + z] = result[((h - row - 1) * w + col) * depth + z]; + result[((h - row - 1) * w + col) * depth + z] = temp; + } + } + } + } +} +#endif + +#ifndef STBI_NO_STDIO + +static FILE *stbi__fopen(char const *filename, char const *mode) +{ + FILE *f; +#if defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != fopen_s(&f, filename, mode)) + f=0; +#else + f = fopen(filename, mode); +#endif + return f; +} + + +STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + unsigned char *result; + if (!f) return stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_flip(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} +#endif //!STBI_NO_STDIO + +STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_flip(&s,x,y,comp,req_comp); +} + +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__load_flip(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_LINEAR +static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *data; + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp); + if (hdr_data) + stbi__float_postprocess(hdr_data,x,y,comp,req_comp); + return hdr_data; + } + #endif + data = stbi__load_flip(s, x, y, comp, req_comp); + if (data) + return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); + return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); +} + +STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_STDIO +STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + float *result; + FILE *f = stbi__fopen(filename, "rb"); + if (!f) return stbi__errpf("can't fopen", "Unable to open file"); + result = stbi_loadf_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_file(&s,f); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} +#endif // !STBI_NO_STDIO + +#endif // !STBI_NO_LINEAR + +// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is +// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always +// reports false! + +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(buffer); + STBI_NOTUSED(len); + return 0; + #endif +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result=0; + if (f) { + result = stbi_is_hdr_from_file(f); + fclose(f); + } + return result; +} + +STBIDEF int stbi_is_hdr_from_file(FILE *f) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_file(&s,f); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(f); + return 0; + #endif +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(clbk); + STBI_NOTUSED(user); + return 0; + #endif +} + +static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; +static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; + +#ifndef STBI_NO_LINEAR +STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } +STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } +#endif + +STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } +STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } + + +////////////////////////////////////////////////////////////////////////////// +// +// Common code used by all image loaders +// + +enum +{ + STBI__SCAN_load=0, + STBI__SCAN_type, + STBI__SCAN_header +}; + +static void stbi__refill_buffer(stbi__context *s) +{ + int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); + if (n == 0) { + // at end of file, treat same as if from memory, but need to handle case + // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file + s->read_from_callbacks = 0; + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start+1; + *s->img_buffer = 0; + } else { + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start + n; + } +} + +stbi_inline static stbi_uc stbi__get8(stbi__context *s) +{ + if (s->img_buffer < s->img_buffer_end) + return *s->img_buffer++; + if (s->read_from_callbacks) { + stbi__refill_buffer(s); + return *s->img_buffer++; + } + return 0; +} + +stbi_inline static int stbi__at_eof(stbi__context *s) +{ + if (s->io.read) { + if (!(s->io.eof)(s->io_user_data)) return 0; + // if feof() is true, check if buffer = end + // special case: we've only got the special 0 character at the end + if (s->read_from_callbacks == 0) return 1; + } + + return s->img_buffer >= s->img_buffer_end; +} + +static void stbi__skip(stbi__context *s, int n) +{ + if (n < 0) { + s->img_buffer = s->img_buffer_end; + return; + } + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + s->img_buffer = s->img_buffer_end; + (s->io.skip)(s->io_user_data, n - blen); + return; + } + } + s->img_buffer += n; +} + +static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) +{ + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + int res, count; + + memcpy(buffer, s->img_buffer, blen); + + count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); + res = (count == (n-blen)); + s->img_buffer = s->img_buffer_end; + return res; + } + } + + if (s->img_buffer+n <= s->img_buffer_end) { + memcpy(buffer, s->img_buffer, n); + s->img_buffer += n; + return 1; + } else + return 0; +} + +static int stbi__get16be(stbi__context *s) +{ + int z = stbi__get8(s); + return (z << 8) + stbi__get8(s); +} + +static stbi__uint32 stbi__get32be(stbi__context *s) +{ + stbi__uint32 z = stbi__get16be(s); + return (z << 16) + stbi__get16be(s); +} + +#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) +// nothing +#else +static int stbi__get16le(stbi__context *s) +{ + int z = stbi__get8(s); + return z + (stbi__get8(s) << 8); +} +#endif + +#ifndef STBI_NO_BMP +static stbi__uint32 stbi__get32le(stbi__context *s) +{ + stbi__uint32 z = stbi__get16le(s); + return z + (stbi__get16le(s) << 16); +} +#endif + +#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings + + +////////////////////////////////////////////////////////////////////////////// +// +// generic converter from built-in img_n to req_comp +// individual types do this automatically as much as possible (e.g. jpeg +// does all cases internally since it needs to colorspace convert anyway, +// and it never has alpha, so very few cases ). png can automatically +// interleave an alpha=255 channel, but falls back to this for other cases +// +// assume data buffer is malloced, so malloc a new one and free that one +// only failure mode is malloc failing + +static stbi_uc stbi__compute_y(int r, int g, int b) +{ + return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); +} + +static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + unsigned char *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (unsigned char *) stbi__malloc(req_comp * x * y); + if (good == NULL) { + STBI_FREE(data); + return stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + unsigned char *src = data + j * x * img_n ; + unsigned char *dest = good + j * x * req_comp; + + #define COMBO(a,b) ((a)*8+(b)) + #define CASE(a,b) case COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (COMBO(img_n, req_comp)) { + CASE(1,2) dest[0]=src[0], dest[1]=255; break; + CASE(1,3) dest[0]=dest[1]=dest[2]=src[0]; break; + CASE(1,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; break; + CASE(2,1) dest[0]=src[0]; break; + CASE(2,3) dest[0]=dest[1]=dest[2]=src[0]; break; + CASE(2,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; break; + CASE(3,4) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; break; + CASE(3,1) dest[0]=stbi__compute_y(src[0],src[1],src[2]); break; + CASE(3,2) dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; break; + CASE(4,1) dest[0]=stbi__compute_y(src[0],src[1],src[2]); break; + CASE(4,2) dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; break; + CASE(4,3) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; break; + default: STBI_ASSERT(0); + } + #undef CASE + } + + STBI_FREE(data); + return good; +} + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) +{ + int i,k,n; + float *output = (float *) stbi__malloc(x * y * comp * sizeof(float)); + if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); + } + if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f; + } + STBI_FREE(data); + return output; +} +#endif + +#ifndef STBI_NO_HDR +#define stbi__float2int(x) ((int) (x)) +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) +{ + int i,k,n; + stbi_uc *output = (stbi_uc *) stbi__malloc(x * y * comp); + if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + if (k < comp) { + float z = data[i*comp+k] * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + } + STBI_FREE(data); + return output; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// "baseline" JPEG/JFIF decoder +// +// simple implementation +// - doesn't support delayed output of y-dimension +// - simple interface (only one output format: 8-bit interleaved RGB) +// - doesn't try to recover corrupt jpegs +// - doesn't allow partial loading, loading multiple at once +// - still fast on x86 (copying globals into locals doesn't help x86) +// - allocates lots of intermediate memory (full size of all components) +// - non-interleaved case requires this anyway +// - allows good upsampling (see next) +// high-quality +// - upsampled channels are bilinearly interpolated, even across blocks +// - quality integer IDCT derived from IJG's 'slow' +// performance +// - fast huffman; reasonable integer IDCT +// - some SIMD kernels for common paths on targets with SSE2/NEON +// - uses a lot of intermediate memory, could cache poorly + +#ifndef STBI_NO_JPEG + +// huffman decoding acceleration +#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache + +typedef struct +{ + stbi_uc fast[1 << FAST_BITS]; + // weirdly, repacking this into AoS is a 10% speed loss, instead of a win + stbi__uint16 code[256]; + stbi_uc values[256]; + stbi_uc size[257]; + unsigned int maxcode[18]; + int delta[17]; // old 'firstsymbol' - old 'firstcode' +} stbi__huffman; + +typedef struct +{ + stbi__context *s; + stbi__huffman huff_dc[4]; + stbi__huffman huff_ac[4]; + stbi_uc dequant[4][64]; + stbi__int16 fast_ac[4][1 << FAST_BITS]; + +// sizes for components, interleaved MCUs + int img_h_max, img_v_max; + int img_mcu_x, img_mcu_y; + int img_mcu_w, img_mcu_h; + +// definition of jpeg image component + struct + { + int id; + int h,v; + int tq; + int hd,ha; + int dc_pred; + + int x,y,w2,h2; + stbi_uc *data; + void *raw_data, *raw_coeff; + stbi_uc *linebuf; + short *coeff; // progressive only + int coeff_w, coeff_h; // number of 8x8 coefficient blocks + } img_comp[4]; + + stbi__uint32 code_buffer; // jpeg entropy-coded buffer + int code_bits; // number of valid bits + unsigned char marker; // marker seen while filling entropy buffer + int nomore; // flag if we saw a marker so must stop + + int progressive; + int spec_start; + int spec_end; + int succ_high; + int succ_low; + int eob_run; + + int scan_n, order[4]; + int restart_interval, todo; + +// kernels + void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); + void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step); + stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); +} stbi__jpeg; + +static int stbi__build_huffman(stbi__huffman *h, int *count) +{ + int i,j,k=0,code; + // build size list for each symbol (from JPEG spec) + for (i=0; i < 16; ++i) + for (j=0; j < count[i]; ++j) + h->size[k++] = (stbi_uc) (i+1); + h->size[k] = 0; + + // compute actual symbols (from jpeg spec) + code = 0; + k = 0; + for(j=1; j <= 16; ++j) { + // compute delta to add to code to compute symbol id + h->delta[j] = k - code; + if (h->size[k] == j) { + while (h->size[k] == j) + h->code[k++] = (stbi__uint16) (code++); + if (code-1 >= (1 << j)) return stbi__err("bad code lengths","Corrupt JPEG"); + } + // compute largest code + 1 for this size, preshifted as needed later + h->maxcode[j] = code << (16-j); + code <<= 1; + } + h->maxcode[j] = 0xffffffff; + + // build non-spec acceleration table; 255 is flag for not-accelerated + memset(h->fast, 255, 1 << FAST_BITS); + for (i=0; i < k; ++i) { + int s = h->size[i]; + if (s <= FAST_BITS) { + int c = h->code[i] << (FAST_BITS-s); + int m = 1 << (FAST_BITS-s); + for (j=0; j < m; ++j) { + h->fast[c+j] = (stbi_uc) i; + } + } + } + return 1; +} + +// build a table that decodes both magnitude and value of small ACs in +// one go. +static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) +{ + int i; + for (i=0; i < (1 << FAST_BITS); ++i) { + stbi_uc fast = h->fast[i]; + fast_ac[i] = 0; + if (fast < 255) { + int rs = h->values[fast]; + int run = (rs >> 4) & 15; + int magbits = rs & 15; + int len = h->size[fast]; + + if (magbits && len + magbits <= FAST_BITS) { + // magnitude code followed by receive_extend code + int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); + int m = 1 << (magbits - 1); + if (k < m) k += (-1 << magbits) + 1; + // if the result is small enough, we can fit it in fast_ac table + if (k >= -128 && k <= 127) + fast_ac[i] = (stbi__int16) ((k << 8) + (run << 4) + (len + magbits)); + } + } + } +} + +static void stbi__grow_buffer_unsafe(stbi__jpeg *j) +{ + do { + int b = j->nomore ? 0 : stbi__get8(j->s); + if (b == 0xff) { + int c = stbi__get8(j->s); + if (c != 0) { + j->marker = (unsigned char) c; + j->nomore = 1; + return; + } + } + j->code_buffer |= b << (24 - j->code_bits); + j->code_bits += 8; + } while (j->code_bits <= 24); +} + +// (1 << n) - 1 +static stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; + +// decode a jpeg huffman value from the bitstream +stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) +{ + unsigned int temp; + int c,k; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + // look at the top FAST_BITS and determine what symbol ID it is, + // if the code is <= FAST_BITS + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + k = h->fast[c]; + if (k < 255) { + int s = h->size[k]; + if (s > j->code_bits) + return -1; + j->code_buffer <<= s; + j->code_bits -= s; + return h->values[k]; + } + + // naive test is to shift the code_buffer down so k bits are + // valid, then test against maxcode. To speed this up, we've + // preshifted maxcode left so that it has (16-k) 0s at the + // end; in other words, regardless of the number of bits, it + // wants to be compared against something shifted to have 16; + // that way we don't need to shift inside the loop. + temp = j->code_buffer >> 16; + for (k=FAST_BITS+1 ; ; ++k) + if (temp < h->maxcode[k]) + break; + if (k == 17) { + // error! code not found + j->code_bits -= 16; + return -1; + } + + if (k > j->code_bits) + return -1; + + // convert the huffman code to the symbol id + c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; + STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); + + // convert the id to a symbol + j->code_bits -= k; + j->code_buffer <<= k; + return h->values[c]; +} + +// bias[n] = (-1<code_bits < n) stbi__grow_buffer_unsafe(j); + + sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB + k = stbi_lrot(j->code_buffer, n); + STBI_ASSERT(n >= 0 && n < (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask))); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k + (stbi__jbias[n] & ~sgn); +} + +// get some unsigned bits +stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) +{ + unsigned int k; + if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k; +} + +stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) +{ + unsigned int k; + if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); + k = j->code_buffer; + j->code_buffer <<= 1; + --j->code_bits; + return k & 0x80000000; +} + +// given a value that's at position X in the zigzag stream, +// where does it appear in the 8x8 matrix coded as row-major? +static stbi_uc stbi__jpeg_dezigzag[64+15] = +{ + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, + // let corrupt input sample past end + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63 +}; + +// decode one 64-entry block-- +static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi_uc *dequant) +{ + int diff,dc,k; + int t; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + + // 0 all the ac values now so we can do it 32-bits at a time + memset(data,0,64*sizeof(data[0])); + + diff = t ? stbi__extend_receive(j, t) : 0; + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short) (dc * dequant[0]); + + // decode AC components, see JPEG spec + k = 1; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) * dequant[zig]); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (rs != 0xf0) break; // end block + k += 16; + } else { + k += r; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]); + } + } + } while (k < 64); + return 1; +} + +static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) +{ + int diff,dc; + int t; + if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + if (j->succ_high == 0) { + // first scan for DC coefficient, must be first + memset(data,0,64*sizeof(data[0])); // 0 all the ac values now + t = stbi__jpeg_huff_decode(j, hdc); + diff = t ? stbi__extend_receive(j, t) : 0; + + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short) (dc << j->succ_low); + } else { + // refinement scan for DC coefficient + if (stbi__jpeg_get_bit(j)) + data[0] += (short) (1 << j->succ_low); + } + return 1; +} + +// @OPTIMIZE: store non-zigzagged during the decode passes, +// and only de-zigzag when dequantizing +static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) +{ + int k; + if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->succ_high == 0) { + int shift = j->succ_low; + + if (j->eob_run) { + --j->eob_run; + return 1; + } + + k = j->spec_start; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) << shift); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r); + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + --j->eob_run; + break; + } + k += 16; + } else { + k += r; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) << shift); + } + } + } while (k <= j->spec_end); + } else { + // refinement scan for these AC coefficients + + short bit = (short) (1 << j->succ_low); + + if (j->eob_run) { + --j->eob_run; + for (k = j->spec_start; k <= j->spec_end; ++k) { + short *p = &data[stbi__jpeg_dezigzag[k]]; + if (*p != 0) + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } + } else { + k = j->spec_start; + do { + int r,s; + int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r) - 1; + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + r = 64; // force end of block + } else { + // r=15 s=0 should write 16 0s, so we just do + // a run of 15 0s and then write s (which is 0), + // so we don't have to do anything special here + } + } else { + if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); + // sign bit + if (stbi__jpeg_get_bit(j)) + s = bit; + else + s = -bit; + } + + // advance by r + while (k <= j->spec_end) { + short *p = &data[stbi__jpeg_dezigzag[k++]]; + if (*p != 0) { + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } else { + if (r == 0) { + *p = (short) s; + break; + } + --r; + } + } + } while (k <= j->spec_end); + } + } + return 1; +} + +// take a -128..127 value and stbi__clamp it and convert to 0..255 +stbi_inline static stbi_uc stbi__clamp(int x) +{ + // trick to use a single test to catch both cases + if ((unsigned int) x > 255) { + if (x < 0) return 0; + if (x > 255) return 255; + } + return (stbi_uc) x; +} + +#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) +#define stbi__fsh(x) ((x) << 12) + +// derived from jidctint -- DCT_ISLOW +#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ + int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ + p2 = s2; \ + p3 = s6; \ + p1 = (p2+p3) * stbi__f2f(0.5411961f); \ + t2 = p1 + p3*stbi__f2f(-1.847759065f); \ + t3 = p1 + p2*stbi__f2f( 0.765366865f); \ + p2 = s0; \ + p3 = s4; \ + t0 = stbi__fsh(p2+p3); \ + t1 = stbi__fsh(p2-p3); \ + x0 = t0+t3; \ + x3 = t0-t3; \ + x1 = t1+t2; \ + x2 = t1-t2; \ + t0 = s7; \ + t1 = s5; \ + t2 = s3; \ + t3 = s1; \ + p3 = t0+t2; \ + p4 = t1+t3; \ + p1 = t0+t3; \ + p2 = t1+t2; \ + p5 = (p3+p4)*stbi__f2f( 1.175875602f); \ + t0 = t0*stbi__f2f( 0.298631336f); \ + t1 = t1*stbi__f2f( 2.053119869f); \ + t2 = t2*stbi__f2f( 3.072711026f); \ + t3 = t3*stbi__f2f( 1.501321110f); \ + p1 = p5 + p1*stbi__f2f(-0.899976223f); \ + p2 = p5 + p2*stbi__f2f(-2.562915447f); \ + p3 = p3*stbi__f2f(-1.961570560f); \ + p4 = p4*stbi__f2f(-0.390180644f); \ + t3 += p1+p4; \ + t2 += p2+p3; \ + t1 += p2+p4; \ + t0 += p1+p3; + +static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) +{ + int i,val[64],*v=val; + stbi_uc *o; + short *d = data; + + // columns + for (i=0; i < 8; ++i,++d, ++v) { + // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing + if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 + && d[40]==0 && d[48]==0 && d[56]==0) { + // no shortcut 0 seconds + // (1|2|3|4|5|6|7)==0 0 seconds + // all separate -0.047 seconds + // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds + int dcterm = d[0] << 2; + v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; + } else { + STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]) + // constants scaled things up by 1<<12; let's bring them back + // down, but keep 2 extra bits of precision + x0 += 512; x1 += 512; x2 += 512; x3 += 512; + v[ 0] = (x0+t3) >> 10; + v[56] = (x0-t3) >> 10; + v[ 8] = (x1+t2) >> 10; + v[48] = (x1-t2) >> 10; + v[16] = (x2+t1) >> 10; + v[40] = (x2-t1) >> 10; + v[24] = (x3+t0) >> 10; + v[32] = (x3-t0) >> 10; + } + } + + for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { + // no fast case since the first 1D IDCT spread components out + STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) + // constants scaled things up by 1<<12, plus we had 1<<2 from first + // loop, plus horizontal and vertical each scale by sqrt(8) so together + // we've got an extra 1<<3, so 1<<17 total we need to remove. + // so we want to round that, which means adding 0.5 * 1<<17, + // aka 65536. Also, we'll end up with -128 to 127 that we want + // to encode as 0..255 by adding 128, so we'll add that before the shift + x0 += 65536 + (128<<17); + x1 += 65536 + (128<<17); + x2 += 65536 + (128<<17); + x3 += 65536 + (128<<17); + // tried computing the shifts into temps, or'ing the temps to see + // if any were out of range, but that was slower + o[0] = stbi__clamp((x0+t3) >> 17); + o[7] = stbi__clamp((x0-t3) >> 17); + o[1] = stbi__clamp((x1+t2) >> 17); + o[6] = stbi__clamp((x1-t2) >> 17); + o[2] = stbi__clamp((x2+t1) >> 17); + o[5] = stbi__clamp((x2-t1) >> 17); + o[3] = stbi__clamp((x3+t0) >> 17); + o[4] = stbi__clamp((x3-t0) >> 17); + } +} + +#ifdef STBI_SSE2 +// sse2 integer IDCT. not the fastest possible implementation but it +// produces bit-identical results to the generic C version so it's +// fully "transparent". +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + // This is constructed to match our regular (generic) integer IDCT exactly. + __m128i row0, row1, row2, row3, row4, row5, row6, row7; + __m128i tmp; + + // dot product constant: even elems=x, odd elems=y + #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y)) + + // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) + // out(1) = c1[even]*x + c1[odd]*y + #define dct_rot(out0,out1, x,y,c0,c1) \ + __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \ + __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \ + __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ + __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ + __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ + __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) + + // out = in << 12 (in 16-bit, out 32-bit) + #define dct_widen(out, in) \ + __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ + __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) + + // wide add + #define dct_wadd(out, a, b) \ + __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_add_epi32(a##_h, b##_h) + + // wide sub + #define dct_wsub(out, a, b) \ + __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) + + // butterfly a/b, add bias, then shift by "s" and pack + #define dct_bfly32o(out0, out1, a,b,bias,s) \ + { \ + __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ + __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ + dct_wadd(sum, abiased, b); \ + dct_wsub(dif, abiased, b); \ + out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ + out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ + } + + // 8-bit interleave step (for transposes) + #define dct_interleave8(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi8(a, b); \ + b = _mm_unpackhi_epi8(tmp, b) + + // 16-bit interleave step (for transposes) + #define dct_interleave16(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi16(a, b); \ + b = _mm_unpackhi_epi16(tmp, b) + + #define dct_pass(bias,shift) \ + { \ + /* even part */ \ + dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \ + __m128i sum04 = _mm_add_epi16(row0, row4); \ + __m128i dif04 = _mm_sub_epi16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \ + dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \ + __m128i sum17 = _mm_add_epi16(row1, row7); \ + __m128i sum35 = _mm_add_epi16(row3, row5); \ + dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \ + dct_wadd(x4, y0o, y4o); \ + dct_wadd(x5, y1o, y5o); \ + dct_wadd(x6, y2o, y5o); \ + dct_wadd(x7, y3o, y4o); \ + dct_bfly32o(row0,row7, x0,x7,bias,shift); \ + dct_bfly32o(row1,row6, x1,x6,bias,shift); \ + dct_bfly32o(row2,row5, x2,x5,bias,shift); \ + dct_bfly32o(row3,row4, x3,x4,bias,shift); \ + } + + __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); + __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f)); + __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); + __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); + __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f)); + __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f)); + __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f)); + __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f)); + + // rounding biases in column/row passes, see stbi__idct_block for explanation. + __m128i bias_0 = _mm_set1_epi32(512); + __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17)); + + // load + row0 = _mm_load_si128((const __m128i *) (data + 0*8)); + row1 = _mm_load_si128((const __m128i *) (data + 1*8)); + row2 = _mm_load_si128((const __m128i *) (data + 2*8)); + row3 = _mm_load_si128((const __m128i *) (data + 3*8)); + row4 = _mm_load_si128((const __m128i *) (data + 4*8)); + row5 = _mm_load_si128((const __m128i *) (data + 5*8)); + row6 = _mm_load_si128((const __m128i *) (data + 6*8)); + row7 = _mm_load_si128((const __m128i *) (data + 7*8)); + + // column pass + dct_pass(bias_0, 10); + + { + // 16bit 8x8 transpose pass 1 + dct_interleave16(row0, row4); + dct_interleave16(row1, row5); + dct_interleave16(row2, row6); + dct_interleave16(row3, row7); + + // transpose pass 2 + dct_interleave16(row0, row2); + dct_interleave16(row1, row3); + dct_interleave16(row4, row6); + dct_interleave16(row5, row7); + + // transpose pass 3 + dct_interleave16(row0, row1); + dct_interleave16(row2, row3); + dct_interleave16(row4, row5); + dct_interleave16(row6, row7); + } + + // row pass + dct_pass(bias_1, 17); + + { + // pack + __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 + __m128i p1 = _mm_packus_epi16(row2, row3); + __m128i p2 = _mm_packus_epi16(row4, row5); + __m128i p3 = _mm_packus_epi16(row6, row7); + + // 8bit 8x8 transpose pass 1 + dct_interleave8(p0, p2); // a0e0a1e1... + dct_interleave8(p1, p3); // c0g0c1g1... + + // transpose pass 2 + dct_interleave8(p0, p1); // a0c0e0g0... + dct_interleave8(p2, p3); // b0d0f0h0... + + // transpose pass 3 + dct_interleave8(p0, p2); // a0b0c0d0... + dct_interleave8(p1, p3); // a4b4c4d4... + + // store + _mm_storel_epi64((__m128i *) out, p0); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p2); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p1); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p3); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e)); + } + +#undef dct_const +#undef dct_rot +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_interleave8 +#undef dct_interleave16 +#undef dct_pass +} + +#endif // STBI_SSE2 + +#ifdef STBI_NEON + +// NEON integer IDCT. should produce bit-identical +// results to the generic C version. +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; + + int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); + int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); + int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f)); + int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f)); + int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); + int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); + int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); + int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); + int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f)); + int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f)); + int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f)); + int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f)); + +#define dct_long_mul(out, inq, coeff) \ + int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) + +#define dct_long_mac(out, acc, inq, coeff) \ + int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) + +#define dct_widen(out, inq) \ + int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ + int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) + +// wide add +#define dct_wadd(out, a, b) \ + int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vaddq_s32(a##_h, b##_h) + +// wide sub +#define dct_wsub(out, a, b) \ + int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vsubq_s32(a##_h, b##_h) + +// butterfly a/b, then shift using "shiftop" by "s" and pack +#define dct_bfly32o(out0,out1, a,b,shiftop,s) \ + { \ + dct_wadd(sum, a, b); \ + dct_wsub(dif, a, b); \ + out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ + out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ + } + +#define dct_pass(shiftop, shift) \ + { \ + /* even part */ \ + int16x8_t sum26 = vaddq_s16(row2, row6); \ + dct_long_mul(p1e, sum26, rot0_0); \ + dct_long_mac(t2e, p1e, row6, rot0_1); \ + dct_long_mac(t3e, p1e, row2, rot0_2); \ + int16x8_t sum04 = vaddq_s16(row0, row4); \ + int16x8_t dif04 = vsubq_s16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + int16x8_t sum15 = vaddq_s16(row1, row5); \ + int16x8_t sum17 = vaddq_s16(row1, row7); \ + int16x8_t sum35 = vaddq_s16(row3, row5); \ + int16x8_t sum37 = vaddq_s16(row3, row7); \ + int16x8_t sumodd = vaddq_s16(sum17, sum35); \ + dct_long_mul(p5o, sumodd, rot1_0); \ + dct_long_mac(p1o, p5o, sum17, rot1_1); \ + dct_long_mac(p2o, p5o, sum35, rot1_2); \ + dct_long_mul(p3o, sum37, rot2_0); \ + dct_long_mul(p4o, sum15, rot2_1); \ + dct_wadd(sump13o, p1o, p3o); \ + dct_wadd(sump24o, p2o, p4o); \ + dct_wadd(sump23o, p2o, p3o); \ + dct_wadd(sump14o, p1o, p4o); \ + dct_long_mac(x4, sump13o, row7, rot3_0); \ + dct_long_mac(x5, sump24o, row5, rot3_1); \ + dct_long_mac(x6, sump23o, row3, rot3_2); \ + dct_long_mac(x7, sump14o, row1, rot3_3); \ + dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \ + dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \ + dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \ + dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \ + } + + // load + row0 = vld1q_s16(data + 0*8); + row1 = vld1q_s16(data + 1*8); + row2 = vld1q_s16(data + 2*8); + row3 = vld1q_s16(data + 3*8); + row4 = vld1q_s16(data + 4*8); + row5 = vld1q_s16(data + 5*8); + row6 = vld1q_s16(data + 6*8); + row7 = vld1q_s16(data + 7*8); + + // add DC bias + row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); + + // column pass + dct_pass(vrshrn_n_s32, 10); + + // 16bit 8x8 transpose + { +// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively. +// whether compilers actually get this is another story, sadly. +#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); } +#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); } + + // pass 1 + dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 + dct_trn16(row2, row3); + dct_trn16(row4, row5); + dct_trn16(row6, row7); + + // pass 2 + dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 + dct_trn32(row1, row3); + dct_trn32(row4, row6); + dct_trn32(row5, row7); + + // pass 3 + dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 + dct_trn64(row1, row5); + dct_trn64(row2, row6); + dct_trn64(row3, row7); + +#undef dct_trn16 +#undef dct_trn32 +#undef dct_trn64 + } + + // row pass + // vrshrn_n_s32 only supports shifts up to 16, we need + // 17. so do a non-rounding shift of 16 first then follow + // up with a rounding shift by 1. + dct_pass(vshrn_n_s32, 16); + + { + // pack and round + uint8x8_t p0 = vqrshrun_n_s16(row0, 1); + uint8x8_t p1 = vqrshrun_n_s16(row1, 1); + uint8x8_t p2 = vqrshrun_n_s16(row2, 1); + uint8x8_t p3 = vqrshrun_n_s16(row3, 1); + uint8x8_t p4 = vqrshrun_n_s16(row4, 1); + uint8x8_t p5 = vqrshrun_n_s16(row5, 1); + uint8x8_t p6 = vqrshrun_n_s16(row6, 1); + uint8x8_t p7 = vqrshrun_n_s16(row7, 1); + + // again, these can translate into one instruction, but often don't. +#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); } +#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); } + + // sadly can't use interleaved stores here since we only write + // 8 bytes to each scan line! + + // 8x8 8-bit transpose pass 1 + dct_trn8_8(p0, p1); + dct_trn8_8(p2, p3); + dct_trn8_8(p4, p5); + dct_trn8_8(p6, p7); + + // pass 2 + dct_trn8_16(p0, p2); + dct_trn8_16(p1, p3); + dct_trn8_16(p4, p6); + dct_trn8_16(p5, p7); + + // pass 3 + dct_trn8_32(p0, p4); + dct_trn8_32(p1, p5); + dct_trn8_32(p2, p6); + dct_trn8_32(p3, p7); + + // store + vst1_u8(out, p0); out += out_stride; + vst1_u8(out, p1); out += out_stride; + vst1_u8(out, p2); out += out_stride; + vst1_u8(out, p3); out += out_stride; + vst1_u8(out, p4); out += out_stride; + vst1_u8(out, p5); out += out_stride; + vst1_u8(out, p6); out += out_stride; + vst1_u8(out, p7); + +#undef dct_trn8_8 +#undef dct_trn8_16 +#undef dct_trn8_32 + } + +#undef dct_long_mul +#undef dct_long_mac +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_pass +} + +#endif // STBI_NEON + +#define STBI__MARKER_none 0xff +// if there's a pending marker from the entropy stream, return that +// otherwise, fetch from the stream and get a marker. if there's no +// marker, return 0xff, which is never a valid marker value +static stbi_uc stbi__get_marker(stbi__jpeg *j) +{ + stbi_uc x; + if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; } + x = stbi__get8(j->s); + if (x != 0xff) return STBI__MARKER_none; + while (x == 0xff) + x = stbi__get8(j->s); + return x; +} + +// in each scan, we'll have scan_n components, and the order +// of the components is specified by order[] +#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) + +// after a restart interval, stbi__jpeg_reset the entropy decoder and +// the dc prediction +static void stbi__jpeg_reset(stbi__jpeg *j) +{ + j->code_bits = 0; + j->code_buffer = 0; + j->nomore = 0; + j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = 0; + j->marker = STBI__MARKER_none; + j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; + j->eob_run = 0; + // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, + // since we don't even allow 1<<30 pixels +} + +static int stbi__parse_entropy_coded_data(stbi__jpeg *z) +{ + stbi__jpeg_reset(z); + if (!z->progressive) { + if (z->scan_n == 1) { + int i,j; + STBI_SIMD_ALIGN(short, data[64]); + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + STBI_SIMD_ALIGN(short, data[64]); + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x)*8; + int y2 = (j*z->img_comp[n].v + y)*8; + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } else { + if (z->scan_n == 1) { + int i,j; + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + if (z->spec_start == 0) { + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } else { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) + return 0; + } + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x); + int y2 = (j*z->img_comp[n].v + y); + short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } +} + +static void stbi__jpeg_dequantize(short *data, stbi_uc *dequant) +{ + int i; + for (i=0; i < 64; ++i) + data[i] *= dequant[i]; +} + +static void stbi__jpeg_finish(stbi__jpeg *z) +{ + if (z->progressive) { + // dequantize and idct the data + int i,j,n; + for (n=0; n < z->s->img_n; ++n) { + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + } + } + } + } +} + +static int stbi__process_marker(stbi__jpeg *z, int m) +{ + int L; + switch (m) { + case STBI__MARKER_none: // no marker found + return stbi__err("expected marker","Corrupt JPEG"); + + case 0xDD: // DRI - specify restart interval + if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG"); + z->restart_interval = stbi__get16be(z->s); + return 1; + + case 0xDB: // DQT - define quantization table + L = stbi__get16be(z->s)-2; + while (L > 0) { + int q = stbi__get8(z->s); + int p = q >> 4; + int t = q & 15,i; + if (p != 0) return stbi__err("bad DQT type","Corrupt JPEG"); + if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); + for (i=0; i < 64; ++i) + z->dequant[t][stbi__jpeg_dezigzag[i]] = stbi__get8(z->s); + L -= 65; + } + return L==0; + + case 0xC4: // DHT - define huffman table + L = stbi__get16be(z->s)-2; + while (L > 0) { + stbi_uc *v; + int sizes[16],i,n=0; + int q = stbi__get8(z->s); + int tc = q >> 4; + int th = q & 15; + if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG"); + for (i=0; i < 16; ++i) { + sizes[i] = stbi__get8(z->s); + n += sizes[i]; + } + L -= 17; + if (tc == 0) { + if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; + v = z->huff_dc[th].values; + } else { + if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0; + v = z->huff_ac[th].values; + } + for (i=0; i < n; ++i) + v[i] = stbi__get8(z->s); + if (tc != 0) + stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); + L -= n; + } + return L==0; + } + // check for comment block or APP blocks + if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { + stbi__skip(z->s, stbi__get16be(z->s)-2); + return 1; + } + return 0; +} + +// after we see SOS +static int stbi__process_scan_header(stbi__jpeg *z) +{ + int i; + int Ls = stbi__get16be(z->s); + z->scan_n = stbi__get8(z->s); + if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG"); + if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG"); + for (i=0; i < z->scan_n; ++i) { + int id = stbi__get8(z->s), which; + int q = stbi__get8(z->s); + for (which = 0; which < z->s->img_n; ++which) + if (z->img_comp[which].id == id) + break; + if (which == z->s->img_n) return 0; // no match + z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG"); + z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG"); + z->order[i] = which; + } + + { + int aa; + z->spec_start = stbi__get8(z->s); + z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 + aa = stbi__get8(z->s); + z->succ_high = (aa >> 4); + z->succ_low = (aa & 15); + if (z->progressive) { + if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) + return stbi__err("bad SOS", "Corrupt JPEG"); + } else { + if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG"); + if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG"); + z->spec_end = 63; + } + } + + return 1; +} + +static int stbi__process_frame_header(stbi__jpeg *z, int scan) +{ + stbi__context *s = z->s; + int Lf,p,i,q, h_max=1,v_max=1,c; + Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG + p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline + s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG + s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires + c = stbi__get8(s); + if (c != 3 && c != 1) return stbi__err("bad component count","Corrupt JPEG"); // JFIF requires + s->img_n = c; + for (i=0; i < c; ++i) { + z->img_comp[i].data = NULL; + z->img_comp[i].linebuf = NULL; + } + + if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG"); + + for (i=0; i < s->img_n; ++i) { + z->img_comp[i].id = stbi__get8(s); + if (z->img_comp[i].id != i+1) // JFIF requires + if (z->img_comp[i].id != i) // some version of jpegtran outputs non-JFIF-compliant files! + return stbi__err("bad component ID","Corrupt JPEG"); + q = stbi__get8(s); + z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); + z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); + z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG"); + } + + if (scan != STBI__SCAN_load) return 1; + + if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); + + for (i=0; i < s->img_n; ++i) { + if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; + if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; + } + + // compute interleaved mcu info + z->img_h_max = h_max; + z->img_v_max = v_max; + z->img_mcu_w = h_max * 8; + z->img_mcu_h = v_max * 8; + z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; + z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; + + for (i=0; i < s->img_n; ++i) { + // number of effective pixels (e.g. for non-interleaved MCU) + z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; + z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; + // to simplify generation, we'll allocate enough memory to decode + // the bogus oversized data from using interleaved MCUs and their + // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't + // discard the extra data until colorspace conversion + z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; + z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; + z->img_comp[i].raw_data = stbi__malloc(z->img_comp[i].w2 * z->img_comp[i].h2+15); + + if (z->img_comp[i].raw_data == NULL) { + for(--i; i >= 0; --i) { + STBI_FREE(z->img_comp[i].raw_data); + z->img_comp[i].raw_data = NULL; + } + return stbi__err("outofmem", "Out of memory"); + } + // align blocks for idct using mmx/sse + z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); + z->img_comp[i].linebuf = NULL; + if (z->progressive) { + z->img_comp[i].coeff_w = (z->img_comp[i].w2 + 7) >> 3; + z->img_comp[i].coeff_h = (z->img_comp[i].h2 + 7) >> 3; + z->img_comp[i].raw_coeff = STBI_MALLOC(z->img_comp[i].coeff_w * z->img_comp[i].coeff_h * 64 * sizeof(short) + 15); + z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); + } else { + z->img_comp[i].coeff = 0; + z->img_comp[i].raw_coeff = 0; + } + } + + return 1; +} + +// use comparisons since in some cases we handle more than one case (e.g. SOF) +#define stbi__DNL(x) ((x) == 0xdc) +#define stbi__SOI(x) ((x) == 0xd8) +#define stbi__EOI(x) ((x) == 0xd9) +#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) +#define stbi__SOS(x) ((x) == 0xda) + +#define stbi__SOF_progressive(x) ((x) == 0xc2) + +static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) +{ + int m; + z->marker = STBI__MARKER_none; // initialize cached marker to empty + m = stbi__get_marker(z); + if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); + if (scan == STBI__SCAN_type) return 1; + m = stbi__get_marker(z); + while (!stbi__SOF(m)) { + if (!stbi__process_marker(z,m)) return 0; + m = stbi__get_marker(z); + while (m == STBI__MARKER_none) { + // some files have extra padding after their blocks, so ok, we'll scan + if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); + m = stbi__get_marker(z); + } + } + z->progressive = stbi__SOF_progressive(m); + if (!stbi__process_frame_header(z, scan)) return 0; + return 1; +} + +// decode image to YCbCr format +static int stbi__decode_jpeg_image(stbi__jpeg *j) +{ + int m; + for (m = 0; m < 4; m++) { + j->img_comp[m].raw_data = NULL; + j->img_comp[m].raw_coeff = NULL; + } + j->restart_interval = 0; + if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0; + m = stbi__get_marker(j); + while (!stbi__EOI(m)) { + if (stbi__SOS(m)) { + if (!stbi__process_scan_header(j)) return 0; + if (!stbi__parse_entropy_coded_data(j)) return 0; + if (j->marker == STBI__MARKER_none ) { + // handle 0s at the end of image data from IP Kamera 9060 + while (!stbi__at_eof(j->s)) { + int x = stbi__get8(j->s); + if (x == 255) { + j->marker = stbi__get8(j->s); + break; + } else if (x != 0) { + return stbi__err("junk before marker", "Corrupt JPEG"); + } + } + // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 + } + } else { + if (!stbi__process_marker(j, m)) return 0; + } + m = stbi__get_marker(j); + } + if (j->progressive) + stbi__jpeg_finish(j); + return 1; +} + +// static jfif-centered resampling (across block boundaries) + +typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, + int w, int hs); + +#define stbi__div4(x) ((stbi_uc) ((x) >> 2)) + +static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + STBI_NOTUSED(out); + STBI_NOTUSED(in_far); + STBI_NOTUSED(w); + STBI_NOTUSED(hs); + return in_near; +} + +static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples vertically for every one in input + int i; + STBI_NOTUSED(hs); + for (i=0; i < w; ++i) + out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2); + return out; +} + +static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples horizontally for every one in input + int i; + stbi_uc *input = in_near; + + if (w == 1) { + // if only one sample, can't do any interpolation + out[0] = out[1] = input[0]; + return out; + } + + out[0] = input[0]; + out[1] = stbi__div4(input[0]*3 + input[1] + 2); + for (i=1; i < w-1; ++i) { + int n = 3*input[i]+2; + out[i*2+0] = stbi__div4(n+input[i-1]); + out[i*2+1] = stbi__div4(n+input[i+1]); + } + out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2); + out[i*2+1] = input[w-1]; + + STBI_NOTUSED(in_far); + STBI_NOTUSED(hs); + + return out; +} + +#define stbi__div16(x) ((stbi_uc) ((x) >> 4)) + +static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i,t0,t1; + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + out[0] = stbi__div4(t1+2); + for (i=1; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i=0,t0,t1; + + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + // process groups of 8 pixels for as long as we can. + // note we can't handle the last pixel in a row in this loop + // because we need to handle the filter boundary conditions. + for (; i < ((w-1) & ~7); i += 8) { +#if defined(STBI_SSE2) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + __m128i zero = _mm_setzero_si128(); + __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i)); + __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i)); + __m128i farw = _mm_unpacklo_epi8(farb, zero); + __m128i nearw = _mm_unpacklo_epi8(nearb, zero); + __m128i diff = _mm_sub_epi16(farw, nearw); + __m128i nears = _mm_slli_epi16(nearw, 2); + __m128i curr = _mm_add_epi16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + __m128i prv0 = _mm_slli_si128(curr, 2); + __m128i nxt0 = _mm_srli_si128(curr, 2); + __m128i prev = _mm_insert_epi16(prv0, t1, 0); + __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + __m128i bias = _mm_set1_epi16(8); + __m128i curs = _mm_slli_epi16(curr, 2); + __m128i prvd = _mm_sub_epi16(prev, curr); + __m128i nxtd = _mm_sub_epi16(next, curr); + __m128i curb = _mm_add_epi16(curs, bias); + __m128i even = _mm_add_epi16(prvd, curb); + __m128i odd = _mm_add_epi16(nxtd, curb); + + // interleave even and odd pixels, then undo scaling. + __m128i int0 = _mm_unpacklo_epi16(even, odd); + __m128i int1 = _mm_unpackhi_epi16(even, odd); + __m128i de0 = _mm_srli_epi16(int0, 4); + __m128i de1 = _mm_srli_epi16(int1, 4); + + // pack and write output + __m128i outv = _mm_packus_epi16(de0, de1); + _mm_storeu_si128((__m128i *) (out + i*2), outv); +#elif defined(STBI_NEON) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + uint8x8_t farb = vld1_u8(in_far + i); + uint8x8_t nearb = vld1_u8(in_near + i); + int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); + int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); + int16x8_t curr = vaddq_s16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + int16x8_t prv0 = vextq_s16(curr, curr, 7); + int16x8_t nxt0 = vextq_s16(curr, curr, 1); + int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); + int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + int16x8_t curs = vshlq_n_s16(curr, 2); + int16x8_t prvd = vsubq_s16(prev, curr); + int16x8_t nxtd = vsubq_s16(next, curr); + int16x8_t even = vaddq_s16(curs, prvd); + int16x8_t odd = vaddq_s16(curs, nxtd); + + // undo scaling and round, then store with even/odd phases interleaved + uint8x8x2_t o; + o.val[0] = vqrshrun_n_s16(even, 4); + o.val[1] = vqrshrun_n_s16(odd, 4); + vst2_u8(out + i*2, o); +#endif + + // "previous" value for next iter + t1 = 3*in_near[i+7] + in_far[i+7]; + } + + t0 = t1; + t1 = 3*in_near[i] + in_far[i]; + out[i*2] = stbi__div16(3*t1 + t0 + 8); + + for (++i; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} +#endif + +static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // resample with nearest-neighbor + int i,j; + STBI_NOTUSED(in_far); + for (i=0; i < w; ++i) + for (j=0; j < hs; ++j) + out[i*hs+j] = in_near[i]; + return out; +} + +#ifdef STBI_JPEG_OLD +// this is the same YCbCr-to-RGB calculation that stb_image has used +// historically before the algorithm changes in 1.49 +#define float2fixed(x) ((int) ((x) * 65536 + 0.5)) +static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) +{ + int i; + for (i=0; i < count; ++i) { + int y_fixed = (y[i] << 16) + 32768; // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr*float2fixed(1.40200f); + g = y_fixed - cr*float2fixed(0.71414f) - cb*float2fixed(0.34414f); + b = y_fixed + cb*float2fixed(1.77200f); + r >>= 16; + g >>= 16; + b >>= 16; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} +#else +// this is a reduced-precision calculation of YCbCr-to-RGB introduced +// to make sure the code produces the same results in both SIMD and scalar +#define float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) +static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) +{ + int i; + for (i=0; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* float2fixed(1.40200f); + g = y_fixed + (cr*-float2fixed(0.71414f)) + ((cb*-float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} +#endif + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) +{ + int i = 0; + +#ifdef STBI_SSE2 + // step == 3 is pretty ugly on the final interleave, and i'm not convinced + // it's useful in practice (you wouldn't use it for textures, for example). + // so just accelerate step == 4 case. + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + __m128i signflip = _mm_set1_epi8(-0x80); + __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f)); + __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f)); + __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f)); + __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f)); + __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128); + __m128i xw = _mm_set1_epi16(255); // alpha channel + + for (; i+7 < count; i += 8) { + // load + __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i)); + __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i)); + __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i)); + __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 + __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 + + // unpack to short (and left-shift cr, cb by 8) + __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); + __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); + __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); + + // color transform + __m128i yws = _mm_srli_epi16(yw, 4); + __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); + __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); + __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); + __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); + __m128i rws = _mm_add_epi16(cr0, yws); + __m128i gwt = _mm_add_epi16(cb0, yws); + __m128i bws = _mm_add_epi16(yws, cb1); + __m128i gws = _mm_add_epi16(gwt, cr1); + + // descale + __m128i rw = _mm_srai_epi16(rws, 4); + __m128i bw = _mm_srai_epi16(bws, 4); + __m128i gw = _mm_srai_epi16(gws, 4); + + // back to byte, set up for transpose + __m128i brb = _mm_packus_epi16(rw, bw); + __m128i gxb = _mm_packus_epi16(gw, xw); + + // transpose to interleave channels + __m128i t0 = _mm_unpacklo_epi8(brb, gxb); + __m128i t1 = _mm_unpackhi_epi8(brb, gxb); + __m128i o0 = _mm_unpacklo_epi16(t0, t1); + __m128i o1 = _mm_unpackhi_epi16(t0, t1); + + // store + _mm_storeu_si128((__m128i *) (out + 0), o0); + _mm_storeu_si128((__m128i *) (out + 16), o1); + out += 32; + } + } +#endif + +#ifdef STBI_NEON + // in this version, step=3 support would be easy to add. but is there demand? + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + uint8x8_t signflip = vdup_n_u8(0x80); + int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f)); + int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f)); + int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f)); + int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f)); + + for (; i+7 < count; i += 8) { + // load + uint8x8_t y_bytes = vld1_u8(y + i); + uint8x8_t cr_bytes = vld1_u8(pcr + i); + uint8x8_t cb_bytes = vld1_u8(pcb + i); + int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); + int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); + + // expand to s16 + int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); + int16x8_t crw = vshll_n_s8(cr_biased, 7); + int16x8_t cbw = vshll_n_s8(cb_biased, 7); + + // color transform + int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); + int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); + int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); + int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); + int16x8_t rws = vaddq_s16(yws, cr0); + int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); + int16x8_t bws = vaddq_s16(yws, cb1); + + // undo scaling, round, convert to byte + uint8x8x4_t o; + o.val[0] = vqrshrun_n_s16(rws, 4); + o.val[1] = vqrshrun_n_s16(gws, 4); + o.val[2] = vqrshrun_n_s16(bws, 4); + o.val[3] = vdup_n_u8(255); + + // store, interleaving r/g/b/a + vst4_u8(out, o); + out += 8*4; + } + } +#endif + + for (; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* float2fixed(1.40200f); + g = y_fixed + cr*-float2fixed(0.71414f) + ((cb*-float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} +#endif + +// set up the kernels +static void stbi__setup_jpeg(stbi__jpeg *j) +{ + j->idct_block_kernel = stbi__idct_block; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; + +#ifdef STBI_SSE2 + if (stbi__sse2_available()) { + j->idct_block_kernel = stbi__idct_simd; + #ifndef STBI_JPEG_OLD + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + #endif + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; + } +#endif + +#ifdef STBI_NEON + j->idct_block_kernel = stbi__idct_simd; + #ifndef STBI_JPEG_OLD + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + #endif + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; +#endif +} + +// clean up the temporary component buffers +static void stbi__cleanup_jpeg(stbi__jpeg *j) +{ + int i; + for (i=0; i < j->s->img_n; ++i) { + if (j->img_comp[i].raw_data) { + STBI_FREE(j->img_comp[i].raw_data); + j->img_comp[i].raw_data = NULL; + j->img_comp[i].data = NULL; + } + if (j->img_comp[i].raw_coeff) { + STBI_FREE(j->img_comp[i].raw_coeff); + j->img_comp[i].raw_coeff = 0; + j->img_comp[i].coeff = 0; + } + if (j->img_comp[i].linebuf) { + STBI_FREE(j->img_comp[i].linebuf); + j->img_comp[i].linebuf = NULL; + } + } +} + +typedef struct +{ + resample_row_func resample; + stbi_uc *line0,*line1; + int hs,vs; // expansion factor in each axis + int w_lores; // horizontal pixels pre-expansion + int ystep; // how far through vertical expansion we are + int ypos; // which pre-expansion row we're on +} stbi__resample; + +static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) +{ + int n, decode_n; + z->s->img_n = 0; // make stbi__cleanup_jpeg safe + + // validate req_comp + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + + // load a jpeg image from whichever source, but leave in YCbCr format + if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } + + // determine actual number of components to generate + n = req_comp ? req_comp : z->s->img_n; + + if (z->s->img_n == 3 && n < 3) + decode_n = 1; + else + decode_n = z->s->img_n; + + // resample and color-convert + { + int k; + unsigned int i,j; + stbi_uc *output; + stbi_uc *coutput[4]; + + stbi__resample res_comp[4]; + + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + + // allocate line buffer big enough for upsampling off the edges + // with upsample factor of 4 + z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3); + if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + r->hs = z->img_h_max / z->img_comp[k].h; + r->vs = z->img_v_max / z->img_comp[k].v; + r->ystep = r->vs >> 1; + r->w_lores = (z->s->img_x + r->hs-1) / r->hs; + r->ypos = 0; + r->line0 = r->line1 = z->img_comp[k].data; + + if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; + else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2; + else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2; + else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel; + else r->resample = stbi__resample_row_generic; + } + + // can't error after this so, this is safe + output = (stbi_uc *) stbi__malloc(n * z->s->img_x * z->s->img_y + 1); + if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + // now go ahead and resample + for (j=0; j < z->s->img_y; ++j) { + stbi_uc *out = output + n * z->s->img_x * j; + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + int y_bot = r->ystep >= (r->vs >> 1); + coutput[k] = r->resample(z->img_comp[k].linebuf, + y_bot ? r->line1 : r->line0, + y_bot ? r->line0 : r->line1, + r->w_lores, r->hs); + if (++r->ystep >= r->vs) { + r->ystep = 0; + r->line0 = r->line1; + if (++r->ypos < z->img_comp[k].y) + r->line1 += z->img_comp[k].w2; + } + } + if (n >= 3) { + stbi_uc *y = coutput[0]; + if (z->s->img_n == 3) { + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } else + for (i=0; i < z->s->img_x; ++i) { + out[0] = out[1] = out[2] = y[i]; + out[3] = 255; // not used if n==3 + out += n; + } + } else { + stbi_uc *y = coutput[0]; + if (n == 1) + for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; + else + for (i=0; i < z->s->img_x; ++i) *out++ = y[i], *out++ = 255; + } + } + stbi__cleanup_jpeg(z); + *out_x = z->s->img_x; + *out_y = z->s->img_y; + if (comp) *comp = z->s->img_n; // report original components, not output + return output; + } +} + +static unsigned char *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__jpeg j; + j.s = s; + stbi__setup_jpeg(&j); + return load_jpeg_image(&j, x,y,comp,req_comp); +} + +static int stbi__jpeg_test(stbi__context *s) +{ + int r; + stbi__jpeg j; + j.s = s; + stbi__setup_jpeg(&j); + r = stbi__decode_jpeg_header(&j, STBI__SCAN_type); + stbi__rewind(s); + return r; +} + +static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) +{ + if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { + stbi__rewind( j->s ); + return 0; + } + if (x) *x = j->s->img_x; + if (y) *y = j->s->img_y; + if (comp) *comp = j->s->img_n; + return 1; +} + +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__jpeg j; + j.s = s; + return stbi__jpeg_info_raw(&j, x, y, comp); +} +#endif + +// public domain zlib decode v0.2 Sean Barrett 2006-11-18 +// simple implementation +// - all input must be provided in an upfront buffer +// - all output is written to a single output buffer (can malloc/realloc) +// performance +// - fast huffman + +#ifndef STBI_NO_ZLIB + +// fast-way is faster to check than jpeg huffman, but slow way is slower +#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables +#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) + +// zlib-style huffman encoding +// (jpegs packs from left, zlib from right, so can't share code) +typedef struct +{ + stbi__uint16 fast[1 << STBI__ZFAST_BITS]; + stbi__uint16 firstcode[16]; + int maxcode[17]; + stbi__uint16 firstsymbol[16]; + stbi_uc size[288]; + stbi__uint16 value[288]; +} stbi__zhuffman; + +stbi_inline static int stbi__bitreverse16(int n) +{ + n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); + n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); + n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); + n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); + return n; +} + +stbi_inline static int stbi__bit_reverse(int v, int bits) +{ + STBI_ASSERT(bits <= 16); + // to bit reverse n bits, reverse 16 and shift + // e.g. 11 bits, bit reverse and shift away 5 + return stbi__bitreverse16(v) >> (16-bits); +} + +static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num) +{ + int i,k=0; + int code, next_code[16], sizes[17]; + + // DEFLATE spec for generating codes + memset(sizes, 0, sizeof(sizes)); + memset(z->fast, 0, sizeof(z->fast)); + for (i=0; i < num; ++i) + ++sizes[sizelist[i]]; + sizes[0] = 0; + for (i=1; i < 16; ++i) + if (sizes[i] > (1 << i)) + return stbi__err("bad sizes", "Corrupt PNG"); + code = 0; + for (i=1; i < 16; ++i) { + next_code[i] = code; + z->firstcode[i] = (stbi__uint16) code; + z->firstsymbol[i] = (stbi__uint16) k; + code = (code + sizes[i]); + if (sizes[i]) + if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG"); + z->maxcode[i] = code << (16-i); // preshift for inner loop + code <<= 1; + k += sizes[i]; + } + z->maxcode[16] = 0x10000; // sentinel + for (i=0; i < num; ++i) { + int s = sizelist[i]; + if (s) { + int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; + stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); + z->size [c] = (stbi_uc ) s; + z->value[c] = (stbi__uint16) i; + if (s <= STBI__ZFAST_BITS) { + int j = stbi__bit_reverse(next_code[s],s); + while (j < (1 << STBI__ZFAST_BITS)) { + z->fast[j] = fastv; + j += (1 << s); + } + } + ++next_code[s]; + } + } + return 1; +} + +// zlib-from-memory implementation for PNG reading +// because PNG allows splitting the zlib stream arbitrarily, +// and it's annoying structurally to have PNG call ZLIB call PNG, +// we require PNG read all the IDATs and combine them into a single +// memory buffer + +typedef struct +{ + stbi_uc *zbuffer, *zbuffer_end; + int num_bits; + stbi__uint32 code_buffer; + + char *zout; + char *zout_start; + char *zout_end; + int z_expandable; + + stbi__zhuffman z_length, z_distance; +} stbi__zbuf; + +stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) +{ + if (z->zbuffer >= z->zbuffer_end) return 0; + return *z->zbuffer++; +} + +static void stbi__fill_bits(stbi__zbuf *z) +{ + do { + STBI_ASSERT(z->code_buffer < (1U << z->num_bits)); + z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; + z->num_bits += 8; + } while (z->num_bits <= 24); +} + +stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) +{ + unsigned int k; + if (z->num_bits < n) stbi__fill_bits(z); + k = z->code_buffer & ((1 << n) - 1); + z->code_buffer >>= n; + z->num_bits -= n; + return k; +} + +static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s,k; + // not resolved by fast table, so compute it the slow way + // use jpeg approach, which requires MSbits at top + k = stbi__bit_reverse(a->code_buffer, 16); + for (s=STBI__ZFAST_BITS+1; ; ++s) + if (k < z->maxcode[s]) + break; + if (s == 16) return -1; // invalid code! + // code size is s, so: + b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; + STBI_ASSERT(z->size[b] == s); + a->code_buffer >>= s; + a->num_bits -= s; + return z->value[b]; +} + +stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s; + if (a->num_bits < 16) stbi__fill_bits(a); + b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; + if (b) { + s = b >> 9; + a->code_buffer >>= s; + a->num_bits -= s; + return b & 511; + } + return stbi__zhuffman_decode_slowpath(a, z); +} + +static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes +{ + char *q; + int cur, limit; + z->zout = zout; + if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); + cur = (int) (z->zout - z->zout_start); + limit = (int) (z->zout_end - z->zout_start); + while (cur + n > limit) + limit *= 2; + q = (char *) STBI_REALLOC(z->zout_start, limit); + if (q == NULL) return stbi__err("outofmem", "Out of memory"); + z->zout_start = q; + z->zout = q + cur; + z->zout_end = q + limit; + return 1; +} + +static int stbi__zlength_base[31] = { + 3,4,5,6,7,8,9,10,11,13, + 15,17,19,23,27,31,35,43,51,59, + 67,83,99,115,131,163,195,227,258,0,0 }; + +static int stbi__zlength_extra[31]= +{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; + +static int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, +257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; + +static int stbi__zdist_extra[32] = +{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +static int stbi__parse_huffman_block(stbi__zbuf *a) +{ + char *zout = a->zout; + for(;;) { + int z = stbi__zhuffman_decode(a, &a->z_length); + if (z < 256) { + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes + if (zout >= a->zout_end) { + if (!stbi__zexpand(a, zout, 1)) return 0; + zout = a->zout; + } + *zout++ = (char) z; + } else { + stbi_uc *p; + int len,dist; + if (z == 256) { + a->zout = zout; + return 1; + } + z -= 257; + len = stbi__zlength_base[z]; + if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); + z = stbi__zhuffman_decode(a, &a->z_distance); + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); + dist = stbi__zdist_base[z]; + if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); + if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); + if (zout + len > a->zout_end) { + if (!stbi__zexpand(a, zout, len)) return 0; + zout = a->zout; + } + p = (stbi_uc *) (zout - dist); + if (dist == 1) { // run of one byte; common in images. + stbi_uc v = *p; + if (len) { do *zout++ = v; while (--len); } + } else { + if (len) { do *zout++ = *p++; while (--len); } + } + } + } +} + +static int stbi__compute_huffman_codes(stbi__zbuf *a) +{ + static stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + stbi__zhuffman z_codelength; + stbi_uc lencodes[286+32+137];//padding for maximum single op + stbi_uc codelength_sizes[19]; + int i,n; + + int hlit = stbi__zreceive(a,5) + 257; + int hdist = stbi__zreceive(a,5) + 1; + int hclen = stbi__zreceive(a,4) + 4; + + memset(codelength_sizes, 0, sizeof(codelength_sizes)); + for (i=0; i < hclen; ++i) { + int s = stbi__zreceive(a,3); + codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; + } + if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; + + n = 0; + while (n < hlit + hdist) { + int c = stbi__zhuffman_decode(a, &z_codelength); + if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG"); + if (c < 16) + lencodes[n++] = (stbi_uc) c; + else if (c == 16) { + c = stbi__zreceive(a,2)+3; + memset(lencodes+n, lencodes[n-1], c); + n += c; + } else if (c == 17) { + c = stbi__zreceive(a,3)+3; + memset(lencodes+n, 0, c); + n += c; + } else { + STBI_ASSERT(c == 18); + c = stbi__zreceive(a,7)+11; + memset(lencodes+n, 0, c); + n += c; + } + } + if (n != hlit+hdist) return stbi__err("bad codelengths","Corrupt PNG"); + if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; + return 1; +} + +static int stbi__parse_uncomperssed_block(stbi__zbuf *a) +{ + stbi_uc header[4]; + int len,nlen,k; + if (a->num_bits & 7) + stbi__zreceive(a, a->num_bits & 7); // discard + // drain the bit-packed data into header + k = 0; + while (a->num_bits > 0) { + header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check + a->code_buffer >>= 8; + a->num_bits -= 8; + } + STBI_ASSERT(a->num_bits == 0); + // now fill header the normal way + while (k < 4) + header[k++] = stbi__zget8(a); + len = header[1] * 256 + header[0]; + nlen = header[3] * 256 + header[2]; + if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); + if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); + if (a->zout + len > a->zout_end) + if (!stbi__zexpand(a, a->zout, len)) return 0; + memcpy(a->zout, a->zbuffer, len); + a->zbuffer += len; + a->zout += len; + return 1; +} + +static int stbi__parse_zlib_header(stbi__zbuf *a) +{ + int cmf = stbi__zget8(a); + int cm = cmf & 15; + /* int cinfo = cmf >> 4; */ + int flg = stbi__zget8(a); + if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png + if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png + // window = 1 << (8 + cinfo)... but who cares, we fully buffer output + return 1; +} + +// @TODO: should statically initialize these for optimal thread safety +static stbi_uc stbi__zdefault_length[288], stbi__zdefault_distance[32]; +static void stbi__init_zdefaults(void) +{ + int i; // use <= to match clearly with spec + for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; + for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9; + for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7; + for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8; + + for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; +} + +static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) +{ + int final, type; + if (parse_header) + if (!stbi__parse_zlib_header(a)) return 0; + a->num_bits = 0; + a->code_buffer = 0; + do { + final = stbi__zreceive(a,1); + type = stbi__zreceive(a,2); + if (type == 0) { + if (!stbi__parse_uncomperssed_block(a)) return 0; + } else if (type == 3) { + return 0; + } else { + if (type == 1) { + // use fixed code lengths + if (!stbi__zdefault_distance[31]) stbi__init_zdefaults(); + if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; + } else { + if (!stbi__compute_huffman_codes(a)) return 0; + } + if (!stbi__parse_huffman_block(a)) return 0; + } + } while (!final); + return 1; +} + +static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) +{ + a->zout_start = obuf; + a->zout = obuf; + a->zout_end = obuf + olen; + a->z_expandable = exp; + + return stbi__parse_zlib(a, parse_header); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) +{ + return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) + return (int) (a.zout - a.zout_start); + else + return -1; +} + +STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(16384); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer+len; + if (stbi__do_zlib(&a, p, 16384, 1, 0)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) + return (int) (a.zout - a.zout_start); + else + return -1; +} +#endif + +// public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18 +// simple implementation +// - only 8-bit samples +// - no CRC checking +// - allocates lots of intermediate memory +// - avoids problem of streaming data between subsystems +// - avoids explicit window management +// performance +// - uses stb_zlib, a PD zlib implementation with fast huffman decoding + +#ifndef STBI_NO_PNG +typedef struct +{ + stbi__uint32 length; + stbi__uint32 type; +} stbi__pngchunk; + +static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) +{ + stbi__pngchunk c; + c.length = stbi__get32be(s); + c.type = stbi__get32be(s); + return c; +} + +static int stbi__check_png_header(stbi__context *s) +{ + static stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; + int i; + for (i=0; i < 8; ++i) + if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); + return 1; +} + +typedef struct +{ + stbi__context *s; + stbi_uc *idata, *expanded, *out; +} stbi__png; + + +enum { + STBI__F_none=0, + STBI__F_sub=1, + STBI__F_up=2, + STBI__F_avg=3, + STBI__F_paeth=4, + // synthetic filters used for first scanline to avoid needing a dummy row of 0s + STBI__F_avg_first, + STBI__F_paeth_first +}; + +static stbi_uc first_row_filter[5] = +{ + STBI__F_none, + STBI__F_sub, + STBI__F_none, + STBI__F_avg_first, + STBI__F_paeth_first +}; + +static int stbi__paeth(int a, int b, int c) +{ + int p = a + b - c; + int pa = abs(p-a); + int pb = abs(p-b); + int pc = abs(p-c); + if (pa <= pb && pa <= pc) return a; + if (pb <= pc) return b; + return c; +} + +static stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; + +// create the png data from post-deflated data +static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) +{ + stbi__context *s = a->s; + stbi__uint32 i,j,stride = x*out_n; + stbi__uint32 img_len, img_width_bytes; + int k; + int img_n = s->img_n; // copy it into a local for later + + STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); + a->out = (stbi_uc *) stbi__malloc(x * y * out_n); // extra bytes to write off the end into + if (!a->out) return stbi__err("outofmem", "Out of memory"); + + img_width_bytes = (((img_n * x * depth) + 7) >> 3); + img_len = (img_width_bytes + 1) * y; + if (s->img_x == x && s->img_y == y) { + if (raw_len != img_len) return stbi__err("not enough pixels","Corrupt PNG"); + } else { // interlaced: + if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); + } + + for (j=0; j < y; ++j) { + stbi_uc *cur = a->out + stride*j; + stbi_uc *prior = cur - stride; + int filter = *raw++; + int filter_bytes = img_n; + int width = x; + if (filter > 4) + return stbi__err("invalid filter","Corrupt PNG"); + + if (depth < 8) { + STBI_ASSERT(img_width_bytes <= x); + cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place + filter_bytes = 1; + width = img_width_bytes; + } + + // if first row, use special filter that doesn't sample previous row + if (j == 0) filter = first_row_filter[filter]; + + // handle first byte explicitly + for (k=0; k < filter_bytes; ++k) { + switch (filter) { + case STBI__F_none : cur[k] = raw[k]; break; + case STBI__F_sub : cur[k] = raw[k]; break; + case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; + case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; + case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break; + case STBI__F_avg_first : cur[k] = raw[k]; break; + case STBI__F_paeth_first: cur[k] = raw[k]; break; + } + } + + if (depth == 8) { + if (img_n != out_n) + cur[img_n] = 255; // first pixel + raw += img_n; + cur += out_n; + prior += out_n; + } else { + raw += 1; + cur += 1; + prior += 1; + } + + // this is a little gross, so that we don't switch per-pixel or per-component + if (depth < 8 || img_n == out_n) { + int nk = (width - 1)*img_n; + #define CASE(f) \ + case f: \ + for (k=0; k < nk; ++k) + switch (filter) { + // "none" filter turns into a memcpy here; make that explicit. + case STBI__F_none: memcpy(cur, raw, nk); break; + CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); break; + CASE(STBI__F_up) cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; + CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); break; + CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); break; + CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); break; + CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); break; + } + #undef CASE + raw += nk; + } else { + STBI_ASSERT(img_n+1 == out_n); + #define CASE(f) \ + case f: \ + for (i=x-1; i >= 1; --i, cur[img_n]=255,raw+=img_n,cur+=out_n,prior+=out_n) \ + for (k=0; k < img_n; ++k) + switch (filter) { + CASE(STBI__F_none) cur[k] = raw[k]; break; + CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(raw[k] + cur[k-out_n]); break; + CASE(STBI__F_up) cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; + CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-out_n])>>1)); break; + CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-out_n],prior[k],prior[k-out_n])); break; + CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(raw[k] + (cur[k-out_n] >> 1)); break; + CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-out_n],0,0)); break; + } + #undef CASE + } + } + + // we make a separate pass to expand bits to pixels; for performance, + // this could run two scanlines behind the above code, so it won't + // intefere with filtering but will still be in the cache. + if (depth < 8) { + for (j=0; j < y; ++j) { + stbi_uc *cur = a->out + stride*j; + stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes; + // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit + // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop + stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range + + // note that the final byte might overshoot and write more data than desired. + // we can allocate enough data that this never writes out of memory, but it + // could also overwrite the next scanline. can it overwrite non-empty data + // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel. + // so we need to explicitly clamp the final ones + + if (depth == 4) { + for (k=x*img_n; k >= 2; k-=2, ++in) { + *cur++ = scale * ((*in >> 4) ); + *cur++ = scale * ((*in ) & 0x0f); + } + if (k > 0) *cur++ = scale * ((*in >> 4) ); + } else if (depth == 2) { + for (k=x*img_n; k >= 4; k-=4, ++in) { + *cur++ = scale * ((*in >> 6) ); + *cur++ = scale * ((*in >> 4) & 0x03); + *cur++ = scale * ((*in >> 2) & 0x03); + *cur++ = scale * ((*in ) & 0x03); + } + if (k > 0) *cur++ = scale * ((*in >> 6) ); + if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03); + if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03); + } else if (depth == 1) { + for (k=x*img_n; k >= 8; k-=8, ++in) { + *cur++ = scale * ((*in >> 7) ); + *cur++ = scale * ((*in >> 6) & 0x01); + *cur++ = scale * ((*in >> 5) & 0x01); + *cur++ = scale * ((*in >> 4) & 0x01); + *cur++ = scale * ((*in >> 3) & 0x01); + *cur++ = scale * ((*in >> 2) & 0x01); + *cur++ = scale * ((*in >> 1) & 0x01); + *cur++ = scale * ((*in ) & 0x01); + } + if (k > 0) *cur++ = scale * ((*in >> 7) ); + if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01); + if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01); + if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01); + if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01); + if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01); + if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01); + } + if (img_n != out_n) { + int q; + // insert alpha = 255 + cur = a->out + stride*j; + if (img_n == 1) { + for (q=x-1; q >= 0; --q) { + cur[q*2+1] = 255; + cur[q*2+0] = cur[q]; + } + } else { + STBI_ASSERT(img_n == 3); + for (q=x-1; q >= 0; --q) { + cur[q*4+3] = 255; + cur[q*4+2] = cur[q*3+2]; + cur[q*4+1] = cur[q*3+1]; + cur[q*4+0] = cur[q*3+0]; + } + } + } + } + } + + return 1; +} + +static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) +{ + stbi_uc *final; + int p; + if (!interlaced) + return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); + + // de-interlacing + final = (stbi_uc *) stbi__malloc(a->s->img_x * a->s->img_y * out_n); + for (p=0; p < 7; ++p) { + int xorig[] = { 0,4,0,2,0,1,0 }; + int yorig[] = { 0,0,4,0,2,0,1 }; + int xspc[] = { 8,8,4,4,2,2,1 }; + int yspc[] = { 8,8,8,4,4,2,2 }; + int i,j,x,y; + // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 + x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; + y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; + if (x && y) { + stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; + if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { + STBI_FREE(final); + return 0; + } + for (j=0; j < y; ++j) { + for (i=0; i < x; ++i) { + int out_y = j*yspc[p]+yorig[p]; + int out_x = i*xspc[p]+xorig[p]; + memcpy(final + out_y*a->s->img_x*out_n + out_x*out_n, + a->out + (j*x+i)*out_n, out_n); + } + } + STBI_FREE(a->out); + image_data += img_len; + image_data_len -= img_len; + } + } + a->out = final; + + return 1; +} + +static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + // compute color-based transparency, assuming we've + // already got 255 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i=0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 255); + p += 2; + } + } else { + for (i=0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) +{ + stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; + stbi_uc *p, *temp_out, *orig = a->out; + + p = (stbi_uc *) stbi__malloc(pixel_count * pal_img_n); + if (p == NULL) return stbi__err("outofmem", "Out of memory"); + + // between here and free(out) below, exitting would leak + temp_out = p; + + if (pal_img_n == 3) { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p += 3; + } + } else { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p[3] = palette[n+3]; + p += 4; + } + } + STBI_FREE(a->out); + a->out = temp_out; + + STBI_NOTUSED(len); + + return 1; +} + +static int stbi__unpremultiply_on_load = 0; +static int stbi__de_iphone_flag = 0; + +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag = flag_true_if_should_convert; +} + +static void stbi__de_iphone(stbi__png *z) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + if (s->img_out_n == 3) { // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 3; + } + } else { + STBI_ASSERT(s->img_out_n == 4); + if (stbi__unpremultiply_on_load) { + // convert bgr to rgb and unpremultiply + for (i=0; i < pixel_count; ++i) { + stbi_uc a = p[3]; + stbi_uc t = p[0]; + if (a) { + p[0] = p[2] * 255 / a; + p[1] = p[1] * 255 / a; + p[2] = t * 255 / a; + } else { + p[0] = p[2]; + p[2] = t; + } + p += 4; + } + } else { + // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 4; + } + } + } +} + +#define STBI__PNG_TYPE(a,b,c,d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) + +static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) +{ + stbi_uc palette[1024], pal_img_n=0; + stbi_uc has_trans=0, tc[3]; + stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; + int first=1,k,interlace=0, color=0, depth=0, is_iphone=0; + stbi__context *s = z->s; + + z->expanded = NULL; + z->idata = NULL; + z->out = NULL; + + if (!stbi__check_png_header(s)) return 0; + + if (scan == STBI__SCAN_type) return 1; + + for (;;) { + stbi__pngchunk c = stbi__get_chunk_header(s); + switch (c.type) { + case STBI__PNG_TYPE('C','g','B','I'): + is_iphone = 1; + stbi__skip(s, c.length); + break; + case STBI__PNG_TYPE('I','H','D','R'): { + int comp,filter; + if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); + first = 0; + if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); + s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); + s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); + depth = stbi__get8(s); if (depth != 1 && depth != 2 && depth != 4 && depth != 8) return stbi__err("1/2/4/8-bit only","PNG not supported: 1/2/4/8-bit only"); + color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); + comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); + filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); + interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); + if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG"); + if (!pal_img_n) { + s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); + if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); + if (scan == STBI__SCAN_header) return 1; + } else { + // if paletted, then pal_n is our final components, and + // img_n is # components to decompress/filter. + s->img_n = 1; + if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); + // if SCAN_header, have to scan to see if we have a tRNS + } + break; + } + + case STBI__PNG_TYPE('P','L','T','E'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); + pal_len = c.length / 3; + if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); + for (i=0; i < pal_len; ++i) { + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + } + break; + } + + case STBI__PNG_TYPE('t','R','N','S'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); + if (pal_img_n) { + if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } + if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); + if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); + pal_img_n = 4; + for (i=0; i < c.length; ++i) + palette[i*4+3] = stbi__get8(s); + } else { + if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); + if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); + has_trans = 1; + for (k=0; k < s->img_n; ++k) + tc[k] = (stbi_uc) (stbi__get16be(s) & 255) * stbi__depth_scale_table[depth]; // non 8-bit images will be larger + } + break; + } + + case STBI__PNG_TYPE('I','D','A','T'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); + if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } + if ((int)(ioff + c.length) < (int)ioff) return 0; + if (ioff + c.length > idata_limit) { + stbi_uc *p; + if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; + while (ioff + c.length > idata_limit) + idata_limit *= 2; + p = (stbi_uc *) STBI_REALLOC(z->idata, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); + z->idata = p; + } + if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); + ioff += c.length; + break; + } + + case STBI__PNG_TYPE('I','E','N','D'): { + stbi__uint32 raw_len, bpl; + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (scan != STBI__SCAN_load) return 1; + if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); + // initial guess for decoded data size to avoid unnecessary reallocs + bpl = (s->img_x * depth + 7) / 8; // bytes per line, per component + raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; + z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); + if (z->expanded == NULL) return 0; // zlib should set error + STBI_FREE(z->idata); z->idata = NULL; + if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) + s->img_out_n = s->img_n+1; + else + s->img_out_n = s->img_n; + if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, depth, color, interlace)) return 0; + if (has_trans) + if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; + if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) + stbi__de_iphone(z); + if (pal_img_n) { + // pal_img_n == 3 or 4 + s->img_n = pal_img_n; // record the actual colors we had + s->img_out_n = pal_img_n; + if (req_comp >= 3) s->img_out_n = req_comp; + if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) + return 0; + } + STBI_FREE(z->expanded); z->expanded = NULL; + return 1; + } + + default: + // if critical, fail + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if ((c.type & (1 << 29)) == 0) { + #ifndef STBI_NO_FAILURE_STRINGS + // not threadsafe + static char invalid_chunk[] = "XXXX PNG chunk not known"; + invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); + invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); + invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); + invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); + #endif + return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); + } + stbi__skip(s, c.length); + break; + } + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + } +} + +static unsigned char *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp) +{ + unsigned char *result=NULL; + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { + result = p->out; + p->out = NULL; + if (req_comp && req_comp != p->s->img_out_n) { + result = stbi__convert_format(result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + p->s->img_out_n = req_comp; + if (result == NULL) return result; + } + *x = p->s->img_x; + *y = p->s->img_y; + if (n) *n = p->s->img_out_n; + } + STBI_FREE(p->out); p->out = NULL; + STBI_FREE(p->expanded); p->expanded = NULL; + STBI_FREE(p->idata); p->idata = NULL; + + return result; +} + +static unsigned char *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__png p; + p.s = s; + return stbi__do_png(&p, x,y,comp,req_comp); +} + +static int stbi__png_test(stbi__context *s) +{ + int r; + r = stbi__check_png_header(s); + stbi__rewind(s); + return r; +} + +static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) +{ + if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { + stbi__rewind( p->s ); + return 0; + } + if (x) *x = p->s->img_x; + if (y) *y = p->s->img_y; + if (comp) *comp = p->s->img_n; + return 1; +} + +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__png p; + p.s = s; + return stbi__png_info_raw(&p, x, y, comp); +} +#endif + +// Microsoft/Windows BMP image + +#ifndef STBI_NO_BMP +static int stbi__bmp_test_raw(stbi__context *s) +{ + int r; + int sz; + if (stbi__get8(s) != 'B') return 0; + if (stbi__get8(s) != 'M') return 0; + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + stbi__get32le(s); // discard data offset + sz = stbi__get32le(s); + r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); + return r; +} + +static int stbi__bmp_test(stbi__context *s) +{ + int r = stbi__bmp_test_raw(s); + stbi__rewind(s); + return r; +} + + +// returns 0..31 for the highest set bit +static int stbi__high_bit(unsigned int z) +{ + int n=0; + if (z == 0) return -1; + if (z >= 0x10000) n += 16, z >>= 16; + if (z >= 0x00100) n += 8, z >>= 8; + if (z >= 0x00010) n += 4, z >>= 4; + if (z >= 0x00004) n += 2, z >>= 2; + if (z >= 0x00002) n += 1, z >>= 1; + return n; +} + +static int stbi__bitcount(unsigned int a) +{ + a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 + a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits + a = (a + (a >> 8)); // max 16 per 8 bits + a = (a + (a >> 16)); // max 32 per 8 bits + return a & 0xff; +} + +static int stbi__shiftsigned(int v, int shift, int bits) +{ + int result; + int z=0; + + if (shift < 0) v <<= -shift; + else v >>= shift; + result = v; + + z = bits; + while (z < 8) { + result += v >> z; + z += bits; + } + return result; +} + +static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi_uc *out; + unsigned int mr=0,mg=0,mb=0,ma=0, all_a=255; + stbi_uc pal[256][4]; + int psize=0,i,j,compress=0,width; + int bpp, flip_vertically, pad, target, offset, hsz; + if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + offset = stbi__get32le(s); + hsz = stbi__get32le(s); + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); + if (hsz == 12) { + s->img_x = stbi__get16le(s); + s->img_y = stbi__get16le(s); + } else { + s->img_x = stbi__get32le(s); + s->img_y = stbi__get32le(s); + } + if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); + bpp = stbi__get16le(s); + if (bpp == 1) return stbi__errpuc("monochrome", "BMP type not supported: 1-bit"); + flip_vertically = ((int) s->img_y) > 0; + s->img_y = abs((int) s->img_y); + if (hsz == 12) { + if (bpp < 24) + psize = (offset - 14 - 24) / 3; + } else { + compress = stbi__get32le(s); + if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); + stbi__get32le(s); // discard sizeof + stbi__get32le(s); // discard hres + stbi__get32le(s); // discard vres + stbi__get32le(s); // discard colorsused + stbi__get32le(s); // discard max important + if (hsz == 40 || hsz == 56) { + if (hsz == 56) { + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + } + if (bpp == 16 || bpp == 32) { + mr = mg = mb = 0; + if (compress == 0) { + if (bpp == 32) { + mr = 0xffu << 16; + mg = 0xffu << 8; + mb = 0xffu << 0; + ma = 0xffu << 24; + all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 + } else { + mr = 31u << 10; + mg = 31u << 5; + mb = 31u << 0; + } + } else if (compress == 3) { + mr = stbi__get32le(s); + mg = stbi__get32le(s); + mb = stbi__get32le(s); + // not documented, but generated by photoshop and handled by mspaint + if (mr == mg && mg == mb) { + // ?!?!? + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else { + STBI_ASSERT(hsz == 108 || hsz == 124); + mr = stbi__get32le(s); + mg = stbi__get32le(s); + mb = stbi__get32le(s); + ma = stbi__get32le(s); + stbi__get32le(s); // discard color space + for (i=0; i < 12; ++i) + stbi__get32le(s); // discard color space parameters + if (hsz == 124) { + stbi__get32le(s); // discard rendering intent + stbi__get32le(s); // discard offset of profile data + stbi__get32le(s); // discard size of profile data + stbi__get32le(s); // discard reserved + } + } + if (bpp < 16) + psize = (offset - 14 - hsz) >> 2; + } + s->img_n = ma ? 4 : 3; + if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 + target = req_comp; + else + target = s->img_n; // if they want monochrome, we'll post-convert + out = (stbi_uc *) stbi__malloc(target * s->img_x * s->img_y); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + if (bpp < 16) { + int z=0; + if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } + for (i=0; i < psize; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + if (hsz != 12) stbi__get8(s); + pal[i][3] = 255; + } + stbi__skip(s, offset - 14 - hsz - psize * (hsz == 12 ? 3 : 4)); + if (bpp == 4) width = (s->img_x + 1) >> 1; + else if (bpp == 8) width = s->img_x; + else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } + pad = (-width)&3; + for (j=0; j < (int) s->img_y; ++j) { + for (i=0; i < (int) s->img_x; i += 2) { + int v=stbi__get8(s),v2=0; + if (bpp == 4) { + v2 = v & 15; + v >>= 4; + } + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + v = (bpp == 8) ? stbi__get8(s) : v2; + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + } + stbi__skip(s, pad); + } + } else { + int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; + int z = 0; + int easy=0; + stbi__skip(s, offset - 14 - hsz); + if (bpp == 24) width = 3 * s->img_x; + else if (bpp == 16) width = 2*s->img_x; + else /* bpp = 32 and pad = 0 */ width=0; + pad = (-width) & 3; + if (bpp == 24) { + easy = 1; + } else if (bpp == 32) { + if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) + easy = 2; + } + if (!easy) { + if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + // right shift amt to put high bit in position #7 + rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr); + gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); + bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); + ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); + } + for (j=0; j < (int) s->img_y; ++j) { + if (easy) { + for (i=0; i < (int) s->img_x; ++i) { + unsigned char a; + out[z+2] = stbi__get8(s); + out[z+1] = stbi__get8(s); + out[z+0] = stbi__get8(s); + z += 3; + a = (easy == 2 ? stbi__get8(s) : 255); + all_a |= a; + if (target == 4) out[z++] = a; + } + } else { + for (i=0; i < (int) s->img_x; ++i) { + stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); + int a; + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); + a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); + all_a |= a; + if (target == 4) out[z++] = STBI__BYTECAST(a); + } + } + stbi__skip(s, pad); + } + } + + // if alpha channel is all 0s, replace with all 255s + if (target == 4 && all_a == 0) + for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4) + out[i] = 255; + + if (flip_vertically) { + stbi_uc t; + for (j=0; j < (int) s->img_y>>1; ++j) { + stbi_uc *p1 = out + j *s->img_x*target; + stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; + for (i=0; i < (int) s->img_x*target; ++i) { + t = p1[i], p1[i] = p2[i], p2[i] = t; + } + } + } + + if (req_comp && req_comp != target) { + out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + return out; +} +#endif + +// Targa Truevision - TGA +// by Jonathan Dummer +#ifndef STBI_NO_TGA +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) +{ + int tga_w, tga_h, tga_comp; + int sz; + stbi__get8(s); // discard Offset + sz = stbi__get8(s); // color type + if( sz > 1 ) { + stbi__rewind(s); + return 0; // only RGB or indexed allowed + } + sz = stbi__get8(s); // image type + // only RGB or grey allowed, +/- RLE + if ((sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11)) return 0; + stbi__skip(s,9); + tga_w = stbi__get16le(s); + if( tga_w < 1 ) { + stbi__rewind(s); + return 0; // test width + } + tga_h = stbi__get16le(s); + if( tga_h < 1 ) { + stbi__rewind(s); + return 0; // test height + } + sz = stbi__get8(s); // bits per pixel + // only RGB or RGBA or grey allowed + if ((sz != 8) && (sz != 16) && (sz != 24) && (sz != 32)) { + stbi__rewind(s); + return 0; + } + tga_comp = sz; + if (x) *x = tga_w; + if (y) *y = tga_h; + if (comp) *comp = tga_comp / 8; + return 1; // seems to have passed everything +} + +static int stbi__tga_test(stbi__context *s) +{ + int res; + int sz; + stbi__get8(s); // discard Offset + sz = stbi__get8(s); // color type + if ( sz > 1 ) return 0; // only RGB or indexed allowed + sz = stbi__get8(s); // image type + if ( (sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11) ) return 0; // only RGB or grey allowed, +/- RLE + stbi__get16be(s); // discard palette start + stbi__get16be(s); // discard palette length + stbi__get8(s); // discard bits per palette color entry + stbi__get16be(s); // discard x origin + stbi__get16be(s); // discard y origin + if ( stbi__get16be(s) < 1 ) return 0; // test width + if ( stbi__get16be(s) < 1 ) return 0; // test height + sz = stbi__get8(s); // bits per pixel + if ( (sz != 8) && (sz != 16) && (sz != 24) && (sz != 32) ) + res = 0; + else + res = 1; + stbi__rewind(s); + return res; +} + +static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + // read in the TGA header stuff + int tga_offset = stbi__get8(s); + int tga_indexed = stbi__get8(s); + int tga_image_type = stbi__get8(s); + int tga_is_RLE = 0; + int tga_palette_start = stbi__get16le(s); + int tga_palette_len = stbi__get16le(s); + int tga_palette_bits = stbi__get8(s); + int tga_x_origin = stbi__get16le(s); + int tga_y_origin = stbi__get16le(s); + int tga_width = stbi__get16le(s); + int tga_height = stbi__get16le(s); + int tga_bits_per_pixel = stbi__get8(s); + int tga_comp = tga_bits_per_pixel / 8; + int tga_inverted = stbi__get8(s); + // image data + unsigned char *tga_data; + unsigned char *tga_palette = NULL; + int i, j; + unsigned char raw_data[4]; + int RLE_count = 0; + int RLE_repeating = 0; + int read_next_pixel = 1; + + // do a tiny bit of precessing + if ( tga_image_type >= 8 ) + { + tga_image_type -= 8; + tga_is_RLE = 1; + } + /* int tga_alpha_bits = tga_inverted & 15; */ + tga_inverted = 1 - ((tga_inverted >> 5) & 1); + + // error check + if ( //(tga_indexed) || + (tga_width < 1) || (tga_height < 1) || + (tga_image_type < 1) || (tga_image_type > 3) || + ((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16) && + (tga_bits_per_pixel != 24) && (tga_bits_per_pixel != 32)) + ) + { + return NULL; // we don't report this as a bad TGA because we don't even know if it's TGA + } + + // If I'm paletted, then I'll use the number of bits from the palette + if ( tga_indexed ) + { + tga_comp = tga_palette_bits / 8; + } + + // tga info + *x = tga_width; + *y = tga_height; + if (comp) *comp = tga_comp; + + tga_data = (unsigned char*)stbi__malloc( (size_t)tga_width * tga_height * tga_comp ); + if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); + + // skip to the data's starting position (offset usually = 0) + stbi__skip(s, tga_offset ); + + if ( !tga_indexed && !tga_is_RLE) { + for (i=0; i < tga_height; ++i) { + int row = tga_inverted ? tga_height -i - 1 : i; + stbi_uc *tga_row = tga_data + row*tga_width*tga_comp; + stbi__getn(s, tga_row, tga_width * tga_comp); + } + } else { + // do I need to load a palette? + if ( tga_indexed) + { + // any data to skip? (offset usually = 0) + stbi__skip(s, tga_palette_start ); + // load the palette + tga_palette = (unsigned char*)stbi__malloc( tga_palette_len * tga_palette_bits / 8 ); + if (!tga_palette) { + STBI_FREE(tga_data); + return stbi__errpuc("outofmem", "Out of memory"); + } + if (!stbi__getn(s, tga_palette, tga_palette_len * tga_palette_bits / 8 )) { + STBI_FREE(tga_data); + STBI_FREE(tga_palette); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + } + // load the data + for (i=0; i < tga_width * tga_height; ++i) + { + // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? + if ( tga_is_RLE ) + { + if ( RLE_count == 0 ) + { + // yep, get the next byte as a RLE command + int RLE_cmd = stbi__get8(s); + RLE_count = 1 + (RLE_cmd & 127); + RLE_repeating = RLE_cmd >> 7; + read_next_pixel = 1; + } else if ( !RLE_repeating ) + { + read_next_pixel = 1; + } + } else + { + read_next_pixel = 1; + } + // OK, if I need to read a pixel, do it now + if ( read_next_pixel ) + { + // load however much data we did have + if ( tga_indexed ) + { + // read in 1 byte, then perform the lookup + int pal_idx = stbi__get8(s); + if ( pal_idx >= tga_palette_len ) + { + // invalid index + pal_idx = 0; + } + pal_idx *= tga_bits_per_pixel / 8; + for (j = 0; j*8 < tga_bits_per_pixel; ++j) + { + raw_data[j] = tga_palette[pal_idx+j]; + } + } else + { + // read in the data raw + for (j = 0; j*8 < tga_bits_per_pixel; ++j) + { + raw_data[j] = stbi__get8(s); + } + } + // clear the reading flag for the next pixel + read_next_pixel = 0; + } // end of reading a pixel + + // copy data + for (j = 0; j < tga_comp; ++j) + tga_data[i*tga_comp+j] = raw_data[j]; + + // in case we're in RLE mode, keep counting down + --RLE_count; + } + // do I need to invert the image? + if ( tga_inverted ) + { + for (j = 0; j*2 < tga_height; ++j) + { + int index1 = j * tga_width * tga_comp; + int index2 = (tga_height - 1 - j) * tga_width * tga_comp; + for (i = tga_width * tga_comp; i > 0; --i) + { + unsigned char temp = tga_data[index1]; + tga_data[index1] = tga_data[index2]; + tga_data[index2] = temp; + ++index1; + ++index2; + } + } + } + // clear my palette, if I had one + if ( tga_palette != NULL ) + { + STBI_FREE( tga_palette ); + } + } + + // swap RGB + if (tga_comp >= 3) + { + unsigned char* tga_pixel = tga_data; + for (i=0; i < tga_width * tga_height; ++i) + { + unsigned char temp = tga_pixel[0]; + tga_pixel[0] = tga_pixel[2]; + tga_pixel[2] = temp; + tga_pixel += tga_comp; + } + } + + // convert to target component count + if (req_comp && req_comp != tga_comp) + tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); + + // the things I do to get rid of an error message, and yet keep + // Microsoft's C compilers happy... [8^( + tga_palette_start = tga_palette_len = tga_palette_bits = + tga_x_origin = tga_y_origin = 0; + // OK, done + return tga_data; +} +#endif + +// ************************************************************************************************* +// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s) +{ + int r = (stbi__get32be(s) == 0x38425053); + stbi__rewind(s); + return r; +} + +static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + int pixelCount; + int channelCount, compression; + int channel, i, count, len; + int bitdepth; + int w,h; + stbi_uc *out; + + // Check identifier + if (stbi__get32be(s) != 0x38425053) // "8BPS" + return stbi__errpuc("not PSD", "Corrupt PSD image"); + + // Check file type version. + if (stbi__get16be(s) != 1) + return stbi__errpuc("wrong version", "Unsupported version of PSD image"); + + // Skip 6 reserved bytes. + stbi__skip(s, 6 ); + + // Read the number of channels (R, G, B, A, etc). + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) + return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); + + // Read the rows and columns of the image. + h = stbi__get32be(s); + w = stbi__get32be(s); + + // Make sure the depth is 8 bits. + bitdepth = stbi__get16be(s); + if (bitdepth != 8 && bitdepth != 16) + return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit"); + + // Make sure the color mode is RGB. + // Valid options are: + // 0: Bitmap + // 1: Grayscale + // 2: Indexed color + // 3: RGB color + // 4: CMYK color + // 7: Multichannel + // 8: Duotone + // 9: Lab color + if (stbi__get16be(s) != 3) + return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); + + // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) + stbi__skip(s,stbi__get32be(s) ); + + // Skip the image resources. (resolution, pen tool paths, etc) + stbi__skip(s, stbi__get32be(s) ); + + // Skip the reserved data. + stbi__skip(s, stbi__get32be(s) ); + + // Find out if the data is compressed. + // Known values: + // 0: no compression + // 1: RLE compressed + compression = stbi__get16be(s); + if (compression > 1) + return stbi__errpuc("bad compression", "PSD has an unknown compression format"); + + // Create the destination image. + out = (stbi_uc *) stbi__malloc(4 * w*h); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + pixelCount = w*h; + + // Initialize the data to zero. + //memset( out, 0, pixelCount * 4 ); + + // Finally, the image data. + if (compression) { + // RLE as used by .PSD and .TIFF + // Loop until you get the number of unpacked bytes you are expecting: + // Read the next source byte into n. + // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. + // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. + // Else if n is 128, noop. + // Endloop + + // The RLE-compressed data is preceeded by a 2-byte data count for each row in the data, + // which we're going to just skip. + stbi__skip(s, h * channelCount * 2 ); + + // Read the RLE data by channel. + for (channel = 0; channel < 4; channel++) { + stbi_uc *p; + + p = out+channel; + if (channel >= channelCount) { + // Fill this channel with default data. + for (i = 0; i < pixelCount; i++, p += 4) + *p = (channel == 3 ? 255 : 0); + } else { + // Read the RLE data. + count = 0; + while (count < pixelCount) { + len = stbi__get8(s); + if (len == 128) { + // No-op. + } else if (len < 128) { + // Copy next len+1 bytes literally. + len++; + count += len; + while (len) { + *p = stbi__get8(s); + p += 4; + len--; + } + } else if (len > 128) { + stbi_uc val; + // Next -len+1 bytes in the dest are replicated from next source byte. + // (Interpret len as a negative 8-bit int.) + len ^= 0x0FF; + len += 2; + val = stbi__get8(s); + count += len; + while (len) { + *p = val; + p += 4; + len--; + } + } + } + } + } + + } else { + // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) + // where each channel consists of an 8-bit value for each pixel in the image. + + // Read the data by channel. + for (channel = 0; channel < 4; channel++) { + stbi_uc *p; + + p = out + channel; + if (channel >= channelCount) { + // Fill this channel with default data. + stbi_uc val = channel == 3 ? 255 : 0; + for (i = 0; i < pixelCount; i++, p += 4) + *p = val; + } else { + // Read the data. + if (bitdepth == 16) { + for (i = 0; i < pixelCount; i++, p += 4) + *p = (stbi_uc) (stbi__get16be(s) >> 8); + } else { + for (i = 0; i < pixelCount; i++, p += 4) + *p = stbi__get8(s); + } + } + } + } + + if (req_comp && req_comp != 4) { + out = stbi__convert_format(out, 4, req_comp, w, h); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + if (comp) *comp = 4; + *y = h; + *x = w; + + return out; +} +#endif + +// ************************************************************************************************* +// Softimage PIC loader +// by Tom Seddon +// +// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format +// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ + +#ifndef STBI_NO_PIC +static int stbi__pic_is4(stbi__context *s,const char *str) +{ + int i; + for (i=0; i<4; ++i) + if (stbi__get8(s) != (stbi_uc)str[i]) + return 0; + + return 1; +} + +static int stbi__pic_test_core(stbi__context *s) +{ + int i; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) + return 0; + + for(i=0;i<84;++i) + stbi__get8(s); + + if (!stbi__pic_is4(s,"PICT")) + return 0; + + return 1; +} + +typedef struct +{ + stbi_uc size,type,channel; +} stbi__pic_packet; + +static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) +{ + int mask=0x80, i; + + for (i=0; i<4; ++i, mask>>=1) { + if (channel & mask) { + if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short"); + dest[i]=stbi__get8(s); + } + } + + return dest; +} + +static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src) +{ + int mask=0x80,i; + + for (i=0;i<4; ++i, mask>>=1) + if (channel&mask) + dest[i]=src[i]; +} + +static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result) +{ + int act_comp=0,num_packets=0,y,chained; + stbi__pic_packet packets[10]; + + // this will (should...) cater for even some bizarre stuff like having data + // for the same channel in multiple packets. + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return stbi__errpuc("bad format","too many packets"); + + packet = &packets[num_packets++]; + + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + + act_comp |= packet->channel; + + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)"); + if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp"); + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? + + for(y=0; ytype) { + default: + return stbi__errpuc("bad format","packet has bad compression type"); + + case 0: {//uncompressed + int x; + + for(x=0;xchannel,dest)) + return 0; + break; + } + + case 1://Pure RLE + { + int left=width, i; + + while (left>0) { + stbi_uc count,value[4]; + + count=stbi__get8(s); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)"); + + if (count > left) + count = (stbi_uc) left; + + if (!stbi__readval(s,packet->channel,value)) return 0; + + for(i=0; ichannel,dest,value); + left -= count; + } + } + break; + + case 2: {//Mixed RLE + int left=width; + while (left>0) { + int count = stbi__get8(s), i; + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)"); + + if (count >= 128) { // Repeated + stbi_uc value[4]; + + if (count==128) + count = stbi__get16be(s); + else + count -= 127; + if (count > left) + return stbi__errpuc("bad file","scanline overrun"); + + if (!stbi__readval(s,packet->channel,value)) + return 0; + + for(i=0;ichannel,dest,value); + } else { // Raw + ++count; + if (count>left) return stbi__errpuc("bad file","scanline overrun"); + + for(i=0;ichannel,dest)) + return 0; + } + left-=count; + } + break; + } + } + } + } + + return result; +} + +static stbi_uc *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp) +{ + stbi_uc *result; + int i, x,y; + + for (i=0; i<92; ++i) + stbi__get8(s); + + x = stbi__get16be(s); + y = stbi__get16be(s); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); + if ((1 << 28) / x < y) return stbi__errpuc("too large", "Image too large to decode"); + + stbi__get32be(s); //skip `ratio' + stbi__get16be(s); //skip `fields' + stbi__get16be(s); //skip `pad' + + // intermediate buffer is RGBA + result = (stbi_uc *) stbi__malloc(x*y*4); + memset(result, 0xff, x*y*4); + + if (!stbi__pic_load_core(s,x,y,comp, result)) { + STBI_FREE(result); + result=0; + } + *px = x; + *py = y; + if (req_comp == 0) req_comp = *comp; + result=stbi__convert_format(result,4,req_comp,x,y); + + return result; +} + +static int stbi__pic_test(stbi__context *s) +{ + int r = stbi__pic_test_core(s); + stbi__rewind(s); + return r; +} +#endif + +// ************************************************************************************************* +// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb + +#ifndef STBI_NO_GIF +typedef struct +{ + stbi__int16 prefix; + stbi_uc first; + stbi_uc suffix; +} stbi__gif_lzw; + +typedef struct +{ + int w,h; + stbi_uc *out, *old_out; // output buffer (always 4 components) + int flags, bgindex, ratio, transparent, eflags, delay; + stbi_uc pal[256][4]; + stbi_uc lpal[256][4]; + stbi__gif_lzw codes[4096]; + stbi_uc *color_table; + int parse, step; + int lflags; + int start_x, start_y; + int max_x, max_y; + int cur_x, cur_y; + int line_size; +} stbi__gif; + +static int stbi__gif_test_raw(stbi__context *s) +{ + int sz; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0; + sz = stbi__get8(s); + if (sz != '9' && sz != '7') return 0; + if (stbi__get8(s) != 'a') return 0; + return 1; +} + +static int stbi__gif_test(stbi__context *s) +{ + int r = stbi__gif_test_raw(s); + stbi__rewind(s); + return r; +} + +static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) +{ + int i; + for (i=0; i < num_entries; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + pal[i][3] = transp == i ? 0 : 255; + } +} + +static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) +{ + stbi_uc version; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') + return stbi__err("not GIF", "Corrupt GIF"); + + version = stbi__get8(s); + if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); + if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); + + stbi__g_failure_reason = ""; + g->w = stbi__get16le(s); + g->h = stbi__get16le(s); + g->flags = stbi__get8(s); + g->bgindex = stbi__get8(s); + g->ratio = stbi__get8(s); + g->transparent = -1; + + if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments + + if (is_info) return 1; + + if (g->flags & 0x80) + stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); + + return 1; +} + +static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__gif g; + if (!stbi__gif_header(s, &g, comp, 1)) { + stbi__rewind( s ); + return 0; + } + if (x) *x = g.w; + if (y) *y = g.h; + return 1; +} + +static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) +{ + stbi_uc *p, *c; + + // recurse to decode the prefixes, since the linked-list is backwards, + // and working backwards through an interleaved image would be nasty + if (g->codes[code].prefix >= 0) + stbi__out_gif_code(g, g->codes[code].prefix); + + if (g->cur_y >= g->max_y) return; + + p = &g->out[g->cur_x + g->cur_y]; + c = &g->color_table[g->codes[code].suffix * 4]; + + if (c[3] >= 128) { + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = c[3]; + } + g->cur_x += 4; + + if (g->cur_x >= g->max_x) { + g->cur_x = g->start_x; + g->cur_y += g->step; + + while (g->cur_y >= g->max_y && g->parse > 0) { + g->step = (1 << g->parse) * g->line_size; + g->cur_y = g->start_y + (g->step >> 1); + --g->parse; + } + } +} + +static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) +{ + stbi_uc lzw_cs; + stbi__int32 len, init_code; + stbi__uint32 first; + stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; + stbi__gif_lzw *p; + + lzw_cs = stbi__get8(s); + if (lzw_cs > 12) return NULL; + clear = 1 << lzw_cs; + first = 1; + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + bits = 0; + valid_bits = 0; + for (init_code = 0; init_code < clear; init_code++) { + g->codes[init_code].prefix = -1; + g->codes[init_code].first = (stbi_uc) init_code; + g->codes[init_code].suffix = (stbi_uc) init_code; + } + + // support no starting clear code + avail = clear+2; + oldcode = -1; + + len = 0; + for(;;) { + if (valid_bits < codesize) { + if (len == 0) { + len = stbi__get8(s); // start new block + if (len == 0) + return g->out; + } + --len; + bits |= (stbi__int32) stbi__get8(s) << valid_bits; + valid_bits += 8; + } else { + stbi__int32 code = bits & codemask; + bits >>= codesize; + valid_bits -= codesize; + // @OPTIMIZE: is there some way we can accelerate the non-clear path? + if (code == clear) { // clear code + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + avail = clear + 2; + oldcode = -1; + first = 0; + } else if (code == clear + 1) { // end of stream code + stbi__skip(s, len); + while ((len = stbi__get8(s)) > 0) + stbi__skip(s,len); + return g->out; + } else if (code <= avail) { + if (first) return stbi__errpuc("no clear code", "Corrupt GIF"); + + if (oldcode >= 0) { + p = &g->codes[avail++]; + if (avail > 4096) return stbi__errpuc("too many codes", "Corrupt GIF"); + p->prefix = (stbi__int16) oldcode; + p->first = g->codes[oldcode].first; + p->suffix = (code == avail) ? p->first : g->codes[code].first; + } else if (code == avail) + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + + stbi__out_gif_code(g, (stbi__uint16) code); + + if ((avail & codemask) == 0 && avail <= 0x0FFF) { + codesize++; + codemask = (1 << codesize) - 1; + } + + oldcode = code; + } else { + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + } + } + } +} + +static void stbi__fill_gif_background(stbi__gif *g, int x0, int y0, int x1, int y1) +{ + int x, y; + stbi_uc *c = g->pal[g->bgindex]; + for (y = y0; y < y1; y += 4 * g->w) { + for (x = x0; x < x1; x += 4) { + stbi_uc *p = &g->out[y + x]; + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = 0; + } + } +} + +// this function is designed to support animated gifs, although stb_image doesn't support it +static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp) +{ + int i; + stbi_uc *prev_out = 0; + + if (g->out == 0 && !stbi__gif_header(s, g, comp,0)) + return 0; // stbi__g_failure_reason set by stbi__gif_header + + prev_out = g->out; + g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h); + if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory"); + + switch ((g->eflags & 0x1C) >> 2) { + case 0: // unspecified (also always used on 1st frame) + stbi__fill_gif_background(g, 0, 0, 4 * g->w, 4 * g->w * g->h); + break; + case 1: // do not dispose + if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h); + g->old_out = prev_out; + break; + case 2: // dispose to background + if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h); + stbi__fill_gif_background(g, g->start_x, g->start_y, g->max_x, g->max_y); + break; + case 3: // dispose to previous + if (g->old_out) { + for (i = g->start_y; i < g->max_y; i += 4 * g->w) + memcpy(&g->out[i + g->start_x], &g->old_out[i + g->start_x], g->max_x - g->start_x); + } + break; + } + + for (;;) { + switch (stbi__get8(s)) { + case 0x2C: /* Image Descriptor */ + { + int prev_trans = -1; + stbi__int32 x, y, w, h; + stbi_uc *o; + + x = stbi__get16le(s); + y = stbi__get16le(s); + w = stbi__get16le(s); + h = stbi__get16le(s); + if (((x + w) > (g->w)) || ((y + h) > (g->h))) + return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); + + g->line_size = g->w * 4; + g->start_x = x * 4; + g->start_y = y * g->line_size; + g->max_x = g->start_x + w * 4; + g->max_y = g->start_y + h * g->line_size; + g->cur_x = g->start_x; + g->cur_y = g->start_y; + + g->lflags = stbi__get8(s); + + if (g->lflags & 0x40) { + g->step = 8 * g->line_size; // first interlaced spacing + g->parse = 3; + } else { + g->step = g->line_size; + g->parse = 0; + } + + if (g->lflags & 0x80) { + stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); + g->color_table = (stbi_uc *) g->lpal; + } else if (g->flags & 0x80) { + if (g->transparent >= 0 && (g->eflags & 0x01)) { + prev_trans = g->pal[g->transparent][3]; + g->pal[g->transparent][3] = 0; + } + g->color_table = (stbi_uc *) g->pal; + } else + return stbi__errpuc("missing color table", "Corrupt GIF"); + + o = stbi__process_gif_raster(s, g); + if (o == NULL) return NULL; + + if (prev_trans != -1) + g->pal[g->transparent][3] = (stbi_uc) prev_trans; + + return o; + } + + case 0x21: // Comment Extension. + { + int len; + if (stbi__get8(s) == 0xF9) { // Graphic Control Extension. + len = stbi__get8(s); + if (len == 4) { + g->eflags = stbi__get8(s); + g->delay = stbi__get16le(s); + g->transparent = stbi__get8(s); + } else { + stbi__skip(s, len); + break; + } + } + while ((len = stbi__get8(s)) != 0) + stbi__skip(s, len); + break; + } + + case 0x3B: // gif stream termination code + return (stbi_uc *) s; // using '1' causes warning on some compilers + + default: + return stbi__errpuc("unknown code", "Corrupt GIF"); + } + } + + STBI_NOTUSED(req_comp); +} + +static stbi_uc *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi_uc *u = 0; + stbi__gif g; + memset(&g, 0, sizeof(g)); + + u = stbi__gif_load_next(s, &g, comp, req_comp); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + if (u) { + *x = g.w; + *y = g.h; + if (req_comp && req_comp != 4) + u = stbi__convert_format(u, 4, req_comp, g.w, g.h); + } + else if (g.out) + STBI_FREE(g.out); + + return u; +} + +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) +{ + return stbi__gif_info_raw(s,x,y,comp); +} +#endif + +// ************************************************************************************************* +// Radiance RGBE HDR loader +// originally by Nicolas Schulz +#ifndef STBI_NO_HDR +static int stbi__hdr_test_core(stbi__context *s) +{ + const char *signature = "#?RADIANCE\n"; + int i; + for (i=0; signature[i]; ++i) + if (stbi__get8(s) != signature[i]) + return 0; + return 1; +} + +static int stbi__hdr_test(stbi__context* s) +{ + int r = stbi__hdr_test_core(s); + stbi__rewind(s); + return r; +} + +#define STBI__HDR_BUFLEN 1024 +static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) +{ + int len=0; + char c = '\0'; + + c = (char) stbi__get8(z); + + while (!stbi__at_eof(z) && c != '\n') { + buffer[len++] = c; + if (len == STBI__HDR_BUFLEN-1) { + // flush to end of line + while (!stbi__at_eof(z) && stbi__get8(z) != '\n') + ; + break; + } + c = (char) stbi__get8(z); + } + + buffer[len] = 0; + return buffer; +} + +static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) +{ + if ( input[3] != 0 ) { + float f1; + // Exponent + f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); + if (req_comp <= 2) + output[0] = (input[0] + input[1] + input[2]) * f1 / 3; + else { + output[0] = input[0] * f1; + output[1] = input[1] * f1; + output[2] = input[2] * f1; + } + if (req_comp == 2) output[1] = 1; + if (req_comp == 4) output[3] = 1; + } else { + switch (req_comp) { + case 4: output[3] = 1; /* fallthrough */ + case 3: output[0] = output[1] = output[2] = 0; + break; + case 2: output[1] = 1; /* fallthrough */ + case 1: output[0] = 0; + break; + } + } +} + +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int width, height; + stbi_uc *scanline; + float *hdr_data; + int len; + unsigned char count, value; + int i, j, k, c1,c2, z; + + + // Check identifier + if (strcmp(stbi__hdr_gettoken(s,buffer), "#?RADIANCE") != 0) + return stbi__errpf("not HDR", "Corrupt HDR image"); + + // Parse header + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format"); + + // Parse width and height + // can't use sscanf() if we're not using stdio! + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + height = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + width = (int) strtol(token, NULL, 10); + + *x = width; + *y = height; + + if (comp) *comp = 3; + if (req_comp == 0) req_comp = 3; + + // Read data + hdr_data = (float *) stbi__malloc(height * width * req_comp * sizeof(float)); + + // Load image data + // image data is stored as some number of sca + if ( width < 8 || width >= 32768) { + // Read flat data + for (j=0; j < height; ++j) { + for (i=0; i < width; ++i) { + stbi_uc rgbe[4]; + main_decode_loop: + stbi__getn(s, rgbe, 4); + stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); + } + } + } else { + // Read RLE-encoded data + scanline = NULL; + + for (j = 0; j < height; ++j) { + c1 = stbi__get8(s); + c2 = stbi__get8(s); + len = stbi__get8(s); + if (c1 != 2 || c2 != 2 || (len & 0x80)) { + // not run-length encoded, so we have to actually use THIS data as a decoded + // pixel (note this can't be a valid pixel--one of RGB must be >= 128) + stbi_uc rgbe[4]; + rgbe[0] = (stbi_uc) c1; + rgbe[1] = (stbi_uc) c2; + rgbe[2] = (stbi_uc) len; + rgbe[3] = (stbi_uc) stbi__get8(s); + stbi__hdr_convert(hdr_data, rgbe, req_comp); + i = 1; + j = 0; + STBI_FREE(scanline); + goto main_decode_loop; // yes, this makes no sense + } + len <<= 8; + len |= stbi__get8(s); + if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } + if (scanline == NULL) scanline = (stbi_uc *) stbi__malloc(width * 4); + + for (k = 0; k < 4; ++k) { + i = 0; + while (i < width) { + count = stbi__get8(s); + if (count > 128) { + // Run + value = stbi__get8(s); + count -= 128; + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = value; + } else { + // Dump + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = stbi__get8(s); + } + } + } + for (i=0; i < width; ++i) + stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); + } + STBI_FREE(scanline); + } + + return hdr_data; +} + +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + + if (strcmp(stbi__hdr_gettoken(s,buffer), "#?RADIANCE") != 0) { + stbi__rewind( s ); + return 0; + } + + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) { + stbi__rewind( s ); + return 0; + } + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *y = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *x = (int) strtol(token, NULL, 10); + *comp = 3; + return 1; +} +#endif // STBI_NO_HDR + +#ifndef STBI_NO_BMP +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) +{ + int hsz; + if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') { + stbi__rewind( s ); + return 0; + } + stbi__skip(s,12); + hsz = stbi__get32le(s); + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) { + stbi__rewind( s ); + return 0; + } + if (hsz == 12) { + *x = stbi__get16le(s); + *y = stbi__get16le(s); + } else { + *x = stbi__get32le(s); + *y = stbi__get32le(s); + } + if (stbi__get16le(s) != 1) { + stbi__rewind( s ); + return 0; + } + *comp = stbi__get16le(s) / 8; + return 1; +} +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) +{ + int channelCount; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + *y = stbi__get32be(s); + *x = stbi__get32be(s); + if (stbi__get16be(s) != 8) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 3) { + stbi__rewind( s ); + return 0; + } + *comp = 4; + return 1; +} +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) +{ + int act_comp=0,num_packets=0,chained; + stbi__pic_packet packets[10]; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) { + stbi__rewind(s); + return 0; + } + + stbi__skip(s, 88); + + *x = stbi__get16be(s); + *y = stbi__get16be(s); + if (stbi__at_eof(s)) { + stbi__rewind( s); + return 0; + } + if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { + stbi__rewind( s ); + return 0; + } + + stbi__skip(s, 8); + + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return 0; + + packet = &packets[num_packets++]; + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + act_comp |= packet->channel; + + if (stbi__at_eof(s)) { + stbi__rewind( s ); + return 0; + } + if (packet->size != 8) { + stbi__rewind( s ); + return 0; + } + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); + + return 1; +} +#endif + +// ************************************************************************************************* +// Portable Gray Map and Portable Pixel Map loader +// by Ken Miller +// +// PGM: http://netpbm.sourceforge.net/doc/pgm.html +// PPM: http://netpbm.sourceforge.net/doc/ppm.html +// +// Known limitations: +// Does not support comments in the header section +// Does not support ASCII image data (formats P2 and P3) +// Does not support 16-bit-per-channel + +#ifndef STBI_NO_PNM + +static int stbi__pnm_test(stbi__context *s) +{ + char p, t; + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind( s ); + return 0; + } + return 1; +} + +static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi_uc *out; + if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) + return 0; + *x = s->img_x; + *y = s->img_y; + *comp = s->img_n; + + out = (stbi_uc *) stbi__malloc(s->img_n * s->img_x * s->img_y); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + stbi__getn(s, out, s->img_n * s->img_x * s->img_y); + + if (req_comp && req_comp != s->img_n) { + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + return out; +} + +static int stbi__pnm_isspace(char c) +{ + return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; +} + +static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) +{ + while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) + *c = (char) stbi__get8(s); +} + +static int stbi__pnm_isdigit(char c) +{ + return c >= '0' && c <= '9'; +} + +static int stbi__pnm_getinteger(stbi__context *s, char *c) +{ + int value = 0; + + while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { + value = value*10 + (*c - '0'); + *c = (char) stbi__get8(s); + } + + return value; +} + +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) +{ + int maxv; + char c, p, t; + + stbi__rewind( s ); + + // Get identifier + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind( s ); + return 0; + } + + *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm + + c = (char) stbi__get8(s); + stbi__pnm_skip_whitespace(s, &c); + + *x = stbi__pnm_getinteger(s, &c); // read width + stbi__pnm_skip_whitespace(s, &c); + + *y = stbi__pnm_getinteger(s, &c); // read height + stbi__pnm_skip_whitespace(s, &c); + + maxv = stbi__pnm_getinteger(s, &c); // read max value + + if (maxv > 255) + return stbi__err("max value > 255", "PPM image not 8-bit"); + else + return 1; +} +#endif + +static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) +{ + #ifndef STBI_NO_JPEG + if (stbi__jpeg_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNG + if (stbi__png_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_GIF + if (stbi__gif_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_BMP + if (stbi__bmp_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PIC + if (stbi__pic_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNM + if (stbi__pnm_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_info(s, x, y, comp)) return 1; + #endif + + // test tga last because it's a crappy test! + #ifndef STBI_NO_TGA + if (stbi__tga_info(s, x, y, comp)) + return 1; + #endif + return stbi__err("unknown image type", "Image not of any known type, or corrupt"); +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_info_from_file(f, x, y, comp); + fclose(f); + return result; +} + +STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__info_main(&s,x,y,comp); + fseek(f,pos,SEEK_SET); + return r; +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__info_main(&s,x,y,comp); +} + +#endif // STB_IMAGE_IMPLEMENTATION + +/* + revision history: + 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA + 2.07 (2015-09-13) fix compiler warnings + partial animated GIF support + limited 16-bit PSD support + #ifdef unused functions + bug with < 92 byte PIC,PNM,HDR,TGA + 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value + 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning + 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit + 2.03 (2015-04-12) extra corruption checking (mmozeiko) + stbi_set_flip_vertically_on_load (nguillemot) + fix NEON support; fix mingw support + 2.02 (2015-01-19) fix incorrect assert, fix warning + 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 + 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG + 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) + progressive JPEG (stb) + PGM/PPM support (Ken Miller) + STBI_MALLOC,STBI_REALLOC,STBI_FREE + GIF bugfix -- seemingly never worked + STBI_NO_*, STBI_ONLY_* + 1.48 (2014-12-14) fix incorrectly-named assert() + 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) + optimize PNG (ryg) + fix bug in interlaced PNG with user-specified channel count (stb) + 1.46 (2014-08-26) + fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG + 1.45 (2014-08-16) + fix MSVC-ARM internal compiler error by wrapping malloc + 1.44 (2014-08-07) + various warning fixes from Ronny Chevalier + 1.43 (2014-07-15) + fix MSVC-only compiler problem in code changed in 1.42 + 1.42 (2014-07-09) + don't define _CRT_SECURE_NO_WARNINGS (affects user code) + fixes to stbi__cleanup_jpeg path + added STBI_ASSERT to avoid requiring assert.h + 1.41 (2014-06-25) + fix search&replace from 1.36 that messed up comments/error messages + 1.40 (2014-06-22) + fix gcc struct-initialization warning + 1.39 (2014-06-15) + fix to TGA optimization when req_comp != number of components in TGA; + fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) + add support for BMP version 5 (more ignored fields) + 1.38 (2014-06-06) + suppress MSVC warnings on integer casts truncating values + fix accidental rename of 'skip' field of I/O + 1.37 (2014-06-04) + remove duplicate typedef + 1.36 (2014-06-03) + convert to header file single-file library + if de-iphone isn't set, load iphone images color-swapped instead of returning NULL + 1.35 (2014-05-27) + various warnings + fix broken STBI_SIMD path + fix bug where stbi_load_from_file no longer left file pointer in correct place + fix broken non-easy path for 32-bit BMP (possibly never used) + TGA optimization by Arseny Kapoulkine + 1.34 (unknown) + use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case + 1.33 (2011-07-14) + make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements + 1.32 (2011-07-13) + support for "info" function for all supported filetypes (SpartanJ) + 1.31 (2011-06-20) + a few more leak fixes, bug in PNG handling (SpartanJ) + 1.30 (2011-06-11) + added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) + removed deprecated format-specific test/load functions + removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway + error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) + fix inefficiency in decoding 32-bit BMP (David Woo) + 1.29 (2010-08-16) + various warning fixes from Aurelien Pocheville + 1.28 (2010-08-01) + fix bug in GIF palette transparency (SpartanJ) + 1.27 (2010-08-01) + cast-to-stbi_uc to fix warnings + 1.26 (2010-07-24) + fix bug in file buffering for PNG reported by SpartanJ + 1.25 (2010-07-17) + refix trans_data warning (Won Chun) + 1.24 (2010-07-12) + perf improvements reading from files on platforms with lock-heavy fgetc() + minor perf improvements for jpeg + deprecated type-specific functions so we'll get feedback if they're needed + attempt to fix trans_data warning (Won Chun) + 1.23 fixed bug in iPhone support + 1.22 (2010-07-10) + removed image *writing* support + stbi_info support from Jetro Lauha + GIF support from Jean-Marc Lienher + iPhone PNG-extensions from James Brown + warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) + 1.21 fix use of 'stbi_uc' in header (reported by jon blow) + 1.20 added support for Softimage PIC, by Tom Seddon + 1.19 bug in interlaced PNG corruption check (found by ryg) + 1.18 (2008-08-02) + fix a threading bug (local mutable static) + 1.17 support interlaced PNG + 1.16 major bugfix - stbi__convert_format converted one too many pixels + 1.15 initialize some fields for thread safety + 1.14 fix threadsafe conversion bug + header-file-only version (#define STBI_HEADER_FILE_ONLY before including) + 1.13 threadsafe + 1.12 const qualifiers in the API + 1.11 Support installable IDCT, colorspace conversion routines + 1.10 Fixes for 64-bit (don't use "unsigned long") + optimized upsampling by Fabian "ryg" Giesen + 1.09 Fix format-conversion for PSD code (bad global variables!) + 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz + 1.07 attempt to fix C++ warning/errors again + 1.06 attempt to fix C++ warning/errors again + 1.05 fix TGA loading to return correct *comp and use good luminance calc + 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free + 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR + 1.02 support for (subset of) HDR files, float interface for preferred access to them + 1.01 fix bug: possible bug in handling right-side up bmps... not sure + fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all + 1.00 interface to zlib that skips zlib header + 0.99 correct handling of alpha in palette + 0.98 TGA loader by lonesock; dynamically add loaders (untested) + 0.97 jpeg errors on too large a file; also catch another malloc failure + 0.96 fix detection of invalid v value - particleman@mollyrocket forum + 0.95 during header scan, seek to markers in case of padding + 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same + 0.93 handle jpegtran output; verbose errors + 0.92 read 4,8,16,24,32-bit BMP files of several formats + 0.91 output 24-bit Windows 3.0 BMP files + 0.90 fix a few more warnings; bump version number to approach 1.0 + 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd + 0.60 fix compiling as c++ + 0.59 fix warnings: merge Dave Moore's -Wall fixes + 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian + 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available + 0.56 fix bug: zlib uncompressed mode len vs. nlen + 0.55 fix bug: restart_interval not initialized to 0 + 0.54 allow NULL for 'int *comp' + 0.53 fix bug in png 3->4; speedup png decoding + 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments + 0.51 obey req_comp requests, 1-component jpegs return as 1-component, + on 'test' only check type, not whether we support this variant + 0.50 (2006-11-19) + first released version +*/ diff --git a/test.cc b/test.cc new file mode 100644 index 0000000..8b3bfd1 --- /dev/null +++ b/test.cc @@ -0,0 +1,314 @@ +#define TINYGLTF_LOADER_IMPLEMENTATION +#define STB_IMAGE_IMPLEMENTATION +#include "tiny_gltf_loader.h" + +#include +#include +#include + +std::string PrintMode(int mode) +{ + if (mode == TINYGLTF_MODE_POINTS) { + return "POINTS"; + } else if (mode == TINYGLTF_MODE_LINE) { + return "LINE"; + } else if (mode == TINYGLTF_MODE_LINE_LOOP) { + return "LINE_LOOP"; + } else if (mode == TINYGLTF_MODE_TRIANGLES) { + return "TRIANGLES"; + } else if (mode == TINYGLTF_MODE_TRIANGLE_FAN) { + return "TRIANGLE_FAN"; + } else if (mode == TINYGLTF_MODE_TRIANGLE_STRIP) { + return "TRIANGLE_STRIP"; + } + return "**UNKNOWN**"; +} + + +std::string PrintType(int ty) +{ + if (ty == TINYGLTF_TYPE_SCALAR) { + return "SCALAR"; + } else if (ty == TINYGLTF_TYPE_VECTOR) { + return "VECTOR"; + } else if (ty == TINYGLTF_TYPE_VEC2) { + return "VEC2"; + } else if (ty == TINYGLTF_TYPE_VEC3) { + return "VEC3"; + } else if (ty == TINYGLTF_TYPE_VEC4) { + return "VEC4"; + } else if (ty == TINYGLTF_TYPE_MATRIX) { + return "MATRIX"; + } else if (ty == TINYGLTF_TYPE_MAT2) { + return "MAT2"; + } else if (ty == TINYGLTF_TYPE_MAT3) { + return "MAT3"; + } else if (ty == TINYGLTF_TYPE_MAT4) { + return "MAT4"; + } + return "**UNKNOWN**"; +} + +std::string PrintComponentType(int ty) +{ + if (ty == TINYGLTF_COMPONENT_TYPE_BYTE) { + return "BYTE"; + } else if (ty == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) { + return "UNSIGNED_BYTE"; + } else if (ty == TINYGLTF_COMPONENT_TYPE_SHORT) { + return "SHORT"; + } else if (ty == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) { + return "UNSIGNED_SHORT"; + } else if (ty == TINYGLTF_COMPONENT_TYPE_INT) { + return "INT"; + } else if (ty == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT) { + return "UNSIGNED_INT"; + } else if (ty == TINYGLTF_COMPONENT_TYPE_FLOAT) { + return "FLOAT"; + } else if (ty == TINYGLTF_COMPONENT_TYPE_DOUBLE) { + return "DOUBLE"; + } + + return "**UNKNOWN**"; +} + +std::string PrintFloatArray(const std::vector& arr) +{ + if (arr.size() == 0) { + return ""; + } + + std::stringstream ss; + ss << "[ "; + for (size_t i = 0; i < arr.size(); i++) { + ss << arr[i] << ((i != arr.size() - 1) ? ", " : ""); + } + ss << " ]"; + + return ss.str(); +} + +std::string PrintStringArray(const std::vector& arr) +{ + if (arr.size() == 0) { + return ""; + } + + std::stringstream ss; + ss << "[ "; + for (size_t i = 0; i < arr.size(); i++) { + ss << arr[i] << ((i != arr.size() - 1) ? ", " : ""); + } + ss << " ]"; + + return ss.str(); +} + + +std::string Indent(int indent) +{ + std::string s; + for (int i = 0; i < indent; i++) { + s += " "; + } + + return s; +} + +void DumpNode(const Node& node, int indent) +{ + std::cout << Indent(indent) << "name : " << node.name << std::endl; + std::cout << Indent(indent) << "camera : " << node.camera << std::endl; + if (!node.rotation.empty()) { + std::cout << Indent(indent) << "rotation : " << PrintFloatArray(node.rotation) << std::endl; + } + if (!node.scale.empty()) { + std::cout << Indent(indent) << "scale : " << PrintFloatArray(node.scale) << std::endl; + } + if (!node.translation.empty()) { + std::cout << Indent(indent) << "translation : " << PrintFloatArray(node.translation) << std::endl; + } + + if (!node.matrix.empty()) { + std::cout << Indent(indent) << "matrix : " << PrintFloatArray(node.matrix) << std::endl; + } + + std::cout << Indent(indent) << "meshes : " << PrintStringArray(node.meshes) << std::endl; + + std::cout << Indent(indent) << "children : " << PrintStringArray(node.children) << std::endl; + +} + +void DumpPrimitive(const Primitive& primitive, int indent) +{ + std::cout << Indent(indent) << "material : " << primitive.material << std::endl; + std::cout << Indent(indent) << "mode : " << PrintMode(primitive.mode) << "(" << primitive.mode << ")" << std::endl; + std::cout << Indent(indent) << "attributes(items=" << primitive.attributes.size() << ")" << std::endl; + std::map::const_iterator it(primitive.attributes.begin()); + std::map::const_iterator itEnd(primitive.attributes.end()); + for (; it != itEnd; it++) { + std::cout << Indent(indent + 1) << it->first << ": " << it->second << std::endl; + } + +} + +void Dump(const Scene& scene) +{ + std::cout << "=== Dump glTF ===" << std::endl; + std::cout << "asset.generator : " << scene.asset.generator << std::endl; + std::cout << "asset.premultipliedAlpha : " << scene.asset.premultipliedAlpha << std::endl; + std::cout << "asset.version : " << scene.asset.version << std::endl; + std::cout << "asset.profile.api : " << scene.asset.profile_api << std::endl; + std::cout << "asset.profile.version : " << scene.asset.profile_version << std::endl; + std::cout << std::endl; + std::cout << "=== Dump scene ===" << std::endl; + std::cout << "defaultScene: " << scene.defaultScene << std::endl; + + { + std::map >::const_iterator it(scene.scenes.begin()); + std::map >::const_iterator itEnd(scene.scenes.end()); + std::cout << "scenes(items=" << scene.scenes.size() << ")" << std::endl; + for (; it != itEnd; it++) { + std::cout << Indent(1) << "name : " << it->first << std::endl; + std::cout << Indent(2) << "nodes : [ "; + for (size_t i = 0; i < it->second.size(); i++) { + std::cout << it->second[i] << ((i != it->second.size()) ? ", " : ""); + } + std::cout << " ] " << std::endl; + } + } + + { + std::map::const_iterator it(scene.meshes.begin()); + std::map::const_iterator itEnd(scene.meshes.end()); + std::cout << "meshes(item=" << scene.meshes.size() << ")" << std::endl; + for (; it != itEnd; it++) { + std::cout << Indent(1) << "name : " << it->second.name << std::endl; + std::cout << Indent(1) << "primitives(items=" << it->second.primitives.size() << "): " << std::endl; + + for (size_t i = 0; i < it->second.primitives.size(); i++) { + DumpPrimitive(it->second.primitives[i], 2); + } + } + } + + { + std::map::const_iterator it(scene.accessors.begin()); + std::map::const_iterator itEnd(scene.accessors.end()); + std::cout << "accessos(items=" << scene.accessors.size() << ")" << std::endl; + for (; it != itEnd; it++) { + std::cout << Indent(1) << "name : " << it->first << std::endl; + std::cout << Indent(2) << "bufferView : " << it->second.bufferView << std::endl; + std::cout << Indent(2) << "byteOffset : " << it->second.byteOffset << std::endl; + std::cout << Indent(2) << "byteStride : " << it->second.byteStride << std::endl; + std::cout << Indent(2) << "componentType: " << PrintComponentType(it->second.componentType) << "(" << it->second.componentType << ")" << std::endl; + std::cout << Indent(2) << "count : " << it->second.count << std::endl; + std::cout << Indent(2) << "type : " << PrintType(it->second.type) << std::endl; + if (!it->second.minValues.empty()) { + std::cout << Indent(2) << "min : ["; + for (size_t i = 0; i < it->second.minValues.size(); i++) { + std::cout << it->second.minValues[i] << ((i != it->second.minValues.size()-1) ? ", " : ""); + } + std::cout << "]" << std::endl; + } + if (!it->second.maxValues.empty()) { + std::cout << Indent(2) << "max : ["; + for (size_t i = 0; i < it->second.maxValues.size(); i++) { + std::cout << it->second.maxValues[i] << ((i != it->second.maxValues.size()-1) ? ", " : ""); + } + std::cout << "]" << std::endl; + } + } + } + + { + std::map::const_iterator it(scene.bufferViews.begin()); + std::map::const_iterator itEnd(scene.bufferViews.end()); + std::cout << "bufferViews(items=" << scene.bufferViews.size() << ")" << std::endl; + for (; it != itEnd; it++) { + std::cout << Indent(1) << "name : " << it->first << std::endl; + std::cout << Indent(2) << "buffer : " << it->second.buffer << std::endl; + std::cout << Indent(2) << "byteLength : " << it->second.byteLength << std::endl; + std::cout << Indent(2) << "byteOffset : " << it->second.byteOffset << std::endl; + } + } + + { + std::map::const_iterator it(scene.buffers.begin()); + std::map::const_iterator itEnd(scene.buffers.end()); + std::cout << "buffers(items=" << scene.buffers.size() << ")" << std::endl; + for (; it != itEnd; it++) { + std::cout << Indent(1) << "name : " << it->first << std::endl; + std::cout << Indent(2) << "byteLength : " << it->second.data.size() << std::endl; + } + } + + { + std::map::const_iterator it(scene.materials.begin()); + std::map::const_iterator itEnd(scene.materials.end()); + std::cout << "materials(items=" << scene.materials.size() << ")" << std::endl; + for (; it != itEnd; it++) { + std::cout << Indent(1) << "name : " << it->first << std::endl; + std::cout << Indent(1) << "technique : " << it->second.technique << std::endl; + std::cout << Indent(1) << "values(items=" << it->second.values.size() << std::endl; + + FloatParameterMap::const_iterator p(it->second.values.begin()); + FloatParameterMap::const_iterator pEnd(it->second.values.end()); + for (; p != pEnd; p++) { + std::cout << Indent(3) << p->first << PrintFloatArray(p->second) << std::endl; + } + } + } + + { + std::map::const_iterator it(scene.nodes.begin()); + std::map::const_iterator itEnd(scene.nodes.end()); + std::cout << "nodes(items=" << scene.nodes.size() << ")" << std::endl; + for (; it != itEnd; it++) { + std::cout << Indent(1) << "name : " << it->first << std::endl; + + DumpNode(it->second, 2); + } + } + + { + std::map::const_iterator it(scene.images.begin()); + std::map::const_iterator itEnd(scene.images.end()); + std::cout << "images(items=" << scene.images.size() << ")" << std::endl; + for (; it != itEnd; it++) { + std::cout << Indent(1) << "name : " << it->first << std::endl; + + std::cout << Indent(2) << "width : " << it->second.width << std::endl; + std::cout << Indent(2) << "height : " << it->second.height << std::endl; + std::cout << Indent(2) << "component : " << it->second.component << std::endl; + std::cout << Indent(2) << "name : " << it->second.name << std::endl; + } + } +} + +int main(int argc, char** argv) +{ + if (argc < 2) { + printf("Needs input.gltf\n"); + exit(1); + } + + Scene scene; + TinyGLTFLoader loader; + std::string err; + + bool ret = loader.LoadFromFile(scene, err, argv[1]); + + if (!err.empty()) { + printf("Err: %s\n", err.c_str()); + } + + if (!ret) { + printf("Failed to parse glTF\n"); + return -1; + } + + Dump(scene); + + return 0; +} diff --git a/tiny_gltf_loader.h b/tiny_gltf_loader.h new file mode 100644 index 0000000..c9ecd0c --- /dev/null +++ b/tiny_gltf_loader.h @@ -0,0 +1,1262 @@ +// +// Tiny glTF loader. +// +// Copyright (c) 2015, Syoyo Fujita. +// All rights reserved. +// (Licensed under 2-clause BSD liecense) +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this +// list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +// FOR +// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// +// Version: +// - v0.9.0 Initial +// +// Tiny glTF loader is using following libraries: +// +// - picojson: C++ JSON library. +// - base64: base64 decode/encode library. +// - stb_image: Image loading library. +// +#ifndef TINY_GLTF_LOADER_H +#define TINY_GLTF_LOADER_H + +#include +#include +#include + +namespace tinygltf { + +#define TINYGLTF_MODE_POINTS (0) +#define TINYGLTF_MODE_LINE (1) +#define TINYGLTF_MODE_LINE_LOOP (2) +#define TINYGLTF_MODE_TRIANGLES (4) +#define TINYGLTF_MODE_TRIANGLE_STRIP (5) +#define TINYGLTF_MODE_TRIANGLE_FAN (6) + +#define TINYGLTF_COMPONENT_TYPE_BYTE (5120) +#define TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE (5121) +#define TINYGLTF_COMPONENT_TYPE_SHORT (5122) +#define TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT (5123) +#define TINYGLTF_COMPONENT_TYPE_INT (5124) +#define TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT (5125) +#define TINYGLTF_COMPONENT_TYPE_FLOAT (5126) +#define TINYGLTF_COMPONENT_TYPE_DOUBLE (5127) + +#define TINYGLTF_TYPE_VEC2 (2) +#define TINYGLTF_TYPE_VEC3 (3) +#define TINYGLTF_TYPE_VEC4 (4) +#define TINYGLTF_TYPE_MAT2 (32 + 2) +#define TINYGLTF_TYPE_MAT3 (32 + 3) +#define TINYGLTF_TYPE_MAT4 (32 + 4) +#define TINYGLTF_TYPE_SCALAR (64 + 1) +#define TINYGLTF_TYPE_VECTOR (64 + 4) +#define TINYGLTF_TYPE_MATRIX (64 + 16) + +#define TINYGLTF_IMAGE_FORMAT_JPEG (0) +#define TINYGLTF_IMAGE_FORMAT_PNG (1) +#define TINYGLTF_IMAGE_FORMAT_BMP (2) +#define TINYGLTF_IMAGE_FORMAT_GIF (3) + +#define TINYGLTF_TARGET_ARRAY_BUFFER (34962) +#define TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER (34963) + +typedef std::map > FloatParameterMap; + +// LDR 8bit image +typedef struct { + std::string name; + int width; + int height; + int component; + std::vector image; +} Image; + +typedef struct { + std::string name; + std::string technique; + FloatParameterMap values; +} Material; + +typedef struct { + std::string name; + std::string buffer; // Required + size_t byteOffset; // Required + size_t byteLength; // default: 0 + int target; +} BufferView; + +typedef struct { + std::string bufferView; + std::string name; + size_t byteOffset; + size_t byteStride; + int componentType; // One of TINYGLTF_COMPONENT_TYPE_*** + size_t count; + int type; // One of TINYGLTF_TYPE_*** + std::vector minValues; // Optional + std::vector maxValues; // Optional +} Accessor; + +class Camera { +public: + Camera() {} + ~Camera() {} + + std::string name; + bool isOrthographic; // false = perspective. + + // Some common properties. + float aspectRatio; + float yFov; + float zFar; + float zNear; +}; + +typedef struct { + std::map attributes; // A dictionary object of + // strings, where each string + // is the ID of the accessor + // containing an attribute. + std::string material; // The ID of the material to apply to this primitive + // when rendering. + std::string indices; // The ID of the accessor that contains the indices. + int mode; // one of TINYGLTF_MODE_*** +} Primitive; + +typedef struct { + std::string name; + std::vector primitives; +} Mesh; + +class Node { +public: + Node() {} + ~Node() {} + + std::string camera; // camera object referenced by this node. + + std::string name; + std::vector children; + std::vector rotation; // length must be 0 or 4 + std::vector scale; // length must be 0 or 3 + std::vector translation; // length must be 0 or 3 + std::vector matrix; // length must be 0 or 16 + std::vector meshes; +}; + +typedef struct { + std::string name; + std::vector data; +} Buffer; + +typedef struct { + std::string generator; + std::string version; + std::string profile_api; + std::string profile_version; + bool premultipliedAlpha; +} Asset; + +class Scene { +public: + Scene() {} + ~Scene() {} + + std::map accessors; + std::map buffers; + std::map bufferViews; + std::map materials; + std::map meshes; + std::map nodes; + std::map images; + std::map > scenes; // list of nodes + + std::string defaultScene; + + Asset asset; +}; + +class TinyGLTFLoader { +public: + TinyGLTFLoader(){}; + ~TinyGLTFLoader(){}; + + /// Loads GLTF asset from a file. + /// Returns false and set error string to `err` if there's and parsing error. + bool LoadFromFile(Scene &scene, std::string &err, + const std::string &filename); +}; + +} // namespace tinygltf + +#ifdef TINYGLTF_LOADER_IMPLEMENTATION +#include +#include +#include + +#include "picojson.h" +#include "stb_image.h" + +#ifdef _WIN32 +#include +#else +#include +#endif + +using namespace tinygltf; + +namespace { + +bool FileExists(const std::string &abs_filename) { + bool ret; + FILE *fp = fopen(abs_filename.c_str(), "rb"); + if (fp) { + ret = true; + fclose(fp); + } else { + ret = false; + } + + return ret; +} + +std::string ExpandFilePath(const std::string &filepath) { +#ifdef _WIN32 + DWORD len = ExpandEnvironmentStringsA(filepath.c_str(), NULL, 0); + char *str = new char[len]; + ExpandEnvironmentStringsA(filepath.c_str(), str, len); + + std::string s(str); + + delete[] str; + + return s; +#else + +#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR + // no expansion + std::string s = filepath; +#else + std::string s; + wordexp_t p; + + if (filepath.empty()) { + return ""; + } + + // char** w; + int ret = wordexp(filepath.c_str(), &p, 0); + if (ret) { + // err + s = filepath; + return s; + } + + // Use first element only. + if (p.we_wordv) { + s = std::string(p.we_wordv[0]); + wordfree(&p); + } else { + s = filepath; + } + +#endif + + return s; +#endif +} + +std::string JoinPath(const std::string &path0, const std::string &path1) { + if (path0.empty()) { + return path1; + } else { + // check '/' + char lastChar = *path0.rbegin(); + if (lastChar != '/') { + return path0 + std::string("/") + path1; + } else { + return path0 + path1; + } + } +} + +std::string FindFile(const std::vector &paths, + const std::string &filepath) { + for (size_t i = 0; i < paths.size(); i++) { + std::string absPath = ExpandFilePath(JoinPath(paths[i], filepath)); + if (FileExists(absPath)) { + return absPath; + } + } + + return std::string(); +} + +// std::string GetFilePathExtension(const std::string& FileName) +//{ +// if(FileName.find_last_of(".") != std::string::npos) +// return FileName.substr(FileName.find_last_of(".")+1); +// return ""; +//} + +std::string GetBaseDir(const std::string &filepath) { + if (filepath.find_last_of("/\\") != std::string::npos) + return filepath.substr(0, filepath.find_last_of("/\\")); + return ""; +} + +// std::string base64_encode(unsigned char const* , unsigned int len); +std::string base64_decode(std::string const &s); + +/* + base64.cpp and base64.h + + Copyright (C) 2004-2008 René Nyffenegger + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + + 3. This notice may not be removed or altered from any source distribution. + + René Nyffenegger rene.nyffenegger@adp-gmbh.ch + +*/ + +//#include "base64.h" +//#include + +static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + +static inline bool is_base64(unsigned char c) { + return (isalnum(c) || (c == '+') || (c == '/')); +} + +#if 0 +std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) { + std::string ret; + int i = 0; + int j = 0; + unsigned char char_array_3[3]; + unsigned char char_array_4[4]; + + while (in_len--) { + char_array_3[i++] = *(bytes_to_encode++); + if (i == 3) { + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for(i = 0; (i <4) ; i++) + ret += base64_chars[char_array_4[i]]; + i = 0; + } + } + + if (i) + { + for(j = i; j < 3; j++) + char_array_3[j] = '\0'; + + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for (j = 0; (j < i + 1); j++) + ret += base64_chars[char_array_4[j]]; + + while((i++ < 3)) + ret += '='; + + } + + return ret; + +} +#endif + +std::string base64_decode(std::string const &encoded_string) { + int in_len = encoded_string.size(); + int i = 0; + int j = 0; + int in_ = 0; + unsigned char char_array_4[4], char_array_3[3]; + std::string ret; + + while (in_len-- && (encoded_string[in_] != '=') && + is_base64(encoded_string[in_])) { + char_array_4[i++] = encoded_string[in_]; + in_++; + if (i == 4) { + for (i = 0; i < 4; i++) + char_array_4[i] = base64_chars.find(char_array_4[i]); + + char_array_3[0] = + (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = + ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (i = 0; (i < 3); i++) + ret += char_array_3[i]; + i = 0; + } + } + + if (i) { + for (j = i; j < 4; j++) + char_array_4[j] = 0; + + for (j = 0; j < 4; j++) + char_array_4[j] = base64_chars.find(char_array_4[j]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = + ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (j = 0; (j < i - 1); j++) + ret += char_array_3[j]; + } + + return ret; +} + +bool LoadExternalFile(std::vector &out, std::string &err, + const std::string &filename, const std::string &basedir, + size_t reqBytes, bool checkSize) { + out.clear(); + + std::vector paths; + paths.push_back(basedir); + paths.push_back("."); + + std::string filepath = FindFile(paths, filename); + if (filepath.empty()) { + err += "File not found : " + filename; + return false; + } + + std::ifstream f(filepath.c_str(), std::ifstream::binary); + if (!f) { + err += "File open error : " + filepath; + return false; + } + + f.seekg(0, f.end); + size_t sz = f.tellg(); + std::vector buf(sz); + + f.seekg(0, f.beg); + f.read(reinterpret_cast(&buf.at(0)), sz); + f.close(); + + if (checkSize) { + if (reqBytes == sz) { + out.swap(buf); + return true; + } else { + std::stringstream ss; + ss << "File size mismatch : " << filepath << ", requestedBytes " + << reqBytes << ", but got " << sz << std::endl; + err += ss.str(); + return false; + } + } + + out.swap(buf); + return true; +} + +bool IsDataURI(const std::string &in) { + std::string header = "data:application/octet-stream;base64,"; + if (in.find(header) == 0) { + return true; + } + return false; +} + +bool DecodeDataURI(std::vector &out, const std::string &in, + size_t reqBytes, bool checkSize) { + std::string header = "data:application/octet-stream;base64,"; + if (in.find(header) == 0) { + std::string data = + base64_decode(in.substr(header.size())); // cut mime string. + if (checkSize) { + if (data.size() != reqBytes) { + return false; + } + out.resize(reqBytes); + } else { + out.resize(data.size()); + } + std::copy(data.begin(), data.end(), out.begin()); + return true; + } + return false; +} + +bool ParseBooleanProperty(bool &ret, std::string &err, + const picojson::object &o, + const std::string &property, bool required) { + picojson::object::const_iterator it = o.find(property); + if (it == o.end()) { + if (required) { + err += "'" + property + "' property is missing.\n"; + } + return false; + } + + if (!it->second.is()) { + if (required) { + err += "'" + property + "' property is not a bool type.\n"; + } + return false; + } + + ret = it->second.get(); + + return true; +} + +bool ParseNumberProperty(double &ret, std::string &err, + const picojson::object &o, const std::string &property, + bool required) { + picojson::object::const_iterator it = o.find(property); + if (it == o.end()) { + if (required) { + err += "'" + property + "' property is missing.\n"; + } + return false; + } + + if (!it->second.is()) { + if (required) { + err += "'" + property + "' property is not a number type.\n"; + } + return false; + } + + ret = it->second.get(); + + return true; +} + +bool ParseNumberArrayProperty(std::vector &ret, std::string &err, + const picojson::object &o, + const std::string &property, bool required) { + picojson::object::const_iterator it = o.find(property); + if (it == o.end()) { + if (required) { + err += "'" + property + "' property is missing.\n"; + } + return false; + } + + if (!it->second.is()) { + if (required) { + err += "'" + property + "' property is not an array.\n"; + } + return false; + } + + ret.clear(); + const picojson::array &arr = it->second.get(); + for (size_t i = 0; i < arr.size(); i++) { + if (!arr[i].is()) { + if (required) { + err += "'" + property + "' property is not a number.\n"; + } + return false; + } + ret.push_back(arr[i].get()); + } + + return true; +} + +bool ParseStringProperty(std::string &ret, std::string &err, + const picojson::object &o, const std::string &property, + bool required) { + picojson::object::const_iterator it = o.find(property); + if (it == o.end()) { + if (required) { + err += "'" + property + "' property is missing.\n"; + } + return false; + } + + if (!it->second.is()) { + if (required) { + err += "'" + property + "' property is not a string type.\n"; + } + return false; + } + + ret = it->second.get(); + + return true; +} + +bool ParseStringArrayProperty(std::vector &ret, std::string &err, + const picojson::object &o, + const std::string &property, bool required) { + picojson::object::const_iterator it = o.find(property); + if (it == o.end()) { + if (required) { + err += "'" + property + "' property is missing.\n"; + } + return false; + } + + if (!it->second.is()) { + if (required) { + err += "'" + property + "' property is not an array.\n"; + } + return false; + } + + ret.clear(); + const picojson::array &arr = it->second.get(); + for (size_t i = 0; i < arr.size(); i++) { + if (!arr[i].is()) { + if (required) { + err += "'" + property + "' property is not a string.\n"; + } + return false; + } + ret.push_back(arr[i].get()); + } + + return true; +} + +bool ParseAsset(Asset &asset, std::string &err, const picojson::object &o) { + + ParseStringProperty(asset.generator, err, o, "generator", false); + ParseBooleanProperty(asset.premultipliedAlpha, err, o, "premultipliedAlpha", + false); + + ParseStringProperty(asset.version, err, o, "version", false); + + picojson::object::const_iterator profile = o.find("profile"); + if (profile != o.end()) { + const picojson::value &v = profile->second; + if (v.contains("api") & v.get("api").is()) { + asset.profile_api = v.get("api").get(); + } + if (v.contains("version") & v.get("version").is()) { + asset.profile_version = v.get("version").get(); + } + } + + return true; +} + +bool ParseImage(Image &image, std::string &err, const picojson::object &o, + const std::string &basedir) { + + std::string uri; + if (!ParseStringProperty(uri, err, o, "uri", true)) { + return false; + } + + ParseStringProperty(image.name, err, o, "name", false); + + std::vector img; + if (IsDataURI(uri)) { + if (!DecodeDataURI(img, uri, 0, false)) { + err += "Failed to decode 'uri'.\n"; + return false; + } + } else { + // Assume external file + if (!LoadExternalFile(img, err, uri, basedir, 0, false)) { + err += "Failed to load external 'uri'.\n"; + return false; + } + if (img.empty()) { + err += "File is empty.\n"; + return false; + } + } + + int w, h, comp; + unsigned char *data = + stbi_load_from_memory(&img.at(0), img.size(), &w, &h, &comp, 0); + if (!data) { + err += "Unknown image format.\n"; + return false; + } + + if (w < 1 || h < 1) { + err += "Unknown image format.\n"; + return false; + } + + image.width = w; + image.height = h; + image.component = comp; + image.image.resize(w * h * comp); + std::copy(data, data + w * h * comp, image.image.begin()); + + return true; +} + +bool ParseBuffer(Buffer &buffer, std::string &err, const picojson::object &o, + const std::string &basedir) { + double byteLength; + if (!ParseNumberProperty(byteLength, err, o, "byteLength", true)) { + return false; + } + + std::string uri; + if (!ParseStringProperty(uri, err, o, "uri", true)) { + return false; + } + + picojson::object::const_iterator type = o.find("type"); + if (type != o.end()) { + if (type->second.is()) { + const std::string &ty = (type->second).get(); + if (ty.compare("arraybuffer") == 0) { + // buffer.type = "arraybuffer"; + } + } + } + + size_t bytes = static_cast(byteLength); + if (IsDataURI(uri)) { + if (!DecodeDataURI(buffer.data, uri, bytes, true)) { + err += "Failed to decode 'uri'.\n"; + return false; + } + } else { + // Assume external .bin file. + if (!LoadExternalFile(buffer.data, err, uri, basedir, bytes, true)) { + return false; + } + } + + ParseStringProperty(buffer.name, err, o, "name", false); + + return true; +} + +bool ParseBufferView(BufferView &bufferView, std::string &err, + const picojson::object &o) { + std::string buffer; + if (!ParseStringProperty(buffer, err, o, "buffer", true)) { + return false; + } + + double byteOffset; + if (!ParseNumberProperty(byteOffset, err, o, "byteOffset", true)) { + return false; + } + + double byteLength = 0.0; + ParseNumberProperty(byteLength, err, o, "byteLength", false); + + double target = 0.0; + ParseNumberProperty(target, err, o, "target", false); + int targetValue = static_cast(target); + if ((targetValue == TINYGLTF_TARGET_ARRAY_BUFFER) || + (targetValue == TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER)) { + // OK + } else { + targetValue = 0; + } + bufferView.target = targetValue; + + ParseStringProperty(bufferView.name, err, o, "name", false); + + bufferView.buffer = buffer; + bufferView.byteOffset = static_cast(byteOffset); + bufferView.byteLength = static_cast(byteLength); + + return true; +} + +bool ParseAccessor(Accessor &accessor, std::string &err, + const picojson::object &o) { + std::string bufferView; + if (!ParseStringProperty(bufferView, err, o, "bufferView", true)) { + return false; + } + + double byteOffset; + if (!ParseNumberProperty(byteOffset, err, o, "byteOffset", true)) { + return false; + } + + double componentType; + if (!ParseNumberProperty(componentType, err, o, "componentType", true)) { + return false; + } + + double count = 0.0; + if (!ParseNumberProperty(count, err, o, "count", true)) { + return false; + } + + std::string type; + if (!ParseStringProperty(type, err, o, "type", true)) { + return false; + } + + if (type.compare("SCALAR") == 0) { + accessor.type = TINYGLTF_TYPE_SCALAR; + } else if (type.compare("VEC2") == 0) { + accessor.type = TINYGLTF_TYPE_VEC2; + } else if (type.compare("VEC3") == 0) { + accessor.type = TINYGLTF_TYPE_VEC3; + } else if (type.compare("VEC4") == 0) { + accessor.type = TINYGLTF_TYPE_VEC4; + } else if (type.compare("MAT2") == 0) { + accessor.type = TINYGLTF_TYPE_MAT2; + } else if (type.compare("MAT3") == 0) { + accessor.type = TINYGLTF_TYPE_MAT3; + } else if (type.compare("MAT4") == 0) { + accessor.type = TINYGLTF_TYPE_MAT4; + } else { + std::stringstream ss; + ss << "Unsupported `type` for accessor object. Got \"" << type << "\"\n"; + err += ss.str(); + return false; + } + + double byteStride = 0.0; + ParseNumberProperty(byteStride, err, o, "byteStride", false); + + ParseStringProperty(accessor.name, err, o, "name", false); + + accessor.minValues.clear(); + accessor.maxValues.clear(); + ParseNumberArrayProperty(accessor.minValues, err, o, "min", false); + ParseNumberArrayProperty(accessor.maxValues, err, o, "max", false); + + accessor.count = static_cast(count); + accessor.bufferView = bufferView; + accessor.byteOffset = static_cast(byteOffset); + accessor.byteStride = static_cast(byteStride); + + { + int comp = static_cast(componentType); + if (comp >= TINYGLTF_COMPONENT_TYPE_BYTE && + comp <= TINYGLTF_COMPONENT_TYPE_DOUBLE) { + // OK + accessor.componentType = comp; + } else { + std::stringstream ss; + ss << "Invalid `componentType` in accessor. Got " << comp << "\n"; + err += ss.str(); + return false; + } + } + + return true; +} + +bool ParsePrimitive(Primitive &primitive, std::string &err, + const picojson::object &o) { + if (!ParseStringProperty(primitive.material, err, o, "material", true)) { + return false; + } + + double mode = static_cast(TINYGLTF_MODE_TRIANGLES); + ParseNumberProperty(mode, err, o, "mode", false); + + int primMode = static_cast(mode); + if (primMode != TINYGLTF_MODE_TRIANGLES) { + err += "Currently TinyGLTFLoader doesn not support primitive mode other \n" + "than TRIANGLES.\n"; + return false; + } + primitive.mode = primMode; + + primitive.indices = ""; + ParseStringProperty(primitive.indices, err, o, "indices", false); + + primitive.attributes.clear(); + picojson::object::const_iterator attribsObject = o.find("attributes"); + if ((attribsObject != o.end()) && + (attribsObject->second).is()) { + const picojson::object &attribs = + (attribsObject->second).get(); + picojson::object::const_iterator it(attribs.begin()); + picojson::object::const_iterator itEnd(attribs.end()); + for (; it != itEnd; it++) { + const std::string &name = it->first; + if (!(it->second).is()) { + err += "attribute expects string value.\n"; + return false; + } + const std::string &value = (it->second).get(); + + primitive.attributes[name] = value; + } + } + + return true; +} + +bool ParseMesh(Mesh &mesh, std::string &err, const picojson::object &o) { + ParseStringProperty(mesh.name, err, o, "name", false); + + mesh.primitives.clear(); + picojson::object::const_iterator primObject = o.find("primitives"); + if ((primObject != o.end()) && (primObject->second).is()) { + const picojson::array &primArray = + (primObject->second).get(); + for (size_t i = 0; i < primArray.size(); i++) { + Primitive primitive; + ParsePrimitive(primitive, err, primArray[i].get()); + mesh.primitives.push_back(primitive); + } + } + + return true; +} + +bool ParseNode(Node &node, std::string &err, const picojson::object &o) { + ParseStringProperty(node.name, err, o, "name", false); + + ParseNumberArrayProperty(node.rotation, err, o, "rotation", false); + ParseNumberArrayProperty(node.scale, err, o, "scale", false); + ParseNumberArrayProperty(node.translation, err, o, "translation", false); + ParseNumberArrayProperty(node.matrix, err, o, "matrix", false); + ParseStringArrayProperty(node.meshes, err, o, "meshes", false); + + node.children.clear(); + picojson::object::const_iterator childrenObject = o.find("children"); + if ((childrenObject != o.end()) && + (childrenObject->second).is()) { + const picojson::array &childrenArray = + (childrenObject->second).get(); + for (size_t i = 0; i < childrenArray.size(); i++) { + Node node; + if (!childrenArray[i].is()) { + err += "Invalid `children` array.\n"; + return false; + } + const std::string &childrenNode = childrenArray[i].get(); + node.children.push_back(childrenNode); + } + } + + return true; +} + +bool ParseMaterial(Material &material, std::string &err, + const picojson::object &o) { + ParseStringProperty(material.name, err, o, "name", false); + ParseStringProperty(material.technique, err, o, "technique", false); + + material.values.clear(); + picojson::object::const_iterator valuesIt = o.find("values"); + if ((valuesIt != o.end()) && (valuesIt->second).is()) { + + const picojson::object &valuesObject = + (valuesIt->second).get(); + picojson::object::const_iterator it(valuesObject.begin()); + picojson::object::const_iterator itEnd(valuesObject.end()); + + for (; it != itEnd; it++) { + // Assume number values. + std::vector values; + if (!ParseNumberArrayProperty(values, err, valuesObject, it->first, + false)) { + // Fallback to numer property. + double value; + if (ParseNumberProperty(value, err, valuesObject, it->first, false)) { + values.push_back(value); + } + } + + material.values[it->first] = values; + } + } + + return true; +} +} + +bool TinyGLTFLoader::LoadFromFile(Scene &scene, std::string &err, + const std::string &filename) { + std::stringstream ss; + + std::ifstream ifs(filename.c_str()); + if (!ifs) { + ss << "Failed to open file: " << filename << std::endl; + err = ss.str(); + return false; + } + + picojson::value v; + std::string perr = picojson::parse(v, ifs); + + if (!perr.empty()) { + err = perr; + return false; + } + + if (v.contains("scene") && v.get("scene").is()) { + // OK + } else { + err += "\"scene\" object not found in .gltf\n"; + return false; + } + + if (v.contains("scenes") && v.get("scenes").is()) { + // OK + } else { + err += "\"scenes\" object not found in .gltf\n"; + return false; + } + + if (v.contains("nodes") && v.get("nodes").is()) { + // OK + } else { + err += "\"nodes\" object not found in .gltf\n"; + return false; + } + + if (v.contains("accessors") && v.get("accessors").is()) { + // OK + } else { + err += "\"accessors\" object not found in .gltf\n"; + return false; + } + + if (v.contains("buffers") && v.get("buffers").is()) { + // OK + } else { + err += "\"buffers\" object not found in .gltf\n"; + return false; + } + + if (v.contains("bufferViews") && + v.get("bufferViews").is()) { + // OK + } else { + err += "\"bufferViews\" object not found in .gltf\n"; + return false; + } + + scene.buffers.clear(); + scene.bufferViews.clear(); + scene.accessors.clear(); + scene.meshes.clear(); + scene.nodes.clear(); + scene.defaultScene = ""; + + std::string basedir = GetBaseDir(filename); + + // 0. Parse Asset + if (v.contains("asset") && v.get("asset").is()) { + const picojson::object &root = v.get("asset").get(); + + ParseAsset(scene.asset, err, root); + } + + // 1. Parse Buffer + if (v.contains("buffers") && v.get("buffers").is()) { + const picojson::object &root = v.get("buffers").get(); + + picojson::object::const_iterator it(root.begin()); + picojson::object::const_iterator itEnd(root.end()); + for (; it != itEnd; it++) { + + Buffer buffer; + if (!ParseBuffer(buffer, err, (it->second).get(), + basedir)) { + return false; + } + + scene.buffers[it->first] = buffer; + } + } + + // 2. Parse BufferView + if (v.contains("bufferViews") && + v.get("bufferViews").is()) { + + const picojson::object &root = v.get("bufferViews").get(); + + picojson::object::const_iterator it(root.begin()); + picojson::object::const_iterator itEnd(root.end()); + for (; it != itEnd; it++) { + + BufferView bufferView; + if (!ParseBufferView(bufferView, err, + (it->second).get())) { + return false; + } + + scene.bufferViews[it->first] = bufferView; + } + } + + // 3. Parse Accessor + if (v.contains("accessors") && v.get("accessors").is()) { + + const picojson::object &root = v.get("accessors").get(); + + picojson::object::const_iterator it(root.begin()); + picojson::object::const_iterator itEnd(root.end()); + for (; it != itEnd; it++) { + + Accessor accessor; + if (!ParseAccessor(accessor, err, (it->second).get())) { + return false; + } + + scene.accessors[it->first] = accessor; + } + } + + // 4. Parse Mesh + if (v.contains("meshes") && v.get("meshes").is()) { + + const picojson::object &root = v.get("meshes").get(); + + picojson::object::const_iterator it(root.begin()); + picojson::object::const_iterator itEnd(root.end()); + for (; it != itEnd; it++) { + + Mesh mesh; + if (!ParseMesh(mesh, err, (it->second).get())) { + return false; + } + + scene.meshes[it->first] = mesh; + } + } + + // 5. Parse Node + if (v.contains("nodes") && v.get("nodes").is()) { + + const picojson::object &root = v.get("nodes").get(); + + picojson::object::const_iterator it(root.begin()); + picojson::object::const_iterator itEnd(root.end()); + for (; it != itEnd; it++) { + + Node node; + if (!ParseNode(node, err, (it->second).get())) { + return false; + } + + scene.nodes[it->first] = node; + } + } + + // 6. Parse scenes. + if (v.contains("scenes") && v.get("scenes").is()) { + + const picojson::object &root = v.get("scenes").get(); + + picojson::object::const_iterator it(root.begin()); + picojson::object::const_iterator itEnd(root.end()); + for (; it != itEnd; it++) { + + const picojson::object &o = (it->second).get(); + std::vector nodes; + if (!ParseStringArrayProperty(nodes, err, o, "nodes", false)) { + return false; + } + + scene.scenes[it->first] = nodes; + } + } + + // 7. Parse default scenes. + if (v.contains("scene") && v.get("scene").is()) { + + const std::string defaultScene = v.get("scene").get(); + + scene.defaultScene = defaultScene; + } + + // 8. Parse Material + if (v.contains("materials") && v.get("materials").is()) { + + const picojson::object &root = v.get("materials").get(); + + picojson::object::const_iterator it(root.begin()); + picojson::object::const_iterator itEnd(root.end()); + for (; it != itEnd; it++) { + + Material material; + if (!ParseMaterial(material, err, (it->second).get())) { + return false; + } + + scene.materials[it->first] = material; + } + } + + // 9. Parse Image + if (v.contains("images") && v.get("images").is()) { + + const picojson::object &root = v.get("images").get(); + + picojson::object::const_iterator it(root.begin()); + picojson::object::const_iterator itEnd(root.end()); + for (; it != itEnd; it++) { + + Image image; + if (!ParseImage(image, err, (it->second).get(), + basedir)) { + return false; + } + + scene.images[it->first] = image; + } + } + + return true; +} + +#endif // TINYGLTF_LOADER_IMPLEMENTATION + +#endif // TINY_GLTF_LOADER_H