From 9aa64e4227f46825357a68e77a150a9831e893d1 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Wed, 24 Nov 2010 13:48:09 -0500 Subject: [PATCH] imported FileLoader, TextureLoader, LoadFile, WFObj, logo, and genLoadFile --- .hgignore | 1 + FileLoader.h | 88 ++++++ LoadFile.cc | 41 +++ LoadFile.h | 25 ++ SConstruct | 11 +- TextureLoader.h | 18 ++ WFObj.cc | 703 ++++++++++++++++++++++++++++++++++++++++++++++ WFObj.h | 92 ++++++ genLoadFile.pl | 60 ++++ logo/dwlogo.blend | Bin 0 -> 169904 bytes logo/dwlogo.mtl | 22 ++ logo/dwlogo.obj | 645 ++++++++++++++++++++++++++++++++++++++++++ 12 files changed, 1704 insertions(+), 2 deletions(-) create mode 100644 FileLoader.h create mode 100644 LoadFile.cc create mode 100644 LoadFile.h create mode 100644 TextureLoader.h create mode 100644 WFObj.cc create mode 100644 WFObj.h create mode 100755 genLoadFile.pl create mode 100644 logo/dwlogo.blend create mode 100644 logo/dwlogo.mtl create mode 100644 logo/dwlogo.obj diff --git a/.hgignore b/.hgignore index 39d4830..1d76a2c 100644 --- a/.hgignore +++ b/.hgignore @@ -1,3 +1,4 @@ glob:.scons* glob:*.o glob:dwss +glob:LoadFile-gen.inc diff --git a/FileLoader.h b/FileLoader.h new file mode 100644 index 0000000..8a6cffb --- /dev/null +++ b/FileLoader.h @@ -0,0 +1,88 @@ + +#ifndef FILELOADER_H +#define FILELOADER_H FILELOADER_H + +#include +#include + +class FileLoader +{ + public: + class Path + { + public: + std::string fullPath; + std::string shortPath; + Path() { } + Path(const std::string & full_path, + const std::string & short_path) + : fullPath(full_path), shortPath(short_path) { } + std::string toString() const + { + std::string ret; + if (shortPath != "") + ret += shortPath + ","; + if (fullPath != "") + ret += fullPath; + return ret; + } + }; + + class Buffer + { + public: + char * data; + int size; + Buffer(int sz) + { + size = sz; + data = new char[size]; + _refcnt = new int; + *_refcnt = 1; + m_alloced = true; + } + Buffer(char * data, int sz) + { + size = sz; + this->data = data; + m_alloced = false; + } + void copy(const Buffer & other) + { + data = other.data; + size = other.size; + m_alloced = other.m_alloced; + if (m_alloced) + { + _refcnt = other._refcnt; + (*_refcnt)++; + } + } + Buffer(const Buffer & other) { copy(other); } + Buffer & operator=(const Buffer & other) + { + copy(other); + return *this; + } + ~Buffer() + { + if (m_alloced) + { + (*_refcnt)--; + if (*_refcnt < 1) + { + delete _refcnt; + delete data; + } + } + } + protected: + int * _refcnt; + bool m_alloced; + }; + + virtual int getSize(const Path & path) = 0; + virtual Buffer load(const Path & path) = 0; +}; + +#endif diff --git a/LoadFile.cc b/LoadFile.cc new file mode 100644 index 0000000..373acf3 --- /dev/null +++ b/LoadFile.cc @@ -0,0 +1,41 @@ + +#include "LoadFile.h" + +using namespace std; + +/* The data section is generated by a perl script. The contents of the + * included file are part of this logical program unit, which is why it + * is directly included instead of compiling it separately. + */ +#include "LoadFile-gen.inc" + +LoadFile::LoadFile() +{ + for (unsigned int i = 0; + i < sizeof(LoadFileData)/sizeof(LoadFileData[0]); + i++) + { + m_filemap[LoadFileData[i].filename] = &LoadFileData[i]; + } +} + +FileLoader::Buffer LoadFile::load(const FileLoader::Path & path) +{ + map::iterator it = m_filemap.find(path.shortPath); + + if (it == m_filemap.end()) + return Buffer(0); + + return Buffer((char *) it->second->data, it->second->length); +} + +int LoadFile::getSize(const FileLoader::Path & path) +{ + map::iterator it = m_filemap.find(path.shortPath); + + if (it == m_filemap.end()) + return 0; + + return it->second->length; +} + diff --git a/LoadFile.h b/LoadFile.h new file mode 100644 index 0000000..7a5845f --- /dev/null +++ b/LoadFile.h @@ -0,0 +1,25 @@ + +#ifndef LOADFILE_H +#define LOADFILE_H + +#include +#include +#include "FileLoader.h" + +typedef struct { + const char * filename; + unsigned char * data; + int length; +} fileref_t; + +class LoadFile : public FileLoader +{ + public: + LoadFile(); + int getSize(const Path & path); + Buffer load(const Path & path); + protected: + std::map< std::string, fileref_t * > m_filemap; +}; + +#endif diff --git a/SConstruct b/SConstruct index e616958..b634ca2 100644 --- a/SConstruct +++ b/SConstruct @@ -1,10 +1,17 @@ install_dir = '/usr/lib/gnome-screensaver/gnome-screensaver' +load_files = ['logo/dwlogo.obj', 'logo/dwlogo.mtl'] -env = Environment() +env = Environment(CPPPATH = ['.']) env.ParseConfig("pkg-config --cflags --libs glib-2.0 gdk-2.0 atk gtk+-2.0 gtkglext-1.0") -dwss = env.Program('dwss', [Glob('*.c'), Glob('*.cc')]) +genLoadFile = Builder(action = 'perl genLoadFile.pl --root=logo $SOURCES') +env.Append(BUILDERS = {'LoadFile' : genLoadFile}) + +sources = [Glob('*.c'), Glob('*.cc'), Glob('LoadFile/*.cc')] +env.LoadFile('LoadFile-gen.inc', load_files) +env.Depends('LoadFile-gen.inc', 'genLoadFile.pl') +dwss = env.Program('dwss', sources) env.Install(install_dir, dwss) env.Alias('install', install_dir) diff --git a/TextureLoader.h b/TextureLoader.h new file mode 100644 index 0000000..a7b9ca5 --- /dev/null +++ b/TextureLoader.h @@ -0,0 +1,18 @@ + +#ifndef TEXTURELOADER_H +#define TEXTURELOADER_H TEXTURELOADER_H + +#include +#include +#include "FileLoader.h" + +class TextureLoader +{ + public: + virtual GLuint load( + const FileLoader::Path & path, + FileLoader & fileLoader, bool mipmaps = true, + int mode = GL_DECAL, int quality = 1) = 0; +}; + +#endif diff --git a/WFObj.cc b/WFObj.cc new file mode 100644 index 0000000..68b0ab6 --- /dev/null +++ b/WFObj.cc @@ -0,0 +1,703 @@ + +#include +#include +#include +#include +#include // isspace() +#include // strlen() +#include +#include +#include +#include +#include +#include +#include +#include "WFObj.h" +using namespace std; + +#define WHITESPACE " \n\r\t\v" +//#define DEBUGGL + +/****** static functions ******/ + +static string trimString(string s) +{ + size_t lastpos = s.find_last_not_of(WHITESPACE); + if (lastpos == string::npos) + return ""; + s.erase(lastpos + 1); + s.erase(0, s.find_first_not_of(WHITESPACE)); + return s; +} + +static string stripFirstToken(string & input) +{ + size_t firstnonspace = input.find_first_not_of(WHITESPACE); + if (firstnonspace == string::npos) + return ""; + size_t spaceafter = input.find_first_of(WHITESPACE, firstnonspace); + string token = input.substr(firstnonspace, spaceafter - firstnonspace); + input.erase(0, spaceafter); + return token; +} + +static vector splitString(const string & str, char delim) +{ + vector ret; + string s = str; + size_t pos; + while ( (pos = s.find(delim)) != string::npos ) + { + string t = s.substr(0, pos); + ret.push_back(t); + s.erase(0, pos + 1); + } + if (s != "") + ret.push_back(s); + return ret; +} + +static string basePath(const string & str) +{ + string path = str; + size_t pos; + if ( (pos = path.find_last_of("/\\")) != string::npos ) + { + path.erase(pos + 1); + return path; + } + return ""; +} + +//#define DEBUG_GL_ERROR +#ifdef DEBUG_GL_ERROR +#define checkGLError() checkGLErrorLine(__FUNCTION__, __LINE__) +static void checkGLErrorLine(const char * function, int line) +{ + GLenum err = glGetError(); + if (err != 0) + { + cerr << "gl error in " << function + << ": " << err << " (0x" << hex << err << ") at line " + << dec << line << endl; + } +} +#else +#define checkGLError() +#endif + + +/****** WFObj functions ******/ + +WFObj::WFObj() +{ + init(); +} + +WFObj::WFObj(FileLoader & fileLoader) +{ + init(&fileLoader); +} + +WFObj::WFObj(TextureLoader & textureLoader) +{ + init(NULL, &textureLoader); +} + +WFObj::WFObj(FileLoader & fileLoader, TextureLoader & textureLoader) +{ + init(&fileLoader, &textureLoader); +} + +void WFObj::init (FileLoader * fileLoader, + TextureLoader * textureLoader) +{ + m_fileLoader = fileLoader; + if (m_fileLoader == NULL) + { + m_fileLoader = new WFFileLoader(); + m_iCreatedFileLoader = true; + } + else + { + m_iCreatedFileLoader = false; + } + m_textureLoader = textureLoader; +} + +WFObj::~WFObj() +{ + if (m_iCreatedFileLoader) + delete m_fileLoader; +} + +void WFObj::clear() +{ + m_data = std::vector< std::vector >(); + m_loadedVertex = false; +} + +bool WFObj::load(const FileLoader::Path & path) +{ + clear(); + + FileLoader::Buffer buff = m_fileLoader->load(path); + if (buff.size <= 0) + return false; + + m_path = path; + string str(buff.data, buff.size); + stringstream istr(str, ios_base::in); + load(istr, buff.size); + + return true; +} + +bool WFObj::load(std::istream & istr, unsigned int size) +{ + char buf[size+1]; + + string buildup; + while (istr.good()) + { + istr.getline(buf, size+1); + string input = trimString(buf); + int sz = input.size(); + if (sz == 0 || input[0] == '#') + continue; + if (input[sz-1] == '\\') + { + input[sz-1] = ' '; + buildup = input; + continue; + } + if (buildup != "") + input = buildup + input; + buildup = ""; + processInputLine(input); + } + return true; +} + +void WFObj::processInputLine(const std::string & input) +{ + string line = input; + vector lineParts; + for (;;) + { + string token = stripFirstToken(line); + if (token == "") + break; + lineParts.push_back(token); + } + if (lineParts.size() > 0) + m_data.push_back(lineParts); +} + + +GLuint WFObj::render(bool doTextureInfo, bool enableBlending) +{ + checkGLError(); + GLuint list = glGenLists(1); + glNewList(list, GL_COMPILE); + int len = m_data.size(); + enum { VERTEX, VERTEX_TEXTURE, VERTEX_NORMAL, VERTEX_TYPES }; + vector vertices[VERTEX_TYPES]; + int numVertsLast = 0; + bool inFace = false; + bool inMaterial = false; + string currentMaterialName; + WFMtl material(this); + for (int i = 0; i < len; i++) + { + string type = m_data[i][0]; + if (type == "v") + { + Vertex v = readVertex(m_data[i]); + updateAABB(v.getData()); + vertices[VERTEX].push_back(v); + } + else if (type == "vt") + vertices[VERTEX_TEXTURE].push_back(readVertex(m_data[i])); + else if (type == "vn") + vertices[VERTEX_NORMAL].push_back(readVertex(m_data[i])); + else if (type == "f") + { + int numVerts = m_data[i].size() - 1; + if (inFace && (numVerts != numVertsLast || numVertsLast > 4)) + { +#ifdef DEBUGGL + cout << "glEnd()" << endl; +#endif + glEnd(); + inFace = false; + } + if (!inFace) + { + if (numVerts == 3) + { +#ifdef DEBUGGL + cout << "glBegin(GL_TRIANGLES)" << endl; +#endif + glBegin(GL_TRIANGLES); + } + else if (numVerts == 4) + { +#ifdef DEBUGGL + cout << "glBegin(GL_QUADS)" << endl; +#endif + glBegin(GL_QUADS); + } + else + { +#ifdef DEBUGGL + cout << "glBegin(GL_POLYGON)" << endl; +#endif + glBegin(GL_POLYGON); + } + inFace = true; + } + for (int v = 1; v <= numVerts; v++) + { + int vertexIndices[3] = {0, 0, 0}; + parseVertexIndices(m_data[i][v], vertexIndices); + for (int j = 0; j < 3; j++) + { + if (vertexIndices[j] < 0) + vertexIndices[j] += vertices[j].size() + 1; + } + bool valid = true; + for (int j = 0; j < 3; j++) + { + if (vertexIndices[j] > (int) vertices[j].size()) + { + valid = false; + break; + } + } + if (vertexIndices[VERTEX] <= 0) + valid = false; + if (!valid) + continue; + if (vertexIndices[VERTEX_NORMAL] != 0) + { + /* a normal is present */ +#ifdef DEBUGGL + cout << " glNormal3f(" << + vertices[VERTEX_NORMAL][vertexIndices[VERTEX_NORMAL]-1] + [0] << ", " << + vertices[VERTEX_NORMAL][vertexIndices[VERTEX_NORMAL]-1] + [1] << ", " << + vertices[VERTEX_NORMAL][vertexIndices[VERTEX_NORMAL]-1] + [2] << ")" << endl; +#endif + glNormal3fv(vertices[VERTEX_NORMAL] + [vertexIndices[VERTEX_NORMAL]-1].getData()); + } + if (vertexIndices[VERTEX_TEXTURE] != 0) + { + /* a texture coordinate is present */ +#ifdef DEBUGGL + cout << " glTexCoord2f(" << + vertices[VERTEX_TEXTURE][vertexIndices[VERTEX_TEXTURE]-1] + [0] << ", " << + vertices[VERTEX_TEXTURE][vertexIndices[VERTEX_TEXTURE]-1] + [1] << ')' << endl; +#endif + glTexCoord2fv(vertices[VERTEX_TEXTURE] + [vertexIndices[VERTEX_TEXTURE]-1].getData()); + } +#ifdef DEBUGGL + cout << " glVertex3f(" << + vertices[VERTEX][vertexIndices[VERTEX]-1][0] << ", " << + vertices[VERTEX][vertexIndices[VERTEX]-1][1] << ", " << + vertices[VERTEX][vertexIndices[VERTEX]-1][2] << ")" << + " [" << vertexIndices[VERTEX] << "]" << endl; +#endif + glVertex3fv(vertices[VERTEX][vertexIndices[VERTEX]-1].getData()); + } + + numVertsLast = numVerts; + } + else if (type == "usemtl") + { + if (inFace) + { +#ifdef DEBUGGL + cout << "glEnd()" << endl; +#endif + glEnd(); + inFace = false; + } + if (inMaterial) + { + material.renderEnd(currentMaterialName, doTextureInfo, + enableBlending); + inMaterial = false; + } + if (m_data[i].size() >= 2) + { + currentMaterialName = m_data[i][1]; + material.renderBegin(currentMaterialName, doTextureInfo, + enableBlending); + inMaterial = true; + } + } + else if (type == "mtllib") + { + if (m_data[i].size() >= 2) + { + FileLoader::Path path( + basePath(m_path.fullPath) + m_data[i][1], + m_data[i][1]); + material.load(path); + } + } + } + if (inFace) + { +#ifdef DEBUGGL + cout << "glEnd()" << endl; +#endif + glEnd(); + inFace = false; + } + if (inMaterial) + { + material.renderEnd(currentMaterialName, doTextureInfo, enableBlending); + inMaterial = false; + } + glEndList(); + checkGLError(); + return list; +} + +void WFObj::updateAABB(const float * const vertex) +{ + if (m_loadedVertex) + { + if (vertex[0] < m_aabb[0]) + m_aabb[0] = vertex[0]; + else if (vertex[0] > m_aabb[3]) + m_aabb[3] = vertex[0]; + if (vertex[1] < m_aabb[1]) + m_aabb[1] = vertex[1]; + else if (vertex[1] > m_aabb[4]) + m_aabb[4] = vertex[1]; + if (vertex[2] < m_aabb[2]) + m_aabb[2] = vertex[2]; + else if (vertex[2] > m_aabb[5]) + m_aabb[5] = vertex[2]; + } + else + { + m_aabb[0] = m_aabb[3] = vertex[0]; + m_aabb[1] = m_aabb[4] = vertex[1]; + m_aabb[2] = m_aabb[5] = vertex[2]; + m_loadedVertex = true; + } +} + +WFObj::Vertex WFObj::readVertex(const vector & parts) +{ + int partslen = parts.size(); + Vertex v; + for (int i = 1; i < partslen && i <= 4; i++) + { + sscanf(parts[i].c_str(), "%f", &v[i - 1]); + } + return v; +} + +void WFObj::parseVertexIndices(const string & vtxref, int * ret) +{ + vector parts = splitString(vtxref, '/'); + int num = parts.size(); + for (int i = 0; i < num && i < 3; i++) + sscanf(parts[i].c_str(), "%d", ret + i); +} + + + + +/****** WFMtl functions ******/ + +void WFObj::WFMtl::clear() +{ + m_data = map< string, vector< vector > >(); + m_currentMaterialName = ""; + m_attributesPushed = false; +} + +bool WFObj::WFMtl::load(const FileLoader::Path & path) +{ + clear(); + + FileLoader::Buffer buff = m_obj->m_fileLoader->load(path); + if (buff.size <= 0) + return false; + + m_path = path; + string str(buff.data, buff.size); + stringstream istr(str, ios_base::in); + load(istr, buff.size); + + return true; +} + +bool WFObj::WFMtl::load(std::istream & istr, unsigned int size) +{ + char buf[size+1]; + + string buildup; + while (istr.good()) + { + istr.getline(buf, size+1); + string input = trimString(buf); + int sz = input.size(); + if (sz == 0 || input[0] == '#') + continue; + if (input[sz-1] == '\\') + { + input[sz-1] = ' '; + buildup = input; + continue; + } + if (buildup != "") + input = buildup + input; + buildup = ""; + processInputLine(input); + } + return true; +} + +void WFObj::WFMtl::processInputLine(const std::string & input) +{ + string line = input; + vector lineParts; + for (;;) + { + string token = stripFirstToken(line); + if (token == "") + break; + lineParts.push_back(token); + } + if (lineParts.size() > 0) + { + if ( (lineParts.size() >= 2) && (lineParts[0] == "newmtl") ) + { + m_currentMaterialName = lineParts[1]; + } + else if (m_currentMaterialName != "") + { + m_data[m_currentMaterialName].push_back(lineParts); + } + } +} + +void WFObj::WFMtl::renderBegin(const string & mtlname, bool doTextureInfo, + bool enableBlending) +{ + map< string, vector< vector > >::iterator it = m_data.find(mtlname); + if (it == m_data.end()) + return; + vector< vector > & stmts = it->second; + int num_stmts = stmts.size(); + bool foundTexture = false; + bool didSomething = false; + checkGLError(); + for (int i = 0; i < num_stmts; i++) + { + string & type = stmts[i][0]; + if (type == "Ka") /* set ambient color */ + { + if ( (stmts[i].size() == 4) && (stmts[i][1] != "spectral") ) + { + pushAttributes(); + float mat[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + for (int j = 0; j < 3; j++) + sscanf(stmts[i][j+1].c_str(), "%f", &mat[j]); +#ifdef DEBUGGL + cout << " glMaterialfv(GL_FRONT, GL_AMBIENT, {"; + for (int j = 0; j < 4; j++) + cout << mat[j] << (j < 3 ? ", " : "})"); + cout << endl; +#endif + glMaterialfv(GL_FRONT, GL_AMBIENT, mat); + didSomething = true; + } + } + else if (type == "Kd") /* set diffuse color */ + { + if ( (stmts[i].size() == 4) && (stmts[i][1] != "spectral") ) + { + pushAttributes(); + float mat[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + for (int j = 0; j < 3; j++) + sscanf(stmts[i][j+1].c_str(), "%f", &mat[j]); +#ifdef DEBUGGL + cout << " glMaterialfv(GL_FRONT, GL_DIFFUSE, {"; + for (int j = 0; j < 4; j++) + cout << mat[j] << (j < 3 ? ", " : "})"); + cout << endl; +#endif + glMaterialfv(GL_FRONT, GL_DIFFUSE, mat); + didSomething = true; + } + } + else if (type == "Ks") /* set specular color */ + { + if ( (stmts[i].size() == 4) && (stmts[i][1] != "spectral") ) + { + pushAttributes(); + float mat[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + for (int j = 0; j < 3; j++) + sscanf(stmts[i][j+1].c_str(), "%f", &mat[j]); +#ifdef DEBUGGL + cout << " glMaterialfv(GL_FRONT, GL_SPECULAR, {"; + for (int j = 0; j < 4; j++) + cout << mat[j] << (j < 3 ? ", " : "})"); + cout << endl; +#endif + glMaterialfv(GL_FRONT, GL_SPECULAR, mat); + didSomething = true; + } + } + else if (type == "Ns") /* set shininess */ + { + if (stmts[i].size() == 2) + { + pushAttributes(); + GLfloat shininess = 0.0f; + sscanf(stmts[i][1].c_str(), "%f", &shininess); +#ifdef DEBUGGL + cout << " glMaterialf(GL_FRONT, GL_SHININESS, " + << shininess << ")" << endl; +#endif + glMaterialf(GL_FRONT, GL_SHININESS, shininess); + didSomething = true; + } + } + else if (type == "map_Kd") /* load a diffuse texture */ + { + if (doTextureInfo) + { + if (stmts[i].size() == 2) + { + if (m_obj->m_textureLoader != NULL) + { + FileLoader::Path path( + basePath(m_path.fullPath + stmts[i][1]), + stmts[i][1]); + GLuint tex = m_obj->m_textureLoader->load(path, + *m_obj->m_fileLoader); + if (tex > 0) + { + pushAttributes(); /* jh 2009-11-16 */ +#ifdef DEBUGGL + cout << " glBindTexture(GL_TEXTURE_2D, " << tex << ")" << endl; +#endif + glBindTexture(GL_TEXTURE_2D, tex); + foundTexture = true; + didSomething = true; + } + } + } + } + } + } + + checkGLError(); + if (didSomething) + { + pushAttributes(); + if (doTextureInfo) + { + if (enableBlending) + { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + } + if (foundTexture) + { +#ifdef DEBUGGL + cout << " glEnable(GL_TEXTURE_2D)" << endl; +#endif + glEnable(GL_TEXTURE_2D); + } + else + { +#ifdef DEBUGGL + cout << " glDisable(GL_TEXTURE_2D)" << endl; +#endif + glDisable(GL_TEXTURE_2D); + } + } + } + checkGLError(); +} + +void WFObj::WFMtl::pushAttributes() +{ + if (m_attributesPushed) + return; + m_attributesPushed = true; +#ifdef DEBUGGL + cout << " glPushAttrib(GL_LIGHTING_BIT | GL_TEXTURE_BIT | GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT)" + << endl; +#endif + checkGLError(); + glPushAttrib(GL_LIGHTING_BIT | GL_TEXTURE_BIT | GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT); + checkGLError(); +} + +void WFObj::WFMtl::renderEnd(const string & mtlname, bool doTextureInfo, + bool enableBlending) +{ + map< string, vector< vector > >::iterator it = m_data.find(mtlname); + if (it == m_data.end()) + return; + if (m_attributesPushed) + { +#ifdef DEBUGGL + cout << " glPopAttrib()" << endl; +#endif + checkGLError(); + glPopAttrib(); + checkGLError(); + m_attributesPushed = false; + } +} + + +/****** WFFileLoader functions ******/ + +int WFObj::WFFileLoader::getSize(const Path & path) +{ + struct stat st; + + if (path.fullPath == "") + return -1; + if (stat(path.fullPath.c_str(), &st)) + return -2; + return st.st_size; +} + +FileLoader::Buffer WFObj::WFFileLoader::load(const Path & path) +{ + int size = getSize(path); + if (size > 0) + { + int fd = open(path.fullPath.c_str(), O_RDONLY); + if (fd > 0) + { + Buffer buf(size); + int num_read = read(fd, buf.data, size); + close(fd); + if (num_read > 0) + return buf; + } + } + return Buffer(0); +} diff --git a/WFObj.h b/WFObj.h new file mode 100644 index 0000000..fd7a5a1 --- /dev/null +++ b/WFObj.h @@ -0,0 +1,92 @@ + +#ifndef WFOBJ_H +#define WFOBJ_H + +#include "FileLoader.h" +#include "TextureLoader.h" +#include +#include +#include +#include + +class WFObj +{ +public: + WFObj(); + WFObj(FileLoader & fileLoader); + WFObj(TextureLoader & textureLoader); + WFObj(FileLoader & fileLoader, TextureLoader & textureLoader); + ~WFObj(); + + class WFMtl + { + public: + WFMtl(WFObj * obj) { m_obj = obj; } + bool load(const FileLoader::Path & path); + void renderBegin(const std::string & mtlname, + bool doTextureInfo = true, + bool enableBlending = false); + void renderEnd(const std::string & mtlname, + bool doTextureInfo = true, + bool enableBlending = false); + + protected: + /* methods */ + void clear(); + void processInputLine(const std::string & input); + void pushAttributes(); + bool load(std::istream & istr, unsigned int size); + + /* variables */ + std::map< std::string, std::vector< std::vector > > m_data; + std::string m_currentMaterialName; + bool m_attributesPushed; + FileLoader::Path m_path; + WFObj * m_obj; + }; + + class WFFileLoader : public FileLoader + { + public: + virtual int getSize(const Path & path); + virtual Buffer load(const Path & path); + }; + + bool load(const FileLoader::Path & path); + GLuint render(bool doTextureInfo = true, + bool enableBlending = false); + const float * const getAABB() { return m_aabb; } + +protected: + /* types */ + class Vertex + { + public: + float operator[](int idx) const { return data[idx]; } + float & operator[](int idx) { return data[idx]; } + float * getData() { return data; } + private: + float data[4]; + }; + + /* methods */ + void init(FileLoader * fileLoader = NULL, + TextureLoader * textureLoader = NULL); + void clear(); + void processInputLine(const std::string & input); + Vertex readVertex(const std::vector & parts); + void parseVertexIndices(const std::string & vtxref, int * ret); + void updateAABB(const float * const vertex); + bool load(std::istream & istr, unsigned int size); + + /* variables */ + std::vector< std::vector > m_data; + FileLoader::Path m_path; + float m_aabb[6]; + bool m_loadedVertex; + FileLoader * m_fileLoader; + TextureLoader * m_textureLoader; + bool m_iCreatedFileLoader; +}; + +#endif diff --git a/genLoadFile.pl b/genLoadFile.pl new file mode 100755 index 0000000..f5880f4 --- /dev/null +++ b/genLoadFile.pl @@ -0,0 +1,60 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Getopt::Long; + +my $root = '.'; +GetOptions('root=s' => \$root); +$root = "$root/" if ($root ne ''); + +my @fileList = @ARGV; +if ($#fileList < 0) +{ + print "$0 \n"; + exit(42); +} + +my %fileData; +my $index = 0; + +open(OUTPUT, '>', 'LoadFile-gen.inc'); +foreach my $fileName (@fileList) +{ + local $/; + open(FILE, '<', $fileName); + my $fileContents = ; + close(FILE); + my $length = length($fileContents); + my @fileContents = split(//, $fileContents); + my $cname = "dat$index"; + print OUTPUT "\nstatic unsigned char ${cname} [] = {\n"; + for (my $byteNum = 0; $byteNum <= $#fileContents; $byteNum++) + { + print OUTPUT " " if ($byteNum % 12 == 0); + printf OUTPUT ("0x%02x", ord($fileContents[$byteNum])); + print OUTPUT ", " unless ($byteNum == $#fileContents); + print OUTPUT "\n" if ($byteNum % 12 == 11); + } + print OUTPUT "\n};\n"; + $index++; + my $shortName = $fileName; + $shortName =~ s/^$root//; + $fileData{$shortName} = [$cname, $length]; +} + +print OUTPUT "\nfileref_t LoadFileData[] = {\n"; + +my @fileNames = keys(%fileData); +for (my $fileIndex = 0; $fileIndex <= $#fileNames; $fileIndex++) +{ + my $fileName = $fileNames[$fileIndex]; + printf OUTPUT (' {"%s", %s, %s}', + $fileName, + $fileData{$fileName}->[0], + $fileData{$fileName}->[1]); + print OUTPUT "," unless ($fileIndex == $#fileNames); + print OUTPUT "\n"; +} +print OUTPUT "};\n"; +close(OUTPUT); diff --git a/logo/dwlogo.blend b/logo/dwlogo.blend new file mode 100644 index 0000000000000000000000000000000000000000..b01601b23f49a160a8e2a03756652b4fbf0e51e8 GIT binary patch literal 169904 zcmeEv34B~t_5YhmOUv2-6+yO11Em&d(*-C?Gm~z#+S>eDHc=pHGHpZCBqr&?A`A!u z0uuQNqJjhjSC+UTvNTgbe~6%U*T3Q~C@2U&4azD?{^xto{l0hK%S<}Sw4{aJd|vLo z=bdxzJ>R?Eci)>?3+H}d&fFzOuAMsls3j6ic;aHO{h{wd1SDv$e~G`eF5Q#{G2%{K zxOmnCp>6V1?kWjGE|Ex7fVEfSv6_>of$VktWVP|VQqRjIMtDn?c-~h)AEEazQ+|*9 zkjdqiE}3#ZGcK1ewm|5;l3*N%cuIr=y%_`6yRoH#nDc@=3sh9a?y^6|{ zpYo-m7bSW<;8%O)ePx*|Mr{08ZN74F8dGb@f*UD2b(~Z_s%9Ee+HG63Osh8>I zlP5prH(7b=W&W9uD1PLpd}@rQPrWSvXnSG)$xrz%D^I;lKiY06PkzcLN;Q4zWxdNM zPkzdGSb6GYzVpeGpYq@$M}ErpSb6GY zxkvi};zxeUSMR0yr(WhepFH^~pSAMTOZ+l<@=t!sSM06nQ!jDPCr^ILcUpPsW&NQY zQT)hH`BFR2pkB)5OP~Cd=X`~FS$@PJnm+j{&->I%+;gQrS{ftgMOTU-+Gf`T#gBTT z?T>h}U65}}_?(N}Zd|oH@G}{UZY`jn zq}{}!;~>R>_{?u^UNv+Sh98G~?Sl24;|1*|4%veh2jWv*+uGhx*O*Q$Xp(WWwl1>0 zv)Qg=xa&jSc47NL;y}BJLvKQHAU;c*m$xr#u0Ln92IpbeUT~n@#33)XR23yNLtm-NXm;D9Q}Q zA8s7-_7Bz=;y}BJ18pTf^O{>_@0--Y`@@X`#?8&OiykqH>oZImu?~r@(?$qw+O%oO z*eO>ZA;AHiUB_(nQoooZj2k^~ZGvqn#K4To&RnQs{-)J=RGp8k`&@yv^gIt$oMJ4uR|X z`rO#y!YD87mvDcC`z78)+ke}AAAi3lvhUqv_u&SY>cHIC9~mW=KKb#?vmC_B6s(cXMayR`+MG}N7i(@#{lHn*f@lAIpYa^aMQ z^tx&F)b`f8&7b=onS`Bpr{)RZ7{t3(&AeVhG>r1@Hus?q+Mc|1QOXdUe}&R=W9ld>Iyib?&)X%W1?>s* zDYl<}^C{b32lJ_X?Mc<{m`?@p2J@+KRo)WwDb5c#U+Ac^M3FCFS{S!XR_cl10{=qm&z}{aR3!biKmSn!9tXLh3~C*JTM z5h`eKz?|^_e{)OzLD#u+6#x0N?Ciuh8Fplai}}VAcVov1Y6tBDUYoH)#;&;JH?z_6 zUX^n9LUA|$dr0aTVQ}-$IP#DCfs^_p`8R!;*FXOOA3_!o3Bj%zC1RJggX!{ z1KSmzMa{>UVUI)AwL?t?`>QC0Tv;(mF(WskG_(GGm` z^@l(D=7|r{syj2U&;Eqq&G_*7QLKV>8CD0wvyM?Tv`+pDb$vjGIXmZIsBhbW%e#(Y z`-!e&*v^7=%)s-V9qX8&7H~{F*6F`+cT22exNhM(hVL10eZ%v2{{E+3zwkU=kjvsi z*w@55=0WjamCKF)+KKz*I$l-GS3i2cXO_}S z=cteIp;wql=Q@V>DgRD6M@PGf1MMe1?}T%7onkcW(S;I5U!9m2u1{lxrt^ibEtH@* z&YKY~ops(WBOdzBeK*)Kp|qg!^8jfVa0&At;~nHM?{z?e^U7rotj}97+sE7Z&C;4VE$>?~+dhBIDVv`-@blI;Mrf)dOer9@VRyYe#c>_V z&+HG{ek(ez5|3b9W%;>Ug7A)UHNYYmS7q>U+?E(uIgWB%rFxFHo_#NZ&t3Ukk>f4- zZ~o}6{pR9>d7cP8KavaMDxViJj&T(Zag3|HFZ=Q(k9(8i7*{_f^nu3J>>}+)GE2k# zpoke)^M0jwEL5N4D(M_gc%O2`?hg+4bF@OAC(>@>K>LZ$JK=d^Lb^QGBktpQ)#3Vt zp~dv;AB-PBjQaa0NT0pop@1&&%&w0x&T(l{xVf9#xQD$BIK7{J$d%PKxvaOP-^Skq zmP;kv{{!#i_5A&ia0l;-77&IoF0>=$nfh+B^j*Zql~^3Kw@xR1qrESlxLEMMvx&vL z(&K{tFxct3LgE!qaMuRfV_xTyWxf)`Gc&^a-SxTQKSuAvKJ3r19&mq#{S501ln-1l zqWc4|XfU+F@ItriGRXq^ZzGWJIrH-8{@Snq4?nBb^zuDtE+GAkXxQ$&Czwb2U7fjE%si6c zo#1ySE)$K=Uiy^w>--)?kP8hhT{88^Ma}i;#zgo|IA_wWo}zj-ovwbxht$v1sozWg zXBy{sCt}{(kwd=2DgvfO8tOj}Lvgt}Nr=uMCC|7!_=7ahI z;oo4CFymoDeDYDQ#mZ41c;S$L_)L#{l-p$Gs1LkwYtcZ&QI33+t2j;bNqx$V|IeBr z<;X|54l74}lv_J8EJr@d^;$XVqnv!tA!HxP$_adP{BlWj&3`lb`Zk zR-Ss9F6E>7CqLyAXKDJ>OZ%hso%WNT@*P&5dMj+Z&L>ZP%6m1MKJ_yH(RRc1$xrzf zD^I<&JD)uHDc@t|sh9Rg+aJ>>Kjo`yHUHGh{O6M=KjpJlo_d+@Xgg;59Ok%2O}%ollzvGE_89(!1BBo4HjI3&KSI1ry=?I>2>$?}kbx%$amIM8n5(BI3m9wmzKN z+}c<_Bn!5jP_#ZQa8$EC&~D<;a*Fno#HUz0ij{Y=JfvW*`j86;+D#lfzpV2p;;k$!;M3s<0kDU4!!@VHSL1<6gzGXHx9YR&0O_?b`yux zlXV6M;#2Inxvk2b6dZ_jfR_ivPH; zGWMp)j;ZJp!ZTAk)(6^69J<=^2A8}?X6r?OLt+YL2jdSn4rj`t-{|@x7Y?+WIHX>j zZg3zzvujt&=j{e#d6;*&aVT`$q}{~9dqnqPh|kiMweo$oK`tsBD2998ooil=b$828 zbbi2gLA!}V$63{;J`f+fzHlrXTyVH?*jJtjMB7EK{Ri6ZUH*x5^#m*lrKJS$82mh>NgY~zY^`^C(IB*?C ze3r<$o}ta46tUqRFLJdDth4z1)*m&2pm*4F0Mgn13HWw4b&_=g*Z zT=R!q>rL8C95&4wZ|0M%7v}lqWc!43^5CCw4)^n{T>V3?=X$i8ICygu2jWw;dRby| zor~b$D#f;n1MOqGpxwlw;sZLbCO+7YYF=lKM-A!7*l?c<%2glSk|Ykan>f@gw(kwv zdLi$)G%Rlz`p(>Nj~7AzFz~)T?IsT1@9py}TQ8(Ov<&V`%P!iUx2@v9@@IXZ-Nd2d zNyUNqELzjp-q1R9B!(M@pj`}HA80pm==#f1x<6^_1)l4*neL&wp(QQ*F@u~@4fnVi z;Gpk|p|-lcKI;SRCJsH%Dh|YF>C&a)iayBLaN`j44`CcQFCY%In>ZvE>$pjLiajq^ z?7sgXVb94PU2n>VZ+u4_Xg6`Fu2vj~PqB6sEAMA`h=F<1$_v4Pb`uA_mq2`$)YdmN zCx(8i#mEoQhAkx)#ow+4ooYy`)W_ z55K2_FA(AT34GtT=I}BdPjbLvZ*253|D5A_^B=CTjzP@ZJz?0L3w_MV$;p4kLf@vw?66}>USg(8})kuLzb^n`JugM#qWgX`X*@Im}!-? zj{c7Cgc1q$@scv?hF(&UjN5INmWjp+{Z449Xc=WSK;L%Ya(*W?A(?0U;rD*{ejVEx zkQ%T(l}`S?+W*0ajUSB{0M3iMDARA@8F{PAkkQ_P@BJueuKxpn?Z3ZRKS7 z37ZwIwX0XluL4i5U)NUGI@!t(r&qtOv3W)Fq~>L3d+s&lERD937u)YyP!YzMP3Pmw z-Gg^1FT5wq_hR{;Y|U*tZg9Nid(M2{J^J4I;8V^of%jq`l!m2WzR>q%5&tzBn>gIZ zJzS%_ozUBiS~pVGqv8hryIWoQT->9tN%;SX5Ah&AnQtmS#4Y+BHs43)`@~du@48!O zGED#fCM5cePtALMj6chs5k7lmk{hL?hW*b8u};En93SRqe1wE?e`oofBp`E7yhh$4 zj+t-gv2PX?{aoo+)UM7hTmJuSGEKYJ`dzmxz2{5n10S5@C7ttF-e&@4gM2&w-K`_M zcf~oMzm-NgK5?Mk#DOft2jBY};!lqmRm1(gz>{Ky{q7d)5$B;DU)TCVJW#1HZn9mG z9{8EtHO%>>8RsmGT)AktXXr9?82?bKNBoSX`8<}U9KrugQrhVk5obF@yOnl&TfpOa zXt#2|%%y2KlRU3$!R~TZo!_H3%1~nx{|H-y?S)WU47Zp-hFlV3G!XgQQl7si|WHjNjwbM{ws#&>M1rnT84N#*|Vz9 zubAKGvF*qIeV#kDJ+YlhSHGF|=wV$zJpg$T^xfLkud zdHxHyZ{)2m!))5B|6R}LO7dyB2GfA8=BOLEWhE8jgm0GMUgmDajd<=Rv;lE5?J>{q z#bid$`KA1`%#<^(cTflGq7DY z8?M)L^Bieo8|9l|vtOBU`|S4|*feMN<=@@-%6_-ZcG(IG54<0>IUV`F-%UHC>o(#s zQWO_r_d?-YDhsy6yoScK_kokVMD>E%C!M@xt~~CTd~%yS5S`rK+%$Pkx@}c^bIW9J z&FYqAYgQ!YH8;v@43j14cZL2Ts)-<&@v^S>f zCoOA~d~6QM&EFsG?P}V_8=-Yue2e@p2G=26mvm;e{c&Cu{k|2ym&El7bN_P3r~0iy zUh3ErbAXWJd`O6y;L`E4TiPerB@kkq9TMVPm+UIz9M&b-0@o!K_o!Xj4c5LB^c+r& z^*4P>>E3tL=X{)We?D&SBY$w)|GH$)7}q7^Of6Hp_@6is7as@9Kz!aQ>k`%@u1mVU zXX}l{17jHaH?}L{82J8NF=J_&yW)FK>+8D^b7kWsoCFP#m!CL0^^J$mm(SW~zATrt zCtqHf<$ss($`_~E)-n?A2F=Q6Um3sWly5zJzN`l_$z1L9lF475+O*flj;F$ZO1u5* z75m(c_>CXCH2KQ+#ylwPwjA3mReBc5EB4BXFed+QR~!F37eL$sIclKggQ%L@J94%Q{KGrBGz9$c4f z&Te__+*>+#;oR9LB^E5II&p4jT@pM`%J&Ru&9byz6%50=WKMIdyon+wgjcmK#Dk?- zi>gD#IM@hID&Pt~Ps+V6DSh8+qdxH;op(>Lel$&t3wWNybqLobz4rU;ET2;Qy;uLa zlKoyc*C*6_N$Fqv?Srkz~*#NcG(8GC?_oifS6_E(QqedfXc9DMW!(Vc-t>grP8F(_#DNxyAhLRD{Gq zAJ&nS=Q^_VM_MnK4)Ql}yEp3Wza8sH*^7AaiN~)>0^fw-OFX%b?ESIgOWe_Z2E;eI zZj8o7erv2FTb|H-w%Gi7-dp#4D53?(fNw1|Q{- z5}$ggm-aC|SMO~tGkv}8@6bUX9raQV_3}Q`o9(}Dl1(jNe%D6c=kF#lP9J)+5@CJe zdb;-~S}v?tTulu_h?L`R2kU9t8C_2k53Z*-XZP-6 zcFyyec+MBBr}Lf99MI|e@~`2 z&+n?dyKnatW$91)zt8)$SHAuE4aq0}SoyiCOt*~6a;cjiTeJZoo-gEj+Kpp9%{bT7 zW4t}2-^BStuBZ1Ia6R4mEA3Y*{#X6PSpEJ2{pv^c`(8DB>-!(*pRj%+o$Dvw*WAAy zp7Ry9o~GTzf%X%h?SDNzU)GVMF%)~_Xq@AtK42Zmdc<{P&vmUvhOCHSzQcA!I{hcF zo18r5f?GF?zWp#W@0~X9xa3oB++2CxNe7rVk)1K+fn$zJC#S#qr%K42KK{-P-XF3X zZrFLcjH$AY6ZvCArc?NE|1{C{jL1U<@lm4pdeJq_$~UF|p88DXrtAm$zLtXgVekKH z^6yV{cE9wm!@4C8-T!X*b247lnf&%`2P7pA$x+9bZ`knsr&7B#KD|Nmu;FL_o|yW= z{QsBz&6Fusl837M=6#_u`PVO3W`A|FoFjha+pjLW^uc?Ver)DN6Hbu)UO&C!oOeC+ z^vL+Et1tiM#`pgE=4|~}_nI{`;XU-1F+Z;w``*q}vHe7`_`SH#{Nx92ePzSpqfg&Z zQvUS~x9n4!`rWn13pSoPMUihFg!{!f^xUW$dX;zw8D+uw!)udYJC4u!F1h5h58i#p z|IVCz((jXBf9Zt{dq4hocX%C%^Xc2uIx;wan0ZRSn`hdSV8HfsfyE~A|FnN*JL7sU zUwbkz%0KACdXMs4?{)o7^)Vf;_co_b_3l{jMb~@8lk2_GC+&D@%Z=;3y!b}fchR^2 zzcto-tS5p0)~)xlu*u@Ybx!FY6gT3@bxvN~r0?Dq*EzI<>m1InXfM|}`Rxiy#1Cx; z>m1q{UFQ%Fu5&hLx4bwo#C6W_pJ#N|Ia}yFqmGXkds}Xu!{3qS??zuHcw-Ds9Bse% zeX_PgzwX(<(k0W5^uK{&eouO-yaTARA>KdQ@#W9zr~YE&z3NxLsDAbcO)uCF`Af+) zvAae*Tau7tjOaCU=oT8rwS@SdP3Lk6BL6iuj$64L<;X|5Eam9?!U>ZJ%8`$9i9e|w z)JHMoA7RRok8&9+M}2{uhA2lq%Jo<|>Z6?JonV5LBOm2bPisD@k8;nJgyqObxlSub zeU$UOokI4Jk8<8KnjZC0?%9&C9Qi0$W96uiaz{k+Nj}PDtsM0Qa^dvIN4bQppVUV= z*>Oj83d+y&Q7&WS)JM4^O2TsFqg;=bW4e^PEf$s|ALYnLeT?503+$U9M7FalBn$(( zY`Y^r>nZD9OW%2O}Xr95$={p6>7kCmrh;>UU&O`rUful}p%pL&Tq>vvS1{FKjHdFo}l zl#k}0{FJYFUel*u+D-Xr`sAm4r~CxVFn#h}^*2qQdYSKN z|H1UhPx&q@PraVacRqRYQ$F!`O`m$1?|ky)r+kN%r(ViO`!VL9{FL|Xe1UqIZa#VP zQ@+K@Q!nxFvHftg{g9vXJyxE2iGMzM@>8Drsh9cAC68S;&WpJ3TpDw~Vk6oj{U_T~ z!p;kr-j?|N>}PfQIebf)^JCn}+)=mEm%fC~8-;Q<@2k&LYf%pvlOI}(M#mYy^bFlGT-?4Ia zus+ak;!t7h3-KxT`|!h!L$2>0=E8w?69=Ei){A$-@7r~X(d<_)lrZKtsn^2&!x*9A zIYjJ~zkgVQ;xbv!yI{5ndZktU<9cVH|9oGz%rId;3VQH9Y-yG5T_+?Sb}@}C4xDX2e4bKa=ZS1*Kx*Ljl+E%irJT#F z`r(q151s$@gJw51H@4S)8K#@9dAb|Gv5YcPtg>@F(Y>y`4!M1CRC4S_8*1A)pifUAkN5E%xaVY-en{VeQlX-9Lww5x&g(e!Xx5{3FF~ z*pHW^MvCvoPZb*Dr`h}BNuNGq!~@=4ajb{G6}w=-^>FW=YFA?4$a)`&#C4S@JzJ_i z@WFbRbk6&GMug?xDeGa{O&m&hQXGg+vFo^E1JK9b-Ht&pqC-KG1IBkQ${p z5TEURJuEAXHw(dmb`yt|(TW4{+1}T~@}2Gf6oLcoCJvoDD-Oh`*xv#0p9L3Hw~G@l z1P9tp95(HuI1ry=?I>2hI0PVFSpPt~iG#PB;y`@1_usWHw11%8#Gzt$#ew(~`@0Uq zUmxcDyO4H4yNN^19*P6;+1`Jz)$>05Mj<%RZsO1}MsXlM+xzde%Fd{%57>XhUPIJz z{y@8l1LvE>XM6u0!hHQC`#<79yNLtwB0k&u?+_L;f9MgTxh~;;Zt32(f3ScA`?;^* z*e8xS{s1;0gOC&+J=h?%#b~ZSv3efAYa|zjTk_kxAYs^5r7)rtpEkQ*?by;-?Mhs5obTQ@y{c^GwXs; zovC8i+r{Gd{|-(i583m|4flNRkPSE9KDPVG#rF#?>QHuDYd;q?4Epsdv0oPs@8|M; z2F;DMg5MsLJbS|QWcy)nRFVe2UanEz-G&5x+kwmZyB>J|fbECxA8?<8?F@}{p!O8D z9nZb++=F}c(Ri49pxCzdJ>?*;i)RJl{2}yL*!Lx#(S2Xy9_;((?yr~v&T=fRI%RHR z-hzd5NwogtHEpf>j%hU;@H>ZeeC!iQF5B>YR0@bq~Q*9&Zl~RwJTE=o;Mi9IsS3{r5wlK zO$UYLkyX=QoI2`--1Cm;^E@P$pBC|%)c^?V%`q_6>9y|MpdoQ2!)${=mm;U#ivvY87hBWZGjLispxxTNC zc?a#}yo3D^@$lyzdHWGJ<>)*k8h3dI4!>RI9mF#_?;!5}ykj%?CIqg$^Nt+fug6yo2)$&O7-273U+-^T~X!>d!xHwZ1cbPrtrw)*(ObM{~YwkrC01{jNpk zc4?cKSA0W!JWqAwpt*6}R~L(27CSkHwfxe}%saXc(f+MxVtC#_O;Mlo4$5)fQ86Jb zFIltwvx?-;!KWdH9N;ClzqcdF=mTE1g2Bk~;s z%JVx0i|ls{I;NkSJS;oH|Bk`a-@PRH{%^(o?-;DT;`|4mP2HayE#EN^9UJy~;FS$m zcO2Nw?-;bVyi)ned*jJe_iHj=?D$sd&+|6?@#nKE-#l?QlqW8n@jC`b*zXv)>wfh0!?W(!ali0+M|ji=X}_cW8?8RLbsqWbM8N z&%5#cD9%U7f5Uj)4`&?ysKf6Y)PBbo#YoOOAkR2xZrq)B+*aVcqjZw?Z>j0wd4p>1 z|DW>?%5mP&F(oV?%sckPCoyt3e{GquHwXNkkKB^8#Q`FhOzm;6r3HQxmv(#L+wKIgW43GccAR?ykU}*zli#-Ue32h_d9O=?dMWHgAEi)L%Bv} zw`@HBeh1qR=N(;BwLP(&1@n%4?I}l2w}W{H?c}_J{Sfg8<{gFD9i3-H<2f+OLwdW+ zJBVj=-a*`hdB?!`CIqJ)^A4>nTVvkA@7wTuHvGO#X^ZU#p3?WTqSbZjlIce-O@Cxf zx~VSh-b4TDy3%7*Pw(;SSD#?@&Q(8S{hE~;&;5NH^g`Nq>)U`q3YZrpB+7IymoW0s zV$+piPDeTNQEro!qrN~`PxDibe3Yx0q4}pi%0<6#Lq5uNSUKtonK%26NX@O>NL&Gg7exzgh_J?f(zzHj5ok&kjM zR*w28=Xo!gD#rB4N4ZT_j`}F~Y)M#-e3YxO^^^K2cTzkoM?T7RSUKtoL#m+9t{CqLy|tUUD+ zzi9hq{UJZ)d#pV562E-%~Iw>Mgan z=aVNtjC3ng^C>Fa?Y#Hd>Nyq!uuC9e) z`>ZN&(>$fuyia}954=xDx_|C>epvpU@;;qs?IsQt3ls<9Q|$Y2#mciBhw9Ih`cuez z0koSqu)YwV?freaLccFVyNLsFCqCQz`*c5(zG!pxp+}5nzvAyJMf#UuU+JKK=RTK4 z*9sct{Tb{HRQUlwS>sicTXoKMmnIMr&atQ6jQIbh6U%p&$47)kwuS$g} z_)eFehYr(owI1)Fm|&q4%gDWBEx+n=Xq$% zXF6>AiOy%(&Vu<2`?uVtnE4FempQ3w$%&B~x(&P%lRML-wokD?u1-R6KKfP}j=Zfg zpW*n-@j6kX{W{0-=)Mv6p|~GI%X0NY-Sfv5JYJtH24XyZS?UnZhq!Uj+<0()Wc27y z$M(dz)!5F$!#2b`xqkM8YFFya@ObO;xM7Zal;gOUJv}TRjC&Iw&%Z7Sk8|?7D(n+X z&BmApH$`mNQ~dK$*y2EE96s(3cHG0eM6TnwM>{y~5f|DEDINFn*%j`0HI2d02E*%G zfN<_{Z!`7HQIdPyoA}1>Qx1~}?ilyNh@fhsZs;Wq)wmtw9@|fJ++#Zn#=U&)Ns-(! z?%66OUNG*3`>@oWA@qM(r*fR*xX1GZ91r=tg6sK;JkM=&jeAf0{=kCAJ>(Vd zTyWfT<74bNfcvF#aome}@%TycSELQbydQ}z1C4tvwK`s9mWRi!d>8>Ayx&DRo_F%< z!t%(Pjt`R#$fYYNvCgdL{S50&^E=-1#f3;*$2sVDMJ|kadt18^W*k25Z)@kB0y~%f zmt-%83){=_mw0mgW%&?y=p6`OjDh_V8w_nQywQ|$kH4F#_l}a>H2!uq=(t(Y6dpe{rT+g>pR+=y9M_#)XNTp3b?1~jid}d9Lej(dns2`q_q{E& z-%2|;?hzN-3q*C?%V$?{<5scb<`C+eK~MkX9`|l8z3GNv8b_pTFagXgMI_|NZ z1>;`6_M~cetUCjEgLS7}h}c`jjC(vc&vWvZiB3Db80|byALK$qOP3sVhshu{fzp#&&{K@g!5$x@(=Ybfrw4#atR_2H8zf0 zxg6!lN4YHJ==;LqbMxe*T%uL;Pkj`No|`8hElZ9C^v2Z@gM>*CP>I>w;`6M6Z z$VYvQ-)Ji)aG4;)tj!nCRaUG~T*%LIWVx_jQ=a^k@3ivNOL^iIl_x*tOV?`p)XQ{< zTU4I>l+Rds>Sel=r(MiH`6=IP<*AqTBZ@!e$xr#3b+%qvJxo7Z4wNT9h<$& z%PE?F@>4#wUel*uKi_%e$xrz%D^I<&pLRs?CqLyA=V)HN;dZPI!Kjk~DJoQq( zCQts!PkGPwr_`HZf0Rd_{FHC8^3+TG@}*CH%CkSGUY2`4dGb@9_)stN@7Dv%fck@d zQjQy3r*)pM_)`zdjqNbnp2)W)e5}ic@;fRea>8e8op&N0#HZ_0#fP}DUJ@sk7t5Wv zocpWS`ki;W@88`nEhD@GesA#eQeM9lChik6{&$-Q;=Rs&ocF#lwoe?t2fx|x4QAA? zO&<%Fzg6w^epKm+3)M&cL0Y8qd@Ju$?xfb*rncqHt*aB&t<5dz*7k;U8}Ak3pVE+C zH?6)9&aK09mG?9MeCw?_k{}MWn>dh__)MFVfGI7_t?h}HAs{i_IEb7Y zaKL%1YFm%E{*Trt^#5l4|G`N)zXMh5`n_2B0@|su+Bui#ppZ$9zq_Q$A(-H&@0{3= zmT%v?fb=t>bbx+h%kH0q^S<@YTVbagbwe-2;P~8GZHj)6L3#TBPl%T2_ZXg)?|4T! z3#H|*Q&DZj#B+a-0sG!;KhgC++nK-q&)c3fUuONECyU$sd8<769x8dX72F#8-kcwB zzQFZ3=Mnxq&dw(}FXKFoHpT9}DaZ4_tNPKZWB%{18PTVH{YCTryPKr$U_J$h`GOnA z?~pUTzr7E>n78xJ3**nnWj^KIE?Xl5?R!^TuJeG3>vGQ*yvr=z`Wz=okB*Z_AFkN> z!h)7&RWwZh%e*i9<7B@10@m2X@1qh%pXXf>#&KsM={Pw#=Qz3P_HQTHQ9 zQiLIg{uBKL&YC?XH~%CT<3F)+l+(UYW%F~M1QD(Ige`Ad?l?O>Q2yk$IJ{FsfBgo} zyIJb*KQ?%o2l~}xxb_SE~Z!vpeS@J*BF{RJ>Z4&6vT(;DSEH8<7LHVI-dXUE58cRD6j$y1LEddynAw(}#nE5Z{3KcR&MXaIAM4)Bm_fy84havX%{X zCX>W7L;N+yl&kt`&F3cTd){03yS6FG8PorQgn@UE4~dAIwOD=qUsJ_c=aOYPiwEVA z5+>@QUdk~&SMO~tGkv}Jz9R~~UC?XG6@`KfWUo>DSpK^TEnLo-thNvMh5ep8%h4_G zpnRnqi~K!z*ui|G^M)N=9kw1=`*s&v*bX7&bf{P7&e2=&(GOfaOXK&)bgyr=CB{K7G<|QtqNWvf?w}_ytX4$EVZ|+K2IGGj?>#>2}F) zW~1l5I$PL7aX0^aNa`73aP!YN@{jw0!~0F=&e3-;`sY93L&yRmA=oveMC`J5aGlC| z4DE%)z;@*tBMPA<1PAaH!i&5|`4Uy24RwBa@7)KBe4?uC;l+}Nu)AfCv-{BweDn2( zKlUoHNFA~SCd+mLE z&*a9~_hgk?;w=_lwjp~v?0r?otHjsT58sq|`wezn{<8WQA9{s}bgol7J{y)_*wC~p zQQK6X;18A#YFAr+52d~#^29%yv#lTJer~S5hd9t~;*kBE;y`>BrQ22(lhfhGVV)RY z2oAKHIP`vAaUeeUo=KuD-Ht*XWK}TmEnaqZx~{z#B#W0V1P9tp91=Gv4#a0pYb`$U zF=RK~I22kRXg6`F{(|B_d}cQ{wY9g_$`8H`r8aopaN|(u_ibo5amd`PI1rz?%a=>N z9vTLyM8k~(zHf7D467e^6=9<0ANxt#O&q#96$j!ozqxtU&`}tE9P+gb)_3ASyNN^3 zEs6v2sjihrz;%u3#Db>wbZc#0dqZw9B4OjNZqD55TAF-cj0I^acH?+aUed$e%Gy7`5{$8M<`$aKo+(O+D#lf zzoa-2pLfc4;b=E;*ksoq#OIyxT{x_>Xg6_SeIY)2Ho8$(TSFT?Ri0Xh$KTw%x(C^^ z>r{RpFS=eGAuPHdS&{R3AXL!V_1s1ezZdU(AFur864~?hgl>L6p6mts1AiY6>v6b| z=It@;_Jm!&@8i+V=)Mv02=UetSiOQj}NOJVT6f)+{6*0Uht z9HFJNm)515(q4P*inJ%oA+khe`CO>tBw1y@YWE z$eKOw$ew&A-V-~)OBg=o94S&)dx?_M;`I_5A%C8?uletJr^{2IcY9?*$ykZe-hSRL zHq1SA`j(u->pVM+?0WPA7Rd4fRdtP&FB;)F=+<_VCoik5TeWP>@~xfF5cN-PU){1T zpRbxcd3pOeEom<`zT8-tI#b?R8881ljStc6EhaYSj-jby4KKY)+pE^ZtzRF9mfJuI z^W+HL0wJ7bkzbz?aHp5>=}X`LMx zY(5~*SqALS{P4p@Khq~aM|cPUEm1cmp)2EswdbVq ztbcQ^uWyXkcVSSs7cBC;uZZH*FIOA&2Z#a$x{k^{Poe$=i{>=9Hl1Z3Y|x+_{FzRG~%&91Iv%) z#quMNELX1PlH&?3KPw{a0m`$hWX>r!I*-xz zwx5K9yH+BHH@j+f?P}Rz_RRlD6%|vIslV)K^h=eWx?+y~R`R2Awq>_jx9suPlt@J8 z-Z>J=Ls}^L#<|eU49)i;!q-3T{=y5ZmbNqp)y-$fA)C;foO=iUt9^f$)UTiQxzFxb zi9VHllirg_?l%Jc^mMTi^i(RfD}EIo&h2>vT`Ifn{XbRCEv}c0bG=w=EZBTLPhBiM za$|izM#Z2XS$@oP#mtrimsQHxBUtKKhjGXqi*iW$nDgEfj~`IQFy}3d=kZfYZ}H_c zj`Lq|nWWTPd4I4#Z7Q_Y{-1Q3=iMOMc`p6k63&OIn~9T7J1M=su=;MqFz15at`oFf z<@1?F>aRL4GvCm0x+TtYD8G-@OF7@aK_%MCA{mAB7wa_)IJ13R3KeeqkBhos4$x!~3fe|qEQ%43d78$F|LKP-9O zNe6UKd-YGIUkK-sd7)nVfqqhg{yCt4Cchai*I3z%>NO)*%qN>ZpD(lx z1c-GmY~R}KvE8$sv)yxT$u(9qSJLj+EK5hJrkq0UJ}86!yl(|1d#0}Ow{}_;&uThj zr%#^Qvg*tS2TpIm^3UX!jn)-6?uIFypBBy|`112ooBFx=(C^HUey7*=JEuy&^R)Ck z$J%~pC)@8#vHi}-QGZKyU-aYbBGWgb&!C$l?L2NGg|vHFU&~xV+dbztBV-~T=*yK~ zruA0%l77lf2l?UU(u)tDcHNzVMc_JGbZ>0aAL|Sp(L)=U3t%sY^%jx=ZgO_V&Ii~J zuwUSw75j@IMGa}c5UgEzUvzI%{X)f06c^@itNBkJYG6I@p%vNAo!^J@H)C(^^jJ6G z_j8$k6hnyex^Xv5>HM^C9>JHNm)g|N&G(d@k1UJKM`lF&g{ih*IQffHs(y6gb24YT zHHEZ;`naQC2;*IN>@T7@ z^!tUW;X9&xo9Y+3cGqXN;aqO{SjQNBws7V7tFm`IyeL#d~^>g$6uk;H?%Y5PMwqIBx^MxK~z7UuB!nLwaIo$ROzxveFs-0ea zE<1n6d?5^P5wVVkx&#V~wg zoeM{oZ}8#he4*>LglXozSLzv~eEmX&t+z-qSHHl1fc*lW{qq@oG^c*QFg<){o9h?; zTlZ?ix!m%xmVao!5MI0IOJ~6Pk;yF;txIm)4O2QlEu2U2<>#d~^>g#>*k1^v6vPCt zR1n*m{X%qqq2gBunr5E4LiZW+^$V=G$Yrj6f&Bpc1)eEkf8kn(u-`8n6~42r^$XsQ z_3U9dms>uz=~kVuh3Dw`(qUW7)y}s5d?B1i<|UffTzSh)+p&&_V#m1Pm0}n^vCf5~ z%QyINzjZ|SMAOV`u5C4bzJ7uA7AfZH7uXN5U*K6g_7~BdO22T9ym3(yjIH!;~HjZ7{slPd}67eBp<8E{@C+&Yi)hY+ zej)r!Vq5DMdOml!Yi`txEf%ksaMU2uK|AEtFAJG|6hnx%T{rHADLok4V0fvY{*Hcu zNc8sw*OW^I&b(aumJfG*R@cv^4-ecgxb@bp!0Z>;53pZgPT5~DPJi*Ng|(~kLRiE_ z`vty}5n+4FqCAWFRwekkmWxy0{bnZF^1=hD{Asdozz^Ir=Z#OEdib)L&ph+D5M4RK zyjs8X&e1P?dc%GnZ%@9k`!aKG;>qQ6yN|tV;f8S!y~pS|w68Sz;w@)Y-q!qn6A$N+ zc?t57J3UaNc~IIl@i!~qvuINHv47jy=)da+cUAsr#<9u&cf)=r{*SX3cE8g5?1TTQ zd$)FI7JBjk{znxla-MbPs$Vxh@mOWcj~}g^)X^zr!aPTPYBqij`*zf?5JH=eY#a4!uIF7Y z&6MX8QB}}tc`m8z;N1P#qPaMC8ScAaGGs&UU3$(VM9UR9Pv1@N+I@LH6=2`AQTKDY zey8V{a;YeURYapu&rVm{8yytIcIXL=g#7si?XLHn(7rvJiwL6F6LoW(^LG=`zWye}jTQ$w(l700?JzJq8DR5K$&V?^#F^iM!KUT&);z4whVlC{ZIqVyAG(NEcDzOS;-FLoH&3vbsnQlek%FtnGi*1SMh&()ge>n_qfgO;+k zU3Zb%23fJA5_Y_N^#KNh8qxn1i&?wka(W)D6MFFJIQ7O4cFNQ(M<6 z{kkR?+d5gvI_cD1p=tR#bzEd^9S_=qq@itr{So_9_D6QC8gw5~bbmkS6t_(Q;JQf$ zb>e}!D8?T+9Y40*T$J+=%n98&C*~oXXTs;)626X?;W;Gc8(6nN5BxDU48PQd;qPg~ z@b|J|_&V1fXDDv?Fv}yIs>d+yBaXD-zsrW9hhg}5UmiS2i(&Y9?;mvJhhg~pf-H38 znPK=?Xo3#A7>55IkcAH08HT?<$U+BB48zBFT|fth48uPVWT69RhT$Isvd~c$48uPd zWTB(H7>1va3v`re0znDGFGEnmn0GP^U(wd}2*dEp<-%ReKN*I92*^T5`(_yap&$!A z?u0=b53P8c+nBl{1|yV!pq-J!U=^U0wo+m2;`YlnbNJf@2+XeWxhwl&1X#n@&L zx9i;)+Y8!|woxy}wu1JfZP<&kouKV#8~0*tBWO3;2k2S^?E-B^`v@<_wgI|btHjtY z&{pi6JjOPGcA|Zd7h`)s8__<>i?J=Bec-;h7~28b2JVZCu?-|7g8Smk+6(m_Z36ej znY9<{Jm@1q5gO|~=(di=Sm)6Wa9>=E^&M>h_r-x^@JIbO5%IVl-_cDG?(h@^@$Zr3p=ac^RWHC^@F+x>npH<%#C`swfbOvhcJ4-(0FEyo`r+`z|_`3 zFR@Y6C*794SJSEaC!PGbkNRfIMM7%($G`Df^1&I8C1vESd}`*Lt*(h<|EaTgp0sU96*hoBPNEl^4dfe}lr_Db&B|-1T+n3!g zUSGrCN2hlG!y8i0*z0}zUeG${9+=wr{ksh&0T?F$zX1Z386HZ7l$u-^sn33&q9QMzZ^aa-;=K+8=^-_)7=ejc^`$ff^N zYqE%cz;vwTC{5&kZrnLl&lyMgCy3nphd$z;}X(65H9D#PRO)^h|^@;Of z<=$@mXp`8pB_5a~pv+~j)8Dg&&9O`@v}a42v+uRRrE$-eG-n?z;B)qD$>;3L`F!r4 zt@4#%AD8=lKA*E6=+oRiTc+XcFZz7WK4gfNvU|3!Eca|lbM`-d*_5+qOFm~m)$)lQ z!M>|6+v)7tQr4kWg4TCo%#{sj&YrFEmAL!IKA)3kpXTgG`!sjYmgzcJ`FswhKFz`2 zr#WTh)10z&Y5txq?Z`NLw#bT*9Xz4g37U zr*V$J{*?XEQ0J7z_V>vD+ra_X^#UUCz?>4}51fuW<;K_Xzue3N6!UU3PtZA9x!G6H zxkR}c|8zg1+{`g_?pSX2Eij+J?i}Y82xESs^M-Qc>wKcz%nx-@nUPg`nbFBG1axnx%*bjU z$_zekSo2wCuyVs{OPRsV4XeFn217Tjn3Nej-LTHH%M7+|Sg|d0_RPvn82e$s8NTi( zmm6RAkju?pGWNZ|17G)w%Z;!5!{uh5Soeg>&EBx?1DBiqVC-i>7XCpt4F6yohM%xu z_=;Y+@yA&@d@Yf3`G*8M~Cf%-H3IRcD#8 z(G6?5WyW4Nta&Rlw!2}?f0@C-4Xcf11{*i5IFuQj7-m1m`62r`ZD+>dLH)}&?;Vtq zw*fP7#j`2mFN+P^3b|3TCKA)uiz(0)Q`+BdL2 zRa#6u^bNcx!MJ44&~VQ>LqlJo{fME)OT+^W{MH#7`VQ?^3^k5A0~+|PGc@!i+Rqqj ze581wId#m?f__=~b`lRX@LLxLE$GV)HIDusG~BZ;jy4(eKZa^(V=bM0Xs@7Y8#dH9 zXlSpXTNg(k1)8>RLp3zCUv1k;L;nSu_GtkP?HP3I;^^Bz)Bes-4Gnb!bnD{i_dwIW z&`=Ex?HzRM;^+%O(|*!W4GrxdbnD{iCqdIb)KCo#{Q>CK#nFd?rv0m-8d}2A4MnPi zzwWl{Y_7Zcod>SREx+&i>+Yj`k_k9<(Zox?QrO;n&EdN4?l~a$`S1ijr!21GZ@PzW zln>!wPnVv_f-=-g){)Mbeg}wjwu{am=H^E^9WPfxE;`6AnZ7>Ran&zpV$Qn$kFBZe zPu?qqFnL^mFnjaF2l7ZKdS07$y(ITw*H9gC9;*D?MGpOcg>;z2V}=-pGQX;EQtIlX zAM1vlclI5)*ZVJ$^VN@kJ^A}JFC;;Gxvz8Kd7qWDO`m${fzyw8)bPF9_w<;)jMumN z@YUT%T%c#YCr!F%_BU?w`kb@R-i+9VaxyA>{u?@DBI}%`2FcKzGuJ-NIh*a%oHN`$ z%{~9Ur-u_e@xHrO-;i4W{#~~0dmi_ z`!ojwpXOlY)7*3Cum$=Y?32JA={jYUL>Vn!=DB5=L|Mi})+zHO%KXyh@jj<+BvCiM zbAi|A&(CcC!uIKmvB*xruGs#s;DokuM&SC0v`^xJVF>*(9QsF|#}F11hOd|p{v12! zC(s$pUBb^Ng1J=qybw~?xmft@I{1~I0E?YpX;|}|F!|NKJYnW;Zdm6^N=N=M5qkb>6CHess>M=YsY(n#Y;{3}dX+`D^|&QP8dH z<#EoMdYqXH>lhq9;}p#O^m&rb@5VXnP%THD&y91|q4Di^kEXpk2CU10K-a zJ{~l*S#84-5C)A}8x=Md93W=dT5ZjIs;d4{0bKd7Q-6%iG{TR8NHLk(! ze^!1jb>#IQl(}D~a`xp7sRIuhnc5O-Fwf#6Nt$$`&pv4v`)lwG#S!PB$iAIq&|i<1 zPJ?*N5aUqh&KV+OE}nflXN`QCb0*2BIcJxAnsdgLfA z`s*KD5$pThE2~oFAGxU;g2#IQ{MPQDE$Q3q@mo@lesxR=wB5XEFI_EpdF+}eQafF9 zt>ODX?Bn10>t{;(YI|NxEji;qW<7HKq|ZM1=8dtwL$4cEbubM$ zRMl5LcD&K|)PiRgyz8El&{?fF`p%i~-ye^;v?OS&&k4yUA^ZG-5;u(`(s-yX=H?}d zyu|B5c}^nF`>YJvmV|9>@=VjgAPEfqxjckb5?CF#Hs+o=O9Io2PA_rKrWqXYjMOP3 zpXQXMPjkxLr*WRdeuM3fV-U(@Fs|5sZ7^wV%e=t#(`a|LpU2t?{Vbf0ErWl?hdGYU zX^MNUhdk)G5Poimd5qG_OgapMU(;2(&Uf?~9O;;sFpTktVbFEHrm{MR(&urc2jf?{ zvzF24m^v5e|147H4f?!N=QH7Fl*psbeZtQxkv`@Q*b&BkhA{`!wOjZ(ChX98M*e4- zn7iqGr?_W-m@8_Y%gp>y(=9XUtG)Vc)TQfuOnG#^reU2AgrCg?b0($hysgY%D{+p% zKER!iOV$c@`Q|)IXP|eFxhY zB=i{;=-TF#hBg(nNu_b^=V=);%*oz|J>Rj4D*SYe(`q0OTHY5Vr# z$UoOX*5){Tu8XukQG3}YwV&|fY_DjWcAXYyTSYstc{KPTj%2D-CmG0(}+?m)NBf5zt0kPqa|rR7-1#L-5PuFHpZ3VChc z5|CnmO`thzFaJ3d*F00@KI(=4{m?w$9hWswzV9Q8bl@@%>iNllk~>r}Prp0f`2l?% z73E5tr1Zq1;?_XDkEtHm7>psZ=KF!_C7tc3<@>qc5t$?MHF6y+7ae3fUpqE?)gg0a zu9T^K^z8eS$JEYD~i3ip|DD&!nkIf$WtI8D2<$KCA4u8G->i3ixTI1RH9#FjRvA_JHJ9fsKX3m^i zi|+=-`}X?p4c#B_#&@JVZ|X;HlqFTXZ{5f5?cR9&K8E(%1;6+^`Ci)d46_EB_|eK| zKzmg5z3{?!H$XPE7Vmk)`;hJ(U#jZ{t?_KU=ONz@ko?{FzB>(#?`r?!yHm6Aeg9x+ z2b}on>%iyTc2f4fBV$>}zEP3A0<`YdbFyPk+s)7pJM@xEK|ANzy6ov^H>JS$+xNb_ z9<*n_cvAMi&ulQX)U*X_K>LHF@yioVHM9dxY&;vZPwaML_Qh3SF}CTu>0aNZUznNw z;rUk^+K;bX@|dXYdv4hY*}X?xVrb(o+4#SZ?LOl8?32$cF3(^2!cm~zyP+!k`rQv0 zT=x6SDGMNb-wCnHr?Ml!Np8MhKy$$#Vp7djXxb-~Hes+6fw))_-p&hpC z#TSB>xa|CF>G%F+XzxDSYX|N0zDu%aAM^>MPs`WqJL8@!vOE9oWkd7Yg;V(AzrHg2 zK&!s*bMb|TVQA|6{J~ddFMs(wW5=!M_51;}IbXUg`^o?LyrKPe<@NV~Hv3l>Wv?Ce zEkiqd!C{{Pt^5b=+1?kjhL$Kh^AgZn()HPEAA4A3U%DUzTG=HhW#2sUenWfihkaLq zw&=!tyFa}1rG^%}ut$c1xJyft=Ex=~>!gwVtxdzpOOknU@|>VI z#LB@mNlYE=lf>RBqa@47Da$0w(kb&K%iO6ON!AUg4kcNKoVu1|U32PWl6BIlyGhnv zr;f`vx$yl3&ut4ywgsonB-v)1wv}Yta@t^$ZP00}Nw!s|O-mZurk%Dg`02MGoIWDS zKEmlslI%;+H`zWX$v(&Fo04wdWc#or`!J`k6Mfp(Iens}t9_!=ciQre`_E}P{&M_s z=7$1l;jY;ELE$NF+ngA`GBSZB9@2rD`3iEa^NsxPpoy5BL-c>|Oy|zwcgirg*1321 z*(~Ph=os<*mh*XpIj=_;PUqG7T?AcQho6gLUaM>R!k$}Veyj7|@bgK`#dRK@|2ZU{ z8R%KCamGJT;>aibgKQZ7!8Qy(VZ)e%GmQFMX6eAwbk3p&woI{f%;hoPhJNrW8sm(g z0$D=PlR{9!3He`+poHO1w_&8qF!FPVrGtlIE zL1P&8NG4N4V_W3qrS>O8~nj{#Ze zXcr8lt;_&f=#J^BZ6 zG5G8U&^L&Sv5!C>FxHT~7<|Oh?$IZRi@|3`Bn-00Q3u>v3~%DV+_fQY5mr* zOxwSHmjrDcar6t~%y&u9-a$v7AkKV)1nnAa9({l~^9>TTY0%OB#l_gJK}Xvc7h{`7 zJI8%-F}7#4aoiUdV_Qc1#(i-yv^lhCv~AoM7n3Sv+H*>L)E#j#w&f~`;J!GJOq-s? zh|u^voqI>X4UDOK_3SYBn1mE^!Cq4MJJco-hqK~({cS*plrvZ{T7P@Ez4Yps*>mDv68W62j>9zM<4AMt6x)~*Ek#D(2}6xY=k3=p~k$Q?WEz;oV@rnC(l03vCXGB82B^?E1%|I>eC$T zeVS87KFujhpXQXgPjl*qPjmO2h=IH3gt~@v8cv-|qE3S5)LmbnQ^$Rp(-wT1(`I~{ zyXSY0>- zC63i6aAg>HG7MZ9mY^R-T_7Fdgj~>raG4EbJ;E^Z?1t4AJvRi~a2LMXqGw(hMmg%* zRc+BVtG?^6WvB1=GYo!R!zx|NRAqG?tMC1jj{2$VR^`!kt@5~G=tVwJml?*oj$y3( z7{wcTmJa_&8-_p0hT&sv4q5mWHVj|)=*o?c^(A=V(?-~L6v#q{ z&-|lKV%-cne5{ud27U}~+AGj&JnRhg+v45NG)K19M=US*~pYB`pfI>Y>< z&M=H}S4_%G9Z;;wOr0VR>I>&$sU@SzP^XJ{B-LATDF zvxDq@q)1+Nk}$?w@LFeR-~-({b2bn(@LOlj5P~*}6w$}=c(g;~xQu(&nX`+K#Xald zzzE~kY`H8p27B~_sLLn=apo)}`Wf`qwqBYuiHM`mw)N7af$;{sNK0HC;b1IK8sZqA zA#YtA@nAeK)Hve77#Glj@i3qT<7Gg@SfOJ_K*QLeV@NEsGh7{6k==-1tD%qPg=%3EoZV_3hrome%xIZ{qTX);5VW*2@3&-Z|d6-a2pn z>V_uyS1WOZ&OvBmOLIe0d%D$I(b~MG#amn3=(W_=drh^g(;u2P^$f55oR+lLwq}{} zmp9g~@Y-tErt7`>+V)znG2P^~H@DX|A|T1HYp9nb8{aHFNQ zxh37&-jEiWL>uatH8$6+LRK5oMx9A?>hy{;JdlEzBq7qZt?8zAuWn82+BE)qMq0DC zvU%OA^f_KjbDOy@Hq_R))-~6sk-KzbdbKyvBrtJZx?#o2_BL;=vDO&a*4R*=ZUr7T z1W;Pj%b^gWZSAdw&x9M!O>4T6{g!6QdTaA)qygr(#x<=iE4_&m+v-{yS|pK)2Cmw= zb|rw%h6JOgwA^oQU0vHQ3JrRKxCe(w@`XcQD18(P|=7~!Xz z>QS6+UUO^v%I34$>S~3dzO{Cp>R8#ZynVgb2Jam2gY(X+Z(d&CAXQ6(wJ6jzt!adp zty*bHM1#v3YTGQeRf)@y@}&_H}@weI0dO!p)Ov{k#h|O?3vhidkA1`KD z9E1wVGCUI6#Oo;7kqcszY=L!`#S-uo2RNx3&Xg&E@?>Kul+jG1@6Mz!pR-m7{BeEl`=QY}B& zzO}J4o-LHh@E2HOzLM+iER+jySsyB;xrg}X4jOXaf`;WqTy0W7$r~kbe_yc2F}T& zLyv@u=MqId%-12GOXo670{li9sN9A~*$SkzorRs#Ub>|sefHs$BVC@&F`3RM`{DHI zQa+uHk!i3$mKg}C*lH^LdSeUDmHT4Zj2eKa9cDoVR)4UnnMw1-R6r*jj*SoQuV=Fn zS}d#mmDLZ^V%%+iO}ZlNGf8?Q8+-2wsFJ9~Bnr$Sx#&nLrfnkdiZH9*c!{mn6C$J; z^P|C#)5eYjdo~Q)(-HF<( zdnWWu`3mIg?zOk664OJtmMgUnglOAi^A>DKK1UO4B{RDtXtgRM+l zs}MKHE6EHQ*0bDPp%9QT3TGiJ35ubSya#MU`fX1&T+P zkme<*SMt3Yn;s-9#42Q}2`=sB`XqZf{93Xw6yKEU)er{@C0WqY$=ee@MSG<~6|pf& z63S##(3_t`7?;xY=+UGhlj6td;?ShPr`}6G=5k?|WQrgH>N^NFkeIN3}M~s~5^= z43|ZeK^L=0U@{iS9^fmS<=fem&P|RZ9YPS^WmMyR2%s7nu|}hHD7{0nH#=w{7pSF1 z`p`6D4Wq$Q@E+p>F{HyLFFniaeYO=yV3sF`yqGqz7y+T|_tqeTtr9wP9O!5+EXN4gSvY}MpxVSb^lx**!;HA-EnR`vlWTOIn47~~E2+t}} z2{bhtV$^dv{Vrf(=p#k;Y)UnA4ecmra%qhaT&+E=fEEDyp>2xZzLLq?dVF2s>iVc zn`n$}MH6lBg8i5lVeCt~f~*%JKHPD7H0v>553z^9O4G#pmraRr?SosH6Z6tY5HOQX z6YN-m3Dz&z0E!;@rC>~kg(01yJf+L*4W=!lLZu}?+A2W43bdO7N}|RmCEjJ8K;KDK z_xD1A9aY?k(KIczkcCH=Jd3h1hk=`GjW%DU+njvX>ua>X%rsXMBj8KYupn+vrexj( z)Zq;WsY*A!(i7Pj2a1qma%#Jy&&)ZSgrr2tfgP|mSW*UoTV%kXAWs#m@6<7oT&m3f zwu6baq;uV6ByB81!EB_)E!t|YLD9y`X}ILsd^g8S{M3wsg77$WcDR5Swahimjo6;IvF0 z`=i=21;aC;RUXwI>n`-N z=2;ge&REV;qLvpWggyt+>ONbW8F}R?bxYrod?vFmZV(~S-3X(j81I3#rZRCapclKm z&eh%7U&bg$An<4kkWA3p zXi~Z;6Etg#C$cAbH5ZJwBtq6s&=)hfrkQ@kH|r6knLsCWde~UVgV4e{C?%3H69wal zo7&sp=J{-)0Hx4W?@4wRx=ab#0-8y}&``^z^2Fk)9&H?{Lbn)(R4z%x^7r*GMRQBb z*hHj42o+hQ{*Fp!3YIh$eXDdEzg-TFVdW+ZCCo(&;5Zd2vP0Zo9hwhGVO_?swlJOT3*7#|UCO3f>}d7!8_zbxD)txl zZUQYWNLob`+2$g4Bj#czNF=Nttv0*?uhY`k5`vKwaxl)>1-LZ^PuIiXMaO( zb-4}evhOAdv{$4Tz@x7~Ikw0k zU#Z@Esy*I9u|gK0-33HUdYjQ zfFl(_4mQ6y+Zz@R@2C&)LST=JV_(IJA20Y7R4`*1p^P$7HXBA$yin@y#K0lyRUvxJNJ1IdFSJ*~pUdnHfe%55MFN*mVj|5H(jCX#%OisVjE@In6Yo<>F@4wq z!~@-;)vCGd7^Fg{&<<5X5@PSqc2Cnh!{oBvP#C6>WFm-3CVWJDGHGOrJHyP|G_-e@ zbpJFgAnB=8f<3Z#UL}sqC|^r|IbE8YF18utAtG1;y)(tPvT2OIJ`)qKPk!wn( ze3huTXb_$tmq19%q_UukS5lb*Vmz8dJQ*YeP8s~0YN(@tQAcE7guh|bu_W@x z`v&~p1nQIJDt*`hG2)hMVavm0dRHcDN$sq4*&1T3>LS`Z6PuMqycUMD*%qlIm;q0$ z&xj%DyD5H6K^HC1-fn#|znu(p+d)saXZ;e1G1W5ib}Ax85DTwGNKNK+#CU`0KJ)E4 z-JUIol5l$T8xr-2=emA-VnbYF9_+I*h|`K>`dR)W&>nbqD*pP4jWZ~Dw!nsdSw zuc{{P=`+3hBs?U>qfQ1Fnj$l&b#jOdoPM z!jBjZx_q@Buhmg~rmt49_XQR%RYq0CLeebY81{Xc)+{>*wfISse90w>mXWp4Tk9jn zN;opKQC7VsZcU#l=34Xtitpf=O@LrghmY~)G%#p{UEm0ww62%H;mvR9Xmn;+|xNGx5R4XScUP|6aLR~TACAL($ zLpz3!HY?cPWGJ%ZD0n_h)(q*TbcZ?#HJU`rYG)sYIKAP7!N&gf0>1)ScfFQvW#T`*x#%cH|F7`pkhEa^O`FB_g zym8t#(11f%{Z-k&)Su&cI|)S~EH|N`LQQl6+n;pQCY}fzQa4b$L_y`=suo}FWry%l z@Hlw_y79t;8S-q=OL1e>GAan*3i$cJh@@i#HYOuWHMvRCLgii?vaN|Nx`?5-j!3+H4?X*9)X2j2W}+f z;)u6478hYA)oj*uZG~!f46%^fJB4cRNXDyifsP)OGB^lJkOuFTO2~ka#>y(gPJlfk zrlFP0ljvX#vqMT{>Cq@*1PZlRgz&JF!h;DVIV}|N(V3C%($#m zRjm555lKg-kEL8m3-3QRA{We4Xm zP7$gvl~LMg%yFqgd%)^$-JtoLwl@486J&(yc zPj1EVAU84Xis6u9k)7J5*nQ2T{smE5f;!Rj7c&`>z~`50!2~E)Zak~e;#d~lfr%+} z2k&`dgQel%)Wcs@3~nsO0)xMg#6l;74p~VmW&rcR!}Q}o&*nnWc0m-P%i1lwCSRlZ zEsx%yYOw8-tvdfrNv)hctcJKywKxj~8AQKGoYD=v~H(S1n-B&;if>&Xm zQQSZv)|pYby8w5nzNosvJ5h`s>MPy?qMw0)@613@B`*^QO3``|UE3niHC3B0@kfd1 z%E3`FR$lqK(ekXHb|J%eNLMqgJGJ_>*($k?=jHlQluufZT#ZwYy)&k-DD%W>FBsB% zNfvp%)TYRdodI7kF^Z6uSap9AP0(KnQ5szwDO%+gLYC30Q%-rS?w}GB%@t1@G%g5Y zEK?#$EHSK~zK0e-9&-E%uXvc~v437I#c z5_|$XeD&U>V&O^|s~PI_gJ4pVUYR5+k3Z~|&tFlK&xV$*-%~0&Y+SKwj7@2|l5x_e z;Lkndxw+(5p9BD;Tu$iACB(6^Ho`K;4FuCmbgG7r2fa2TX3@#Ej9`rVRyLEB^_Gfs z#HR{5kg#n@cd30cj#XIs!8Xn2F%a-}gMpxE8T(L>QXL~^nJ{gth5J#`rMLQmxfPpF z4TSpJy@oyz!DN{+#Pt+&S!-YQB&OtgJJV9U5F`EGQ}J6h#*dDQWH+{oBBBW=c;evIhOVRP60~$)lfzK%(7wxwn08+-U9zVUu*;o3WL7P&6~(GLWVtuc!+K+0!|;Xl zda~8XdYc7-xCG$#Wqgv4Ra9;n5W(_sELZ zlL;=KY94eNLkd4{7NHULL2N)|kNFM3YpgL1JK_o{kqPLiR=RnlFnRURRtWbj(F}NS zVVznrmGZ<-iL!VzyV%k2$f#yAD(~&@1nuMGTu6d!QYRrf^@%q^9ve$8l<( z*WXxBT2tcHx+O!T90h~62W;Hyk}Pg*kQU&5pVI5hoCzxR(h~EfWed_9A19BG(p&h0 z#TlMbgq%;fi>V6<#*^)1?P)z&;-A)$CF9vumjonj`f*cd%9|hj6%B|*Gs50Ptz0mp z$9^lYF6+F^-{a%6h$hHQB}o8JjX!<5N&Zx2K@? zR?gX6`(!(`Xm7E5qNyoT!&37C18`z?VKN_NxHer}>Eme3`}zlbeHx7nF2WNAb#KB3Erv|VE@5l{we-SpQHKPCu0brDA{T&x<@ ztq@%VKqSCE#M<_Z8L3g^&S`G-Mh18LMafDp*X~2f<1GX#Qeq-gpl>$R4y=l1h~%sg zz6t*%iNBa4k7&4AA3%tCd07b7Vjg1~x_?s(#(GQx^vA)h7`2`*r|e<01Al|Nu~&6D z|Lp*i%=}8{)_j}C%>9s|Z0RLaaXIk7bkMKcnOS=@!^C8&m@PhLpF$Nn_-bY#h+bUr zFBqZ00oZmXo*hW1(`faX)t8pJUWSi>elZ{eeqB|vUDrM6$Pyo%4vO)VN>H&zwX6tPdP55y%L+1?vN}RN@}JB7%}d{k{(3f*Obme4-%Emh3(NgU0?| z?1*voH}D~(WDA_5`PiBt(kje_3Aly+vk4Per zRqtNWB!4r*w{5@=GiJZj4KP}4_aYQy9*Z_#Q*g#2CXCu(o4Xwp2H!g|cgX#+M8aBW z1>XY5){Sjcw9}o@WeG;df8s&|YTvr}J9k#9ct~J6lYZOLDU#8&+m$%~bxfg~qaNJ= zz;44{WufY<>AIXXqGV=bmeW9lq*SO(+YBE(a`Z!09l^ysV@|eNn8`$&wuq!0&)6A@ zX))qk!G-B!4sF^e;m8pG`v-TCd2$&UDMIS@rZC zGoVB>U1>H7w&Md`0n{BYrl_OSWLNLnwrDZN)s?9hRpPdkC1w%pg?Es?&3I{rXS&Ss zs+f73)LFJzv{khFF0%nOCCm`5&Uwq`pl(XJ`)RN`IQFhOIwtZ$0DkrHg$6Vrzg@r4 zbsq&XU7{|L3PJ^jxtvjh9}r#E!>+B5`aJ&#zME1$egBt94vG-#W-W7a7{?%M(jx=| zbK&V{MC{3oAzmOFk3f`0d(&-2E}iqSARO9g7fTse5o}oCv!2}>gN2tN^#m7!b>35b z$2S&1^?XyJ(*ysV9X-|U=u)`?^D;HS#sX8XjXb6yxQcm~lFKb6pLm?fc6NY_6vp0S zoRTll(5JBV@2Q$Nr!B3nGV4gb;MI;AKaLr1 z*5=IVEkgzyL^!}BMu=kFztE9DK41GbPU4yNKWm=X`@|F>A ziGkptNNf!Yxz~`WH`x_@D6jwlC3ajeSLTuAb*XMwMVuy6-S%Z0!L%T%#4SF_Pe zAF;1$Y(FQ1wSZl*dbYrzWju9w>KliAA}VaghLz^ZbDvJ#^}gy*Z&IsG z_qScyw0WxbuI`drBNVg`c5NfJey|C6AuQQt>y{A@TF%8Z6-wjimJQ12CXp;D&?3B5 zog&I5Gfw$17f;Hu1l-v^kMwK88$q}upaXJKBs`~2aHP@cbn>rLe{MZ+>7hIxqbKXn zD2yw;`Un_l$HX@-2vtR#M3=P(juh~Af4@!lYxrIjVzSd6O2XI;>DhN^iQp_3>$Ywm zGtek%oImj1dzeakE@O{;%#6I!EVv5EdQ@6YgVGWfEx;Sh1)MAKG!qzCf-uLy3wk?Q zy7DA?NiC1R@T~$f9Lf}fD*&dDbHzX@l38&*2pg+gtY~|fS?Jg)>=K0pDC0b|*L#Su z8C$T&+^K8vkv%le;kG@kk4T#8s&;v(lijdlPut%8;W|fI1x)X=M47V?5n9Cdk)E45 zgX5X8r(JgDEQ*-%7Bk*rFgp=5!D1#@%mlU*ny*K@n>j^-1A=n@6rC&9f_SMbQH-O` zO+$9@ud!V1lJ0L|5p~Ifnt|$9wuUWWHt?jKJZ>&SoK7jDn+!E@zC72@{Y<;7ZqHp| zyv~QEMY;K~jC66n|Jb*cVq74^$UE0Q3zctji?wC4E{nCGcDSke9w{#~b1f*Tq#$6I zk!L~4ZZ}L~t`!wjLbOA9N^xJ1(~9Z#`veQ8VKs2}v_e}^(xysbY>|Az6+5Sx7TpAG zNiSVMXX#MOT)XT#TVEedW-@2Wlt;Z~rJrncsQZp?W_MwV|4s&a-H)3K^QE5)5k3>L z`S({#+s%K6)EXqTVrzcipdh?Vz_%!PV_#^vY8ec(M$@$hciF8aZT{1mW#VQb-f<6P znK&DcWnx+?$PvrLOk(}%#;e_w_x-d_LzjtC1Kac!#xk*}%dG>4!LYf6 zrw324vqa;GNp?8m5_9#rf##efb_HC8w@|p7_S5U-Q~d36BfvQcwaT@%h{jk^%He5R zzBVLjxKLXQi`y09|5YF0yOq7~oc2NI%j!gYxP;GWpJ>WB@eo-e=q!FV2MFd7CkiSx?i?`b;3Wg=eYSS1CBj)W&{H@^oRd#`KBLW(IJZEi@Lgwm z*D|<-#kn>e-psNeHxMs}2wj5V)6Gd7V_>+(LgvciY8%OPGcLL|84Z1}>s2+7$$l7Q7gbzw_o$SrT7BSU- zzG$2WzpbRIs|)0|c__kWB~jfe*+sAjwAt4vF43xkfNEetfsMTyV1rB)Fz;2v)%?{k zE#rm-I&U?CB~~kUK2%Z2)n4^iy)5ApM1g>6P^!O2ru(XUct@c1j zX^~u*sO|xtHzOU`-JXD9SA({Qs8QyQ1har7E&f)0Jt)d0c0r_KTgfDA=~#aHDs2IF z;A&Qvm@gR{4%P)9uEoy6y!F4at(kmlyl-&2HcoARn%6gQa4JgcvZ@D1PBUdx0?*)B z*{o%)F>P}23u`AG9~=iSkS4!uhp6o5GXGDUZ#w$x;1cI&Ix>iFss5cMsttZ)ruAiO z@*S=2z17{-7?c+nJ=ZbWvCULZA8p%(#rkj{;rhS=X{X|`Cg4tze5+6k*UoJdQD8HwXfY#|nPNXrvg;#e5XS?KNQ&(!D zqThAhf>~2%hxo;>F#jUKKmDfOiu{YXA^cmB-?Uqf-{@1!$l$p*e@9_P*g3AQy9;{Nol>soUa%HjK%%+zs%2swHCvw?WsjvF zuetlIEaygsG%9O^#)ht^hx&cK3&=mje(3Q`l|7uep_jXn)bugvqm2(U+%qU|BxPw_ zN2>(>jihANr*^Ba)I@J)(DKnPi@P_Wofx+vyw^C4WQ=BzkCyYRg(In*w$k%snK%7{ z;O_2v+%-Zcx`RSyhqMZtHPn&LQ&ia1^V^A4+N$R_6T|$DV+7Rm8=hf$BPy$> zo;rN`R}Z56E@s_8x(3246RxHmLU@%Rbv3<8T$Q+L*~-(vztxBvoNowmBP_3Chk{{X zIKNA&ym~tn37OhGi)u4Iy@2upYB8k~Hgs4Jczn(8&8yq>5Ua;ryE7 z>io)Lm|y=5GgErMF74Crsjf>s4gA7n1HX_MW(33hDq;ls8OkpgHrOu^s=b@z9}C7& z+j3Usy1_3wN1!9+9nP;VuEVb}uEnoN`f?`XZVgtUb@jw=gMVAF9oXL5pkLHhtNpKp z`(GpUEc=FBwMo#l(o4OdV55I~7bLJRQs+_e|WK!7j9U7QGiOw1U|{`5LV+ zqiBc5%eQS6+B^r$1@pjs&;}NOUBN=I8`vG}L7qLqBK(W3k0ae)jHqZ&l=E8S9aNWZxId+Iy~_gruuZ8{%Z zK-`6-xd>bgE+Os@#9az5!+$wwg!;4|2iJ84;Z1nA5foWZTQo)+0@3!Bq`w3zUCH{g zvAYUty_)pbfNOcLal8(Hb-u5soEwPyBe)TNJJ9&v1a4+5CfM9GxLe3`E4U5Z4(U?|^r~d*FTW0r)qlj`4^1KLY=ujE})5 z;8XA!wD39jFa9sUm*6Y#HTZ_~--7SJ_k@1{KhjqH4YW{*9Rk#W2&fOivq1wG0)`Sd z3=9u7x#jpP`}jw!TnmEGFAYMU`4PJSQ)GWRt2kp5ny$& z23QlU1=a??0_%Wv!FpgMSRZTvHUy){1PqLl>WU%KQ|-pH(+xx z7K|f(GZ+shfGxn5U@I^YYz?*n+fv4M;0MNad)yt!yCc{MOad)nGMGZzsbCtI4rYLv z#Cv|Qx!XCkx!Z;Ovp_3A)N^xqKNrj+?R?N?U}L?5h`1k!8G9S^kbjw0{T;CG?zO=dU-|FPgW za6I`=04Fl$CxMf}Dd5!54&;Q-4x|n9K1{swsQ)`6N9Z?xcckCGZ>QUP-;Oizp9#(a zXM^8^bHKUaJo29pE})JJY12it`C`zB^d=sA329EJ4f=&^?L&)0+L3GHrFQ+6op$R% zWAO(Yi!tuf&=_|axZK8Nvb!R*p1U%n@fq%}qR!g5Xq>|CYU(-?XzZ@x{k7maa6NI= zw%>sNkF;+w?g-LN0h@puNp};t8QcPH1-F6Q!5!dEa2L3nzT5-u4NY|Sf&0Oqzyp-| zXYd#BAZSGLcnJ4l@JMJU_gC;}XbSWpKIvttF}R+Nocmj7DstRZMrkT@P#w$F-DCXi z%g1S}WG|(E0{@fX@8Bt*zCKO6y!;q(&)|O+JO`TS-SeSo^sh!|FW6XC$8oxQF*L*d zBQ(>!6x!Ln9NNXb5}M`y8ESQ}hGx6h$oqO|j(Y=X{>{)(_f}}0dmH=}wM(1Jb4x3e1--pvgUFLcY1 zW_f-Keg)7N-qWo}TFr^(L-W#zWV$@E;YyUdvdRXlg4MtXusT=+G_vDrUf*Gi*Cf1F zxXs3SZOZ#qc)D9Byo*~Gf3;lI(TGGF1rCJh!%E;SLX!8_3ooX(i`+;CbA7N9*Z{OJ zzZ>#9`lG^oG5&flxlwt3%bX1khuyDf$422;5YL_$Zg8V%!zQ39yf^*w>BmsUreHJh z8`5kJ##&nR4bnD)@j$Ztgs>zY->xlakM{2^!-=3R?1`2x$%rYWa8@m?bRM%wEPXSYxNt+(1YZ~dMhua7GC)>uh)~2wV z8SY^GtK-2QOF81xt&CMQ%}Qtjs|0Cww!CVu+U9veBYoS2e6v6+5HFmKI|t0A?(M-& z);8oV;^v1lHlLcaHXwarF}zpvvu$`EX0Fzr1*G2psW>L7qp;s*#dg$fEH}-COC`!oeh2uj%4u8!95q8$Gh{xlADIR3uym^;39A_ zeSC{{UP4_F@CVX;4qv#Gx-KJpIk<`bTtV6^!BybuaM4{8F1c&NTe<6ae?7PX{1Mzp ze(e!A;lDXtcDIBp?pAOc<=qaXhaZflx&m+@#5|0me2tHE5KoVq^D0e7+#QsqdAyS} zdr-HmLU$2&H_*N*y1IvV_k#Pt{oqgF0q|$=7w}-Xm%1c7mCW|>5N&xl+~*z%_q)IH zUgP;F_#1c(JPw`!PlCULr@+(T8R~o%Jcs{z@B-x|Y3qx){~-P)@G^D1LinFxB6Yq> zy4S$#;0@lt3El#4gMWc{z&yt6X54qfOWk{n+i3cwKEF@g2jJi2{Sfyf@E`mi<9-4@ z#s3-j9Q+r20loxZQTNxl-+*tycj0O7d+-DJ5qfZS?2{l|r*(%eRmWd60rkX1>)69^ zhk&8@hk@bvmjla#73y|&jdlA5vR+j;^g7y#yk7~d3|0ZFg4MtXusT=+NRL_#tP0ko z?6rtn8~h5a1J(uWfstVSI`$kOooGYCqrk7hMqpzw8f*fZz!s-$ zcn3UfUbwSxphO`Jl@R*ZD0Y| z6)Xh1f!)C#U{4@^(!>V)E@p+;4&L-nxU#7A3yBH*s;007;Mn+S}5&?Vtm6 zf=u1P#75jcw7H9RseReHLn!?aYC0s~#ap;s-BvD7diA4#+YOe~9g2eqeua0638M2Z4jZA>dGOBW*bh_i%6oI1(HMJ|n&r z9F6~X;23Z$I1U^SP5>u@lfcQ~6!1CePsKfrwn!#D9se2NOmG%B8~h%eQ@6T17o1l& z!ku3S-z4rr(8w4`pS_5-UJNb)e*l+)%Xoh|xB^@Wt^!wsYrwVOI&eL>0sIl%2yOy5 z)0SJnt>89rJGg`L?!>(d+zsvl_Y!v>xF7rpJOKU-{sJBZ4}phS$B%%&f=BBPgFfJE z`1Kc~3PAKRFLXHZhZ8#7X!0@MKTi3p*iL_>dxAD;{+}dnUg#*S%jhb^Jw^FXgJ5-n1RsGR;oqTS9pnB}r!{)C`@FQ@MW3ie_#~Oo~XLfR(q5j-gr8RN!K_okG)S>$B*o5(3{^T?@g zEDF^)(ufx}+ZZ656P^IJ09*2YD^Q@!HZYNLw+7pQZNYY6d$0qLO*u-Q9l=gu5@-SY z1ameS{}eD4Oe6htFe9?9n;9AIb|!8YAU$msuIRNDcQ%*<7BdHPBd5W?SH~)(vyTyO zUSx!u585ba0oWBR1iO)bcd!T86D$IY!Cv%l6~;6Ai{pCw|MBh&sOgvH171zpi$kZm z7&Njs{fS4k7whcAxdh{vr2Z60gLcpXBp1krpz-Onwjmcs)W0*`IzL;N=1ucY9?%7{ zAji1GaPvTAsg45e=*InuwXlTxi}*{R3?z?MaC?Z?z9T!3Y>d5;vk3oEA5}+{UVU9_ zQbr$;jls+EXa7RG)#l&3e)_nSI`;+pf&IxVx#$2~&G&)02Z4hl=eR>~4+V#T!@-rT znj`4bk>DtBH259y$576(k#nJl|Et}@-EpMVxEv2u*VE8bH}iBtkb}eD8=L_ALq}M*Ac{mII**352LHIktIY9f3)_T=` zbuRw%Xv6v7g2*^`VdNt8*I%k{FuiC_E@mbCQrZpNMbv*WxP*FJtX-VT5WW;#1}+Cz zfGfdO;A+}(4QuLJa9!k*Uuef4-1URXD=;@VL@q@x`nh(fjh;UK7`coS++Rwwmb)?H z&l)v9`@l*(7;C1i@coVz@-Uj~y?|^rqh4;Yw-~;gQ$QABG@DY9c5BL~-0zL(wF-D(* z|AH^b`z81ad=0*dTgg<##Za;=*U&rnfb4t;}{SIbsz%jK@>EA zAz&yN28M&>!17=P&;Ih}&95U!?Q75{2r1Xvxc0oDX-fwjS}z&c=E zupSr*)(0Da4Z$ezYp@a67>ov+fF>{oYzj65zX6+rv0xl%2IIj5um#u>Yy~EQt-&^6 zTd*D29_#>i1UuDVgIsbAy|^Zjm9KJ>=vNDv45omoU>cYXW`LPsXRr&H1zN#uFbC)s z$vi9fT86sHFQuPj=c$)2dmX1*KEACUU4gW_f`wo=ushfT>`>@y%n`n^FM zBtVk56i9=1&_P@$$l%`xbb&0$QAWOgxGUiA21`H@lesZ`#aoYz_H*s za6C8x$VPo4?n&U}`WqOx8<>w9n2#IWDfP>_Q)$a8oc1;V2NZuA=}ss8dB`(U`3mdTwwR zQQyV&*SkxY!#~uI;9OvYyA<~_@?H+E09R7qI;`QV@LvtCA$%>k4qOjzAnuRgMsO3* z{R-K3Zf3l00k_uQL1$;xj)s9a}VJE zGx!U5khHpoAf4x-`di@bw~*=<`V(P4^yklO@-O`FfJRRKBftUOU3!&H)1H60S zXWsd9&Lp=OHUkd)H2-y!BYRjl%6STifcex}PyG|AzX|;)N?ZdN0)~QNU^tk|JKa@S z4*&8%cDxnjf)#1oN?>KM3Ro4a21bC@!5Toa{+hUlBmb`zWlsRVBJVZaxL7Bu^XLbW z{U4;=5B^NMf7!0SE@h}~-kyFwW9rB3pSm1DZ@}i!$0*yM z|46=H5sW2%T=a4B_;53M#)G-^NpjNS&=Ujg(H*LFjDMm7hM#0?lt=T=c}?{1yj56f z*i$KROUh9hI-l4o`V{HMxQWDX4Yr9sP1~L($I}C2Ig0e^+qSsdf$f3sr^=O`{u#GJ z)St=j$h)0vT%Khe>Aml(*5VelXAB4S7RD8$jiJjd&NQ4Tuv=LOpH0;Rk__=RO?O0-nAc@QnD z-|vyupYc>^Ll5W$eY8vGo&ETif_*_FH_}!$nMwET-go=KEB24-4&a9F0Q?6=wfAZM z8{9$QU~mXH6dVQ)r%de?M^OKf;3#l(^aJ`MTNrm#NOKH0mNp&-j*tEu+WsY-%+saT zb{lE$gg4&>G%m7NEDn80xgRnHA2J5&=TLV7_1{GOjaWW74WQ29?nL4`E$$;^fR9N3 z5$Qj2qj-0cjT7f!wCNOZDmX0|m(%f|0nP;CdAd(?7XH!D$Jw~Q2j_ru!FfRU8Fd%) z#k&76Z@%vHqu6?_yolMjbdGufIQfCH|4{jo>D5Gq?rZ z3T^|pgDXN~+#S&+jPG!FCv~XKyNH*K{chZQqMtA#pU}2XXq#w4XPcrY&v)*Pc9X-8 z!JW}hnU9~FW7%b-pX-d&*Kr?p$xd=VuIv?mqOJ#`pTR3WqvX$mx|9|PBKkS&TDSf_ zCtkE(pP~E9C6Qs7p$&ONO^ufpPx%)s{e1A0yi)Jf91dzLn~T4 z#z4>7FOcvdVT2%vS8!WBnR6OY|-oI`9P;;VlH-9HZ^Yt(A4tN)A%UHjMJCn6D z2lsu(?*s5}*5G(s+{s{aBd>kDbT8W#eSU{*>>uX5p6XL5f#HaW_ z1D}Kc(m&1b7u545{;$B-<%Z=$t27LCtAf>t8_}== zW%~QdIv0EhVRm&k)ir2CBe!k!6-ZUDUX!>U`mz?T#zyGd`Vt`ZLItnJvykNV^^w33NAbecTPeh7GHb)8Bg^)v#(XXRASP z*pR4mBd{?TO?%X~O~}&(#(+)1lF$e^c~#E$YiYBF)ydC%7@zcK+rJ_0=3p!s*DxZ~ z490^A4HvSOJ)LiaWqJ$dVoUOGMY@S#Yp@O2Hnaxy$aajM@Y?jD(H$Aghp%@n_F0_` zZO8kYc)vaF4wlxRg*7^zo2?Prv0+W<*w35iduX-ro}K9DB;e)hdGMz-LoLkTWH1Fx R1&wa%>?th_&j0-P{{V-q>s|l= literal 0 HcmV?d00001 diff --git a/logo/dwlogo.mtl b/logo/dwlogo.mtl new file mode 100644 index 0000000..06fff4a --- /dev/null +++ b/logo/dwlogo.mtl @@ -0,0 +1,22 @@ +# Blender3D MTL File: dwlogo.blend +# Material Count: 2 +newmtl Material.002 +Ns 96.078431 +Ka 0.396 0.392 0.078 +Kd 0.396 0.392 0.078 +Ks 0.2 0.2 0.2 +Ni 1.000000 +d 1.000000 +illum 2 + + +newmtl Material.001 +Ns 96.078431 +Ka 0.000000 0.326 0.341 +Kd 0.000000 0.326 0.341 +Ks 0.2 0.2 0.2 +Ni 1.000000 +d 1.000000 +illum 2 + + diff --git a/logo/dwlogo.obj b/logo/dwlogo.obj new file mode 100644 index 0000000..9f0a1bf --- /dev/null +++ b/logo/dwlogo.obj @@ -0,0 +1,645 @@ +# Blender3D v245 OBJ File: dwlogo.blend +# www.blender3d.org +mtllib dwlogo.mtl +v -1.967500 3.292557 0.000000 +v -1.539864 2.771481 0.000000 +v -1.222102 2.176990 0.000000 +v -1.026424 1.531928 0.000000 +v -0.969990 1.037352 0.000000 +v -0.578603 1.035548 0.000000 +v 0.007450 -0.426248 0.000000 +v 1.376684 3.048505 0.000000 +v 2.744326 -0.341223 0.000000 +v 3.879164 2.783177 0.000000 +v 4.794436 2.784227 0.000000 +v 4.794755 3.733678 0.000000 +v -2.503128 3.729895 0.000000 +v -2.503128 3.729895 0.500000 +v 4.794755 3.733678 0.500000 +v 4.794436 2.784227 0.500000 +v 3.879164 2.783177 0.500000 +v 2.744326 -0.341223 0.500000 +v 1.376684 3.048505 0.500000 +v 0.007450 -0.426248 0.500000 +v -0.578603 1.035548 0.500000 +v -0.969990 1.037352 0.500000 +v -1.026424 1.531928 0.500000 +v -1.222102 2.176990 0.500000 +v -1.539864 2.771481 0.500000 +v -1.967500 3.292557 0.500000 +vn 0.000000 0.000000 -1.000000 +vn -0.928184 -0.372121 0.000000 +vn -0.000518 1.000000 0.000000 +vn 1.000000 -0.000336 0.000000 +vn 0.001147 -0.999999 0.000000 +vn 0.939920 -0.341396 0.000000 +vn -0.927364 -0.374160 0.000000 +vn 0.930373 -0.366615 0.000000 +vn -0.004611 -0.999989 0.000000 +vn 0.000000 0.000000 1.000000 +g Cube.005_Cube.006_Material.002 +usemtl Material.002 +s off +f 11//1 13//1 12//1 +f 8//1 1//1 13//1 +f 11//1 8//1 13//1 +f 2//1 1//1 8//1 +f 3//1 2//1 8//1 +f 6//1 3//1 8//1 +f 7//1 6//1 8//1 +f 10//1 9//1 8//1 +f 11//1 10//1 8//1 +f 6//1 4//1 3//1 +f 6//1 5//1 4//1 +f 7//2 20//2 21//2 6//2 +f 13//3 14//3 15//3 12//3 +f 12//4 15//4 16//4 11//4 +f 11//5 16//5 17//5 10//5 +f 10//6 17//6 18//6 9//6 +f 9//7 18//7 19//7 8//7 +f 8//8 19//8 20//8 7//8 +f 6//9 21//9 22//9 5//9 +f 14//10 16//10 15//10 +f 26//10 19//10 14//10 +f 19//10 16//10 14//10 +f 25//10 19//10 26//10 +f 25//10 24//10 19//10 +f 24//10 21//10 19//10 +f 21//10 20//10 19//10 +f 18//10 17//10 19//10 +f 17//10 16//10 19//10 +f 23//10 21//10 24//10 +f 22//10 21//10 23//10 +v 2.768149 -1.634091 0.000000 +v 1.384947 1.793045 0.000000 +v 0.012920 -1.618155 0.000000 +v -0.883670 0.580436 0.000000 +v -0.972935 0.581641 0.000000 +v -1.028585 0.087289 0.000000 +v -1.218865 -0.539980 0.000000 +v -1.527863 -1.118075 0.000000 +v -1.943704 -1.624779 0.000000 +v -2.450409 -2.040621 0.000000 +v -2.782750 -2.236504 0.000000 +v 4.806163 -2.230783 0.000000 +v 4.807395 2.336444 0.000000 +v 4.206083 2.335061 0.000000 +v 4.206083 2.335061 0.500000 +v 4.807395 2.336444 0.500000 +v 4.806163 -2.230783 0.500000 +v -2.782750 -2.236504 0.500000 +v -2.450409 -2.040621 0.500000 +v -1.943704 -1.624779 0.500000 +v -1.527863 -1.118075 0.500000 +v -1.218865 -0.539980 0.500000 +v -1.028585 0.087289 0.500000 +v -0.972935 0.581641 0.500000 +v -0.883670 0.580436 0.500000 +v 0.012920 -1.618155 0.500000 +v 1.384947 1.793045 0.500000 +v 2.768149 -1.634091 0.500000 +vn 0.000754 -1.000000 0.000000 +vn -0.940203 0.340614 0.000000 +vn -0.002300 0.999997 0.000000 +vn 1.000000 -0.000270 0.000000 +vn 0.013502 0.999909 0.000000 +vn 0.925965 0.377610 0.000000 +vn -0.927767 0.373159 0.000000 +vn 0.927320 0.374269 0.000000 +g Cube.004_Cube.005_Material.001 +usemtl Material.001 +s off +f 38//1 40//1 39//1 +f 38//1 27//1 40//1 +f 27//1 29//1 28//1 +f 30//1 32//1 31//1 +f 29//1 32//1 30//1 +f 29//1 33//1 32//1 +f 29//1 34//1 33//1 +f 29//1 35//1 34//1 +f 27//1 35//1 29//1 +f 27//1 36//1 35//1 +f 36//1 27//1 38//1 +f 38//1 37//1 36//1 +f 38//11 43//11 44//11 37//11 +f 27//12 54//12 41//12 40//12 +f 40//13 41//13 42//13 39//13 +f 39//14 42//14 43//14 38//14 +f 31//15 50//15 51//15 30//15 +f 30//16 51//16 52//16 29//16 +f 29//17 52//17 53//17 28//17 +f 54//18 27//18 28//18 53//18 +f 41//10 43//10 42//10 +f 54//10 43//10 41//10 +f 52//10 54//10 53//10 +f 49//10 51//10 50//10 +f 49//10 52//10 51//10 +f 48//10 52//10 49//10 +f 47//10 52//10 48//10 +f 46//10 52//10 47//10 +f 46//10 54//10 52//10 +f 45//10 54//10 46//10 +f 45//10 43//10 54//10 +f 44//10 43//10 45//10 +v -3.414269 0.996186 0.000000 +v -3.360440 0.922096 0.000000 +v -3.332140 0.834999 0.000000 +v -3.332140 0.743420 0.000000 +v -3.360440 0.656322 0.000000 +v -3.414269 0.582233 0.000000 +v -3.488358 0.528404 0.000000 +v -3.575455 0.500104 0.000000 +v -3.667035 0.500104 0.000000 +v -3.754132 0.528404 0.000000 +v -3.828222 0.582233 0.000000 +v -3.882050 0.656322 0.000000 +v -3.910350 0.743420 0.000000 +v -3.910350 0.834999 0.000000 +v -3.882050 0.922097 0.000000 +v -3.828221 0.996186 0.000000 +v -3.754131 1.050015 0.000000 +v -3.667034 1.078314 0.000000 +v -3.575454 1.078314 0.000000 +v -3.488358 1.050014 0.000000 +v -3.488358 1.050014 0.500000 +v -3.575454 1.078314 0.500000 +v -3.667034 1.078314 0.500000 +v -3.754131 1.050015 0.500000 +v -3.828221 0.996186 0.500000 +v -3.882050 0.922097 0.500000 +v -3.910350 0.834999 0.500000 +v -3.910350 0.743420 0.500000 +v -3.882050 0.656322 0.500000 +v -3.828222 0.582233 0.500000 +v -3.754132 0.528404 0.500000 +v -3.667035 0.500104 0.500000 +v -3.575455 0.500104 0.500000 +v -3.488358 0.528404 0.500000 +v -3.414269 0.582233 0.500000 +v -3.360440 0.656322 0.500000 +v -3.332140 0.743420 0.500000 +v -3.332140 0.834999 0.500000 +v -3.360440 0.922096 0.500000 +v -3.414269 0.996186 0.500000 +g Cube.003_Cube.004_Material.002 +usemtl Material.002 +s off +f 73//1 71//1 72//1 +f 74//1 71//1 73//1 +f 74//1 70//1 71//1 +f 55//1 70//1 74//1 +f 55//1 69//1 70//1 +f 69//1 55//1 56//1 +f 56//1 68//1 69//1 +f 57//1 68//1 56//1 +f 57//1 67//1 68//1 +f 58//1 67//1 57//1 +f 58//1 66//1 67//1 +f 59//1 66//1 58//1 +f 59//1 65//1 66//1 +f 60//1 65//1 59//1 +f 60//1 64//1 65//1 +f 61//1 64//1 60//1 +f 61//1 63//1 64//1 +f 62//1 63//1 61//1 +f 78//10 76//10 77//10 +f 78//10 75//10 76//10 +f 79//10 75//10 78//10 +f 79//10 94//10 75//10 +f 80//10 94//10 79//10 +f 80//10 93//10 94//10 +f 81//10 93//10 80//10 +f 81//10 92//10 93//10 +f 82//10 92//10 81//10 +f 82//10 91//10 92//10 +f 83//10 91//10 82//10 +f 83//10 90//10 91//10 +f 84//10 90//10 83//10 +f 84//10 89//10 90//10 +f 85//10 89//10 84//10 +f 85//10 88//10 89//10 +f 86//10 88//10 85//10 +f 86//10 87//10 88//10 +v -2.327900 2.981822 0.000000 +v -1.946631 2.517246 0.000000 +v -1.663324 1.987213 0.000000 +v -1.488863 1.412095 0.000000 +v -1.441604 0.586849 0.000000 +v -1.488863 0.215889 0.000000 +v -1.663323 -0.359229 0.000000 +v -1.946631 -0.889262 0.000000 +v -2.327900 -1.353839 0.000000 +v -2.792477 -1.735108 0.000000 +v -3.322510 -2.018416 0.000000 +v -3.897629 -2.192876 0.000000 +v -4.747342 -2.200104 0.000000 +v -4.747336 3.727444 0.000000 +v -3.550383 3.725241 0.000000 +v -3.322504 3.646397 0.000000 +v -2.792472 3.363088 0.000000 +v -3.110140 1.315794 0.000000 +v -2.962800 1.105371 0.000000 +v -2.943537 1.031374 0.000000 +v -2.924606 0.589536 0.000000 +v -3.027266 0.368530 0.000000 +v -3.208907 0.186889 0.000000 +v -3.441719 0.078327 0.000000 +v -3.697621 0.055938 0.000000 +v -3.945747 0.122423 0.000000 +v -4.156171 0.269763 0.000000 +v -4.303511 0.480187 0.000000 +v -4.369996 0.728313 0.000000 +v -4.347608 0.984215 0.000000 +v -4.239046 1.217027 0.000000 +v -4.057405 1.398669 0.000000 +v -3.824593 1.507231 0.000000 +v -3.568691 1.529619 0.000000 +v -3.320565 1.463135 0.000000 +v -1.442270 1.039348 0.000000 +v -1.442270 1.039348 0.500000 +v -3.320565 1.463135 0.500000 +v -3.568691 1.529619 0.500000 +v -3.824593 1.507231 0.500000 +v -4.057405 1.398669 0.500000 +v -4.239046 1.217027 0.500000 +v -4.347608 0.984215 0.500000 +v -4.369996 0.728313 0.500000 +v -4.303511 0.480187 0.500000 +v -4.156171 0.269763 0.500000 +v -3.945747 0.122423 0.500000 +v -3.697621 0.055938 0.500000 +v -3.441719 0.078327 0.500000 +v -3.208907 0.186889 0.500000 +v -3.027266 0.368530 0.500000 +v -2.924606 0.589536 0.500000 +v -2.943537 1.031374 0.500000 +v -2.962800 1.105371 0.500000 +v -3.110140 1.315794 0.500000 +v -2.792472 3.363088 0.500000 +v -3.322504 3.646397 0.500000 +v -3.550383 3.725241 0.500000 +v -4.747336 3.727444 0.500000 +v -4.747342 -2.200104 0.500000 +v -3.897629 -2.192876 0.500000 +v -3.322510 -2.018416 0.500000 +v -2.792477 -1.735108 0.500000 +v -2.327900 -1.353839 0.500000 +v -1.946631 -0.889262 0.500000 +v -1.663323 -0.359229 0.500000 +v -1.488863 0.215889 0.500000 +v -1.441604 0.586849 0.500000 +v -1.488863 1.412095 0.500000 +v -1.663324 1.987213 0.500000 +v -1.946631 2.517246 0.500000 +v -2.327900 2.981822 0.500000 +vn 0.001812 0.999998 0.000000 +vn 0.005311 -0.999986 0.000000 +vn -1.000000 0.000001 0.000000 +vn 0.001840 0.999998 0.000000 +vn 0.008506 -0.999964 0.000000 +g Cylinder.001_Cylinder.001_Material.001 +usemtl Material.001 +s off +f 124//1 107//1 108//1 +f 125//1 124//1 108//1 +f 126//1 125//1 108//1 +f 109//1 126//1 108//1 +f 110//1 126//1 109//1 +f 111//1 126//1 110//1 +f 95//1 126//1 111//1 +f 126//1 95//1 96//1 +f 127//1 126//1 96//1 +f 128//1 127//1 96//1 +f 97//1 128//1 96//1 +f 98//1 128//1 97//1 +f 98//1 129//1 128//1 +f 98//1 112//1 129//1 +f 130//1 112//1 98//1 +f 130//1 113//1 112//1 +f 130//1 114//1 113//1 +f 123//1 107//1 124//1 +f 122//1 107//1 123//1 +f 99//1 116//1 115//1 +f 100//1 116//1 99//1 +f 121//1 107//1 122//1 +f 100//1 117//1 116//1 +f 120//1 107//1 121//1 +f 101//1 117//1 100//1 +f 101//1 118//1 117//1 +f 119//1 107//1 120//1 +f 101//1 119//1 118//1 +f 101//1 107//1 119//1 +f 102//1 107//1 101//1 +f 103//1 107//1 102//1 +f 104//1 107//1 103//1 +f 105//1 107//1 104//1 +f 106//1 107//1 105//1 +f 115//19 146//19 162//19 99//19 +f 130//20 131//20 147//20 114//20 +f 107//21 154//21 153//21 108//21 +f 108//22 153//22 152//22 109//22 +f 106//23 155//23 154//23 107//23 +f 154//10 137//10 153//10 +f 137//10 136//10 153//10 +f 136//10 135//10 153//10 +f 135//10 152//10 153//10 +f 135//10 151//10 152//10 +f 135//10 150//10 151//10 +f 135//10 166//10 150//10 +f 135//10 165//10 166//10 +f 135//10 134//10 165//10 +f 134//10 133//10 165//10 +f 133//10 164//10 165//10 +f 133//10 163//10 164//10 +f 132//10 163//10 133//10 +f 149//10 163//10 132//10 +f 149//10 131//10 163//10 +f 148//10 131//10 149//10 +f 147//10 131//10 148//10 +f 154//10 138//10 137//10 +f 154//10 139//10 138//10 +f 145//10 162//10 146//10 +f 145//10 161//10 162//10 +f 154//10 140//10 139//10 +f 144//10 161//10 145//10 +f 154//10 141//10 140//10 +f 144//10 160//10 161//10 +f 143//10 160//10 144//10 +f 154//10 142//10 141//10 +f 142//10 160//10 143//10 +f 154//10 160//10 142//10 +f 154//10 159//10 160//10 +f 154//10 158//10 159//10 +f 154//10 157//10 158//10 +f 154//10 156//10 157//10 +f 154//10 155//10 156//10 +v -1.967500 3.292557 0.000000 +v -1.539864 2.771481 0.000000 +v -1.222102 2.176990 0.000000 +v -1.026424 1.531928 0.000000 +v -0.969990 1.037352 0.000000 +v -2.503128 3.729895 0.000000 +v -2.503128 3.729895 0.500000 +v -0.969990 1.037352 0.500000 +v -1.026424 1.531928 0.500000 +v -1.222102 2.176990 0.500000 +v -1.539864 2.771481 0.500000 +v -1.967500 3.292557 0.500000 +vn -0.706198 -0.707968 0.000000 +vn -0.632435 -0.774590 0.000000 +vn -0.993530 -0.113346 0.000000 +vn -0.979247 -0.202643 0.000000 +vn -0.923856 -0.382672 0.000000 +vn -0.831446 -0.555559 0.000000 +g Cube.002_Cube.003_Material.002 +usemtl Material.002 +s 1 +f 167//24 178//24 173//25 172//25 +f 171//26 174//26 175//27 170//27 +f 170//27 175//27 176//28 169//28 +f 169//28 176//28 177//29 168//29 +f 178//24 167//24 168//29 177//29 +v -3.414269 0.996186 0.000000 +v -3.360440 0.922096 0.000000 +v -3.332140 0.834999 0.000000 +v -3.332140 0.743420 0.000000 +v -3.360440 0.656322 0.000000 +v -3.414269 0.582233 0.000000 +v -3.488358 0.528404 0.000000 +v -3.575455 0.500104 0.000000 +v -3.667035 0.500104 0.000000 +v -3.754132 0.528404 0.000000 +v -3.828222 0.582233 0.000000 +v -3.882050 0.656322 0.000000 +v -3.910350 0.743420 0.000000 +v -3.910350 0.834999 0.000000 +v -3.882050 0.922097 0.000000 +v -3.828221 0.996186 0.000000 +v -3.754131 1.050015 0.000000 +v -3.667034 1.078314 0.000000 +v -3.575454 1.078314 0.000000 +v -3.488358 1.050014 0.000000 +v -3.488358 1.050014 0.500000 +v -3.575454 1.078314 0.500000 +v -3.667034 1.078314 0.500000 +v -3.754131 1.050015 0.500000 +v -3.828221 0.996186 0.500000 +v -3.882050 0.922097 0.500000 +v -3.910350 0.834999 0.500000 +v -3.910350 0.743420 0.500000 +v -3.882050 0.656322 0.500000 +v -3.828222 0.582233 0.500000 +v -3.754132 0.528404 0.500000 +v -3.667035 0.500104 0.500000 +v -3.575455 0.500104 0.500000 +v -3.488358 0.528404 0.500000 +v -3.414269 0.582233 0.500000 +v -3.360440 0.656322 0.500000 +v -3.332140 0.743420 0.500000 +v -3.332140 0.834999 0.500000 +v -3.360440 0.922096 0.500000 +v -3.414269 0.996186 0.500000 +vn 0.707083 0.707083 0.000000 +vn 0.453963 0.890988 0.000000 +vn 0.156407 0.987671 0.000000 +vn -0.156407 0.987671 0.000000 +vn -0.453963 0.890988 0.000000 +vn -0.707083 0.707083 0.000000 +vn -0.890988 0.453993 0.000000 +vn -0.987671 0.156407 0.000000 +vn -0.987671 -0.156407 0.000000 +vn -0.890988 -0.453963 0.000000 +vn -0.707083 -0.707083 0.000000 +vn -0.453963 -0.890988 0.000000 +vn -0.156407 -0.987671 0.000000 +vn 0.156407 -0.987671 0.000000 +vn 0.453963 -0.890988 0.000000 +vn 0.707083 -0.707083 0.000000 +vn 0.890988 -0.453963 0.000000 +vn 0.987671 -0.156407 0.000000 +vn 0.987671 0.156407 0.000000 +vn 0.890988 0.453963 0.000000 +g Cube.001_Cube.002_Material.002 +usemtl Material.002 +s 1 +f 218//30 179//30 198//31 199//31 +f 197//32 200//32 199//31 198//31 +f 196//33 201//33 200//32 197//32 +f 195//34 202//34 201//33 196//33 +f 194//35 203//35 202//34 195//34 +f 193//36 204//36 203//35 194//35 +f 192//37 205//37 204//36 193//36 +f 191//38 206//38 205//37 192//37 +f 190//39 207//39 206//38 191//38 +f 189//40 208//40 207//39 190//39 +f 188//41 209//41 208//40 189//40 +f 187//42 210//42 209//41 188//41 +f 186//43 211//43 210//42 187//42 +f 185//44 212//44 211//43 186//43 +f 184//45 213//45 212//44 185//44 +f 183//46 214//46 213//45 184//45 +f 182//47 215//47 214//46 183//46 +f 181//48 216//48 215//47 182//47 +f 180//49 217//49 216//48 181//48 +f 179//30 218//30 217//49 180//49 +v -0.972935 0.581641 0.000000 +v -1.028585 0.087289 0.000000 +v -1.218865 -0.539980 0.000000 +v -1.527863 -1.118075 0.000000 +v -1.943704 -1.624779 0.000000 +v -2.450409 -2.040621 0.000000 +v -2.782750 -2.236504 0.000000 +v -2.782750 -2.236504 0.500000 +v -2.450409 -2.040621 0.500000 +v -1.943704 -1.624779 0.500000 +v -1.527863 -1.118075 0.500000 +v -1.218865 -0.539980 0.500000 +v -1.028585 0.087289 0.500000 +v -0.972935 0.581641 0.500000 +vn -0.507767 0.861476 0.000000 +vn -0.572771 0.819697 0.000000 +vn -0.831446 0.555559 0.000000 +vn -0.923856 0.382672 0.000000 +vn -0.979400 0.201910 0.000000 +vn -0.993713 0.111850 0.000000 +g Cube_Cube.001_Material.001 +usemtl Material.001 +s 1 +f 225//50 226//50 227//51 224//51 +f 224//51 227//51 228//35 223//35 +f 223//35 228//35 229//52 222//52 +f 222//52 229//52 230//53 221//53 +f 221//53 230//53 231//54 220//54 +f 232//55 219//55 220//54 231//54 +v -2.327900 2.981822 0.000000 +v -1.946631 2.517246 0.000000 +v -1.663324 1.987213 0.000000 +v -1.488863 1.412095 0.000000 +v -1.441604 0.586849 0.000000 +v -1.488863 0.215889 0.000000 +v -1.663323 -0.359229 0.000000 +v -1.946631 -0.889262 0.000000 +v -2.327900 -1.353839 0.000000 +v -2.792477 -1.735108 0.000000 +v -3.322510 -2.018416 0.000000 +v -3.897629 -2.192876 0.000000 +v -3.550383 3.725241 0.000000 +v -3.322504 3.646397 0.000000 +v -2.792472 3.363088 0.000000 +v -3.110140 1.315794 0.000000 +v -2.962800 1.105371 0.000000 +v -2.943537 1.031374 0.000000 +v -2.924606 0.589536 0.000000 +v -3.027266 0.368530 0.000000 +v -3.208907 0.186889 0.000000 +v -3.441719 0.078327 0.000000 +v -3.697621 0.055938 0.000000 +v -3.945747 0.122423 0.000000 +v -4.156171 0.269763 0.000000 +v -4.303511 0.480187 0.000000 +v -4.369996 0.728313 0.000000 +v -4.347608 0.984215 0.000000 +v -4.239046 1.217027 0.000000 +v -4.057405 1.398669 0.000000 +v -3.824593 1.507231 0.000000 +v -3.568691 1.529619 0.000000 +v -3.320565 1.463135 0.000000 +v -1.442270 1.039348 0.000000 +v -1.442270 1.039348 0.500000 +v -3.320565 1.463135 0.500000 +v -3.568691 1.529619 0.500000 +v -3.824593 1.507231 0.500000 +v -4.057405 1.398669 0.500000 +v -4.239046 1.217027 0.500000 +v -4.347608 0.984215 0.500000 +v -4.369996 0.728313 0.500000 +v -4.303511 0.480187 0.500000 +v -4.156171 0.269763 0.500000 +v -3.945747 0.122423 0.500000 +v -3.697621 0.055938 0.500000 +v -3.441719 0.078327 0.500000 +v -3.208907 0.186889 0.500000 +v -3.027266 0.368530 0.500000 +v -2.924606 0.589536 0.500000 +v -2.943537 1.031374 0.500000 +v -2.962800 1.105371 0.500000 +v -3.110140 1.315794 0.500000 +v -2.792472 3.363088 0.500000 +v -3.322504 3.646397 0.500000 +v -3.550383 3.725241 0.500000 +v -3.897629 -2.192876 0.500000 +v -3.322510 -2.018416 0.500000 +v -2.792477 -1.735108 0.500000 +v -2.327900 -1.353839 0.500000 +v -1.946631 -0.889262 0.500000 +v -1.663323 -0.359229 0.500000 +v -1.488863 0.215889 0.500000 +v -1.441604 0.586849 0.500000 +v -1.488863 1.412095 0.500000 +v -1.663324 1.987213 0.500000 +v -1.946631 2.517246 0.500000 +v -2.327900 2.981822 0.500000 +vn 0.978118 0.207892 0.000000 +vn 0.992248 0.124027 0.000000 +vn -0.422590 -0.906308 0.000000 +vn -0.087130 -0.996185 0.000000 +vn 0.258797 -0.965911 0.000000 +vn 0.573565 -0.819147 0.000000 +vn 0.819147 -0.573565 0.000000 +vn 0.965911 -0.258797 0.000000 +vn 0.996185 0.087130 0.000000 +vn 0.906278 0.422590 0.000000 +vn 0.422590 0.906278 0.000000 +vn 0.087130 0.996185 0.000000 +vn -0.258797 0.965911 0.000000 +vn -0.573565 0.819147 0.000000 +vn -0.819575 0.572954 0.000000 +vn -0.906919 0.421277 0.000000 +vn -0.967742 -0.251930 0.000000 +vn -0.907804 -0.419385 0.000000 +vn 0.555559 0.831446 0.000000 +vn 0.400403 0.916318 0.000000 +vn 0.326945 0.945006 0.000000 +vn 0.382672 -0.923856 0.000000 +vn 0.290262 -0.956938 0.000000 +vn 0.555559 -0.831446 0.000000 +vn 0.831446 -0.555559 0.000000 +vn 0.923856 -0.382672 0.000000 +vn 0.977874 -0.209052 0.000000 +vn 0.991974 -0.126347 0.000000 +vn 0.923856 0.382672 0.000000 +vn 0.831446 0.555559 0.000000 +g Cylinder_Cylinder_Material.001 +usemtl Material.001 +s 1 +f 236//56 297//56 267//57 266//57 +f 248//40 285//40 268//58 265//58 +f 265//58 268//58 269//59 264//59 +f 264//59 269//59 270//60 263//60 +f 263//60 270//60 271//61 262//61 +f 262//61 271//61 272//62 261//62 +f 261//62 272//62 273//63 260//63 +f 260//63 273//63 274//64 259//64 +f 259//64 274//64 275//65 258//65 +f 258//65 275//65 276//30 257//30 +f 257//30 276//30 277//66 256//66 +f 256//66 277//66 278//67 255//67 +f 255//67 278//67 279//68 254//68 +f 254//68 279//68 280//69 253//69 +f 253//69 280//69 281//70 252//70 +f 252//70 281//70 282//71 251//71 +f 250//72 283//72 284//73 249//73 +f 249//73 284//73 285//40 248//40 +f 300//30 233//30 247//74 286//74 +f 246//75 287//75 286//74 247//74 +f 245//76 288//76 287//75 246//75 +f 243//77 290//77 289//78 244//78 +f 242//79 291//79 290//77 243//77 +f 241//45 292//45 291//79 242//79 +f 240//80 293//80 292//45 241//45 +f 239//81 294//81 293//80 240//80 +f 238//82 295//82 294//81 239//81 +f 237//83 296//83 295//82 238//82 +f 235//84 298//84 297//56 236//56 +f 234//85 299//85 298//84 235//84 +f 233//30 300//30 299//85 234//85