This commit is contained in:
2021-10-14 13:47:35 +02:00
commit 6625a8dfaa
4026 changed files with 844291 additions and 0 deletions
@@ -0,0 +1,47 @@
PROJECT(mensia-advanced-visualization)
MESSAGE(STATUS "Now building ${PROJECT_NAME} ${PROJECT_VERSION} (${OV_PROJECT_BRANCH}~${OV_PROJECT_COMMITHASH})" )
INCLUDE_DIRECTORIES("include/mensia/")
INCLUDE_DIRECTORIES("include/mensia/advanced-visualization")
FILE(GLOB_RECURSE SRC_FILES src/*.cpp src/*.hpp include/*.hpp)
INCLUDE("FindSourceRCProperties")
ADD_LIBRARY(${PROJECT_NAME}-static STATIC ${SRC_FILES})
ADD_LIBRARY(${PROJECT_NAME} SHARED EXCLUDE_FROM_ALL ${SRC_FILES})
IF(UNIX)
SET_TARGET_PROPERTIES(${PROJECT_NAME}-static PROPERTIES COMPILE_FLAGS "-fPIC")
ENDIF(UNIX)
SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
COMPILE_FLAGS "-DLMAV_Exports -DLMAV_Shared")
ADD_DEFINITIONS(-D_USE_MATH_DEFINES) # Definition for constant math as M_PI
INCLUDE("FindThirdPartyOpenGL")
INCLUDE("FindThirdPartyEigen")
# ---------------------------------
# Target macros
# Defines target operating system, architecture and compiler
# ---------------------------------
SET_BUILD_PLATFORM()
# -----------------------------
# Install files
# -----------------------------
#INSTALL(TARGETS ${PROJECT_NAME}
# RUNTIME DESTINATION ${DIST_BINDIR}
# LIBRARY DESTINATION ${DIST_LIBDIR}
# ARCHIVE DESTINATION ${DIST_LIBDIR})
INSTALL(TARGETS ${PROJECT_NAME}-static
RUNTIME DESTINATION ${DIST_BINDIR}
LIBRARY DESTINATION ${DIST_LIBDIR}
ARCHIVE DESTINATION ${DIST_LIBDIR})
INSTALL(DIRECTORY include/ DESTINATION ${DIST_INCLUDEDIR} FILES_MATCHING PATTERN "*.hpp")
ADD_SUBDIRECTORY(test)
@@ -0,0 +1,25 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "advanced-visualization/mIRenderer.hpp"
#include "advanced-visualization/mCRendererContext.hpp"
#include "advanced-visualization/mCVertex.hpp"
@@ -0,0 +1,173 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "m_defines.hpp"
#include <cstdint>
#include <string>
#include <cstdlib> // size_t for unix
#include <vector>
#include "mCVertex.hpp"
#include <map>
namespace OpenViBE {
namespace AdvancedVisualization {
class LMAV_API CRendererContext
{
public:
enum class EDataType { Matrix, Signal, Spectrum, TimeFrequency };
CRendererContext() { clear(); }
explicit CRendererContext(CRendererContext* parentCtx);
~CRendererContext() = default;
void clear();
void setParentRendererContext(CRendererContext* ctx) { m_parentCtx = ctx; }
void clearChannelInfo();
void addChannel(const std::string& name, float x = 0, float y = 0, float z = 0);
void selectChannel(const size_t index);
void unselectChannel(const size_t index);
void sortSelectedChannel(const size_t mode);
void setDimensionLabel(const size_t idx1, const size_t idx2, const char* label);
size_t getDimensionLabelCount(const size_t index) const;
const char* getDimensionLabel(const size_t idx1, const size_t idx2) const;
void clearTransformInfo();
void scaleBy(const float scale) { m_scale *= scale; }
void setScale(const float scale) { m_scale = scale; }
void zoomBy(const float zoom) { m_zoom *= zoom; }
void rotateByX(const float rotation) { m_rotationX += rotation; }
void rotateByY(const float rotation) { m_rotationY += rotation; }
void setTranslucency(const float translucency) { m_translucency = translucency; }
void setAspect(const float aspect) { m_aspect = aspect; }
void setSampleDuration(const uint64_t sampleDuration) { m_sampleDuration = sampleDuration; }
void setTimeScale(const size_t timeScale) { m_timeScale = timeScale; }
void setElementCount(const size_t elementCount) { m_nElement = elementCount; }
void setFlowerRingCount(const size_t flowerRingCount) { m_nFlowerRing = flowerRingCount; }
void setXYZPlotDepth(const bool hasDepth) { m_hasXYZPlotDepth = hasDepth; }
void setAxisDisplay(const bool isAxisDisplayed) { m_isAxisDisplayed = isAxisDisplayed; }
void setPositiveOnly(const bool bPositiveOnly) { m_isPositiveOnly = bPositiveOnly; }
void setTimeLocked(const bool timeLocked) { m_isTimeLocked = timeLocked; }
void setScrollModeActive(const bool scrollModeActive) { m_isScrollModeActive = scrollModeActive; }
void setScaleVisibility(const bool visibility) { m_scaleVisiblity = visibility; }
void setCheckBoardVisibility(const bool visibility) { m_checkBoardVisiblity = visibility; }
void setDataType(const EDataType type) { m_dataType = type; }
void setSpectrumFrequencyRange(const size_t range) { m_spectrumFreqRange = range; }
void setMinimumSpectrumFrequency(const size_t frequency) { m_minSpectrumFreq = frequency; }
void setMaximumSpectrumFrequency(const size_t frequency) { m_maxSpectrumFreq = frequency; }
void setStackCount(const size_t count) { m_nStack = count; }
void setStackIndex(const size_t index) { m_stackIdx = index; }
void setFaceMeshVisible(const bool visible) { m_faceMeshVisible = visible; }
void setScalpMeshVisible(const bool visible) { m_scalpMeshVisible = visible; }
void setERPPlayerActive(const bool active) { m_erpPlayerActive = active; }
void stepERPFractionBy(const float erpFraction) { m_erpFraction += erpFraction; }
std::string getChannelName(const size_t index) const;
bool getChannelLocalisation(const size_t index, float& x, float& y, float& z) const;
size_t getChannelCount() const { return m_channelName.size(); }
size_t getSelectedCount() const { return m_channelLookup.size(); }
size_t getSelected(const size_t index) const { return m_channelLookup[index]; }
bool isSelected(const size_t index) const;
float getScale() const { return m_scale * (m_parentCtx ? m_parentCtx->getScale() : 1); }
float getZoom() const { return m_zoom * (m_parentCtx ? m_parentCtx->getZoom() : 1); }
float getRotationX() const { return m_rotationX + (m_parentCtx ? m_parentCtx->getRotationX() : 0); }
float getRotationY() const { return m_rotationY + (m_parentCtx ? m_parentCtx->getRotationY() : 0); }
float getTranslucency() const { return m_translucency * (m_parentCtx ? m_parentCtx->getTranslucency() : 1); }
float getAspect() const { return m_aspect * (m_parentCtx ? m_parentCtx->getAspect() : 1); }
uint64_t getSampleDuration() const { return m_sampleDuration; }
size_t getTimeScale() const { return m_timeScale; }
size_t getElementCount() const { return m_nElement; }
size_t getFlowerRingCount() const { return m_nFlowerRing; }
bool hasXYZPlotDepth() const { return m_hasXYZPlotDepth; }
bool isAxisDisplayed() const { return m_isAxisDisplayed; }
bool isPositiveOnly() const { return m_isPositiveOnly; }
bool isTimeLocked() const { return m_isTimeLocked; }
bool isScrollModeActive() const { return m_isScrollModeActive; }
bool getScaleVisibility() const { return (m_parentCtx ? m_parentCtx->getScaleVisibility() : m_scaleVisiblity); }
bool getCheckBoardVisibility() const { return (m_parentCtx ? m_parentCtx->getCheckBoardVisibility() : m_checkBoardVisiblity); }
EDataType getDataType() const { return m_dataType; }
size_t getSpectrumFrequencyRange() const { return m_spectrumFreqRange; }
size_t getMinSpectrumFrequency() const { return m_minSpectrumFreq > m_spectrumFreqRange ? m_spectrumFreqRange : m_minSpectrumFreq; }
size_t getMaxSpectrumFrequency() const { return m_maxSpectrumFreq > m_spectrumFreqRange ? m_spectrumFreqRange : m_maxSpectrumFreq; }
size_t getStackCount() const { return m_nStack; }
size_t getStackIndex() const { return m_stackIdx; }
bool isFaceMeshVisible() const { return m_faceMeshVisible; }
bool isScalpMeshVisible() const { return m_scalpMeshVisible; }
bool isERPPlayerActive() const { return m_erpPlayerActive || (m_parentCtx ? m_parentCtx->isERPPlayerActive() : false); }
float getERPFraction() const;
static size_t getMaximumSampleCountPerDisplay() { return 1000; } /*500;*/ /*128*/
protected:
CRendererContext* m_parentCtx = nullptr;
std::vector<size_t> m_channelLookup;
std::vector<std::string> m_channelName;
std::vector<CVertex> m_channelPos;
std::map<size_t, std::vector<std::string>> m_dimLabels;
std::map<std::string, float> m_leftRightScore;
std::map<std::string, float> m_frontBackScore;
float m_scale = 1;
float m_zoom = 1;
float m_rotationX = 2;
float m_rotationY = 1;
float m_translucency = 1;
float m_aspect = 1;
uint64_t m_sampleDuration = 0;
size_t m_timeScale = 1;
size_t m_nElement = 1;
size_t m_nFlowerRing = 1;
bool m_hasXYZPlotDepth = false;
bool m_isAxisDisplayed = false;
bool m_isPositiveOnly = false;
bool m_isTimeLocked = true;
bool m_isScrollModeActive = false;
bool m_scaleVisiblity = true;
bool m_checkBoardVisiblity = false;
EDataType m_dataType = EDataType::Matrix;
size_t m_spectrumFreqRange = 0;
size_t m_minSpectrumFreq = 0;
size_t m_maxSpectrumFreq = 0;
size_t m_nStack = 1;
size_t m_stackIdx = 1;
bool m_faceMeshVisible = true;
bool m_scalpMeshVisible = true;
bool m_erpPlayerActive = false;
float m_erpFraction = 0;
};
} // namespace AdvancedVisualization
} // namespace OpenViBE
@@ -0,0 +1,95 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <cmath>
#pragma pack(1)
namespace OpenViBE {
namespace AdvancedVisualization {
class CVertex
{
public:
explicit CVertex(const double _x = 0, const double _y = 0, const double _z = 0, const double _u = 0, const double _v = 0)
: x(float(_x)), y(float(_y)), z(float(_z)), u(float(_u)), v(float(_v)) { }
CVertex(const CVertex& a, const CVertex& b)
: x(b.x - a.x), y(b.y - a.y), z(b.z - a.z), u(b.u - a.u), v(b.v - a.v) { }
float x = 0;
float y = 0;
float z = 0;
float u = 0;
float v = 0;
CVertex& normalize()
{
const float n = this->length();
if (n != 0)
{
const float in = 1.F / n;
this->x *= in;
this->y *= in;
this->z *= in;
}
return *this;
}
float length() const { return sqrt(this->sqrLength()); }
float sqrLength() const { return dot(*this, *this); }
static float dot(const CVertex& a, const CVertex& b) { return a.x * b.x + a.y * b.y + a.z * b.z; }
static CVertex cross(const CVertex& a, const CVertex& b)
{
CVertex r;
r.x = a.y * b.z - a.z * b.y;
r.y = a.z * b.x - a.x * b.z;
r.z = a.x * b.y - a.y * b.x;
return r;
}
static CVertex cross(const CVertex& a1, const CVertex& b1, const CVertex& a2, const CVertex& b2)
{
const CVertex v1(a1, b1);
const CVertex v2(a2, b2);
return cross(v1, v2);
}
static bool isOnSameSide(const CVertex& p1, const CVertex& p2, const CVertex& a, const CVertex& b)
{
const CVertex cp1 = cross(a, b, a, p1);
const CVertex cp2 = cross(a, b, a, p2);
return dot(cp1, cp2) >= 0;
}
static bool isInTriangle(const CVertex& p, const CVertex& a, const CVertex& b, const CVertex& c)
{
return isOnSameSide(p, a, b, c) && isOnSameSide(p, b, c, a) && isOnSameSide(p, c, a, b);
}
};
} // namespace AdvancedVisualization
} // namespace OpenViBE
#pragma pack()
@@ -0,0 +1,119 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "m_defines.hpp"
#include "mCRendererContext.hpp"
#include "mCVertex.hpp"
#if defined TARGET_OS_Windows
#include <windows.h>
#endif // TARGET_OS_Windows
#include <GL/gl.h>
#include <GL/glu.h>
#include <string>
#include <map>
#include <vector>
namespace OpenViBE {
namespace AdvancedVisualization {
enum class ERendererType
{
Default, Topography2D, Topography3D, Bars, Bitmap, Connectivity, Cube, Flower, Line, Loreta, Mountain, MultiLine, Slice, XYZPlot, Last
};
class LMAV_API IRenderer
{
public:
IRenderer();
IRenderer(const IRenderer&) = delete;
virtual ~IRenderer();
static IRenderer* create(const ERendererType type, const bool stimulation);
static void release(IRenderer* renderer) { delete renderer; }
void setChannelLocalisation(const char* filename) { m_channelPosFilename = filename; }
void setChannelCount(const size_t nChannel);
void setSampleCount(const size_t nSample);
void setHistoryDrawIndex(const size_t index);
void feed(const float* data);
void feed(const float* data, const size_t nSample);
void feed(const uint64_t stimDate, const uint64_t stimID) { m_stimulationHistory.emplace_back((stimDate >> 16) / 65536., stimID); }
void prefeed(const size_t nPreFeedSample);
float getSuggestedScale();
void clear(const size_t nSampleToKeep = 0);
size_t getChannelCount() const { return m_nChannel; }
size_t getSampleCount() const { return m_nSample; }
size_t getHistoryCount() const { return m_nHistory; }
size_t getHistoryIndex() const { return m_historyIdx; }
bool getSampleAtERPFraction(const float erpFraction, std::vector<float>& samples) const;
void setTimeOffset(const uint64_t offset) { m_timeOffset = offset; }
uint64_t getTimeOffset() const { return m_timeOffset; }
static void draw2DCoordinateSystem();
static void draw3DCoordinateSystem();
void drawCoordinateSystem() const { this->draw3DCoordinateSystem(); }
virtual void rebuild(const CRendererContext& /*ctx*/) { }
virtual void refresh(const CRendererContext& ctx);
virtual bool render(const CRendererContext& ctx) = 0;
virtual void clearRegionSelection() { }
virtual size_t getRegionCategoryCount() { return 0; }
virtual size_t getRegionCount(const size_t /*category*/) { return 0; }
virtual const char* getRegionCategoryName(const size_t /*category*/) { return nullptr; }
virtual const char* getRegionName(const size_t /*category*/, const size_t /*index*/) { return nullptr; }
virtual void selectRegion(const size_t /*category*/, const char* /*name*/) { }
virtual void selectRegion(const size_t /*category*/, const size_t /*index*/) { }
protected:
std::string m_channelPosFilename;
size_t m_historyIdx = 0;
size_t m_historyDrawIdx = 0;
size_t m_nHistory = 0;
size_t m_nChannel = 0;
size_t m_nSample = 1;
float m_nInverseChannel = 1.0;
float m_nInverseSample = 1.0;
size_t m_autoDecimationFactor = 1;
float m_erpFraction = 0.0;
size_t m_sampleIndexERP = 0;
uint64_t m_timeOffset = 0;
// std::map < std::string, CVertex > m_channelPos;
std::vector<std::pair<double, uint64_t>> m_stimulationHistory;
std::vector<std::vector<float>> m_history;
std::vector<std::vector<CVertex>> m_vertex;
std::vector<size_t> m_mesh;
};
} // namespace AdvancedVisualization
} // namespace OpenViBE
@@ -0,0 +1,52 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
//___________________________________________________________________//
// //
// API Definition //
//___________________________________________________________________//
// //
// Taken from
// - http://people.redhat.com/drepper/dsohowto.pdf
// - http://www.nedprod.com/programs/gccvisibility.html
#if defined LMAV_Shared
#if defined TARGET_OS_Windows
#define LMAV_API_Export __declspec(dllexport)
#define LMAV_API_Import __declspec(dllimport)
#elif defined TARGET_OS_Linux
#define LMAV_API_Export __attribute__((visibility("default")))
#define LMAV_API_Import __attribute__((visibility("default")))
#else
#define LMAV_API_Export
#define LMAV_API_Import
#endif
#else
#define LMAV_API_Export
#define LMAV_API_Import
#endif
#if defined LMAV_Exports
#define LMAV_API LMAV_API_Export
#else
#define LMAV_API LMAV_API_Import
#endif
@@ -0,0 +1,494 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
static const unsigned char SCALP_DATA[12212] = {
0x69, 0x01, 0x00, 0x00, 0x90, 0x02, 0x00, 0x00, 0xfb, 0xb6, 0x45, 0xbf, 0xc8, 0xc7, 0x80, 0x3d, 0x7c, 0xbc, 0xe3, 0x3d, 0xfa, 0x71, 0x45, 0xbf, 0x40, 0x1f,
0x70, 0x3c, 0x68, 0xc2, 0xfc, 0x3c, 0x87, 0xa8, 0x45, 0xbf, 0x88, 0x5b, 0x92, 0x3d, 0xf0, 0x57, 0x45, 0x3c, 0xb3, 0xe1, 0x1f, 0xbf, 0x28, 0x69, 0x8e, 0x3d,
0x68, 0x5f, 0x2e, 0xbf, 0xd4, 0xaf, 0x21, 0xbf, 0xc0, 0x51, 0xfb, 0x3c, 0x3b, 0x42, 0x24, 0xbf, 0x55, 0xeb, 0x1f, 0xbf, 0x80, 0x9e, 0xd4, 0xbb, 0x63, 0xbd,
0x30, 0xbf, 0x7f, 0xf9, 0x23, 0xbf, 0xec, 0xef, 0x14, 0xbe, 0xa9, 0x8e, 0x24, 0xbf, 0xc6, 0x53, 0x1e, 0xbf, 0x80, 0xa0, 0xc1, 0xbc, 0x89, 0xe3, 0x3a, 0xbf,
0x3b, 0xc4, 0x1c, 0xbf, 0x60, 0xfe, 0x28, 0xbd, 0xcc, 0xbc, 0x44, 0xbf, 0x0c, 0xfa, 0x1b, 0xbf, 0x90, 0x9e, 0xd3, 0x3d, 0x73, 0x38, 0x40, 0xbf, 0xd3, 0xe5,
0x29, 0xbf, 0x54, 0x05, 0x96, 0xbd, 0x98, 0xd6, 0x0c, 0xbf, 0x60, 0xd6, 0x2c, 0xbf, 0x70, 0x07, 0x6b, 0xbd, 0x1a, 0x9e, 0x03, 0xbf, 0x27, 0xd1, 0x32, 0xbf,
0xde, 0xc8, 0x41, 0xbe, 0xf6, 0xae, 0xef, 0xbe, 0x0d, 0x75, 0x24, 0xbf, 0x64, 0x97, 0x3c, 0xbe, 0xa4, 0x4f, 0x30, 0xbf, 0x51, 0x0e, 0x19, 0xbf, 0xb0, 0x56,
0x05, 0xbe, 0xe1, 0xeb, 0x48, 0xbf, 0x74, 0xbc, 0x3b, 0xbe, 0x34, 0x0b, 0x4a, 0x3e, 0x26, 0x05, 0x82, 0xbf, 0x1b, 0xf7, 0x68, 0xbe, 0x56, 0x2b, 0xbf, 0x3e,
0x43, 0x55, 0x7d, 0xbf, 0x25, 0xf0, 0x70, 0xbe, 0x2c, 0x67, 0x44, 0x3e, 0xb7, 0x2b, 0x81, 0xbf, 0xbe, 0x9b, 0xd0, 0xbe, 0x8c, 0x99, 0x11, 0x3f, 0xe9, 0x36,
0x2c, 0x3f, 0xe0, 0x74, 0x9b, 0xbe, 0xae, 0xa9, 0x20, 0x3f, 0x88, 0xe6, 0x32, 0x3f, 0x62, 0xc5, 0x97, 0xbe, 0x4c, 0xc1, 0x19, 0x3f, 0xf4, 0x7f, 0x37, 0x3f,
0xa6, 0x2a, 0x21, 0xbf, 0x68, 0x02, 0xde, 0x3e, 0x1c, 0x9e, 0x03, 0x3f, 0x5e, 0xb9, 0x0b, 0xbf, 0x22, 0x1f, 0x0c, 0x3f, 0x52, 0x1e, 0x11, 0x3f, 0x23, 0x4e,
0x07, 0xbf, 0x40, 0x5f, 0xfd, 0x3e, 0x09, 0xec, 0x1a, 0x3f, 0x4a, 0x30, 0x38, 0xbf, 0xb6, 0xf1, 0xc5, 0x3e, 0x7b, 0x88, 0xbd, 0x3e, 0xc4, 0x78, 0x34, 0xbf,
0xfe, 0x34, 0xab, 0x3e, 0x68, 0xb0, 0xd6, 0x3e, 0xb5, 0x9c, 0x42, 0xbf, 0x18, 0x2c, 0x59, 0x3e, 0xd1, 0xe4, 0xa2, 0x3e, 0x5e, 0xc3, 0x40, 0xbf, 0x00, 0xa7,
0x9f, 0xbd, 0x76, 0x77, 0x96, 0x3e, 0x97, 0xfe, 0x42, 0xbf, 0x20, 0x4e, 0x9a, 0xbc, 0x73, 0x74, 0x85, 0x3e, 0x8c, 0xa3, 0x3c, 0xbf, 0xc0, 0x35, 0xb8, 0x3d,
0xd0, 0x99, 0xc8, 0x3e, 0xf1, 0x67, 0x05, 0xbe, 0xc8, 0x40, 0x32, 0x3f, 0x82, 0x1a, 0x35, 0x3f, 0xeb, 0x39, 0x15, 0xbe, 0x80, 0xb0, 0x21, 0x3f, 0x06, 0x91,
0x3f, 0x3f, 0xbf, 0x3b, 0x29, 0xbe, 0xda, 0xa1, 0x2e, 0x3f, 0x60, 0x0b, 0x35, 0x3f, 0xd6, 0x71, 0x24, 0xbf, 0xc4, 0x00, 0xcb, 0x3e, 0xae, 0x34, 0x15, 0xbf,
0x70, 0xee, 0x2c, 0xbf, 0x54, 0xc5, 0x8c, 0x3e, 0x43, 0x16, 0x03, 0xbf, 0x36, 0x23, 0x24, 0xbf, 0x56, 0x3e, 0xbf, 0x3e, 0x66, 0xb1, 0x1b, 0xbf, 0x12, 0xe8,
0x37, 0xbf, 0x40, 0xc5, 0x5e, 0xbc, 0xd6, 0xb4, 0xc2, 0xbe, 0x1a, 0x65, 0x3a, 0xbf, 0x9e, 0x00, 0x08, 0xbe, 0x64, 0xaf, 0xb0, 0xbe, 0x14, 0xe9, 0x34, 0xbf,
0xb0, 0xe1, 0xa8, 0xbc, 0x4f, 0x57, 0xd3, 0xbe, 0x85, 0xa8, 0x45, 0x3f, 0x90, 0x5b, 0x92, 0x3d, 0x50, 0x58, 0x45, 0x3c, 0xf9, 0x71, 0x45, 0x3f, 0x40, 0x1f,
0x70, 0x3c, 0x98, 0xc2, 0xfc, 0x3c, 0xf9, 0xb6, 0x45, 0x3f, 0xd0, 0xc7, 0x80, 0x3d, 0x88, 0xbc, 0xe3, 0x3d, 0xc5, 0x53, 0x1e, 0x3f, 0x60, 0xa0, 0xc1, 0xbc,
0x88, 0xe3, 0x3a, 0xbf, 0x0f, 0xfa, 0x1b, 0x3f, 0x90, 0x9e, 0xd3, 0x3d, 0x73, 0x38, 0x40, 0xbf, 0x3b, 0xc4, 0x1c, 0x3f, 0x60, 0xfe, 0x28, 0xbd, 0xcc, 0xbc,
0x44, 0xbf, 0x80, 0xf9, 0x23, 0x3f, 0xe8, 0xef, 0x14, 0xbe, 0xa8, 0x8e, 0x24, 0xbf, 0x56, 0xeb, 0x1f, 0x3f, 0x80, 0x9e, 0xd4, 0xbb, 0x63, 0xbd, 0x30, 0xbf,
0xd5, 0xaf, 0x21, 0x3f, 0xe0, 0x51, 0xfb, 0x3c, 0x3a, 0x42, 0x24, 0xbf, 0xb7, 0xe1, 0x1f, 0x3f, 0x30, 0x69, 0x8e, 0x3d, 0x67, 0x5f, 0x2e, 0xbf, 0x27, 0xd1,
0x32, 0x3f, 0xdc, 0xc8, 0x41, 0xbe, 0xf2, 0xae, 0xef, 0xbe, 0x61, 0xd6, 0x2c, 0x3f, 0x70, 0x07, 0x6b, 0xbd, 0x1a, 0x9e, 0x03, 0xbf, 0xd6, 0xe5, 0x29, 0x3f,
0x50, 0x05, 0x96, 0xbd, 0x98, 0xd6, 0x0c, 0xbf, 0x52, 0x0e, 0x19, 0x3f, 0xae, 0x56, 0x05, 0xbe, 0xdf, 0xeb, 0x48, 0xbf, 0x0e, 0x75, 0x24, 0x3f, 0x62, 0x97,
0x3c, 0xbe, 0xa2, 0x4f, 0x30, 0xbf, 0x35, 0xf0, 0x70, 0x3e, 0x30, 0x67, 0x44, 0x3e, 0xb7, 0x2b, 0x81, 0xbf, 0x31, 0xf7, 0x68, 0x3e, 0x58, 0x2b, 0xbf, 0x3e,
0x41, 0x55, 0x7d, 0xbf, 0x81, 0xbc, 0x3b, 0x3e, 0x34, 0x0b, 0x4a, 0x3e, 0x26, 0x05, 0x82, 0xbf, 0x5f, 0xc5, 0x97, 0x3e, 0x4c, 0xc1, 0x19, 0x3f, 0xf6, 0x7f,
0x37, 0x3f, 0xde, 0x74, 0x9b, 0x3e, 0xb0, 0xa9, 0x20, 0x3f, 0x8a, 0xe6, 0x32, 0x3f, 0xbd, 0x9b, 0xd0, 0x3e, 0x8c, 0x99, 0x11, 0x3f, 0xea, 0x36, 0x2c, 0x3f,
0x23, 0x4e, 0x07, 0x3f, 0x40, 0x5f, 0xfd, 0x3e, 0x0b, 0xec, 0x1a, 0x3f, 0x5e, 0xb9, 0x0b, 0x3f, 0x22, 0x1f, 0x0c, 0x3f, 0x55, 0x1e, 0x11, 0x3f, 0xa4, 0x2a,
0x21, 0x3f, 0x68, 0x02, 0xde, 0x3e, 0x1e, 0x9e, 0x03, 0x3f, 0xb4, 0x9c, 0x42, 0x3f, 0x1c, 0x2c, 0x59, 0x3e, 0xd3, 0xe4, 0xa2, 0x3e, 0xc3, 0x78, 0x34, 0x3f,
0xfe, 0x34, 0xab, 0x3e, 0x68, 0xb0, 0xd6, 0x3e, 0x49, 0x30, 0x38, 0x3f, 0xb8, 0xf1, 0xc5, 0x3e, 0x7f, 0x88, 0xbd, 0x3e, 0x89, 0xa3, 0x3c, 0x3f, 0xc8, 0x35,
0xb8, 0x3d, 0xd2, 0x99, 0xc8, 0x3e, 0x93, 0xfe, 0x42, 0x3f, 0x00, 0x4e, 0x9a, 0xbc, 0x76, 0x74, 0x85, 0x3e, 0x58, 0xc3, 0x40, 0x3f, 0xfc, 0xa6, 0x9f, 0xbd,
0x78, 0x77, 0x96, 0x3e, 0xbf, 0x3b, 0x29, 0x3e, 0xda, 0xa1, 0x2e, 0x3f, 0x60, 0x0b, 0x35, 0x3f, 0xea, 0x39, 0x15, 0x3e, 0x82, 0xb0, 0x21, 0x3f, 0x08, 0x91,
0x3f, 0x3f, 0xf3, 0x67, 0x05, 0x3e, 0xc8, 0x40, 0x32, 0x3f, 0x84, 0x1a, 0x35, 0x3f, 0x3b, 0x23, 0x24, 0x3f, 0x58, 0x3e, 0xbf, 0x3e, 0x65, 0xb1, 0x1b, 0xbf,
0x74, 0xee, 0x2c, 0x3f, 0x54, 0xc5, 0x8c, 0x3e, 0x43, 0x16, 0x03, 0xbf, 0xda, 0x71, 0x24, 0x3f, 0xc4, 0x00, 0xcb, 0x3e, 0xad, 0x34, 0x15, 0xbf, 0x16, 0xe9,
0x34, 0x3f, 0xa0, 0xe1, 0xa8, 0xbc, 0x4a, 0x57, 0xd3, 0xbe, 0x18, 0x65, 0x3a, 0x3f, 0x9c, 0x00, 0x08, 0xbe, 0x60, 0xaf, 0xb0, 0xbe, 0x13, 0xe8, 0x37, 0x3f,
0x20, 0xc5, 0x5e, 0xbc, 0xd4, 0xb4, 0xc2, 0xbe, 0xf6, 0xca, 0x46, 0xbf, 0x00, 0xe6, 0x62, 0xba, 0x4e, 0xd4, 0x02, 0x3e, 0xa0, 0xb3, 0x47, 0xbf, 0x80, 0xac,
0xcd, 0xbc, 0xb8, 0x37, 0x47, 0x3d, 0x8c, 0x94, 0x44, 0xbf, 0x10, 0xe6, 0x75, 0x3d, 0xa5, 0xcf, 0x41, 0x3e, 0x0e, 0xbb, 0x44, 0xbf, 0x80, 0xf5, 0xa5, 0x3c,
0xf6, 0x37, 0x5c, 0x3e, 0x03, 0x20, 0x47, 0xbf, 0xa0, 0xa6, 0x82, 0xbd, 0x80, 0xdf, 0xc0, 0xbb, 0x3b, 0x55, 0x43, 0xbf, 0xf0, 0x8b, 0x74, 0xbd, 0x62, 0x91,
0xbc, 0xbd, 0xe2, 0x36, 0x1e, 0xbf, 0xd0, 0x2b, 0x4c, 0x3e, 0x4e, 0x6a, 0x3a, 0xbf, 0x70, 0xe2, 0x20, 0xbf, 0x4c, 0xbf, 0x11, 0x3e, 0x23, 0x04, 0x29, 0xbf,
0x23, 0x94, 0x27, 0xbf, 0xc0, 0xe5, 0x6f, 0x3d, 0xce, 0x1a, 0x16, 0xbf, 0x45, 0x39, 0x2a, 0xbf, 0x50, 0xb2, 0x79, 0xbe, 0xec, 0xaf, 0x10, 0xbf, 0xa6, 0x96,
0x31, 0xbf, 0xc0, 0xbd, 0xbc, 0x3d, 0xab, 0x3b, 0x00, 0xbf, 0xf6, 0xa0, 0x27, 0xbf, 0x20, 0x2b, 0x51, 0x3e, 0xd2, 0x36, 0x17, 0xbf, 0x26, 0xe3, 0x21, 0xbe,
0xa0, 0x95, 0x3f, 0x3d, 0xf2, 0x68, 0x83, 0xbf, 0x40, 0xad, 0x0c, 0xbe, 0xd8, 0x42, 0xd3, 0xbd, 0xf7, 0xbe, 0x83, 0xbf, 0x95, 0xb3, 0x75, 0xbd, 0x58, 0xa2,
0xe5, 0xbd, 0x6c, 0x4c, 0x84, 0xbf, 0x5a, 0x08, 0x86, 0xbd, 0x80, 0x14, 0x36, 0x3d, 0xae, 0xf1, 0x83, 0xbf, 0x1f, 0xf7, 0x68, 0xbe, 0xa0, 0x1a, 0x19, 0x3d,
0xd9, 0x51, 0x82, 0xbf, 0x21, 0xf7, 0x68, 0xbe, 0x74, 0xff, 0xcb, 0xbd, 0x00, 0x86, 0x82, 0xbf, 0xea, 0x50, 0xb0, 0xbe, 0x20, 0x42, 0x04, 0x3d, 0xfc, 0x40,
0x7a, 0xbf, 0x62, 0x52, 0xb2, 0xbe, 0x8c, 0xe5, 0xf8, 0xbd, 0x39, 0x0b, 0x78, 0xbf, 0x3b, 0x2d, 0xe4, 0xbe, 0xc0, 0xd7, 0xb2, 0x3c, 0x78, 0x29, 0x6e, 0xbf,
0xdf, 0x21, 0xe6, 0xbe, 0x18, 0xc8, 0x0c, 0xbe, 0xb1, 0x6a, 0x6d, 0xbf, 0xa7, 0x05, 0x0b, 0xbf, 0x60, 0x86, 0x4d, 0xbc, 0xfc, 0xf5, 0x5e, 0xbf, 0x9c, 0xb0,
0x0a, 0xbf, 0x30, 0x25, 0x00, 0xbe, 0x36, 0x9a, 0x5f, 0xbf, 0x01, 0x1f, 0x04, 0xbf, 0x58, 0xb2, 0x59, 0x3f, 0xae, 0x78, 0x90, 0x3e, 0x7e, 0x6e, 0x03, 0xbf,
0xe6, 0xda, 0x5e, 0x3f, 0x18, 0xb9, 0x73, 0x3d, 0xb5, 0x19, 0xc5, 0xbe, 0xec, 0x70, 0x78, 0x3f, 0xe8, 0x1d, 0x4d, 0x3d, 0x0c, 0xa1, 0xbd, 0xbe, 0x8e, 0x83,
0x72, 0x3f, 0x1e, 0x92, 0x8a, 0x3e, 0x98, 0x8a, 0x1a, 0xbf, 0x50, 0x80, 0x3c, 0x3f, 0x3f, 0x09, 0x8c, 0x3e, 0x34, 0xa7, 0x1e, 0xbf, 0xe8, 0x7f, 0x41, 0x3f,
0xc8, 0x3c, 0x91, 0x3d, 0x88, 0xb0, 0xc5, 0xbe, 0x9c, 0xc7, 0x71, 0x3f, 0xa0, 0xa1, 0x1f, 0xbe, 0x08, 0x58, 0x03, 0xbf, 0xc0, 0xa1, 0x56, 0x3f, 0xb0, 0xde,
0x0e, 0xbe, 0xca, 0x7c, 0x79, 0xbe, 0xba, 0x37, 0x82, 0x3f, 0xf8, 0xa8, 0x33, 0x3d, 0x58, 0x1c, 0x70, 0xbe, 0x24, 0x34, 0x7d, 0x3f, 0x7b, 0xab, 0x8d, 0x3e,
0xe5, 0xee, 0xb1, 0xbe, 0x18, 0xdd, 0x5d, 0x3f, 0x76, 0x0d, 0xe5, 0x3e, 0x00, 0x5c, 0xf8, 0xbe, 0x90, 0x11, 0x48, 0x3f, 0xa6, 0xbe, 0xe0, 0x3e, 0x2a, 0x1b,
0xc7, 0xbe, 0x78, 0x03, 0x44, 0x3f, 0x35, 0xcb, 0x12, 0xbf, 0xe4, 0x45, 0xc4, 0xbe, 0x82, 0x11, 0x27, 0x3f, 0x89, 0x1e, 0x3f, 0xbf, 0x0d, 0xc7, 0x5b, 0xbe,
0x86, 0xdd, 0x36, 0x3f, 0x62, 0x83, 0x45, 0xbf, 0x14, 0x75, 0x5d, 0xbe, 0x92, 0xbd, 0x54, 0x3f, 0xc6, 0x81, 0x18, 0xbf, 0x52, 0x64, 0xff, 0xbe, 0x2c, 0x9b,
0x2c, 0x3f, 0x95, 0xf4, 0x06, 0xbf, 0x43, 0x08, 0xfc, 0xbe, 0x8a, 0x63, 0x13, 0x3f, 0x9c, 0x54, 0x32, 0xbf, 0xe7, 0x45, 0xc4, 0xbe, 0x96, 0x58, 0x13, 0x3f,
0x18, 0xcc, 0x51, 0xbf, 0xcc, 0x73, 0x64, 0xbe, 0x72, 0xff, 0x1c, 0x3f, 0xae, 0x0f, 0x5c, 0xbf, 0x4b, 0x3f, 0xae, 0xbd, 0xc4, 0xe8, 0x3d, 0x3f, 0xde, 0x2c,
0x46, 0xbf, 0xa0, 0xb0, 0xab, 0xbd, 0x6c, 0xef, 0x5b, 0x3f, 0xfe, 0x21, 0x17, 0xbf, 0xf7, 0xdd, 0x60, 0xbe, 0x18, 0xdc, 0x6d, 0x3f, 0x98, 0x50, 0xcc, 0xbe,
0x1b, 0x34, 0xc6, 0xbe, 0x00, 0x87, 0x5c, 0x3f, 0x49, 0xe7, 0xc1, 0xbe, 0xa3, 0x80, 0x36, 0xbf, 0x30, 0x42, 0xf4, 0x3d, 0x4e, 0xef, 0xdd, 0xbe, 0xa4, 0x5b,
0x20, 0xbf, 0xa6, 0x46, 0x94, 0x3e, 0x4e, 0xd8, 0x2e, 0xbf, 0xb0, 0x60, 0x34, 0xbf, 0x88, 0xfb, 0xac, 0x3e, 0x6e, 0x28, 0xc6, 0xbe, 0x8e, 0xab, 0x3c, 0xbf,
0xcc, 0x6c, 0x31, 0x3e, 0x81, 0xf8, 0xa3, 0xbe, 0xc1, 0xf1, 0x42, 0xbf, 0x04, 0x0b, 0x36, 0xbe, 0x0b, 0xa6, 0xa4, 0xbd, 0xae, 0x34, 0x3e, 0xbf, 0x54, 0x27,
0x56, 0xbe, 0x48, 0xa0, 0x54, 0xbe, 0x55, 0xd0, 0x3e, 0xbf, 0xdc, 0x77, 0xb0, 0xbd, 0x90, 0x5b, 0x68, 0xbe, 0xe9, 0x50, 0xb0, 0xbe, 0xe4, 0x82, 0x3f, 0x3e,
0x84, 0x74, 0x79, 0xbf, 0xf4, 0x2c, 0xe8, 0xbe, 0x1c, 0x6a, 0x1d, 0x3e, 0x30, 0x7f, 0x6c, 0xbf, 0x67, 0xb2, 0x91, 0x33, 0x9c, 0x7e, 0xe0, 0xbd, 0x90, 0xa9,
0x82, 0xbf, 0x81, 0x31, 0xd8, 0x33, 0x40, 0x67, 0x16, 0x3d, 0x7a, 0x24, 0x83, 0xbf, 0xe0, 0xbd, 0x9a, 0xbd, 0x10, 0x4c, 0x57, 0x3e, 0x7a, 0x25, 0x82, 0xbf,
0x21, 0x99, 0x30, 0xbf, 0x90, 0xd3, 0xaa, 0xbe, 0x1e, 0x66, 0x00, 0xbf, 0x4d, 0xe7, 0x2b, 0xbf, 0xe4, 0xea, 0xc0, 0xbe, 0xc6, 0xcf, 0x14, 0xbf, 0xf1, 0x36,
0x29, 0xbf, 0x3e, 0x3b, 0x94, 0xbe, 0xe6, 0xad, 0x1e, 0xbf, 0x1f, 0xe3, 0x39, 0xbf, 0x22, 0x4e, 0x95, 0xbe, 0x12, 0xf7, 0xcd, 0xbe, 0x85, 0x06, 0x0a, 0xbf,
0x0c, 0x49, 0x0d, 0x3e, 0x4e, 0xd3, 0x58, 0xbf, 0x76, 0x08, 0x86, 0x3d, 0x80, 0x14, 0x36, 0x3d, 0xae, 0xf1, 0x83, 0xbf, 0xbd, 0xb3, 0x75, 0x3d, 0x58, 0xa2,
0xe5, 0xbd, 0x6c, 0x4c, 0x84, 0xbf, 0x3a, 0x64, 0x12, 0x34, 0x5c, 0x97, 0x4a, 0x3e, 0x1b, 0x3a, 0x83, 0xbf, 0xa5, 0x9a, 0xb0, 0xbd, 0xf0, 0x4b, 0xc5, 0x3e,
0xad, 0x65, 0x80, 0xbf, 0xc0, 0xef, 0x3b, 0x34, 0x58, 0x64, 0xc3, 0x3e, 0xf5, 0x73, 0x81, 0xbf, 0x07, 0xbe, 0x9a, 0x3d, 0x14, 0x4c, 0x57, 0x3e, 0x79, 0x25,
0x82, 0xbf, 0x9c, 0xc3, 0xbc, 0xbe, 0x04, 0xfc, 0xaf, 0x3e, 0x3f, 0x75, 0x71, 0xbf, 0x7f, 0x22, 0xf4, 0xbe, 0x24, 0x60, 0x9a, 0x3e, 0xde, 0x97, 0x61, 0xbf,
0x07, 0x02, 0x11, 0xbf, 0x10, 0x05, 0x81, 0x3e, 0x06, 0x77, 0x4e, 0xbf, 0xb9, 0xe3, 0x3c, 0xbf, 0x94, 0x82, 0x7a, 0xbe, 0x41, 0xf4, 0x9f, 0xbe, 0xa1, 0x52,
0x46, 0xbf, 0x2c, 0x85, 0x26, 0xbe, 0x00, 0x6d, 0xf5, 0xbb, 0x06, 0xac, 0x41, 0xbf, 0xe8, 0xd2, 0x87, 0x3d, 0x33, 0x81, 0xf4, 0xbd, 0x17, 0xda, 0x3c, 0xbf,
0x40, 0x4e, 0xea, 0x3c, 0x7c, 0xa7, 0x85, 0xbe, 0x9e, 0xad, 0x41, 0xbf, 0xf0, 0x66, 0x5c, 0x3e, 0xdd, 0x88, 0x1b, 0xbe, 0x67, 0x5e, 0x20, 0xb2, 0x68, 0x63,
0x28, 0x3f, 0x70, 0xa7, 0x40, 0x3f, 0x80, 0xf3, 0x9d, 0xb3, 0x0c, 0x9b, 0xdf, 0x3e, 0x7c, 0xf9, 0x5c, 0x3f, 0xb3, 0x9d, 0xfa, 0xbd, 0x40, 0x56, 0xdb, 0x3e,
0x10, 0x96, 0x59, 0x3f, 0x9d, 0x9d, 0xfa, 0x3d, 0x40, 0x56, 0xdb, 0x3e, 0x10, 0x96, 0x59, 0x3f, 0x00, 0x51, 0x13, 0xb4, 0xf8, 0x2b, 0x4a, 0x3e, 0x61, 0xd2,
0x70, 0x3f, 0xa9, 0xab, 0xea, 0xbd, 0x88, 0x76, 0x51, 0x3e, 0x08, 0x16, 0x6e, 0x3f, 0xd4, 0x98, 0x86, 0xbe, 0x30, 0xa9, 0xd1, 0x3e, 0xd6, 0xca, 0x51, 0x3f,
0xcd, 0xf4, 0x7c, 0x32, 0x26, 0x86, 0x3b, 0x3f, 0x38, 0xc4, 0x32, 0x3f, 0x86, 0xab, 0xea, 0x3d, 0x88, 0x76, 0x51, 0x3e, 0x08, 0x16, 0x6e, 0x3f, 0xc4, 0x7a,
0x80, 0xbe, 0xa8, 0x2c, 0x50, 0x3e, 0x10, 0x5a, 0x63, 0x3f, 0x35, 0x31, 0xc2, 0xbe, 0x82, 0x5d, 0xc0, 0x3e, 0xe7, 0xce, 0x45, 0x3f, 0x5f, 0x4e, 0xbe, 0xbe,
0x8c, 0x3a, 0x41, 0x3e, 0xd0, 0x22, 0x58, 0x3f, 0x83, 0xf9, 0x00, 0xbf, 0x0a, 0x38, 0xa5, 0x3e, 0xb8, 0xc6, 0x32, 0x3f, 0xd9, 0x3d, 0xff, 0xbe, 0x38, 0x54,
0x09, 0x3e, 0x73, 0x88, 0x44, 0x3f, 0x7c, 0x76, 0x1b, 0xbf, 0x30, 0x61, 0x8d, 0x3e, 0xe7, 0xff, 0x1b, 0x3f, 0x5b, 0xaf, 0xe2, 0xbe, 0x2c, 0x7c, 0x2a, 0x3f,
0x05, 0xa2, 0x16, 0x3f, 0xf7, 0xee, 0x19, 0xbf, 0xe0, 0x7a, 0xc2, 0x3d, 0x1a, 0x9b, 0x2c, 0x3f, 0x30, 0xda, 0x2f, 0xbf, 0x40, 0xc7, 0x53, 0x3e, 0x88, 0xc2,
0x01, 0x3f, 0x30, 0xaa, 0x2d, 0xbf, 0xe0, 0x29, 0xa2, 0x3c, 0x82, 0xf7, 0x11, 0x3f, 0xab, 0x68, 0x29, 0xbf, 0x66, 0xb1, 0x07, 0x3f, 0xf4, 0x88, 0xd1, 0x3e,
0xaf, 0x73, 0x38, 0xbf, 0xe0, 0x41, 0x5f, 0xbd, 0xd6, 0x1d, 0xe5, 0x3e, 0x38, 0xed, 0x3e, 0xbf, 0x7a, 0x5a, 0x0b, 0xbe, 0x9a, 0x36, 0xa2, 0x3e, 0xe8, 0x9e,
0x45, 0xbf, 0x8c, 0xb2, 0x7f, 0x3e, 0x83, 0x75, 0x78, 0x3e, 0x17, 0x85, 0x47, 0xbf, 0xc0, 0xb8, 0x7c, 0x3e, 0xdc, 0x0f, 0xe9, 0x3d, 0x05, 0x52, 0x43, 0xbf,
0x50, 0xc7, 0x76, 0x3e, 0xa8, 0xd2, 0x8b, 0xbc, 0xd0, 0x33, 0x3f, 0xbf, 0xb2, 0x6b, 0xdf, 0x3e, 0x48, 0x4f, 0xd7, 0x3d, 0x88, 0x42, 0x3b, 0xbf, 0x12, 0x73,
0xe1, 0x3e, 0x42, 0xa5, 0x85, 0x3e, 0xa6, 0x86, 0x3c, 0xbf, 0x30, 0xb3, 0xdb, 0x3e, 0xfc, 0x24, 0x50, 0xbd, 0x81, 0xc1, 0x64, 0x33, 0x7c, 0x2e, 0x58, 0x3f,
0x8a, 0x5a, 0x19, 0x3f, 0xa1, 0xb3, 0xf5, 0xbd, 0x4a, 0x17, 0x53, 0x3f, 0x8f, 0x91, 0x19, 0x3f, 0x69, 0xff, 0x13, 0xbf, 0x68, 0x8a, 0xb5, 0x3e, 0x22, 0xc0,
0x41, 0xbf, 0xde, 0x4d, 0xff, 0xbe, 0xf8, 0xc1, 0xda, 0x3e, 0xdd, 0x0d, 0x51, 0xbf, 0xa3, 0x47, 0xc2, 0xbe, 0x22, 0xf2, 0xfc, 0x3e, 0x2c, 0x94, 0x60, 0xbf,
0x5a, 0x6f, 0xbb, 0xbd, 0x70, 0xcf, 0x09, 0x3f, 0x48, 0x48, 0x70, 0xbf, 0x18, 0xf7, 0x68, 0xbe, 0x26, 0xad, 0x06, 0x3f, 0xd1, 0xc1, 0x6c, 0xbf, 0xd4, 0x9a,
0xb0, 0x3d, 0xf0, 0x4b, 0xc5, 0x3e, 0xad, 0x65, 0x80, 0xbf, 0x8d, 0x6c, 0x57, 0x34, 0xbe, 0xf0, 0x08, 0x3f, 0x1f, 0xbc, 0x73, 0xbf, 0xf7, 0xdb, 0x15, 0xbf,
0xea, 0xaa, 0xe0, 0x3e, 0xec, 0x22, 0x2f, 0xbf, 0x9f, 0x0d, 0x00, 0xbf, 0xf8, 0x05, 0x02, 0x3f, 0x8c, 0x5b, 0x40, 0xbf, 0x63, 0xfe, 0xac, 0xbd, 0x82, 0x3c,
0x22, 0x3f, 0x00, 0x55, 0x61, 0xbf, 0x90, 0x6f, 0xbb, 0x3d, 0x70, 0xcf, 0x09, 0x3f, 0x48, 0x48, 0x70, 0xbf, 0x4d, 0x75, 0x67, 0x34, 0xa8, 0xae, 0x24, 0x3f,
0x46, 0x1f, 0x63, 0xbf, 0xce, 0xe8, 0x15, 0xbf, 0xf8, 0xf6, 0xf9, 0x3e, 0x61, 0xdf, 0x22, 0xbf, 0x9b, 0xfe, 0xac, 0x3d, 0x84, 0x3c, 0x22, 0x3f, 0xfe, 0x54,
0x61, 0xbf, 0xb4, 0xc5, 0x70, 0x34, 0x64, 0x8b, 0x40, 0x3f, 0x8e, 0xe0, 0x46, 0xbf, 0xde, 0xcf, 0x16, 0xbf, 0x24, 0xfd, 0x15, 0x3f, 0x6a, 0xe1, 0xf9, 0xbe,
0x2c, 0xe9, 0x27, 0xbf, 0x06, 0xc4, 0xf1, 0x3e, 0xe1, 0x4d, 0xe3, 0xbe, 0x88, 0x3f, 0xae, 0x3d, 0xc4, 0xe8, 0x3d, 0x3f, 0xdd, 0x2c, 0x46, 0xbf, 0xe7, 0xe0,
0x71, 0x34, 0x0e, 0x7a, 0x5f, 0x3f, 0x48, 0xa6, 0x17, 0xbf, 0xdb, 0xb0, 0xab, 0x3d, 0x6c, 0xef, 0x5b, 0x3f, 0xfe, 0x21, 0x17, 0xbf, 0x01, 0xda, 0x68, 0x34,
0xc0, 0x4b, 0x75, 0x3f, 0xa2, 0xfa, 0xca, 0xbe, 0xb5, 0x85, 0xc8, 0xbd, 0x52, 0xc6, 0x73, 0x3f, 0xd0, 0x43, 0xcc, 0xbe, 0xf2, 0x85, 0xc8, 0x3d, 0x52, 0xc6,
0x73, 0x3f, 0xd0, 0x43, 0xcc, 0xbe, 0x34, 0xbe, 0x55, 0x34, 0x69, 0xd5, 0x82, 0x3f, 0x28, 0xf4, 0x2a, 0xbe, 0x6e, 0x4f, 0xc4, 0xbd, 0xc2, 0x00, 0x82, 0x3f,
0x84, 0x26, 0x2a, 0xbe, 0xa7, 0x4f, 0xc4, 0x3d, 0xc2, 0x00, 0x82, 0x3f, 0x82, 0x26, 0x2a, 0xbe, 0xe7, 0x95, 0x3b, 0x34, 0x15, 0x14, 0x86, 0x3f, 0x38, 0xca,
0x45, 0x3d, 0x07, 0x9f, 0xd9, 0xbd, 0x6c, 0x00, 0x85, 0x3f, 0x78, 0x23, 0x3e, 0x3d, 0x0c, 0x5b, 0x6e, 0xbe, 0x0c, 0x51, 0x7f, 0x3f, 0x1c, 0xf3, 0x29, 0xbe,
0x39, 0x9f, 0xd9, 0x3d, 0x6c, 0x00, 0x85, 0x3f, 0x78, 0x23, 0x3e, 0x3d, 0x54, 0xce, 0x13, 0x34, 0xfb, 0xc2, 0x82, 0x3f, 0x21, 0x17, 0x8c, 0x3e, 0x34, 0x5b,
0xd4, 0xbd, 0x17, 0x39, 0x82, 0x3f, 0xa8, 0x2f, 0x89, 0x3e, 0x5b, 0x5b, 0xd4, 0x3d, 0x17, 0x39, 0x82, 0x3f, 0xa8, 0x2f, 0x89, 0x3e, 0x74, 0xc7, 0xce, 0x33,
0xf4, 0x93, 0x73, 0x3f, 0x0b, 0x5a, 0xeb, 0x3e, 0xf3, 0xba, 0xdc, 0xbd, 0x6a, 0xd6, 0x71, 0x3f, 0xbb, 0x8e, 0xe6, 0x3e, 0x0e, 0xbb, 0xdc, 0x3d, 0x6a, 0xd6,
0x71, 0x3f, 0xbb, 0x8e, 0xe6, 0x3e, 0x82, 0x2e, 0x5d, 0xbe, 0xe8, 0x88, 0x6c, 0x3f, 0x39, 0xbf, 0xe4, 0x3e, 0xb2, 0xb3, 0xf5, 0x3d, 0x4a, 0x17, 0x53, 0x3f,
0x90, 0x91, 0x19, 0x3f, 0xd5, 0x12, 0x40, 0xbe, 0xd2, 0xf2, 0x4c, 0x3f, 0x0a, 0x5d, 0x19, 0x3f, 0xf7, 0x3f, 0xa6, 0xbe, 0xd0, 0xd0, 0x3d, 0x3f, 0x46, 0x0f,
0x1a, 0x3f, 0x95, 0xe8, 0x01, 0xbf, 0x2c, 0x50, 0x44, 0x3f, 0xf0, 0x68, 0xad, 0xbe, 0x19, 0xb1, 0x1a, 0xbf, 0x16, 0x3b, 0x2b, 0x3f, 0x12, 0xe0, 0x98, 0xbe,
0x79, 0xd7, 0x1c, 0xbf, 0x7c, 0xca, 0x3a, 0x3f, 0x9c, 0xce, 0xe1, 0xbd, 0xd1, 0xa3, 0x15, 0xbf, 0xc4, 0x64, 0x2c, 0x3f, 0xca, 0x3f, 0xdb, 0x3e, 0x80, 0xea,
0x2b, 0xbf, 0xbc, 0xc4, 0x0b, 0x3f, 0xa4, 0x3d, 0x82, 0xbe, 0x50, 0x64, 0x2e, 0xbf, 0x74, 0xc3, 0x17, 0x3f, 0x58, 0x35, 0xb8, 0xbd, 0x77, 0xb0, 0x2f, 0xbf,
0xcc, 0x06, 0x1b, 0x3f, 0x54, 0x36, 0xa0, 0x3d, 0x22, 0xdf, 0x2d, 0xbf, 0xd4, 0x26, 0x16, 0x3f, 0xe5, 0x7e, 0x88, 0x3e, 0x51, 0xca, 0x38, 0xbf, 0x56, 0x2c,
0xc9, 0x3e, 0xe4, 0x8c, 0x56, 0xbe, 0x9e, 0xb3, 0x47, 0x3f, 0x60, 0xac, 0xcd, 0xbc, 0xd4, 0x37, 0x47, 0x3d, 0xf6, 0xca, 0x46, 0x3f, 0x00, 0xe4, 0x62, 0xba,
0x52, 0xd4, 0x02, 0x3e, 0x0d, 0xbb, 0x44, 0x3f, 0xa0, 0xf5, 0xa5, 0x3c, 0xf8, 0x37, 0x5c, 0x3e, 0x8a, 0x94, 0x44, 0x3f, 0x10, 0xe6, 0x75, 0x3d, 0xa9, 0xcf,
0x41, 0x3e, 0x3b, 0x55, 0x43, 0x3f, 0xe8, 0x8b, 0x74, 0xbd, 0x58, 0x91, 0xbc, 0xbd, 0xff, 0x1f, 0x47, 0x3f, 0x9c, 0xa6, 0x82, 0xbd, 0xe0, 0xde, 0xc0, 0xbb,
0x74, 0xe2, 0x20, 0x3f, 0x50, 0xbf, 0x11, 0x3e, 0x22, 0x04, 0x29, 0xbf, 0xe6, 0x36, 0x1e, 0x3f, 0xd0, 0x2b, 0x4c, 0x3e, 0x4e, 0x6a, 0x3a, 0xbf, 0x24, 0x94,
0x27, 0x3f, 0xc0, 0xe5, 0x6f, 0x3d, 0xce, 0x1a, 0x16, 0xbf, 0x45, 0x39, 0x2a, 0x3f, 0x50, 0xb2, 0x79, 0xbe, 0xec, 0xaf, 0x10, 0xbf, 0xa8, 0x96, 0x31, 0x3f,
0xc0, 0xbd, 0xbc, 0x3d, 0xaa, 0x3b, 0x00, 0xbf, 0xfb, 0xa0, 0x27, 0x3f, 0x20, 0x2b, 0x51, 0x3e, 0xd2, 0x36, 0x17, 0xbf, 0x49, 0xad, 0x0c, 0x3e, 0xd0, 0x42,
0xd3, 0xbd, 0xf6, 0xbe, 0x83, 0xbf, 0x34, 0xe3, 0x21, 0x3e, 0xb0, 0x95, 0x3f, 0x3d, 0xf1, 0x68, 0x83, 0xbf, 0x2a, 0xf7, 0x68, 0x3e, 0x70, 0xff, 0xcb, 0xbd,
0xff, 0x85, 0x82, 0xbf, 0x2c, 0xf7, 0x68, 0x3e, 0xa0, 0x1a, 0x19, 0x3d, 0xd9, 0x51, 0x82, 0xbf, 0x64, 0x52, 0xb2, 0x3e, 0x84, 0xe5, 0xf8, 0xbd, 0x36, 0x0b,
0x78, 0xbf, 0xef, 0x50, 0xb0, 0x3e, 0x20, 0x42, 0x04, 0x3d, 0xfc, 0x40, 0x7a, 0xbf, 0xe3, 0x21, 0xe6, 0x3e, 0x16, 0xc8, 0x0c, 0xbe, 0xb0, 0x6a, 0x6d, 0xbf,
0x41, 0x2d, 0xe4, 0x3e, 0xe0, 0xd7, 0xb2, 0x3c, 0x75, 0x29, 0x6e, 0xbf, 0x9e, 0xb0, 0x0a, 0x3f, 0x30, 0x25, 0x00, 0xbe, 0x35, 0x9a, 0x5f, 0xbf, 0xa9, 0x05,
0x0b, 0x3f, 0x40, 0x86, 0x4d, 0xbc, 0xfa, 0xf5, 0x5e, 0xbf, 0x14, 0xa1, 0xbd, 0x3e, 0x90, 0x83, 0x72, 0x3f, 0x22, 0x92, 0x8a, 0x3e, 0xbe, 0x19, 0xc5, 0x3e,
0xec, 0x70, 0x78, 0x3f, 0xe8, 0x1d, 0x4d, 0x3d, 0x83, 0x6e, 0x03, 0x3f, 0xe6, 0xda, 0x5e, 0x3f, 0x18, 0xb9, 0x73, 0x3d, 0x05, 0x1f, 0x04, 0x3f, 0x58, 0xb2,
0x59, 0x3f, 0xb0, 0x78, 0x90, 0x3e, 0x69, 0x1c, 0x70, 0x3e, 0x24, 0x34, 0x7d, 0x3f, 0x7b, 0xab, 0x8d, 0x3e, 0xdf, 0x7c, 0x79, 0x3e, 0xba, 0x37, 0x82, 0x3f,
0xf8, 0xa8, 0x33, 0x3d, 0x0d, 0x58, 0x03, 0x3f, 0xc0, 0xa1, 0x56, 0x3f, 0xae, 0xde, 0x0e, 0xbe, 0x95, 0xb0, 0xc5, 0x3e, 0x9e, 0xc7, 0x71, 0x3f, 0x9a, 0xa1,
0x1f, 0xbe, 0x37, 0xa7, 0x1e, 0x3f, 0xe8, 0x7f, 0x41, 0x3f, 0xd4, 0x3c, 0x91, 0x3d, 0x9c, 0x8a, 0x1a, 0x3f, 0x52, 0x80, 0x3c, 0x3f, 0x45, 0x09, 0x8c, 0x3e,
0x04, 0x5c, 0xf8, 0x3e, 0x90, 0x11, 0x48, 0x3f, 0xaa, 0xbe, 0xe0, 0x3e, 0xec, 0xee, 0xb1, 0x3e, 0x18, 0xdd, 0x5d, 0x3f, 0x78, 0x0d, 0xe5, 0x3e, 0x30, 0x75,
0x5d, 0x3e, 0x92, 0xbd, 0x54, 0x3f, 0xc6, 0x81, 0x18, 0xbf, 0x28, 0xc7, 0x5b, 0x3e, 0x86, 0xdd, 0x36, 0x3f, 0x60, 0x83, 0x45, 0xbf, 0xf3, 0x45, 0xc4, 0x3e,
0x82, 0x11, 0x27, 0x3f, 0x88, 0x1e, 0x3f, 0xbf, 0x37, 0x1b, 0xc7, 0x3e, 0x78, 0x03, 0x44, 0x3f, 0x35, 0xcb, 0x12, 0xbf, 0xe8, 0x73, 0x64, 0x3e, 0x72, 0xff,
0x1c, 0x3f, 0xae, 0x0f, 0x5c, 0xbf, 0xf0, 0x45, 0xc4, 0x3e, 0x98, 0x58, 0x13, 0x3f, 0x17, 0xcc, 0x51, 0xbf, 0x53, 0x08, 0xfc, 0x3e, 0x8a, 0x63, 0x13, 0x3f,
0x9c, 0x54, 0x32, 0xbf, 0x60, 0x64, 0xff, 0x3e, 0x2c, 0x9b, 0x2c, 0x3f, 0x94, 0xf4, 0x06, 0xbf, 0x29, 0x34, 0xc6, 0x3e, 0x00, 0x87, 0x5c, 0x3f, 0x48, 0xe7,
0xc1, 0xbe, 0x14, 0xde, 0x60, 0x3e, 0x18, 0xdc, 0x6d, 0x3f, 0x98, 0x50, 0xcc, 0xbe, 0xa7, 0x80, 0x36, 0x3f, 0x38, 0x42, 0xf4, 0x3d, 0x4a, 0xef, 0xdd, 0xbe,
0xaa, 0x5b, 0x20, 0x3f, 0xa8, 0x46, 0x94, 0x3e, 0x4e, 0xd8, 0x2e, 0xbf, 0x8e, 0xab, 0x3c, 0x3f, 0xcc, 0x6c, 0x31, 0x3e, 0x7f, 0xf8, 0xa3, 0xbe, 0xb3, 0x60,
0x34, 0x3f, 0x8a, 0xfb, 0xac, 0x3e, 0x6a, 0x28, 0xc6, 0xbe, 0x51, 0xd0, 0x3e, 0x3f, 0xd8, 0x77, 0xb0, 0xbd, 0x8a, 0x5b, 0x68, 0xbe, 0xac, 0x34, 0x3e, 0x3f,
0x54, 0x27, 0x56, 0xbe, 0x43, 0xa0, 0x54, 0xbe, 0xbd, 0xf1, 0x42, 0x3f, 0x02, 0x0b, 0x36, 0xbe, 0xfe, 0xa5, 0xa4, 0xbd, 0xfe, 0x2c, 0xe8, 0x3e, 0x1c, 0x6a,
0x1d, 0x3e, 0x30, 0x7f, 0x6c, 0xbf, 0xf0, 0x50, 0xb0, 0x3e, 0xe8, 0x82, 0x3f, 0x3e, 0x82, 0x74, 0x79, 0xbf, 0xee, 0x36, 0x29, 0x3f, 0x3c, 0x3b, 0x94, 0xbe,
0xe4, 0xad, 0x1e, 0xbf, 0x4c, 0xe7, 0x2b, 0x3f, 0xe3, 0xea, 0xc0, 0xbe, 0xc5, 0xcf, 0x14, 0xbf, 0x21, 0x99, 0x30, 0x3f, 0x90, 0xd3, 0xaa, 0xbe, 0x1d, 0x66,
0x00, 0xbf, 0x1e, 0xe3, 0x39, 0x3f, 0x21, 0x4e, 0x95, 0xbe, 0x10, 0xf7, 0xcd, 0xbe, 0x88, 0x06, 0x0a, 0x3f, 0x08, 0x49, 0x0d, 0x3e, 0x50, 0xd3, 0x58, 0xbf,
0xa5, 0xc3, 0xbc, 0x3e, 0x04, 0xfc, 0xaf, 0x3e, 0x3e, 0x75, 0x71, 0xbf, 0x89, 0x22, 0xf4, 0x3e, 0x26, 0x60, 0x9a, 0x3e, 0xde, 0x97, 0x61, 0xbf, 0x0b, 0x02,
0x11, 0x3f, 0x10, 0x05, 0x81, 0x3e, 0x06, 0x77, 0x4e, 0xbf, 0xb8, 0xe3, 0x3c, 0x3f, 0x94, 0x82, 0x7a, 0xbe, 0x3e, 0xf4, 0x9f, 0xbe, 0x9c, 0x52, 0x46, 0x3f,
0x2c, 0x85, 0x26, 0xbe, 0x50, 0x6c, 0xf5, 0xbb, 0x18, 0xda, 0x3c, 0x3f, 0x40, 0x4e, 0xea, 0x3c, 0x78, 0xa7, 0x85, 0xbe, 0x02, 0xac, 0x41, 0x3f, 0xe8, 0xd2,
0x87, 0x3d, 0x26, 0x81, 0xf4, 0xbd, 0x9e, 0xad, 0x41, 0x3f, 0xf4, 0x66, 0x5c, 0x3e, 0xd8, 0x88, 0x1b, 0xbe, 0xcf, 0x98, 0x86, 0x3e, 0x30, 0xa9, 0xd1, 0x3e,
0xd8, 0xca, 0x51, 0x3f, 0xb9, 0x7a, 0x80, 0x3e, 0xa8, 0x2c, 0x50, 0x3e, 0x12, 0x5a, 0x63, 0x3f, 0x31, 0x31, 0xc2, 0x3e, 0x84, 0x5d, 0xc0, 0x3e, 0xe8, 0xce,
0x45, 0x3f, 0x58, 0x4e, 0xbe, 0x3e, 0x8c, 0x3a, 0x41, 0x3e, 0xd0, 0x22, 0x58, 0x3f, 0x81, 0xf9, 0x00, 0x3f, 0x0c, 0x38, 0xa5, 0x3e, 0xba, 0xc6, 0x32, 0x3f,
0xd3, 0x3d, 0xff, 0x3e, 0x3c, 0x54, 0x09, 0x3e, 0x74, 0x88, 0x44, 0x3f, 0x7a, 0x76, 0x1b, 0x3f, 0x30, 0x61, 0x8d, 0x3e, 0xe8, 0xff, 0x1b, 0x3f, 0x5d, 0xaf,
0xe2, 0x3e, 0x2e, 0x7c, 0x2a, 0x3f, 0x08, 0xa2, 0x16, 0x3f, 0xf4, 0xee, 0x19, 0x3f, 0xe0, 0x7a, 0xc2, 0x3d, 0x1c, 0x9b, 0x2c, 0x3f, 0x30, 0xda, 0x2f, 0x3f,
0x40, 0xc7, 0x53, 0x3e, 0x89, 0xc2, 0x01, 0x3f, 0x2f, 0xaa, 0x2d, 0x3f, 0x00, 0x2a, 0xa2, 0x3c, 0x83, 0xf7, 0x11, 0x3f, 0xad, 0x68, 0x29, 0x3f, 0x66, 0xb1,
0x07, 0x3f, 0xf6, 0x88, 0xd1, 0x3e, 0xa9, 0x73, 0x38, 0x3f, 0xe0, 0x41, 0x5f, 0xbd, 0xd8, 0x1d, 0xe5, 0x3e, 0x32, 0xed, 0x3e, 0x3f, 0x7a, 0x5a, 0x0b, 0xbe,
0x9b, 0x36, 0xa2, 0x3e, 0xe3, 0x9e, 0x45, 0x3f, 0x90, 0xb2, 0x7f, 0x3e, 0x85, 0x75, 0x78, 0x3e, 0x17, 0x85, 0x47, 0x3f, 0xc0, 0xb8, 0x7c, 0x3e, 0xe4, 0x0f,
0xe9, 0x3d, 0x85, 0x42, 0x3b, 0x3f, 0x12, 0x73, 0xe1, 0x3e, 0x44, 0xa5, 0x85, 0x3e, 0xd0, 0x33, 0x3f, 0x3f, 0xb4, 0x6b, 0xdf, 0x3e, 0x50, 0x4f, 0xd7, 0x3d,
0x05, 0x52, 0x43, 0x3f, 0x54, 0xc7, 0x76, 0x3e, 0x78, 0xd2, 0x8b, 0xbc, 0xa7, 0x86, 0x3c, 0x3f, 0x30, 0xb3, 0xdb, 0x3e, 0xec, 0x24, 0x50, 0xbd, 0x6e, 0xff,
0x13, 0x3f, 0x6a, 0x8a, 0xb5, 0x3e, 0x20, 0xc0, 0x41, 0xbf, 0xe6, 0x4d, 0xff, 0x3e, 0xf8, 0xc1, 0xda, 0x3e, 0xdd, 0x0d, 0x51, 0xbf, 0xaf, 0x47, 0xc2, 0x3e,
0x24, 0xf2, 0xfc, 0x3e, 0x2a, 0x94, 0x60, 0xbf, 0x35, 0xf7, 0x68, 0x3e, 0x26, 0xad, 0x06, 0x3f, 0xd1, 0xc1, 0x6c, 0xbf, 0xff, 0xdb, 0x15, 0x3f, 0xec, 0xaa,
0xe0, 0x3e, 0xea, 0x22, 0x2f, 0xbf, 0xa5, 0x0d, 0x00, 0x3f, 0xf8, 0x05, 0x02, 0x3f, 0x8c, 0x5b, 0x40, 0xbf, 0xd4, 0xe8, 0x15, 0x3f, 0xf8, 0xf6, 0xf9, 0x3e,
0x60, 0xdf, 0x22, 0xbf, 0x30, 0xe9, 0x27, 0x3f, 0x06, 0xc4, 0xf1, 0x3e, 0xde, 0x4d, 0xe3, 0xbe, 0xe3, 0xcf, 0x16, 0x3f, 0x24, 0xfd, 0x15, 0x3f, 0x67, 0xe1,
0xf9, 0xbe, 0x24, 0x5b, 0x6e, 0x3e, 0x0c, 0x51, 0x7f, 0x3f, 0x1a, 0xf3, 0x29, 0xbe, 0x8f, 0x2e, 0x5d, 0x3e, 0xe8, 0x88, 0x6c, 0x3f, 0x3f, 0xbf, 0xe4, 0x3e,
0xdc, 0x12, 0x40, 0x3e, 0xd4, 0xf2, 0x4c, 0x3f, 0x0c, 0x5d, 0x19, 0x3f, 0xf7, 0x3f, 0xa6, 0x3e, 0xd0, 0xd0, 0x3d, 0x3f, 0x48, 0x0f, 0x1a, 0x3f, 0x9a, 0xe8,
0x01, 0x3f, 0x2c, 0x50, 0x44, 0x3f, 0xee, 0x68, 0xad, 0xbe, 0x1f, 0xb1, 0x1a, 0x3f, 0x16, 0x3b, 0x2b, 0x3f, 0x10, 0xe0, 0x98, 0xbe, 0x7f, 0xd7, 0x1c, 0x3f,
0x7c, 0xca, 0x3a, 0x3f, 0x90, 0xce, 0xe1, 0xbd, 0xd2, 0xa3, 0x15, 0x3f, 0xc4, 0x64, 0x2c, 0x3f, 0xcc, 0x3f, 0xdb, 0x3e, 0x83, 0xea, 0x2b, 0x3f, 0xbc, 0xc4,
0x0b, 0x3f, 0xa2, 0x3d, 0x82, 0xbe, 0x53, 0x64, 0x2e, 0x3f, 0x74, 0xc3, 0x17, 0x3f, 0x4c, 0x35, 0xb8, 0xbd, 0x78, 0xb0, 0x2f, 0x3f, 0xce, 0x06, 0x1b, 0x3f,
0x5c, 0x36, 0xa0, 0x3d, 0x24, 0xdf, 0x2d, 0x3f, 0xd4, 0x26, 0x16, 0x3f, 0xe5, 0x7e, 0x88, 0x3e, 0x55, 0xca, 0x38, 0x3f, 0x58, 0x2c, 0xc9, 0x3e, 0xde, 0x8c,
0x56, 0xbe, 0x94, 0xa0, 0x49, 0xb4, 0xa0, 0xe5, 0x1c, 0xbc, 0xae, 0xbf, 0x79, 0x3f, 0xcb, 0xac, 0xda, 0xbd, 0xc0, 0xf9, 0xeb, 0xbb, 0x0b, 0xea, 0x76, 0x3f,
0x9a, 0xac, 0xda, 0x3d, 0x00, 0xf9, 0xeb, 0xbb, 0x0f, 0xea, 0x76, 0x3f, 0x10, 0xfd, 0x70, 0xbe, 0x00, 0xb0, 0x5f, 0xbc, 0xcc, 0xd3, 0x70, 0x3f, 0xde, 0x51,
0xba, 0xbe, 0x90, 0x00, 0x99, 0xbc, 0x42, 0xc6, 0x64, 0x3f, 0xe7, 0x17, 0xf7, 0xbe, 0xd0, 0x4e, 0x62, 0xbd, 0x87, 0xc8, 0x50, 0x3f, 0x5d, 0xa8, 0x19, 0xbf,
0xd8, 0xb4, 0xd6, 0xbd, 0xc0, 0x0a, 0x34, 0x3f, 0xc2, 0x26, 0x2b, 0xbf, 0xec, 0x3f, 0x2f, 0xbe, 0x18, 0x3b, 0x18, 0x3f, 0xf2, 0xcc, 0x35, 0xbf, 0x3c, 0xd3,
0x72, 0xbe, 0xa5, 0x37, 0xee, 0x3e, 0x70, 0xdc, 0x3d, 0xbf, 0x98, 0xd7, 0x56, 0xbe, 0x2b, 0x47, 0xb1, 0x3e, 0xf5, 0xfc, 0x70, 0x3e, 0x00, 0xb0, 0x5f, 0xbc,
0xcc, 0xd3, 0x70, 0x3f, 0xd1, 0x51, 0xba, 0x3e, 0x90, 0x00, 0x99, 0xbc, 0x42, 0xc6, 0x64, 0x3f, 0xdc, 0x17, 0xf7, 0x3e, 0xd0, 0x4e, 0x62, 0xbd, 0x87, 0xc8,
0x50, 0x3f, 0x57, 0xa8, 0x19, 0x3f, 0xd0, 0xb4, 0xd6, 0xbd, 0xc2, 0x0a, 0x34, 0x3f, 0xbd, 0x26, 0x2b, 0x3f, 0xe8, 0x3f, 0x2f, 0xbe, 0x1b, 0x3b, 0x18, 0x3f,
0xec, 0xcc, 0x35, 0x3f, 0x3a, 0xd3, 0x72, 0xbe, 0xa7, 0x37, 0xee, 0x3e, 0x6b, 0xdc, 0x3d, 0x3f, 0x96, 0xd7, 0x56, 0xbe, 0x2d, 0x47, 0xb1, 0x3e, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00,
0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00,
0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00,
0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x24, 0x00,
0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00,
0x2b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x2f, 0x00,
0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x3b, 0x00,
0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00,
0x42, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x48, 0x00,
0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x51, 0x00,
0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00,
0x52, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00,
0x55, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00,
0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x0b, 0x00,
0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0a, 0x00,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x58, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x59, 0x00,
0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00,
0x5b, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x5f, 0x00,
0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00,
0x5f, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x61, 0x00,
0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
0x64, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x65, 0x00,
0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00,
0x69, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x6b, 0x00,
0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00,
0x6c, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x6e, 0x00,
0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00,
0x72, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x73, 0x00,
0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00,
0x79, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x7b, 0x00,
0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00,
0x7d, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x59, 0x00,
0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
0x24, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x22, 0x00,
0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
0x81, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x84, 0x00,
0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,
0x85, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x11, 0x00,
0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
0x5c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x89, 0x00,
0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00,
0x8a, 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x8d, 0x00,
0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00,
0x0d, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x08, 0x00,
0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00,
0x87, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x5d, 0x00,
0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00,
0x93, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x91, 0x00,
0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x85, 0x00,
0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00,
0x86, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x97, 0x00,
0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
0x09, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x25, 0x00,
0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00,
0x25, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x52, 0x00,
0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00,
0x84, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x53, 0x00,
0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
0x24, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x9c, 0x00,
0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
0x9d, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x46, 0x00,
0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0xa1, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00,
0x1f, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x1f, 0x00,
0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00,
0xa5, 0x00, 0x00, 0x00, 0xa1, 0x00, 0x00, 0x00, 0xa1, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0xa2, 0x00,
0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00,
0xa7, 0x00, 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x13, 0x00,
0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00,
0xa8, 0x00, 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00, 0xa9, 0x00,
0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00,
0xa9, 0x00, 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00, 0x00, 0x15, 0x00,
0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
0xac, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00, 0x00, 0xa9, 0x00,
0x00, 0x00, 0xae, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00,
0xab, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00, 0x00, 0x1d, 0x00,
0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00,
0x15, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, 0xaf, 0x00,
0x00, 0x00, 0xb1, 0x00, 0x00, 0x00, 0xb1, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00,
0x1a, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1d, 0x00,
0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xb1, 0x00, 0x00, 0x00, 0xb2, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00,
0x51, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, 0xb4, 0x00,
0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0xb5, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0xb7, 0x00,
0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0xb5, 0x00, 0x00, 0x00, 0xb5, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x9a, 0x00, 0x00, 0x00, 0xb5, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, 0xb5, 0x00,
0x00, 0x00, 0xb9, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0xb9, 0x00, 0x00, 0x00,
0x9d, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x54, 0x00,
0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00,
0x96, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0x95, 0x00,
0x00, 0x00, 0xbd, 0x00, 0x00, 0x00, 0xbd, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00,
0xbe, 0x00, 0x00, 0x00, 0xbe, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x94, 0x00,
0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00,
0xc1, 0x00, 0x00, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xc2, 0x00,
0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00,
0x55, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0xc2, 0x00,
0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0xbd, 0x00, 0x00, 0x00,
0x95, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0xbd, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0xbc, 0x00,
0x00, 0x00, 0xbd, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0xbd, 0x00, 0x00, 0x00,
0xbf, 0x00, 0x00, 0x00, 0xbe, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0xc5, 0x00,
0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0xbe, 0x00, 0x00, 0x00,
0xc1, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0xc2, 0x00,
0x00, 0x00, 0xc7, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00,
0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x73, 0x00,
0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00,
0x7a, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, 0xc1, 0x00,
0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x00, 0xc9, 0x00, 0x00, 0x00, 0xc9, 0x00, 0x00, 0x00,
0x7a, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x00, 0x00, 0xca, 0x00, 0x00, 0x00, 0xca, 0x00, 0x00, 0x00, 0xcb, 0x00,
0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0xca, 0x00, 0x00, 0x00, 0xca, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x00, 0x00,
0x77, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xc9, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0xcc, 0x00,
0x00, 0x00, 0xc9, 0x00, 0x00, 0x00, 0xcd, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0xc9, 0x00, 0x00, 0x00,
0xcc, 0x00, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, 0xcd, 0x00, 0x00, 0x00, 0xcd, 0x00, 0x00, 0x00, 0xc9, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xcd, 0x00,
0x00, 0x00, 0xcf, 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0xcd, 0x00, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00,
0xd1, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0x00, 0xcd, 0x00, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0x00, 0xd2, 0x00,
0x00, 0x00, 0xd3, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00,
0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0xd1, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0xd2, 0x00,
0x00, 0x00, 0xd2, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0x00, 0xd1, 0x00, 0x00, 0x00, 0xd2, 0x00, 0x00, 0x00, 0xd5, 0x00, 0x00, 0x00, 0xd6, 0x00, 0x00, 0x00,
0xd6, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x00, 0x00, 0xd2, 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x00, 0x00, 0xd7, 0x00, 0x00, 0x00, 0xd7, 0x00,
0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0xd5, 0x00, 0x00, 0x00, 0xd5, 0x00, 0x00, 0x00,
0xd2, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0xd5, 0x00, 0x00, 0x00, 0xd9, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, 0xd6, 0x00,
0x00, 0x00, 0xd5, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x00, 0x00, 0xd6, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0xd7, 0x00, 0x00, 0x00,
0xd3, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, 0xd9, 0x00, 0x00, 0x00, 0xd9, 0x00, 0x00, 0x00, 0xd5, 0x00, 0x00, 0x00, 0xd8, 0x00,
0x00, 0x00, 0xd9, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, 0xd9, 0x00, 0x00, 0x00,
0xd6, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0xd6, 0x00, 0x00, 0x00, 0xdb, 0x00,
0x00, 0x00, 0xde, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 0xd9, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00,
0xb9, 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, 0xdd, 0x00,
0x00, 0x00, 0xdf, 0x00, 0x00, 0x00, 0xdf, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, 0xde, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00,
0xb9, 0x00, 0x00, 0x00, 0xb9, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 0xde, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0xe1, 0x00,
0x00, 0x00, 0xe1, 0x00, 0x00, 0x00, 0xdf, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00,
0xa4, 0x00, 0x00, 0x00, 0xb9, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00,
0x00, 0x00, 0xe1, 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xd7, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
0x7d, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xd7, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x6c, 0x00,
0x00, 0x00, 0xd7, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0xdf, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00,
0x6f, 0x00, 0x00, 0x00, 0xdf, 0x00, 0x00, 0x00, 0xe1, 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xdf, 0x00,
0x00, 0x00, 0xe1, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0xe1, 0x00, 0x00, 0x00,
0x72, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0xe3, 0x00, 0x00, 0x00, 0xe3, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x7d, 0x00,
0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0xe3, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00,
0xe2, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x13, 0x00,
0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0xe3, 0x00, 0x00, 0x00,
0xe4, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0xca, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0xe3, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0xe5, 0x00,
0x00, 0x00, 0xe5, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0xe3, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00,
0x6b, 0x00, 0x00, 0x00, 0xe5, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00,
0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00,
0xe6, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0xcb, 0x00, 0x00, 0x00, 0xca, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0xe7, 0x00,
0x00, 0x00, 0xcb, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0xe5, 0x00, 0x00, 0x00, 0xe5, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00,
0xe7, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, 0xe5, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0xe9, 0x00, 0x00, 0x00, 0xe8, 0x00,
0x00, 0x00, 0xe9, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0xe9, 0x00, 0x00, 0x00,
0xea, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0xb0, 0x00,
0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
0xcb, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0xcb, 0x00, 0x00, 0x00, 0xe7, 0x00,
0x00, 0x00, 0xeb, 0x00, 0x00, 0x00, 0xeb, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xcb, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00,
0xb8, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0xeb, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, 0xe9, 0x00, 0x00, 0x00, 0xb6, 0x00,
0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, 0xe9, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0xb7, 0x00, 0x00, 0x00,
0xb7, 0x00, 0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0xe9, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00,
0x00, 0x00, 0xb7, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xeb, 0x00, 0x00, 0x00, 0xeb, 0x00, 0x00, 0x00,
0x9c, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0xeb, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0xb5, 0x00,
0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xb7, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,
0xb3, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x7e, 0x00,
0x00, 0x00, 0xec, 0x00, 0x00, 0x00, 0xed, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xec, 0x00, 0x00, 0x00,
0x29, 0x00, 0x00, 0x00, 0xed, 0x00, 0x00, 0x00, 0xee, 0x00, 0x00, 0x00, 0xee, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0xf0, 0x00,
0x00, 0x00, 0xf1, 0x00, 0x00, 0x00, 0xec, 0x00, 0x00, 0x00, 0xec, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00,
0x2a, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xf2, 0x00,
0x00, 0x00, 0xf3, 0x00, 0x00, 0x00, 0xf3, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00,
0x2c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x33, 0x00,
0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00,
0x4b, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x2f, 0x00,
0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00,
0x33, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0xf6, 0x00,
0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0xf2, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00,
0xf4, 0x00, 0x00, 0x00, 0xf2, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x00, 0x00, 0xf2, 0x00,
0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00,
0xf9, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x00, 0x00, 0xfb, 0x00,
0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00,
0xfc, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01,
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0x34, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x04, 0x01,
0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x05, 0x01, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x06, 0x01, 0x00, 0x00,
0x06, 0x01, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x03, 0x01,
0x00, 0x00, 0x09, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x0b, 0x01, 0x00, 0x00, 0x05, 0x01, 0x00, 0x00, 0x05, 0x01, 0x00, 0x00,
0x04, 0x01, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x05, 0x01, 0x00, 0x00, 0x0c, 0x01, 0x00, 0x00, 0x0d, 0x01, 0x00, 0x00, 0x0d, 0x01, 0x00, 0x00, 0x02, 0x01,
0x00, 0x00, 0x05, 0x01, 0x00, 0x00, 0x0e, 0x01, 0x00, 0x00, 0x0f, 0x01, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00,
0x0e, 0x01, 0x00, 0x00, 0x0f, 0x01, 0x00, 0x00, 0x0e, 0x01, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x0f, 0x01,
0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x0f, 0x01, 0x00, 0x00, 0x12, 0x01, 0x00, 0x00, 0x12, 0x01, 0x00, 0x00, 0x13, 0x01, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00,
0x14, 0x01, 0x00, 0x00, 0x15, 0x01, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x11, 0x01,
0x00, 0x00, 0x16, 0x01, 0x00, 0x00, 0x17, 0x01, 0x00, 0x00, 0x17, 0x01, 0x00, 0x00, 0x0e, 0x01, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00,
0xf7, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x00, 0x00, 0x49, 0x00,
0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x19, 0x01, 0x00, 0x00, 0xf7, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00,
0x18, 0x01, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0xf6, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x1a, 0x01, 0x00, 0x00, 0x1b, 0x01, 0x00, 0x00, 0x49, 0x00,
0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0x1a, 0x01, 0x00, 0x00, 0x1c, 0x01, 0x00, 0x00, 0x1d, 0x01, 0x00, 0x00, 0x1e, 0x01, 0x00, 0x00,
0x1e, 0x01, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x1c, 0x01, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x1f, 0x01, 0x00, 0x00, 0x1f, 0x01,
0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
0x36, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x38, 0x00,
0x00, 0x00, 0xf9, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00,
0x8f, 0x00, 0x00, 0x00, 0x21, 0x01, 0x00, 0x00, 0x22, 0x01, 0x00, 0x00, 0x23, 0x01, 0x00, 0x00, 0x23, 0x01, 0x00, 0x00, 0xf5, 0x00, 0x00, 0x00, 0x21, 0x01,
0x00, 0x00, 0xf5, 0x00, 0x00, 0x00, 0x23, 0x01, 0x00, 0x00, 0x24, 0x01, 0x00, 0x00, 0x24, 0x01, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x00, 0x00,
0x2d, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x21, 0x01, 0x00, 0x00, 0x21, 0x01, 0x00, 0x00, 0xf5, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x01, 0x01,
0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x25, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00,
0x94, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x26, 0x01, 0x00, 0x00, 0x37, 0x00,
0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x26, 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
0x25, 0x01, 0x00, 0x00, 0x25, 0x01, 0x00, 0x00, 0x1f, 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x26, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x1f, 0x01,
0x00, 0x00, 0x1f, 0x01, 0x00, 0x00, 0x27, 0x01, 0x00, 0x00, 0x26, 0x01, 0x00, 0x00, 0x27, 0x01, 0x00, 0x00, 0x1f, 0x01, 0x00, 0x00, 0x25, 0x01, 0x00, 0x00,
0x25, 0x01, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00, 0x27, 0x01, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00, 0x25, 0x01, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x2b, 0x00,
0x00, 0x00, 0xf3, 0x00, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00, 0x24, 0x01, 0x00, 0x00, 0x29, 0x01, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00,
0x31, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0x00, 0x1c, 0x01, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x29, 0x01, 0x00, 0x00, 0x29, 0x01, 0x00, 0x00, 0x1d, 0x01,
0x00, 0x00, 0x1c, 0x01, 0x00, 0x00, 0x2a, 0x01, 0x00, 0x00, 0xf1, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x1e, 0x01, 0x00, 0x00,
0x2a, 0x01, 0x00, 0x00, 0x2b, 0x01, 0x00, 0x00, 0x1c, 0x01, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00, 0x2b, 0x01,
0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x1c, 0x01, 0x00, 0x00, 0x1c, 0x01, 0x00, 0x00, 0x2b, 0x01, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00,
0x2c, 0x01, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00, 0x2d, 0x01,
0x00, 0x00, 0x1a, 0x01, 0x00, 0x00, 0x2b, 0x01, 0x00, 0x00, 0x2b, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00, 0x2d, 0x01, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00,
0x2e, 0x01, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x2e, 0x01, 0x00, 0x00, 0x2f, 0x01,
0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x2e, 0x01, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00,
0x2e, 0x01, 0x00, 0x00, 0x2e, 0x01, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x39, 0x00,
0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0x31, 0x01, 0x00, 0x00, 0x2f, 0x01, 0x00, 0x00,
0x2f, 0x01, 0x00, 0x00, 0x2e, 0x01, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x32, 0x01, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0x30, 0x01,
0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x32, 0x01, 0x00, 0x00, 0x33, 0x01, 0x00, 0x00, 0x31, 0x01, 0x00, 0x00, 0x31, 0x01, 0x00, 0x00,
0x30, 0x01, 0x00, 0x00, 0x32, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x34, 0x01, 0x00, 0x00, 0x32, 0x01, 0x00, 0x00, 0x32, 0x01, 0x00, 0x00, 0x3c, 0x00,
0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x35, 0x01, 0x00, 0x00,
0x3d, 0x00, 0x00, 0x00, 0x34, 0x01, 0x00, 0x00, 0x36, 0x01, 0x00, 0x00, 0x33, 0x01, 0x00, 0x00, 0x33, 0x01, 0x00, 0x00, 0x32, 0x01, 0x00, 0x00, 0x34, 0x01,
0x00, 0x00, 0x34, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x37, 0x01, 0x00, 0x00, 0x34, 0x01, 0x00, 0x00,
0x37, 0x01, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x36, 0x01, 0x00, 0x00, 0x36, 0x01, 0x00, 0x00, 0x34, 0x01, 0x00, 0x00, 0x37, 0x01, 0x00, 0x00, 0x41, 0x00,
0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x39, 0x01, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x37, 0x01, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x37, 0x01, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3a, 0x01,
0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x37, 0x01, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00,
0xee, 0x00, 0x00, 0x00, 0xee, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3a, 0x01, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x44, 0x00,
0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x3b, 0x01, 0x00, 0x00, 0x3a, 0x01, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, 0xee, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00,
0x3f, 0x00, 0x00, 0x00, 0x3c, 0x01, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, 0x3c, 0x01, 0x00, 0x00, 0x3d, 0x01, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x29, 0x00,
0x00, 0x00, 0xef, 0x00, 0x00, 0x00, 0x3c, 0x01, 0x00, 0x00, 0x3e, 0x01, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0x3d, 0x01, 0x00, 0x00, 0x3d, 0x01, 0x00, 0x00,
0x3c, 0x01, 0x00, 0x00, 0x3e, 0x01, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x3d, 0x01,
0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x2d, 0x01, 0x00, 0x00, 0x2d, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00,
0x27, 0x00, 0x00, 0x00, 0x3d, 0x01, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0x41, 0x01, 0x00, 0x00, 0x41, 0x01, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x3d, 0x01,
0x00, 0x00, 0x19, 0x01, 0x00, 0x00, 0x42, 0x01, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00, 0xf3, 0x00, 0x00, 0x00, 0x19, 0x01, 0x00, 0x00,
0x42, 0x01, 0x00, 0x00, 0x43, 0x01, 0x00, 0x00, 0x27, 0x01, 0x00, 0x00, 0x27, 0x01, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00, 0x42, 0x01, 0x00, 0x00, 0x43, 0x01,
0x00, 0x00, 0x44, 0x01, 0x00, 0x00, 0x26, 0x01, 0x00, 0x00, 0x26, 0x01, 0x00, 0x00, 0x27, 0x01, 0x00, 0x00, 0x43, 0x01, 0x00, 0x00, 0x45, 0x01, 0x00, 0x00,
0xc5, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x45, 0x01, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x46, 0x01,
0x00, 0x00, 0x42, 0x01, 0x00, 0x00, 0x42, 0x01, 0x00, 0x00, 0x19, 0x01, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0xf2, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x00, 0x00,
0x19, 0x01, 0x00, 0x00, 0x19, 0x01, 0x00, 0x00, 0xf3, 0x00, 0x00, 0x00, 0xf2, 0x00, 0x00, 0x00, 0x46, 0x01, 0x00, 0x00, 0x47, 0x01, 0x00, 0x00, 0x43, 0x01,
0x00, 0x00, 0x43, 0x01, 0x00, 0x00, 0x42, 0x01, 0x00, 0x00, 0x46, 0x01, 0x00, 0x00, 0x47, 0x01, 0x00, 0x00, 0x13, 0x01, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00,
0x44, 0x01, 0x00, 0x00, 0x43, 0x01, 0x00, 0x00, 0x47, 0x01, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, 0x45, 0x01, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x37, 0x00,
0x00, 0x00, 0x26, 0x01, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, 0x13, 0x01, 0x00, 0x00, 0x12, 0x01, 0x00, 0x00, 0x45, 0x01, 0x00, 0x00, 0x45, 0x01, 0x00, 0x00,
0x44, 0x01, 0x00, 0x00, 0x13, 0x01, 0x00, 0x00, 0x12, 0x01, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x45, 0x01,
0x00, 0x00, 0x12, 0x01, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x48, 0x01, 0x00, 0x00, 0x46, 0x01, 0x00, 0x00, 0x46, 0x01, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
0x4a, 0x00, 0x00, 0x00, 0x48, 0x01, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x47, 0x01, 0x00, 0x00, 0x47, 0x01, 0x00, 0x00, 0x46, 0x01, 0x00, 0x00, 0x48, 0x01,
0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x13, 0x01, 0x00, 0x00, 0x13, 0x01, 0x00, 0x00, 0x47, 0x01, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00,
0x0f, 0x01, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x00, 0x0f, 0x01, 0x00, 0x00, 0x49, 0x01,
0x00, 0x00, 0x4a, 0x01, 0x00, 0x00, 0x48, 0x01, 0x00, 0x00, 0x48, 0x01, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x49, 0x01, 0x00, 0x00, 0x48, 0x01, 0x00, 0x00,
0x4a, 0x01, 0x00, 0x00, 0x15, 0x01, 0x00, 0x00, 0x15, 0x01, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x48, 0x01, 0x00, 0x00, 0x0e, 0x01, 0x00, 0x00, 0x17, 0x01,
0x00, 0x00, 0xd1, 0x00, 0x00, 0x00, 0xd1, 0x00, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, 0x0e, 0x01, 0x00, 0x00, 0x17, 0x01, 0x00, 0x00, 0x4b, 0x01, 0x00, 0x00,
0xd4, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0xd1, 0x00, 0x00, 0x00, 0x17, 0x01, 0x00, 0x00, 0x4b, 0x01, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, 0xd8, 0x00,
0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x4b, 0x01, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, 0x06, 0x01, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00,
0xdb, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, 0x06, 0x01, 0x00, 0x00, 0x4c, 0x01, 0x00, 0x00, 0xde, 0x00, 0x00, 0x00, 0xde, 0x00,
0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x06, 0x01, 0x00, 0x00, 0x4c, 0x01, 0x00, 0x00, 0x4d, 0x01, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00,
0xde, 0x00, 0x00, 0x00, 0x4c, 0x01, 0x00, 0x00, 0x4d, 0x01, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0xe0, 0x00,
0x00, 0x00, 0x4d, 0x01, 0x00, 0x00, 0x16, 0x01, 0x00, 0x00, 0x09, 0x01, 0x00, 0x00, 0x4b, 0x01, 0x00, 0x00, 0x4b, 0x01, 0x00, 0x00, 0x17, 0x01, 0x00, 0x00,
0x16, 0x01, 0x00, 0x00, 0x09, 0x01, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, 0x4b, 0x01, 0x00, 0x00, 0x09, 0x01,
0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x0d, 0x01, 0x00, 0x00, 0x4c, 0x01, 0x00, 0x00, 0x4c, 0x01, 0x00, 0x00, 0x06, 0x01, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00,
0x0d, 0x01, 0x00, 0x00, 0x4e, 0x01, 0x00, 0x00, 0x4d, 0x01, 0x00, 0x00, 0x4d, 0x01, 0x00, 0x00, 0x4c, 0x01, 0x00, 0x00, 0x0d, 0x01, 0x00, 0x00, 0x4e, 0x01,
0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x4d, 0x01, 0x00, 0x00, 0x4e, 0x01, 0x00, 0x00, 0x15, 0x01, 0x00, 0x00,
0x4f, 0x01, 0x00, 0x00, 0x16, 0x01, 0x00, 0x00, 0x16, 0x01, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x15, 0x01, 0x00, 0x00, 0x4f, 0x01, 0x00, 0x00, 0x08, 0x01,
0x00, 0x00, 0x09, 0x01, 0x00, 0x00, 0x09, 0x01, 0x00, 0x00, 0x16, 0x01, 0x00, 0x00, 0x4f, 0x01, 0x00, 0x00, 0x0c, 0x01, 0x00, 0x00, 0x35, 0x01, 0x00, 0x00,
0x4e, 0x01, 0x00, 0x00, 0x4e, 0x01, 0x00, 0x00, 0x0d, 0x01, 0x00, 0x00, 0x0c, 0x01, 0x00, 0x00, 0x35, 0x01, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x3a, 0x00,
0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x4e, 0x01, 0x00, 0x00, 0x35, 0x01, 0x00, 0x00, 0x4a, 0x01, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00, 0x4f, 0x01, 0x00, 0x00,
0x4f, 0x01, 0x00, 0x00, 0x15, 0x01, 0x00, 0x00, 0x4a, 0x01, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00, 0x51, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x01,
0x00, 0x00, 0x4f, 0x01, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00, 0x51, 0x01, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00,
0x08, 0x01, 0x00, 0x00, 0x51, 0x01, 0x00, 0x00, 0x0b, 0x01, 0x00, 0x00, 0x52, 0x01, 0x00, 0x00, 0x0c, 0x01, 0x00, 0x00, 0x0c, 0x01, 0x00, 0x00, 0x05, 0x01,
0x00, 0x00, 0x0b, 0x01, 0x00, 0x00, 0x52, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x35, 0x01, 0x00, 0x00, 0x35, 0x01, 0x00, 0x00, 0x0c, 0x01, 0x00, 0x00,
0x52, 0x01, 0x00, 0x00, 0x53, 0x01, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00, 0x4a, 0x01, 0x00, 0x00, 0x4a, 0x01, 0x00, 0x00, 0x49, 0x01, 0x00, 0x00, 0x53, 0x01,
0x00, 0x00, 0x54, 0x01, 0x00, 0x00, 0x51, 0x01, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00, 0x53, 0x01, 0x00, 0x00, 0x54, 0x01, 0x00, 0x00,
0x55, 0x01, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x51, 0x01, 0x00, 0x00, 0x51, 0x01, 0x00, 0x00, 0x54, 0x01, 0x00, 0x00, 0x55, 0x01, 0x00, 0x00, 0x56, 0x01,
0x00, 0x00, 0x0b, 0x01, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x55, 0x01, 0x00, 0x00, 0x56, 0x01, 0x00, 0x00, 0x39, 0x01, 0x00, 0x00,
0x52, 0x01, 0x00, 0x00, 0x0b, 0x01, 0x00, 0x00, 0x0b, 0x01, 0x00, 0x00, 0x56, 0x01, 0x00, 0x00, 0x39, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x3d, 0x00,
0x00, 0x00, 0x52, 0x01, 0x00, 0x00, 0x52, 0x01, 0x00, 0x00, 0x39, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x1b, 0x01, 0x00, 0x00,
0x49, 0x01, 0x00, 0x00, 0x49, 0x01, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x1b, 0x01, 0x00, 0x00, 0x57, 0x01, 0x00, 0x00, 0x53, 0x01,
0x00, 0x00, 0x53, 0x01, 0x00, 0x00, 0x49, 0x01, 0x00, 0x00, 0x1b, 0x01, 0x00, 0x00, 0x57, 0x01, 0x00, 0x00, 0x41, 0x01, 0x00, 0x00, 0x54, 0x01, 0x00, 0x00,
0x54, 0x01, 0x00, 0x00, 0x53, 0x01, 0x00, 0x00, 0x57, 0x01, 0x00, 0x00, 0x41, 0x01, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0x55, 0x01, 0x00, 0x00, 0x55, 0x01,
0x00, 0x00, 0x54, 0x01, 0x00, 0x00, 0x41, 0x01, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0x3e, 0x01, 0x00, 0x00, 0x56, 0x01, 0x00, 0x00, 0x56, 0x01, 0x00, 0x00,
0x55, 0x01, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0x3e, 0x01, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x39, 0x01, 0x00, 0x00, 0x39, 0x01, 0x00, 0x00, 0x56, 0x01,
0x00, 0x00, 0x3e, 0x01, 0x00, 0x00, 0x2d, 0x01, 0x00, 0x00, 0x57, 0x01, 0x00, 0x00, 0x1b, 0x01, 0x00, 0x00, 0x1b, 0x01, 0x00, 0x00, 0x1a, 0x01, 0x00, 0x00,
0x2d, 0x01, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x41, 0x01, 0x00, 0x00, 0x57, 0x01, 0x00, 0x00, 0x57, 0x01, 0x00, 0x00, 0x2d, 0x01, 0x00, 0x00, 0x40, 0x01,
0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x3e, 0x01, 0x00, 0x00, 0x3e, 0x01, 0x00, 0x00, 0x3c, 0x01, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00,
0x4d, 0x00, 0x00, 0x00, 0x2b, 0x01, 0x00, 0x00, 0x1a, 0x01, 0x00, 0x00, 0x1a, 0x01, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0xa1, 0x00,
0x00, 0x00, 0x58, 0x01, 0x00, 0x00, 0x59, 0x01, 0x00, 0x00, 0x59, 0x01, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, 0xa1, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00,
0x5a, 0x01, 0x00, 0x00, 0x58, 0x01, 0x00, 0x00, 0x58, 0x01, 0x00, 0x00, 0xa1, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, 0x59, 0x01,
0x00, 0x00, 0x5b, 0x01, 0x00, 0x00, 0x5b, 0x01, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, 0x5b, 0x01, 0x00, 0x00,
0x5c, 0x01, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x5d, 0x01,
0x00, 0x00, 0x5d, 0x01, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x5d, 0x01, 0x00, 0x00, 0x5e, 0x01, 0x00, 0x00,
0x5e, 0x01, 0x00, 0x00, 0xad, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, 0x00, 0x5e, 0x01, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x5f, 0x01,
0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00,
0xb1, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x61, 0x01, 0x00, 0x00, 0xb2, 0x00, 0x00, 0x00, 0xb1, 0x00, 0x00, 0x00, 0xb1, 0x00, 0x00, 0x00, 0x60, 0x01,
0x00, 0x00, 0x61, 0x01, 0x00, 0x00, 0x2f, 0x01, 0x00, 0x00, 0x62, 0x01, 0x00, 0x00, 0x5a, 0x01, 0x00, 0x00, 0x5a, 0x01, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00,
0x2f, 0x01, 0x00, 0x00, 0x31, 0x01, 0x00, 0x00, 0x63, 0x01, 0x00, 0x00, 0x62, 0x01, 0x00, 0x00, 0x62, 0x01, 0x00, 0x00, 0x2f, 0x01, 0x00, 0x00, 0x31, 0x01,
0x00, 0x00, 0x33, 0x01, 0x00, 0x00, 0x64, 0x01, 0x00, 0x00, 0x63, 0x01, 0x00, 0x00, 0x63, 0x01, 0x00, 0x00, 0x31, 0x01, 0x00, 0x00, 0x33, 0x01, 0x00, 0x00,
0x36, 0x01, 0x00, 0x00, 0x65, 0x01, 0x00, 0x00, 0x64, 0x01, 0x00, 0x00, 0x64, 0x01, 0x00, 0x00, 0x33, 0x01, 0x00, 0x00, 0x36, 0x01, 0x00, 0x00, 0x38, 0x01,
0x00, 0x00, 0x66, 0x01, 0x00, 0x00, 0x65, 0x01, 0x00, 0x00, 0x65, 0x01, 0x00, 0x00, 0x36, 0x01, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x3a, 0x01, 0x00, 0x00,
0x67, 0x01, 0x00, 0x00, 0x66, 0x01, 0x00, 0x00, 0x66, 0x01, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x3a, 0x01, 0x00, 0x00, 0x67, 0x01, 0x00, 0x00, 0x3a, 0x01,
0x00, 0x00, 0x3b, 0x01, 0x00, 0x00, 0x3b, 0x01, 0x00, 0x00, 0x68, 0x01, 0x00, 0x00, 0x67, 0x01, 0x00, 0x00,
};
@@ -0,0 +1,153 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#if defined TARGET_HAS_ThirdPartyOpenGL
#include "mC3DMesh.hpp"
#include <cstring>
namespace OpenViBE {
namespace AdvancedVisualization {
namespace {
template <typename T>
bool littleEndianToHost(const uint8_t* buffer, T* value)
{
if (!buffer || !value) { return false; }
memset(value, 0, sizeof(T));
for (uint32_t i = 0; i < sizeof(T); ++i) { reinterpret_cast<uint8_t*>(value)[i] = buffer[i]; }
return true;
}
} // namespace
void C3DMesh::clear()
{
m_Color.fill(1.0);
m_Vertices.clear();
m_Normals.clear();
m_Triangles.clear();
}
bool C3DMesh::load(const void* buffer)
{
const auto* tmp = reinterpret_cast<const uint32_t*>(buffer);
uint32_t nVertex;
uint32_t nTriangle;
littleEndianToHost<uint32_t>(reinterpret_cast<const uint8_t*>(&tmp[0]), &nVertex);
littleEndianToHost<uint32_t>(reinterpret_cast<const uint8_t*>(&tmp[1]), &nTriangle);
m_Vertices.resize(nVertex);
m_Triangles.resize(size_t(nTriangle) * 3);
size_t j = 2;
for (size_t i = 0; i < nVertex; ++i)
{
littleEndianToHost<float>(reinterpret_cast<const uint8_t*>(&tmp[j++]), &m_Vertices[i].x);
littleEndianToHost<float>(reinterpret_cast<const uint8_t*>(&tmp[j++]), &m_Vertices[i].y);
littleEndianToHost<float>(reinterpret_cast<const uint8_t*>(&tmp[j++]), &m_Vertices[i].z);
}
for (size_t i = 0; i < nTriangle * 3; ++i) { littleEndianToHost<uint32_t>(reinterpret_cast<const uint8_t*>(&tmp[j++]), &m_Triangles[i]); }
this->compile();
return true;
}
bool C3DMesh::compile()
{
m_Normals.clear();
m_Normals.resize(m_Vertices.size());
for (size_t i = 0; i < m_Triangles.size(); i += 3)
{
const uint32_t i1 = m_Triangles[i];
const uint32_t i2 = m_Triangles[i + 1];
const uint32_t i3 = m_Triangles[i + 2];
CVertex v1 = m_Vertices[i1];
CVertex v2 = m_Vertices[i2];
CVertex v3 = m_Vertices[i3];
v2.x -= v1.x;
v2.y -= v1.y;
v2.z -= v1.z;
v3.x -= v1.x;
v3.y -= v1.y;
v3.z -= v1.z;
v1 = CVertex::cross(v2, v3);
v1.normalize();
m_Normals[i1].x += v1.x;
m_Normals[i1].y += v1.y;
m_Normals[i1].z += v1.z;
m_Normals[i2].x += v1.x;
m_Normals[i2].y += v1.y;
m_Normals[i2].z += v1.z;
m_Normals[i3].x += v1.x;
m_Normals[i3].y += v1.y;
m_Normals[i3].z += v1.z;
}
for (auto& normal : m_Normals) { normal.normalize(); }
return true;
}
bool C3DMesh::project(std::vector<CVertex>& out, const std::vector<CVertex>& in)
{
out.resize(in.size());
for (size_t i = 0; i < in.size(); ++i)
{
CVertex p, q;
p = in[i];
// q = vChannelCoordinate[i];
for (size_t j = 0; j < this->m_Triangles.size(); j += 3)
{
const uint32_t i1 = this->m_Triangles[j];
const uint32_t i2 = this->m_Triangles[j + 1];
const uint32_t i3 = this->m_Triangles[j + 2];
CVertex v1, v2, v3;
v1 = this->m_Vertices[i1];
v2 = this->m_Vertices[i2];
v3 = this->m_Vertices[i3];
CVertex e1(v1, v2);
CVertex e2(v1, v3);
CVertex n = CVertex::cross(e1, e2).normalize();
const float t = CVertex::dot(v1, n) / CVertex::dot(p, n);
q.x = t * p.x;
q.y = t * p.y;
q.z = t * p.z;
if (CVertex::isInTriangle(q, v1, v2, v3) && t >= 0) { out[i] = q; }
}
// if (q.x == 0 && q.y == 0 && q.z == 0) { ::printf("Could not project coordinates on mesh for channel %i [%s]\n", i+1, ctx.getChannelName(i).c_str()); }
}
return true;
}
} // namespace AdvancedVisualization
} // namespace OpenViBE
#endif // TARGET_HAS_ThirdPartyOpenGL
@@ -0,0 +1,58 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#if defined TARGET_HAS_ThirdPartyOpenGL
#include <vector>
#include <array>
#include <cstdint>
#include <cstdlib> // size_t for unix
#include "mCVertex.hpp"
namespace OpenViBE {
namespace AdvancedVisualization {
class C3DMesh final
{
public:
C3DMesh() { m_Color.fill(1.0); }
//C3DMesh(const char* filename);
~C3DMesh() = default;
void clear();
bool load(const void* buffer);
bool compile();
bool project(std::vector<CVertex>& out, const std::vector<CVertex>& in);
std::vector<CVertex> m_Vertices;
std::vector<CVertex> m_Normals;
std::vector<uint32_t> m_Triangles;
std::array<float, 3> m_Color;
};
} // namespace AdvancedVisualization
} // namespace OpenViBE
#endif // TARGET_HAS_ThirdPartyOpenGL
@@ -0,0 +1,134 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "mCRendererBars.hpp"
namespace OpenViBE {
namespace AdvancedVisualization {
void CRendererBars::rebuild(const CRendererContext& ctx)
{
IRenderer::rebuild(ctx);
m_vertex.resize(m_nChannel);
for (size_t i = 0; i < m_nChannel; ++i)
{
m_vertex[i].resize(size_t(m_nSample) * 4);
for (size_t j = 0; j < m_nSample; ++j)
{
const size_t id = j * 4;
const float value = j * m_nInverseSample;
m_vertex[i][id].x = value;
m_vertex[i][id + 1].x = value + m_nInverseSample;
m_vertex[i][id + 2].x = value + m_nInverseSample;
m_vertex[i][id + 3].x = value;
m_vertex[i][id].u = value;
m_vertex[i][id + 1].u = value;
m_vertex[i][id + 2].u = value;
m_vertex[i][id + 3].u = value;
}
}
m_historyIdx = 0;
}
void CRendererBars::refresh(const CRendererContext& ctx)
{
IRenderer::refresh(ctx);
if (!m_nHistory) { return; }
for (size_t i = 0; i < m_nChannel; ++i)
{
size_t k = ((m_nHistory - 1) / m_nSample) * m_nSample;
std::vector<float>& history = m_history[i];
CVertex* vertex = &m_vertex[i][0];
for (size_t j = 0; j < m_nSample; j++, k++)
{
if (k >= m_historyIdx && k < m_nHistory)
{
const float value = history[k];
vertex++->y = 0;
vertex++->y = 0;
vertex++->y = value;
vertex++->y = value;
}
else { vertex += 4; }
}
}
m_historyIdx = m_nHistory;
}
bool CRendererBars::render(const CRendererContext& ctx)
{
if (!ctx.getSelectedCount() || m_vertex.empty() || !m_nHistory) { return false; }
size_t i;
glMatrixMode(GL_TEXTURE);
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glScalef(1, 1.F / ctx.getSelectedCount(), 1);
glTranslatef(0, ctx.isPositiveOnly() ? 0 : 0.5F, 0);
glPushAttrib(GL_CURRENT_BIT);
glDisable(GL_TEXTURE_1D);
glColor3f(.2F, .2F, .2F);
glBegin(GL_LINES);
for (i = 0; i < ctx.getSelectedCount(); ++i)
{
glVertex2f(0, float(i));
glVertex2f(1, float(i));
}
glEnd();
glEnable(GL_TEXTURE_1D);
glPopAttrib();
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
for (i = 0; i < ctx.getSelectedCount(); ++i)
{
glPushMatrix();
glTranslatef(0, float(ctx.getSelectedCount()) - i - 1.F, 0);
glScalef(1, ctx.getScale(), 1);
glVertexPointer(2, GL_FLOAT, sizeof(CVertex), &m_vertex[ctx.getSelected(i)][0].x);
glTexCoordPointer(1, GL_FLOAT, sizeof(CVertex), &m_vertex[ctx.getSelected(i)][0].u);
glDrawArrays(GL_QUADS, 0, GLsizei(m_nSample * 4));
glPopMatrix();
}
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glPopMatrix();
glMatrixMode(GL_TEXTURE);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
return true;
}
} // namespace AdvancedVisualization
} // namespace OpenViBE
@@ -0,0 +1,36 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "mIRenderer.hpp"
namespace OpenViBE {
namespace AdvancedVisualization {
class CRendererBars : public IRenderer
{
public:
void rebuild(const CRendererContext& ctx) override;
void refresh(const CRendererContext& ctx) override;
bool render(const CRendererContext& ctx) override;
};
} // namespace AdvancedVisualization
} // namespace OpenViBE
@@ -0,0 +1,123 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "mCRendererBitmap.hpp"
namespace OpenViBE {
namespace AdvancedVisualization {
void CRendererBitmap::rebuild(const CRendererContext& ctx)
{
IRenderer::rebuild(ctx);
m_autoDecimationFactor = 1 + size_t((m_nSample - 1) / ctx.getMaximumSampleCountPerDisplay());
m_vertex.clear();
m_vertex.resize(m_nChannel);
for (size_t i = 0; i < m_nChannel; ++i)
{
m_vertex[i].resize((m_nSample / m_autoDecimationFactor) * 4);
for (size_t j = 0; j < m_nSample - m_autoDecimationFactor + 1; j += m_autoDecimationFactor)
{
const size_t l = j / m_autoDecimationFactor;
const size_t id = l * 4;
const float factor = m_autoDecimationFactor * m_nInverseSample;
const float value = l * factor;
m_vertex[i][id].x = value;
m_vertex[i][id].y = 0;
m_vertex[i][id + 1].x = value + factor;
m_vertex[i][id + 1].y = 0;
m_vertex[i][id + 2].x = value + factor;
m_vertex[i][id + 2].y = 1;
m_vertex[i][id + 3].x = value;
m_vertex[i][id + 3].y = 1;
}
}
m_historyIdx = 0;
}
void CRendererBitmap::refresh(const CRendererContext& ctx)
{
IRenderer::refresh(ctx);
if (!m_nHistory) { return; }
if (m_vertex.empty()) { return; }
for (size_t i = 0; i < m_nChannel; ++i)
{
size_t k = ((m_nHistory - 1) / m_nSample) * m_nSample;
std::vector<float>& history = m_history[i];
CVertex* vertex = &m_vertex[i][0];
for (size_t j = 0; j < m_nSample - m_autoDecimationFactor + 1; j += m_autoDecimationFactor, k += m_autoDecimationFactor)
{
if (k >= m_historyIdx && k < m_nHistory)
{
const float value = history[k];
vertex++->u = value;
vertex++->u = value;
vertex++->u = value;
vertex++->u = value;
}
else { vertex += 4; }
}
}
m_historyIdx = m_nHistory;
}
bool CRendererBitmap::render(const CRendererContext& ctx)
{
if (!ctx.getSelectedCount() || m_vertex.empty() || !m_nHistory) { return false; }
glMatrixMode(GL_TEXTURE);
glPushMatrix();
glScalef(ctx.getScale(), 1, 1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glScalef(1, 1.F / ctx.getSelectedCount(), 1);
for (size_t i = 0; i < ctx.getSelectedCount(); ++i)
{
glPushMatrix();
glTranslatef(0, float(ctx.getSelectedCount() - i) - 1.F, 0);
glVertexPointer(3, GL_FLOAT, sizeof(CVertex), &m_vertex[ctx.getSelected(i)][0].x);
glTexCoordPointer(1, GL_FLOAT, sizeof(CVertex), &m_vertex[ctx.getSelected(i)][0].u);
glDrawArrays(GL_QUADS, 0, GLsizei((m_nSample / m_autoDecimationFactor) * 4));
glPopMatrix();
}
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glPopMatrix();
glMatrixMode(GL_TEXTURE);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
return true;
}
} // namespace AdvancedVisualization
} // namespace OpenViBE
@@ -0,0 +1,36 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "mIRenderer.hpp"
namespace OpenViBE {
namespace AdvancedVisualization {
class CRendererBitmap : public IRenderer
{
public:
void rebuild(const CRendererContext& ctx) override;
void refresh(const CRendererContext& ctx) override;
bool render(const CRendererContext& ctx) override;
};
} // namespace AdvancedVisualization
} // namespace OpenViBE
@@ -0,0 +1,205 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "mCRendererConnectivity.hpp"
#include "mC3DMesh.hpp"
// #include "content/Face.obj.hpp"
#include "content/Scalp.obj.hpp"
#include <Eigen/Geometry>
//constexpr size_t COUNT = 16; //Macro modernization, Not yet with jenkins (not the last visual 2013 which it works)
#define COUNT 16
namespace OpenViBE {
namespace AdvancedVisualization {
static void q_rotate(Eigen::VectorXd& dst, const Eigen::VectorXd& src, const Eigen::Quaterniond& q) { dst = q.matrix() * src; }
static void q_from_polar(Eigen::Quaterniond& q, Eigen::VectorXd& v1, Eigen::VectorXd& v2, const CVertex& cv1, const CVertex& cv2)
{
v1(0) = cv1.x;
v1(1) = cv1.y;
v1(2) = cv1.z;
v2(0) = cv2.x;
v2(1) = cv2.y;
v2(2) = cv2.z;
q.setFromTwoVectors(v1, v2);
}
void CRendererConnectivity::rebuild(const CRendererContext& ctx)
{
IRenderer::rebuild(ctx);
Eigen::Quaterniond q = Eigen::Quaterniond::Identity();
const Eigen::Quaterniond qId = Eigen::Quaterniond::Identity();
Eigen::Quaterniond qDiff = Eigen::Quaterniond::Identity();
Eigen::VectorXd v(3);
Eigen::VectorXd v1(3);
Eigen::VectorXd v2(3);
C3DMesh scalp;
scalp.load(SCALP_DATA);
// Projects electrode coordinates to 3D mesh
std::vector<CVertex> projectedChannelPos;
std::vector<CVertex> channelPos;
channelPos.resize(ctx.getChannelCount());
for (size_t i = 0; i < ctx.getChannelCount(); ++i) { ctx.getChannelLocalisation(i, channelPos[i].x, channelPos[i].y, channelPos[i].z); }
scalp.project(projectedChannelPos, channelPos);
// Generates arcs
m_vertex.clear();
m_vertex.resize(m_nChannel * (m_nChannel - 1) / 2);
size_t l = 0;
for (size_t i = 0; i < m_nChannel; ++i)
{
for (size_t j = 0; j < i; ++j)
{
m_vertex[l].resize(COUNT);
CVertex vi, vj;
vi = channelPos[i];
vj = channelPos[j];
const float viLen = projectedChannelPos[i].length();
const float vjLen = projectedChannelPos[j].length();
q_from_polar(qDiff, v1, v2, vi, vj);
const double alpha = 0;
const double dot = (1 - CVertex::dot(vi, vj)) * .5;
for (size_t k = 0; k < COUNT; ++k)
{
const float t = float(k * 1. / (COUNT - 1));
auto s = float((t - .5) * 2);
s = float(1 + .5 * (1 - s * s) * dot);
q = qId.slerp(t, qDiff);
q_rotate(v, v1, q);
const float len = (viLen * (1 - t) + vjLen * t);
m_vertex[l][k].x = float(s * v[0] * len);
m_vertex[l][k].y = float(s * v[1] * len);
m_vertex[l][k].z = float(s * v[2] * len);
m_vertex[l][k].u = float(alpha);
}
l++;
}
}
m_historyIdx = 0;
}
void CRendererConnectivity::refresh(const CRendererContext& ctx)
{
IRenderer::refresh(ctx);
if (!m_nHistory) { return; }
if (m_nHistory < m_nChannel) { return; }
size_t l = 0;
for (size_t i = 0; i < m_nChannel; ++i)
{
for (size_t j = 0; j < i; ++j)
{
for (size_t k = 0; k < COUNT; ++k) { m_vertex[l][k].u = m_history[i][m_nHistory - 1 - j]; }
l++;
}
}
m_historyIdx = m_nHistory;
}
bool CRendererConnectivity::render(const CRendererContext& ctx)
{
if (!ctx.getSelectedCount() || m_vertex.empty() || !m_nHistory) { return false; }
const float d = 3.5;
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluPerspective(60, ctx.getAspect(), .01, 100);
glTranslatef(0, 0, -d);
glRotatef(ctx.getRotationX() * 10, 1, 0, 0);
glRotatef(ctx.getRotationY() * 10, 0, 1, 0);
glMatrixMode(GL_TEXTURE);
glPushMatrix();
glScalef(ctx.getScale(), 1, 1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glScalef(ctx.getZoom(), ctx.getZoom(), ctx.getZoom());
const float rgb = 1.F;
glColor4f(rgb, rgb, rgb, ctx.getTranslucency());
glPushMatrix();
glTranslatef(0, .5F, 0);
glRotatef(19, 1, 0, 0);
glTranslatef(0, -.2F, .35F);
// ::glScalef(1.8f, 1.8f, 1.8f);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
for (size_t i = 0; i < m_nChannel * (m_nChannel - 1) / 2; ++i)
{
glVertexPointer(3, GL_FLOAT, sizeof(CVertex), &m_vertex[i][0].x);
glTexCoordPointer(1, GL_FLOAT, sizeof(CVertex), &m_vertex[i][0].u);
glDrawArrays(GL_LINE_STRIP, 0, COUNT);
}
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glPopMatrix();
if (ctx.getCheckBoardVisibility()) { this->drawCoordinateSystem(); }
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_TEXTURE);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
return true;
}
} // namespace AdvancedVisualization
} // namespace OpenViBE
@@ -0,0 +1,40 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
// #if defined TARGET_HAS_ThirdPartyVRPN
#include "mIRenderer.hpp"
namespace OpenViBE {
namespace AdvancedVisualization {
class CRendererConnectivity : public IRenderer
{
public:
void rebuild(const CRendererContext& ctx) override;
void refresh(const CRendererContext& ctx) override;
bool render(const CRendererContext& ctx) override;
};
} // namespace AdvancedVisualization
} // namespace OpenViBE
// #endif // TARGET_HAS_ThirdPartyVRPN
@@ -0,0 +1,263 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "mCRendererContext.hpp"
#include <algorithm>
#include <map>
#include <cstdio>
#include <cmath>
#include <iostream>
namespace OpenViBE {
namespace AdvancedVisualization {
namespace {
void getLeftRightScore(std::map<std::string, float>& scores, const std::vector<std::string>& names, const std::vector<CVertex>& positions)
{
for (size_t i = 0; i < names.size() && i < positions.size(); ++i)
{
std::string name = std::string(",") + names[i] + std::string(",");
std::transform(name.begin(), name.end(), name.begin(), tolower);
scores[name] = float(positions[i].x * 1E-0 + positions[i].y * 1E-10 + positions[i].z * 1E-5);
}
}
void getFrontBackScore(std::map<std::string, float>& scores, const std::vector<std::string>& names, const std::vector<CVertex>& positions)
{
for (size_t i = 0; i < names.size() && i < positions.size(); ++i)
{
std::string name = std::string(",") + names[i] + std::string(",");
std::transform(name.begin(), name.end(), name.begin(), tolower);
scores[name] = float(positions[i].x * 1E-5 + positions[i].y * 1E-10 + positions[i].z * 1E-0);
}
}
struct SSortAlpha
{
explicit SSortAlpha(const std::vector<std::string>& channels) : names(channels) { }
bool operator()(const size_t i, const size_t j) const
{
std::string nameI = names[i];
std::string nameJ = names[j];
std::transform(nameI.begin(), nameI.end(), nameI.begin(), tolower);
std::transform(nameJ.begin(), nameJ.end(), nameJ.begin(), tolower);
return nameI < nameJ;
}
const std::vector<std::string>& names;
};
struct SSortSpecial
{
SSortSpecial(const std::vector<std::string>& channels, const std::map<std::string, float>& scoreMap)
: names(channels), scores(scoreMap) { }
bool operator()(const size_t i, const size_t j) const
{
float scoreI = 0;
float scoreJ = 0;
std::string nameI = std::string(",") + names[i] + std::string(",");
std::string nameJ = std::string(",") + names[j] + std::string(",");
std::transform(nameI.begin(), nameI.end(), nameI.begin(), tolower);
std::transform(nameJ.begin(), nameJ.end(), nameJ.begin(), tolower);
for (auto it = scores.begin(); it != scores.end(); ++it)
{
if (it->first == nameI) { scoreI = it->second; }
if (it->first == nameJ) { scoreJ = it->second; }
}
return scoreI < scoreJ;
}
const std::vector<std::string>& names;
const std::map<std::string, float>& scores;
};
} // namespace
CRendererContext::CRendererContext(CRendererContext* parentCtx)
{
clear();
setParentRendererContext(parentCtx);
}
void CRendererContext::clear()
{
this->clearChannelInfo();
this->clearTransformInfo();
m_dimLabels.clear();
}
void CRendererContext::clearChannelInfo()
{
m_channelLookup.clear();
m_channelName.clear();
m_channelPos.clear();
m_leftRightScore.clear();
m_frontBackScore.clear();
}
void CRendererContext::addChannel(const std::string& name, const float x, const float y, const float z)
{
const auto norm = float(sqrt(x * x + y * y + z * z));
const float invNorm = (norm != 0 ? 1.F / norm : 0);
CVertex pos;
pos.x = x * invNorm;
pos.y = y * invNorm;
pos.z = z * invNorm;
m_channelLookup.push_back(m_channelName.size());
m_channelName.push_back(name);
m_channelPos.push_back(pos);
}
void CRendererContext::selectChannel(const size_t index)
{
for (auto& i : m_channelLookup) { if (i == index) { return; } }
m_channelLookup.push_back(index);
}
void CRendererContext::unselectChannel(const size_t index)
{
for (size_t i = 0; i < m_channelLookup.size(); ++i)
{
if (m_channelLookup[i] == index)
{
m_channelLookup.erase(m_channelLookup.begin() + i);
return;
}
}
}
void CRendererContext::sortSelectedChannel(const size_t mode)
{
if (m_leftRightScore.empty()) { getLeftRightScore(m_leftRightScore, m_channelName, m_channelPos); }
if (m_frontBackScore.empty()) { getFrontBackScore(m_frontBackScore, m_channelName, m_channelPos); }
switch (mode)
{
case 0: break;
case 1: std::stable_sort(m_channelLookup.begin(), m_channelLookup.end());
break;
case 2: std::stable_sort(m_channelLookup.begin(), m_channelLookup.end(), SSortAlpha(m_channelName));
break;
case 3: std::reverse(m_channelLookup.begin(), m_channelLookup.end());
break;
case 4: std::stable_sort(m_channelLookup.begin(), m_channelLookup.end(), SSortSpecial(m_channelName, m_leftRightScore));
break;
case 5: std::stable_sort(m_channelLookup.begin(), m_channelLookup.end(), SSortSpecial(m_channelName, m_frontBackScore));
break;
default: break;
}
}
///-------------------------------------------------------------------------------------------------
void CRendererContext::setDimensionLabel(const size_t idx1, const size_t idx2, const char* label)
{
if (m_dimLabels[idx1].size() <= idx2) { m_dimLabels[idx1].resize(idx2 + 1); }
m_dimLabels[idx1][idx2] = label;
}
size_t CRendererContext::getDimensionLabelCount(const size_t index) const
{
if (m_dimLabels.count(index) == 0) { return 0; }
return m_dimLabels.at(index).size();
}
const char* CRendererContext::getDimensionLabel(const size_t idx1, const size_t idx2) const
{
if (m_dimLabels.count(idx1) == 0 || m_dimLabels.at(idx1).size() <= idx2) { return nullptr; }
return m_dimLabels.at(idx1)[idx2].c_str();
}
///-------------------------------------------------------------------------------------------------
void CRendererContext::clearTransformInfo()
{
m_parentCtx = nullptr;
m_scale = 1;
m_zoom = 1;
m_rotationX = 2;
m_rotationY = 1;
m_translucency = 1;
m_aspect = 1;
m_sampleDuration = 0;
m_timeScale = 1;
m_nElement = 1;
m_nFlowerRing = 1;
m_hasXYZPlotDepth = false;
m_isAxisDisplayed = false;
m_isPositiveOnly = false;
m_isTimeLocked = true;
m_isScrollModeActive = false;
m_checkBoardVisiblity = false;
m_scaleVisiblity = true;
m_dataType = EDataType::Matrix;
m_spectrumFreqRange = 0;
m_minSpectrumFreq = 0;
m_maxSpectrumFreq = 0;
m_erpPlayerActive = false;
m_erpFraction = 0;
m_nStack = 1;
m_stackIdx = 1;
m_faceMeshVisible = true;
m_scalpMeshVisible = true;
}
std::string CRendererContext::getChannelName(const size_t index) const
{
if (index < m_channelName.size()) { return m_channelName[index]; }
std::cout << "No name for channel " << index << std::endl;
return std::string();
}
bool CRendererContext::getChannelLocalisation(const size_t index, float& x, float& y, float& z) const
{
const CVertex& tmp = m_channelPos[index];
x = tmp.x;
y = tmp.y;
z = tmp.z;
return true;
}
bool CRendererContext::isSelected(const size_t index) const
{
for (auto& i : m_channelLookup) { if (i == index) { return true; } }
return false;
}
float CRendererContext::getERPFraction() const
{
const float erpFraction = m_erpFraction + (m_parentCtx ? m_parentCtx->getERPFraction() : 0);
return erpFraction - floorf(erpFraction);
}
} // namespace AdvancedVisualization
} // namespace OpenViBE
@@ -0,0 +1,131 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "mCRendererCube.hpp"
#include "m_RendererTools.hpp"
#include <cmath>
namespace OpenViBE {
namespace AdvancedVisualization {
CRendererCube::CRendererCube() = default;
void CRendererCube::rebuild(const CRendererContext& ctx)
{
IRenderer::rebuild(ctx);
m_vertices.clear();
m_vertices.resize(ctx.getChannelCount());
m_historyIdx = 0;
}
void CRendererCube::refresh(const CRendererContext& ctx)
{
IRenderer::refresh(ctx);
if (!m_nHistory) { return; }
const float indexERP = (m_erpFraction * float(m_nSample - 1));
const float alpha = indexERP - std::floor(indexERP);
const size_t indexERP1 = size_t(indexERP) % m_nSample;
const size_t indexERP2 = size_t(indexERP + 1) % m_nSample;
for (size_t i = 0; i < m_vertices.size(); ++i)
{
m_vertices[i].u = m_history[i][m_nHistory - m_nSample + indexERP1] * (1 - alpha) + m_history[i][m_nHistory - m_nSample + indexERP2] * (alpha);
}
m_historyIdx = m_nHistory;
}
bool CRendererCube::render(const CRendererContext& ctx)
{
if (!ctx.getSelectedCount() || m_vertices.empty() || !m_nHistory) { return false; }
const float d = 3.5;
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluPerspective(60, ctx.getAspect(), .01, 100);
glTranslatef(0, 0, -d);
glRotatef(ctx.getRotationX() * 10, 1, 0, 0);
glRotatef(ctx.getRotationY() * 10, 0, 1, 0);
glMatrixMode(GL_TEXTURE);
glPushMatrix();
glScalef(ctx.getScale(), 1, 1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glScalef(ctx.getZoom(), ctx.getZoom(), ctx.getZoom());
glPushMatrix();
glRotatef(19, 1, 0, 0);
for (size_t j = 0; j < ctx.getSelectedCount(); ++j)
{
CVertex v;
const size_t k = ctx.getSelected(j);
ctx.getChannelLocalisation(k, v.x, v.y, v.z);
const float scale = .1F * (.25F + fabs(m_vertices[k].u * ctx.getScale()));
glPushMatrix();
glTranslatef(v.x, v.y, v.z);
glTexCoord1f(m_vertices[k].u);
glScalef(scale, scale, scale);
glColor3f(1, 1, 1);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
cube();
glColor3f(0, 0, 0);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
cube();
glPopMatrix();
}
glPopMatrix();
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
if (ctx.getCheckBoardVisibility()) { this->drawCoordinateSystem(); }
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_TEXTURE);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
return true;
}
} // namespace AdvancedVisualization
} // namespace OpenViBE
@@ -0,0 +1,41 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "mIRenderer.hpp"
namespace OpenViBE {
namespace AdvancedVisualization {
class CRendererCube : public IRenderer
{
public:
CRendererCube();
void rebuild(const CRendererContext& ctx) override;
void refresh(const CRendererContext& ctx) override;
bool render(const CRendererContext& ctx) override;
protected:
std::vector<CVertex> m_vertices;
};
} // namespace AdvancedVisualization
} // namespace OpenViBE
@@ -0,0 +1,171 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#define _USE_MATH_DEFINES
#include <cmath>
#include "mCRendererFlower.hpp"
namespace OpenViBE {
namespace AdvancedVisualization {
CRendererFlower::CRendererFlower(const size_t multiCount) { m_muliVertices.resize(multiCount); }
void CRendererFlower::rebuild(const CRendererContext& ctx)
{
IRenderer::rebuild(ctx);
m_autoDecimationFactor = 1 + size_t((m_nSample - 1) / ctx.getMaximumSampleCountPerDisplay());
const size_t n = m_nSample / m_autoDecimationFactor;
for (auto& multivertex : m_muliVertices)
{
multivertex.clear();
multivertex.resize(m_nChannel);
for (size_t i = 0; i < m_nChannel; ++i)
{
multivertex[i].resize(n);
for (size_t j = 0; j < m_nSample - m_autoDecimationFactor + 1; j += m_autoDecimationFactor)
{
multivertex[i][j / m_autoDecimationFactor].u = j * m_nInverseSample;
}
}
}
m_circles.clear();
m_circles.resize(n);
for (size_t i = 0; i < n; ++i)
{
m_circles[i].x = cosf(float(ctx.getFlowerRingCount()) * i * float(M_PI) * 2.F / n);
m_circles[i].y = sinf(float(ctx.getFlowerRingCount()) * i * float(M_PI) * 2.F / n);
m_circles[i].z = 0;
}
m_historyIdx = 0;
}
void CRendererFlower::refresh(const CRendererContext& ctx)
{
IRenderer::refresh(ctx);
if (!m_nHistory) { return; }
for (size_t z = 0; z < m_muliVertices.size(); ++z)
{
for (size_t i = 0; i < m_nChannel; ++i)
{
size_t k = ((m_nHistory - 1 - z * m_muliVertices[z][i].size()) / m_nSample) * m_nSample;
std::vector<float>& history = m_history[i];
CVertex* vertex = &m_muliVertices[z][i][0];
CVertex* circleVertex = &m_circles[0];
for (size_t j = 0; j < m_nSample - m_autoDecimationFactor + 1; j += m_autoDecimationFactor, k += m_autoDecimationFactor)
{
float sum = 0;
size_t count = 0;
for (size_t l = 0; l < m_autoDecimationFactor; ++l)
{
if (/*k+l>=m_historyIdx && */k + l < m_nHistory)
{
sum += history[k + l];
count++;
}
}
if (count)
{
const float v = sum / count;
vertex->x = circleVertex->x * v;
vertex->y = circleVertex->y * v;
vertex->z = circleVertex->z * v;
vertex++;
circleVertex++;
}
else
{
vertex++;
circleVertex++;
}
}
}
}
m_historyIdx = m_nHistory;
}
bool CRendererFlower::render(const CRendererContext& ctx)
{
if (!ctx.getSelectedCount() || m_muliVertices.empty() || !m_nHistory) { return false; }
const size_t n = m_nSample / m_autoDecimationFactor;
const size_t d = (m_historyIdx % m_nSample) / m_autoDecimationFactor;
glMatrixMode(GL_TEXTURE);
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
for (size_t i = 0; i < ctx.getSelectedCount(); ++i)
{
glPushMatrix();
glTranslatef(.5F, .5F, 0);
glScalef(ctx.getScale(), ctx.getScale(), ctx.getScale());
for (auto& multi : m_muliVertices)
{
if (!multi.empty())
{
std::vector<CVertex>& vertices = multi[ctx.getSelected(i)];
glVertexPointer(3, GL_FLOAT, sizeof(CVertex), &vertices[0].x);
glTexCoordPointer(1, GL_FLOAT, sizeof(CVertex), &vertices[n - d].u);
glDrawArrays(GL_LINE_STRIP, 0, GLsizei(d));
glVertexPointer(3, GL_FLOAT, sizeof(CVertex), &vertices[d].x);
glTexCoordPointer(1, GL_FLOAT, sizeof(CVertex), &vertices[0].u);
glDrawArrays(GL_LINE_STRIP, 0, GLsizei(n - d));
glBegin(GL_LINES);
glTexCoord1fv(&vertices[n - d].u);
glVertex2fv(&vertices[n - 1].x);
glVertex2fv(&vertices[0].x);
glEnd();
}
}
glPopMatrix();
}
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glMatrixMode(GL_TEXTURE);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
return true;
}
} // namespace AdvancedVisualization
} // namespace OpenViBE
@@ -0,0 +1,42 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "mIRenderer.hpp"
namespace OpenViBE {
namespace AdvancedVisualization {
class CRendererFlower : public IRenderer
{
public:
explicit CRendererFlower(size_t multiCount = 1);
void rebuild(const CRendererContext& ctx) override;
void refresh(const CRendererContext& ctx) override;
bool render(const CRendererContext& ctx) override;
protected:
std::vector<std::vector<std::vector<CVertex>>> m_muliVertices;
std::vector<CVertex> m_circles;
};
} // namespace AdvancedVisualization
} // namespace OpenViBE
@@ -0,0 +1,166 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <cstdint>
#include "mCRendererLine.hpp"
namespace OpenViBE {
namespace AdvancedVisualization {
void CRendererLine::rebuild(const CRendererContext& ctx)
{
IRenderer::rebuild(ctx);
m_vertices.clear();
m_vertices.resize(m_nChannel);
for (size_t i = 0; i < m_nChannel; ++i)
{
m_vertices[i].resize(m_nSample);
for (size_t j = 0; j < m_nSample; ++j) { m_vertices[i][j].x = j * m_nInverseSample; }
}
m_historyIdx = 0;
}
void CRendererLine::refresh(const CRendererContext& ctx)
{
IRenderer::refresh(ctx);
if (!m_nHistory) { return; }
size_t maxIdx;
if (m_historyDrawIdx == 0) { maxIdx = m_nHistory; } // Draw real-time
else { maxIdx = m_historyDrawIdx; } // stay at the m_historyDrawIdx
for (size_t i = 0; i < m_nChannel; ++i)
{
const size_t firstIdx = ((maxIdx - 1) / m_nSample) * m_nSample;
std::vector<float>& history = m_history[i];
CVertex* vertex = &m_vertices[i][0];
for (size_t j = 0; j < m_nSample; ++j)
{
const size_t idx = firstIdx + j;
if (idx < maxIdx) { vertex->y = history[idx]; }
else if (idx >= m_nSample) { vertex->y = history[idx - m_nSample]; }
vertex++;
}
}
m_historyIdx = maxIdx;
}
bool CRendererLine::render(const CRendererContext& ctx)
{
if (!ctx.getSelectedCount() || !m_nHistory) { return false; }
const auto nSample = int(m_nSample);
// When the display is in continuous mode, there will be n1 samples
// displayed until the 'cursor' and n2 samples will be displayed to
// complete the whole window.
// For example at 25s with a display size of 20s
// <- n1 samples -><------------ n2 samples ---------------->
// | ____ | ___ |
// |/ \ | ___ / \ ____ |
// |------\------/|-----/---\--------/-----\___/----\-------|
// | \____/ | / \______/ \______|
// | |___/ |
// Time 25s 10s 20s
const auto n1 = int(m_historyIdx % m_nSample);
const auto n2 = int(nSample - n1);
if (!nSample) { return false; }
const float t1 = n2 * 1.F / nSample;
const float t2 = -n1 * 1.F / nSample;
glDisable(GL_TEXTURE_1D);
glPushMatrix();
glScalef(1, 1.F / ctx.getSelectedCount(), 1);
glTranslatef(0, ctx.isPositiveOnly() ? 0 : 0.5F, 0);
glPushAttrib(GL_CURRENT_BIT);
glColor3f(.2F, .2F, .2F);
glBegin(GL_LINES);
for (size_t i = 0; i < ctx.getSelectedCount(); ++i)
{
glVertex2f(0, float(i));
glVertex2f(1, float(i));
}
glEnd();
glPopAttrib();
glEnableClientState(GL_VERTEX_ARRAY);
for (size_t i = 0; i < ctx.getSelectedCount(); ++i)
{
glPushMatrix();
glTranslatef(0, float(ctx.getSelectedCount() - i) - 1.F, 0);
glScalef(1, ctx.getScale(), 1);
std::vector<CVertex>& vertices = m_vertices[ctx.getSelected(i)];
if (ctx.isScrollModeActive())
{
glPushMatrix();
glTranslatef(t1, 0, 0);
glVertexPointer(3, GL_FLOAT, sizeof(CVertex), &vertices[0].x);
glDrawArrays(GL_LINE_STRIP, 0, n1);
glPopMatrix();
if (n2 > 0)
{
glPushMatrix();
glTranslatef(t2, 0, 0);
glVertexPointer(3, GL_FLOAT, sizeof(CVertex), &vertices[n1].x);
glDrawArrays(GL_LINE_STRIP, 0, n2);
glPopMatrix();
if (n1 > 0)
{
glBegin(GL_LINES);
glVertex2f(vertices[nSample - 1].x + t2, vertices[nSample - 1].y);
glVertex2f(vertices[0].x + t1, vertices[0].y);
glEnd();
}
}
}
else
{
glVertexPointer(3, GL_FLOAT, sizeof(CVertex), &vertices[0].x);
glDrawArrays(GL_LINE_STRIP, 0, nSample);
}
glPopMatrix();
}
glDisableClientState(GL_VERTEX_ARRAY);
glPopMatrix();
return true;
}
} // namespace AdvancedVisualization
} // namespace OpenViBE
@@ -0,0 +1,40 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "mIRenderer.hpp"
namespace OpenViBE {
namespace AdvancedVisualization {
class CRendererLine : public IRenderer
{
public:
CRendererLine() = default;
void rebuild(const CRendererContext& ctx) override;
void refresh(const CRendererContext& ctx) override;
bool render(const CRendererContext& ctx) override;
protected:
std::vector<std::vector<CVertex>> m_vertices;
};
} // namespace AdvancedVisualization
} // namespace OpenViBE
@@ -0,0 +1,664 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#if defined TARGET_HAS_ThirdPartyOpenGL
#include "mCRendererLoreta.hpp"
#include "content/loreta_anatomic_voxels.hpp"
#include "content/loreta_roi_voxels.hpp"
#include "content/Face.obj.hpp"
#include "content/Scalp.obj.hpp"
namespace OpenViBE {
namespace AdvancedVisualization {
namespace {
//-32,8,-40,
int loretaVoxel[2394][3] = {
{ 52, -41, -11 }, { 45, -41, -11 }, { 38, -41, -11 }, { 31, -41, -11 }, { -32, -41, -11 }, { -39, -41, -11 }, { -46, -41, -11 }, { -53, -41, -11 },
{ 52, -41, -4 }, { 45, -41, -4 }, { 38, -41, -4 }, { 31, -41, -4 }, { 24, -41, -4 }, { -25, -41, -4 }, { -32, -41, -4 }, { -39, -41, -4 },
{ -46, -41, -4 }, { -53, -41, -4 }, { 52, -41, 3 }, { 45, -41, 3 }, { 38, -41, 3 }, { 31, -41, 3 }, { 24, -41, 3 }, { -18, -41, 3 }, { -25, -41, 3 },
{ -32, -41, 3 }, { -39, -41, 3 }, { -46, -41, 3 }, { -53, -41, 3 }, { 45, -41, 10 }, { 38, -41, 10 }, { 31, -41, 10 }, { -25, -41, 10 },
{ -32, -41, 10 }, { -39, -41, 10 }, { -46, -41, 10 }, { 38, -41, 17 }, { 31, -41, 17 }, { -32, -41, 17 }, { -39, -41, 17 }, { 59, -34, -18 },
{ 52, -34, -18 }, { 45, -34, -18 }, { 38, -34, -18 }, { 31, -34, -18 }, { -32, -34, -18 }, { -39, -34, -18 }, { -46, -34, -18 }, { -53, -34, -18 },
{ -60, -34, -18 }, { 59, -34, -11 }, { 52, -34, -11 }, { 45, -34, -11 }, { 38, -34, -11 }, { 31, -34, -11 }, { 24, -34, -11 }, { -25, -34, -11 },
{ -32, -34, -11 }, { -39, -34, -11 }, { -46, -34, -11 }, { -53, -34, -11 }, { -60, -34, -11 }, { 59, -34, -4 }, { 52, -34, -4 }, { 31, -34, -4 },
{ 24, -34, -4 }, { 17, -34, -4 }, { -18, -34, -4 }, { -25, -34, -4 }, { -32, -34, -4 }, { -39, -34, -4 }, { -46, -34, -4 }, { -53, -34, -4 },
{ -60, -34, -4 }, { 52, -34, 3 }, { 45, -34, 3 }, { 24, -34, 3 }, { -18, -34, 3 }, { -25, -34, 3 }, { -46, -34, 3 }, { -53, -34, 3 }, { 52, -34, 10 },
{ 45, -34, 10 }, { 38, -34, 10 }, { 31, -34, 10 }, { 24, -34, 10 }, { -25, -34, 10 }, { -32, -34, 10 }, { -39, -34, 10 }, { -46, -34, 10 },
{ -53, -34, 10 }, { 45, -34, 17 }, { 38, -34, 17 }, { 31, -34, 17 }, { -32, -34, 17 }, { -39, -34, 17 }, { -46, -34, 17 }, { 52, -27, -46 },
{ 45, -27, -46 }, { -46, -27, -46 }, { -53, -27, -46 }, { 59, -27, -39 }, { 52, -27, -39 }, { 45, -27, -39 }, { 38, -27, -39 }, { -39, -27, -39 },
{ -46, -27, -39 }, { -53, -27, -39 }, { -60, -27, -39 }, { 59, -27, -32 }, { 52, -27, -32 }, { 45, -27, -32 }, { 38, -27, -32 }, { 31, -27, -32 },
{ -32, -27, -32 }, { -39, -27, -32 }, { -46, -27, -32 }, { -53, -27, -32 }, { -60, -27, -32 }, { 59, -27, -25 }, { 52, -27, -25 }, { 45, -27, -25 },
{ 38, -27, -25 }, { 31, -27, -25 }, { 24, -27, -25 }, { -25, -27, -25 }, { -32, -27, -25 }, { -39, -27, -25 }, { -46, -27, -25 }, { -53, -27, -25 },
{ -60, -27, -25 }, { 59, -27, -18 }, { 52, -27, -18 }, { 45, -27, -18 }, { 38, -27, -18 }, { 31, -27, -18 }, { -32, -27, -18 }, { -39, -27, -18 },
{ -46, -27, -18 }, { -53, -27, -18 }, { -60, -27, -18 }, { 59, -27, -11 }, { 52, -27, -11 }, { 38, -27, -11 }, { 31, -27, -11 }, { 24, -27, -11 },
{ 17, -27, -11 }, { -18, -27, -11 }, { -25, -27, -11 }, { -32, -27, -11 }, { -39, -27, -11 }, { -53, -27, -11 }, { -60, -27, -11 }, { 59, -27, -4 },
{ 52, -27, -4 }, { 31, -27, -4 }, { 24, -27, -4 }, { 17, -27, -4 }, { -18, -27, -4 }, { -25, -27, -4 }, { -32, -27, -4 }, { -60, -27, -4 },
{ 59, -27, 3 }, { 52, -27, 3 }, { 31, -27, 3 }, { 24, -27, 3 }, { 17, -27, 3 }, { -18, -27, 3 }, { -25, -27, 3 }, { -32, -27, 3 }, { -53, -27, 3 },
{ -60, -27, 3 }, { 52, -27, 10 }, { 45, -27, 10 }, { 38, -27, 10 }, { 31, -27, 10 }, { -32, -27, 10 }, { -39, -27, 10 }, { -46, -27, 10 },
{ -53, -27, 10 }, { 45, -27, 17 }, { 38, -27, 17 }, { 31, -27, 17 }, { -32, -27, 17 }, { -39, -27, 17 }, { -46, -27, 17 }, { 10, -27, 24 },
{ 3, -27, 24 }, { -4, -27, 24 }, { -11, -27, 24 }, { 10, -27, 31 }, { 3, -27, 31 }, { -4, -27, 31 }, { -11, -27, 31 }, { 10, -27, 38 }, { 3, -27, 38 },
{ -4, -27, 38 }, { -11, -27, 38 }, { 10, -27, 45 }, { 3, -27, 45 }, { -4, -27, 45 }, { -11, -27, 45 }, { 10, -27, 52 }, { 3, -27, 52 }, { -4, -27, 52 },
{ -11, -27, 52 }, { 52, -20, -60 }, { 45, -20, -60 }, { 38, -20, -60 }, { -39, -20, -60 }, { -46, -20, -60 }, { -53, -20, -60 }, { 59, -20, -53 },
{ 52, -20, -53 }, { 45, -20, -53 }, { 38, -20, -53 }, { 31, -20, -53 }, { -32, -20, -53 }, { -39, -20, -53 }, { -46, -20, -53 }, { -53, -20, -53 },
{ -60, -20, -53 }, { 59, -20, -46 }, { 52, -20, -46 }, { 45, -20, -46 }, { 38, -20, -46 }, { 31, -20, -46 }, { -32, -20, -46 }, { -39, -20, -46 },
{ -46, -20, -46 }, { -53, -20, -46 }, { -60, -20, -46 }, { 66, -20, -39 }, { 59, -20, -39 }, { 52, -20, -39 }, { 45, -20, -39 }, { 38, -20, -39 },
{ 31, -20, -39 }, { 24, -20, -39 }, { -25, -20, -39 }, { -32, -20, -39 }, { -39, -20, -39 }, { -46, -20, -39 }, { -53, -20, -39 }, { -60, -20, -39 },
{ 66, -20, -32 }, { 59, -20, -32 }, { 52, -20, -32 }, { 45, -20, -32 }, { 38, -20, -32 }, { 31, -20, -32 }, { 24, -20, -32 }, { -25, -20, -32 },
{ -32, -20, -32 }, { -39, -20, -32 }, { -46, -20, -32 }, { -53, -20, -32 }, { -60, -20, -32 }, { -67, -20, -32 }, { 66, -20, -25 }, { 59, -20, -25 },
{ 38, -20, -25 }, { 31, -20, -25 }, { -25, -20, -25 }, { -32, -20, -25 }, { -39, -20, -25 }, { -60, -20, -25 }, { -67, -20, -25 }, { 66, -20, -18 },
{ 59, -20, -18 }, { 38, -20, -18 }, { 31, -20, -18 }, { 24, -20, -18 }, { 17, -20, -18 }, { -18, -20, -18 }, { -25, -20, -18 }, { -32, -20, -18 },
{ -60, -20, -18 }, { -67, -20, -18 }, { 66, -20, -11 }, { 59, -20, -11 }, { 31, -20, -11 }, { 24, -20, -11 }, { 17, -20, -11 }, { -18, -20, -11 },
{ -25, -20, -11 }, { -32, -20, -11 }, { -60, -20, -11 }, { -67, -20, -11 }, { 59, -20, -4 }, { 52, -20, -4 }, { 31, -20, -4 }, { 24, -20, -4 },
{ 17, -20, -4 }, { -18, -20, -4 }, { -25, -20, -4 }, { -32, -20, -4 }, { -53, -20, -4 }, { -60, -20, -4 }, { 59, -20, 3 }, { 52, -20, 3 },
{ 45, -20, 3 }, { 38, -20, 3 }, { 31, -20, 3 }, { -25, -20, 3 }, { -32, -20, 3 }, { -39, -20, 3 }, { -46, -20, 3 }, { -53, -20, 3 }, { -60, -20, 3 },
{ 52, -20, 10 }, { 45, -20, 10 }, { 24, -20, 10 }, { 17, -20, 10 }, { 10, -20, 10 }, { -4, -20, 10 }, { -11, -20, 10 }, { -18, -20, 10 },
{ -25, -20, 10 }, { -46, -20, 10 }, { -53, -20, 10 }, { 52, -20, 17 }, { 45, -20, 17 }, { 38, -20, 17 }, { 31, -20, 17 }, { 24, -20, 17 },
{ 17, -20, 17 }, { 10, -20, 17 }, { 3, -20, 17 }, { -4, -20, 17 }, { -11, -20, 17 }, { -18, -20, 17 }, { -25, -20, 17 }, { -32, -20, 17 },
{ -46, -20, 17 }, { -53, -20, 17 }, { 38, -20, 24 }, { 31, -20, 24 }, { 24, -20, 24 }, { 17, -20, 24 }, { 10, -20, 24 }, { 3, -20, 24 },
{ -4, -20, 24 }, { -11, -20, 24 }, { -18, -20, 24 }, { -25, -20, 24 }, { -32, -20, 24 }, { -39, -20, 24 }, { 38, -20, 31 }, { 31, -20, 31 },
{ 24, -20, 31 }, { 10, -20, 31 }, { 3, -20, 31 }, { -4, -20, 31 }, { -11, -20, 31 }, { -18, -20, 31 }, { -25, -20, 31 }, { -32, -20, 31 },
{ -39, -20, 31 }, { 24, -20, 38 }, { 10, -20, 38 }, { 3, -20, 38 }, { -4, -20, 38 }, { -11, -20, 38 }, { -18, -20, 38 }, { -25, -20, 38 },
{ 17, -20, 45 }, { 10, -20, 45 }, { 3, -20, 45 }, { -4, -20, 45 }, { -11, -20, 45 }, { -18, -20, 45 }, { -25, -20, 45 }, { 17, -20, 52 },
{ 3, -20, 52 }, { -4, -20, 52 }, { -18, -20, 52 }, { 10, -20, 59 }, { 3, -20, 59 }, { -4, -20, 59 }, { -11, -20, 59 }, { -18, -20, 59 },
{ 17, -13, -102 }, { 10, -13, -102 }, { 17, -13, -95 }, { 10, -13, -95 }, { 3, -13, -95 }, { -32, -13, -95 }, { 38, -13, -88 }, { 17, -13, -88 },
{ 10, -13, -88 }, { 3, -13, -88 }, { -4, -13, -88 }, { -11, -13, -88 }, { -18, -13, -88 }, { -25, -13, -88 }, { -32, -13, -88 }, { -39, -13, -88 },
{ 45, -13, -81 }, { 38, -13, -81 }, { 31, -13, -81 }, { 24, -13, -81 }, { 17, -13, -81 }, { 10, -13, -81 }, { 3, -13, -81 }, { -4, -13, -81 },
{ -11, -13, -81 }, { -18, -13, -81 }, { -39, -13, -81 }, { -46, -13, -81 }, { 45, -13, -74 }, { 38, -13, -74 }, { -32, -13, -74 }, { -39, -13, -74 },
{ -46, -13, -74 }, { 52, -13, -67 }, { 45, -13, -67 }, { 38, -13, -67 }, { -39, -13, -67 }, { -46, -13, -67 }, { -53, -13, -67 }, { 59, -13, -60 },
{ 52, -13, -60 }, { 45, -13, -60 }, { 38, -13, -60 }, { 31, -13, -60 }, { -39, -13, -60 }, { -46, -13, -60 }, { -53, -13, -60 }, { -60, -13, -60 },
{ 59, -13, -53 }, { 52, -13, -53 }, { 45, -13, -53 }, { 38, -13, -53 }, { -46, -13, -53 }, { -53, -13, -53 }, { -60, -13, -53 }, { 66, -13, -46 },
{ 59, -13, -46 }, { 52, -13, -46 }, { 45, -13, -46 }, { 31, -13, -46 }, { 24, -13, -46 }, { -46, -13, -46 }, { -53, -13, -46 }, { -60, -13, -46 },
{ -67, -13, -46 }, { 66, -13, -39 }, { 59, -13, -39 }, { 31, -13, -39 }, { 24, -13, -39 }, { 17, -13, -39 }, { -25, -13, -39 }, { -32, -13, -39 },
{ -60, -13, -39 }, { -67, -13, -39 }, { 66, -13, -32 }, { 59, -13, -32 }, { 31, -13, -32 }, { 24, -13, -32 }, { 17, -13, -32 }, { -18, -13, -32 },
{ -32, -13, -32 }, { -60, -13, -32 }, { -67, -13, -32 }, { 66, -13, -25 }, { 59, -13, -25 }, { 38, -13, -25 }, { 31, -13, -25 }, { 24, -13, -25 },
{ -25, -13, -25 }, { -32, -13, -25 }, { -39, -13, -25 }, { -60, -13, -25 }, { -67, -13, -25 }, { 66, -13, -18 }, { 59, -13, -18 }, { 52, -13, -18 },
{ 31, -13, -18 }, { 24, -13, -18 }, { -32, -13, -18 }, { -53, -13, -18 }, { -67, -13, -18 }, { 66, -13, -11 }, { 59, -13, -11 }, { 52, -13, -11 },
{ 24, -13, -11 }, { 17, -13, -11 }, { -18, -13, -11 }, { -25, -13, -11 }, { -53, -13, -11 }, { -60, -13, -11 }, { -67, -13, -11 }, { 59, -13, -4 },
{ 52, -13, -4 }, { 45, -13, -4 }, { 38, -13, -4 }, { 31, -13, -4 }, { 24, -13, -4 }, { 17, -13, -4 }, { 10, -13, -4 }, { -18, -13, -4 },
{ -25, -13, -4 }, { -39, -13, -4 }, { -46, -13, -4 }, { -53, -13, -4 }, { -60, -13, -4 }, { 59, -13, 3 }, { 52, -13, 3 }, { 45, -13, 3 },
{ 38, -13, 3 }, { 31, -13, 3 }, { 24, -13, 3 }, { 17, -13, 3 }, { 10, -13, 3 }, { 3, -13, 3 }, { -4, -13, 3 }, { -11, -13, 3 }, { -18, -13, 3 },
{ -25, -13, 3 }, { -32, -13, 3 }, { -39, -13, 3 }, { -46, -13, 3 }, { -53, -13, 3 }, { -60, -13, 3 }, { 52, -13, 10 }, { 38, -13, 10 }, { 31, -13, 10 },
{ 24, -13, 10 }, { 17, -13, 10 }, { 10, -13, 10 }, { 3, -13, 10 }, { -4, -13, 10 }, { -11, -13, 10 }, { -18, -13, 10 }, { -25, -13, 10 },
{ -32, -13, 10 }, { -39, -13, 10 }, { -46, -13, 10 }, { -53, -13, 10 }, { 52, -13, 17 }, { 45, -13, 17 }, { 38, -13, 17 }, { 31, -13, 17 },
{ 3, -13, 17 }, { -4, -13, 17 }, { -11, -13, 17 }, { -32, -13, 17 }, { -39, -13, 17 }, { -46, -13, 17 }, { -53, -13, 17 }, { 45, -13, 24 },
{ 3, -13, 24 }, { -4, -13, 24 }, { -32, -13, 24 }, { -39, -13, 24 }, { -46, -13, 24 }, { 45, -13, 31 }, { 38, -13, 31 }, { 31, -13, 31 },
{ 24, -13, 31 }, { 3, -13, 31 }, { -4, -13, 31 }, { -25, -13, 31 }, { -46, -13, 31 }, { 52, -13, 38 }, { 38, -13, 38 }, { 31, -13, 38 },
{ 24, -13, 38 }, { 10, -13, 38 }, { 3, -13, 38 }, { -4, -13, 38 }, { -25, -13, 38 }, { -32, -13, 38 }, { -39, -13, 38 }, { 45, -13, 45 },
{ 38, -13, 45 }, { 31, -13, 45 }, { 24, -13, 45 }, { 10, -13, 45 }, { 3, -13, 45 }, { -4, -13, 45 }, { -25, -13, 45 }, { -32, -13, 45 },
{ -39, -13, 45 }, { -46, -13, 45 }, { 38, -13, 52 }, { 31, -13, 52 }, { 24, -13, 52 }, { 3, -13, 52 }, { -4, -13, 52 }, { -25, -13, 52 },
{ -32, -13, 52 }, { -39, -13, 52 }, { 38, -13, 59 }, { 31, -13, 59 }, { 24, -13, 59 }, { 3, -13, 59 }, { -4, -13, 59 }, { -18, -13, 59 },
{ -25, -13, 59 }, { -32, -13, 59 }, { -39, -13, 59 }, { 17, -13, 66 }, { 10, -13, 66 }, { 3, -13, 66 }, { -4, -13, 66 }, { -11, -13, 66 },
{ -18, -13, 66 }, { -25, -13, 66 }, { 24, -6, -102 }, { 17, -6, -102 }, { 10, -6, -102 }, { 10, -6, -95 }, { 3, -6, -95 }, { -32, -6, -95 },
{ 45, -6, -88 }, { 38, -6, -88 }, { 31, -6, -88 }, { 3, -6, -88 }, { -4, -6, -88 }, { -39, -6, -88 }, { 45, -6, -81 }, { 3, -6, -81 }, { -4, -6, -81 },
{ -46, -6, -81 }, { 52, -6, -74 }, { 45, -6, -74 }, { 10, -6, -74 }, { 3, -6, -74 }, { -4, -6, -74 }, { -11, -6, -74 }, { -25, -6, -74 },
{ -46, -6, -74 }, { -53, -6, -74 }, { 59, -6, -67 }, { 52, -6, -67 }, { 45, -6, -67 }, { 24, -6, -67 }, { 17, -6, -67 }, { 10, -6, -67 },
{ -11, -6, -67 }, { -18, -6, -67 }, { -25, -6, -67 }, { -46, -6, -67 }, { -53, -6, -67 }, { 59, -6, -60 }, { 52, -6, -60 }, { 45, -6, -60 },
{ 24, -6, -60 }, { 17, -6, -60 }, { 10, -6, -60 }, { -11, -6, -60 }, { -18, -6, -60 }, { -25, -6, -60 }, { -46, -6, -60 }, { -53, -6, -60 },
{ -60, -6, -60 }, { 66, -6, -53 }, { 59, -6, -53 }, { 31, -6, -53 }, { 24, -6, -53 }, { 17, -6, -53 }, { 10, -6, -53 }, { -11, -6, -53 },
{ -18, -6, -53 }, { -25, -6, -53 }, { -32, -6, -53 }, { -46, -6, -53 }, { -53, -6, -53 }, { -60, -6, -53 }, { 66, -6, -46 }, { 59, -6, -46 },
{ 31, -6, -46 }, { 24, -6, -46 }, { 17, -6, -46 }, { -11, -6, -46 }, { -18, -6, -46 }, { -25, -6, -46 }, { -32, -6, -46 }, { -60, -6, -46 },
{ -67, -6, -46 }, { 66, -6, -39 }, { 59, -6, -39 }, { 31, -6, -39 }, { 24, -6, -39 }, { -18, -6, -39 }, { -32, -6, -39 }, { -60, -6, -39 },
{ -67, -6, -39 }, { 66, -6, -32 }, { 59, -6, -32 }, { 52, -6, -32 }, { 31, -6, -32 }, { 24, -6, -32 }, { 17, -6, -32 }, { -18, -6, -32 },
{ -25, -6, -32 }, { -32, -6, -32 }, { -53, -6, -32 }, { -60, -6, -32 }, { -67, -6, -32 }, { 66, -6, -25 }, { 59, -6, -25 }, { 52, -6, -25 },
{ -46, -6, -25 }, { -53, -6, -25 }, { -60, -6, -25 }, { -67, -6, -25 }, { 66, -6, -18 }, { 59, -6, -18 }, { 52, -6, -18 }, { 38, -6, -18 },
{ -53, -6, -18 }, { -60, -6, -18 }, { -67, -6, -18 }, { 59, -6, -11 }, { 52, -6, -11 }, { 45, -6, -11 }, { 38, -6, -11 }, { 3, -6, -11 },
{ -4, -6, -11 }, { -39, -6, -11 }, { -46, -6, -11 }, { -53, -6, -11 }, { -60, -6, -11 }, { -67, -6, -11 }, { 59, -6, -4 }, { 38, -6, -4 },
{ 3, -6, -4 }, { -4, -6, -4 }, { -39, -6, -4 }, { -46, -6, -4 }, { -53, -6, -4 }, { -60, -6, -4 }, { 59, -6, 3 }, { 52, -6, 3 }, { 38, -6, 3 },
{ 3, -6, 3 }, { -4, -6, 3 }, { -39, -6, 3 }, { -53, -6, 3 }, { -60, -6, 3 }, { 52, -6, 10 }, { 38, -6, 10 }, { 3, -6, 10 }, { -4, -6, 10 },
{ -39, -6, 10 }, { -46, -6, 10 }, { -53, -6, 10 }, { -60, -6, 10 }, { 38, -6, 17 }, { 31, -6, 17 }, { 3, -6, 17 }, { -4, -6, 17 }, { -32, -6, 17 },
{ -39, -6, 17 }, { 52, -6, 24 }, { 45, -6, 24 }, { 38, -6, 24 }, { 31, -6, 24 }, { 3, -6, 24 }, { -4, -6, 24 }, { -32, -6, 24 }, { -39, -6, 24 },
{ -46, -6, 24 }, { -53, -6, 24 }, { 52, -6, 31 }, { 45, -6, 31 }, { 3, -6, 31 }, { -4, -6, 31 }, { -46, -6, 31 }, { -53, -6, 31 }, { 52, -6, 38 },
{ 45, -6, 38 }, { 10, -6, 38 }, { 3, -6, 38 }, { -4, -6, 38 }, { -11, -6, 38 }, { -53, -6, 38 }, { 45, -6, 45 }, { 10, -6, 45 }, { 3, -6, 45 },
{ -4, -6, 45 }, { -11, -6, 45 }, { -46, -6, 45 }, { 45, -6, 52 }, { 38, -6, 52 }, { 10, -6, 52 }, { 3, -6, 52 }, { -4, -6, 52 }, { -11, -6, 52 },
{ -39, -6, 52 }, { -46, -6, 52 }, { 38, -6, 59 }, { 31, -6, 59 }, { 24, -6, 59 }, { 3, -6, 59 }, { -4, -6, 59 }, { -25, -6, 59 }, { -32, -6, 59 },
{ -39, -6, 59 }, { 24, -6, 66 }, { 17, -6, 66 }, { 10, -6, 66 }, { 3, -6, 66 }, { -4, -6, 66 }, { -11, -6, 66 }, { -18, -6, 66 }, { -25, -6, 66 },
{ -32, -6, 66 }, { 24, 1, -102 }, { 31, 1, -95 }, { 3, 1, -95 }, { -32, 1, -95 }, { 45, 1, -88 }, { 38, 1, -88 }, { 31, 1, -88 }, { 10, 1, -88 },
{ 3, 1, -88 }, { -4, 1, -88 }, { -11, 1, -88 }, { -32, 1, -88 }, { -39, 1, -88 }, { 45, 1, -81 }, { 10, 1, -81 }, { 3, 1, -81 }, { -4, 1, -81 },
{ -11, 1, -81 }, { -46, 1, -81 }, { 52, 1, -74 }, { 45, 1, -74 }, { 3, 1, -74 }, { -4, 1, -74 }, { -46, 1, -74 }, { -53, 1, -74 }, { 59, 1, -67 },
{ 52, 1, -67 }, { 45, 1, -67 }, { 17, 1, -67 }, { 10, 1, -67 }, { 3, 1, -67 }, { -4, 1, -67 }, { -46, 1, -67 }, { -53, 1, -67 }, { 59, 1, -60 },
{ 52, 1, -60 }, { 17, 1, -60 }, { 10, 1, -60 }, { -11, 1, -60 }, { -46, 1, -60 }, { -53, 1, -60 }, { -60, 1, -60 }, { 66, 1, -53 }, { 59, 1, -53 },
{ 24, 1, -53 }, { 17, 1, -53 }, { 10, 1, -53 }, { -11, 1, -53 }, { -18, 1, -53 }, { -25, 1, -53 }, { -32, 1, -53 }, { -60, 1, -53 }, { 66, 1, -46 },
{ 59, 1, -46 }, { 52, 1, -46 }, { 10, 1, -46 }, { -11, 1, -46 }, { -18, 1, -46 }, { -60, 1, -46 }, { -67, 1, -46 }, { 66, 1, -39 }, { 59, 1, -39 },
{ 52, 1, -39 }, { 31, 1, -39 }, { 24, 1, -39 }, { 17, 1, -39 }, { -11, 1, -39 }, { -18, 1, -39 }, { -25, 1, -39 }, { -46, 1, -39 }, { -53, 1, -39 },
{ -60, 1, -39 }, { -67, 1, -39 }, { 66, 1, -32 }, { 59, 1, -32 }, { 52, 1, -32 }, { -46, 1, -32 }, { -53, 1, -32 }, { -60, 1, -32 }, { -67, 1, -32 },
{ 66, 1, -25 }, { 59, 1, -25 }, { 38, 1, -25 }, { -53, 1, -25 }, { -60, 1, -25 }, { -67, 1, -25 }, { 66, 1, -18 }, { 45, 1, -18 }, { 38, 1, -18 },
{ 31, 1, -18 }, { -39, 1, -18 }, { -46, 1, -18 }, { -67, 1, -18 }, { 59, 1, -11 }, { 52, 1, -11 }, { 38, 1, -11 }, { 31, 1, -11 }, { -39, 1, -11 },
{ -46, 1, -11 }, { -67, 1, -11 }, { 59, 1, -4 }, { 52, 1, -4 }, { 45, 1, -4 }, { 38, 1, -4 }, { -39, 1, -4 }, { -53, 1, -4 }, { -60, 1, -4 },
{ 59, 1, 3 }, { 52, 1, 3 }, { 45, 1, 3 }, { 38, 1, 3 }, { -39, 1, 3 }, { -46, 1, 3 }, { -53, 1, 3 }, { -60, 1, 3 }, { 52, 1, 10 }, { 45, 1, 10 },
{ 38, 1, 10 }, { -39, 1, 10 }, { -46, 1, 10 }, { -53, 1, 10 }, { 52, 1, 17 }, { 45, 1, 17 }, { 38, 1, 17 }, { 31, 1, 17 }, { -32, 1, 17 },
{ -39, 1, 17 }, { -46, 1, 17 }, { -53, 1, 17 }, { 52, 1, 24 }, { 45, 1, 24 }, { 38, 1, 24 }, { 31, 1, 24 }, { -32, 1, 24 }, { -39, 1, 24 },
{ -46, 1, 24 }, { -53, 1, 24 }, { 52, 1, 31 }, { 38, 1, 31 }, { 31, 1, 31 }, { -32, 1, 31 }, { -39, 1, 31 }, { -53, 1, 31 }, { 52, 1, 38 },
{ 3, 1, 38 }, { -4, 1, 38 }, { -46, 1, 38 }, { -53, 1, 38 }, { 45, 1, 45 }, { 38, 1, 45 }, { 10, 1, 45 }, { 3, 1, 45 }, { -4, 1, 45 }, { -11, 1, 45 },
{ -39, 1, 45 }, { -46, 1, 45 }, { 45, 1, 52 }, { 38, 1, 52 }, { 24, 1, 52 }, { 10, 1, 52 }, { 3, 1, 52 }, { -4, 1, 52 }, { -11, 1, 52 }, { -25, 1, 52 },
{ -32, 1, 52 }, { -39, 1, 52 }, { -46, 1, 52 }, { 38, 1, 59 }, { 31, 1, 59 }, { 24, 1, 59 }, { 10, 1, 59 }, { 3, 1, 59 }, { -4, 1, 59 }, { -25, 1, 59 },
{ -32, 1, 59 }, { -39, 1, 59 }, { 24, 1, 66 }, { 17, 1, 66 }, { 10, 1, 66 }, { 3, 1, 66 }, { -4, 1, 66 }, { -11, 1, 66 }, { -18, 1, 66 },
{ -25, 1, 66 }, { 31, 8, -95 }, { -4, 8, -95 }, { -32, 8, -95 }, { 45, 8, -88 }, { 38, 8, -88 }, { 31, 8, -88 }, { 3, 8, -88 }, { -4, 8, -88 },
{ -11, 8, -88 }, { -32, 8, -88 }, { -39, 8, -88 }, { 45, 8, -81 }, { 10, 8, -81 }, { 3, 8, -81 }, { -4, 8, -81 }, { -11, 8, -81 }, { -39, 8, -81 },
{ -46, 8, -81 }, { 52, 8, -74 }, { 45, 8, -74 }, { 10, 8, -74 }, { 3, 8, -74 }, { -4, 8, -74 }, { -11, 8, -74 }, { -46, 8, -74 }, { -53, 8, -74 },
{ 59, 8, -67 }, { 52, 8, -67 }, { 45, 8, -67 }, { 24, 8, -67 }, { 17, 8, -67 }, { 10, 8, -67 }, { 3, 8, -67 }, { -4, 8, -67 }, { -11, 8, -67 },
{ -18, 8, -67 }, { -25, 8, -67 }, { -46, 8, -67 }, { -53, 8, -67 }, { 59, 8, -60 }, { 52, 8, -60 }, { 45, 8, -60 }, { 24, 8, -60 }, { 17, 8, -60 },
{ 10, 8, -60 }, { 3, 8, -60 }, { -4, 8, -60 }, { -11, 8, -60 }, { -18, 8, -60 }, { -25, 8, -60 }, { -46, 8, -60 }, { -53, 8, -60 }, { -60, 8, -60 },
{ 66, 8, -53 }, { 59, 8, -53 }, { 52, 8, -53 }, { 10, 8, -53 }, { -4, 8, -53 }, { -11, 8, -53 }, { -18, 8, -53 }, { -25, 8, -53 }, { -46, 8, -53 },
{ -53, 8, -53 }, { -60, 8, -53 }, { 66, 8, -46 }, { 59, 8, -46 }, { 52, 8, -46 }, { -4, 8, -46 }, { -53, 8, -46 }, { -60, 8, -46 }, { -67, 8, -46 },
{ 66, 8, -39 }, { 59, 8, -39 }, { 52, 8, -39 }, { -46, 8, -39 }, { -53, 8, -39 }, { -60, 8, -39 }, { -67, 8, -39 }, { 66, 8, -32 }, { 59, 8, -32 },
{ 52, 8, -32 }, { 45, 8, -32 }, { -60, 8, -32 }, { -67, 8, -32 }, { 66, 8, -25 }, { 59, 8, -25 }, { 52, 8, -25 }, { 45, 8, -25 }, { 38, 8, -25 },
{ 31, 8, -25 }, { -46, 8, -25 }, { -60, 8, -25 }, { -67, 8, -25 }, { 66, 8, -18 }, { 59, 8, -18 }, { 52, 8, -18 }, { 45, 8, -18 }, { 38, 8, -18 },
{ -39, 8, -18 }, { -46, 8, -18 }, { -53, 8, -18 }, { -60, 8, -18 }, { -67, 8, -18 }, { 59, 8, -11 }, { 52, 8, -11 }, { 45, 8, -11 }, { 38, 8, -11 },
{ -39, 8, -11 }, { -46, 8, -11 }, { -53, 8, -11 }, { -60, 8, -11 }, { 59, 8, -4 }, { 52, 8, -4 }, { 45, 8, -4 }, { 38, 8, -4 }, { -39, 8, -4 },
{ -46, 8, -4 }, { -53, 8, -4 }, { -60, 8, -4 }, { 59, 8, 3 }, { 45, 8, 3 }, { 38, 8, 3 }, { -39, 8, 3 }, { -46, 8, 3 }, { -53, 8, 3 }, { -60, 8, 3 },
{ 59, 8, 10 }, { 52, 8, 10 }, { 38, 8, 10 }, { 31, 8, 10 }, { -32, 8, 10 }, { -39, 8, 10 }, { -46, 8, 10 }, { -53, 8, 10 }, { -60, 8, 10 },
{ 52, 8, 17 }, { 45, 8, 17 }, { 38, 8, 17 }, { 31, 8, 17 }, { -32, 8, 17 }, { -39, 8, 17 }, { -46, 8, 17 }, { -53, 8, 17 }, { -60, 8, 17 },
{ 52, 8, 24 }, { 38, 8, 24 }, { 31, 8, 24 }, { -32, 8, 24 }, { -39, 8, 24 }, { -46, 8, 24 }, { -53, 8, 24 }, { 52, 8, 31 }, { -53, 8, 31 },
{ 52, 8, 38 }, { 45, 8, 38 }, { 38, 8, 38 }, { 3, 8, 38 }, { -4, 8, 38 }, { -11, 8, 38 }, { -39, 8, 38 }, { -46, 8, 38 }, { -53, 8, 38 }, { 45, 8, 45 },
{ 38, 8, 45 }, { 10, 8, 45 }, { 3, 8, 45 }, { -4, 8, 45 }, { -11, 8, 45 }, { -39, 8, 45 }, { -46, 8, 45 }, { 45, 8, 52 }, { 38, 8, 52 }, { 31, 8, 52 },
{ 24, 8, 52 }, { 10, 8, 52 }, { 3, 8, 52 }, { -4, 8, 52 }, { -11, 8, 52 }, { -25, 8, 52 }, { -32, 8, 52 }, { -39, 8, 52 }, { -46, 8, 52 },
{ 38, 8, 59 }, { 31, 8, 59 }, { 24, 8, 59 }, { 10, 8, 59 }, { 3, 8, 59 }, { -4, 8, 59 }, { -11, 8, 59 }, { -25, 8, 59 }, { -32, 8, 59 }, { -39, 8, 59 },
{ 24, 8, 66 }, { 17, 8, 66 }, { 10, 8, 66 }, { -4, 8, 66 }, { -11, 8, 66 }, { -18, 8, 66 }, { -25, 8, 66 }, { 31, 15, -95 }, { 24, 15, -95 },
{ 3, 15, -95 }, { 38, 15, -88 }, { 31, 15, -88 }, { 3, 15, -88 }, { -4, 15, -88 }, { -39, 15, -88 }, { 45, 15, -81 }, { 38, 15, -81 }, { 3, 15, -81 },
{ -4, 15, -81 }, { -39, 15, -81 }, { -46, 15, -81 }, { 52, 15, -74 }, { 45, 15, -74 }, { 38, 15, -74 }, { 3, 15, -74 }, { -4, 15, -74 },
{ -11, 15, -74 }, { -39, 15, -74 }, { -46, 15, -74 }, { -53, 15, -74 }, { 59, 15, -67 }, { 52, 15, -67 }, { 45, 15, -67 }, { 38, 15, -67 },
{ 17, 15, -67 }, { 10, 15, -67 }, { 3, 15, -67 }, { -4, 15, -67 }, { -11, 15, -67 }, { -18, 15, -67 }, { -46, 15, -67 }, { -53, 15, -67 },
{ 59, 15, -60 }, { 52, 15, -60 }, { 45, 15, -60 }, { 17, 15, -60 }, { 10, 15, -60 }, { 3, 15, -60 }, { -4, 15, -60 }, { -11, 15, -60 },
{ -18, 15, -60 }, { -46, 15, -60 }, { -53, 15, -60 }, { -60, 15, -60 }, { 59, 15, -53 }, { 52, 15, -53 }, { 45, 15, -53 }, { 3, 15, -53 },
{ -4, 15, -53 }, { -11, 15, -53 }, { -18, 15, -53 }, { -46, 15, -53 }, { -53, 15, -53 }, { -60, 15, -53 }, { 66, 15, -46 }, { 59, 15, -46 },
{ 52, 15, -46 }, { 3, 15, -46 }, { -4, 15, -46 }, { -46, 15, -46 }, { -53, 15, -46 }, { -60, 15, -46 }, { -67, 15, -46 }, { 66, 15, -39 },
{ 59, 15, -39 }, { 45, 15, -39 }, { -53, 15, -39 }, { -60, 15, -39 }, { -67, 15, -39 }, { 66, 15, -32 }, { 59, 15, -32 }, { 52, 15, -32 },
{ 45, 15, -32 }, { 38, 15, -32 }, { -39, 15, -32 }, { -46, 15, -32 }, { -53, 15, -32 }, { -60, 15, -32 }, { -67, 15, -32 }, { 66, 15, -25 },
{ 59, 15, -25 }, { 52, 15, -25 }, { 45, 15, -25 }, { 38, 15, -25 }, { 31, 15, -25 }, { -32, 15, -25 }, { -39, 15, -25 }, { -46, 15, -25 },
{ -53, 15, -25 }, { -60, 15, -25 }, { -67, 15, -25 }, { 66, 15, -18 }, { 59, 15, -18 }, { 52, 15, -18 }, { 45, 15, -18 }, { 38, 15, -18 },
{ -39, 15, -18 }, { -46, 15, -18 }, { -53, 15, -18 }, { -60, 15, -18 }, { -67, 15, -18 }, { 66, 15, -11 }, { 52, 15, -11 }, { 45, 15, -11 },
{ 38, 15, -11 }, { -39, 15, -11 }, { -46, 15, -11 }, { -53, 15, -11 }, { -60, 15, -11 }, { -67, 15, -11 }, { 59, 15, -4 }, { 38, 15, -4 },
{ -39, 15, -4 }, { -60, 15, -4 }, { -67, 15, -4 }, { 59, 15, 3 }, { -39, 15, 3 }, { -60, 15, 3 }, { 59, 15, 10 }, { 52, 15, 10 }, { -53, 15, 10 },
{ -60, 15, 10 }, { 59, 15, 17 }, { 52, 15, 17 }, { -53, 15, 17 }, { -60, 15, 17 }, { -53, 15, 24 }, { 52, 15, 31 }, { 45, 15, 31 }, { 3, 15, 31 },
{ -4, 15, 31 }, { -39, 15, 31 }, { -46, 15, 31 }, { -53, 15, 31 }, { 45, 15, 38 }, { 38, 15, 38 }, { 10, 15, 38 }, { 3, 15, 38 }, { -4, 15, 38 },
{ -11, 15, 38 }, { -46, 15, 38 }, { -53, 15, 38 }, { 45, 15, 45 }, { 38, 15, 45 }, { 24, 15, 45 }, { 10, 15, 45 }, { 3, 15, 45 }, { -4, 15, 45 },
{ -11, 15, 45 }, { -46, 15, 45 }, { 38, 15, 52 }, { 31, 15, 52 }, { 24, 15, 52 }, { 10, 15, 52 }, { 3, 15, 52 }, { -4, 15, 52 }, { -11, 15, 52 },
{ -25, 15, 52 }, { -32, 15, 52 }, { -39, 15, 52 }, { 31, 15, 59 }, { 24, 15, 59 }, { 3, 15, 59 }, { -4, 15, 59 }, { -18, 15, 59 }, { -25, 15, 59 },
{ -32, 15, 59 }, { 17, 15, 66 }, { 10, 15, 66 }, { -4, 15, 66 }, { -11, 15, 66 }, { -18, 15, 66 }, { -25, 15, 66 }, { 24, 22, -95 }, { 3, 22, -95 },
{ 38, 22, -88 }, { 31, 22, -88 }, { 24, 22, -88 }, { -4, 22, -88 }, { -32, 22, -88 }, { -39, 22, -88 }, { 45, 22, -81 }, { 31, 22, -81 },
{ 24, 22, -81 }, { 3, 22, -81 }, { -4, 22, -81 }, { -32, 22, -81 }, { -39, 22, -81 }, { -46, 22, -81 }, { 52, 22, -74 }, { 45, 22, -74 },
{ 38, 22, -74 }, { 10, 22, -74 }, { 3, 22, -74 }, { -4, 22, -74 }, { -32, 22, -74 }, { -46, 22, -74 }, { -53, 22, -74 }, { 52, 22, -67 },
{ 45, 22, -67 }, { 17, 22, -67 }, { 10, 22, -67 }, { 3, 22, -67 }, { -4, 22, -67 }, { -11, 22, -67 }, { -18, 22, -67 }, { -46, 22, -67 },
{ -53, 22, -67 }, { 59, 22, -60 }, { 52, 22, -60 }, { 45, 22, -60 }, { 17, 22, -60 }, { 3, 22, -60 }, { -4, 22, -60 }, { -11, 22, -60 },
{ -18, 22, -60 }, { -25, 22, -60 }, { -46, 22, -60 }, { -53, 22, -60 }, { -60, 22, -60 }, { 59, 22, -53 }, { 45, 22, -53 }, { 3, 22, -53 },
{ -4, 22, -53 }, { -46, 22, -53 }, { -53, 22, -53 }, { -60, 22, -53 }, { 66, 22, -46 }, { 59, 22, -46 }, { 52, 22, -46 }, { 3, 22, -46 },
{ -4, 22, -46 }, { -46, 22, -46 }, { -53, 22, -46 }, { -60, 22, -46 }, { -67, 22, -46 }, { 66, 22, -39 }, { 59, 22, -39 }, { 52, 22, -39 },
{ 45, 22, -39 }, { 3, 22, -39 }, { -4, 22, -39 }, { -53, 22, -39 }, { -60, 22, -39 }, { -67, 22, -39 }, { 66, 22, -32 }, { 59, 22, -32 },
{ 52, 22, -32 }, { -46, 22, -32 }, { -53, 22, -32 }, { -60, 22, -32 }, { -67, 22, -32 }, { 66, 22, -25 }, { 59, 22, -25 }, { 52, 22, -25 },
{ 45, 22, -25 }, { 38, 22, -25 }, { -39, 22, -25 }, { -46, 22, -25 }, { -53, 22, -25 }, { -60, 22, -25 }, { -67, 22, -25 }, { 66, 22, -18 },
{ 59, 22, -18 }, { -39, 22, -18 }, { -53, 22, -18 }, { -60, 22, -18 }, { -67, 22, -18 }, { 66, 22, -11 }, { -67, 22, -11 }, { 59, 22, -4 },
{ -60, 22, -4 }, { -67, 22, -4 }, { 59, 22, 3 }, { 45, 22, 3 }, { 59, 22, 10 }, { 52, 22, 10 }, { 45, 22, 10 }, { -46, 22, 10 }, { -53, 22, 10 },
{ -60, 22, 10 }, { 52, 22, 17 }, { 45, 22, 17 }, { 3, 22, 17 }, { -4, 22, 17 }, { -46, 22, 17 }, { -53, 22, 17 }, { -60, 22, 17 }, { 52, 22, 24 },
{ 45, 22, 24 }, { 3, 22, 24 }, { -4, 22, 24 }, { -46, 22, 24 }, { -53, 22, 24 }, { 52, 22, 31 }, { 10, 22, 31 }, { 3, 22, 31 }, { -4, 22, 31 },
{ -11, 22, 31 }, { -46, 22, 31 }, { -53, 22, 31 }, { 45, 22, 38 }, { 10, 22, 38 }, { 3, 22, 38 }, { -4, 22, 38 }, { -11, 22, 38 }, { -46, 22, 38 },
{ 45, 22, 45 }, { 38, 22, 45 }, { 31, 22, 45 }, { 24, 22, 45 }, { 10, 22, 45 }, { 3, 22, 45 }, { -4, 22, 45 }, { -11, 22, 45 }, { -25, 22, 45 },
{ -32, 22, 45 }, { -39, 22, 45 }, { -46, 22, 45 }, { 38, 22, 52 }, { 31, 22, 52 }, { 24, 22, 52 }, { 3, 22, 52 }, { -4, 22, 52 }, { -25, 22, 52 },
{ -32, 22, 52 }, { -39, 22, 52 }, { 24, 22, 59 }, { 17, 22, 59 }, { 3, 22, 59 }, { -4, 22, 59 }, { -18, 22, 59 }, { -25, 22, 59 }, { 10, 22, 66 },
{ -11, 22, 66 }, { -18, 22, 66 }, { 31, 29, -88 }, { 24, 29, -88 }, { 17, 29, -88 }, { 3, 29, -88 }, { -25, 29, -88 }, { -32, 29, -88 },
{ 45, 29, -81 }, { 24, 29, -81 }, { 3, 29, -81 }, { -4, 29, -81 }, { -32, 29, -81 }, { -39, 29, -81 }, { 52, 29, -74 }, { 45, 29, -74 },
{ 24, 29, -74 }, { 10, 29, -74 }, { 3, 29, -74 }, { -4, 29, -74 }, { -11, 29, -74 }, { -18, 29, -74 }, { -32, 29, -74 }, { -46, 29, -74 },
{ 52, 29, -67 }, { 45, 29, -67 }, { 10, 29, -67 }, { 3, 29, -67 }, { -4, 29, -67 }, { -11, 29, -67 }, { -18, 29, -67 }, { -32, 29, -67 },
{ -46, 29, -67 }, { -53, 29, -67 }, { 59, 29, -60 }, { 52, 29, -60 }, { 45, 29, -60 }, { 3, 29, -60 }, { -4, 29, -60 }, { -11, 29, -60 },
{ -46, 29, -60 }, { -53, 29, -60 }, { -60, 29, -60 }, { 59, 29, -53 }, { 52, 29, -53 }, { 10, 29, -53 }, { 3, 29, -53 }, { -4, 29, -53 },
{ -53, 29, -53 }, { -60, 29, -53 }, { 59, 29, -46 }, { 3, 29, -46 }, { -4, 29, -46 }, { -53, 29, -46 }, { -60, 29, -46 }, { 66, 29, -39 },
{ 59, 29, -39 }, { 52, 29, -39 }, { 3, 29, -39 }, { -4, 29, -39 }, { -53, 29, -39 }, { -60, 29, -39 }, { -67, 29, -39 }, { 66, 29, -32 },
{ 59, 29, -32 }, { 3, 29, -32 }, { -4, 29, -32 }, { -60, 29, -32 }, { -67, 29, -32 }, { 66, 29, -25 }, { 59, 29, -25 }, { 3, 29, -25 }, { -4, 29, -25 },
{ -60, 29, -25 }, { -67, 29, -25 }, { 66, 29, -18 }, { 59, 29, -18 }, { 3, 29, -18 }, { -4, 29, -18 }, { -60, 29, -18 }, { -67, 29, -18 },
{ 66, 29, -11 }, { 59, 29, -11 }, { 3, 29, -11 }, { -4, 29, -11 }, { -60, 29, -11 }, { -67, 29, -11 }, { 59, 29, -4 }, { 52, 29, -4 }, { 3, 29, -4 },
{ -4, 29, -4 }, { -60, 29, -4 }, { 59, 29, 3 }, { 45, 29, 3 }, { 38, 29, 3 }, { 3, 29, 3 }, { -4, 29, 3 }, { -39, 29, 3 }, { -46, 29, 3 },
{ -60, 29, 3 }, { 52, 29, 10 }, { 45, 29, 10 }, { 38, 29, 10 }, { 3, 29, 10 }, { -4, 29, 10 }, { -39, 29, 10 }, { -46, 29, 10 }, { -53, 29, 10 },
{ -60, 29, 10 }, { 52, 29, 17 }, { 45, 29, 17 }, { 38, 29, 17 }, { 10, 29, 17 }, { 3, 29, 17 }, { -4, 29, 17 }, { -39, 29, 17 }, { -46, 29, 17 },
{ -53, 29, 17 }, { 52, 29, 24 }, { 45, 29, 24 }, { 10, 29, 24 }, { 3, 29, 24 }, { -4, 29, 24 }, { -11, 29, 24 }, { -53, 29, 24 }, { 45, 29, 31 },
{ 10, 29, 31 }, { 3, 29, 31 }, { -4, 29, 31 }, { -11, 29, 31 }, { -53, 29, 31 }, { 45, 29, 38 }, { 38, 29, 38 }, { 31, 29, 38 }, { 24, 29, 38 },
{ 10, 29, 38 }, { 3, 29, 38 }, { -4, 29, 38 }, { -32, 29, 38 }, { -46, 29, 38 }, { 38, 29, 45 }, { 31, 29, 45 }, { 24, 29, 45 }, { 3, 29, 45 },
{ -4, 29, 45 }, { -25, 29, 45 }, { -32, 29, 45 }, { -39, 29, 45 }, { 31, 29, 52 }, { 24, 29, 52 }, { 17, 29, 52 }, { 3, 29, 52 }, { -4, 29, 52 },
{ -18, 29, 52 }, { -25, 29, 52 }, { -32, 29, 52 }, { 17, 29, 59 }, { 10, 29, 59 }, { 3, 29, 59 }, { -4, 29, 59 }, { -11, 29, 59 }, { -18, 29, 59 },
{ -25, 29, 59 }, { 31, 36, -88 }, { 24, 36, -88 }, { 17, 36, -88 }, { 10, 36, -88 }, { 3, 36, -88 }, { -11, 36, -88 }, { -18, 36, -88 },
{ -25, 36, -88 }, { 38, 36, -81 }, { 31, 36, -81 }, { 24, 36, -81 }, { 10, 36, -81 }, { 3, 36, -81 }, { -4, 36, -81 }, { -11, 36, -81 },
{ -39, 36, -81 }, { 45, 36, -74 }, { 38, 36, -74 }, { 24, 36, -74 }, { 10, 36, -74 }, { 3, 36, -74 }, { -4, 36, -74 }, { -11, 36, -74 },
{ -18, 36, -74 }, { -32, 36, -74 }, { -46, 36, -74 }, { 52, 36, -67 }, { 45, 36, -67 }, { 24, 36, -67 }, { 3, 36, -67 }, { -4, 36, -67 },
{ -11, 36, -67 }, { -32, 36, -67 }, { -46, 36, -67 }, { -53, 36, -67 }, { 59, 36, -60 }, { 52, 36, -60 }, { 45, 36, -60 }, { 10, 36, -60 },
{ 3, 36, -60 }, { -4, 36, -60 }, { -46, 36, -60 }, { -53, 36, -60 }, { -60, 36, -60 }, { 59, 36, -53 }, { 52, 36, -53 }, { 10, 36, -53 },
{ 3, 36, -53 }, { -4, 36, -53 }, { -11, 36, -53 }, { -53, 36, -53 }, { -60, 36, -53 }, { 59, 36, -46 }, { 10, 36, -46 }, { 3, 36, -46 },
{ -4, 36, -46 }, { -11, 36, -46 }, { -53, 36, -46 }, { -60, 36, -46 }, { 59, 36, -39 }, { 10, 36, -39 }, { 3, 36, -39 }, { -4, 36, -39 },
{ -11, 36, -39 }, { -53, 36, -39 }, { -60, 36, -39 }, { -67, 36, -39 }, { 66, 36, -32 }, { 59, 36, -32 }, { 3, 36, -32 }, { -4, 36, -32 },
{ -67, 36, -32 }, { 66, 36, -25 }, { 59, 36, -25 }, { 45, 36, -25 }, { 3, 36, -25 }, { -4, 36, -25 }, { -60, 36, -25 }, { -67, 36, -25 },
{ 59, 36, -18 }, { 52, 36, -18 }, { 45, 36, -18 }, { 3, 36, -18 }, { -4, 36, -18 }, { -53, 36, -18 }, { -60, 36, -18 }, { -67, 36, -18 },
{ 59, 36, -11 }, { 3, 36, -11 }, { -4, 36, -11 }, { -46, 36, -11 }, { -53, 36, -11 }, { 59, 36, -4 }, { 52, 36, -4 }, { 3, 36, -4 }, { -4, 36, -4 },
{ -60, 36, -4 }, { 59, 36, 3 }, { 52, 36, 3 }, { 45, 36, 3 }, { 38, 36, 3 }, { 3, 36, 3 }, { -4, 36, 3 }, { -39, 36, 3 }, { -46, 36, 3 },
{ -53, 36, 3 }, { -60, 36, 3 }, { 52, 36, 10 }, { 45, 36, 10 }, { 10, 36, 10 }, { 3, 36, 10 }, { -4, 36, 10 }, { -11, 36, 10 }, { -39, 36, 10 },
{ -46, 36, 10 }, { -53, 36, 10 }, { 52, 36, 17 }, { 10, 36, 17 }, { 3, 36, 17 }, { -4, 36, 17 }, { -11, 36, 17 }, { -46, 36, 17 }, { -53, 36, 17 },
{ 24, 36, 24 }, { 3, 36, 24 }, { -4, 36, 24 }, { -11, 36, 24 }, { -39, 36, 24 }, { -46, 36, 24 }, { -53, 36, 24 }, { 45, 36, 31 }, { 38, 36, 31 },
{ 31, 36, 31 }, { 24, 36, 31 }, { 3, 36, 31 }, { -4, 36, 31 }, { -25, 36, 31 }, { -39, 36, 31 }, { -46, 36, 31 }, { 38, 36, 38 }, { 31, 36, 38 },
{ 24, 36, 38 }, { 3, 36, 38 }, { -4, 36, 38 }, { -25, 36, 38 }, { -32, 36, 38 }, { -39, 36, 38 }, { 31, 36, 45 }, { 24, 36, 45 }, { 17, 36, 45 },
{ 3, 36, 45 }, { -4, 36, 45 }, { -25, 36, 45 }, { -32, 36, 45 }, { 24, 36, 52 }, { 17, 36, 52 }, { 3, 36, 52 }, { -4, 36, 52 }, { -18, 36, 52 },
{ -25, 36, 52 }, { 10, 36, 59 }, { -11, 36, 59 }, { -18, 43, -88 }, { 31, 43, -81 }, { 24, 43, -81 }, { 17, 43, -81 }, { 10, 43, -81 }, { 3, 43, -81 },
{ -11, 43, -81 }, { -18, 43, -81 }, { -25, 43, -81 }, { -32, 43, -81 }, { 45, 43, -74 }, { 38, 43, -74 }, { 31, 43, -74 }, { 24, 43, -74 },
{ 10, 43, -74 }, { 3, 43, -74 }, { -4, 43, -74 }, { -11, 43, -74 }, { -25, 43, -74 }, { -32, 43, -74 }, { -39, 43, -74 }, { -46, 43, -74 },
{ 52, 43, -67 }, { 45, 43, -67 }, { 38, 43, -67 }, { 31, 43, -67 }, { 24, 43, -67 }, { 3, 43, -67 }, { -4, 43, -67 }, { -25, 43, -67 },
{ -32, 43, -67 }, { -39, 43, -67 }, { -46, 43, -67 }, { 52, 43, -60 }, { 45, 43, -60 }, { 38, 43, -60 }, { 31, 43, -60 }, { 3, 43, -60 },
{ -4, 43, -60 }, { -46, 43, -60 }, { -53, 43, -60 }, { 59, 43, -53 }, { 52, 43, -53 }, { 38, 43, -53 }, { 31, 43, -53 }, { 10, 43, -53 },
{ 3, 43, -53 }, { -4, 43, -53 }, { -11, 43, -53 }, { -39, 43, -53 }, { -53, 43, -53 }, { -60, 43, -53 }, { 59, 43, -46 }, { 52, 43, -46 },
{ 45, 43, -46 }, { 38, 43, -46 }, { 31, 43, -46 }, { 10, 43, -46 }, { 3, 43, -46 }, { -4, 43, -46 }, { -11, 43, -46 }, { -32, 43, -46 },
{ -39, 43, -46 }, { -46, 43, -46 }, { -60, 43, -46 }, { 59, 43, -39 }, { 52, 43, -39 }, { 45, 43, -39 }, { 38, 43, -39 }, { 31, 43, -39 },
{ 10, 43, -39 }, { 3, 43, -39 }, { -4, 43, -39 }, { -11, 43, -39 }, { -39, 43, -39 }, { -46, 43, -39 }, { -53, 43, -39 }, { -60, 43, -39 },
{ 59, 43, -32 }, { 52, 43, -32 }, { 45, 43, -32 }, { 38, 43, -32 }, { 10, 43, -32 }, { 3, 43, -32 }, { -4, 43, -32 }, { -11, 43, -32 },
{ -39, 43, -32 }, { -46, 43, -32 }, { -60, 43, -32 }, { 59, 43, -25 }, { 52, 43, -25 }, { 10, 43, -25 }, { 3, 43, -25 }, { -4, 43, -25 },
{ -11, 43, -25 }, { -46, 43, -25 }, { -53, 43, -25 }, { -60, 43, -25 }, { 59, 43, -18 }, { 52, 43, -18 }, { 45, 43, -18 }, { 38, 43, -18 },
{ 10, 43, -18 }, { 3, 43, -18 }, { -4, 43, -18 }, { -11, 43, -18 }, { -53, 43, -18 }, { -60, 43, -18 }, { 59, 43, -11 }, { 52, 43, -11 },
{ 10, 43, -11 }, { 3, 43, -11 }, { -4, 43, -11 }, { -11, 43, -11 }, { -53, 43, -11 }, { -60, 43, -11 }, { 45, 43, -4 }, { 10, 43, -4 }, { 3, 43, -4 },
{ -4, 43, -4 }, { -11, 43, -4 }, { -53, 43, -4 }, { 52, 43, 3 }, { 45, 43, 3 }, { 10, 43, 3 }, { 3, 43, 3 }, { -4, 43, 3 }, { -11, 43, 3 },
{ -39, 43, 3 }, { -46, 43, 3 }, { -53, 43, 3 }, { 52, 43, 10 }, { 45, 43, 10 }, { 3, 43, 10 }, { -4, 43, 10 }, { -11, 43, 10 }, { -46, 43, 10 },
{ -53, 43, 10 }, { 45, 43, 17 }, { 24, 43, 17 }, { 10, 43, 17 }, { 3, 43, 17 }, { -4, 43, 17 }, { -25, 43, 17 }, { -39, 43, 17 }, { -46, 43, 17 },
{ 45, 43, 24 }, { 31, 43, 24 }, { 24, 43, 24 }, { 3, 43, 24 }, { -4, 43, 24 }, { -25, 43, 24 }, { -39, 43, 24 }, { -46, 43, 24 }, { 38, 43, 31 },
{ 31, 43, 31 }, { 24, 43, 31 }, { 3, 43, 31 }, { -4, 43, 31 }, { -25, 43, 31 }, { -32, 43, 31 }, { -39, 43, 31 }, { 31, 43, 38 }, { 24, 43, 38 },
{ 3, 43, 38 }, { -4, 43, 38 }, { -18, 43, 38 }, { -25, 43, 38 }, { -32, 43, 38 }, { 24, 43, 45 }, { 17, 43, 45 }, { 10, 43, 45 }, { 3, 43, 45 },
{ -4, 43, 45 }, { -18, 43, 45 }, { -25, 43, 45 }, { 10, 43, 52 }, { -4, 43, 52 }, { -11, 43, 52 }, { 17, 50, -81 }, { 10, 50, -81 }, { 31, 50, -74 },
{ 24, 50, -74 }, { 17, 50, -74 }, { 10, 50, -74 }, { 3, 50, -74 }, { -4, 50, -74 }, { -11, 50, -74 }, { -18, 50, -74 }, { -25, 50, -74 },
{ -32, 50, -74 }, { 45, 50, -67 }, { 38, 50, -67 }, { 31, 50, -67 }, { 24, 50, -67 }, { 17, 50, -67 }, { 3, 50, -67 }, { -4, 50, -67 },
{ -18, 50, -67 }, { -25, 50, -67 }, { -32, 50, -67 }, { -39, 50, -67 }, { 52, 50, -60 }, { 45, 50, -60 }, { 38, 50, -60 }, { 3, 50, -60 },
{ -4, 50, -60 }, { -39, 50, -60 }, { -46, 50, -60 }, { 52, 50, -53 }, { 45, 50, -53 }, { 38, 50, -53 }, { 31, 50, -53 }, { 3, 50, -53 },
{ -4, 50, -53 }, { -32, 50, -53 }, { -39, 50, -53 }, { -46, 50, -53 }, { -53, 50, -53 }, { 52, 50, -46 }, { 45, 50, -46 }, { 38, 50, -46 },
{ 31, 50, -46 }, { 10, 50, -46 }, { 3, 50, -46 }, { -4, 50, -46 }, { -11, 50, -46 }, { -32, 50, -46 }, { -39, 50, -46 }, { -46, 50, -46 },
{ -53, 50, -46 }, { 59, 50, -39 }, { 52, 50, -39 }, { 45, 50, -39 }, { 38, 50, -39 }, { 10, 50, -39 }, { 3, 50, -39 }, { -4, 50, -39 },
{ -11, 50, -39 }, { -39, 50, -39 }, { -46, 50, -39 }, { -53, 50, -39 }, { -60, 50, -39 }, { 59, 50, -32 }, { 52, 50, -32 }, { 45, 50, -32 },
{ 10, 50, -32 }, { 3, 50, -32 }, { -4, 50, -32 }, { -11, 50, -32 }, { -39, 50, -32 }, { -46, 50, -32 }, { -53, 50, -32 }, { -60, 50, -32 },
{ 3, 50, -25 }, { -4, 50, -25 }, { -46, 50, -25 }, { -53, 50, -25 }, { -60, 50, -25 }, { 45, 50, -18 }, { 3, 50, -18 }, { -4, 50, -18 },
{ -60, 50, -18 }, { 52, 50, -11 }, { 24, 50, -11 }, { 10, 50, -11 }, { 3, 50, -11 }, { -4, 50, -11 }, { -46, 50, -11 }, { -53, 50, -11 },
{ 52, 50, -4 }, { 45, 50, -4 }, { 31, 50, -4 }, { 24, 50, -4 }, { 3, 50, -4 }, { -4, 50, -4 }, { -11, 50, -4 }, { -25, 50, -4 }, { -32, 50, -4 },
{ -53, 50, -4 }, { 52, 50, 3 }, { 45, 50, 3 }, { 24, 50, 3 }, { 3, 50, 3 }, { -4, 50, 3 }, { -25, 50, 3 }, { -39, 50, 3 }, { -46, 50, 3 },
{ 45, 50, 10 }, { 24, 50, 10 }, { 3, 50, 10 }, { -4, 50, 10 }, { -46, 50, 10 }, { 24, 50, 17 }, { 3, 50, 17 }, { -4, 50, 17 }, { -25, 50, 17 },
{ -32, 50, 17 }, { -46, 50, 17 }, { 38, 50, 24 }, { 31, 50, 24 }, { 24, 50, 24 }, { 3, 50, 24 }, { -4, 50, 24 }, { -25, 50, 24 }, { -39, 50, 24 },
{ 31, 50, 31 }, { 24, 50, 31 }, { 3, 50, 31 }, { -4, 50, 31 }, { -18, 50, 31 }, { -25, 50, 31 }, { -32, 50, 31 }, { 24, 50, 38 }, { 17, 50, 38 },
{ 10, 50, 38 }, { 3, 50, 38 }, { -4, 50, 38 }, { -18, 50, 38 }, { -25, 50, 38 }, { 10, 50, 45 }, { 3, 50, 45 }, { 17, 57, -74 }, { 10, 57, -74 },
{ -11, 57, -74 }, { -18, 57, -74 }, { 31, 57, -67 }, { 24, 57, -67 }, { 17, 57, -67 }, { 10, 57, -67 }, { 3, 57, -67 }, { -4, 57, -67 },
{ -11, 57, -67 }, { -25, 57, -67 }, { -32, 57, -67 }, { 38, 57, -60 }, { 31, 57, -60 }, { 24, 57, -60 }, { 10, 57, -60 }, { 3, 57, -60 },
{ -4, 57, -60 }, { -11, 57, -60 }, { -32, 57, -60 }, { -39, 57, -60 }, { 45, 57, -53 }, { 38, 57, -53 }, { 17, 57, -53 }, { 10, 57, -53 },
{ 3, 57, -53 }, { -4, 57, -53 }, { -32, 57, -53 }, { -39, 57, -53 }, { -46, 57, -53 }, { 45, 57, -46 }, { 38, 57, -46 }, { 31, 57, -46 },
{ 10, 57, -46 }, { 3, 57, -46 }, { -4, 57, -46 }, { -11, 57, -46 }, { -32, 57, -46 }, { -39, 57, -46 }, { 45, 57, -39 }, { 38, 57, -39 },
{ 3, 57, -39 }, { -4, 57, -39 }, { -39, 57, -39 }, { 38, 57, -32 }, { 3, 57, -32 }, { -4, 57, -32 }, { -46, 57, -32 }, { 52, 57, -25 }, { 3, 57, -25 },
{ -4, 57, -25 }, { -53, 57, -25 }, { 52, 57, -18 }, { 45, 57, -18 }, { 3, 57, -18 }, { -4, 57, -18 }, { -53, 57, -18 }, { 45, 57, -11 },
{ 31, 57, -11 }, { 24, 57, -11 }, { 3, 57, -11 }, { -4, 57, -11 }, { -25, 57, -11 }, { -46, 57, -11 }, { 45, 57, -4 }, { 31, 57, -4 }, { 24, 57, -4 },
{ 3, 57, -4 }, { -4, 57, -4 }, { -25, 57, -4 }, { -32, 57, -4 }, { -39, 57, -4 }, { -46, 57, -4 }, { 45, 57, 3 }, { 38, 57, 3 }, { 31, 57, 3 },
{ 24, 57, 3 }, { 3, 57, 3 }, { -4, 57, 3 }, { -25, 57, 3 }, { -32, 57, 3 }, { -39, 57, 3 }, { 38, 57, 10 }, { 24, 57, 10 }, { 3, 57, 10 },
{ -4, 57, 10 }, { -25, 57, 10 }, { -32, 57, 10 }, { -39, 57, 10 }, { 38, 57, 17 }, { 24, 57, 17 }, { 3, 57, 17 }, { -4, 57, 17 }, { -25, 57, 17 },
{ -32, 57, 17 }, { -39, 57, 17 }, { 31, 57, 24 }, { 24, 57, 24 }, { 3, 57, 24 }, { -4, 57, 24 }, { -11, 57, 24 }, { -25, 57, 24 }, { -32, 57, 24 },
{ 17, 57, 31 }, { 10, 57, 31 }, { 3, 57, 31 }, { -4, 57, 31 }, { -11, 57, 31 }, { -18, 57, 31 }, { 10, 57, 38 }, { 24, 64, -67 }, { 17, 64, -67 },
{ 10, 64, -67 }, { -11, 64, -67 }, { -18, 64, -67 }, { 31, 64, -60 }, { 24, 64, -60 }, { 17, 64, -60 }, { 10, 64, -60 }, { 3, 64, -60 },
{ -4, 64, -60 }, { -11, 64, -60 }, { -18, 64, -60 }, { 24, 64, -53 }, { 17, 64, -53 }, { 10, 64, -53 }, { 3, 64, -53 }, { -4, 64, -53 },
{ -25, 64, -53 }, { -32, 64, -53 }, { 31, 64, -46 }, { 10, 64, -46 }, { 3, 64, -46 }, { -4, 64, -46 }, { -11, 64, -46 }, { -39, 64, -46 },
{ 3, 64, -39 }, { -4, 64, -39 }, { -39, 64, -39 }, { 3, 64, -32 }, { -4, 64, -32 }, { 3, 64, -25 }, { -4, 64, -25 }, { 3, 64, -18 }, { -4, 64, -18 },
{ 24, 64, -11 }, { 17, 64, -11 }, { 10, 64, -11 }, { 3, 64, -11 }, { -4, 64, -11 }, { -25, 64, -11 }, { 24, 64, -4 }, { 3, 64, -4 }, { -4, 64, -4 },
{ -25, 64, -4 }, { -32, 64, -4 }, { 31, 64, 3 }, { 24, 64, 3 }, { 3, 64, 3 }, { -4, 64, 3 }, { -18, 64, 3 }, { -25, 64, 3 }, { -32, 64, 3 },
{ 24, 64, 10 }, { 3, 64, 10 }, { -4, 64, 10 }, { -11, 64, 10 }, { -18, 64, 10 }, { -25, 64, 10 }, { 24, 64, 17 }, { 17, 64, 17 }, { 10, 64, 17 },
{ 3, 64, 17 }, { -4, 64, 17 }, { -11, 64, 17 }, { -18, 64, 17 }, { -25, 64, 17 }, { 10, 64, 24 }, { -11, 64, 24 }, { 17, 71, -60 }, { 17, 71, -53 },
{ 10, 71, -53 }, { -11, 71, -53 }, { -18, 71, -53 }, { -25, 71, -53 }, { 10, 71, -46 }, { -11, 71, -46 }, { -18, 71, -46 }, { -25, 71, -46 },
{ 3, 71, -39 }, { -4, 71, -39 }, { 10, 71, -32 }, { 3, 71, -32 }, { 3, 71, -25 }, { 3, 71, -18 }, { -4, 71, -18 }, { 24, 71, -11 }, { 17, 71, -11 },
{ 10, 71, -11 }, { 3, 71, -11 }, { -4, 71, -11 }, { -18, 71, -11 }, { 17, 71, -4 }, { 10, 71, -4 }, { 3, 71, -4 }, { -4, 71, -4 }, { -11, 71, -4 },
{ -18, 71, -4 }, { 17, 71, 3 }, { 10, 71, 3 }, { 3, 71, 3 }, { -4, 71, 3 }, { -11, 71, 3 }, { -18, 71, 3 }, { 17, 71, 10 },
};
void insertLoretaVoxelInMesh(C3DMesh& mesh, const float x, const float y, const float z, const float s)
{
const size_t i = mesh.m_Vertices.size();
// Insert the 8 vertices of the cube
mesh.m_Vertices.emplace_back(x - s, y - s, z - s); // i+0
mesh.m_Vertices.emplace_back(x + s, y - s, z - s); // i+1
mesh.m_Vertices.emplace_back(x + s, y + s, z - s); // i+2
mesh.m_Vertices.emplace_back(x - s, y + s, z - s); // i+3
mesh.m_Vertices.emplace_back(x - s, y - s, z + s); // i+4
mesh.m_Vertices.emplace_back(x + s, y - s, z + s); // i+5
mesh.m_Vertices.emplace_back(x + s, y + s, z + s); // i+6
mesh.m_Vertices.emplace_back(x - s, y + s, z + s); // i+7
// Insert the 12 triangles of the cube
mesh.m_Triangles.push_back(i + 0);
mesh.m_Triangles.push_back(i + 1);
mesh.m_Triangles.push_back(i + 2);
mesh.m_Triangles.push_back(i + 0);
mesh.m_Triangles.push_back(i + 2);
mesh.m_Triangles.push_back(i + 3);
mesh.m_Triangles.push_back(i + 1);
mesh.m_Triangles.push_back(i + 5);
mesh.m_Triangles.push_back(i + 6);
mesh.m_Triangles.push_back(i + 1);
mesh.m_Triangles.push_back(i + 6);
mesh.m_Triangles.push_back(i + 2);
mesh.m_Triangles.push_back(i + 5);
mesh.m_Triangles.push_back(i + 4);
mesh.m_Triangles.push_back(i + 7);
mesh.m_Triangles.push_back(i + 5);
mesh.m_Triangles.push_back(i + 7);
mesh.m_Triangles.push_back(i + 6);
mesh.m_Triangles.push_back(i + 4);
mesh.m_Triangles.push_back(i + 0);
mesh.m_Triangles.push_back(i + 3);
mesh.m_Triangles.push_back(i + 4);
mesh.m_Triangles.push_back(i + 3);
mesh.m_Triangles.push_back(i + 7);
mesh.m_Triangles.push_back(i + 4);
mesh.m_Triangles.push_back(i + 5);
mesh.m_Triangles.push_back(i + 1);
mesh.m_Triangles.push_back(i + 4);
mesh.m_Triangles.push_back(i + 1);
mesh.m_Triangles.push_back(i + 0);
mesh.m_Triangles.push_back(i + 3);
mesh.m_Triangles.push_back(i + 2);
mesh.m_Triangles.push_back(i + 6);
mesh.m_Triangles.push_back(i + 3);
mesh.m_Triangles.push_back(i + 6);
mesh.m_Triangles.push_back(i + 7);
}
} // namespace
CRendererLoreta::CRendererLoreta()
{
m_face.load(FACE_DATA);
m_scalp.load(SCALP_DATA);
m_brain.clear();
for (auto& voxel : loretaVoxel) { insertLoretaVoxelInMesh(m_brain, float(-voxel[0]), float(voxel[1]), float(-voxel[2]), 3.5); }
m_lookups.clear();
//const size_t idxBrodmanns = 0, idxAnatomicals = 1, idxLobes = 2, idxRoi = 3;
m_lookups.reserve(4);
m_lookups.emplace_back(LoretaRegions::BRODMANNS);
m_lookups.emplace_back(LoretaRegions::ANATOMICALS);
m_lookups.emplace_back(LoretaRegions::LOBES);
m_lookups.emplace_back(LoretaRegions::REGIONS_OF_INTEREST);
m_selecteds.resize(2394, true);
this->refreshBrainSubset();
}
#define __Rendering_VertexBuffer__
bool CRendererLoreta::render(const CRendererContext& ctx)
{
// if(!m_nHistory) return false;
// if(m_history.size()!=2394) return false;
const float d = 3.5;
// ::glDisable(GL_TEXTURE_1D);
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluPerspective(60, ctx.getAspect(), .01, 100);
glTranslatef(0, 0, -d);
glRotatef(ctx.getRotationX() * 10, 1, 0, 0);
glRotatef(ctx.getRotationY() * 10, 0, 1, 0);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glScalef(ctx.getZoom(), ctx.getZoom(), ctx.getZoom());
glPushMatrix();
glTranslatef(0, .5, 0);
glScalef(.00944F, .00944F, .00944F);
glRotatef(19, 1, 0, 0);
glTranslatef(0, -10, 15);
glDisable(GL_DEPTH_TEST);
if (m_nHistory && m_history.size() == 2394)
{
std::vector<float> samples;
this->getSampleAtERPFraction(m_erpFraction, samples);
#if defined __Rendering_VertexBuffer__
for (size_t i = 0, j = 0; i < 2394; ++i)
{
// Apply texture coordinate to each of the 8 vertices of this voxel
const float power = samples[i] * ctx.getScale();
m_brain.m_Vertices[j++].u = power;
m_brain.m_Vertices[j++].u = power;
m_brain.m_Vertices[j++].u = power;
m_brain.m_Vertices[j++].u = power;
m_brain.m_Vertices[j++].u = power;
m_brain.m_Vertices[j++].u = power;
m_brain.m_Vertices[j++].u = power;
m_brain.m_Vertices[j++].u = power;
}
#else
for (size_t i = 0; i < 2394; ++i)
{
if (m_selecteds[i])
{
float power = samples[i] * ctx.getScale();
// m_history[i][m_nHistory-m_nSample+m_sampleIndexERP]*ctx.getScale();
::glColor4f(.1f, .1f, .1f, ctx.getTranslucency());
::glPushMatrix();
::glTexCoord1f(power);
::glTranslatef(float(-loretaVoxel[i][0]), float(loretaVoxel[i][1]), float(-loretaVoxel[i][2]));
::glScalef(3.5, 3.5, 3.5);
cube();
::glPopMatrix();
}
}
#endif
}
else
{
#if defined __Rendering_VertexBuffer__
for (size_t i = 0, j = 0; i < 2394; ++i)
{
// Apply texture coordinate to each of the 8 vertices of this voxel
const float power = 0;
m_brain.m_Vertices[j++].u = power;
m_brain.m_Vertices[j++].u = power;
m_brain.m_Vertices[j++].u = power;
m_brain.m_Vertices[j++].u = power;
m_brain.m_Vertices[j++].u = power;
m_brain.m_Vertices[j++].u = power;
m_brain.m_Vertices[j++].u = power;
m_brain.m_Vertices[j++].u = power;
}
#else
for (size_t i = 0; i < 2394; ++i)
{
if (m_selecteds[i])
{
// float power=m_history[i][m_nHistory-m_nSample+m_sampleIndexERP]*ctx.getScale();
::glColor4f(.1f, .1f, .1f, ctx.getTranslucency());
::glPushMatrix();
::glTexCoord1f(0);
::glTranslatef(float(-loretaVoxel[i][0]), float(loretaVoxel[i][1]), float(-loretaVoxel[i][2]));
::glScalef(3.5, 3.5, 3.5);
cube();
::glPopMatrix();
}
}
#endif
}
#if defined __Rendering_VertexBuffer__
glEnable(GL_TEXTURE_1D);
glDisable(GL_LIGHTING);
glColor4f(.1F, .1F, .1F, ctx.getTranslucency());
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(CVertex), &m_brain.m_Vertices[0].x);
glTexCoordPointer(1, GL_FLOAT, sizeof(CVertex), &m_brain.m_Vertices[0].u);
// ::glDrawElements(GL_TRIANGLES, m_brain.m_Triangles.size(), GL_UNSIGNED_INT, &m_brain.m_Triangles[0]);
if (!m_brainSubsetTriangles.empty()) { glDrawElements(GL_TRIANGLES, GLsizei(m_brainSubsetTriangles.size()), GL_UNSIGNED_INT, &m_brainSubsetTriangles[0]); }
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
#endif
glPopMatrix();
glEnable(GL_LIGHTING);
glDisable(GL_TEXTURE_1D);
glPushMatrix();
glTranslatef(0, .5F, 0);
glRotatef(19, 1, 0, 0);
glTranslatef(0, -.2F, .35F);
// ::glScalef(1.8f, 1.8f, 1.8f);
if (ctx.isScalpMeshVisible())
{
glColor4f(.8F, .6F, .5F, .1F);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(CVertex), &m_scalp.m_Vertices[0].x);
glNormalPointer(GL_FLOAT, sizeof(CVertex), &m_scalp.m_Normals[0].x);
glDrawElements(GL_TRIANGLES, GLsizei(m_scalp.m_Triangles.size()), GL_UNSIGNED_INT, &m_scalp.m_Triangles[0]);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
}
if (ctx.isFaceMeshVisible())
{
glColor4f(.8F, .6F, .5F, .1F);
glDisable(GL_TEXTURE_1D);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(CVertex), &m_face.m_Vertices[0].x);
glNormalPointer(GL_FLOAT, sizeof(CVertex), &m_face.m_Normals[0].x);
glDrawElements(GL_TRIANGLES, GLsizei(m_face.m_Triangles.size()), GL_UNSIGNED_INT, &m_face.m_Triangles[0]);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
}
glDisable(GL_LIGHTING);
glPopMatrix();
if (ctx.getCheckBoardVisibility()) { this->drawCoordinateSystem(); }
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
return true;
}
void CRendererLoreta::clearRegionSelection()
{
for (auto it = m_selecteds.begin(); it != m_selecteds.end(); ++it) { *it = false; }
this->refreshBrainSubset();
}
size_t CRendererLoreta::getRegionCount(const size_t category)
{
if (category >= m_lookups.size()) { return 0; }
return size_t(m_lookups[category].size());
}
const char* CRendererLoreta::getRegionCategoryName(const size_t category)
{
switch (category)
{
case 0: return "Brodmann";
case 1: return "Anatomic";
case 2: return "Lobe";
case 3: return "Function";
default: return nullptr;
}
}
const char* CRendererLoreta::getRegionName(const size_t category, const size_t index)
{
if (category >= m_lookups.size()) { return nullptr; }
auto& lookup = m_lookups[category];
auto it = lookup.begin();
for (size_t j = 0; j < index && it != lookup.end(); ++j) { ++it; }
if (it != lookup.end()) { return it->first.c_str(); }
return nullptr;
}
void CRendererLoreta::selectRegion(const size_t category, const char* name)
{
if (category >= m_lookups.size()) { return; }
auto& lookup = m_lookups[category];
auto it = lookup.find(name);
if (it != lookup.end())
{
std::vector<size_t>& list = it->second;
for (auto& i : list) { m_selecteds[i] = true; }
}
this->refreshBrainSubset();
}
void CRendererLoreta::selectRegion(const size_t category, const size_t index)
{
if (category >= m_lookups.size()) { return; }
auto& lookup = m_lookups[category];
auto it = lookup.begin();
for (size_t j = 0; j < index && it != lookup.end(); ++j) { ++it; }
if (it != lookup.end())
{
std::vector<size_t>& list = it->second;
for (auto& i : list) { m_selecteds[i] = true; }
}
this->refreshBrainSubset();
}
void CRendererLoreta::refreshBrainSubset()
{
// Initializes look up to its maximum size
m_brainSubsetTriangles = m_brain.m_Triangles;
// Inserts selected voxels in look up
const size_t trianglePerVoxel = 12;
const size_t vertexPerVoxel = trianglePerVoxel * 3;
size_t i, j, k;
for (i = 0, j = 0, k = 0; i < 2394; i++, k += vertexPerVoxel)
{
if (m_selecteds[i]) { for (size_t l = 0; l < vertexPerVoxel; ++l) { m_brainSubsetTriangles[j++] = m_brain.m_Triangles[k + l]; } }
}
// Crops look up to the subset size
m_brainSubsetTriangles.resize(j);
}
} // namespace AdvancedVisualization
} // namespace OpenViBE
#endif // TARGET_HAS_ThirdPartyOpenGL
@@ -0,0 +1,65 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#if defined TARGET_HAS_ThirdPartyOpenGL
#include "mIRenderer.hpp"
#include "mC3DMesh.hpp"
#include <vector>
#include <map>
#include <string>
namespace OpenViBE {
namespace AdvancedVisualization {
class CRendererLoreta : public IRenderer
{
public:
CRendererLoreta();
void rebuild(const CRendererContext& ctx) override { IRenderer::rebuild(ctx); }
void refresh(const CRendererContext& ctx) override { IRenderer::refresh(ctx); }
bool render(const CRendererContext& ctx) override;
void clearRegionSelection() override;
size_t getRegionCategoryCount() override { return m_lookups.size(); }
size_t getRegionCount(const size_t category) override;
const char* getRegionCategoryName(const size_t category) override;
const char* getRegionName(const size_t category, const size_t index) override;
void selectRegion(const size_t category, const char* name) override;
void selectRegion(const size_t category, const size_t index) override;
void refreshBrainSubset();
protected:
std::vector<std::map<std::string, std::vector<size_t>>> m_lookups;
std::vector<bool> m_selecteds;
C3DMesh m_face, m_scalp, m_brain;
std::vector<uint32_t> m_brainSubsetTriangles;
};
} // namespace AdvancedVisualization
} // namespace OpenViBE
#endif // TARGET_HAS_ThirdPartyOpenGL
@@ -0,0 +1,161 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "mCRendererMountain.hpp"
namespace OpenViBE {
namespace AdvancedVisualization {
void CRendererMountain::rebuild(const CRendererContext& ctx)
{
IRenderer::rebuild(ctx);
m_mountain.m_Vertices.clear();
m_mountain.m_Vertices.resize(m_nChannel * m_nSample);
for (size_t i = 0, k = 0; i < m_nChannel; ++i)
{
for (size_t j = 0; j < m_nSample; ++j)
{
const float a = i * 1.F / float(m_nChannel - 1);
const float b = 1 - j * 1.F / float(m_nSample - 1);
m_mountain.m_Vertices[k].x = a;
m_mountain.m_Vertices[k].y = 0;
m_mountain.m_Vertices[k].z = b;
m_mountain.m_Vertices[k].u = 0;
k++;
}
}
m_mountain.m_Triangles.clear();
m_mountain.m_Triangles.resize((m_nChannel - 1) * (m_nSample - 1) * 6);
size_t id = 0;
for (size_t i = 0; i < m_nChannel - 1; ++i)
{
for (size_t j = 0; j < m_nSample - 1; ++j)
{
const size_t v1 = i * m_nSample + j;
const size_t v2 = v1 + m_nSample;
m_mountain.m_Triangles[id++] = v1;
m_mountain.m_Triangles[id++] = v2;
m_mountain.m_Triangles[id++] = v2 + 1;
m_mountain.m_Triangles[id++] = v1;
m_mountain.m_Triangles[id++] = v2 + 1;
m_mountain.m_Triangles[id++] = v1 + 1;
}
}
m_historyIdx = 0;
}
void CRendererMountain::refresh(const CRendererContext& ctx)
{
IRenderer::refresh(ctx);
if (!m_nHistory) { return; }
for (size_t i = 0; i < ctx.getSelectedCount(); ++i)
{
size_t k = ((m_nHistory - 1) / m_nSample) * m_nSample;
std::vector<float>& history = m_history[ctx.getSelected(i)];
CVertex* vertex = &m_mountain.m_Vertices[i * m_nSample];
for (size_t j = 0; j < m_nSample; ++j, ++k)
{
if (/*k>=m_historyIdx && */k < m_nHistory)
{
vertex[j].u = history[k];
vertex[j].y = history[k] / 2;
}
}
}
m_mountain.compile();
m_historyIdx = m_nHistory;
}
bool CRendererMountain::render(const CRendererContext& ctx)
{
if (m_mountain.m_Vertices.empty() || !m_nHistory) { return false; }
const float d = 2.5F;
glEnable(GL_LIGHTING);
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluPerspective(60, ctx.getAspect(), .01, 100);
glTranslatef(0, -.2F, -d);
glRotatef(ctx.getRotationX() * 10, 1, 0, 0);
glRotatef(ctx.getRotationY() * 10, 0, 1, 0);
glMatrixMode(GL_TEXTURE);
glPushMatrix();
glScalef(ctx.getScale(), 1, 1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glScalef(3 * ctx.getZoom(), 3 * ctx.getZoom(), 3 * ctx.getZoom());
glTranslatef(-.5F, 0, -.5F);
glScalef(m_nChannel * 1.F / ctx.getSelectedCount(), ctx.getScale(), 1);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(CVertex), &m_mountain.m_Vertices[0].x);
glNormalPointer(GL_FLOAT, sizeof(CVertex), &m_mountain.m_Normals[0].x);
glTexCoordPointer(1, GL_FLOAT, sizeof(CVertex), &m_mountain.m_Vertices[0].u);
glColor3f(ctx.getTranslucency(), ctx.getTranslucency(), ctx.getTranslucency());
glDrawElements(GL_TRIANGLES, GLsizei((ctx.getSelectedCount() - 1) * (m_nSample - 1) * 6), GL_UNSIGNED_INT, &m_mountain.m_Triangles[0]);
/*
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glColor3f(0, 0, 0);
glDrawElements(GL_TRIANGLES, m_mountain.m_Triangles.size(), GL_UNSIGNED_INT, &m_mountain.m_Triangles[0]);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
*/
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_TEXTURE);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
return true;
}
} // namespace AdvancedVisualization
} // namespace OpenViBE
@@ -0,0 +1,40 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "mIRenderer.hpp"
#include "mC3DMesh.hpp"
namespace OpenViBE {
namespace AdvancedVisualization {
class CRendererMountain : public IRenderer
{
public:
void rebuild(const CRendererContext& ctx) override;
void refresh(const CRendererContext& ctx) override;
bool render(const CRendererContext& ctx) override;
protected:
C3DMesh m_mountain;
};
} // namespace AdvancedVisualization
} // namespace OpenViBE
@@ -0,0 +1,103 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <cstdint>
#include "mCRendererMultiLine.hpp"
namespace OpenViBE {
namespace AdvancedVisualization {
bool CRendererMultiLine::render(const CRendererContext& ctx)
{
if (!ctx.getSelectedCount() || !m_nHistory) { return false; }
const auto nSample = int(m_nSample);
const auto n1 = int(m_historyIdx % m_nSample);
const auto n2 = int(nSample - n1);
if (!nSample) { return false; }
const float t1 = n2 * 1.F / nSample;
const float t2 = -n1 * 1.F / nSample;
glMatrixMode(GL_TEXTURE);
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glTranslatef(0, ctx.isPositiveOnly() ? 0 : 0.5F, 0);
glScalef(1, ctx.getScale(), 1);
glEnableClientState(GL_VERTEX_ARRAY);
for (size_t i = 0; i < ctx.getSelectedCount(); ++i)
{
std::vector<CVertex>& vertices = m_vertices[ctx.getSelected(i)];
glTexCoord1f(1 - (i + .5F) / ctx.getSelectedCount());
if (ctx.isScrollModeActive())
{
glPushMatrix();
glTranslatef(t1, 0, 0);
glVertexPointer(3, GL_FLOAT, sizeof(CVertex), &vertices[0].x);
glDrawArrays(GL_LINE_STRIP, 0, n1);
glPopMatrix();
if (n2 > 0)
{
glPushMatrix();
glTranslatef(t2, 0, 0);
glVertexPointer(3, GL_FLOAT, sizeof(CVertex), &vertices[n1].x);
glDrawArrays(GL_LINE_STRIP, 0, n2);
glPopMatrix();
if (n1 > 0)
{
glBegin(GL_LINES);
glVertex2f(vertices[nSample - 1].x + t2, vertices[nSample - 1].y);
glVertex2f(vertices[0].x + t1, vertices[0].y);
glEnd();
}
}
}
else
{
glVertexPointer(3, GL_FLOAT, sizeof(CVertex), &vertices[0].x);
glDrawArrays(GL_LINE_STRIP, 0, nSample);
}
}
glDisableClientState(GL_VERTEX_ARRAY);
glPopMatrix();
glMatrixMode(GL_TEXTURE);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glDisable(GL_TEXTURE_1D);
glColor3f(.2F, .2F, .2F);
glBegin(GL_LINES);
glVertex2f(0, ctx.isPositiveOnly() ? 0 : 0.5F);
glVertex2f(1, ctx.isPositiveOnly() ? 0 : 0.5F);
glEnd();
return true;
}
} // namespace AdvancedVisualization
} // namespace OpenViBE
@@ -0,0 +1,34 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "mCRendererLine.hpp"
namespace OpenViBE {
namespace AdvancedVisualization {
class CRendererMultiLine : public CRendererLine
{
public:
bool render(const CRendererContext& ctx) override;
};
} // namespace AdvancedVisualization
} // namespace OpenViBE
@@ -0,0 +1,247 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "mCRendererSlice.hpp"
namespace OpenViBE {
namespace AdvancedVisualization {
void CRendererSlice::rebuild(const CRendererContext& ctx)
{
IRenderer::rebuild(ctx);
m_vertices.clear();
m_vertices.resize(m_nSample * m_nChannel * 8);
m_quads.clear();
m_quads.resize(m_nSample * m_nChannel * 6 * 4);
size_t k = 0, l = 0;
for (size_t i = 0; i < m_nSample; ++i)
{
for (size_t j = 0; j < m_nChannel; ++j)
{
const float size = .5;
m_quads[l++] = k + 0;
m_quads[l++] = k + 1; // q0
m_quads[l++] = k + 2;
m_quads[l++] = k + 3;
m_quads[l++] = k + 4;
m_quads[l++] = k + 7; // q1
m_quads[l++] = k + 6;
m_quads[l++] = k + 5;
m_quads[l++] = k + 5;
m_quads[l++] = k + 1; // q2
m_quads[l++] = k + 2;
m_quads[l++] = k + 6;
m_quads[l++] = k + 4;
m_quads[l++] = k + 7; // q3
m_quads[l++] = k + 3;
m_quads[l++] = k + 0;
m_quads[l++] = k + 5;
m_quads[l++] = k + 4; // q4
m_quads[l++] = k + 0;
m_quads[l++] = k + 1;
m_quads[l++] = k + 6;
m_quads[l++] = k + 7; // q5
m_quads[l++] = k + 3;
m_quads[l++] = k + 2;
const float ox = 0;
const float oy = 0.5F * float(m_nChannel - 1) - j;
const float oz = 0.5F * float(m_nSample - 1) - i;
m_vertices[k].x = ox + size;
m_vertices[k].y = oy - size; // v0
m_vertices[k].z = oz + size;
k++;
m_vertices[k].x = ox + size;
m_vertices[k].y = oy + size; // v1
m_vertices[k].z = oz + size;
k++;
m_vertices[k].x = ox + size;
m_vertices[k].y = oy + size; // v2
m_vertices[k].z = oz - size;
k++;
m_vertices[k].x = ox + size;
m_vertices[k].y = oy - size; // v3
m_vertices[k].z = oz - size;
k++;
m_vertices[k].x = ox - size;
m_vertices[k].y = oy - size; // v4
m_vertices[k].z = oz + size;
k++;
m_vertices[k].x = ox - size;
m_vertices[k].y = oy + size; // v5
m_vertices[k].z = oz + size;
k++;
m_vertices[k].x = ox - size;
m_vertices[k].y = oy + size; // v6
m_vertices[k].z = oz - size;
k++;
m_vertices[k].x = ox - size;
m_vertices[k].y = oy - size; // v7
m_vertices[k].z = oz - size;
k++;
}
}
m_historyIdx = 0;
}
void CRendererSlice::refresh(const CRendererContext& ctx)
{
IRenderer::refresh(ctx);
for (size_t i = m_historyIdx; i < m_nHistory; ++i)
{
size_t k = (i % m_nSample) * m_nChannel * 8;
for (size_t j = 0; j < m_nChannel; ++j) { for (size_t l = 0; l < 8; ++l) { m_vertices[k++].u = m_history[j][i]; } }
}
m_historyIdx = m_nHistory;
}
bool CRendererSlice::render(const CRendererContext& ctx)
{
// size_t i, j;
const float d = 3.5;
if (!ctx.getSelectedCount() || !m_nHistory) { return false; }
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
// ::glEnable(GL_CULL_FACE);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluPerspective(60, ctx.getAspect(), .01, 100);
glTranslatef(0, 0, -d);
glRotatef(ctx.getRotationX() * 10, 1, 0, 0);
glRotatef(ctx.getRotationY() * 10, 0, 1, 0);
glMatrixMode(GL_TEXTURE);
glPushMatrix();
glScalef(ctx.getScale(), 1, 1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glScalef(ctx.getZoom(), ctx.getZoom(), ctx.getZoom());
glScalef(1., 1., 3.);
glPushMatrix();
glScalef(1.F / ctx.getStackCount(), 1.F / m_nChannel, 1.F / m_nSample);
glTranslatef(ctx.getStackIndex() - 0.5F * float(ctx.getStackCount() - 1), 0, 0);
glColor4f(.1F, .1F, .1F, ctx.getTranslucency());
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(CVertex), &m_vertices[0].x);
glTexCoordPointer(1, GL_FLOAT, sizeof(CVertex), &m_vertices[0].u);
glDrawElements(GL_QUADS, GLsizei(m_quads.size()), GL_UNSIGNED_INT, &m_quads[0]);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glPopMatrix();
glDisable(GL_TEXTURE_1D);
const float progress = 1 - 2.0F * float(m_historyIdx % m_nSample) / m_nSample;
glScalef(.5, .5, .5);
glBegin(GL_LINE_LOOP);
glColor3f(1, 1, 1);
glVertex3f(-1, -1, -1);
glVertex3f(-1, 1, -1);
glVertex3f(1, 1, -1);
glVertex3f(1, -1, -1);
glEnd();
glBegin(GL_LINE_LOOP);
glColor3f(1, 1, 1);
glVertex3f(-1, -1, 1);
glVertex3f(-1, 1, 1);
glVertex3f(1, 1, 1);
glVertex3f(1, -1, 1);
glEnd();
glBegin(GL_LINE_LOOP);
glColor3f(1, 1, 1);
glVertex3f(-1, -1, -1);
glVertex3f(-1, 1, -1);
glVertex3f(-1, 1, 1);
glVertex3f(-1, -1, 1);
glEnd();
glBegin(GL_LINE_LOOP);
glColor3f(1, 1, 1);
glVertex3f(1, -1, -1);
glVertex3f(1, 1, -1);
glVertex3f(1, 1, 1);
glVertex3f(1, -1, 1);
glEnd();
glBegin(GL_LINE_LOOP);
glColor4f(0.25F, 1, 0.25F, .9F / ctx.getStackCount());
glVertex3f(-1, -1, progress);
glVertex3f(-1, 1, progress);
glVertex3f(1, 1, progress);
glVertex3f(1, -1, progress);
glEnd();
glBegin(GL_QUADS);
glColor4f(0.25F, 1, 0.25F, .1F / ctx.getStackCount());
glVertex3f(-1, -1, progress);
glVertex3f(-1, 1, progress);
glVertex3f(1, 1, progress);
glVertex3f(1, -1, progress);
glEnd();
glEnable(GL_TEXTURE_1D);
if (ctx.getCheckBoardVisibility()) { this->drawCoordinateSystem(); }
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_TEXTURE);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
return true;
}
} // namespace AdvancedVisualization
} // namespace OpenViBE
@@ -0,0 +1,40 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "mIRenderer.hpp"
namespace OpenViBE {
namespace AdvancedVisualization {
class CRendererSlice : public IRenderer
{
public:
void rebuild(const CRendererContext& ctx) override;
void refresh(const CRendererContext& ctx) override;
bool render(const CRendererContext& ctx) override;
protected:
std::vector<CVertex> m_vertices;
std::vector<size_t> m_quads;
};
} // namespace AdvancedVisualization
} // namespace OpenViBE
@@ -0,0 +1,438 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "mCRendererTopo.hpp"
#include "m_RendererTools.hpp"
#include <cmath>
namespace OpenViBE {
namespace AdvancedVisualization {
const bool MULTI_SLICE = false;
namespace {
const size_t S = 1000;
// Legendre polynomials
// http://en.wikipedia.org/wiki/Legendre_polynomials
void legendre(const size_t n, const double x, std::vector<double>& legendres)
{
legendres.resize(n + 1);
legendres[0] = 1;
legendres[1] = x;
for (size_t i = 2; i <= n; ++i)
{
const double invi = 1. / i;
legendres[i] = (2 - invi) * x * legendres[i - 1] - (1 - invi) * legendres[i - 2];
}
}
// G function :
// Spherical splines for scalp potential and current density mapping
// http://www.sciencedirect.com/science/article/pii/0013469489901806
double g(const size_t n, const size_t m, const std::vector<double>& legendres)
{
double result = 0;
for (size_t i = 1; i <= n; ++i) { result += (2 * i + 1) / pow(double(i * (i + 1)), int(m)) * legendres[i]; }
return result / (4 * M_PI);
}
// H function :
// Spherical splines for scalp potential and current density mapping
// http://www.sciencedirect.com/science/article/pii/0013469489901806
double h(const size_t n, const size_t m, const std::vector<double>& legendres)
{
double result = 0;
for (size_t i = 1; i <= n; ++i) { result += (2 * i + 1) / pow(double(i * (i + 1)), int(m - 1)) * legendres[i]; }
return result / (4 * M_PI);
}
// Caching system
void build(const size_t n, const size_t m, std::vector<double>& gCache, std::vector<double>& hCache)
{
gCache.resize(2 * S + 1);
hCache.resize(2 * S + 1);
for (size_t i = 0; i <= 2 * S; ++i)
{
std::vector<double> legendres;
const double cosine = (double(i) - S) / S;
legendre(n, cosine, legendres);
gCache[i] = g(n, m, legendres);
hCache[i] = h(n, m, legendres);
}
gCache.push_back(gCache.back());
hCache.push_back(hCache.back());
}
double cache(const double x, std::vector<double>& rCache)
{
if (x < -1) { return rCache[0]; }
if (x > 1) { return rCache[2 * S]; }
double t = (x + 1) * S;
const int i1 = int(t);
const int i2 = int(t + 1);
t -= i1;
return rCache[i1] * (1 - t) + rCache[i2] * t;
}
} // namespace
void CRendererTopo::rebuild(const CRendererContext& ctx)
{
IRenderer::rebuild(ctx);
this->rebuild3DMeshesPre(ctx);
// Projects electrode coordinates to 3D mesh
std::vector<CVertex> projectedPositions;
std::vector<CVertex> positions;
positions.resize(ctx.getChannelCount());
for (size_t i = 0; i < ctx.getChannelCount(); ++i) { ctx.getChannelLocalisation(i, positions[i].x, positions[i].y, positions[i].z); }
m_scalp.project(projectedPositions, positions);
m_projectedPositions = projectedPositions;
#if 0
m_projectedPositions.resize(ctx.getChannelCount());
for (size_t i = 0; i < ctx.getChannelCount(); ++i)
{
CVertex p, q;
ctx.getChannelLocalisation(i, p.x, p.y, p.z);
for (size_t j = 0; j < m_scalp.m_Triangles.size(); j += 3)
{
size_t i1, i2, i3;
i1 = m_scalp.m_Triangles[j];
i2 = m_scalp.m_Triangles[j + 1];
i3 = m_scalp.m_Triangles[j + 2];
CVertex v1, v2, v3;
v1 = m_scalp.m_vertex[i1];
v2 = m_scalp.m_vertex[i2];
v3 = m_scalp.m_vertex[i3];
CVertex e1(v1, v2);
CVertex e2(v1, v3);
CVertex n = CVertex::cross(e1, e2).normalize();
float t = CVertex::dot(v1, n) / CVertex::dot(p, n);
q.x = t * p.x;
q.y = t * p.y;
q.z = t * p.z;
if (CVertex::isInTriangle(q, v1, v2, v3) && t >= 0)
{
m_projectedPositions[i].x = q.x;
m_projectedPositions[i].y = q.y;
m_projectedPositions[i].z = q.z;
}
}
if (m_projectedPositions[i].x == 0 && m_projectedPositions[i].y == 0 && m_projectedPositions[i].z == 0)
{
// ::printf("Could not project coordinates on mesh for channel %i [%s]\n", i+1, rContext.getChannelName(i).c_str());
}
}
#endif
// Generates transformation matrices based spherical spline interpolations
const size_t m = 3;
const auto n = size_t(pow(10., 10. / (2 * m - 2)));
std::vector<double> gCaches;
std::vector<double> hCaches;
build(n, m, gCaches, hCaches);
const size_t nc = ctx.getChannelCount();
const size_t vc = m_scalp.m_Vertices.size();
A = Eigen::MatrixXd(nc + 1, nc + 1);
A(nc, nc) = 0;
for (size_t i = 0; i < nc; ++i)
{
A(i, nc) = 1;
A(nc, i) = 1;
for (size_t j = 0; j <= i; ++j)
{
CVertex v1, v2;
ctx.getChannelLocalisation(i, v1.x, v1.y, v1.z);
ctx.getChannelLocalisation(j, v2.x, v2.y, v2.z);
const double cosine = CVertex::dot(v1, v2);
A(i, j) = cache(cosine, gCaches);
A(j, i) = cache(cosine, gCaches);
}
}
B = Eigen::MatrixXd(vc + 1, nc + 1);
D = Eigen::MatrixXd(vc + 1, nc + 1);
B(vc, nc) = 0;
D(vc, nc) = 0;
for (size_t i = 0; i < vc; ++i)
{
B(i, nc) = 1;
D(i, nc) = 1;
for (size_t j = 0; j < nc; ++j)
{
B(vc, j) = 1;
D(vc, j) = 1;
CVertex v1, v2;
v1 = m_scalp.m_Vertices[i];
v1.normalize();
ctx.getChannelLocalisation(j, v2.x, v2.y, v2.z);
const double cosine = CVertex::dot(v1, v2);
B(i, j) = cache(cosine, gCaches);
D(i, j) = cache(cosine, hCaches);
}
}
Ai = A.inverse();
// Post processed 3D meshes when needed
this->rebuild3DMeshesPost(ctx);
// Rebuilds texture coordinates array
if (MULTI_SLICE)
{
m_interpolatedSamples.clear();
m_interpolatedSamples.resize(m_nSample, Eigen::VectorXd::Zero(m_scalp.m_Vertices.size()));
}
// Finalizes
m_historyIdx = 0;
}
// V has sensor potentials
// W has interpolated potentials
// Z has interpolated current densities
void CRendererTopo::interpolate(const Eigen::VectorXd& v, Eigen::VectorXd& w, Eigen::VectorXd& z) const
{
Eigen::VectorXd c = Ai * v;
w = B * c;
c[v.size() - 1] = 0;
z = D * c;
}
void CRendererTopo::refresh(const CRendererContext& ctx)
{
IRenderer::refresh(ctx);
if (!m_nHistory) { return; }
size_t nc = ctx.getChannelCount();
const size_t vc = m_scalp.m_Vertices.size();
std::vector<float> samples;
Eigen::VectorXd v = Eigen::VectorXd::Zero(nc + 1);
Eigen::VectorXd w;
Eigen::VectorXd z;
if (!MULTI_SLICE)
{
this->getSampleAtERPFraction(m_erpFraction, samples);
for (size_t i = 0; i < nc; ++i) { v(i) = samples[i]; }
this->interpolate(v, w, z);
for (size_t j = 0; j < vc; ++j) { m_scalp.m_Vertices[j].u = float(w(j)); }
}
else
{
if (m_nHistory >= m_nSample)
{
for (size_t k = 0; k < m_nSample; ++k)
{
for (size_t i = 0; i < nc; ++i) { v(i) = m_history[i][m_nHistory - m_nSample + k]; }
this->interpolate(v, w, z);
m_interpolatedSamples[k] = w;
}
}
}
m_historyIdx = m_nHistory;
}
bool CRendererTopo::render(const CRendererContext& ctx)
{
if (!ctx.getSelectedCount() || m_scalp.m_Vertices.empty() || !m_nHistory) { return false; }
const float d = 3.5;
// ::glEnable(GL_DEPTH_TEST);
// ::glDisable(GL_BLEND);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluPerspective(60, ctx.getAspect(), .01, 100);
glTranslatef(0, 0, -d);
glRotatef(ctx.getRotationX() * 10, 1, 0, 0);
glRotatef(ctx.getRotationY() * 10, 0, 1, 0);
glMatrixMode(GL_TEXTURE);
glPushMatrix();
glScalef(ctx.getScale(), 1, 1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glScalef(ctx.getZoom(), ctx.getZoom(), ctx.getZoom());
// Now renders
glPushMatrix();
#if 1
glTranslatef(0, .5F, 0);
glRotatef(19, 1, 0, 0);
glTranslatef(0, -.2F, .35F);
// ::glScalef(1.8f, 1.8f, 1.8f);
#else
::glRotatef(19, 1, 0, 0);
::glTranslatef(0, -.2f, .35f);
// ::glScalef(1.8f, 1.8f, 1.8f);
#endif
if (ctx.isFaceMeshVisible())
{
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_1D);
if (!m_face.m_Triangles.empty())
{
if (!m_face.m_Normals.empty())
{
glEnable(GL_LIGHTING);
glEnableClientState(GL_NORMAL_ARRAY);
}
glColor3f(m_face.m_Color[0], m_face.m_Color[1], m_face.m_Color[2]);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(CVertex), &m_face.m_Vertices[0].x);
if (!m_face.m_Normals.empty()) { glNormalPointer(GL_FLOAT, sizeof(CVertex), &m_face.m_Normals[0].x); }
glDrawElements(GL_TRIANGLES, GLsizei(m_face.m_Triangles.size()), GL_UNSIGNED_INT, &m_face.m_Triangles[0]);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glDisable(GL_LIGHTING);
}
}
if (ctx.isScalpMeshVisible())
{
glEnable(GL_TEXTURE_1D);
if (!m_scalp.m_Triangles.empty())
{
if (!m_scalp.m_Normals.empty())
{
glEnable(GL_LIGHTING);
glEnableClientState(GL_NORMAL_ARRAY);
}
glColor3f(m_scalp.m_Color[0], m_scalp.m_Color[1], m_scalp.m_Color[2]);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(CVertex), &m_scalp.m_Vertices[0].x);
if (!m_scalp.m_Normals.empty()) { glNormalPointer(GL_FLOAT, sizeof(CVertex), &m_scalp.m_Normals[0].x); }
if (!MULTI_SLICE)
{
glColor3f(1, 1, 1);
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
glTexCoordPointer(1, GL_FLOAT, sizeof(CVertex), &m_scalp.m_Vertices[0].u);
glDrawElements(GL_TRIANGLES, GLsizei(m_scalp.m_Triangles.size()), GL_UNSIGNED_INT, &m_scalp.m_Triangles[0]);
}
else
{
glColor4f(1.F, 1.F, 1.F, 4.F / m_nSample);
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
for (size_t i = 0; i < m_nSample; ++i)
{
float scale = 1.F + i * 0.25F / m_nSample;
glPushMatrix();
glScalef(scale, scale, scale);
glTexCoordPointer(1, GL_DOUBLE, 0, &m_interpolatedSamples[i][0]);
glDrawElements(GL_TRIANGLES, GLsizei(m_scalp.m_Triangles.size()), GL_UNSIGNED_INT, &m_scalp.m_Triangles[0]);
glPopMatrix();
}
}
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glDisable(GL_LIGHTING);
}
}
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_1D);
glLineWidth(3);
for (size_t j = 0; j < ctx.getChannelCount(); ++j)
{
const float scale = .025F;
const CVertex v = m_projectedPositions[j];
//ctx.getChannelLocalisation(j, v.x, v.y, v.z);
glPushMatrix();
glTranslatef(v.x, v.y, v.z);
glScalef(scale, scale, scale);
const float value = ctx.isSelected(j) ? 1.0F : 0.2F;
const std::array<float, 3> color = { value, value, value };
glColor3fv(color.data());
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
cube();
glColor3f(0, 0, 0);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
cube();
glPopMatrix();
}
glPopMatrix();
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
if (ctx.getCheckBoardVisibility()) { this->drawCoordinateSystem(); }
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_TEXTURE);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
return true;
}
} // namespace AdvancedVisualization
} // namespace OpenViBE
@@ -0,0 +1,61 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "mIRenderer.hpp"
#include "mC3DMesh.hpp"
#include <Eigen/Eigen>
#include <vector>
namespace OpenViBE {
namespace AdvancedVisualization {
class CRendererTopo : public IRenderer
{
public:
void rebuild(const CRendererContext& ctx) override;
void refresh(const CRendererContext& ctx) override;
bool render(const CRendererContext& ctx) override;
// Called before electrode projections and spherical interpolation parameters generations and might be used to load a mesh or generate a sphere for instance
virtual void rebuild3DMeshesPre(const CRendererContext& ctx) = 0;
// Called after electrode projections and spherical interpolation parameters generations and might be used to unfold previously loaded mesh for instance
virtual void rebuild3DMeshesPost(const CRendererContext& ctx) = 0;
private:
void interpolate(const Eigen::VectorXd& v, Eigen::VectorXd& w, Eigen::VectorXd& z) const;
protected:
std::vector<CVertex> m_projectedPositions;
C3DMesh m_face;
C3DMesh m_scalp;
std::vector<Eigen::VectorXd> m_interpolatedSamples;
Eigen::MatrixXd A, B, D, Ai;
};
} // namespace AdvancedVisualization
} // namespace OpenViBE
@@ -0,0 +1,144 @@
#include "mCRendererTopo2D.hpp"
#include <cmath>
namespace OpenViBE {
namespace AdvancedVisualization {
// constexpr constexpr float OFFSET = 0.0001f; //Macro modernization, Not yet with jenkins (not the last visual 2013 which it works)
#define OFFSET 0.0001f
void CRendererTopo2D::rebuild3DMeshesPre(const CRendererContext& /*rContext*/)
{
const size_t nVertex1 = 32;
const size_t nVertex2 = 32;
const size_t nCircleVertex = 128;
{ // Scalp
m_scalp.clear();
std::vector<CVertex>& vertices = m_scalp.m_Vertices;
std::vector<uint32_t>& triangles = m_scalp.m_Triangles;
vertices.resize(nVertex1 * nVertex2);
for (size_t i = 0, k = 0; i < nVertex1; ++i)
{
for (size_t j = 0; j < nVertex2; j++, k++)
{
const auto a = float(i * M_PI / (nVertex1 - 1));
const auto b = float(j * 1.25 * M_PI / (nVertex2 - 1) - M_PI * .2);
vertices[k].x = cosf(a);
vertices[k].y = sinf(a) * sinf(b) - OFFSET;
vertices[k].z = sinf(a) * cosf(b);
vertices[k].u = k * 200.F / (nVertex1 * nVertex2);
}
}
triangles.resize((nVertex1 - 1) * (nVertex2 - 1) * 6);
for (size_t i = 0, k = 0; i < nVertex1 - 1; ++i)
{
for (size_t j = 0; j < nVertex2 - 1; j++, k += 6)
{
triangles[k] = (i) * nVertex2 + (j);
triangles[k + 1] = (i + 1) * nVertex2 + (j);
triangles[k + 2] = (i + 1) * nVertex2 + (j + 1);
triangles[k + 3] = triangles[k];
triangles[k + 4] = triangles[k + 2];
triangles[k + 5] = (i) * nVertex2 + (j + 1);
}
}
m_scalp.m_Color.fill(1.0);
// m_scalp.compile();
}
{ // Face
m_face.clear();
std::vector<CVertex>& vertices = m_face.m_Vertices;
std::vector<uint32_t>& triangles = m_face.m_Triangles;
// Ribbon mesh
vertices.resize(nCircleVertex * 2/*+6*/);
for (size_t i = 0, k = 0; i < nCircleVertex; ++i, ++k)
{
const auto a = float(i * 4 * M_PI / nCircleVertex);
vertices[k].x = cosf(a);
vertices[k].y = .01F;
vertices[k].z = sinf(a);
k++;
vertices[k].x = cosf(a);
vertices[k].y = -.01F;
vertices[k].z = sinf(a);
}
// Nose mesh
/*
vertices[k].x=-1; vertices[k].y=.01; vertices[k].z=-.5;
k++;
vertices[k].x=-1; vertices[k].y=-.01; vertices[k].z=-.5;
k++;
vertices[k].x=0; vertices[k].y=.01; vertices[k].z=-1.5;
k++;
vertices[k].x=0; vertices[k].y=-.01; vertices[k].z=-1.5;
k++;
vertices[k].x=1; vertices[k].y=.01; vertices[k].z=-.5;
k++;
vertices[k].x=1; vertices[k].y=-.01; vertices[k].z=-.5;
*/
// Ribon mesh
triangles.resize(nCircleVertex * 6/*+12*/);
const size_t mod = nCircleVertex * 2;
for (size_t i = 0, k = 0; i < nCircleVertex; ++i)
{
triangles[k++] = (i) % mod;
triangles[k++] = (i + 1) % mod;
triangles[k++] = (i + 2) % mod;
triangles[k++] = (i + 1) % mod;
triangles[k++] = (i + 2) % mod;
triangles[k++] = (i + 3) % mod;
}
// Nose mesh
/*
triangles[k++] = mod; triangles[k++] = mod + 1; triangles[k++] = mod + 2;
triangles[k++] = mod + 1; triangles[k++] = mod + 2; triangles[k++] = mod + 3;
triangles[k++] = mod + 2; triangles[k++] = mod + 3; triangles[k++] = mod + 4;
triangles[k++] = mod + 3; triangles[k++] = mod + 4; triangles[k++] = mod + 5;
*/
m_face.m_Color.fill(1.15F);
// m_face.compile();
}
}
namespace {
void unfold(std::vector<CVertex>& vertices, const float layer = 0)
{
for (auto& v : vertices)
{
v.y += OFFSET;
const float phi = float(M_PI) * .5F - asinf(v.y);
const float psi = atan2f(v.z, v.x);
v.x = phi * cos(psi);
v.y = layer;
v.z = phi * sin(psi);
}
}
} // namespace
void CRendererTopo2D::rebuild3DMeshesPost(const CRendererContext& /*ctx*/)
{
const float layer = 1E-3F;
unfold(m_scalp.m_Vertices, -layer);
unfold(m_face.m_Vertices, layer);
unfold(m_projectedPositions);
}
} // namespace AdvancedVisualization
} // namespace OpenViBE
@@ -0,0 +1,15 @@
#pragma once
#include "mCRendererTopo.hpp"
namespace OpenViBE {
namespace AdvancedVisualization {
class CRendererTopo2D : public CRendererTopo
{
public:
void rebuild3DMeshesPre(const CRendererContext& ctx) override;
void rebuild3DMeshesPost(const CRendererContext& ctx) override;
};
} // namespace AdvancedVisualization
} // namespace OpenViBE
@@ -0,0 +1,25 @@
#include "mCRendererTopo3D.hpp"
#include "content/Face.obj.hpp"
#include "content/Scalp.obj.hpp"
namespace OpenViBE {
namespace AdvancedVisualization {
void CRendererTopo3D::rebuild3DMeshesPre(const CRendererContext& /*ctx*/)
{
m_face.clear();
m_scalp.clear();
//m_face.load(OpenViBE::Directories::getDataDir() + "/content/Face.obj");
//m_scalp.load(OpenViBE::Directories::getDataDir() + "/content/Scalp.obj");
m_face.load(FACE_DATA);
m_scalp.load(SCALP_DATA);
m_face.m_Color[0] = .8F;
m_face.m_Color[1] = .6F;
m_face.m_Color[2] = .5F;
}
} // namespace AdvancedVisualization
} // namespace OpenViBE
@@ -0,0 +1,15 @@
#pragma once
#include "mCRendererTopo.hpp"
namespace OpenViBE {
namespace AdvancedVisualization {
class CRendererTopo3D : public CRendererTopo
{
public:
void rebuild3DMeshesPre(const CRendererContext& ctx) override;
void rebuild3DMeshesPost(const CRendererContext& /*ctx*/) override { }
};
} // namespace AdvancedVisualization
} // namespace OpenViBE
@@ -0,0 +1,145 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "mCRendererXYZPlot.hpp"
namespace OpenViBE {
namespace AdvancedVisualization {
void CRendererXYZPlot::rebuild(const CRendererContext& ctx)
{
IRenderer::rebuild(ctx);
m_hasDepth = ctx.hasXYZPlotDepth();
m_plotDim = (m_hasDepth ? 3 : 2);
m_nPlot = (ctx.getChannelCount() + m_plotDim - 1) / m_plotDim;
m_vertex.resize(m_nPlot);
const float inverseSampleCount = 1.0F / float(m_nSample < 2 ? 1 : (m_nSample - 1));
for (size_t i = 0; i < m_nPlot; ++i)
{
m_vertex[i].resize(this->m_nSample);
for (size_t j = 0; j < this->m_nSample; ++j) { m_vertex[i][j].u = j * inverseSampleCount; }
}
m_historyIdx = 0;
}
void CRendererXYZPlot::refresh(const CRendererContext& ctx)
{
IRenderer::refresh(ctx);
if (!m_nHistory) { return; }
while (m_historyIdx < m_nHistory)
{
const size_t j = m_historyIdx % this->m_nSample;
for (size_t i = 0; i < m_nPlot; ++i)
{
if (m_hasDepth)
{
const size_t i3 = i * 3;
m_vertex[i][j].x = (i3 < m_history.size() ? m_history[i3][m_historyIdx] : 0);
m_vertex[i][j].y = (i3 + 1 < m_history.size() ? m_history[i3 + 1][m_historyIdx] : 0);
m_vertex[i][j].z = (i3 + 2 < m_history.size() ? m_history[i3 + 2][m_historyIdx] : 0);
}
else
{
const size_t i3 = i * 2;
m_vertex[i][j].x = (i3 < m_history.size() ? m_history[i3][m_historyIdx] : 0);
m_vertex[i][j].y = (i3 + 1 < m_history.size() ? m_history[i3 + 1][m_historyIdx] : 0);
}
}
m_historyIdx++;
}
}
bool CRendererXYZPlot::render(const CRendererContext& ctx)
{
if (!ctx.getSelectedCount() || m_vertex.empty() || !m_nHistory) { return false; }
glPointSize(5);
if (m_hasDepth)
{
const float d = 3.5;
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluPerspective(60, ctx.getAspect(), .01, 100);
glTranslatef(0, 0, -d);
glRotatef(ctx.getRotationX() * 10, 1, 0, 0);
glRotatef(ctx.getRotationY() * 10, 0, 1, 0);
}
glMatrixMode(GL_TEXTURE);
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glTranslatef(m_hasDepth ? 0 : 0.5F, m_hasDepth ? 0 : 0.5F, 0);
glScalef(ctx.getZoom(), ctx.getZoom(), ctx.getZoom());
if (ctx.isAxisDisplayed())
{
if (m_hasDepth) { this->draw3DCoordinateSystem(); }
else { this->draw2DCoordinateSystem(); }
}
size_t n = m_nSample;
const size_t d = (m_historyIdx % m_nSample);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
for (size_t i = 0; i < m_nPlot; ++i)
{
glPushMatrix();
glScalef(ctx.getScale(), ctx.getScale(), ctx.getScale());
glVertexPointer(GLint(m_plotDim), GL_FLOAT, sizeof(CVertex), &m_vertex[i][0].x);
glTexCoordPointer(1, GL_FLOAT, sizeof(CVertex), &m_vertex[i][n - d].u);
glDrawArrays(GL_POINTS, 0, GLsizei(d));
glVertexPointer(GLint(m_plotDim), GL_FLOAT, sizeof(CVertex), &m_vertex[i][d].x);
glTexCoordPointer(1, GL_FLOAT, sizeof(CVertex), &m_vertex[i][0].u);
glDrawArrays(GL_POINTS, 0, GLsizei((m_historyIdx > n ? n : m_historyIdx) - d));
glPopMatrix();
}
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glMatrixMode(GL_TEXTURE);
glPopMatrix();
if (m_hasDepth)
{
glMatrixMode(GL_PROJECTION);
glPopMatrix();
}
glMatrixMode(GL_MODELVIEW);
return true;
}
} // namespace AdvancedVisualization
} // namespace OpenViBE
@@ -0,0 +1,42 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "mIRenderer.hpp"
namespace OpenViBE {
namespace AdvancedVisualization {
class CRendererXYZPlot : public IRenderer
{
public:
void rebuild(const CRendererContext& ctx) override;
void refresh(const CRendererContext& ctx) override;
bool render(const CRendererContext& ctx) override;
protected:
bool m_hasDepth = false;
size_t m_plotDim = 0;
size_t m_nPlot = 0;
std::vector<std::vector<CVertex>> m_vertex;
};
} // namespace AdvancedVisualization
} // namespace OpenViBE
@@ -0,0 +1,319 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "mIRenderer.hpp"
#include "mCRendererBars.hpp"
#include "mCRendererBitmap.hpp"
#include "mCRendererConnectivity.hpp"
#include "mCRendererCube.hpp"
#include "mCRendererFlower.hpp"
#include "mCRendererLine.hpp"
#include "mCRendererLoreta.hpp"
#include "mCRendererMountain.hpp"
#include "mCRendererMultiLine.hpp"
#include "mCRendererSlice.hpp"
#include "mTRendererStimulation.hpp"
#include "mCRendererTopo2D.hpp"
#include "mCRendererTopo3D.hpp"
#include "mCRendererXYZPlot.hpp"
#include <cmath>
#include <algorithm> // std::min_element, std::max_element
namespace OpenViBE {
namespace AdvancedVisualization {
static int iCount = 0;
IRenderer* IRenderer::create(const ERendererType type, const bool stimulation)
{
switch (type)
{
case ERendererType::Topography2D: return (stimulation ? nullptr : new CRendererTopo2D);
case ERendererType::Topography3D: return (stimulation ? nullptr : new CRendererTopo3D);
case ERendererType::Bars: return (stimulation ? new TRendererStimulation<true, CRendererBars> : new CRendererBars);
case ERendererType::Bitmap: return (stimulation ? new TRendererStimulation<true, CRendererBitmap> : new CRendererBitmap);
case ERendererType::Connectivity: return (stimulation ? nullptr : new CRendererConnectivity);
case ERendererType::Cube: return (stimulation ? nullptr : new CRendererCube);
case ERendererType::Flower: return (stimulation ? nullptr : new CRendererFlower);
case ERendererType::Line: return (stimulation ? new TRendererStimulation<false, CRendererLine> : new CRendererLine);
case ERendererType::Loreta: return (stimulation ? nullptr : new CRendererLoreta);
case ERendererType::Mountain: return (stimulation ? nullptr : new CRendererMountain);
case ERendererType::MultiLine: return (stimulation ? new TRendererStimulation<false, CRendererMultiLine> : new CRendererMultiLine);
case ERendererType::Slice: return (stimulation ? nullptr : new CRendererSlice);
case ERendererType::XYZPlot: return (stimulation ? nullptr : new CRendererXYZPlot);
// case ERendererType::Default: return (stimulation ? new TRendererStimulation<false, CRenderer> : new CRenderer);
default: return nullptr;
}
}
IRenderer::IRenderer() { iCount++; }
IRenderer::~IRenderer() { iCount--; }
void IRenderer::setChannelCount(const size_t nChannel)
{
m_nChannel = nChannel;
m_nInverseChannel = (nChannel ? 1.F / nChannel : 1);
m_vertex.clear();
m_mesh.clear();
m_historyIdx = 0;
m_nHistory = 0;
m_history.clear();
m_history.resize(nChannel);
}
void IRenderer::setSampleCount(const size_t nSample)
{
m_nSample = nSample == 0 ? 1 : nSample;
m_nInverseSample = (m_nSample ? 1.F / m_nSample : 1);
m_vertex.clear();
m_mesh.clear();
}
void IRenderer::feed(const float* data)
{
for (size_t i = 0; i < m_nChannel; ++i) { m_history[i].push_back(data[i]); }
m_nHistory++;
}
void IRenderer::feed(const float* data, const size_t nSample)
{
for (size_t i = 0; i < m_nChannel; ++i)
{
for (size_t j = 0; j < nSample; ++j) { m_history[i].push_back(data[j]); }
data += nSample;
}
m_nHistory += nSample;
}
void IRenderer::prefeed(const size_t nPreFeedSample)
{
for (size_t i = 0; i < m_nChannel; ++i) { m_history[i].insert(m_history[i].begin(), nPreFeedSample, 0.F); }
m_nHistory += nPreFeedSample;
m_historyIdx = 0;
}
float IRenderer::getSuggestedScale()
{
if (m_nChannel != 0)
{
std::vector<float> averages;
for (size_t i = 0; i < m_nChannel; ++i)
{
averages.push_back(0);
const size_t n = (m_history[i].size() < m_nSample) ? m_history[i].size() : m_nSample;
for (size_t j = m_history[i].size(); j > (m_history[i].size() - n); --j) { averages.back() += m_history[i][j - 1]; }
averages.back() /= float(n);
}
return (1 / *std::max_element(averages.begin(), averages.end()));
}
return 0;
}
void IRenderer::clear(const size_t nSampleToKeep)
{
if (!m_history.empty())
{
if (nSampleToKeep == 0)
{
for (auto& vec : m_history) { vec.clear(); }
m_nHistory = 0;
}
else if (nSampleToKeep < m_history[0].size())
{
const size_t sampleToDelete = m_history[0].size() - nSampleToKeep;
if (sampleToDelete > 1)
{
for (auto& vec : m_history) { std::vector<float>(vec.begin() + sampleToDelete, vec.end()).swap(vec); }
m_nHistory -= size_t(sampleToDelete);
}
}
}
// We always delete all of the stimulations, ideally we would know the time
// scale so we can keep the stimulations according to the kept samples
m_stimulationHistory.clear();
m_historyIdx = 0;
}
void IRenderer::setHistoryDrawIndex(const size_t index)
{
m_historyDrawIdx = index;
m_historyIdx = 0;
}
bool IRenderer::getSampleAtERPFraction(const float erpFraction, std::vector<float>& samples) const
{
samples.resize(m_nChannel);
if (m_nSample > m_nHistory) { return false; }
const float sampleIndexERP = (erpFraction * float(m_nSample - 1));
const float alpha = sampleIndexERP - std::floor(sampleIndexERP);
const size_t sampleIndexERP1 = size_t(sampleIndexERP) % m_nSample;
const size_t sampleIndexERP2 = size_t(sampleIndexERP + 1) % m_nSample;
for (size_t i = 0; i < m_nChannel; ++i)
{
samples[i] = m_history[i][m_nHistory - m_nSample + sampleIndexERP1] * (1 - alpha)
+ m_history[i][m_nHistory - m_nSample + sampleIndexERP2] * (alpha);
}
return true;
}
void IRenderer::refresh(const CRendererContext& ctx)
{
if (!m_nSample)
{
m_erpFraction = 0;
m_sampleIndexERP = 0;
return;
}
m_erpFraction = ctx.getERPFraction();
m_sampleIndexERP = size_t(m_erpFraction * float(m_nSample - 1)) % m_nSample;
}
/*
bool IRenderer::render(const CRendererContext & ctx)
{
::glLineWidth(7);
::glColor3f(1.f, 0.9f, 0.1f);
::glDisable(GL_TEXTURE_1D);
::glBegin(GL_LINES);
::glVertex2f(0, 0);
::glVertex2f(1, 1);
::glVertex2f(0, 1);
::glVertex2f(1, 0);
::glEnd();
::glBegin(GL_LINE_LOOP);
::glVertex2f(0, 0);
::glVertex2f(0, 1);
::glVertex2f(1, 1);
::glVertex2f(1, 0);
::glEnd();
}
*/
void IRenderer::draw3DCoordinateSystem()
{
glPushAttrib(GL_ALL_ATTRIB_BITS);
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glDisable(GL_TEXTURE_1D);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glLineWidth(2);
glPushMatrix();
glColor3f(.2F, .2F, .2F);
glScalef(.2F, .2F, .2F);
glBegin(GL_LINES);
for (int x = -10; x <= 10; ++x)
{
for (int z = -10; z <= 10; ++z)
{
if (x != 0)
{
glVertex3f(float(x), 0, 10.F);
glVertex3f(float(x), 0, -10.F);
}
if (z != 0)
{
glVertex3f(10.F, 0, float(z));
glVertex3f(-10.F, 0, float(z));
}
}
}
glEnd();
glPopMatrix();
glBegin(GL_LINES);
glColor3f(0, 0, 1);
glVertex3f(0, 0, 2.F);
glVertex3f(0, 0, -3.F);
glColor3f(0, 1, 0);
glVertex3f(0, 1.25F, 0);
glVertex3f(0, -1.25F, 0);
glColor3f(1, 0, 0);
glVertex3f(2.F, 0, 0);
glVertex3f(-2.F, 0, 0);
glEnd();
glPopAttrib();
}
void IRenderer::draw2DCoordinateSystem()
{
glPushAttrib(GL_ALL_ATTRIB_BITS);
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glDisable(GL_TEXTURE_1D);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glLineWidth(2);
glPushMatrix();
glColor3f(.2F, .2F, .2F);
glScalef(.2F, .2F, .2F);
glBegin(GL_LINES);
for (int x = -10; x <= 10; ++x)
{
for (int y = -10; y <= 10; ++y)
{
if (x != 0)
{
glVertex2f(float(x), 10.F);
glVertex2f(float(x), -10.F);
}
if (y != 0)
{
glVertex2f(10.F, float(y));
glVertex2f(-10.F, float(y));
}
}
}
glEnd();
glPopMatrix();
glBegin(GL_LINES);
glColor3f(0, 1, 0);
glVertex2f(0, 2.0F);
glVertex2f(0, -2.0F);
glColor3f(1, 0, 0);
glVertex2f(2.F, 0);
glVertex2f(-2.F, 0);
glEnd();
glPopAttrib();
}
} // namespace AdvancedVisualization
} // namespace OpenViBE
@@ -0,0 +1,194 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "mIRenderer.hpp"
#include <string>
#include <vector>
#include <map>
namespace OpenViBE {
namespace AdvancedVisualization {
static const int STIMULATION_INDICATOR_SMOOTHNESS = 10;
static const float STIMULATION_INDICATOR_RADIUS = 0.01F;
static const float STIMULATION_INDICATOR_SPACING = 0.03F;
template <bool TPreRender, class T>
class TRendererStimulation : public T
{
public:
std::vector<std::pair<float, float>> m_Circles;
std::map<uint64_t, int> m_Stimulations;
TRendererStimulation()
{
// Render a circle into a buffer so we don't have to do this each time
for (int i = 0; i < STIMULATION_INDICATOR_SMOOTHNESS; ++i)
{
m_Circles.push_back(std::make_pair(
STIMULATION_INDICATOR_RADIUS * cosf(float(i) / float(STIMULATION_INDICATOR_SMOOTHNESS - 1) * 2 * float(M_PI)),
STIMULATION_INDICATOR_RADIUS * sinf(float(i) / float(STIMULATION_INDICATOR_SMOOTHNESS - 1) * 2 * float(M_PI))
));
}
}
bool render(const CRendererContext& ctx) override
{
bool res = true;
if (TPreRender)
{
glPushAttrib(GL_ALL_ATTRIB_BITS);
res = T::render(ctx);
glPopAttrib();
}
bool ok = true;
ok &= (IRenderer::getSampleCount() != 0);
ok &= (IRenderer::getHistoryCount() != 0);
ok &= (IRenderer::getHistoryIndex() != 0);
if (ok)
{
glPushAttrib(GL_ALL_ATTRIB_BITS);
const size_t nSample = IRenderer::getSampleCount();
const size_t historyIndex = IRenderer::getHistoryIndex();
const uint64_t sampleDuration = ctx.getSampleDuration();
glDisable(GL_TEXTURE_1D);
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
const size_t leftIndex = historyIndex - historyIndex % nSample;
const size_t midIndex = historyIndex;
const double startTime = ((leftIndex * sampleDuration) >> 16) / 65536.;
const double midTime = ((midIndex * sampleDuration) >> 16) / 65536.;
const double duration = ((nSample * sampleDuration) >> 16) / 65536.;
m_Stimulations.clear();
for (const auto& stim : IRenderer::m_stimulationHistory)
{
if (m_Stimulations.count(stim.second) == 0)
{
// we store the "position" of the indicator for each new encountered stimulation
// if there are too many of them, we loop over to the beginning.
m_Stimulations[stim.second] = m_Stimulations.size() % int(1.0F / STIMULATION_INDICATOR_SPACING);
}
if (midTime - duration < stim.first && stim.first < midTime)
{
float progress;
if (stim.first > startTime) { progress = float((stim.first - startTime) / duration); }
else { progress = float((stim.first + duration - startTime) / duration); }
/*
::glLineWidth(3);
::glColor3f(0, 0, 0);
::glBegin(GL_LINES);
::glVertex2f(progress, 0);
::glVertex2f(progress, 1);
::glEnd();
*/
// draw a vertical line representing the stimulation
glLineWidth(1);
glColor3fv(getMarkerColor(stim.second));
glBegin(GL_LINES);
glVertex2f(progress, 0);
glVertex2f(progress, 1);
glEnd();
// draw a (ugly) disc representing a stimulation
glBegin(GL_TRIANGLE_FAN);
for (const auto& circle : m_Circles)
{
glVertex2f(float(circle.first / ctx.getAspect() + progress),
float(circle.second + 0.95F - m_Stimulations[stim.second] * STIMULATION_INDICATOR_SPACING));
}
glEnd();
// now draw
glLineWidth(2);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_LINE_SMOOTH);
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
glBegin(GL_LINE_LOOP);
for (const auto& circle : m_Circles)
{
glVertex2f(float(circle.first / ctx.getAspect() + progress),
float(circle.second + 0.95F - m_Stimulations[stim.second] * STIMULATION_INDICATOR_SPACING));
}
glEnd();
glDisable(GL_LINE_SMOOTH);
glDisable(GL_BLEND);
}
}
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
glEnable(GL_TEXTURE_1D);
glPopAttrib();
}
if (!TPreRender)
{
glPushAttrib(GL_ALL_ATTRIB_BITS);
res = T::render(ctx);
glPopAttrib();
}
return res && ok;
}
float* getMarkerColor(const uint64_t id)
{
static float color[4];
const float alpha = reverse<>(uint8_t(id & 255)) * 3.F / 255.F;
const auto alphai = int(alpha);
color[(alphai + 0) % 3] = 1 - alpha / 3.F;
color[(alphai + 1) % 3] = alpha / 3.F;
color[(alphai + 2) % 3] = 0;
color[3] = .75F;
return color;
}
template <typename Tvector>
Tvector reverse(Tvector v)
{
Tvector res = 0;
for (Tvector i = 0; i < sizeof(Tvector) * 8; ++i)
{
res <<= 1;
res |= ((v & (1 << i)) ? 1 : 0);
}
return res;
}
};
} // namespace AdvancedVisualization
} // namespace OpenViBE
@@ -0,0 +1,58 @@
/*********************************************************************
* Software License Agreement (AGPL-3 License)
*
* OpenViBE Designer
* Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
* Copyright (C) Inria, 2015-2017,V1.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
inline void cube(const float size = 1)
{
glBegin(GL_QUADS);
glVertex3f(size, -size, size);
glVertex3f(size, size, size);
glVertex3f(size, size, -size);
glVertex3f(size, -size, -size);
glVertex3f(-size, -size, size);
glVertex3f(-size, -size, -size);
glVertex3f(-size, size, -size);
glVertex3f(-size, size, size);
glVertex3f(-size, size, size);
glVertex3f(size, size, size);
glVertex3f(size, size, -size);
glVertex3f(-size, size, -size);
glVertex3f(-size, -size, size);
glVertex3f(-size, -size, -size);
glVertex3f(size, -size, -size);
glVertex3f(size, -size, size);
glVertex3f(-size, size, size);
glVertex3f(-size, -size, size);
glVertex3f(size, -size, size);
glVertex3f(size, size, size);
glVertex3f(-size, size, -size);
glVertex3f(-size, -size, -size);
glVertex3f(size, -size, -size);
glVertex3f(size, size, -size);
glEnd();
}
@@ -0,0 +1 @@
OV_ADD_PROJECTS("LIBRARIES_LIB-ADVANCED-VISUALIZATION_TEST")
@@ -0,0 +1,12 @@
PROJECT(openvibe-lib-adv-viz-test-renderer)
MESSAGE(STATUS "Now building ${PROJECT_NAME} ${PROJECT_VERSION} (${PROJECT_BRANCH}/${PROJECT_COMMITHASH})" )
ADD_EXECUTABLE(${PROJECT_NAME} main_test_renderer.cpp)
INCLUDE("FindLibMensiaAdvancedVisualisation")
INCLUDE("FindThirdPartyOpenGL")
INSTALL(TARGETS ${PROJECT_NAME}
RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR})
@@ -0,0 +1,18 @@
#include <mensia/advanced-visualization.hpp>
namespace OAV = OpenViBE::AdvancedVisualization;
int main()
{
OAV::CRendererContext context;
context.clear();
context.setDataType(OAV::CRendererContext::EDataType::Matrix);
OAV::IRenderer* rend = OAV::IRenderer::create(OAV::ERendererType::Bitmap, false);
rend->setChannelCount(10);
auto* tmp = new float[666];
rend->feed(tmp);
rend->refresh(context);
}